blob: b3c9ff7874cb466d306d6272a58629a898bc05cb [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>
Neale Ranns03c254e2020-03-17 14:25:10 +000052#include <vnet/mfib/ip4_mfib.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010053#include <vnet/dpo/load_balance.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070054#include <vnet/dpo/load_balance_map.h>
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +020055#include <vnet/dpo/receive_dpo.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010056#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000057#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Neale Ranns4ec36c52020-03-31 09:21:29 -040058#include <vnet/adj/adj_dp.h>
Neale Ranns68d48d92021-06-03 14:59:47 +000059#include <vnet/pg/pg.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070060
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080061#include <vnet/ip/ip4_forward.h>
Neale Ranns25edf142019-03-22 08:12:48 +000062#include <vnet/interface_output.h>
Neale Rannsba4a5bf2020-01-09 06:43:14 +000063#include <vnet/classify/vnet_classify.h>
Klement Sekera01c1fa42021-12-14 18:25:11 +000064#include <vnet/ip/reass/ip4_full_reass.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070065
Chris Luke8e5b0412016-07-26 13:06:10 -040066/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040067 @node ip4-lookup
68
69 This is the main IPv4 lookup dispatch node.
70
71 @param vm vlib_main_t corresponding to the current thread
72 @param node vlib_node_runtime_t
73 @param frame vlib_frame_t whose contents should be dispatched
74
75 @par Graph mechanics: buffer metadata, next index usage
76
77 @em Uses:
78 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
79 - Indicates the @c sw_if_index value of the interface that the
80 packet was received on.
81 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
82 - When the value is @c ~0 then the node performs a longest prefix
83 match (LPM) for the packet destination address in the FIB attached
84 to the receive interface.
85 - Otherwise perform LPM for the packet destination address in the
86 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
87 value (0, 1, ...) and not a VRF id.
88
89 @em Sets:
90 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
91 - The lookup result adjacency index.
92
93 <em>Next Index:</em>
94 - Dispatches the packet to the node index found in
95 ip_adjacency_t @c adj->lookup_next_index
96 (where @c adj is the lookup result adjacency).
97*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020098VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
99 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100{
Neale Rannscb54e3c2019-06-19 07:14:10 +0000101 return ip4_lookup_inline (vm, node, frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102}
103
Dave Barachd7cb1b52016-12-09 09:52:16 -0500104static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100105
Neale Rannsf8686322017-11-29 02:39:53 -0800106/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500107VLIB_REGISTER_NODE (ip4_lookup_node) =
108{
Neale Rannsf8686322017-11-29 02:39:53 -0800109 .name = "ip4-lookup",
110 .vector_size = sizeof (u32),
111 .format_trace = format_ip4_lookup_trace,
112 .n_next_nodes = IP_LOOKUP_N_NEXT,
113 .next_nodes = IP4_LOOKUP_NEXT_NODES,
114};
115/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100116
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200117VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
118 vlib_node_runtime_t * node,
119 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500121 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400122 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200123 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800124 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400125 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100127 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400128 n_left = frame->n_vectors;
129 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100130
Neale Ranns3ce72b22019-05-27 08:21:32 -0400131 vlib_get_buffers (vm, from, bufs, n_left);
132
133 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400135 const load_balance_t *lb0, *lb1;
136 const ip4_header_t *ip0, *ip1;
137 u32 lbi0, hc0, lbi1, hc1;
138 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100139
Neale Ranns3ce72b22019-05-27 08:21:32 -0400140 /* Prefetch next iteration. */
141 {
142 vlib_prefetch_buffer_header (b[2], LOAD);
143 vlib_prefetch_buffer_header (b[3], LOAD);
144
145 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
146 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
147 }
148
149 ip0 = vlib_buffer_get_current (b[0]);
150 ip1 = vlib_buffer_get_current (b[1]);
151 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
152 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
153
154 lb0 = load_balance_get (lbi0);
155 lb1 = load_balance_get (lbi1);
156
157 /*
158 * this node is for via FIBs we can re-use the hash value from the
159 * to node if present.
160 * We don't want to use the same hash value at each level in the recursion
161 * graph as that would lead to polarisation
162 */
163 hc0 = hc1 = 0;
164
165 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500166 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400167 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500168 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400169 hc0 = vnet_buffer (b[0])->ip.flow_hash =
170 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700171 }
172 else
173 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400174 hc0 = vnet_buffer (b[0])->ip.flow_hash =
175 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500176 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400177 dpo0 = load_balance_get_fwd_bucket
178 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
179 }
180 else
181 {
182 dpo0 = load_balance_get_bucket_i (lb0, 0);
183 }
184 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
185 {
186 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500187 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400188 hc1 = vnet_buffer (b[1])->ip.flow_hash =
189 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500190 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700191 else
192 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400193 hc1 = vnet_buffer (b[1])->ip.flow_hash =
194 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700195 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400196 dpo1 = load_balance_get_fwd_bucket
197 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
198 }
199 else
200 {
201 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500202 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000203
Neale Ranns3ce72b22019-05-27 08:21:32 -0400204 next[0] = dpo0->dpoi_next_node;
205 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100206
Neale Ranns3ce72b22019-05-27 08:21:32 -0400207 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
208 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100209
Neale Ranns3ce72b22019-05-27 08:21:32 -0400210 vlib_increment_combined_counter
211 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
212 vlib_increment_combined_counter
213 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100214
Neale Ranns3ce72b22019-05-27 08:21:32 -0400215 b += 2;
216 next += 2;
217 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218 }
219
Neale Ranns3ce72b22019-05-27 08:21:32 -0400220 while (n_left > 0)
221 {
222 const load_balance_t *lb0;
223 const ip4_header_t *ip0;
224 const dpo_id_t *dpo0;
225 u32 lbi0, hc0;
226
227 ip0 = vlib_buffer_get_current (b[0]);
228 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
229
230 lb0 = load_balance_get (lbi0);
231
232 hc0 = 0;
233 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
234 {
235 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
236 {
237 hc0 = vnet_buffer (b[0])->ip.flow_hash =
238 vnet_buffer (b[0])->ip.flow_hash >> 1;
239 }
240 else
241 {
242 hc0 = vnet_buffer (b[0])->ip.flow_hash =
243 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
244 }
245 dpo0 = load_balance_get_fwd_bucket
246 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
247 }
248 else
249 {
250 dpo0 = load_balance_get_bucket_i (lb0, 0);
251 }
252
253 next[0] = dpo0->dpoi_next_node;
254 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
255
256 vlib_increment_combined_counter
257 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
258
259 b += 1;
260 next += 1;
261 n_left -= 1;
262 }
263
264 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800265 if (node->flags & VLIB_NODE_FLAG_TRACE)
266 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
267
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100268 return frame->n_vectors;
269}
270
Neale Rannsf8686322017-11-29 02:39:53 -0800271/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500272VLIB_REGISTER_NODE (ip4_load_balance_node) =
273{
Neale Rannsf8686322017-11-29 02:39:53 -0800274 .name = "ip4-load-balance",
275 .vector_size = sizeof (u32),
276 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200277 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800278};
279/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200281#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100282/* get first interface address */
283ip4_address_t *
284ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500285 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100286{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500287 ip_lookup_main_t *lm = &im->lookup_main;
288 ip_interface_address_t *ia = 0;
289 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100290
Neale Ranns32e1c012016-11-22 17:07:28 +0000291 /* *INDENT-OFF* */
292 foreach_ip_interface_address
293 (lm, ia, sw_if_index,
294 1 /* honor unnumbered */ ,
295 ({
296 ip4_address_t * a =
297 ip_interface_address_get_address (lm, ia);
298 result = a;
299 break;
300 }));
301 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100302 if (result_ia)
303 *result_ia = result ? ia : 0;
304 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500306#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307
308static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700309ip4_add_subnet_bcast_route (u32 fib_index,
310 fib_prefix_t *pfx,
311 u32 sw_if_index)
312{
313 vnet_sw_interface_flags_t iflags;
314
315 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
316
317 fib_table_entry_special_remove(fib_index,
318 pfx,
319 FIB_SOURCE_INTERFACE);
320
321 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
322 {
323 fib_table_entry_update_one_path (fib_index, pfx,
324 FIB_SOURCE_INTERFACE,
325 FIB_ENTRY_FLAG_NONE,
326 DPO_PROTO_IP4,
327 /* No next-hop address */
328 &ADJ_BCAST_ADDR,
329 sw_if_index,
330 // invalid FIB index
331 ~0,
332 1,
333 // no out-label stack
334 NULL,
335 FIB_ROUTE_PATH_FLAG_NONE);
336 }
337 else
338 {
339 fib_table_entry_special_add(fib_index,
340 pfx,
341 FIB_SOURCE_INTERFACE,
342 (FIB_ENTRY_FLAG_DROP |
343 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
344 }
345}
346
347static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500348ip4_add_interface_prefix_routes (ip4_main_t *im,
349 u32 sw_if_index,
350 u32 fib_index,
351 ip_interface_address_t * a)
352{
353 ip_lookup_main_t *lm = &im->lookup_main;
354 ip_interface_prefix_t *if_prefix;
355 ip4_address_t *address = ip_interface_address_get_address (lm, a);
356
357 ip_interface_prefix_key_t key = {
358 .prefix = {
359 .fp_len = a->address_length,
360 .fp_proto = FIB_PROTOCOL_IP4,
361 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
362 },
363 .sw_if_index = sw_if_index,
364 };
365
366 fib_prefix_t pfx_special = {
367 .fp_proto = FIB_PROTOCOL_IP4,
368 };
369
370 /* If prefix already set on interface, just increment ref count & return */
371 if_prefix = ip_get_interface_prefix (lm, &key);
372 if (if_prefix)
373 {
374 if_prefix->ref_count += 1;
375 return;
376 }
377
378 /* New prefix - allocate a pool entry, initialize it, add to the hash */
379 pool_get (lm->if_prefix_pool, if_prefix);
380 if_prefix->ref_count = 1;
381 if_prefix->src_ia_index = a - lm->if_address_pool;
382 clib_memcpy (&if_prefix->key, &key, sizeof (key));
383 mhash_set (&lm->prefix_to_if_prefix_index, &key,
384 if_prefix - lm->if_prefix_pool, 0 /* old value */);
385
Neale Rannse2fe0972020-11-26 08:37:27 +0000386 pfx_special.fp_len = a->address_length;
387 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
388
389 /* set the glean route for the prefix */
390 fib_table_entry_update_one_path (fib_index, &pfx_special,
391 FIB_SOURCE_INTERFACE,
392 (FIB_ENTRY_FLAG_CONNECTED |
393 FIB_ENTRY_FLAG_ATTACHED),
394 DPO_PROTO_IP4,
395 /* No next-hop address */
396 NULL,
397 sw_if_index,
398 /* invalid FIB index */
399 ~0,
400 1,
401 /* no out-label stack */
402 NULL,
403 FIB_ROUTE_PATH_FLAG_NONE);
404
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500405 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
406 if (a->address_length <= 30)
407 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500408 /* set a drop route for the base address of the prefix */
409 pfx_special.fp_len = 32;
410 pfx_special.fp_addr.ip4.as_u32 =
411 address->as_u32 & im->fib_masks[a->address_length];
412
413 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
414 fib_table_entry_special_add (fib_index, &pfx_special,
415 FIB_SOURCE_INTERFACE,
416 (FIB_ENTRY_FLAG_DROP |
417 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
418
419 /* set a route for the broadcast address of the prefix */
420 pfx_special.fp_len = 32;
421 pfx_special.fp_addr.ip4.as_u32 =
422 address->as_u32 | ~im->fib_masks[a->address_length];
423 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
424 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
425
426
427 }
428 /* length == 31 - add an attached route for the other address */
429 else if (a->address_length == 31)
430 {
431 pfx_special.fp_len = 32;
432 pfx_special.fp_addr.ip4.as_u32 =
433 address->as_u32 ^ clib_host_to_net_u32(1);
434
435 fib_table_entry_update_one_path (fib_index, &pfx_special,
436 FIB_SOURCE_INTERFACE,
437 (FIB_ENTRY_FLAG_ATTACHED),
438 DPO_PROTO_IP4,
439 &pfx_special.fp_addr,
440 sw_if_index,
441 /* invalid FIB index */
442 ~0,
443 1,
444 NULL,
445 FIB_ROUTE_PATH_FLAG_NONE);
446 }
447}
448
449static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450ip4_add_interface_routes (u32 sw_if_index,
451 ip4_main_t * im, u32 fib_index,
452 ip_interface_address_t * a)
453{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500454 ip_lookup_main_t *lm = &im->lookup_main;
455 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100456 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500457 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500458 .fp_proto = FIB_PROTOCOL_IP4,
459 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100460 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500462 /* set special routes for the prefix if needed */
463 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100464
465 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500466 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100467 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500468 lm->classify_table_index_by_sw_if_index[sw_if_index];
469 if (classify_table_index != (u32) ~ 0)
470 {
471 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100472
Dave Barachd7cb1b52016-12-09 09:52:16 -0500473 dpo_set (&dpo,
474 DPO_CLASSIFY,
475 DPO_PROTO_IP4,
476 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100477
Dave Barachd7cb1b52016-12-09 09:52:16 -0500478 fib_table_entry_special_dpo_add (fib_index,
479 &pfx,
480 FIB_SOURCE_CLASSIFY,
481 FIB_ENTRY_FLAG_NONE, &dpo);
482 dpo_reset (&dpo);
483 }
484 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100485
Neale Ranns32e1c012016-11-22 17:07:28 +0000486 fib_table_entry_update_one_path (fib_index, &pfx,
487 FIB_SOURCE_INTERFACE,
488 (FIB_ENTRY_FLAG_CONNECTED |
489 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700490 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000491 &pfx.fp_addr,
492 sw_if_index,
493 // invalid FIB index
494 ~0,
495 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500496 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497}
498
499static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500500ip4_del_interface_prefix_routes (ip4_main_t * im,
501 u32 sw_if_index,
502 u32 fib_index,
503 ip4_address_t * address,
504 u32 address_length)
505{
506 ip_lookup_main_t *lm = &im->lookup_main;
507 ip_interface_prefix_t *if_prefix;
508
509 ip_interface_prefix_key_t key = {
510 .prefix = {
511 .fp_len = address_length,
512 .fp_proto = FIB_PROTOCOL_IP4,
513 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
514 },
515 .sw_if_index = sw_if_index,
516 };
517
518 fib_prefix_t pfx_special = {
519 .fp_len = 32,
520 .fp_proto = FIB_PROTOCOL_IP4,
521 };
522
523 if_prefix = ip_get_interface_prefix (lm, &key);
524 if (!if_prefix)
525 {
526 clib_warning ("Prefix not found while deleting %U",
527 format_ip4_address_and_length, address, address_length);
528 return;
529 }
530
531 if_prefix->ref_count -= 1;
532
533 /*
Neale Rannse2fe0972020-11-26 08:37:27 +0000534 * Routes need to be adjusted if deleting last intf addr in prefix
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500535 *
536 * We're done now otherwise
537 */
Neale Rannse2fe0972020-11-26 08:37:27 +0000538 if (if_prefix->ref_count > 0)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500539 return;
540
541 /* length <= 30, delete glean route, first address, last address */
542 if (address_length <= 30)
543 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000544 /* Less work to do in FIB if we remove the covered /32s first */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500545
Neale Rannse2fe0972020-11-26 08:37:27 +0000546 /* first address in prefix */
547 pfx_special.fp_addr.ip4.as_u32 =
548 address->as_u32 & im->fib_masks[address_length];
549 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500550
Neale Rannse2fe0972020-11-26 08:37:27 +0000551 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
552 fib_table_entry_special_remove (fib_index,
553 &pfx_special,
554 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500555
Neale Rannse2fe0972020-11-26 08:37:27 +0000556 /* prefix broadcast address */
557 pfx_special.fp_addr.ip4.as_u32 =
558 address->as_u32 | ~im->fib_masks[address_length];
559 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500560
Neale Rannse2fe0972020-11-26 08:37:27 +0000561 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
562 fib_table_entry_special_remove (fib_index,
563 &pfx_special,
564 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500565 }
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500566 else if (address_length == 31)
567 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000568 /* length == 31, delete attached route for the other address */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500569 pfx_special.fp_addr.ip4.as_u32 =
570 address->as_u32 ^ clib_host_to_net_u32(1);
571
572 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
573 }
574
Neale Rannse2fe0972020-11-26 08:37:27 +0000575 /* remove glean route for prefix */
576 pfx_special.fp_addr.ip4 = *address;
577 pfx_special.fp_len = address_length;
578 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
579
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500580 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
581 pool_put (lm->if_prefix_pool, if_prefix);
582}
583
584static void
585ip4_del_interface_routes (u32 sw_if_index,
586 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100587 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700589{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500590 fib_prefix_t pfx = {
Neale Rannse2fe0972020-11-26 08:37:27 +0000591 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500592 .fp_proto = FIB_PROTOCOL_IP4,
593 .fp_addr.ip4 = *address,
594 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595
Neale Rannse2fe0972020-11-26 08:37:27 +0000596 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
597
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500598 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
599 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700600}
601
Matthew G Smith88d29a92019-07-17 10:01:17 -0500602#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100603void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500604ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100605{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500606 ip4_main_t *im = &ip4_main;
John Lo4a302ee2020-05-12 22:34:39 -0400607 vnet_main_t *vnm = vnet_get_main ();
608 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100610 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
611
612 /*
613 * enable/disable only on the 1<->0 transition
614 */
615 if (is_enable)
616 {
617 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500618 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100619 }
620 else
621 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500622 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100623 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500624 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100625 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800626 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800627 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100628
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100629
Neale Ranns8269d3d2018-01-30 09:02:20 -0800630 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400631 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000632
John Lo4a302ee2020-05-12 22:34:39 -0400633 if (is_enable)
634 hi->l3_if_count++;
635 else if (hi->l3_if_count)
636 hi->l3_if_count--;
637
Neale Ranns57e53bb2019-05-29 13:58:43 +0000638 {
639 ip4_enable_disable_interface_callback_t *cb;
640 vec_foreach (cb, im->enable_disable_interface_callbacks)
641 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
642 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100643}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644
Ed Warnickecb9cada2015-12-08 15:45:58 -0700645static clib_error_t *
646ip4_add_del_interface_address_internal (vlib_main_t * vm,
647 u32 sw_if_index,
648 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500649 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500651 vnet_main_t *vnm = vnet_get_main ();
652 ip4_main_t *im = &ip4_main;
653 ip_lookup_main_t *lm = &im->lookup_main;
654 clib_error_t *error = 0;
Neale Ranns59f71132020-04-08 12:19:38 +0000655 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500656 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657
Pim van Pelt76b19ce2021-08-10 23:44:44 +0200658 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
659 if (error)
Matthew Smith1b6c7932021-09-24 15:27:36 -0500660 {
661 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
662 return error;
663 }
Pavel Kotucek57808982017-08-02 08:20:19 +0200664
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665 ip4_addr_fib_init (&ip4_af, address,
666 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
667 vec_add1 (addr_fib, ip4_af);
668
Neale Ranns744902e2017-08-14 10:35:44 -0700669 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100670 * there is no support for adj-fib handling in the presence of overlapping
671 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
672 * most routers do.
673 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000674 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500675 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100677 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700678 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500679 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700680 vnet_sw_interface_t *sif;
681
Damjan Marionb2c31b62020-12-13 21:47:40 +0100682 pool_foreach (sif, vnm->interface_main.sw_interfaces)
683 {
Neale Ranns744902e2017-08-14 10:35:44 -0700684 if (im->fib_index_by_sw_if_index[sw_if_index] ==
685 im->fib_index_by_sw_if_index[sif->sw_if_index])
686 {
687 foreach_ip_interface_address
688 (&im->lookup_main, ia, sif->sw_if_index,
689 0 /* honor unnumbered */ ,
690 ({
691 ip4_address_t * x =
692 ip_interface_address_get_address
693 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000694
Neale Ranns744902e2017-08-14 10:35:44 -0700695 if (ip4_destination_matches_route
696 (im, address, x, ia->address_length) ||
697 ip4_destination_matches_route (im,
698 x,
699 address,
700 address_length))
701 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500702 /* an intf may have >1 addr from the same prefix */
703 if ((sw_if_index == sif->sw_if_index) &&
704 (ia->address_length == address_length) &&
705 (x->as_u32 != address->as_u32))
706 continue;
707
Neale Ranns59f71132020-04-08 12:19:38 +0000708 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
709 /* if the address we're comparing against is stale
710 * then the CP has not added this one back yet, maybe
711 * it never will, so we have to assume it won't and
712 * ignore it. if it does add it back, then it will fail
713 * because this one is now present */
714 continue;
Neale Ranns744902e2017-08-14 10:35:44 -0700715
Neale Ranns59f71132020-04-08 12:19:38 +0000716 /* error if the length or intf was different */
717 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
718
719 error = clib_error_create
Ole Troan33a58172019-09-04 09:12:29 +0200720 ("failed to add %U on %U which conflicts with %U for interface %U",
Neale Ranns744902e2017-08-14 10:35:44 -0700721 format_ip4_address_and_length, address,
722 address_length,
Ole Troan33a58172019-09-04 09:12:29 +0200723 format_vnet_sw_if_index_name, vnm,
724 sw_if_index,
Neale Ranns744902e2017-08-14 10:35:44 -0700725 format_ip4_address_and_length, x,
726 ia->address_length,
727 format_vnet_sw_if_index_name, vnm,
728 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000729 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700730 }
731 }));
732 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100733 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000735 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736
Neale Ranns59f71132020-04-08 12:19:38 +0000737 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738
Neale Ranns59f71132020-04-08 12:19:38 +0000739 if (is_del)
740 {
741 if (~0 == if_address_index)
742 {
743 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
744 error = clib_error_create ("%U not found for interface %U",
745 lm->format_address_and_length,
746 addr_fib, address_length,
747 format_vnet_sw_if_index_name, vnm,
748 sw_if_index);
749 goto done;
750 }
751
yedgdbd366b2020-05-14 10:51:53 +0800752 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
753 address_length, sw_if_index);
754 if (error)
755 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000756 }
757 else
758 {
759 if (~0 != if_address_index)
760 {
761 ip_interface_address_t *ia;
762
763 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
764
765 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
766 {
767 if (ia->sw_if_index == sw_if_index)
768 {
769 /* re-adding an address during the replace action.
770 * consdier this the update. clear the flag and
771 * we're done */
772 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
773 goto done;
774 }
775 else
776 {
777 /* The prefix is moving from one interface to another.
778 * delete the stale and add the new */
779 ip4_add_del_interface_address_internal (vm,
780 ia->sw_if_index,
781 address,
782 address_length, 1);
783 ia = NULL;
784 error = ip_interface_address_add (lm, sw_if_index,
785 addr_fib, address_length,
786 &if_address_index);
787 }
788 }
789 else
790 {
791 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
792 error = clib_error_create
793 ("Prefix %U already found on interface %U",
794 lm->format_address_and_length, addr_fib, address_length,
795 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
796 }
797 }
798 else
799 error = ip_interface_address_add (lm, sw_if_index,
800 addr_fib, address_length,
801 &if_address_index);
802 }
803
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804 if (error)
805 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400806
Dave Barachd7cb1b52016-12-09 09:52:16 -0500807 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns03c254e2020-03-17 14:25:10 +0000808 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100809
Matthew G Smith88d29a92019-07-17 10:01:17 -0500810 /* intf addr routes are added/deleted on admin up/down */
811 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
812 {
813 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500814 ip4_del_interface_routes (sw_if_index,
815 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500816 address_length);
817 else
818 ip4_add_interface_routes (sw_if_index,
819 im, ip4_af.fib_index,
820 pool_elt_at_index
821 (lm->if_address_pool, if_address_index));
822 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823
Neale Ranns59f71132020-04-08 12:19:38 +0000824 ip4_add_del_interface_address_callback_t *cb;
825 vec_foreach (cb, im->add_del_interface_address_callbacks)
826 cb->function (im, cb->function_opaque, sw_if_index,
827 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828
Dave Barachd7cb1b52016-12-09 09:52:16 -0500829done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830 vec_free (addr_fib);
831 return error;
832}
833
834clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000835ip4_add_del_interface_address (vlib_main_t * vm,
836 u32 sw_if_index,
837 ip4_address_t * address,
838 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839{
840 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500841 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700842}
843
Neale Ranns1855b8e2018-07-11 10:31:26 -0700844void
845ip4_directed_broadcast (u32 sw_if_index, u8 enable)
846{
847 ip_interface_address_t *ia;
848 ip4_main_t *im;
849
850 im = &ip4_main;
851
852 /*
853 * when directed broadcast is enabled, the subnet braodcast route will forward
854 * packets using an adjacency with a broadcast MAC. otherwise it drops
855 */
856 /* *INDENT-OFF* */
857 foreach_ip_interface_address(&im->lookup_main, ia,
858 sw_if_index, 0,
859 ({
860 if (ia->address_length <= 30)
861 {
862 ip4_address_t *ipa;
863
864 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
865
866 fib_prefix_t pfx = {
867 .fp_len = 32,
868 .fp_proto = FIB_PROTOCOL_IP4,
869 .fp_addr = {
870 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
871 },
872 };
873
874 ip4_add_subnet_bcast_route
875 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
876 sw_if_index),
877 &pfx, sw_if_index);
878 }
879 }));
880 /* *INDENT-ON* */
881}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200882#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700883
Matthew G Smith88d29a92019-07-17 10:01:17 -0500884static clib_error_t *
885ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
886{
887 ip4_main_t *im = &ip4_main;
888 ip_interface_address_t *ia;
889 ip4_address_t *a;
890 u32 is_admin_up, fib_index;
891
Matthew G Smith88d29a92019-07-17 10:01:17 -0500892 vec_validate_init_empty (im->
893 lookup_main.if_address_pool_index_by_sw_if_index,
894 sw_if_index, ~0);
895
896 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
897
898 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
899
900 /* *INDENT-OFF* */
901 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
902 0 /* honor unnumbered */,
903 ({
904 a = ip_interface_address_get_address (&im->lookup_main, ia);
905 if (is_admin_up)
906 ip4_add_interface_routes (sw_if_index,
907 im, fib_index,
908 ia);
909 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500910 ip4_del_interface_routes (sw_if_index,
911 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500912 a, ia->address_length);
913 }));
914 /* *INDENT-ON* */
915
916 return 0;
917}
918
919VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
920
Dave Barachd6534602016-06-14 18:38:02 -0400921/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500922/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100923VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
924{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500925 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100926 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500927 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100928 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
929};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100930
Dave Barachd7cb1b52016-12-09 09:52:16 -0500931VNET_FEATURE_INIT (ip4_flow_classify, static) =
932{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100933 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700934 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100935 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700936};
937
Dave Barachd7cb1b52016-12-09 09:52:16 -0500938VNET_FEATURE_INIT (ip4_inacl, static) =
939{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100940 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400941 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100942 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400943};
944
Dave Barachd7cb1b52016-12-09 09:52:16 -0500945VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
946{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100947 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400948 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100949 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400950};
951
Dave Barachd7cb1b52016-12-09 09:52:16 -0500952VNET_FEATURE_INIT (ip4_policer_classify, static) =
953{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100954 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700955 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100956 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700957};
958
Dave Barachd7cb1b52016-12-09 09:52:16 -0500959VNET_FEATURE_INIT (ip4_ipsec, static) =
960{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100961 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100962 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100963 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400964};
965
Dave Barachd7cb1b52016-12-09 09:52:16 -0500966VNET_FEATURE_INIT (ip4_vpath, static) =
967{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100968 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400969 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500970 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
971};
972
Dave Barachd7cb1b52016-12-09 09:52:16 -0500973VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
974{
John Lo37682e12016-11-30 12:51:39 -0500975 .arc_name = "ip4-unicast",
976 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100977 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400978};
979
Neale Ranns8269d3d2018-01-30 09:02:20 -0800980VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500981{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100982 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800983 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400984 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100985};
986
Neale Ranns180279b2017-03-16 15:49:09 -0400987VNET_FEATURE_INIT (ip4_lookup, static) =
988{
989 .arc_name = "ip4-unicast",
990 .node_name = "ip4-lookup",
991 .runs_before = 0, /* not before any other features */
992};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100993
Dave Barachd6534602016-06-14 18:38:02 -0400994/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100995VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
996{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500997 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100998 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500999 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001000 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1001};
1002
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1004{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001005 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001006 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001007 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001008};
1009
Neale Ranns8269d3d2018-01-30 09:02:20 -08001010VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001011{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001012 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -08001013 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -04001014 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1015};
1016
1017VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1018{
1019 .arc_name = "ip4-multicast",
1020 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001022};
Dave Barach5331c722016-08-17 11:54:30 -04001023
1024/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001025VNET_FEATURE_ARC_INIT (ip4_output, static) =
1026{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001027 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001028 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001029 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001030 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1031};
Dave Barach5331c722016-08-17 11:54:30 -04001032
Dave Barachd7cb1b52016-12-09 09:52:16 -05001033VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1034{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001035 .arc_name = "ip4-output",
1036 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001037 .runs_before = VNET_FEATURES ("ip4-outacl"),
1038};
1039
1040VNET_FEATURE_INIT (ip4_outacl, static) =
1041{
1042 .arc_name = "ip4-output",
1043 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001044 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001045};
1046
Dave Barachd7cb1b52016-12-09 09:52:16 -05001047VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1048{
Matus Fabian08a6f012016-11-15 06:08:51 -08001049 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001050 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001051 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001052};
1053
1054/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001055VNET_FEATURE_INIT (ip4_interface_output, static) =
1056{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001057 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001058 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001059 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001060};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001061/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001062
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001064ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001065{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001066 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001068 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1069 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001070
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001071 if (is_add)
1072 {
1073 /* Fill in lookup tables with default table (0). */
1074 im->fib_index_by_sw_if_index[sw_if_index] = 0;
1075 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1076 }
1077 else
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001078 {
1079 ip4_main_t *im4 = &ip4_main;
1080 ip_lookup_main_t *lm4 = &im4->lookup_main;
1081 ip_interface_address_t *ia = 0;
1082 ip4_address_t *address;
1083 vlib_main_t *vm = vlib_get_main ();
1084
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001085 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001086 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001087 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001088 ({
1089 address = ip_interface_address_get_address (lm4, ia);
1090 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1091 }));
1092 /* *INDENT-ON* */
Neale Ranns03c254e2020-03-17 14:25:10 +00001093 ip4_mfib_interface_enable_disable (sw_if_index, 0);
Nathan Skrzypczaka424dd12021-08-20 15:53:43 +02001094
1095 if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
1096 fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1097 if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
1098 mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1099
1100 /* Erase the lookup tables just in case */
1101 im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
1102 im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001103 }
1104
Neale Ranns8269d3d2018-01-30 09:02:20 -08001105 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001106 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001107
Neale Ranns8269d3d2018-01-30 09:02:20 -08001108 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1109 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111 return /* no error */ 0;
1112}
1113
1114VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1115
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001117#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001119#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001121static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122ip4_lookup_init (vlib_main_t * vm)
1123{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001124 ip4_main_t *im = &ip4_main;
1125 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126 uword i;
1127
Damjan Marion8b3191e2016-11-09 19:54:20 +01001128 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1129 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001130 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1131 return (error);
1132 if ((error = vlib_call_init_function (vm, fib_module_init)))
1133 return error;
1134 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1135 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001136
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1138 {
1139 u32 m;
1140
1141 if (i < 32)
1142 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001143 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144 m = ~0;
1145 im->fib_masks[i] = clib_host_to_net_u32 (m);
1146 }
1147
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1149
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001150 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001151 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1152 FIB_SOURCE_DEFAULT_ROUTE);
1153 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1154 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001155
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001157 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158 pn = pg_get_node (ip4_lookup_node.index);
1159 pn->unformat_edit = unformat_pg_ip4_header;
1160 }
1161
1162 {
1163 ethernet_arp_header_t h;
1164
Dave Barachb7b92992018-10-17 10:38:51 -04001165 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1168#define _8(f,v) h.f = v;
1169 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1170 _16 (l3_type, ETHERNET_TYPE_IP4);
1171 _8 (n_l2_address_bytes, 6);
1172 _8 (n_l3_address_bytes, 4);
1173 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1174#undef _16
1175#undef _8
1176
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178 /* data */ &h,
1179 sizeof (h),
1180 /* alloc chunk size */ 8,
1181 "ip4 arp");
1182 }
1183
Dave Barach203c6322016-06-26 10:29:03 -04001184 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185}
1186
1187VLIB_INIT_FUNCTION (ip4_lookup_init);
1188
Dave Barachd7cb1b52016-12-09 09:52:16 -05001189typedef struct
1190{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001192 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193 u32 flow_hash;
1194 u32 fib_index;
1195
1196 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001197 u8 packet_data[64 - 1 * sizeof (u32)];
1198}
1199ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001201#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001202u8 *
1203format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204{
1205 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1206 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001207 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001208 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001209 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001210 format_white_space, indent,
1211 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001212 return s;
1213}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001214#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001215
Dave Barachd7cb1b52016-12-09 09:52:16 -05001216static u8 *
1217format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001218{
1219 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1220 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001221 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001222 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223
John Loac8146c2016-09-27 17:44:02 -04001224 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001225 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001226 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001227 format_white_space, indent,
1228 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001229 return s;
1230}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231
Dave Barachd7cb1b52016-12-09 09:52:16 -05001232static u8 *
1233format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001234{
1235 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1236 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001237 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001238 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239
Vengada Govindanf1544482016-09-28 02:45:57 -07001240 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001241 t->fib_index, t->dpo_index, format_ip_adjacency,
1242 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001243 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001244 format_white_space, indent,
1245 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001246 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 return s;
1248}
1249
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001250#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001251/* Common trace function for all ip4-forward next nodes. */
1252void
1253ip4_forward_next_trace (vlib_main_t * vm,
1254 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001255 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001257 u32 *from, n_left;
1258 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001259
1260 n_left = frame->n_vectors;
1261 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001262
Ed Warnickecb9cada2015-12-08 15:45:58 -07001263 while (n_left >= 4)
1264 {
1265 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001266 vlib_buffer_t *b0, *b1;
1267 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001268
1269 /* Prefetch next iteration. */
1270 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1271 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1272
1273 bi0 = from[0];
1274 bi1 = from[1];
1275
1276 b0 = vlib_get_buffer (vm, bi0);
1277 b1 = vlib_get_buffer (vm, bi1);
1278
1279 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1280 {
1281 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001282 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001284 t0->fib_index =
1285 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1286 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1287 vec_elt (im->fib_index_by_sw_if_index,
1288 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001289
Dave Barach178cf492018-11-13 16:34:13 -05001290 clib_memcpy_fast (t0->packet_data,
1291 vlib_buffer_get_current (b0),
1292 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293 }
1294 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1295 {
1296 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001297 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001299 t1->fib_index =
1300 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1301 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1302 vec_elt (im->fib_index_by_sw_if_index,
1303 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001304 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1305 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 }
1307 from += 2;
1308 n_left -= 2;
1309 }
1310
1311 while (n_left >= 1)
1312 {
1313 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001314 vlib_buffer_t *b0;
1315 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316
1317 bi0 = from[0];
1318
1319 b0 = vlib_get_buffer (vm, bi0);
1320
1321 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1322 {
1323 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001324 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001326 t0->fib_index =
1327 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1328 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1329 vec_elt (im->fib_index_by_sw_if_index,
1330 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001331 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1332 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001333 }
1334 from += 1;
1335 n_left -= 1;
1336 }
1337}
1338
Ed Warnickecb9cada2015-12-08 15:45:58 -07001339/* Compute TCP/UDP/ICMP4 checksum in software. */
1340u16
1341ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1342 ip4_header_t * ip0)
1343{
1344 ip_csum_t sum0;
1345 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001346
Ed Warnickecb9cada2015-12-08 15:45:58 -07001347 /* Initialize checksum with ip header. */
1348 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001349 payload_length_host_byte_order =
1350 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1351 sum0 =
1352 clib_host_to_net_u32 (payload_length_host_byte_order +
1353 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354
1355 if (BITS (uword) == 32)
1356 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001357 sum0 =
1358 ip_csum_with_carry (sum0,
1359 clib_mem_unaligned (&ip0->src_address, u32));
1360 sum0 =
1361 ip_csum_with_carry (sum0,
1362 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363 }
1364 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001365 sum0 =
1366 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367
Srikanth A02833ff2019-10-02 17:48:58 -07001368 return ip_calculate_l4_checksum (vm, p0, sum0,
1369 payload_length_host_byte_order, (u8 *) ip0,
1370 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001371}
1372
John Lo37682e12016-11-30 12:51:39 -05001373u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001374ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1375{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001376 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1377 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001378 u16 sum16;
1379
1380 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1381 || ip0->protocol == IP_PROTOCOL_UDP);
1382
1383 udp0 = (void *) (ip0 + 1);
1384 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1385 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001386 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1387 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388 return p0->flags;
1389 }
1390
1391 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1392
Damjan Marion213b5aa2017-07-13 21:19:27 +02001393 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1394 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395
1396 return p0->flags;
1397}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001398#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399
Dave Barach68b0fb02017-02-28 15:15:56 -05001400/* *INDENT-OFF* */
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001401VNET_FEATURE_ARC_INIT (ip4_local) = {
1402 .arc_name = "ip4-local",
1403 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
Dave Baracha25def72018-11-26 11:04:45 -05001404 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001405};
1406/* *INDENT-ON* */
1407
Florin Coras20a14b92017-08-15 22:47:22 -07001408static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001409ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1410 ip4_header_t * ip, u8 is_udp, u8 * error,
1411 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001412{
1413 u32 flags0;
1414 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1415 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1416 if (is_udp)
1417 {
1418 udp_header_t *udp;
1419 u32 ip_len, udp_len;
1420 i32 len_diff;
1421 udp = ip4_next_header (ip);
1422 /* Verify UDP length. */
1423 ip_len = clib_net_to_host_u16 (ip->length);
1424 udp_len = clib_net_to_host_u16 (udp->length);
1425
1426 len_diff = ip_len - udp_len;
1427 *good_tcp_udp &= len_diff >= 0;
1428 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1429 }
1430}
1431
Mohsin Kazmi68095382021-02-10 11:26:24 +01001432#define ip4_local_csum_is_offloaded(_b) \
1433 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001434 (vnet_buffer (_b)->oflags & \
Mohsin Kazmi68095382021-02-10 11:26:24 +01001435 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
Florin Coras1b255522018-06-01 12:22:23 -07001436
1437#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1438 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1439 || ip4_local_csum_is_offloaded (_b)))
1440
1441#define ip4_local_csum_is_valid(_b) \
1442 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1443 || (ip4_local_csum_is_offloaded (_b))) != 0
1444
1445static inline void
1446ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1447 ip4_header_t * ih, u8 * error)
1448{
1449 u8 is_udp, is_tcp_udp, good_tcp_udp;
1450
1451 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1452 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1453
1454 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1455 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1456 else
1457 good_tcp_udp = ip4_local_csum_is_valid (b);
1458
1459 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1460 *error = (is_tcp_udp && !good_tcp_udp
1461 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1462}
1463
1464static inline void
1465ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1466 ip4_header_t ** ih, u8 * error)
1467{
1468 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1469
1470 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1471 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1472
1473 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1474 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1475
1476 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1477 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1478
1479 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1480 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1481 {
Mohsin Kazmidd2eff62023-01-16 15:28:26 +00001482 if (is_tcp_udp[0] && !ip4_local_csum_is_offloaded (b[0]))
Florin Coras1b255522018-06-01 12:22:23 -07001483 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1484 &good_tcp_udp[0]);
Mohsin Kazmidd2eff62023-01-16 15:28:26 +00001485 if (is_tcp_udp[1] && !ip4_local_csum_is_offloaded (b[1]))
Florin Coras1b255522018-06-01 12:22:23 -07001486 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1487 &good_tcp_udp[1]);
1488 }
1489
1490 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1491 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1492 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1493 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1494}
1495
1496static inline void
1497ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1498 vlib_buffer_t * b, u16 * next, u8 error,
1499 u8 head_of_feature_arc)
1500{
1501 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1502 u32 next_index;
1503
1504 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1505 b->error = error ? error_node->errors[error] : 0;
1506 if (head_of_feature_arc)
1507 {
1508 next_index = *next;
1509 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1510 {
Florin Corasf8408802021-11-09 18:29:03 -08001511 vnet_feature_arc_start (
1512 arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
Florin Coras1b255522018-06-01 12:22:23 -07001513 *next = next_index;
1514 }
1515 }
1516}
1517
1518typedef struct
1519{
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001520 /* The src and fib-index together determine if packet n is the same as n-1 */
Florin Coras1b255522018-06-01 12:22:23 -07001521 ip4_address_t src;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001522 u32 fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001523 u32 lbi;
1524 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001525 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001526} ip4_local_last_check_t;
1527
1528static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001529ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1530 ip4_local_last_check_t *last_check, u8 *error0,
1531 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001532{
Florin Coras1b255522018-06-01 12:22:23 -07001533 const dpo_id_t *dpo0;
1534 load_balance_t *lb0;
1535 u32 lbi0;
1536
1537 vnet_buffer (b)->ip.fib_index =
1538 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1539 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1540
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001541 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001542 if (is_receive_dpo)
1543 {
1544 receive_dpo_t *rd;
1545 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001546 if (rd->rd_sw_if_index != ~0)
1547 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001548 }
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001549
Matthew Smith44e60462019-07-06 19:27:29 -05001550 /*
1551 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1552 * adjacency for the destination address (the local interface address).
1553 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1554 * adjacency for the source address (the remote sender's address)
1555 */
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001556 if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
1557 (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301558 last_check->first)
Florin Coras1b255522018-06-01 12:22:23 -07001559 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001560 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1561 &ip0->src_address);
Florin Coras1b255522018-06-01 12:22:23 -07001562
Matthew Smith44e60462019-07-06 19:27:29 -05001563 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1564 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001565 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001566
1567 lb0 = load_balance_get (lbi0);
1568 dpo0 = load_balance_get_bucket_i (lb0, 0);
1569
1570 /*
1571 * Must have a route to source otherwise we drop the packet.
1572 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1573 *
1574 * The checks are:
1575 * - the source is a recieve => it's from us => bogus, do this
1576 * first since it sets a different error code.
1577 * - uRPF check for any route to source - accept if passes.
1578 * - allow packets destined to the broadcast address from unknown sources
1579 */
1580
1581 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1582 && dpo0->dpoi_type == DPO_RECEIVE) ?
1583 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1584 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1585 && !fib_urpf_check_size (lb0->lb_urpf)
1586 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1587 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1588
1589 last_check->src.as_u32 = ip0->src_address.as_u32;
1590 last_check->lbi = lbi0;
1591 last_check->error = *error0;
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301592 last_check->first = 0;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001593 last_check->fib_index = vnet_buffer (b)->ip.fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001594 }
1595 else
1596 {
Matthew Smith44e60462019-07-06 19:27:29 -05001597 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1598 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001599 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001600 *error0 = last_check->error;
1601 }
1602}
1603
1604static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001605ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1606 ip4_local_last_check_t *last_check, u8 *error,
1607 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001608{
Florin Coras1b255522018-06-01 12:22:23 -07001609 const dpo_id_t *dpo[2];
1610 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001611 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001612 u32 lbi[2];
1613
Neale Rannsbe2286b2018-12-09 12:54:51 -08001614 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001615 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1616 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1617
1618 vnet_buffer (b[0])->ip.fib_index =
1619 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1620 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1621 vnet_buffer (b[0])->ip.fib_index;
1622
1623 vnet_buffer (b[1])->ip.fib_index =
1624 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1625 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1626 vnet_buffer (b[1])->ip.fib_index;
1627
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001628 not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
1629 not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
1630
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001631 vnet_buffer (b[0])->ip.rx_sw_if_index =
1632 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1633 vnet_buffer (b[1])->ip.rx_sw_if_index =
1634 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001635 if (is_receive_dpo)
1636 {
1637 const receive_dpo_t *rd0, *rd1;
1638 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1639 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001640 if (rd0->rd_sw_if_index != ~0)
1641 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1642 if (rd1->rd_sw_if_index != ~0)
1643 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001644 }
1645
Matthew Smith44e60462019-07-06 19:27:29 -05001646 /*
1647 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1648 * adjacency for the destination address (the local interface address).
1649 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1650 * adjacency for the source address (the remote sender's address)
1651 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301652 if (PREDICT_TRUE (not_last_hit))
Florin Coras1b255522018-06-01 12:22:23 -07001653 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001654 ip4_fib_forwarding_lookup_x2 (
1655 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1656 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001657
Matthew Smith44e60462019-07-06 19:27:29 -05001658 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1659 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001660 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001661
Matthew Smith44e60462019-07-06 19:27:29 -05001662 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1663 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001664 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001665
1666 lb[0] = load_balance_get (lbi[0]);
1667 lb[1] = load_balance_get (lbi[1]);
1668
1669 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1670 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1671
1672 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1673 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1674 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1675 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1676 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1677 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1678 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1679
1680 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1681 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1682 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1683 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1684 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1685 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1686 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1687
1688 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1689 last_check->lbi = lbi[1];
1690 last_check->error = error[1];
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301691 last_check->first = 0;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001692 last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001693 }
1694 else
1695 {
Matthew Smith44e60462019-07-06 19:27:29 -05001696 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1697 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001698 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001699
Matthew Smith44e60462019-07-06 19:27:29 -05001700 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1701 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001702 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001703
1704 error[0] = last_check->error;
1705 error[1] = last_check->error;
1706 }
1707}
Florin Coras20a14b92017-08-15 22:47:22 -07001708
Florin Corasc67cfd22018-10-01 21:59:18 -07001709enum ip_local_packet_type_e
1710{
1711 IP_LOCAL_PACKET_TYPE_L4,
1712 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001713 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001714};
1715
1716/**
1717 * Determine packet type and next node.
1718 *
1719 * The expectation is that all packets that are not L4 will skip
1720 * checksums and source checks.
1721 */
1722always_inline u8
1723ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1724{
1725 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1726
Juraj Sloboda3048b632018-10-02 11:13:53 +02001727 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1728 {
1729 *next = IP_LOCAL_NEXT_REASSEMBLY;
1730 return IP_LOCAL_PACKET_TYPE_FRAG;
1731 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001732 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1733 {
1734 *next = lm->local_next_by_ip_protocol[ip->protocol];
1735 return IP_LOCAL_PACKET_TYPE_NAT;
1736 }
1737
1738 *next = lm->local_next_by_ip_protocol[ip->protocol];
1739 return IP_LOCAL_PACKET_TYPE_L4;
1740}
1741
Dave Barach68b0fb02017-02-28 15:15:56 -05001742static inline uword
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001743ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1744 vlib_frame_t *frame, int head_of_feature_arc,
1745 int is_receive_dpo)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001746{
Florin Coras1b255522018-06-01 12:22:23 -07001747 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001748 vlib_node_runtime_t *error_node =
Florin Corasfa2a3162020-02-11 03:01:19 +00001749 vlib_node_get_runtime (vm, ip4_local_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001750 u16 nexts[VLIB_FRAME_SIZE], *next;
1751 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1752 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001753 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001754
1755 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001756 /*
1757 * 0.0.0.0 can appear as the source address of an IP packet,
1758 * as can any other address, hence the need to use the 'first'
1759 * member to make sure the .lbi is initialised for the first
1760 * packet.
1761 */
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001762 .src = { .as_u32 = 0 },
Florin Coras1b255522018-06-01 12:22:23 -07001763 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001764 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1765 .first = 1,
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001766 .fib_index = 0,
Florin Coras1b255522018-06-01 12:22:23 -07001767 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768
1769 from = vlib_frame_vector_args (frame);
1770 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001771
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772 if (node->flags & VLIB_NODE_FLAG_TRACE)
1773 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1774
Florin Coras1b255522018-06-01 12:22:23 -07001775 vlib_get_buffers (vm, from, bufs, n_left_from);
1776 b = bufs;
1777 next = nexts;
1778
1779 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001780 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001781 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782
Florin Coras1b255522018-06-01 12:22:23 -07001783 /* Prefetch next iteration. */
1784 {
1785 vlib_prefetch_buffer_header (b[4], LOAD);
1786 vlib_prefetch_buffer_header (b[5], LOAD);
1787
Damjan Marionaf7fb042021-07-15 11:54:41 +02001788 clib_prefetch_load (b[4]->data);
1789 clib_prefetch_load (b[5]->data);
Florin Coras1b255522018-06-01 12:22:23 -07001790 }
1791
1792 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1793
1794 ip[0] = vlib_buffer_get_current (b[0]);
1795 ip[1] = vlib_buffer_get_current (b[1]);
1796
1797 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1798 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1799
Florin Corasc67cfd22018-10-01 21:59:18 -07001800 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1801 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001802
Florin Corasc67cfd22018-10-01 21:59:18 -07001803 not_batch = pt[0] ^ pt[1];
1804
1805 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001806 goto skip_checks;
1807
1808 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001809 {
Florin Coras1b255522018-06-01 12:22:23 -07001810 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001811 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001812 }
1813 else
1814 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001815 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001816 {
Florin Coras1b255522018-06-01 12:22:23 -07001817 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001818 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1819 is_receive_dpo);
Florin Coras20a14b92017-08-15 22:47:22 -07001820 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001821 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001822 {
Florin Coras1b255522018-06-01 12:22:23 -07001823 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001824 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1825 is_receive_dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001826 }
1827 }
1828
Florin Coras1b255522018-06-01 12:22:23 -07001829 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001830
Florin Coras1b255522018-06-01 12:22:23 -07001831 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1832 head_of_feature_arc);
1833 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1834 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001835
Florin Coras1b255522018-06-01 12:22:23 -07001836 b += 2;
1837 next += 2;
1838 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001839 }
1840
Florin Coras1b255522018-06-01 12:22:23 -07001841 while (n_left_from > 0)
1842 {
1843 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1844
1845 ip[0] = vlib_buffer_get_current (b[0]);
1846 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001847 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001848
Florin Corasc67cfd22018-10-01 21:59:18 -07001849 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001850 goto skip_check;
1851
1852 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001853 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1854 is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001855
1856 skip_check:
1857
Florin Coras1b255522018-06-01 12:22:23 -07001858 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1859 head_of_feature_arc);
1860
1861 b += 1;
1862 next += 1;
1863 n_left_from -= 1;
1864 }
1865
1866 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001867 return frame->n_vectors;
1868}
1869
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001870VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1871 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001872{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001873 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1874 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001875}
1876
Neale Ranns32e1c012016-11-22 17:07:28 +00001877VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001878{
Dave Barach68b0fb02017-02-28 15:15:56 -05001879 .name = "ip4-local",
1880 .vector_size = sizeof (u32),
1881 .format_trace = format_ip4_forward_next_trace,
Florin Corasfa2a3162020-02-11 03:01:19 +00001882 .n_errors = IP4_N_ERROR,
Neale Rannse22a7042022-08-09 03:03:29 +00001883 .error_counters = ip4_error_counters,
Dave Barach68b0fb02017-02-28 15:15:56 -05001884 .n_next_nodes = IP_LOCAL_N_NEXT,
1885 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001886 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001887 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1888 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001889 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001890 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera01c1fa42021-12-14 18:25:11 +00001891 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001892 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001893};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001894
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001895VLIB_NODE_FN (ip4_receive_local_node)
1896(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1897{
1898 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1899 1 /* is_receive_dpo */);
1900}
1901
1902VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1903 .name = "ip4-receive",
1904 .vector_size = sizeof (u32),
1905 .format_trace = format_ip4_forward_next_trace,
1906 .sibling_of = "ip4-local"
1907};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001908
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001909VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1910 vlib_node_runtime_t * node,
1911 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001912{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001913 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1914 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001915}
1916
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001917VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001918 .name = "ip4-local-end-of-arc",
1919 .vector_size = sizeof (u32),
1920
1921 .format_trace = format_ip4_forward_next_trace,
1922 .sibling_of = "ip4-local",
1923};
1924
Dave Barach68b0fb02017-02-28 15:15:56 -05001925VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1926 .arc_name = "ip4-local",
1927 .node_name = "ip4-local-end-of-arc",
1928 .runs_before = 0, /* not before any other features */
1929};
Dave Barach68b0fb02017-02-28 15:15:56 -05001930
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001931#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001932void
1933ip4_register_protocol (u32 protocol, u32 node_index)
1934{
1935 vlib_main_t *vm = vlib_get_main ();
1936 ip4_main_t *im = &ip4_main;
1937 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001938
1939 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001940 lm->local_next_by_ip_protocol[protocol] =
1941 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942}
Neale Rannsb538dd82019-05-21 06:54:54 -07001943
1944void
1945ip4_unregister_protocol (u32 protocol)
1946{
1947 ip4_main_t *im = &ip4_main;
1948 ip_lookup_main_t *lm = &im->lookup_main;
1949
1950 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1951 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1952}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001953#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001954
1955static clib_error_t *
1956show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001957 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001959 ip4_main_t *im = &ip4_main;
1960 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001961 int i;
1962
1963 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001964 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001965 {
1966 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001967 {
1968 u32 node_index = vlib_get_node (vm,
1969 ip4_local_node.index)->
1970 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001971 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1972 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001973 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001974 }
1975 return 0;
1976}
1977
1978
1979
Billy McFall0683c9c2016-10-13 08:27:31 -04001980/*?
1981 * Display the set of protocols handled by the local IPv4 stack.
1982 *
1983 * @cliexpar
1984 * Example of how to display local protocol table:
1985 * @cliexstart{show ip local}
1986 * Protocols handled by ip4_local
1987 * 1
1988 * 17
1989 * 47
1990 * @cliexend
1991?*/
1992/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001993VLIB_CLI_COMMAND (show_ip_local, static) =
1994{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995 .path = "show ip local",
1996 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001997 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001998};
Billy McFall0683c9c2016-10-13 08:27:31 -04001999/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002000
Dave Barachd7cb1b52016-12-09 09:52:16 -05002001typedef enum
2002{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002003 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002004 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02002005 IP4_REWRITE_NEXT_FRAGMENT,
2006 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002007} ip4_rewrite_next_t;
2008
Neale Ranns889fe942017-06-01 05:43:19 -04002009/**
2010 * This bits of an IPv4 address to mask to construct a multicast
2011 * MAC address
2012 */
2013#if CLIB_ARCH_IS_BIG_ENDIAN
2014#define IP4_MCAST_ADDR_MASK 0x007fffff
2015#else
2016#define IP4_MCAST_ADDR_MASK 0xffff7f00
2017#endif
2018
Ole Troan8a9c8f12018-05-18 11:01:31 +02002019always_inline void
2020ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Ole Troaneb284a12019-10-09 13:33:19 +02002021 u16 adj_packet_bytes, bool df, u16 * next,
2022 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002023{
2024 if (packet_len > adj_packet_bytes)
2025 {
2026 *error = IP4_ERROR_MTU_EXCEEDED;
2027 if (df)
2028 {
2029 icmp4_error_set_vnet_buffer
2030 (b, ICMP4_destination_unreachable,
2031 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2032 adj_packet_bytes);
2033 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2034 }
2035 else
2036 {
Ole Troan313f7e22018-04-10 16:02:51 +02002037 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002038 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00002039 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02002040 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2041 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002042 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002043 }
2044 }
2045}
2046
Neale Ranns0b6a8572019-10-30 17:34:14 +00002047/* increment TTL & update checksum.
2048 Works either endian, so no need for byte swap. */
2049static_always_inline void
2050ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2051{
2052 i32 ttl;
2053 u32 checksum;
2054 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002055 return;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002056
2057 ttl = ip->ttl;
2058
2059 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2060 checksum += checksum >= 0xffff;
2061
2062 ip->checksum = checksum;
2063 ttl += 1;
2064 ip->ttl = ttl;
2065
Aloys Augustin0b77e312022-02-24 15:44:23 +00002066 ASSERT (ip4_header_checksum_is_valid (ip) ||
2067 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2068 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002069}
2070
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002071/* Decrement TTL & update checksum.
2072 Works either endian, so no need for byte swap. */
2073static_always_inline void
2074ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2075 u32 * error)
2076{
2077 i32 ttl;
2078 u32 checksum;
2079 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002080 return;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002081
2082 ttl = ip->ttl;
2083
2084 /* Input node should have reject packets with ttl 0. */
2085 ASSERT (ip->ttl > 0);
2086
2087 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2088 checksum += checksum >= 0xffff;
2089
2090 ip->checksum = checksum;
2091 ttl -= 1;
2092 ip->ttl = ttl;
2093
2094 /*
2095 * If the ttl drops below 1 when forwarding, generate
2096 * an ICMP response.
2097 */
2098 if (PREDICT_FALSE (ttl <= 0))
2099 {
2100 *error = IP4_ERROR_TIME_EXPIRED;
2101 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2102 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2103 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2104 0);
2105 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2106 }
2107
2108 /* Verify checksum. */
Benoît Ganne6e334e32020-08-31 18:59:34 +02002109 ASSERT (ip4_header_checksum_is_valid (ip) ||
Mohsin Kazmi4fd9f102021-06-17 17:29:27 +00002110 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2111 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002112}
2113
Ed Warnickecb9cada2015-12-08 15:45:58 -07002114always_inline uword
Damjan Mariond06e2eb2021-04-21 23:44:40 +02002115ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2116 vlib_frame_t *frame, int do_counters, int is_midchain,
2117 int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002118{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002119 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2120 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002121 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2122 u16 nexts[VLIB_FRAME_SIZE], *next;
2123 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002124 vlib_node_runtime_t *error_node =
2125 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002126
2127 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002128 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002129
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002130 vlib_get_buffers (vm, from, bufs, n_left_from);
2131 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2132
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002133#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002134 if (n_left_from >= 6)
2135 {
2136 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002137 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002138 vlib_prefetch_buffer_header (bufs[i], LOAD);
2139 }
2140
2141 next = nexts;
2142 b = bufs;
2143 while (n_left_from >= 8)
2144 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002145 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002146 ip4_header_t *ip0, *ip1;
2147 u32 rw_len0, error0, adj_index0;
2148 u32 rw_len1, error1, adj_index1;
2149 u32 tx_sw_if_index0, tx_sw_if_index1;
2150 u8 *p;
2151
PiotrX Kleskib801cd12020-12-09 14:32:26 +01002152 if (is_midchain)
2153 {
2154 vlib_prefetch_buffer_header (b[6], LOAD);
2155 vlib_prefetch_buffer_header (b[7], LOAD);
2156 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002157
2158 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2159 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2160
2161 /*
2162 * pre-fetch the per-adjacency counters
2163 */
2164 if (do_counters)
2165 {
2166 vlib_prefetch_combined_counter (&adjacency_counters,
2167 thread_index, adj_index0);
2168 vlib_prefetch_combined_counter (&adjacency_counters,
2169 thread_index, adj_index1);
2170 }
2171
2172 ip0 = vlib_buffer_get_current (b[0]);
2173 ip1 = vlib_buffer_get_current (b[1]);
2174
2175 error0 = error1 = IP4_ERROR_NONE;
2176
2177 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2178 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2179
2180 /* Rewrite packet header and updates lengths. */
2181 adj0 = adj_get (adj_index0);
2182 adj1 = adj_get (adj_index1);
2183
2184 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2185 rw_len0 = adj0[0].rewrite_header.data_bytes;
2186 rw_len1 = adj1[0].rewrite_header.data_bytes;
2187 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2188 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2189
2190 p = vlib_buffer_get_current (b[2]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002191 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2192 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002193
2194 p = vlib_buffer_get_current (b[3]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002195 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2196 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002197
2198 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002199 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2200 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2201
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002202 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002203 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002204 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002205 ip1_len = gso_mtu_sz (b[1]);
2206
2207 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002208 adj0[0].rewrite_header.max_l3_packet_bytes,
2209 ip0->flags_and_fragment_offset &
2210 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002211 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002212 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002213 adj1[0].rewrite_header.max_l3_packet_bytes,
2214 ip1->flags_and_fragment_offset &
2215 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002216 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002217
2218 if (is_mcast)
2219 {
2220 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2221 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2222 IP4_ERROR_SAME_INTERFACE : error0);
2223 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2224 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2225 IP4_ERROR_SAME_INTERFACE : error1);
2226 }
2227
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002228 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002229 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002230 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2231 {
2232 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002233 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002234
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002235 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2236 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2237
2238 if (PREDICT_FALSE
2239 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002240 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2241 tx_sw_if_index0,
2242 &next_index, b[0],
2243 adj0->ia_cfg_index);
2244
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002245 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002246 if (is_midchain)
Dave Barach1bd2c012020-04-12 08:31:39 -04002247 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002248 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002249 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002250 else
2251 {
2252 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002253 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2254 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002255 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002256 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2257 {
2258 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002259 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002260
2261 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2262 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2263
2264 if (PREDICT_FALSE
2265 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002266 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2267 tx_sw_if_index1,
2268 &next_index, b[1],
2269 adj1->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002270 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002271 if (is_midchain)
Neale Rannsfc746972020-05-20 19:58:20 +00002272 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002273 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002274 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002275 else
2276 {
2277 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002278 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2279 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002280 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002281
Neale Ranns4ec36c52020-03-31 09:21:29 -04002282 if (is_midchain)
2283 /* Guess we are only writing on ipv4 header. */
2284 vnet_rewrite_two_headers (adj0[0], adj1[0],
2285 ip0, ip1, sizeof (ip4_header_t));
2286 else
2287 /* Guess we are only writing on simple Ethernet header. */
2288 vnet_rewrite_two_headers (adj0[0], adj1[0],
2289 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002290
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002291 if (do_counters)
2292 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002293 if (error0 == IP4_ERROR_NONE)
2294 vlib_increment_combined_counter
2295 (&adjacency_counters,
2296 thread_index,
2297 adj_index0, 1,
2298 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002299
Neale Ranns0b6a8572019-10-30 17:34:14 +00002300 if (error1 == IP4_ERROR_NONE)
2301 vlib_increment_combined_counter
2302 (&adjacency_counters,
2303 thread_index,
2304 adj_index1, 1,
2305 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002306 }
2307
2308 if (is_midchain)
2309 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002310 if (error0 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002311 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns4ec36c52020-03-31 09:21:29 -04002312 if (error1 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002313 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002314 }
2315
2316 if (is_mcast)
2317 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002318 /* copy bytes from the IP address into the MAC rewrite */
2319 if (error0 == IP4_ERROR_NONE)
2320 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2321 adj0->rewrite_header.dst_mcast_offset,
2322 &ip0->dst_address.as_u32, (u8 *) ip0);
2323 if (error1 == IP4_ERROR_NONE)
2324 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2325 adj1->rewrite_header.dst_mcast_offset,
2326 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002327 }
2328
2329 next += 2;
2330 b += 2;
2331 n_left_from -= 2;
2332 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002333#elif (CLIB_N_PREFETCHES >= 4)
2334 next = nexts;
2335 b = bufs;
2336 while (n_left_from >= 1)
2337 {
2338 ip_adjacency_t *adj0;
2339 ip4_header_t *ip0;
2340 u32 rw_len0, error0, adj_index0;
2341 u32 tx_sw_if_index0;
2342 u8 *p;
2343
2344 /* Prefetch next iteration */
2345 if (PREDICT_TRUE (n_left_from >= 4))
2346 {
2347 ip_adjacency_t *adj2;
2348 u32 adj_index2;
2349
2350 vlib_prefetch_buffer_header (b[3], LOAD);
2351 vlib_prefetch_buffer_data (b[2], LOAD);
2352
2353 /* Prefetch adj->rewrite_header */
2354 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2355 adj2 = adj_get (adj_index2);
2356 p = (u8 *) adj2;
2357 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2358 LOAD);
2359 }
2360
2361 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2362
2363 /*
2364 * Prefetch the per-adjacency counters
2365 */
2366 if (do_counters)
2367 {
2368 vlib_prefetch_combined_counter (&adjacency_counters,
2369 thread_index, adj_index0);
2370 }
2371
2372 ip0 = vlib_buffer_get_current (b[0]);
2373
2374 error0 = IP4_ERROR_NONE;
2375
2376 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2377
2378 /* Rewrite packet header and updates lengths. */
2379 adj0 = adj_get (adj_index0);
2380
2381 /* Rewrite header was prefetched. */
2382 rw_len0 = adj0[0].rewrite_header.data_bytes;
2383 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2384
2385 /* Check MTU of outgoing interface. */
2386 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2387
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002388 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002389 ip0_len = gso_mtu_sz (b[0]);
2390
2391 ip4_mtu_check (b[0], ip0_len,
2392 adj0[0].rewrite_header.max_l3_packet_bytes,
2393 ip0->flags_and_fragment_offset &
2394 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002395 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002396
2397 if (is_mcast)
2398 {
2399 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2400 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2401 IP4_ERROR_SAME_INTERFACE : error0);
2402 }
2403
2404 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2405 * to see the IP header */
2406 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2407 {
2408 u32 next_index = adj0[0].rewrite_header.next_index;
2409 vlib_buffer_advance (b[0], -(word) rw_len0);
2410 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2411 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2412
2413 if (PREDICT_FALSE
2414 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002415 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2416 tx_sw_if_index0,
2417 &next_index, b[0],
2418 adj0->ia_cfg_index);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002419 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002420
2421 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002422 {
2423 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002424 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002425
Neale Ranns4ec36c52020-03-31 09:21:29 -04002426 /* Guess we are only writing on ipv4 header. */
2427 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2428 }
2429 else
2430 /* Guess we are only writing on simple Ethernet header. */
2431 vnet_rewrite_one_header (adj0[0], ip0,
2432 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002433
2434 /*
2435 * Bump the per-adjacency counters
2436 */
2437 if (do_counters)
2438 vlib_increment_combined_counter
2439 (&adjacency_counters,
2440 thread_index,
2441 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2442 b[0]) + rw_len0);
2443
Neale Ranns4ec36c52020-03-31 09:21:29 -04002444 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002445 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002446
2447 if (is_mcast)
2448 /* copy bytes from the IP address into the MAC rewrite */
2449 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2450 adj0->rewrite_header.dst_mcast_offset,
2451 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002452 }
2453 else
2454 {
2455 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002456 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2457 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002458 }
2459
2460 next += 1;
2461 b += 1;
2462 n_left_from -= 1;
2463 }
2464#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002465
Ed Warnickecb9cada2015-12-08 15:45:58 -07002466 while (n_left_from > 0)
2467 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002468 ip_adjacency_t *adj0;
2469 ip4_header_t *ip0;
2470 u32 rw_len0, adj_index0, error0;
2471 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002472
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002473 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2474
2475 adj0 = adj_get (adj_index0);
2476
2477 if (do_counters)
2478 vlib_prefetch_combined_counter (&adjacency_counters,
2479 thread_index, adj_index0);
2480
2481 ip0 = vlib_buffer_get_current (b[0]);
2482
2483 error0 = IP4_ERROR_NONE;
2484
2485 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2486
2487
2488 /* Update packet buffer attributes/set output interface. */
2489 rw_len0 = adj0[0].rewrite_header.data_bytes;
2490 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2491
2492 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002493 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002494 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002495 ip0_len = gso_mtu_sz (b[0]);
2496
2497 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002498 adj0[0].rewrite_header.max_l3_packet_bytes,
2499 ip0->flags_and_fragment_offset &
2500 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002501 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002502
2503 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002504 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002505 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2506 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2507 IP4_ERROR_SAME_INTERFACE : error0);
2508 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002509
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002510 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002511 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002512 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2513 {
2514 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002515 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002516 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2517 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002518
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002519 if (PREDICT_FALSE
2520 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002521 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2522 tx_sw_if_index0,
2523 &next_index, b[0],
2524 adj0->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002525 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002526
2527 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002528 {
2529 /* this acts on the packet that is about to be encapped */
2530 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002531 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002532
Neale Ranns4ec36c52020-03-31 09:21:29 -04002533 /* Guess we are only writing on ipv4 header. */
2534 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2535 }
2536 else
2537 /* Guess we are only writing on simple Ethernet header. */
2538 vnet_rewrite_one_header (adj0[0], ip0,
2539 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002540
2541 if (do_counters)
2542 vlib_increment_combined_counter
2543 (&adjacency_counters,
2544 thread_index, adj_index0, 1,
2545 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2546
Neale Rannse2fe0972020-11-26 08:37:27 +00002547 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002548 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002549
2550 if (is_mcast)
2551 /* copy bytes from the IP address into the MAC rewrite */
2552 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2553 adj0->rewrite_header.dst_mcast_offset,
2554 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002555 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002556 else
2557 {
2558 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002559 /* undo the TTL decrement - we'll be back to do it again */
2560 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2561 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002562 }
2563
2564 next += 1;
2565 b += 1;
2566 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002567 }
2568
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002569
Ed Warnickecb9cada2015-12-08 15:45:58 -07002570 /* Need to do trace after rewrites to pick up new packet data. */
2571 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002572 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002573
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002574 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002575 return frame->n_vectors;
2576}
2577
Neale Rannsf06aea52016-11-29 06:51:37 -08002578/** @brief IPv4 rewrite node.
2579 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002580
2581 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2582 header checksum, fetch the ip adjacency, check the outbound mtu,
2583 apply the adjacency rewrite, and send pkts to the adjacency
2584 rewrite header's rewrite_next_index.
2585
2586 @param vm vlib_main_t corresponding to the current thread
2587 @param node vlib_node_runtime_t
2588 @param frame vlib_frame_t whose contents should be dispatched
2589
2590 @par Graph mechanics: buffer metadata, next index usage
2591
2592 @em Uses:
2593 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2594 - the rewrite adjacency index
2595 - <code>adj->lookup_next_index</code>
2596 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002597 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002598 - <code>adj->rewrite_header</code>
2599 - Rewrite string length, rewrite string, next_index
2600
2601 @em Sets:
2602 - <code>b->current_data, b->current_length</code>
2603 - Updated net of applying the rewrite string
2604
2605 <em>Next Indices:</em>
2606 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002607 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002608*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002609
2610VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2611 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002612{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002613 if (adj_are_counters_enabled ())
2614 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2615 else
2616 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002617}
2618
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002619VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2620 vlib_node_runtime_t * node,
2621 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002622{
2623 if (adj_are_counters_enabled ())
2624 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2625 else
2626 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2627}
2628
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002629VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2630 vlib_node_runtime_t * node,
2631 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002632{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002633 if (adj_are_counters_enabled ())
2634 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2635 else
2636 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002637}
2638
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002639VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2640 vlib_node_runtime_t * node,
2641 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002642{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002643 if (adj_are_counters_enabled ())
2644 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2645 else
2646 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002647}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002648
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002649VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2650 vlib_node_runtime_t * node,
2651 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002652{
2653 if (adj_are_counters_enabled ())
2654 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2655 else
2656 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2657}
2658
Neale Ranns32e1c012016-11-22 17:07:28 +00002659/* *INDENT-OFF* */
2660VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002661 .name = "ip4-rewrite",
2662 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002663
Neale Ranns32e1c012016-11-22 17:07:28 +00002664 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002665
Ole Troan313f7e22018-04-10 16:02:51 +02002666 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002667 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002668 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002669 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002670 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002671 },
2672};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002673
2674VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002675 .name = "ip4-rewrite-bcast",
2676 .vector_size = sizeof (u32),
2677
2678 .format_trace = format_ip4_rewrite_trace,
2679 .sibling_of = "ip4-rewrite",
2680};
Neale Ranns32e1c012016-11-22 17:07:28 +00002681
2682VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002683 .name = "ip4-rewrite-mcast",
2684 .vector_size = sizeof (u32),
2685
2686 .format_trace = format_ip4_rewrite_trace,
2687 .sibling_of = "ip4-rewrite",
2688};
Neale Ranns32e1c012016-11-22 17:07:28 +00002689
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002690VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002691 .name = "ip4-mcast-midchain",
2692 .vector_size = sizeof (u32),
2693
2694 .format_trace = format_ip4_rewrite_trace,
2695 .sibling_of = "ip4-rewrite",
2696};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002697
Neale Ranns32e1c012016-11-22 17:07:28 +00002698VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002699 .name = "ip4-midchain",
2700 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002701 .format_trace = format_ip4_rewrite_trace,
2702 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002703};
Neale Ranns32e1c012016-11-22 17:07:28 +00002704/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002705
Ed Warnickecb9cada2015-12-08 15:45:58 -07002706static clib_error_t *
2707set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002708 unformat_input_t * input,
2709 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002710{
2711 int matched = 0;
2712 u32 table_id = 0;
2713 u32 flow_hash_config = 0;
2714 int rv;
2715
Dave Barachd7cb1b52016-12-09 09:52:16 -05002716 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2717 {
2718 if (unformat (input, "table %d", &table_id))
2719 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002720#define _(a, b, v) \
2721 else if (unformat (input, #a)) \
2722 { \
2723 flow_hash_config |= v; \
2724 matched = 1; \
2725 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002726 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002728 else
2729 break;
2730 }
Dave Barach75fc8542016-10-11 16:16:02 -04002731
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732 if (matched == 0)
2733 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002734 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002735
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002736 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737 switch (rv)
2738 {
2739 case 0:
2740 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002741
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742 case VNET_API_ERROR_NO_SUCH_FIB:
2743 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002744
Ed Warnickecb9cada2015-12-08 15:45:58 -07002745 default:
2746 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2747 break;
2748 }
Dave Barach75fc8542016-10-11 16:16:02 -04002749
Ed Warnickecb9cada2015-12-08 15:45:58 -07002750 return 0;
2751}
Dave Barach75fc8542016-10-11 16:16:02 -04002752
Billy McFall0683c9c2016-10-13 08:27:31 -04002753/*?
2754 * Configure the set of IPv4 fields used by the flow hash.
2755 *
2756 * @cliexpar
2757 * Example of how to set the flow hash on a given table:
2758 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2759 * Example of display the configured flow hash:
2760 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002761 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2762 * 0.0.0.0/0
2763 * unicast-ip4-chain
2764 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2765 * [0] [@0]: dpo-drop ip6
2766 * 0.0.0.0/32
2767 * unicast-ip4-chain
2768 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2769 * [0] [@0]: dpo-drop ip6
2770 * 224.0.0.0/8
2771 * unicast-ip4-chain
2772 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2773 * [0] [@0]: dpo-drop ip6
2774 * 6.0.1.2/32
2775 * unicast-ip4-chain
2776 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2777 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2778 * 7.0.0.1/32
2779 * unicast-ip4-chain
2780 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2781 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2782 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2783 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2784 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2785 * 240.0.0.0/8
2786 * unicast-ip4-chain
2787 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2788 * [0] [@0]: dpo-drop ip6
2789 * 255.255.255.255/32
2790 * unicast-ip4-chain
2791 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2792 * [0] [@0]: dpo-drop ip6
2793 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2794 * 0.0.0.0/0
2795 * unicast-ip4-chain
2796 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2797 * [0] [@0]: dpo-drop ip6
2798 * 0.0.0.0/32
2799 * unicast-ip4-chain
2800 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2801 * [0] [@0]: dpo-drop ip6
2802 * 172.16.1.0/24
2803 * unicast-ip4-chain
2804 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2805 * [0] [@4]: ipv4-glean: af_packet0
2806 * 172.16.1.1/32
2807 * unicast-ip4-chain
2808 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2809 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2810 * 172.16.1.2/32
2811 * unicast-ip4-chain
2812 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2813 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2814 * 172.16.2.0/24
2815 * unicast-ip4-chain
2816 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2817 * [0] [@4]: ipv4-glean: af_packet1
2818 * 172.16.2.1/32
2819 * unicast-ip4-chain
2820 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2821 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2822 * 224.0.0.0/8
2823 * unicast-ip4-chain
2824 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2825 * [0] [@0]: dpo-drop ip6
2826 * 240.0.0.0/8
2827 * unicast-ip4-chain
2828 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2829 * [0] [@0]: dpo-drop ip6
2830 * 255.255.255.255/32
2831 * unicast-ip4-chain
2832 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2833 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002834 * @cliexend
2835?*/
2836/* *INDENT-OFF* */
Takeru Hayasakab23c6f42023-01-17 04:45:58 +09002837VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002838 .path = "set ip flow-hash",
Takeru Hayasakab23c6f42023-01-17 04:45:58 +09002839 .short_help = "set ip flow-hash table <table-id> [src] [dst] [sport] "
2840 "[dport] [proto] [reverse] [gtpv1teid]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002841 .function = set_ip_flow_hash_command_fn,
2842};
Billy McFall0683c9c2016-10-13 08:27:31 -04002843/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002844
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002845#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002846int
2847vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2848 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002849{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002850 vnet_main_t *vnm = vnet_get_main ();
2851 vnet_interface_main_t *im = &vnm->interface_main;
2852 ip4_main_t *ipm = &ip4_main;
2853 ip_lookup_main_t *lm = &ipm->lookup_main;
2854 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002855 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002856
2857 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2858 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2859
2860 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2861 return VNET_API_ERROR_NO_SUCH_ENTRY;
2862
2863 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002864 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002865
Neale Rannsdf089a82016-10-02 16:39:06 +01002866 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2867
2868 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002869 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002870 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002871 .fp_len = 32,
2872 .fp_proto = FIB_PROTOCOL_IP4,
2873 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002874 };
2875 u32 fib_index;
2876
Dave Barachd7cb1b52016-12-09 09:52:16 -05002877 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2878 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002879
2880
Dave Barachd7cb1b52016-12-09 09:52:16 -05002881 if (table_index != (u32) ~ 0)
2882 {
2883 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002884
Dave Barachd7cb1b52016-12-09 09:52:16 -05002885 dpo_set (&dpo,
2886 DPO_CLASSIFY,
2887 DPO_PROTO_IP4,
2888 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002889
Dave Barachd7cb1b52016-12-09 09:52:16 -05002890 fib_table_entry_special_dpo_add (fib_index,
2891 &pfx,
2892 FIB_SOURCE_CLASSIFY,
2893 FIB_ENTRY_FLAG_NONE, &dpo);
2894 dpo_reset (&dpo);
2895 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002896 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002897 {
2898 fib_table_entry_special_remove (fib_index,
2899 &pfx, FIB_SOURCE_CLASSIFY);
2900 }
2901 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002902
Ed Warnickecb9cada2015-12-08 15:45:58 -07002903 return 0;
2904}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002905#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002906
2907static clib_error_t *
2908set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002909 unformat_input_t * input,
2910 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002911{
2912 u32 table_index = ~0;
2913 int table_index_set = 0;
2914 u32 sw_if_index = ~0;
2915 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002916
Dave Barachd7cb1b52016-12-09 09:52:16 -05002917 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2918 {
2919 if (unformat (input, "table-index %d", &table_index))
2920 table_index_set = 1;
2921 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2922 vnet_get_main (), &sw_if_index))
2923 ;
2924 else
2925 break;
2926 }
Dave Barach75fc8542016-10-11 16:16:02 -04002927
Ed Warnickecb9cada2015-12-08 15:45:58 -07002928 if (table_index_set == 0)
2929 return clib_error_return (0, "classify table-index must be specified");
2930
2931 if (sw_if_index == ~0)
2932 return clib_error_return (0, "interface / subif must be specified");
2933
2934 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2935
2936 switch (rv)
2937 {
2938 case 0:
2939 break;
2940
2941 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2942 return clib_error_return (0, "No such interface");
2943
2944 case VNET_API_ERROR_NO_SUCH_ENTRY:
2945 return clib_error_return (0, "No such classifier table");
2946 }
2947 return 0;
2948}
2949
Billy McFall0683c9c2016-10-13 08:27:31 -04002950/*?
2951 * Assign a classification table to an interface. The classification
2952 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2953 * commands. Once the table is create, use this command to filter packets
2954 * on an interface.
2955 *
2956 * @cliexpar
2957 * Example of how to assign a classification table to an interface:
2958 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2959?*/
2960/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002961VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2962{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002963 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002964 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002965 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002966 .function = set_ip_classify_command_fn,
2967};
Billy McFall0683c9c2016-10-13 08:27:31 -04002968/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002969
2970/*
2971 * fd.io coding-style-patch-verification: ON
2972 *
2973 * Local Variables:
2974 * eval: (c-set-style "gnu")
2975 * End:
2976 */