blob: ff74b52eb1882ebb6d57798856cb7062678d72e3 [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
Dave Barachd7cb1b52016-12-09 09:52:16 -0500106VLIB_REGISTER_NODE (ip4_lookup_node) =
107{
Neale Rannsf8686322017-11-29 02:39:53 -0800108 .name = "ip4-lookup",
109 .vector_size = sizeof (u32),
110 .format_trace = format_ip4_lookup_trace,
111 .n_next_nodes = IP_LOOKUP_N_NEXT,
112 .next_nodes = IP4_LOOKUP_NEXT_NODES,
113};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100114
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200115VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
116 vlib_node_runtime_t * node,
117 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500119 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400120 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200121 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800122 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400123 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100125 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400126 n_left = frame->n_vectors;
127 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100128
Neale Ranns3ce72b22019-05-27 08:21:32 -0400129 vlib_get_buffers (vm, from, bufs, n_left);
130
131 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400133 const load_balance_t *lb0, *lb1;
134 const ip4_header_t *ip0, *ip1;
135 u32 lbi0, hc0, lbi1, hc1;
136 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100137
Neale Ranns3ce72b22019-05-27 08:21:32 -0400138 /* Prefetch next iteration. */
139 {
140 vlib_prefetch_buffer_header (b[2], LOAD);
141 vlib_prefetch_buffer_header (b[3], LOAD);
142
143 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
144 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
145 }
146
147 ip0 = vlib_buffer_get_current (b[0]);
148 ip1 = vlib_buffer_get_current (b[1]);
149 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
150 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
151
152 lb0 = load_balance_get (lbi0);
153 lb1 = load_balance_get (lbi1);
154
155 /*
156 * this node is for via FIBs we can re-use the hash value from the
157 * to node if present.
158 * We don't want to use the same hash value at each level in the recursion
159 * graph as that would lead to polarisation
160 */
161 hc0 = hc1 = 0;
162
163 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500164 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400165 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500166 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400167 hc0 = vnet_buffer (b[0])->ip.flow_hash =
168 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700169 }
170 else
171 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400172 hc0 = vnet_buffer (b[0])->ip.flow_hash =
173 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500174 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400175 dpo0 = load_balance_get_fwd_bucket
176 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
177 }
178 else
179 {
180 dpo0 = load_balance_get_bucket_i (lb0, 0);
181 }
182 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
183 {
184 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500185 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400186 hc1 = vnet_buffer (b[1])->ip.flow_hash =
187 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500188 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700189 else
190 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400191 hc1 = vnet_buffer (b[1])->ip.flow_hash =
192 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700193 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400194 dpo1 = load_balance_get_fwd_bucket
195 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
196 }
197 else
198 {
199 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500200 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000201
Neale Ranns3ce72b22019-05-27 08:21:32 -0400202 next[0] = dpo0->dpoi_next_node;
203 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100204
Neale Ranns3ce72b22019-05-27 08:21:32 -0400205 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
206 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100207
Neale Ranns3ce72b22019-05-27 08:21:32 -0400208 vlib_increment_combined_counter
209 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
210 vlib_increment_combined_counter
211 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100212
Neale Ranns3ce72b22019-05-27 08:21:32 -0400213 b += 2;
214 next += 2;
215 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 }
217
Neale Ranns3ce72b22019-05-27 08:21:32 -0400218 while (n_left > 0)
219 {
220 const load_balance_t *lb0;
221 const ip4_header_t *ip0;
222 const dpo_id_t *dpo0;
223 u32 lbi0, hc0;
224
225 ip0 = vlib_buffer_get_current (b[0]);
226 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
227
228 lb0 = load_balance_get (lbi0);
229
230 hc0 = 0;
231 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
232 {
233 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
234 {
235 hc0 = vnet_buffer (b[0])->ip.flow_hash =
236 vnet_buffer (b[0])->ip.flow_hash >> 1;
237 }
238 else
239 {
240 hc0 = vnet_buffer (b[0])->ip.flow_hash =
241 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
242 }
243 dpo0 = load_balance_get_fwd_bucket
244 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
245 }
246 else
247 {
248 dpo0 = load_balance_get_bucket_i (lb0, 0);
249 }
250
251 next[0] = dpo0->dpoi_next_node;
252 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
253
254 vlib_increment_combined_counter
255 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
256
257 b += 1;
258 next += 1;
259 n_left -= 1;
260 }
261
262 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800263 if (node->flags & VLIB_NODE_FLAG_TRACE)
264 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
265
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100266 return frame->n_vectors;
267}
268
Dave Barachd7cb1b52016-12-09 09:52:16 -0500269VLIB_REGISTER_NODE (ip4_load_balance_node) =
270{
Neale Rannsf8686322017-11-29 02:39:53 -0800271 .name = "ip4-load-balance",
272 .vector_size = sizeof (u32),
273 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200274 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800275};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100276
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200277#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100278/* get first interface address */
279ip4_address_t *
280ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500281 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100282{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500283 ip_lookup_main_t *lm = &im->lookup_main;
284 ip_interface_address_t *ia = 0;
285 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100286
Neale Ranns32e1c012016-11-22 17:07:28 +0000287 foreach_ip_interface_address
288 (lm, ia, sw_if_index,
289 1 /* honor unnumbered */ ,
290 ({
291 ip4_address_t * a =
292 ip_interface_address_get_address (lm, ia);
293 result = a;
294 break;
295 }));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100296 if (result_ia)
297 *result_ia = result ? ia : 0;
298 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500300#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301
302static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700303ip4_add_subnet_bcast_route (u32 fib_index,
304 fib_prefix_t *pfx,
305 u32 sw_if_index)
306{
307 vnet_sw_interface_flags_t iflags;
308
309 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
310
311 fib_table_entry_special_remove(fib_index,
312 pfx,
313 FIB_SOURCE_INTERFACE);
314
315 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
316 {
317 fib_table_entry_update_one_path (fib_index, pfx,
318 FIB_SOURCE_INTERFACE,
319 FIB_ENTRY_FLAG_NONE,
320 DPO_PROTO_IP4,
321 /* No next-hop address */
322 &ADJ_BCAST_ADDR,
323 sw_if_index,
324 // invalid FIB index
325 ~0,
326 1,
327 // no out-label stack
328 NULL,
329 FIB_ROUTE_PATH_FLAG_NONE);
330 }
331 else
332 {
333 fib_table_entry_special_add(fib_index,
334 pfx,
335 FIB_SOURCE_INTERFACE,
336 (FIB_ENTRY_FLAG_DROP |
337 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
338 }
339}
340
341static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500342ip4_add_interface_prefix_routes (ip4_main_t *im,
343 u32 sw_if_index,
344 u32 fib_index,
345 ip_interface_address_t * a)
346{
347 ip_lookup_main_t *lm = &im->lookup_main;
348 ip_interface_prefix_t *if_prefix;
349 ip4_address_t *address = ip_interface_address_get_address (lm, a);
350
351 ip_interface_prefix_key_t key = {
352 .prefix = {
353 .fp_len = a->address_length,
354 .fp_proto = FIB_PROTOCOL_IP4,
355 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
356 },
357 .sw_if_index = sw_if_index,
358 };
359
360 fib_prefix_t pfx_special = {
361 .fp_proto = FIB_PROTOCOL_IP4,
362 };
363
364 /* If prefix already set on interface, just increment ref count & return */
365 if_prefix = ip_get_interface_prefix (lm, &key);
366 if (if_prefix)
367 {
368 if_prefix->ref_count += 1;
369 return;
370 }
371
372 /* New prefix - allocate a pool entry, initialize it, add to the hash */
373 pool_get (lm->if_prefix_pool, if_prefix);
374 if_prefix->ref_count = 1;
375 if_prefix->src_ia_index = a - lm->if_address_pool;
376 clib_memcpy (&if_prefix->key, &key, sizeof (key));
377 mhash_set (&lm->prefix_to_if_prefix_index, &key,
378 if_prefix - lm->if_prefix_pool, 0 /* old value */);
379
Neale Rannse2fe0972020-11-26 08:37:27 +0000380 pfx_special.fp_len = a->address_length;
381 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
382
383 /* set the glean route for the prefix */
384 fib_table_entry_update_one_path (fib_index, &pfx_special,
385 FIB_SOURCE_INTERFACE,
386 (FIB_ENTRY_FLAG_CONNECTED |
387 FIB_ENTRY_FLAG_ATTACHED),
388 DPO_PROTO_IP4,
389 /* No next-hop address */
390 NULL,
391 sw_if_index,
392 /* invalid FIB index */
393 ~0,
394 1,
395 /* no out-label stack */
396 NULL,
397 FIB_ROUTE_PATH_FLAG_NONE);
398
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500399 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
400 if (a->address_length <= 30)
401 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500402 /* set a drop route for the base address of the prefix */
403 pfx_special.fp_len = 32;
404 pfx_special.fp_addr.ip4.as_u32 =
405 address->as_u32 & im->fib_masks[a->address_length];
406
407 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
408 fib_table_entry_special_add (fib_index, &pfx_special,
409 FIB_SOURCE_INTERFACE,
410 (FIB_ENTRY_FLAG_DROP |
411 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
412
413 /* set a route for the broadcast address of the prefix */
414 pfx_special.fp_len = 32;
415 pfx_special.fp_addr.ip4.as_u32 =
416 address->as_u32 | ~im->fib_masks[a->address_length];
417 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
418 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
419
420
421 }
422 /* length == 31 - add an attached route for the other address */
423 else if (a->address_length == 31)
424 {
425 pfx_special.fp_len = 32;
426 pfx_special.fp_addr.ip4.as_u32 =
427 address->as_u32 ^ clib_host_to_net_u32(1);
428
429 fib_table_entry_update_one_path (fib_index, &pfx_special,
430 FIB_SOURCE_INTERFACE,
431 (FIB_ENTRY_FLAG_ATTACHED),
432 DPO_PROTO_IP4,
433 &pfx_special.fp_addr,
434 sw_if_index,
435 /* invalid FIB index */
436 ~0,
437 1,
438 NULL,
439 FIB_ROUTE_PATH_FLAG_NONE);
440 }
441}
442
443static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444ip4_add_interface_routes (u32 sw_if_index,
445 ip4_main_t * im, u32 fib_index,
446 ip_interface_address_t * a)
447{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500448 ip_lookup_main_t *lm = &im->lookup_main;
449 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100450 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500451 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 .fp_proto = FIB_PROTOCOL_IP4,
453 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500456 /* set special routes for the prefix if needed */
457 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100458
459 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100461 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500462 lm->classify_table_index_by_sw_if_index[sw_if_index];
463 if (classify_table_index != (u32) ~ 0)
464 {
465 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467 dpo_set (&dpo,
468 DPO_CLASSIFY,
469 DPO_PROTO_IP4,
470 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100471
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 fib_table_entry_special_dpo_add (fib_index,
473 &pfx,
474 FIB_SOURCE_CLASSIFY,
475 FIB_ENTRY_FLAG_NONE, &dpo);
476 dpo_reset (&dpo);
477 }
478 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100479
Neale Ranns32e1c012016-11-22 17:07:28 +0000480 fib_table_entry_update_one_path (fib_index, &pfx,
481 FIB_SOURCE_INTERFACE,
482 (FIB_ENTRY_FLAG_CONNECTED |
483 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700484 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000485 &pfx.fp_addr,
486 sw_if_index,
487 // invalid FIB index
488 ~0,
489 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500490 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491}
492
493static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500494ip4_del_interface_prefix_routes (ip4_main_t * im,
495 u32 sw_if_index,
496 u32 fib_index,
497 ip4_address_t * address,
498 u32 address_length)
499{
500 ip_lookup_main_t *lm = &im->lookup_main;
501 ip_interface_prefix_t *if_prefix;
502
503 ip_interface_prefix_key_t key = {
504 .prefix = {
505 .fp_len = address_length,
506 .fp_proto = FIB_PROTOCOL_IP4,
507 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
508 },
509 .sw_if_index = sw_if_index,
510 };
511
512 fib_prefix_t pfx_special = {
513 .fp_len = 32,
514 .fp_proto = FIB_PROTOCOL_IP4,
515 };
516
517 if_prefix = ip_get_interface_prefix (lm, &key);
518 if (!if_prefix)
519 {
520 clib_warning ("Prefix not found while deleting %U",
521 format_ip4_address_and_length, address, address_length);
522 return;
523 }
524
525 if_prefix->ref_count -= 1;
526
527 /*
Neale Rannse2fe0972020-11-26 08:37:27 +0000528 * Routes need to be adjusted if deleting last intf addr in prefix
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500529 *
530 * We're done now otherwise
531 */
Neale Rannse2fe0972020-11-26 08:37:27 +0000532 if (if_prefix->ref_count > 0)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500533 return;
534
535 /* length <= 30, delete glean route, first address, last address */
536 if (address_length <= 30)
537 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000538 /* Less work to do in FIB if we remove the covered /32s first */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500539
Neale Rannse2fe0972020-11-26 08:37:27 +0000540 /* first address in prefix */
541 pfx_special.fp_addr.ip4.as_u32 =
542 address->as_u32 & im->fib_masks[address_length];
543 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500544
Neale Rannse2fe0972020-11-26 08:37:27 +0000545 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
546 fib_table_entry_special_remove (fib_index,
547 &pfx_special,
548 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500549
Neale Rannse2fe0972020-11-26 08:37:27 +0000550 /* prefix broadcast address */
551 pfx_special.fp_addr.ip4.as_u32 =
552 address->as_u32 | ~im->fib_masks[address_length];
553 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500554
Neale Rannse2fe0972020-11-26 08:37:27 +0000555 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
556 fib_table_entry_special_remove (fib_index,
557 &pfx_special,
558 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500559 }
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500560 else if (address_length == 31)
561 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000562 /* length == 31, delete attached route for the other address */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500563 pfx_special.fp_addr.ip4.as_u32 =
564 address->as_u32 ^ clib_host_to_net_u32(1);
565
566 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
567 }
568
Neale Rannse2fe0972020-11-26 08:37:27 +0000569 /* remove glean route for prefix */
570 pfx_special.fp_addr.ip4 = *address;
571 pfx_special.fp_len = address_length;
572 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
573
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500574 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
575 pool_put (lm->if_prefix_pool, if_prefix);
576}
577
578static void
579ip4_del_interface_routes (u32 sw_if_index,
580 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100581 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500582 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700583{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500584 fib_prefix_t pfx = {
Neale Rannse2fe0972020-11-26 08:37:27 +0000585 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500586 .fp_proto = FIB_PROTOCOL_IP4,
587 .fp_addr.ip4 = *address,
588 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700589
Neale Rannse2fe0972020-11-26 08:37:27 +0000590 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
591
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500592 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
593 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700594}
595
Matthew G Smith88d29a92019-07-17 10:01:17 -0500596#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100597void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500598ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100599{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500600 ip4_main_t *im = &ip4_main;
John Lo4a302ee2020-05-12 22:34:39 -0400601 vnet_main_t *vnm = vnet_get_main ();
602 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700603
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100604 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
605
606 /*
607 * enable/disable only on the 1<->0 transition
608 */
609 if (is_enable)
610 {
611 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500612 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100613 }
614 else
615 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500616 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100617 if (0 != --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 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800620 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800621 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100622
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100623
Neale Ranns8269d3d2018-01-30 09:02:20 -0800624 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400625 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000626
John Lo4a302ee2020-05-12 22:34:39 -0400627 if (is_enable)
628 hi->l3_if_count++;
629 else if (hi->l3_if_count)
630 hi->l3_if_count--;
631
Neale Ranns57e53bb2019-05-29 13:58:43 +0000632 {
633 ip4_enable_disable_interface_callback_t *cb;
634 vec_foreach (cb, im->enable_disable_interface_callbacks)
635 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
636 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700638
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639static clib_error_t *
640ip4_add_del_interface_address_internal (vlib_main_t * vm,
641 u32 sw_if_index,
642 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500643 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500645 vnet_main_t *vnm = vnet_get_main ();
646 ip4_main_t *im = &ip4_main;
647 ip_lookup_main_t *lm = &im->lookup_main;
648 clib_error_t *error = 0;
Neale Ranns59f71132020-04-08 12:19:38 +0000649 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500650 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651
Pim van Pelt76b19ce2021-08-10 23:44:44 +0200652 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
653 if (error)
Matthew Smith1b6c7932021-09-24 15:27:36 -0500654 {
655 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
656 return error;
657 }
Pavel Kotucek57808982017-08-02 08:20:19 +0200658
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659 ip4_addr_fib_init (&ip4_af, address,
660 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
661 vec_add1 (addr_fib, ip4_af);
662
Neale Ranns744902e2017-08-14 10:35:44 -0700663 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100664 * there is no support for adj-fib handling in the presence of overlapping
665 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
666 * most routers do.
667 */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500668 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700669 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100670 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700671 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500672 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700673 vnet_sw_interface_t *sif;
674
Damjan Marionb2c31b62020-12-13 21:47:40 +0100675 pool_foreach (sif, vnm->interface_main.sw_interfaces)
676 {
Neale Ranns744902e2017-08-14 10:35:44 -0700677 if (im->fib_index_by_sw_if_index[sw_if_index] ==
678 im->fib_index_by_sw_if_index[sif->sw_if_index])
679 {
680 foreach_ip_interface_address
681 (&im->lookup_main, ia, sif->sw_if_index,
682 0 /* honor unnumbered */ ,
683 ({
684 ip4_address_t * x =
685 ip_interface_address_get_address
686 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000687
Neale Ranns744902e2017-08-14 10:35:44 -0700688 if (ip4_destination_matches_route
689 (im, address, x, ia->address_length) ||
690 ip4_destination_matches_route (im,
691 x,
692 address,
693 address_length))
694 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500695 /* an intf may have >1 addr from the same prefix */
696 if ((sw_if_index == sif->sw_if_index) &&
697 (ia->address_length == address_length) &&
698 (x->as_u32 != address->as_u32))
699 continue;
700
Neale Ranns59f71132020-04-08 12:19:38 +0000701 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
702 /* if the address we're comparing against is stale
703 * then the CP has not added this one back yet, maybe
704 * it never will, so we have to assume it won't and
705 * ignore it. if it does add it back, then it will fail
706 * because this one is now present */
707 continue;
Neale Ranns744902e2017-08-14 10:35:44 -0700708
Neale Ranns59f71132020-04-08 12:19:38 +0000709 /* error if the length or intf was different */
710 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
711
712 error = clib_error_create
Ole Troan33a58172019-09-04 09:12:29 +0200713 ("failed to add %U on %U which conflicts with %U for interface %U",
Neale Ranns744902e2017-08-14 10:35:44 -0700714 format_ip4_address_and_length, address,
715 address_length,
Ole Troan33a58172019-09-04 09:12:29 +0200716 format_vnet_sw_if_index_name, vnm,
717 sw_if_index,
Neale Ranns744902e2017-08-14 10:35:44 -0700718 format_ip4_address_and_length, x,
719 ia->address_length,
720 format_vnet_sw_if_index_name, vnm,
721 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000722 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700723 }
724 }));
725 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100726 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727 }
728
Neale Ranns59f71132020-04-08 12:19:38 +0000729 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700730
Neale Ranns59f71132020-04-08 12:19:38 +0000731 if (is_del)
732 {
733 if (~0 == if_address_index)
734 {
735 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
736 error = clib_error_create ("%U not found for interface %U",
737 lm->format_address_and_length,
738 addr_fib, address_length,
739 format_vnet_sw_if_index_name, vnm,
740 sw_if_index);
741 goto done;
742 }
743
yedgdbd366b2020-05-14 10:51:53 +0800744 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
745 address_length, sw_if_index);
746 if (error)
747 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000748 }
749 else
750 {
751 if (~0 != if_address_index)
752 {
753 ip_interface_address_t *ia;
754
755 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
756
757 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
758 {
759 if (ia->sw_if_index == sw_if_index)
760 {
761 /* re-adding an address during the replace action.
762 * consdier this the update. clear the flag and
763 * we're done */
764 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
765 goto done;
766 }
767 else
768 {
769 /* The prefix is moving from one interface to another.
770 * delete the stale and add the new */
771 ip4_add_del_interface_address_internal (vm,
772 ia->sw_if_index,
773 address,
774 address_length, 1);
775 ia = NULL;
776 error = ip_interface_address_add (lm, sw_if_index,
777 addr_fib, address_length,
778 &if_address_index);
779 }
780 }
781 else
782 {
783 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
784 error = clib_error_create
785 ("Prefix %U already found on interface %U",
786 lm->format_address_and_length, addr_fib, address_length,
787 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
788 }
789 }
790 else
791 error = ip_interface_address_add (lm, sw_if_index,
792 addr_fib, address_length,
793 &if_address_index);
794 }
795
Ed Warnickecb9cada2015-12-08 15:45:58 -0700796 if (error)
797 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400798
Dave Barachd7cb1b52016-12-09 09:52:16 -0500799 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns03c254e2020-03-17 14:25:10 +0000800 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100801
Matthew G Smith88d29a92019-07-17 10:01:17 -0500802 /* intf addr routes are added/deleted on admin up/down */
803 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
804 {
805 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500806 ip4_del_interface_routes (sw_if_index,
807 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500808 address_length);
809 else
810 ip4_add_interface_routes (sw_if_index,
811 im, ip4_af.fib_index,
812 pool_elt_at_index
813 (lm->if_address_pool, if_address_index));
814 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815
Neale Ranns59f71132020-04-08 12:19:38 +0000816 ip4_add_del_interface_address_callback_t *cb;
817 vec_foreach (cb, im->add_del_interface_address_callbacks)
818 cb->function (im, cb->function_opaque, sw_if_index,
819 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700820
Dave Barachd7cb1b52016-12-09 09:52:16 -0500821done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822 vec_free (addr_fib);
823 return error;
824}
825
826clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000827ip4_add_del_interface_address (vlib_main_t * vm,
828 u32 sw_if_index,
829 ip4_address_t * address,
830 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700831{
832 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500833 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834}
835
Neale Ranns1855b8e2018-07-11 10:31:26 -0700836void
837ip4_directed_broadcast (u32 sw_if_index, u8 enable)
838{
839 ip_interface_address_t *ia;
840 ip4_main_t *im;
841
842 im = &ip4_main;
843
844 /*
845 * when directed broadcast is enabled, the subnet braodcast route will forward
846 * packets using an adjacency with a broadcast MAC. otherwise it drops
847 */
Neale Ranns1855b8e2018-07-11 10:31:26 -0700848 foreach_ip_interface_address(&im->lookup_main, ia,
849 sw_if_index, 0,
850 ({
851 if (ia->address_length <= 30)
852 {
853 ip4_address_t *ipa;
854
855 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
856
857 fib_prefix_t pfx = {
858 .fp_len = 32,
859 .fp_proto = FIB_PROTOCOL_IP4,
860 .fp_addr = {
861 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
862 },
863 };
864
865 ip4_add_subnet_bcast_route
866 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
867 sw_if_index),
868 &pfx, sw_if_index);
869 }
870 }));
Neale Ranns1855b8e2018-07-11 10:31:26 -0700871}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200872#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700873
Matthew G Smith88d29a92019-07-17 10:01:17 -0500874static clib_error_t *
875ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
876{
877 ip4_main_t *im = &ip4_main;
878 ip_interface_address_t *ia;
879 ip4_address_t *a;
880 u32 is_admin_up, fib_index;
881
Matthew G Smith88d29a92019-07-17 10:01:17 -0500882 vec_validate_init_empty (im->
883 lookup_main.if_address_pool_index_by_sw_if_index,
884 sw_if_index, ~0);
885
886 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
887
888 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
889
Matthew G Smith88d29a92019-07-17 10:01:17 -0500890 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
891 0 /* honor unnumbered */,
892 ({
893 a = ip_interface_address_get_address (&im->lookup_main, ia);
894 if (is_admin_up)
895 ip4_add_interface_routes (sw_if_index,
896 im, fib_index,
897 ia);
898 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500899 ip4_del_interface_routes (sw_if_index,
900 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500901 a, ia->address_length);
902 }));
Matthew G Smith88d29a92019-07-17 10:01:17 -0500903
904 return 0;
905}
906
907VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
908
Dave Barachd6534602016-06-14 18:38:02 -0400909/* Built-in ip4 unicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100910VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
911{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500912 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100913 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500914 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100915 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
916};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100917
Dave Barachd7cb1b52016-12-09 09:52:16 -0500918VNET_FEATURE_INIT (ip4_flow_classify, static) =
919{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100920 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700921 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100922 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700923};
924
Dave Barachd7cb1b52016-12-09 09:52:16 -0500925VNET_FEATURE_INIT (ip4_inacl, static) =
926{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100927 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400928 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100929 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400930};
931
Dave Barachd7cb1b52016-12-09 09:52:16 -0500932VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
933{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100934 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400935 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100936 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400937};
938
Dave Barachd7cb1b52016-12-09 09:52:16 -0500939VNET_FEATURE_INIT (ip4_policer_classify, static) =
940{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100941 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700942 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100943 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700944};
945
Dave Barachd7cb1b52016-12-09 09:52:16 -0500946VNET_FEATURE_INIT (ip4_ipsec, static) =
947{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100948 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100949 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100950 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400951};
952
Dave Barachd7cb1b52016-12-09 09:52:16 -0500953VNET_FEATURE_INIT (ip4_vpath, static) =
954{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100955 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400956 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500957 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
958};
959
Dave Barachd7cb1b52016-12-09 09:52:16 -0500960VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
961{
John Lo37682e12016-11-30 12:51:39 -0500962 .arc_name = "ip4-unicast",
963 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100964 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400965};
966
Neale Ranns8269d3d2018-01-30 09:02:20 -0800967VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500968{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100969 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800970 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400971 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100972};
973
Neale Ranns180279b2017-03-16 15:49:09 -0400974VNET_FEATURE_INIT (ip4_lookup, static) =
975{
976 .arc_name = "ip4-unicast",
977 .node_name = "ip4-lookup",
978 .runs_before = 0, /* not before any other features */
979};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100980
Dave Barachd6534602016-06-14 18:38:02 -0400981/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100982VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
983{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500984 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100985 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500986 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100987 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
988};
989
Dave Barachd7cb1b52016-12-09 09:52:16 -0500990VNET_FEATURE_INIT (ip4_vpath_mc, static) =
991{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100992 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400993 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000994 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400995};
996
Neale Ranns8269d3d2018-01-30 09:02:20 -0800997VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500998{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100999 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -08001000 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -04001001 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1002};
1003
1004VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1005{
1006 .arc_name = "ip4-multicast",
1007 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001008 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001009};
Dave Barach5331c722016-08-17 11:54:30 -04001010
1011/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001012VNET_FEATURE_ARC_INIT (ip4_output, static) =
1013{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001015 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001016 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001017 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1018};
Dave Barach5331c722016-08-17 11:54:30 -04001019
Dave Barachd7cb1b52016-12-09 09:52:16 -05001020VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1021{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001022 .arc_name = "ip4-output",
1023 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001024 .runs_before = VNET_FEATURES ("ip4-outacl"),
1025};
1026
1027VNET_FEATURE_INIT (ip4_outacl, static) =
1028{
1029 .arc_name = "ip4-output",
1030 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001031 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001032};
1033
Dave Barachd7cb1b52016-12-09 09:52:16 -05001034VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1035{
Matus Fabian08a6f012016-11-15 06:08:51 -08001036 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001037 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001038 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001039};
1040
1041/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042VNET_FEATURE_INIT (ip4_interface_output, static) =
1043{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001044 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001045 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001046 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001047};
Dave Barachd6534602016-06-14 18:38:02 -04001048
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001050ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001052 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001054 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1055 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001056
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001057 if (is_add)
1058 {
1059 /* Fill in lookup tables with default table (0). */
1060 im->fib_index_by_sw_if_index[sw_if_index] = 0;
1061 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1062 }
1063 else
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001064 {
1065 ip4_main_t *im4 = &ip4_main;
1066 ip_lookup_main_t *lm4 = &im4->lookup_main;
1067 ip_interface_address_t *ia = 0;
1068 ip4_address_t *address;
1069 vlib_main_t *vm = vlib_get_main ();
1070
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001071 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001072 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001073 ({
1074 address = ip_interface_address_get_address (lm4, ia);
1075 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1076 }));
Neale Ranns03c254e2020-03-17 14:25:10 +00001077 ip4_mfib_interface_enable_disable (sw_if_index, 0);
Nathan Skrzypczaka424dd12021-08-20 15:53:43 +02001078
1079 if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
1080 fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1081 if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
1082 mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1083
1084 /* Erase the lookup tables just in case */
1085 im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
1086 im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001087 }
1088
Neale Ranns8269d3d2018-01-30 09:02:20 -08001089 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001090 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091
Neale Ranns8269d3d2018-01-30 09:02:20 -08001092 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1093 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095 return /* no error */ 0;
1096}
1097
1098VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1099
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001101#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001103#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001105static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106ip4_lookup_init (vlib_main_t * vm)
1107{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001108 ip4_main_t *im = &ip4_main;
1109 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110 uword i;
1111
Damjan Marion8b3191e2016-11-09 19:54:20 +01001112 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1113 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001114 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1115 return (error);
1116 if ((error = vlib_call_init_function (vm, fib_module_init)))
1117 return error;
1118 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1119 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001120
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1122 {
1123 u32 m;
1124
1125 if (i < 32)
1126 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001127 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128 m = ~0;
1129 im->fib_masks[i] = clib_host_to_net_u32 (m);
1130 }
1131
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1133
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001134 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001135 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1136 FIB_SOURCE_DEFAULT_ROUTE);
1137 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1138 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001139
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001141 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 pn = pg_get_node (ip4_lookup_node.index);
1143 pn->unformat_edit = unformat_pg_ip4_header;
1144 }
1145
1146 {
1147 ethernet_arp_header_t h;
1148
Dave Barachb7b92992018-10-17 10:38:51 -04001149 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1152#define _8(f,v) h.f = v;
1153 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1154 _16 (l3_type, ETHERNET_TYPE_IP4);
1155 _8 (n_l2_address_bytes, 6);
1156 _8 (n_l3_address_bytes, 4);
1157 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1158#undef _16
1159#undef _8
1160
Dave Barachd7cb1b52016-12-09 09:52:16 -05001161 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162 /* data */ &h,
1163 sizeof (h),
1164 /* alloc chunk size */ 8,
1165 "ip4 arp");
1166 }
1167
Dave Barach203c6322016-06-26 10:29:03 -04001168 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169}
1170
1171VLIB_INIT_FUNCTION (ip4_lookup_init);
1172
Dave Barachd7cb1b52016-12-09 09:52:16 -05001173typedef struct
1174{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001176 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177 u32 flow_hash;
1178 u32 fib_index;
1179
1180 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001181 u8 packet_data[64 - 1 * sizeof (u32)];
1182}
1183ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001185#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001186u8 *
1187format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188{
1189 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1190 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001191 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001192 u32 indent = format_get_indent (s);
Vladislav Grishenko302db472024-01-24 16:17:23 +05001193
1194 s = format (s, "%Ufib:%d adj:%d flow:0x%08x", format_white_space, indent,
1195 t->fib_index, t->dpo_index, t->flow_hash);
1196 s = format (s, "\n%U%U", format_white_space, indent, format_ip4_header,
1197 t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001198 return s;
1199}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001200#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001201
Dave Barachd7cb1b52016-12-09 09:52:16 -05001202static u8 *
1203format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001204{
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);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209
John Loac8146c2016-09-27 17:44:02 -04001210 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001212 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001213 format_white_space, indent,
1214 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001215 return s;
1216}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001217
Dave Barachd7cb1b52016-12-09 09:52:16 -05001218static u8 *
1219format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001220{
1221 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1222 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001223 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001224 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001225
Vengada Govindanf1544482016-09-28 02:45:57 -07001226 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001227 t->fib_index, t->dpo_index, format_ip_adjacency,
1228 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001229 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001230 format_white_space, indent,
1231 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001232 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001233 return s;
1234}
1235
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001236#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237/* Common trace function for all ip4-forward next nodes. */
1238void
1239ip4_forward_next_trace (vlib_main_t * vm,
1240 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001241 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001242{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001243 u32 *from, n_left;
1244 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001245
1246 n_left = frame->n_vectors;
1247 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001248
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249 while (n_left >= 4)
1250 {
1251 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001252 vlib_buffer_t *b0, *b1;
1253 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254
1255 /* Prefetch next iteration. */
1256 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1257 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1258
1259 bi0 = from[0];
1260 bi1 = from[1];
1261
1262 b0 = vlib_get_buffer (vm, bi0);
1263 b1 = vlib_get_buffer (vm, bi1);
1264
1265 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1266 {
1267 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001268 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001269 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001270 t0->fib_index =
1271 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1272 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1273 vec_elt (im->fib_index_by_sw_if_index,
1274 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001275
Dave Barach178cf492018-11-13 16:34:13 -05001276 clib_memcpy_fast (t0->packet_data,
1277 vlib_buffer_get_current (b0),
1278 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279 }
1280 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1281 {
1282 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001283 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001284 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001285 t1->fib_index =
1286 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1287 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1288 vec_elt (im->fib_index_by_sw_if_index,
1289 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001290 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1291 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001292 }
1293 from += 2;
1294 n_left -= 2;
1295 }
1296
1297 while (n_left >= 1)
1298 {
1299 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001300 vlib_buffer_t *b0;
1301 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302
1303 bi0 = from[0];
1304
1305 b0 = vlib_get_buffer (vm, bi0);
1306
1307 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1308 {
1309 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001310 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001311 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001312 t0->fib_index =
1313 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1314 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1315 vec_elt (im->fib_index_by_sw_if_index,
1316 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001317 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1318 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001319 }
1320 from += 1;
1321 n_left -= 1;
1322 }
1323}
1324
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325/* Compute TCP/UDP/ICMP4 checksum in software. */
1326u16
1327ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1328 ip4_header_t * ip0)
1329{
1330 ip_csum_t sum0;
1331 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001332
Ed Warnickecb9cada2015-12-08 15:45:58 -07001333 /* Initialize checksum with ip header. */
1334 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001335 payload_length_host_byte_order =
1336 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1337 sum0 =
1338 clib_host_to_net_u32 (payload_length_host_byte_order +
1339 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001340
1341 if (BITS (uword) == 32)
1342 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001343 sum0 =
1344 ip_csum_with_carry (sum0,
1345 clib_mem_unaligned (&ip0->src_address, u32));
1346 sum0 =
1347 ip_csum_with_carry (sum0,
1348 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349 }
1350 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001351 sum0 =
1352 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001353
Srikanth A02833ff2019-10-02 17:48:58 -07001354 return ip_calculate_l4_checksum (vm, p0, sum0,
1355 payload_length_host_byte_order, (u8 *) ip0,
1356 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001357}
1358
John Lo37682e12016-11-30 12:51:39 -05001359u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001360ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1361{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001362 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1363 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364 u16 sum16;
1365
1366 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1367 || ip0->protocol == IP_PROTOCOL_UDP);
1368
1369 udp0 = (void *) (ip0 + 1);
1370 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1371 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001372 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1373 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001374 return p0->flags;
1375 }
1376
1377 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1378
Damjan Marion213b5aa2017-07-13 21:19:27 +02001379 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1380 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001381
1382 return p0->flags;
1383}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001384#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001385
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001386VNET_FEATURE_ARC_INIT (ip4_local) = {
1387 .arc_name = "ip4-local",
1388 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
Dave Baracha25def72018-11-26 11:04:45 -05001389 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001390};
Dave Barach68b0fb02017-02-28 15:15:56 -05001391
Florin Coras20a14b92017-08-15 22:47:22 -07001392static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001393ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1394 ip4_header_t * ip, u8 is_udp, u8 * error,
1395 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001396{
1397 u32 flags0;
1398 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1399 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1400 if (is_udp)
1401 {
1402 udp_header_t *udp;
1403 u32 ip_len, udp_len;
1404 i32 len_diff;
1405 udp = ip4_next_header (ip);
1406 /* Verify UDP length. */
1407 ip_len = clib_net_to_host_u16 (ip->length);
1408 udp_len = clib_net_to_host_u16 (udp->length);
1409
1410 len_diff = ip_len - udp_len;
1411 *good_tcp_udp &= len_diff >= 0;
1412 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1413 }
1414}
1415
Mohsin Kazmi68095382021-02-10 11:26:24 +01001416#define ip4_local_csum_is_offloaded(_b) \
1417 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001418 (vnet_buffer (_b)->oflags & \
Mohsin Kazmi68095382021-02-10 11:26:24 +01001419 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
Florin Coras1b255522018-06-01 12:22:23 -07001420
1421#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1422 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1423 || ip4_local_csum_is_offloaded (_b)))
1424
1425#define ip4_local_csum_is_valid(_b) \
1426 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1427 || (ip4_local_csum_is_offloaded (_b))) != 0
1428
1429static inline void
1430ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1431 ip4_header_t * ih, u8 * error)
1432{
1433 u8 is_udp, is_tcp_udp, good_tcp_udp;
1434
1435 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1436 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1437
1438 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1439 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1440 else
1441 good_tcp_udp = ip4_local_csum_is_valid (b);
1442
1443 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1444 *error = (is_tcp_udp && !good_tcp_udp
1445 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1446}
1447
1448static inline void
1449ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1450 ip4_header_t ** ih, u8 * error)
1451{
1452 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1453
1454 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1455 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1456
1457 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1458 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1459
1460 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1461 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1462
1463 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1464 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1465 {
Mohsin Kazmidd2eff62023-01-16 15:28:26 +00001466 if (is_tcp_udp[0] && !ip4_local_csum_is_offloaded (b[0]))
Florin Coras1b255522018-06-01 12:22:23 -07001467 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1468 &good_tcp_udp[0]);
Mohsin Kazmidd2eff62023-01-16 15:28:26 +00001469 if (is_tcp_udp[1] && !ip4_local_csum_is_offloaded (b[1]))
Florin Coras1b255522018-06-01 12:22:23 -07001470 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1471 &good_tcp_udp[1]);
1472 }
1473
1474 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1475 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1476 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1477 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1478}
1479
1480static inline void
1481ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1482 vlib_buffer_t * b, u16 * next, u8 error,
1483 u8 head_of_feature_arc)
1484{
1485 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1486 u32 next_index;
1487
1488 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1489 b->error = error ? error_node->errors[error] : 0;
1490 if (head_of_feature_arc)
1491 {
1492 next_index = *next;
1493 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1494 {
Florin Corasf8408802021-11-09 18:29:03 -08001495 vnet_feature_arc_start (
1496 arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
Florin Coras1b255522018-06-01 12:22:23 -07001497 *next = next_index;
1498 }
1499 }
1500}
1501
1502typedef struct
1503{
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001504 /* The src and fib-index together determine if packet n is the same as n-1 */
Florin Coras1b255522018-06-01 12:22:23 -07001505 ip4_address_t src;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001506 u32 fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001507 u32 lbi;
1508 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001509 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001510} ip4_local_last_check_t;
1511
1512static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001513ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1514 ip4_local_last_check_t *last_check, u8 *error0,
1515 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001516{
Florin Coras1b255522018-06-01 12:22:23 -07001517 const dpo_id_t *dpo0;
1518 load_balance_t *lb0;
1519 u32 lbi0;
1520
1521 vnet_buffer (b)->ip.fib_index =
1522 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1523 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1524
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001525 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001526 if (is_receive_dpo)
1527 {
1528 receive_dpo_t *rd;
1529 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001530 if (rd->rd_sw_if_index != ~0)
1531 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001532 }
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001533
Matthew Smith44e60462019-07-06 19:27:29 -05001534 /*
1535 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1536 * adjacency for the destination address (the local interface address).
1537 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1538 * adjacency for the source address (the remote sender's address)
1539 */
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001540 if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
1541 (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301542 last_check->first)
Florin Coras1b255522018-06-01 12:22:23 -07001543 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001544 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1545 &ip0->src_address);
Florin Coras1b255522018-06-01 12:22:23 -07001546
Matthew Smith44e60462019-07-06 19:27:29 -05001547 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1548 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001549 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001550
1551 lb0 = load_balance_get (lbi0);
1552 dpo0 = load_balance_get_bucket_i (lb0, 0);
1553
1554 /*
1555 * Must have a route to source otherwise we drop the packet.
1556 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1557 *
1558 * The checks are:
1559 * - the source is a recieve => it's from us => bogus, do this
1560 * first since it sets a different error code.
1561 * - uRPF check for any route to source - accept if passes.
1562 * - allow packets destined to the broadcast address from unknown sources
1563 */
1564
1565 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1566 && dpo0->dpoi_type == DPO_RECEIVE) ?
1567 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1568 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1569 && !fib_urpf_check_size (lb0->lb_urpf)
1570 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1571 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1572
1573 last_check->src.as_u32 = ip0->src_address.as_u32;
1574 last_check->lbi = lbi0;
1575 last_check->error = *error0;
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301576 last_check->first = 0;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001577 last_check->fib_index = vnet_buffer (b)->ip.fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001578 }
1579 else
1580 {
Matthew Smith44e60462019-07-06 19:27:29 -05001581 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1582 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001583 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001584 *error0 = last_check->error;
1585 }
1586}
1587
1588static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001589ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1590 ip4_local_last_check_t *last_check, u8 *error,
1591 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001592{
Florin Coras1b255522018-06-01 12:22:23 -07001593 const dpo_id_t *dpo[2];
1594 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001595 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001596 u32 lbi[2];
1597
Neale Rannsbe2286b2018-12-09 12:54:51 -08001598 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001599 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1600 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1601
1602 vnet_buffer (b[0])->ip.fib_index =
1603 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1604 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1605 vnet_buffer (b[0])->ip.fib_index;
1606
1607 vnet_buffer (b[1])->ip.fib_index =
1608 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1609 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1610 vnet_buffer (b[1])->ip.fib_index;
1611
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001612 not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
1613 not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
1614
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001615 vnet_buffer (b[0])->ip.rx_sw_if_index =
1616 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1617 vnet_buffer (b[1])->ip.rx_sw_if_index =
1618 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001619 if (is_receive_dpo)
1620 {
1621 const receive_dpo_t *rd0, *rd1;
1622 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1623 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001624 if (rd0->rd_sw_if_index != ~0)
1625 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1626 if (rd1->rd_sw_if_index != ~0)
1627 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001628 }
1629
Matthew Smith44e60462019-07-06 19:27:29 -05001630 /*
1631 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1632 * adjacency for the destination address (the local interface address).
1633 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1634 * adjacency for the source address (the remote sender's address)
1635 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301636 if (PREDICT_TRUE (not_last_hit))
Florin Coras1b255522018-06-01 12:22:23 -07001637 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001638 ip4_fib_forwarding_lookup_x2 (
1639 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1640 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001641
Matthew Smith44e60462019-07-06 19:27:29 -05001642 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1643 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001644 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001645
Matthew Smith44e60462019-07-06 19:27:29 -05001646 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1647 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001648 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001649
1650 lb[0] = load_balance_get (lbi[0]);
1651 lb[1] = load_balance_get (lbi[1]);
1652
1653 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1654 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1655
1656 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1657 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1658 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1659 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1660 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1661 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1662 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1663
1664 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1665 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1666 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1667 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1668 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1669 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1670 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1671
1672 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1673 last_check->lbi = lbi[1];
1674 last_check->error = error[1];
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301675 last_check->first = 0;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001676 last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001677 }
1678 else
1679 {
Matthew Smith44e60462019-07-06 19:27:29 -05001680 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1681 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001682 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001683
Matthew Smith44e60462019-07-06 19:27:29 -05001684 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1685 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001686 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001687
1688 error[0] = last_check->error;
1689 error[1] = last_check->error;
1690 }
1691}
Florin Coras20a14b92017-08-15 22:47:22 -07001692
Florin Corasc67cfd22018-10-01 21:59:18 -07001693enum ip_local_packet_type_e
1694{
1695 IP_LOCAL_PACKET_TYPE_L4,
1696 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001697 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001698};
1699
1700/**
1701 * Determine packet type and next node.
1702 *
1703 * The expectation is that all packets that are not L4 will skip
1704 * checksums and source checks.
1705 */
1706always_inline u8
1707ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1708{
1709 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1710
Juraj Sloboda3048b632018-10-02 11:13:53 +02001711 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1712 {
1713 *next = IP_LOCAL_NEXT_REASSEMBLY;
1714 return IP_LOCAL_PACKET_TYPE_FRAG;
1715 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001716 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1717 {
1718 *next = lm->local_next_by_ip_protocol[ip->protocol];
1719 return IP_LOCAL_PACKET_TYPE_NAT;
1720 }
1721
1722 *next = lm->local_next_by_ip_protocol[ip->protocol];
1723 return IP_LOCAL_PACKET_TYPE_L4;
1724}
1725
Dave Barach68b0fb02017-02-28 15:15:56 -05001726static inline uword
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001727ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1728 vlib_frame_t *frame, int head_of_feature_arc,
1729 int is_receive_dpo)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730{
Florin Coras1b255522018-06-01 12:22:23 -07001731 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001732 vlib_node_runtime_t *error_node =
Florin Corasfa2a3162020-02-11 03:01:19 +00001733 vlib_node_get_runtime (vm, ip4_local_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001734 u16 nexts[VLIB_FRAME_SIZE], *next;
1735 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1736 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001737 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001738
1739 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001740 /*
1741 * 0.0.0.0 can appear as the source address of an IP packet,
1742 * as can any other address, hence the need to use the 'first'
1743 * member to make sure the .lbi is initialised for the first
1744 * packet.
1745 */
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001746 .src = { .as_u32 = 0 },
Florin Coras1b255522018-06-01 12:22:23 -07001747 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001748 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1749 .first = 1,
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001750 .fib_index = 0,
Florin Coras1b255522018-06-01 12:22:23 -07001751 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001752
1753 from = vlib_frame_vector_args (frame);
1754 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001755
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756 if (node->flags & VLIB_NODE_FLAG_TRACE)
1757 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1758
Florin Coras1b255522018-06-01 12:22:23 -07001759 vlib_get_buffers (vm, from, bufs, n_left_from);
1760 b = bufs;
1761 next = nexts;
1762
1763 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001765 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766
Florin Coras1b255522018-06-01 12:22:23 -07001767 /* Prefetch next iteration. */
1768 {
1769 vlib_prefetch_buffer_header (b[4], LOAD);
1770 vlib_prefetch_buffer_header (b[5], LOAD);
1771
Damjan Marionaf7fb042021-07-15 11:54:41 +02001772 clib_prefetch_load (b[4]->data);
1773 clib_prefetch_load (b[5]->data);
Florin Coras1b255522018-06-01 12:22:23 -07001774 }
1775
1776 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1777
1778 ip[0] = vlib_buffer_get_current (b[0]);
1779 ip[1] = vlib_buffer_get_current (b[1]);
1780
1781 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1782 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1783
Florin Corasc67cfd22018-10-01 21:59:18 -07001784 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1785 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001786
Florin Corasc67cfd22018-10-01 21:59:18 -07001787 not_batch = pt[0] ^ pt[1];
1788
1789 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001790 goto skip_checks;
1791
1792 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001793 {
Florin Coras1b255522018-06-01 12:22:23 -07001794 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001795 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001796 }
1797 else
1798 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001799 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001800 {
Florin Coras1b255522018-06-01 12:22:23 -07001801 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001802 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1803 is_receive_dpo);
Florin Coras20a14b92017-08-15 22:47:22 -07001804 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001805 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806 {
Florin Coras1b255522018-06-01 12:22:23 -07001807 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001808 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1809 is_receive_dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001810 }
1811 }
1812
Florin Coras1b255522018-06-01 12:22:23 -07001813 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001814
Florin Coras1b255522018-06-01 12:22:23 -07001815 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1816 head_of_feature_arc);
1817 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1818 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001819
Florin Coras1b255522018-06-01 12:22:23 -07001820 b += 2;
1821 next += 2;
1822 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001823 }
1824
Florin Coras1b255522018-06-01 12:22:23 -07001825 while (n_left_from > 0)
1826 {
1827 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1828
1829 ip[0] = vlib_buffer_get_current (b[0]);
1830 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001831 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001832
Florin Corasc67cfd22018-10-01 21:59:18 -07001833 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001834 goto skip_check;
1835
1836 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001837 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1838 is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001839
1840 skip_check:
1841
Florin Coras1b255522018-06-01 12:22:23 -07001842 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1843 head_of_feature_arc);
1844
1845 b += 1;
1846 next += 1;
1847 n_left_from -= 1;
1848 }
1849
1850 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001851 return frame->n_vectors;
1852}
1853
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001854VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1855 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001856{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001857 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1858 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001859}
1860
Neale Ranns32e1c012016-11-22 17:07:28 +00001861VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001862{
Dave Barach68b0fb02017-02-28 15:15:56 -05001863 .name = "ip4-local",
1864 .vector_size = sizeof (u32),
1865 .format_trace = format_ip4_forward_next_trace,
Florin Corasfa2a3162020-02-11 03:01:19 +00001866 .n_errors = IP4_N_ERROR,
Neale Rannse22a7042022-08-09 03:03:29 +00001867 .error_counters = ip4_error_counters,
Dave Barach68b0fb02017-02-28 15:15:56 -05001868 .n_next_nodes = IP_LOCAL_N_NEXT,
1869 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001870 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001871 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1872 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001873 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001874 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera01c1fa42021-12-14 18:25:11 +00001875 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001876 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001877};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001878
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001879VLIB_NODE_FN (ip4_receive_local_node)
1880(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1881{
1882 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1883 1 /* is_receive_dpo */);
1884}
1885
1886VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1887 .name = "ip4-receive",
1888 .vector_size = sizeof (u32),
1889 .format_trace = format_ip4_forward_next_trace,
1890 .sibling_of = "ip4-local"
1891};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001892
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001893VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1894 vlib_node_runtime_t * node,
1895 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001896{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001897 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1898 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001899}
1900
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001901VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001902 .name = "ip4-local-end-of-arc",
1903 .vector_size = sizeof (u32),
1904
1905 .format_trace = format_ip4_forward_next_trace,
1906 .sibling_of = "ip4-local",
1907};
1908
Dave Barach68b0fb02017-02-28 15:15:56 -05001909VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1910 .arc_name = "ip4-local",
1911 .node_name = "ip4-local-end-of-arc",
1912 .runs_before = 0, /* not before any other features */
1913};
Dave Barach68b0fb02017-02-28 15:15:56 -05001914
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001915#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001916void
1917ip4_register_protocol (u32 protocol, u32 node_index)
1918{
1919 vlib_main_t *vm = vlib_get_main ();
1920 ip4_main_t *im = &ip4_main;
1921 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001922
1923 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001924 lm->local_next_by_ip_protocol[protocol] =
1925 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001926}
Neale Rannsb538dd82019-05-21 06:54:54 -07001927
1928void
1929ip4_unregister_protocol (u32 protocol)
1930{
1931 ip4_main_t *im = &ip4_main;
1932 ip_lookup_main_t *lm = &im->lookup_main;
1933
1934 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1935 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1936}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001937#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001938
1939static clib_error_t *
1940show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001941 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001943 ip4_main_t *im = &ip4_main;
1944 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001945 int i;
1946
1947 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001948 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001949 {
1950 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001951 {
1952 u32 node_index = vlib_get_node (vm,
1953 ip4_local_node.index)->
1954 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001955 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1956 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001957 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958 }
1959 return 0;
1960}
1961
1962
1963
Billy McFall0683c9c2016-10-13 08:27:31 -04001964/*?
1965 * Display the set of protocols handled by the local IPv4 stack.
1966 *
1967 * @cliexpar
1968 * Example of how to display local protocol table:
1969 * @cliexstart{show ip local}
1970 * Protocols handled by ip4_local
1971 * 1
1972 * 17
1973 * 47
1974 * @cliexend
1975?*/
Dave Barachd7cb1b52016-12-09 09:52:16 -05001976VLIB_CLI_COMMAND (show_ip_local, static) =
1977{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001978 .path = "show ip local",
1979 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001980 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001981};
1982
Dave Barachd7cb1b52016-12-09 09:52:16 -05001983typedef enum
1984{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001985 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001986 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001987 IP4_REWRITE_NEXT_FRAGMENT,
1988 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001989} ip4_rewrite_next_t;
1990
Neale Ranns889fe942017-06-01 05:43:19 -04001991/**
1992 * This bits of an IPv4 address to mask to construct a multicast
1993 * MAC address
1994 */
1995#if CLIB_ARCH_IS_BIG_ENDIAN
1996#define IP4_MCAST_ADDR_MASK 0x007fffff
1997#else
1998#define IP4_MCAST_ADDR_MASK 0xffff7f00
1999#endif
2000
Ole Troan8a9c8f12018-05-18 11:01:31 +02002001always_inline void
2002ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Ole Troaneb284a12019-10-09 13:33:19 +02002003 u16 adj_packet_bytes, bool df, u16 * next,
2004 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002005{
2006 if (packet_len > adj_packet_bytes)
2007 {
2008 *error = IP4_ERROR_MTU_EXCEEDED;
2009 if (df)
2010 {
2011 icmp4_error_set_vnet_buffer
2012 (b, ICMP4_destination_unreachable,
2013 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2014 adj_packet_bytes);
2015 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2016 }
2017 else
2018 {
Ole Troan313f7e22018-04-10 16:02:51 +02002019 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002020 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00002021 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02002022 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2023 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002024 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002025 }
2026 }
2027}
2028
Neale Ranns0b6a8572019-10-30 17:34:14 +00002029/* increment TTL & update checksum.
2030 Works either endian, so no need for byte swap. */
2031static_always_inline void
2032ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2033{
2034 i32 ttl;
2035 u32 checksum;
2036 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002037 return;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002038
2039 ttl = ip->ttl;
2040
2041 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2042 checksum += checksum >= 0xffff;
2043
2044 ip->checksum = checksum;
2045 ttl += 1;
2046 ip->ttl = ttl;
2047
Aloys Augustin0b77e312022-02-24 15:44:23 +00002048 ASSERT (ip4_header_checksum_is_valid (ip) ||
2049 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2050 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002051}
2052
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002053/* Decrement TTL & update checksum.
2054 Works either endian, so no need for byte swap. */
2055static_always_inline void
2056ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2057 u32 * error)
2058{
2059 i32 ttl;
2060 u32 checksum;
2061 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002062 return;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002063
2064 ttl = ip->ttl;
2065
2066 /* Input node should have reject packets with ttl 0. */
2067 ASSERT (ip->ttl > 0);
2068
2069 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2070 checksum += checksum >= 0xffff;
2071
2072 ip->checksum = checksum;
2073 ttl -= 1;
2074 ip->ttl = ttl;
2075
2076 /*
2077 * If the ttl drops below 1 when forwarding, generate
2078 * an ICMP response.
2079 */
2080 if (PREDICT_FALSE (ttl <= 0))
2081 {
2082 *error = IP4_ERROR_TIME_EXPIRED;
2083 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2084 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2085 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2086 0);
2087 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2088 }
2089
2090 /* Verify checksum. */
Benoît Ganne6e334e32020-08-31 18:59:34 +02002091 ASSERT (ip4_header_checksum_is_valid (ip) ||
Mohsin Kazmi4fd9f102021-06-17 17:29:27 +00002092 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2093 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002094}
2095
Ed Warnickecb9cada2015-12-08 15:45:58 -07002096always_inline uword
Damjan Mariond06e2eb2021-04-21 23:44:40 +02002097ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2098 vlib_frame_t *frame, int do_counters, int is_midchain,
2099 int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002100{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002101 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2102 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002103 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2104 u16 nexts[VLIB_FRAME_SIZE], *next;
2105 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002106 vlib_node_runtime_t *error_node =
2107 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002108
2109 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002110 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002111
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002112 vlib_get_buffers (vm, from, bufs, n_left_from);
2113 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2114
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002115#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002116 if (n_left_from >= 6)
2117 {
2118 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002119 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002120 vlib_prefetch_buffer_header (bufs[i], LOAD);
2121 }
2122
2123 next = nexts;
2124 b = bufs;
2125 while (n_left_from >= 8)
2126 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002127 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002128 ip4_header_t *ip0, *ip1;
2129 u32 rw_len0, error0, adj_index0;
2130 u32 rw_len1, error1, adj_index1;
2131 u32 tx_sw_if_index0, tx_sw_if_index1;
2132 u8 *p;
2133
PiotrX Kleskib801cd12020-12-09 14:32:26 +01002134 if (is_midchain)
2135 {
2136 vlib_prefetch_buffer_header (b[6], LOAD);
2137 vlib_prefetch_buffer_header (b[7], LOAD);
2138 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002139
2140 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2141 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2142
2143 /*
2144 * pre-fetch the per-adjacency counters
2145 */
2146 if (do_counters)
2147 {
2148 vlib_prefetch_combined_counter (&adjacency_counters,
2149 thread_index, adj_index0);
2150 vlib_prefetch_combined_counter (&adjacency_counters,
2151 thread_index, adj_index1);
2152 }
2153
2154 ip0 = vlib_buffer_get_current (b[0]);
2155 ip1 = vlib_buffer_get_current (b[1]);
2156
2157 error0 = error1 = IP4_ERROR_NONE;
2158
2159 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2160 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2161
2162 /* Rewrite packet header and updates lengths. */
2163 adj0 = adj_get (adj_index0);
2164 adj1 = adj_get (adj_index1);
2165
2166 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2167 rw_len0 = adj0[0].rewrite_header.data_bytes;
2168 rw_len1 = adj1[0].rewrite_header.data_bytes;
2169 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2170 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2171
2172 p = vlib_buffer_get_current (b[2]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002173 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2174 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002175
2176 p = vlib_buffer_get_current (b[3]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002177 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2178 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002179
2180 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002181 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2182 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2183
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002184 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002185 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002186 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002187 ip1_len = gso_mtu_sz (b[1]);
2188
2189 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002190 adj0[0].rewrite_header.max_l3_packet_bytes,
2191 ip0->flags_and_fragment_offset &
2192 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002193 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002194 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002195 adj1[0].rewrite_header.max_l3_packet_bytes,
2196 ip1->flags_and_fragment_offset &
2197 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002198 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002199
2200 if (is_mcast)
2201 {
2202 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2203 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2204 IP4_ERROR_SAME_INTERFACE : error0);
2205 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2206 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2207 IP4_ERROR_SAME_INTERFACE : error1);
2208 }
2209
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002210 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002211 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002212 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2213 {
2214 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002215 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002216
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002217 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2218 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2219
2220 if (PREDICT_FALSE
2221 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002222 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2223 tx_sw_if_index0,
2224 &next_index, b[0],
2225 adj0->ia_cfg_index);
2226
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002227 next[0] = next_index;
2228 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002229 else
2230 {
2231 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002232 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2233 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002234 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002235 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2236 {
2237 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002238 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002239
2240 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2241 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2242
2243 if (PREDICT_FALSE
2244 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002245 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2246 tx_sw_if_index1,
2247 &next_index, b[1],
2248 adj1->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002249 next[1] = next_index;
2250 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002251 else
2252 {
2253 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002254 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2255 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002256 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002257
Neale Ranns4ec36c52020-03-31 09:21:29 -04002258 if (is_midchain)
2259 /* Guess we are only writing on ipv4 header. */
2260 vnet_rewrite_two_headers (adj0[0], adj1[0],
2261 ip0, ip1, sizeof (ip4_header_t));
2262 else
2263 /* Guess we are only writing on simple Ethernet header. */
2264 vnet_rewrite_two_headers (adj0[0], adj1[0],
2265 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002266
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002267 if (do_counters)
2268 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002269 if (error0 == IP4_ERROR_NONE)
2270 vlib_increment_combined_counter
2271 (&adjacency_counters,
2272 thread_index,
2273 adj_index0, 1,
2274 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002275
Neale Ranns0b6a8572019-10-30 17:34:14 +00002276 if (error1 == IP4_ERROR_NONE)
2277 vlib_increment_combined_counter
2278 (&adjacency_counters,
2279 thread_index,
2280 adj_index1, 1,
2281 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002282 }
2283
2284 if (is_midchain)
2285 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002286 if (error0 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002287 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns4ec36c52020-03-31 09:21:29 -04002288 if (error1 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002289 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002290 }
2291
2292 if (is_mcast)
2293 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002294 /* copy bytes from the IP address into the MAC rewrite */
2295 if (error0 == IP4_ERROR_NONE)
2296 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2297 adj0->rewrite_header.dst_mcast_offset,
2298 &ip0->dst_address.as_u32, (u8 *) ip0);
2299 if (error1 == IP4_ERROR_NONE)
2300 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2301 adj1->rewrite_header.dst_mcast_offset,
2302 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002303 }
2304
2305 next += 2;
2306 b += 2;
2307 n_left_from -= 2;
2308 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002309#elif (CLIB_N_PREFETCHES >= 4)
2310 next = nexts;
2311 b = bufs;
2312 while (n_left_from >= 1)
2313 {
2314 ip_adjacency_t *adj0;
2315 ip4_header_t *ip0;
2316 u32 rw_len0, error0, adj_index0;
2317 u32 tx_sw_if_index0;
2318 u8 *p;
2319
2320 /* Prefetch next iteration */
2321 if (PREDICT_TRUE (n_left_from >= 4))
2322 {
2323 ip_adjacency_t *adj2;
2324 u32 adj_index2;
2325
2326 vlib_prefetch_buffer_header (b[3], LOAD);
2327 vlib_prefetch_buffer_data (b[2], LOAD);
2328
2329 /* Prefetch adj->rewrite_header */
2330 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2331 adj2 = adj_get (adj_index2);
2332 p = (u8 *) adj2;
2333 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2334 LOAD);
2335 }
2336
2337 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2338
2339 /*
2340 * Prefetch the per-adjacency counters
2341 */
2342 if (do_counters)
2343 {
2344 vlib_prefetch_combined_counter (&adjacency_counters,
2345 thread_index, adj_index0);
2346 }
2347
2348 ip0 = vlib_buffer_get_current (b[0]);
2349
2350 error0 = IP4_ERROR_NONE;
2351
2352 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2353
2354 /* Rewrite packet header and updates lengths. */
2355 adj0 = adj_get (adj_index0);
2356
2357 /* Rewrite header was prefetched. */
2358 rw_len0 = adj0[0].rewrite_header.data_bytes;
2359 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2360
2361 /* Check MTU of outgoing interface. */
2362 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2363
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002364 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002365 ip0_len = gso_mtu_sz (b[0]);
2366
2367 ip4_mtu_check (b[0], ip0_len,
2368 adj0[0].rewrite_header.max_l3_packet_bytes,
2369 ip0->flags_and_fragment_offset &
2370 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002371 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002372
2373 if (is_mcast)
2374 {
2375 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2376 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2377 IP4_ERROR_SAME_INTERFACE : error0);
2378 }
2379
2380 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2381 * to see the IP header */
2382 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2383 {
2384 u32 next_index = adj0[0].rewrite_header.next_index;
2385 vlib_buffer_advance (b[0], -(word) rw_len0);
2386 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2387 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2388
2389 if (PREDICT_FALSE
2390 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002391 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2392 tx_sw_if_index0,
2393 &next_index, b[0],
2394 adj0->ia_cfg_index);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002395 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002396
2397 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002398 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002399 /* Guess we are only writing on ipv4 header. */
2400 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2401 }
2402 else
2403 /* Guess we are only writing on simple Ethernet header. */
2404 vnet_rewrite_one_header (adj0[0], ip0,
2405 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002406
2407 /*
2408 * Bump the per-adjacency counters
2409 */
2410 if (do_counters)
2411 vlib_increment_combined_counter
2412 (&adjacency_counters,
2413 thread_index,
2414 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2415 b[0]) + rw_len0);
2416
Neale Ranns4ec36c52020-03-31 09:21:29 -04002417 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002418 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002419
2420 if (is_mcast)
2421 /* copy bytes from the IP address into the MAC rewrite */
2422 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2423 adj0->rewrite_header.dst_mcast_offset,
2424 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002425 }
2426 else
2427 {
2428 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002429 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2430 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002431 }
2432
2433 next += 1;
2434 b += 1;
2435 n_left_from -= 1;
2436 }
2437#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002438
Ed Warnickecb9cada2015-12-08 15:45:58 -07002439 while (n_left_from > 0)
2440 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002441 ip_adjacency_t *adj0;
2442 ip4_header_t *ip0;
2443 u32 rw_len0, adj_index0, error0;
2444 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002445
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002446 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2447
2448 adj0 = adj_get (adj_index0);
2449
2450 if (do_counters)
2451 vlib_prefetch_combined_counter (&adjacency_counters,
2452 thread_index, adj_index0);
2453
2454 ip0 = vlib_buffer_get_current (b[0]);
2455
2456 error0 = IP4_ERROR_NONE;
2457
2458 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2459
2460
2461 /* Update packet buffer attributes/set output interface. */
2462 rw_len0 = adj0[0].rewrite_header.data_bytes;
2463 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2464
2465 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002466 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002467 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002468 ip0_len = gso_mtu_sz (b[0]);
2469
2470 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002471 adj0[0].rewrite_header.max_l3_packet_bytes,
2472 ip0->flags_and_fragment_offset &
2473 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002474 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002475
2476 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002477 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002478 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2479 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2480 IP4_ERROR_SAME_INTERFACE : error0);
2481 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002482
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002483 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002484 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002485 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2486 {
2487 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002488 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002489 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2490 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002491
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002492 if (PREDICT_FALSE
2493 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002494 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2495 tx_sw_if_index0,
2496 &next_index, b[0],
2497 adj0->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002498 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002499
2500 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002501 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002502 /* Guess we are only writing on ipv4 header. */
2503 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2504 }
2505 else
2506 /* Guess we are only writing on simple Ethernet header. */
2507 vnet_rewrite_one_header (adj0[0], ip0,
2508 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002509
2510 if (do_counters)
2511 vlib_increment_combined_counter
2512 (&adjacency_counters,
2513 thread_index, adj_index0, 1,
2514 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2515
Neale Rannse2fe0972020-11-26 08:37:27 +00002516 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002517 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002518
2519 if (is_mcast)
2520 /* copy bytes from the IP address into the MAC rewrite */
2521 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2522 adj0->rewrite_header.dst_mcast_offset,
2523 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002524 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002525 else
2526 {
2527 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002528 /* undo the TTL decrement - we'll be back to do it again */
2529 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2530 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002531 }
2532
2533 next += 1;
2534 b += 1;
2535 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002536 }
2537
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002538
Ed Warnickecb9cada2015-12-08 15:45:58 -07002539 /* Need to do trace after rewrites to pick up new packet data. */
2540 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002541 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002542
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002543 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002544 return frame->n_vectors;
2545}
2546
Neale Rannsf06aea52016-11-29 06:51:37 -08002547/** @brief IPv4 rewrite node.
2548 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002549
2550 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2551 header checksum, fetch the ip adjacency, check the outbound mtu,
2552 apply the adjacency rewrite, and send pkts to the adjacency
2553 rewrite header's rewrite_next_index.
2554
2555 @param vm vlib_main_t corresponding to the current thread
2556 @param node vlib_node_runtime_t
2557 @param frame vlib_frame_t whose contents should be dispatched
2558
2559 @par Graph mechanics: buffer metadata, next index usage
2560
2561 @em Uses:
2562 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2563 - the rewrite adjacency index
2564 - <code>adj->lookup_next_index</code>
2565 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002566 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002567 - <code>adj->rewrite_header</code>
2568 - Rewrite string length, rewrite string, next_index
2569
2570 @em Sets:
2571 - <code>b->current_data, b->current_length</code>
2572 - Updated net of applying the rewrite string
2573
2574 <em>Next Indices:</em>
2575 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002576 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002577*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002578
2579VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2580 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002581{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002582 if (adj_are_counters_enabled ())
2583 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2584 else
2585 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586}
2587
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002588VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2589 vlib_node_runtime_t * node,
2590 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002591{
2592 if (adj_are_counters_enabled ())
2593 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2594 else
2595 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2596}
2597
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002598VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2599 vlib_node_runtime_t * node,
2600 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002601{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002602 if (adj_are_counters_enabled ())
2603 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2604 else
2605 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002606}
2607
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002608VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2609 vlib_node_runtime_t * node,
2610 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002611{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002612 if (adj_are_counters_enabled ())
2613 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2614 else
2615 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002616}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002617
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002618VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2619 vlib_node_runtime_t * node,
2620 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002621{
2622 if (adj_are_counters_enabled ())
2623 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2624 else
2625 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2626}
2627
Neale Ranns32e1c012016-11-22 17:07:28 +00002628VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002629 .name = "ip4-rewrite",
2630 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002631
Neale Ranns32e1c012016-11-22 17:07:28 +00002632 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002633
Ole Troan313f7e22018-04-10 16:02:51 +02002634 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002635 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002636 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002637 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002638 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002639 },
2640};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002641
2642VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002643 .name = "ip4-rewrite-bcast",
2644 .vector_size = sizeof (u32),
2645
2646 .format_trace = format_ip4_rewrite_trace,
2647 .sibling_of = "ip4-rewrite",
2648};
Neale Ranns32e1c012016-11-22 17:07:28 +00002649
2650VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002651 .name = "ip4-rewrite-mcast",
2652 .vector_size = sizeof (u32),
2653
2654 .format_trace = format_ip4_rewrite_trace,
2655 .sibling_of = "ip4-rewrite",
2656};
Neale Ranns32e1c012016-11-22 17:07:28 +00002657
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002658VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002659 .name = "ip4-mcast-midchain",
2660 .vector_size = sizeof (u32),
2661
2662 .format_trace = format_ip4_rewrite_trace,
2663 .sibling_of = "ip4-rewrite",
2664};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002665
Neale Ranns32e1c012016-11-22 17:07:28 +00002666VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002667 .name = "ip4-midchain",
2668 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002669 .format_trace = format_ip4_rewrite_trace,
2670 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002671};
Damjan Marion1c80e832016-05-11 23:07:18 +02002672
Ed Warnickecb9cada2015-12-08 15:45:58 -07002673static clib_error_t *
2674set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002675 unformat_input_t * input,
2676 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677{
2678 int matched = 0;
2679 u32 table_id = 0;
2680 u32 flow_hash_config = 0;
2681 int rv;
2682
Dave Barachd7cb1b52016-12-09 09:52:16 -05002683 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2684 {
2685 if (unformat (input, "table %d", &table_id))
2686 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002687#define _(a, b, v) \
2688 else if (unformat (input, #a)) \
2689 { \
2690 flow_hash_config |= v; \
2691 matched = 1; \
2692 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002693 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002694#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002695 else
2696 break;
2697 }
Dave Barach75fc8542016-10-11 16:16:02 -04002698
Ed Warnickecb9cada2015-12-08 15:45:58 -07002699 if (matched == 0)
2700 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002701 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002702
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002703 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002704 switch (rv)
2705 {
2706 case 0:
2707 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002708
Ed Warnickecb9cada2015-12-08 15:45:58 -07002709 case VNET_API_ERROR_NO_SUCH_FIB:
2710 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002711
Ed Warnickecb9cada2015-12-08 15:45:58 -07002712 default:
2713 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2714 break;
2715 }
Dave Barach75fc8542016-10-11 16:16:02 -04002716
Ed Warnickecb9cada2015-12-08 15:45:58 -07002717 return 0;
2718}
Dave Barach75fc8542016-10-11 16:16:02 -04002719
Billy McFall0683c9c2016-10-13 08:27:31 -04002720/*?
2721 * Configure the set of IPv4 fields used by the flow hash.
2722 *
2723 * @cliexpar
2724 * Example of how to set the flow hash on a given table:
2725 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2726 * Example of display the configured flow hash:
2727 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002728 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2729 * 0.0.0.0/0
2730 * unicast-ip4-chain
2731 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2732 * [0] [@0]: dpo-drop ip6
2733 * 0.0.0.0/32
2734 * unicast-ip4-chain
2735 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2736 * [0] [@0]: dpo-drop ip6
2737 * 224.0.0.0/8
2738 * unicast-ip4-chain
2739 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2740 * [0] [@0]: dpo-drop ip6
2741 * 6.0.1.2/32
2742 * unicast-ip4-chain
2743 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2744 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2745 * 7.0.0.1/32
2746 * unicast-ip4-chain
2747 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2748 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2749 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2750 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2751 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2752 * 240.0.0.0/8
2753 * unicast-ip4-chain
2754 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2755 * [0] [@0]: dpo-drop ip6
2756 * 255.255.255.255/32
2757 * unicast-ip4-chain
2758 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2759 * [0] [@0]: dpo-drop ip6
2760 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2761 * 0.0.0.0/0
2762 * unicast-ip4-chain
2763 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2764 * [0] [@0]: dpo-drop ip6
2765 * 0.0.0.0/32
2766 * unicast-ip4-chain
2767 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2768 * [0] [@0]: dpo-drop ip6
2769 * 172.16.1.0/24
2770 * unicast-ip4-chain
2771 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2772 * [0] [@4]: ipv4-glean: af_packet0
2773 * 172.16.1.1/32
2774 * unicast-ip4-chain
2775 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2776 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2777 * 172.16.1.2/32
2778 * unicast-ip4-chain
2779 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2780 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2781 * 172.16.2.0/24
2782 * unicast-ip4-chain
2783 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2784 * [0] [@4]: ipv4-glean: af_packet1
2785 * 172.16.2.1/32
2786 * unicast-ip4-chain
2787 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2788 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2789 * 224.0.0.0/8
2790 * unicast-ip4-chain
2791 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2792 * [0] [@0]: dpo-drop ip6
2793 * 240.0.0.0/8
2794 * unicast-ip4-chain
2795 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2796 * [0] [@0]: dpo-drop ip6
2797 * 255.255.255.255/32
2798 * unicast-ip4-chain
2799 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2800 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002801 * @cliexend
2802?*/
Takeru Hayasakab23c6f42023-01-17 04:45:58 +09002803VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002804 .path = "set ip flow-hash",
Takeru Hayasakab23c6f42023-01-17 04:45:58 +09002805 .short_help = "set ip flow-hash table <table-id> [src] [dst] [sport] "
2806 "[dport] [proto] [reverse] [gtpv1teid]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002807 .function = set_ip_flow_hash_command_fn,
2808};
Dave Barach75fc8542016-10-11 16:16:02 -04002809
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002810#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002811int
2812vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2813 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002814{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002815 vnet_main_t *vnm = vnet_get_main ();
2816 vnet_interface_main_t *im = &vnm->interface_main;
2817 ip4_main_t *ipm = &ip4_main;
2818 ip_lookup_main_t *lm = &ipm->lookup_main;
2819 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002820 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002821
2822 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2823 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2824
2825 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2826 return VNET_API_ERROR_NO_SUCH_ENTRY;
2827
2828 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002829 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002830
Neale Rannsdf089a82016-10-02 16:39:06 +01002831 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2832
2833 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002834 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002835 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002836 .fp_len = 32,
2837 .fp_proto = FIB_PROTOCOL_IP4,
2838 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002839 };
2840 u32 fib_index;
2841
Dave Barachd7cb1b52016-12-09 09:52:16 -05002842 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2843 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002844
2845
Dave Barachd7cb1b52016-12-09 09:52:16 -05002846 if (table_index != (u32) ~ 0)
2847 {
2848 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002849
Dave Barachd7cb1b52016-12-09 09:52:16 -05002850 dpo_set (&dpo,
2851 DPO_CLASSIFY,
2852 DPO_PROTO_IP4,
2853 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002854
Dave Barachd7cb1b52016-12-09 09:52:16 -05002855 fib_table_entry_special_dpo_add (fib_index,
2856 &pfx,
2857 FIB_SOURCE_CLASSIFY,
2858 FIB_ENTRY_FLAG_NONE, &dpo);
2859 dpo_reset (&dpo);
2860 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002861 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002862 {
2863 fib_table_entry_special_remove (fib_index,
2864 &pfx, FIB_SOURCE_CLASSIFY);
2865 }
2866 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002867
Ed Warnickecb9cada2015-12-08 15:45:58 -07002868 return 0;
2869}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002870#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002871
2872static clib_error_t *
2873set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002874 unformat_input_t * input,
2875 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002876{
2877 u32 table_index = ~0;
2878 int table_index_set = 0;
2879 u32 sw_if_index = ~0;
2880 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002881
Dave Barachd7cb1b52016-12-09 09:52:16 -05002882 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2883 {
2884 if (unformat (input, "table-index %d", &table_index))
2885 table_index_set = 1;
2886 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2887 vnet_get_main (), &sw_if_index))
2888 ;
2889 else
2890 break;
2891 }
Dave Barach75fc8542016-10-11 16:16:02 -04002892
Ed Warnickecb9cada2015-12-08 15:45:58 -07002893 if (table_index_set == 0)
2894 return clib_error_return (0, "classify table-index must be specified");
2895
2896 if (sw_if_index == ~0)
2897 return clib_error_return (0, "interface / subif must be specified");
2898
2899 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2900
2901 switch (rv)
2902 {
2903 case 0:
2904 break;
2905
2906 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2907 return clib_error_return (0, "No such interface");
2908
2909 case VNET_API_ERROR_NO_SUCH_ENTRY:
2910 return clib_error_return (0, "No such classifier table");
2911 }
2912 return 0;
2913}
2914
Billy McFall0683c9c2016-10-13 08:27:31 -04002915/*?
2916 * Assign a classification table to an interface. The classification
2917 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2918 * commands. Once the table is create, use this command to filter packets
2919 * on an interface.
2920 *
2921 * @cliexpar
2922 * Example of how to assign a classification table to an interface:
2923 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2924?*/
Dave Barachd7cb1b52016-12-09 09:52:16 -05002925VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2926{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002927 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002928 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002929 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002930 .function = set_ip_classify_command_fn,
2931};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002932
2933/*
2934 * fd.io coding-style-patch-verification: ON
2935 *
2936 * Local Variables:
2937 * eval: (c-set-style "gnu")
2938 * End:
2939 */