blob: e85c888f6695a0b4c58c6d9f8a66728332f3bdc2 [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);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001193 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001194 format_white_space, indent,
1195 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001196 return s;
1197}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001198#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001199
Dave Barachd7cb1b52016-12-09 09:52:16 -05001200static u8 *
1201format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001202{
1203 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1204 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001205 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001206 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001207
John Loac8146c2016-09-27 17:44:02 -04001208 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001209 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001210 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 format_white_space, indent,
1212 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001213 return s;
1214}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001215
Dave Barachd7cb1b52016-12-09 09:52:16 -05001216static u8 *
1217format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001218{
1219 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1220 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001221 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001222 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223
Vengada Govindanf1544482016-09-28 02:45:57 -07001224 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001225 t->fib_index, t->dpo_index, format_ip_adjacency,
1226 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001227 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001228 format_white_space, indent,
1229 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001230 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231 return s;
1232}
1233
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001234#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001235/* Common trace function for all ip4-forward next nodes. */
1236void
1237ip4_forward_next_trace (vlib_main_t * vm,
1238 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001239 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001240{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001241 u32 *from, n_left;
1242 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243
1244 n_left = frame->n_vectors;
1245 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001246
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 while (n_left >= 4)
1248 {
1249 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001250 vlib_buffer_t *b0, *b1;
1251 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001252
1253 /* Prefetch next iteration. */
1254 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1255 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1256
1257 bi0 = from[0];
1258 bi1 = from[1];
1259
1260 b0 = vlib_get_buffer (vm, bi0);
1261 b1 = vlib_get_buffer (vm, bi1);
1262
1263 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1264 {
1265 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001266 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001268 t0->fib_index =
1269 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1270 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1271 vec_elt (im->fib_index_by_sw_if_index,
1272 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001273
Dave Barach178cf492018-11-13 16:34:13 -05001274 clib_memcpy_fast (t0->packet_data,
1275 vlib_buffer_get_current (b0),
1276 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277 }
1278 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1279 {
1280 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001281 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001283 t1->fib_index =
1284 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1285 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1286 vec_elt (im->fib_index_by_sw_if_index,
1287 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001288 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1289 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290 }
1291 from += 2;
1292 n_left -= 2;
1293 }
1294
1295 while (n_left >= 1)
1296 {
1297 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001298 vlib_buffer_t *b0;
1299 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001300
1301 bi0 = from[0];
1302
1303 b0 = vlib_get_buffer (vm, bi0);
1304
1305 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1306 {
1307 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001308 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001309 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001310 t0->fib_index =
1311 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1312 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1313 vec_elt (im->fib_index_by_sw_if_index,
1314 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001315 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1316 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001317 }
1318 from += 1;
1319 n_left -= 1;
1320 }
1321}
1322
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323/* Compute TCP/UDP/ICMP4 checksum in software. */
1324u16
1325ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1326 ip4_header_t * ip0)
1327{
1328 ip_csum_t sum0;
1329 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001330
Ed Warnickecb9cada2015-12-08 15:45:58 -07001331 /* Initialize checksum with ip header. */
1332 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001333 payload_length_host_byte_order =
1334 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1335 sum0 =
1336 clib_host_to_net_u32 (payload_length_host_byte_order +
1337 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338
1339 if (BITS (uword) == 32)
1340 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001341 sum0 =
1342 ip_csum_with_carry (sum0,
1343 clib_mem_unaligned (&ip0->src_address, u32));
1344 sum0 =
1345 ip_csum_with_carry (sum0,
1346 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001347 }
1348 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001349 sum0 =
1350 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351
Srikanth A02833ff2019-10-02 17:48:58 -07001352 return ip_calculate_l4_checksum (vm, p0, sum0,
1353 payload_length_host_byte_order, (u8 *) ip0,
1354 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001355}
1356
John Lo37682e12016-11-30 12:51:39 -05001357u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001358ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1359{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001360 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1361 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362 u16 sum16;
1363
1364 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1365 || ip0->protocol == IP_PROTOCOL_UDP);
1366
1367 udp0 = (void *) (ip0 + 1);
1368 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1369 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001370 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1371 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372 return p0->flags;
1373 }
1374
1375 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1376
Damjan Marion213b5aa2017-07-13 21:19:27 +02001377 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1378 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001379
1380 return p0->flags;
1381}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001382#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001383
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001384VNET_FEATURE_ARC_INIT (ip4_local) = {
1385 .arc_name = "ip4-local",
1386 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
Dave Baracha25def72018-11-26 11:04:45 -05001387 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001388};
Dave Barach68b0fb02017-02-28 15:15:56 -05001389
Florin Coras20a14b92017-08-15 22:47:22 -07001390static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001391ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1392 ip4_header_t * ip, u8 is_udp, u8 * error,
1393 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001394{
1395 u32 flags0;
1396 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1397 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1398 if (is_udp)
1399 {
1400 udp_header_t *udp;
1401 u32 ip_len, udp_len;
1402 i32 len_diff;
1403 udp = ip4_next_header (ip);
1404 /* Verify UDP length. */
1405 ip_len = clib_net_to_host_u16 (ip->length);
1406 udp_len = clib_net_to_host_u16 (udp->length);
1407
1408 len_diff = ip_len - udp_len;
1409 *good_tcp_udp &= len_diff >= 0;
1410 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1411 }
1412}
1413
Mohsin Kazmi68095382021-02-10 11:26:24 +01001414#define ip4_local_csum_is_offloaded(_b) \
1415 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001416 (vnet_buffer (_b)->oflags & \
Mohsin Kazmi68095382021-02-10 11:26:24 +01001417 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
Florin Coras1b255522018-06-01 12:22:23 -07001418
1419#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1420 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1421 || ip4_local_csum_is_offloaded (_b)))
1422
1423#define ip4_local_csum_is_valid(_b) \
1424 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1425 || (ip4_local_csum_is_offloaded (_b))) != 0
1426
1427static inline void
1428ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1429 ip4_header_t * ih, u8 * error)
1430{
1431 u8 is_udp, is_tcp_udp, good_tcp_udp;
1432
1433 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1434 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1435
1436 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1437 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1438 else
1439 good_tcp_udp = ip4_local_csum_is_valid (b);
1440
1441 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1442 *error = (is_tcp_udp && !good_tcp_udp
1443 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1444}
1445
1446static inline void
1447ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1448 ip4_header_t ** ih, u8 * error)
1449{
1450 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1451
1452 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1453 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1454
1455 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1456 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1457
1458 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1459 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1460
1461 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1462 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1463 {
Mohsin Kazmidd2eff62023-01-16 15:28:26 +00001464 if (is_tcp_udp[0] && !ip4_local_csum_is_offloaded (b[0]))
Florin Coras1b255522018-06-01 12:22:23 -07001465 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1466 &good_tcp_udp[0]);
Mohsin Kazmidd2eff62023-01-16 15:28:26 +00001467 if (is_tcp_udp[1] && !ip4_local_csum_is_offloaded (b[1]))
Florin Coras1b255522018-06-01 12:22:23 -07001468 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1469 &good_tcp_udp[1]);
1470 }
1471
1472 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1473 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1474 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1475 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1476}
1477
1478static inline void
1479ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1480 vlib_buffer_t * b, u16 * next, u8 error,
1481 u8 head_of_feature_arc)
1482{
1483 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1484 u32 next_index;
1485
1486 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1487 b->error = error ? error_node->errors[error] : 0;
1488 if (head_of_feature_arc)
1489 {
1490 next_index = *next;
1491 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1492 {
Florin Corasf8408802021-11-09 18:29:03 -08001493 vnet_feature_arc_start (
1494 arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
Florin Coras1b255522018-06-01 12:22:23 -07001495 *next = next_index;
1496 }
1497 }
1498}
1499
1500typedef struct
1501{
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001502 /* The src and fib-index together determine if packet n is the same as n-1 */
Florin Coras1b255522018-06-01 12:22:23 -07001503 ip4_address_t src;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001504 u32 fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001505 u32 lbi;
1506 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001507 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001508} ip4_local_last_check_t;
1509
1510static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001511ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1512 ip4_local_last_check_t *last_check, u8 *error0,
1513 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001514{
Florin Coras1b255522018-06-01 12:22:23 -07001515 const dpo_id_t *dpo0;
1516 load_balance_t *lb0;
1517 u32 lbi0;
1518
1519 vnet_buffer (b)->ip.fib_index =
1520 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1521 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1522
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001523 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001524 if (is_receive_dpo)
1525 {
1526 receive_dpo_t *rd;
1527 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001528 if (rd->rd_sw_if_index != ~0)
1529 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001530 }
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001531
Matthew Smith44e60462019-07-06 19:27:29 -05001532 /*
1533 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1534 * adjacency for the destination address (the local interface address).
1535 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1536 * adjacency for the source address (the remote sender's address)
1537 */
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001538 if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
1539 (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301540 last_check->first)
Florin Coras1b255522018-06-01 12:22:23 -07001541 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001542 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1543 &ip0->src_address);
Florin Coras1b255522018-06-01 12:22:23 -07001544
Matthew Smith44e60462019-07-06 19:27:29 -05001545 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1546 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001547 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001548
1549 lb0 = load_balance_get (lbi0);
1550 dpo0 = load_balance_get_bucket_i (lb0, 0);
1551
1552 /*
1553 * Must have a route to source otherwise we drop the packet.
1554 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1555 *
1556 * The checks are:
1557 * - the source is a recieve => it's from us => bogus, do this
1558 * first since it sets a different error code.
1559 * - uRPF check for any route to source - accept if passes.
1560 * - allow packets destined to the broadcast address from unknown sources
1561 */
1562
1563 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1564 && dpo0->dpoi_type == DPO_RECEIVE) ?
1565 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1566 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1567 && !fib_urpf_check_size (lb0->lb_urpf)
1568 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1569 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1570
1571 last_check->src.as_u32 = ip0->src_address.as_u32;
1572 last_check->lbi = lbi0;
1573 last_check->error = *error0;
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301574 last_check->first = 0;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001575 last_check->fib_index = vnet_buffer (b)->ip.fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001576 }
1577 else
1578 {
Matthew Smith44e60462019-07-06 19:27:29 -05001579 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1580 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001581 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001582 *error0 = last_check->error;
1583 }
1584}
1585
1586static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001587ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1588 ip4_local_last_check_t *last_check, u8 *error,
1589 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001590{
Florin Coras1b255522018-06-01 12:22:23 -07001591 const dpo_id_t *dpo[2];
1592 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001593 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001594 u32 lbi[2];
1595
Neale Rannsbe2286b2018-12-09 12:54:51 -08001596 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001597 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1598 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1599
1600 vnet_buffer (b[0])->ip.fib_index =
1601 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1602 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1603 vnet_buffer (b[0])->ip.fib_index;
1604
1605 vnet_buffer (b[1])->ip.fib_index =
1606 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1607 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1608 vnet_buffer (b[1])->ip.fib_index;
1609
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001610 not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
1611 not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
1612
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001613 vnet_buffer (b[0])->ip.rx_sw_if_index =
1614 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1615 vnet_buffer (b[1])->ip.rx_sw_if_index =
1616 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001617 if (is_receive_dpo)
1618 {
1619 const receive_dpo_t *rd0, *rd1;
1620 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1621 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001622 if (rd0->rd_sw_if_index != ~0)
1623 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1624 if (rd1->rd_sw_if_index != ~0)
1625 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001626 }
1627
Matthew Smith44e60462019-07-06 19:27:29 -05001628 /*
1629 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1630 * adjacency for the destination address (the local interface address).
1631 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1632 * adjacency for the source address (the remote sender's address)
1633 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301634 if (PREDICT_TRUE (not_last_hit))
Florin Coras1b255522018-06-01 12:22:23 -07001635 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001636 ip4_fib_forwarding_lookup_x2 (
1637 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1638 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001639
Matthew Smith44e60462019-07-06 19:27:29 -05001640 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1641 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001642 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001643
Matthew Smith44e60462019-07-06 19:27:29 -05001644 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1645 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001646 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001647
1648 lb[0] = load_balance_get (lbi[0]);
1649 lb[1] = load_balance_get (lbi[1]);
1650
1651 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1652 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1653
1654 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1655 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1656 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1657 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1658 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1659 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1660 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1661
1662 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1663 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1664 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1665 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1666 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1667 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1668 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1669
1670 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1671 last_check->lbi = lbi[1];
1672 last_check->error = error[1];
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301673 last_check->first = 0;
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001674 last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
Florin Coras1b255522018-06-01 12:22:23 -07001675 }
1676 else
1677 {
Matthew Smith44e60462019-07-06 19:27:29 -05001678 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1679 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001680 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001681
Matthew Smith44e60462019-07-06 19:27:29 -05001682 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1683 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001684 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001685
1686 error[0] = last_check->error;
1687 error[1] = last_check->error;
1688 }
1689}
Florin Coras20a14b92017-08-15 22:47:22 -07001690
Florin Corasc67cfd22018-10-01 21:59:18 -07001691enum ip_local_packet_type_e
1692{
1693 IP_LOCAL_PACKET_TYPE_L4,
1694 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001695 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001696};
1697
1698/**
1699 * Determine packet type and next node.
1700 *
1701 * The expectation is that all packets that are not L4 will skip
1702 * checksums and source checks.
1703 */
1704always_inline u8
1705ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1706{
1707 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1708
Juraj Sloboda3048b632018-10-02 11:13:53 +02001709 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1710 {
1711 *next = IP_LOCAL_NEXT_REASSEMBLY;
1712 return IP_LOCAL_PACKET_TYPE_FRAG;
1713 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001714 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1715 {
1716 *next = lm->local_next_by_ip_protocol[ip->protocol];
1717 return IP_LOCAL_PACKET_TYPE_NAT;
1718 }
1719
1720 *next = lm->local_next_by_ip_protocol[ip->protocol];
1721 return IP_LOCAL_PACKET_TYPE_L4;
1722}
1723
Dave Barach68b0fb02017-02-28 15:15:56 -05001724static inline uword
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001725ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1726 vlib_frame_t *frame, int head_of_feature_arc,
1727 int is_receive_dpo)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728{
Florin Coras1b255522018-06-01 12:22:23 -07001729 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001730 vlib_node_runtime_t *error_node =
Florin Corasfa2a3162020-02-11 03:01:19 +00001731 vlib_node_get_runtime (vm, ip4_local_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001732 u16 nexts[VLIB_FRAME_SIZE], *next;
1733 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1734 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001735 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001736
1737 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001738 /*
1739 * 0.0.0.0 can appear as the source address of an IP packet,
1740 * as can any other address, hence the need to use the 'first'
1741 * member to make sure the .lbi is initialised for the first
1742 * packet.
1743 */
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001744 .src = { .as_u32 = 0 },
Florin Coras1b255522018-06-01 12:22:23 -07001745 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001746 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1747 .first = 1,
Neale Rannsaa7cfd02022-03-24 12:28:42 +00001748 .fib_index = 0,
Florin Coras1b255522018-06-01 12:22:23 -07001749 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001750
1751 from = vlib_frame_vector_args (frame);
1752 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001753
Ed Warnickecb9cada2015-12-08 15:45:58 -07001754 if (node->flags & VLIB_NODE_FLAG_TRACE)
1755 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1756
Florin Coras1b255522018-06-01 12:22:23 -07001757 vlib_get_buffers (vm, from, bufs, n_left_from);
1758 b = bufs;
1759 next = nexts;
1760
1761 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001762 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001763 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764
Florin Coras1b255522018-06-01 12:22:23 -07001765 /* Prefetch next iteration. */
1766 {
1767 vlib_prefetch_buffer_header (b[4], LOAD);
1768 vlib_prefetch_buffer_header (b[5], LOAD);
1769
Damjan Marionaf7fb042021-07-15 11:54:41 +02001770 clib_prefetch_load (b[4]->data);
1771 clib_prefetch_load (b[5]->data);
Florin Coras1b255522018-06-01 12:22:23 -07001772 }
1773
1774 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1775
1776 ip[0] = vlib_buffer_get_current (b[0]);
1777 ip[1] = vlib_buffer_get_current (b[1]);
1778
1779 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1780 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1781
Florin Corasc67cfd22018-10-01 21:59:18 -07001782 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1783 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001784
Florin Corasc67cfd22018-10-01 21:59:18 -07001785 not_batch = pt[0] ^ pt[1];
1786
1787 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001788 goto skip_checks;
1789
1790 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001791 {
Florin Coras1b255522018-06-01 12:22:23 -07001792 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001793 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001794 }
1795 else
1796 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001797 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001798 {
Florin Coras1b255522018-06-01 12:22:23 -07001799 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001800 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1801 is_receive_dpo);
Florin Coras20a14b92017-08-15 22:47:22 -07001802 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001803 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804 {
Florin Coras1b255522018-06-01 12:22:23 -07001805 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001806 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1807 is_receive_dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001808 }
1809 }
1810
Florin Coras1b255522018-06-01 12:22:23 -07001811 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001812
Florin Coras1b255522018-06-01 12:22:23 -07001813 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1814 head_of_feature_arc);
1815 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1816 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001817
Florin Coras1b255522018-06-01 12:22:23 -07001818 b += 2;
1819 next += 2;
1820 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001821 }
1822
Florin Coras1b255522018-06-01 12:22:23 -07001823 while (n_left_from > 0)
1824 {
1825 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1826
1827 ip[0] = vlib_buffer_get_current (b[0]);
1828 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001829 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001830
Florin Corasc67cfd22018-10-01 21:59:18 -07001831 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001832 goto skip_check;
1833
1834 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001835 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1836 is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001837
1838 skip_check:
1839
Florin Coras1b255522018-06-01 12:22:23 -07001840 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1841 head_of_feature_arc);
1842
1843 b += 1;
1844 next += 1;
1845 n_left_from -= 1;
1846 }
1847
1848 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001849 return frame->n_vectors;
1850}
1851
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001852VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1853 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001854{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001855 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1856 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001857}
1858
Neale Ranns32e1c012016-11-22 17:07:28 +00001859VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001860{
Dave Barach68b0fb02017-02-28 15:15:56 -05001861 .name = "ip4-local",
1862 .vector_size = sizeof (u32),
1863 .format_trace = format_ip4_forward_next_trace,
Florin Corasfa2a3162020-02-11 03:01:19 +00001864 .n_errors = IP4_N_ERROR,
Neale Rannse22a7042022-08-09 03:03:29 +00001865 .error_counters = ip4_error_counters,
Dave Barach68b0fb02017-02-28 15:15:56 -05001866 .n_next_nodes = IP_LOCAL_N_NEXT,
1867 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001868 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001869 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1870 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001871 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001872 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera01c1fa42021-12-14 18:25:11 +00001873 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001874 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001875};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001876
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001877VLIB_NODE_FN (ip4_receive_local_node)
1878(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1879{
1880 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1881 1 /* is_receive_dpo */);
1882}
1883
1884VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1885 .name = "ip4-receive",
1886 .vector_size = sizeof (u32),
1887 .format_trace = format_ip4_forward_next_trace,
1888 .sibling_of = "ip4-local"
1889};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001890
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001891VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1892 vlib_node_runtime_t * node,
1893 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001894{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001895 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1896 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001897}
1898
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001899VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001900 .name = "ip4-local-end-of-arc",
1901 .vector_size = sizeof (u32),
1902
1903 .format_trace = format_ip4_forward_next_trace,
1904 .sibling_of = "ip4-local",
1905};
1906
Dave Barach68b0fb02017-02-28 15:15:56 -05001907VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1908 .arc_name = "ip4-local",
1909 .node_name = "ip4-local-end-of-arc",
1910 .runs_before = 0, /* not before any other features */
1911};
Dave Barach68b0fb02017-02-28 15:15:56 -05001912
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001913#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001914void
1915ip4_register_protocol (u32 protocol, u32 node_index)
1916{
1917 vlib_main_t *vm = vlib_get_main ();
1918 ip4_main_t *im = &ip4_main;
1919 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001920
1921 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 lm->local_next_by_ip_protocol[protocol] =
1923 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001924}
Neale Rannsb538dd82019-05-21 06:54:54 -07001925
1926void
1927ip4_unregister_protocol (u32 protocol)
1928{
1929 ip4_main_t *im = &ip4_main;
1930 ip_lookup_main_t *lm = &im->lookup_main;
1931
1932 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1933 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1934}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001935#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001936
1937static clib_error_t *
1938show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001939 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001940{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001941 ip4_main_t *im = &ip4_main;
1942 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001943 int i;
1944
1945 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001946 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001947 {
1948 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001949 {
1950 u32 node_index = vlib_get_node (vm,
1951 ip4_local_node.index)->
1952 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001953 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1954 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001955 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956 }
1957 return 0;
1958}
1959
1960
1961
Billy McFall0683c9c2016-10-13 08:27:31 -04001962/*?
1963 * Display the set of protocols handled by the local IPv4 stack.
1964 *
1965 * @cliexpar
1966 * Example of how to display local protocol table:
1967 * @cliexstart{show ip local}
1968 * Protocols handled by ip4_local
1969 * 1
1970 * 17
1971 * 47
1972 * @cliexend
1973?*/
Dave Barachd7cb1b52016-12-09 09:52:16 -05001974VLIB_CLI_COMMAND (show_ip_local, static) =
1975{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001976 .path = "show ip local",
1977 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001978 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001979};
1980
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981typedef enum
1982{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001984 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001985 IP4_REWRITE_NEXT_FRAGMENT,
1986 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987} ip4_rewrite_next_t;
1988
Neale Ranns889fe942017-06-01 05:43:19 -04001989/**
1990 * This bits of an IPv4 address to mask to construct a multicast
1991 * MAC address
1992 */
1993#if CLIB_ARCH_IS_BIG_ENDIAN
1994#define IP4_MCAST_ADDR_MASK 0x007fffff
1995#else
1996#define IP4_MCAST_ADDR_MASK 0xffff7f00
1997#endif
1998
Ole Troan8a9c8f12018-05-18 11:01:31 +02001999always_inline void
2000ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Ole Troaneb284a12019-10-09 13:33:19 +02002001 u16 adj_packet_bytes, bool df, u16 * next,
2002 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002003{
2004 if (packet_len > adj_packet_bytes)
2005 {
2006 *error = IP4_ERROR_MTU_EXCEEDED;
2007 if (df)
2008 {
2009 icmp4_error_set_vnet_buffer
2010 (b, ICMP4_destination_unreachable,
2011 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2012 adj_packet_bytes);
2013 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2014 }
2015 else
2016 {
Ole Troan313f7e22018-04-10 16:02:51 +02002017 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002018 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00002019 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02002020 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2021 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002022 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002023 }
2024 }
2025}
2026
Neale Ranns0b6a8572019-10-30 17:34:14 +00002027/* increment TTL & update checksum.
2028 Works either endian, so no need for byte swap. */
2029static_always_inline void
2030ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2031{
2032 i32 ttl;
2033 u32 checksum;
2034 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002035 return;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002036
2037 ttl = ip->ttl;
2038
2039 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2040 checksum += checksum >= 0xffff;
2041
2042 ip->checksum = checksum;
2043 ttl += 1;
2044 ip->ttl = ttl;
2045
Aloys Augustin0b77e312022-02-24 15:44:23 +00002046 ASSERT (ip4_header_checksum_is_valid (ip) ||
2047 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2048 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002049}
2050
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002051/* Decrement TTL & update checksum.
2052 Works either endian, so no need for byte swap. */
2053static_always_inline void
2054ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2055 u32 * error)
2056{
2057 i32 ttl;
2058 u32 checksum;
2059 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002060 return;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002061
2062 ttl = ip->ttl;
2063
2064 /* Input node should have reject packets with ttl 0. */
2065 ASSERT (ip->ttl > 0);
2066
2067 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2068 checksum += checksum >= 0xffff;
2069
2070 ip->checksum = checksum;
2071 ttl -= 1;
2072 ip->ttl = ttl;
2073
2074 /*
2075 * If the ttl drops below 1 when forwarding, generate
2076 * an ICMP response.
2077 */
2078 if (PREDICT_FALSE (ttl <= 0))
2079 {
2080 *error = IP4_ERROR_TIME_EXPIRED;
2081 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2082 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2083 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2084 0);
2085 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2086 }
2087
2088 /* Verify checksum. */
Benoît Ganne6e334e32020-08-31 18:59:34 +02002089 ASSERT (ip4_header_checksum_is_valid (ip) ||
Mohsin Kazmi4fd9f102021-06-17 17:29:27 +00002090 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2091 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002092}
2093
Ed Warnickecb9cada2015-12-08 15:45:58 -07002094always_inline uword
Damjan Mariond06e2eb2021-04-21 23:44:40 +02002095ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2096 vlib_frame_t *frame, int do_counters, int is_midchain,
2097 int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002098{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002099 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2100 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002101 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2102 u16 nexts[VLIB_FRAME_SIZE], *next;
2103 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002104 vlib_node_runtime_t *error_node =
2105 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002106
2107 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002108 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002109
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002110 vlib_get_buffers (vm, from, bufs, n_left_from);
2111 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2112
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002113#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002114 if (n_left_from >= 6)
2115 {
2116 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002117 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002118 vlib_prefetch_buffer_header (bufs[i], LOAD);
2119 }
2120
2121 next = nexts;
2122 b = bufs;
2123 while (n_left_from >= 8)
2124 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002125 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002126 ip4_header_t *ip0, *ip1;
2127 u32 rw_len0, error0, adj_index0;
2128 u32 rw_len1, error1, adj_index1;
2129 u32 tx_sw_if_index0, tx_sw_if_index1;
2130 u8 *p;
2131
PiotrX Kleskib801cd12020-12-09 14:32:26 +01002132 if (is_midchain)
2133 {
2134 vlib_prefetch_buffer_header (b[6], LOAD);
2135 vlib_prefetch_buffer_header (b[7], LOAD);
2136 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002137
2138 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2139 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2140
2141 /*
2142 * pre-fetch the per-adjacency counters
2143 */
2144 if (do_counters)
2145 {
2146 vlib_prefetch_combined_counter (&adjacency_counters,
2147 thread_index, adj_index0);
2148 vlib_prefetch_combined_counter (&adjacency_counters,
2149 thread_index, adj_index1);
2150 }
2151
2152 ip0 = vlib_buffer_get_current (b[0]);
2153 ip1 = vlib_buffer_get_current (b[1]);
2154
2155 error0 = error1 = IP4_ERROR_NONE;
2156
2157 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2158 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2159
2160 /* Rewrite packet header and updates lengths. */
2161 adj0 = adj_get (adj_index0);
2162 adj1 = adj_get (adj_index1);
2163
2164 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2165 rw_len0 = adj0[0].rewrite_header.data_bytes;
2166 rw_len1 = adj1[0].rewrite_header.data_bytes;
2167 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2168 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2169
2170 p = vlib_buffer_get_current (b[2]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002171 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2172 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002173
2174 p = vlib_buffer_get_current (b[3]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002175 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2176 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002177
2178 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002179 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2180 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2181
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002182 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002183 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002184 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002185 ip1_len = gso_mtu_sz (b[1]);
2186
2187 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002188 adj0[0].rewrite_header.max_l3_packet_bytes,
2189 ip0->flags_and_fragment_offset &
2190 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002191 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002192 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002193 adj1[0].rewrite_header.max_l3_packet_bytes,
2194 ip1->flags_and_fragment_offset &
2195 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002196 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002197
2198 if (is_mcast)
2199 {
2200 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2201 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2202 IP4_ERROR_SAME_INTERFACE : error0);
2203 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2204 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2205 IP4_ERROR_SAME_INTERFACE : error1);
2206 }
2207
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002208 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002209 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002210 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2211 {
2212 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002213 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002214
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002215 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2216 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2217
2218 if (PREDICT_FALSE
2219 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002220 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2221 tx_sw_if_index0,
2222 &next_index, b[0],
2223 adj0->ia_cfg_index);
2224
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002225 next[0] = next_index;
2226 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002227 else
2228 {
2229 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002230 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2231 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002232 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002233 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2234 {
2235 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002236 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002237
2238 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2239 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2240
2241 if (PREDICT_FALSE
2242 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002243 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2244 tx_sw_if_index1,
2245 &next_index, b[1],
2246 adj1->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002247 next[1] = next_index;
2248 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002249 else
2250 {
2251 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002252 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2253 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002254 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002255
Neale Ranns4ec36c52020-03-31 09:21:29 -04002256 if (is_midchain)
2257 /* Guess we are only writing on ipv4 header. */
2258 vnet_rewrite_two_headers (adj0[0], adj1[0],
2259 ip0, ip1, sizeof (ip4_header_t));
2260 else
2261 /* Guess we are only writing on simple Ethernet header. */
2262 vnet_rewrite_two_headers (adj0[0], adj1[0],
2263 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002264
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002265 if (do_counters)
2266 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002267 if (error0 == IP4_ERROR_NONE)
2268 vlib_increment_combined_counter
2269 (&adjacency_counters,
2270 thread_index,
2271 adj_index0, 1,
2272 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002273
Neale Ranns0b6a8572019-10-30 17:34:14 +00002274 if (error1 == IP4_ERROR_NONE)
2275 vlib_increment_combined_counter
2276 (&adjacency_counters,
2277 thread_index,
2278 adj_index1, 1,
2279 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002280 }
2281
2282 if (is_midchain)
2283 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002284 if (error0 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002285 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns4ec36c52020-03-31 09:21:29 -04002286 if (error1 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002287 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002288 }
2289
2290 if (is_mcast)
2291 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002292 /* copy bytes from the IP address into the MAC rewrite */
2293 if (error0 == IP4_ERROR_NONE)
2294 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2295 adj0->rewrite_header.dst_mcast_offset,
2296 &ip0->dst_address.as_u32, (u8 *) ip0);
2297 if (error1 == IP4_ERROR_NONE)
2298 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2299 adj1->rewrite_header.dst_mcast_offset,
2300 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002301 }
2302
2303 next += 2;
2304 b += 2;
2305 n_left_from -= 2;
2306 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002307#elif (CLIB_N_PREFETCHES >= 4)
2308 next = nexts;
2309 b = bufs;
2310 while (n_left_from >= 1)
2311 {
2312 ip_adjacency_t *adj0;
2313 ip4_header_t *ip0;
2314 u32 rw_len0, error0, adj_index0;
2315 u32 tx_sw_if_index0;
2316 u8 *p;
2317
2318 /* Prefetch next iteration */
2319 if (PREDICT_TRUE (n_left_from >= 4))
2320 {
2321 ip_adjacency_t *adj2;
2322 u32 adj_index2;
2323
2324 vlib_prefetch_buffer_header (b[3], LOAD);
2325 vlib_prefetch_buffer_data (b[2], LOAD);
2326
2327 /* Prefetch adj->rewrite_header */
2328 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2329 adj2 = adj_get (adj_index2);
2330 p = (u8 *) adj2;
2331 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2332 LOAD);
2333 }
2334
2335 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2336
2337 /*
2338 * Prefetch the per-adjacency counters
2339 */
2340 if (do_counters)
2341 {
2342 vlib_prefetch_combined_counter (&adjacency_counters,
2343 thread_index, adj_index0);
2344 }
2345
2346 ip0 = vlib_buffer_get_current (b[0]);
2347
2348 error0 = IP4_ERROR_NONE;
2349
2350 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2351
2352 /* Rewrite packet header and updates lengths. */
2353 adj0 = adj_get (adj_index0);
2354
2355 /* Rewrite header was prefetched. */
2356 rw_len0 = adj0[0].rewrite_header.data_bytes;
2357 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2358
2359 /* Check MTU of outgoing interface. */
2360 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2361
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002362 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002363 ip0_len = gso_mtu_sz (b[0]);
2364
2365 ip4_mtu_check (b[0], ip0_len,
2366 adj0[0].rewrite_header.max_l3_packet_bytes,
2367 ip0->flags_and_fragment_offset &
2368 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002369 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002370
2371 if (is_mcast)
2372 {
2373 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2374 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2375 IP4_ERROR_SAME_INTERFACE : error0);
2376 }
2377
2378 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2379 * to see the IP header */
2380 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2381 {
2382 u32 next_index = adj0[0].rewrite_header.next_index;
2383 vlib_buffer_advance (b[0], -(word) rw_len0);
2384 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2385 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2386
2387 if (PREDICT_FALSE
2388 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002389 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2390 tx_sw_if_index0,
2391 &next_index, b[0],
2392 adj0->ia_cfg_index);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002393 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002394
2395 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002396 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002397 /* Guess we are only writing on ipv4 header. */
2398 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2399 }
2400 else
2401 /* Guess we are only writing on simple Ethernet header. */
2402 vnet_rewrite_one_header (adj0[0], ip0,
2403 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002404
2405 /*
2406 * Bump the per-adjacency counters
2407 */
2408 if (do_counters)
2409 vlib_increment_combined_counter
2410 (&adjacency_counters,
2411 thread_index,
2412 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2413 b[0]) + rw_len0);
2414
Neale Ranns4ec36c52020-03-31 09:21:29 -04002415 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002416 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002417
2418 if (is_mcast)
2419 /* copy bytes from the IP address into the MAC rewrite */
2420 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2421 adj0->rewrite_header.dst_mcast_offset,
2422 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002423 }
2424 else
2425 {
2426 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002427 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2428 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002429 }
2430
2431 next += 1;
2432 b += 1;
2433 n_left_from -= 1;
2434 }
2435#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002436
Ed Warnickecb9cada2015-12-08 15:45:58 -07002437 while (n_left_from > 0)
2438 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002439 ip_adjacency_t *adj0;
2440 ip4_header_t *ip0;
2441 u32 rw_len0, adj_index0, error0;
2442 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002443
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002444 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2445
2446 adj0 = adj_get (adj_index0);
2447
2448 if (do_counters)
2449 vlib_prefetch_combined_counter (&adjacency_counters,
2450 thread_index, adj_index0);
2451
2452 ip0 = vlib_buffer_get_current (b[0]);
2453
2454 error0 = IP4_ERROR_NONE;
2455
2456 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2457
2458
2459 /* Update packet buffer attributes/set output interface. */
2460 rw_len0 = adj0[0].rewrite_header.data_bytes;
2461 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2462
2463 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002464 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002465 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002466 ip0_len = gso_mtu_sz (b[0]);
2467
2468 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002469 adj0[0].rewrite_header.max_l3_packet_bytes,
2470 ip0->flags_and_fragment_offset &
2471 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002472 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002473
2474 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002475 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002476 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2477 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2478 IP4_ERROR_SAME_INTERFACE : error0);
2479 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002480
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002481 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002482 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002483 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2484 {
2485 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002486 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002487 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2488 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002489
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002490 if (PREDICT_FALSE
2491 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002492 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2493 tx_sw_if_index0,
2494 &next_index, b[0],
2495 adj0->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002496 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002497
2498 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002499 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002500 /* Guess we are only writing on ipv4 header. */
2501 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2502 }
2503 else
2504 /* Guess we are only writing on simple Ethernet header. */
2505 vnet_rewrite_one_header (adj0[0], ip0,
2506 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002507
2508 if (do_counters)
2509 vlib_increment_combined_counter
2510 (&adjacency_counters,
2511 thread_index, adj_index0, 1,
2512 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2513
Neale Rannse2fe0972020-11-26 08:37:27 +00002514 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002515 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002516
2517 if (is_mcast)
2518 /* copy bytes from the IP address into the MAC rewrite */
2519 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2520 adj0->rewrite_header.dst_mcast_offset,
2521 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002522 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002523 else
2524 {
2525 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002526 /* undo the TTL decrement - we'll be back to do it again */
2527 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2528 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002529 }
2530
2531 next += 1;
2532 b += 1;
2533 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002534 }
2535
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002536
Ed Warnickecb9cada2015-12-08 15:45:58 -07002537 /* Need to do trace after rewrites to pick up new packet data. */
2538 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002539 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002540
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002541 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002542 return frame->n_vectors;
2543}
2544
Neale Rannsf06aea52016-11-29 06:51:37 -08002545/** @brief IPv4 rewrite node.
2546 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002547
2548 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2549 header checksum, fetch the ip adjacency, check the outbound mtu,
2550 apply the adjacency rewrite, and send pkts to the adjacency
2551 rewrite header's rewrite_next_index.
2552
2553 @param vm vlib_main_t corresponding to the current thread
2554 @param node vlib_node_runtime_t
2555 @param frame vlib_frame_t whose contents should be dispatched
2556
2557 @par Graph mechanics: buffer metadata, next index usage
2558
2559 @em Uses:
2560 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2561 - the rewrite adjacency index
2562 - <code>adj->lookup_next_index</code>
2563 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002564 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002565 - <code>adj->rewrite_header</code>
2566 - Rewrite string length, rewrite string, next_index
2567
2568 @em Sets:
2569 - <code>b->current_data, b->current_length</code>
2570 - Updated net of applying the rewrite string
2571
2572 <em>Next Indices:</em>
2573 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002574 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002575*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002576
2577VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2578 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002579{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002580 if (adj_are_counters_enabled ())
2581 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2582 else
2583 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002584}
2585
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002586VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2587 vlib_node_runtime_t * node,
2588 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002589{
2590 if (adj_are_counters_enabled ())
2591 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2592 else
2593 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2594}
2595
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002596VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2597 vlib_node_runtime_t * node,
2598 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002599{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002600 if (adj_are_counters_enabled ())
2601 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2602 else
2603 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002604}
2605
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002606VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2607 vlib_node_runtime_t * node,
2608 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002609{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002610 if (adj_are_counters_enabled ())
2611 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2612 else
2613 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002614}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002615
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002616VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2617 vlib_node_runtime_t * node,
2618 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002619{
2620 if (adj_are_counters_enabled ())
2621 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2622 else
2623 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2624}
2625
Neale Ranns32e1c012016-11-22 17:07:28 +00002626VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002627 .name = "ip4-rewrite",
2628 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629
Neale Ranns32e1c012016-11-22 17:07:28 +00002630 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002631
Ole Troan313f7e22018-04-10 16:02:51 +02002632 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002633 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002634 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002635 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002636 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002637 },
2638};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002639
2640VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002641 .name = "ip4-rewrite-bcast",
2642 .vector_size = sizeof (u32),
2643
2644 .format_trace = format_ip4_rewrite_trace,
2645 .sibling_of = "ip4-rewrite",
2646};
Neale Ranns32e1c012016-11-22 17:07:28 +00002647
2648VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002649 .name = "ip4-rewrite-mcast",
2650 .vector_size = sizeof (u32),
2651
2652 .format_trace = format_ip4_rewrite_trace,
2653 .sibling_of = "ip4-rewrite",
2654};
Neale Ranns32e1c012016-11-22 17:07:28 +00002655
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002656VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002657 .name = "ip4-mcast-midchain",
2658 .vector_size = sizeof (u32),
2659
2660 .format_trace = format_ip4_rewrite_trace,
2661 .sibling_of = "ip4-rewrite",
2662};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002663
Neale Ranns32e1c012016-11-22 17:07:28 +00002664VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002665 .name = "ip4-midchain",
2666 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002667 .format_trace = format_ip4_rewrite_trace,
2668 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002669};
Damjan Marion1c80e832016-05-11 23:07:18 +02002670
Ed Warnickecb9cada2015-12-08 15:45:58 -07002671static clib_error_t *
2672set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002673 unformat_input_t * input,
2674 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675{
2676 int matched = 0;
2677 u32 table_id = 0;
2678 u32 flow_hash_config = 0;
2679 int rv;
2680
Dave Barachd7cb1b52016-12-09 09:52:16 -05002681 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2682 {
2683 if (unformat (input, "table %d", &table_id))
2684 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002685#define _(a, b, v) \
2686 else if (unformat (input, #a)) \
2687 { \
2688 flow_hash_config |= v; \
2689 matched = 1; \
2690 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002691 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002692#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002693 else
2694 break;
2695 }
Dave Barach75fc8542016-10-11 16:16:02 -04002696
Ed Warnickecb9cada2015-12-08 15:45:58 -07002697 if (matched == 0)
2698 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002699 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002700
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002701 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002702 switch (rv)
2703 {
2704 case 0:
2705 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002706
Ed Warnickecb9cada2015-12-08 15:45:58 -07002707 case VNET_API_ERROR_NO_SUCH_FIB:
2708 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002709
Ed Warnickecb9cada2015-12-08 15:45:58 -07002710 default:
2711 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2712 break;
2713 }
Dave Barach75fc8542016-10-11 16:16:02 -04002714
Ed Warnickecb9cada2015-12-08 15:45:58 -07002715 return 0;
2716}
Dave Barach75fc8542016-10-11 16:16:02 -04002717
Billy McFall0683c9c2016-10-13 08:27:31 -04002718/*?
2719 * Configure the set of IPv4 fields used by the flow hash.
2720 *
2721 * @cliexpar
2722 * Example of how to set the flow hash on a given table:
2723 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2724 * Example of display the configured flow hash:
2725 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002726 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2727 * 0.0.0.0/0
2728 * unicast-ip4-chain
2729 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2730 * [0] [@0]: dpo-drop ip6
2731 * 0.0.0.0/32
2732 * unicast-ip4-chain
2733 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2734 * [0] [@0]: dpo-drop ip6
2735 * 224.0.0.0/8
2736 * unicast-ip4-chain
2737 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2738 * [0] [@0]: dpo-drop ip6
2739 * 6.0.1.2/32
2740 * unicast-ip4-chain
2741 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2742 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2743 * 7.0.0.1/32
2744 * unicast-ip4-chain
2745 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2746 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2747 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2748 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2749 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2750 * 240.0.0.0/8
2751 * unicast-ip4-chain
2752 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2753 * [0] [@0]: dpo-drop ip6
2754 * 255.255.255.255/32
2755 * unicast-ip4-chain
2756 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2757 * [0] [@0]: dpo-drop ip6
2758 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2759 * 0.0.0.0/0
2760 * unicast-ip4-chain
2761 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2762 * [0] [@0]: dpo-drop ip6
2763 * 0.0.0.0/32
2764 * unicast-ip4-chain
2765 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2766 * [0] [@0]: dpo-drop ip6
2767 * 172.16.1.0/24
2768 * unicast-ip4-chain
2769 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2770 * [0] [@4]: ipv4-glean: af_packet0
2771 * 172.16.1.1/32
2772 * unicast-ip4-chain
2773 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2774 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2775 * 172.16.1.2/32
2776 * unicast-ip4-chain
2777 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2778 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2779 * 172.16.2.0/24
2780 * unicast-ip4-chain
2781 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2782 * [0] [@4]: ipv4-glean: af_packet1
2783 * 172.16.2.1/32
2784 * unicast-ip4-chain
2785 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2786 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2787 * 224.0.0.0/8
2788 * unicast-ip4-chain
2789 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2790 * [0] [@0]: dpo-drop ip6
2791 * 240.0.0.0/8
2792 * unicast-ip4-chain
2793 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2794 * [0] [@0]: dpo-drop ip6
2795 * 255.255.255.255/32
2796 * unicast-ip4-chain
2797 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2798 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002799 * @cliexend
2800?*/
Takeru Hayasakab23c6f42023-01-17 04:45:58 +09002801VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002802 .path = "set ip flow-hash",
Takeru Hayasakab23c6f42023-01-17 04:45:58 +09002803 .short_help = "set ip flow-hash table <table-id> [src] [dst] [sport] "
2804 "[dport] [proto] [reverse] [gtpv1teid]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002805 .function = set_ip_flow_hash_command_fn,
2806};
Dave Barach75fc8542016-10-11 16:16:02 -04002807
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002808#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002809int
2810vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2811 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002812{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002813 vnet_main_t *vnm = vnet_get_main ();
2814 vnet_interface_main_t *im = &vnm->interface_main;
2815 ip4_main_t *ipm = &ip4_main;
2816 ip_lookup_main_t *lm = &ipm->lookup_main;
2817 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002818 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002819
2820 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2821 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2822
2823 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2824 return VNET_API_ERROR_NO_SUCH_ENTRY;
2825
2826 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002827 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002828
Neale Rannsdf089a82016-10-02 16:39:06 +01002829 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2830
2831 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002832 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002833 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002834 .fp_len = 32,
2835 .fp_proto = FIB_PROTOCOL_IP4,
2836 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002837 };
2838 u32 fib_index;
2839
Dave Barachd7cb1b52016-12-09 09:52:16 -05002840 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2841 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002842
2843
Dave Barachd7cb1b52016-12-09 09:52:16 -05002844 if (table_index != (u32) ~ 0)
2845 {
2846 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002847
Dave Barachd7cb1b52016-12-09 09:52:16 -05002848 dpo_set (&dpo,
2849 DPO_CLASSIFY,
2850 DPO_PROTO_IP4,
2851 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002852
Dave Barachd7cb1b52016-12-09 09:52:16 -05002853 fib_table_entry_special_dpo_add (fib_index,
2854 &pfx,
2855 FIB_SOURCE_CLASSIFY,
2856 FIB_ENTRY_FLAG_NONE, &dpo);
2857 dpo_reset (&dpo);
2858 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002859 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860 {
2861 fib_table_entry_special_remove (fib_index,
2862 &pfx, FIB_SOURCE_CLASSIFY);
2863 }
2864 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002865
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866 return 0;
2867}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002868#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002869
2870static clib_error_t *
2871set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002872 unformat_input_t * input,
2873 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002874{
2875 u32 table_index = ~0;
2876 int table_index_set = 0;
2877 u32 sw_if_index = ~0;
2878 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002879
Dave Barachd7cb1b52016-12-09 09:52:16 -05002880 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2881 {
2882 if (unformat (input, "table-index %d", &table_index))
2883 table_index_set = 1;
2884 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2885 vnet_get_main (), &sw_if_index))
2886 ;
2887 else
2888 break;
2889 }
Dave Barach75fc8542016-10-11 16:16:02 -04002890
Ed Warnickecb9cada2015-12-08 15:45:58 -07002891 if (table_index_set == 0)
2892 return clib_error_return (0, "classify table-index must be specified");
2893
2894 if (sw_if_index == ~0)
2895 return clib_error_return (0, "interface / subif must be specified");
2896
2897 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2898
2899 switch (rv)
2900 {
2901 case 0:
2902 break;
2903
2904 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2905 return clib_error_return (0, "No such interface");
2906
2907 case VNET_API_ERROR_NO_SUCH_ENTRY:
2908 return clib_error_return (0, "No such classifier table");
2909 }
2910 return 0;
2911}
2912
Billy McFall0683c9c2016-10-13 08:27:31 -04002913/*?
2914 * Assign a classification table to an interface. The classification
2915 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2916 * commands. Once the table is create, use this command to filter packets
2917 * on an interface.
2918 *
2919 * @cliexpar
2920 * Example of how to assign a classification table to an interface:
2921 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2922?*/
Dave Barachd7cb1b52016-12-09 09:52:16 -05002923VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2924{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002926 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002927 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002928 .function = set_ip_classify_command_fn,
2929};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002930
2931/*
2932 * fd.io coding-style-patch-verification: ON
2933 *
2934 * Local Variables:
2935 * eval: (c-set-style "gnu")
2936 * End:
2937 */