blob: 58af706e2b227a9765d39ba4b9c5cb0eeba03c9e [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>
Ed Warnickecb9cada2015-12-08 15:45:58 -070064
Chris Luke8e5b0412016-07-26 13:06:10 -040065/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040066 @node ip4-lookup
67
68 This is the main IPv4 lookup dispatch node.
69
70 @param vm vlib_main_t corresponding to the current thread
71 @param node vlib_node_runtime_t
72 @param frame vlib_frame_t whose contents should be dispatched
73
74 @par Graph mechanics: buffer metadata, next index usage
75
76 @em Uses:
77 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
78 - Indicates the @c sw_if_index value of the interface that the
79 packet was received on.
80 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
81 - When the value is @c ~0 then the node performs a longest prefix
82 match (LPM) for the packet destination address in the FIB attached
83 to the receive interface.
84 - Otherwise perform LPM for the packet destination address in the
85 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
86 value (0, 1, ...) and not a VRF id.
87
88 @em Sets:
89 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
90 - The lookup result adjacency index.
91
92 <em>Next Index:</em>
93 - Dispatches the packet to the node index found in
94 ip_adjacency_t @c adj->lookup_next_index
95 (where @c adj is the lookup result adjacency).
96*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020097VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
98 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070099{
Neale Rannscb54e3c2019-06-19 07:14:10 +0000100 return ip4_lookup_inline (vm, node, frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101}
102
Dave Barachd7cb1b52016-12-09 09:52:16 -0500103static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100104
Neale Rannsf8686322017-11-29 02:39:53 -0800105/* *INDENT-OFF* */
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};
114/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100115
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200116VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
117 vlib_node_runtime_t * node,
118 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500120 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400121 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200122 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800123 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400124 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700125
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100126 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400127 n_left = frame->n_vectors;
128 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100129
Neale Ranns3ce72b22019-05-27 08:21:32 -0400130 vlib_get_buffers (vm, from, bufs, n_left);
131
132 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400134 const load_balance_t *lb0, *lb1;
135 const ip4_header_t *ip0, *ip1;
136 u32 lbi0, hc0, lbi1, hc1;
137 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100138
Neale Ranns3ce72b22019-05-27 08:21:32 -0400139 /* Prefetch next iteration. */
140 {
141 vlib_prefetch_buffer_header (b[2], LOAD);
142 vlib_prefetch_buffer_header (b[3], LOAD);
143
144 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
145 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
146 }
147
148 ip0 = vlib_buffer_get_current (b[0]);
149 ip1 = vlib_buffer_get_current (b[1]);
150 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
151 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
152
153 lb0 = load_balance_get (lbi0);
154 lb1 = load_balance_get (lbi1);
155
156 /*
157 * this node is for via FIBs we can re-use the hash value from the
158 * to node if present.
159 * We don't want to use the same hash value at each level in the recursion
160 * graph as that would lead to polarisation
161 */
162 hc0 = hc1 = 0;
163
164 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500165 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400166 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500167 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400168 hc0 = vnet_buffer (b[0])->ip.flow_hash =
169 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700170 }
171 else
172 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400173 hc0 = vnet_buffer (b[0])->ip.flow_hash =
174 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500175 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400176 dpo0 = load_balance_get_fwd_bucket
177 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
178 }
179 else
180 {
181 dpo0 = load_balance_get_bucket_i (lb0, 0);
182 }
183 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
184 {
185 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500186 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400187 hc1 = vnet_buffer (b[1])->ip.flow_hash =
188 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700190 else
191 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400192 hc1 = vnet_buffer (b[1])->ip.flow_hash =
193 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700194 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400195 dpo1 = load_balance_get_fwd_bucket
196 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
197 }
198 else
199 {
200 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500201 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000202
Neale Ranns3ce72b22019-05-27 08:21:32 -0400203 next[0] = dpo0->dpoi_next_node;
204 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100205
Neale Ranns3ce72b22019-05-27 08:21:32 -0400206 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
207 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100208
Neale Ranns3ce72b22019-05-27 08:21:32 -0400209 vlib_increment_combined_counter
210 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
211 vlib_increment_combined_counter
212 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100213
Neale Ranns3ce72b22019-05-27 08:21:32 -0400214 b += 2;
215 next += 2;
216 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217 }
218
Neale Ranns3ce72b22019-05-27 08:21:32 -0400219 while (n_left > 0)
220 {
221 const load_balance_t *lb0;
222 const ip4_header_t *ip0;
223 const dpo_id_t *dpo0;
224 u32 lbi0, hc0;
225
226 ip0 = vlib_buffer_get_current (b[0]);
227 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
228
229 lb0 = load_balance_get (lbi0);
230
231 hc0 = 0;
232 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
233 {
234 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
235 {
236 hc0 = vnet_buffer (b[0])->ip.flow_hash =
237 vnet_buffer (b[0])->ip.flow_hash >> 1;
238 }
239 else
240 {
241 hc0 = vnet_buffer (b[0])->ip.flow_hash =
242 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
243 }
244 dpo0 = load_balance_get_fwd_bucket
245 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
246 }
247 else
248 {
249 dpo0 = load_balance_get_bucket_i (lb0, 0);
250 }
251
252 next[0] = dpo0->dpoi_next_node;
253 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
254
255 vlib_increment_combined_counter
256 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
257
258 b += 1;
259 next += 1;
260 n_left -= 1;
261 }
262
263 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800264 if (node->flags & VLIB_NODE_FLAG_TRACE)
265 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
266
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100267 return frame->n_vectors;
268}
269
Neale Rannsf8686322017-11-29 02:39:53 -0800270/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500271VLIB_REGISTER_NODE (ip4_load_balance_node) =
272{
Neale Rannsf8686322017-11-29 02:39:53 -0800273 .name = "ip4-load-balance",
274 .vector_size = sizeof (u32),
275 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200276 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800277};
278/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100279
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200280#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281/* get first interface address */
282ip4_address_t *
283ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500284 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100285{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500286 ip_lookup_main_t *lm = &im->lookup_main;
287 ip_interface_address_t *ia = 0;
288 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100289
Neale Ranns32e1c012016-11-22 17:07:28 +0000290 /* *INDENT-OFF* */
291 foreach_ip_interface_address
292 (lm, ia, sw_if_index,
293 1 /* honor unnumbered */ ,
294 ({
295 ip4_address_t * a =
296 ip_interface_address_get_address (lm, ia);
297 result = a;
298 break;
299 }));
300 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100301 if (result_ia)
302 *result_ia = result ? ia : 0;
303 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700304}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500305#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
307static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700308ip4_add_subnet_bcast_route (u32 fib_index,
309 fib_prefix_t *pfx,
310 u32 sw_if_index)
311{
312 vnet_sw_interface_flags_t iflags;
313
314 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
315
316 fib_table_entry_special_remove(fib_index,
317 pfx,
318 FIB_SOURCE_INTERFACE);
319
320 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
321 {
322 fib_table_entry_update_one_path (fib_index, pfx,
323 FIB_SOURCE_INTERFACE,
324 FIB_ENTRY_FLAG_NONE,
325 DPO_PROTO_IP4,
326 /* No next-hop address */
327 &ADJ_BCAST_ADDR,
328 sw_if_index,
329 // invalid FIB index
330 ~0,
331 1,
332 // no out-label stack
333 NULL,
334 FIB_ROUTE_PATH_FLAG_NONE);
335 }
336 else
337 {
338 fib_table_entry_special_add(fib_index,
339 pfx,
340 FIB_SOURCE_INTERFACE,
341 (FIB_ENTRY_FLAG_DROP |
342 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
343 }
344}
345
346static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500347ip4_add_interface_prefix_routes (ip4_main_t *im,
348 u32 sw_if_index,
349 u32 fib_index,
350 ip_interface_address_t * a)
351{
352 ip_lookup_main_t *lm = &im->lookup_main;
353 ip_interface_prefix_t *if_prefix;
354 ip4_address_t *address = ip_interface_address_get_address (lm, a);
355
356 ip_interface_prefix_key_t key = {
357 .prefix = {
358 .fp_len = a->address_length,
359 .fp_proto = FIB_PROTOCOL_IP4,
360 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
361 },
362 .sw_if_index = sw_if_index,
363 };
364
365 fib_prefix_t pfx_special = {
366 .fp_proto = FIB_PROTOCOL_IP4,
367 };
368
369 /* If prefix already set on interface, just increment ref count & return */
370 if_prefix = ip_get_interface_prefix (lm, &key);
371 if (if_prefix)
372 {
373 if_prefix->ref_count += 1;
374 return;
375 }
376
377 /* New prefix - allocate a pool entry, initialize it, add to the hash */
378 pool_get (lm->if_prefix_pool, if_prefix);
379 if_prefix->ref_count = 1;
380 if_prefix->src_ia_index = a - lm->if_address_pool;
381 clib_memcpy (&if_prefix->key, &key, sizeof (key));
382 mhash_set (&lm->prefix_to_if_prefix_index, &key,
383 if_prefix - lm->if_prefix_pool, 0 /* old value */);
384
Neale Rannse2fe0972020-11-26 08:37:27 +0000385 pfx_special.fp_len = a->address_length;
386 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
387
388 /* set the glean route for the prefix */
389 fib_table_entry_update_one_path (fib_index, &pfx_special,
390 FIB_SOURCE_INTERFACE,
391 (FIB_ENTRY_FLAG_CONNECTED |
392 FIB_ENTRY_FLAG_ATTACHED),
393 DPO_PROTO_IP4,
394 /* No next-hop address */
395 NULL,
396 sw_if_index,
397 /* invalid FIB index */
398 ~0,
399 1,
400 /* no out-label stack */
401 NULL,
402 FIB_ROUTE_PATH_FLAG_NONE);
403
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500404 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
405 if (a->address_length <= 30)
406 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500407 /* set a drop route for the base address of the prefix */
408 pfx_special.fp_len = 32;
409 pfx_special.fp_addr.ip4.as_u32 =
410 address->as_u32 & im->fib_masks[a->address_length];
411
412 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
413 fib_table_entry_special_add (fib_index, &pfx_special,
414 FIB_SOURCE_INTERFACE,
415 (FIB_ENTRY_FLAG_DROP |
416 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
417
418 /* set a route for the broadcast address of the prefix */
419 pfx_special.fp_len = 32;
420 pfx_special.fp_addr.ip4.as_u32 =
421 address->as_u32 | ~im->fib_masks[a->address_length];
422 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
423 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
424
425
426 }
427 /* length == 31 - add an attached route for the other address */
428 else if (a->address_length == 31)
429 {
430 pfx_special.fp_len = 32;
431 pfx_special.fp_addr.ip4.as_u32 =
432 address->as_u32 ^ clib_host_to_net_u32(1);
433
434 fib_table_entry_update_one_path (fib_index, &pfx_special,
435 FIB_SOURCE_INTERFACE,
436 (FIB_ENTRY_FLAG_ATTACHED),
437 DPO_PROTO_IP4,
438 &pfx_special.fp_addr,
439 sw_if_index,
440 /* invalid FIB index */
441 ~0,
442 1,
443 NULL,
444 FIB_ROUTE_PATH_FLAG_NONE);
445 }
446}
447
448static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700449ip4_add_interface_routes (u32 sw_if_index,
450 ip4_main_t * im, u32 fib_index,
451 ip_interface_address_t * a)
452{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500453 ip_lookup_main_t *lm = &im->lookup_main;
454 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100455 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500456 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500457 .fp_proto = FIB_PROTOCOL_IP4,
458 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100459 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500461 /* set special routes for the prefix if needed */
462 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100463
464 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500465 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467 lm->classify_table_index_by_sw_if_index[sw_if_index];
468 if (classify_table_index != (u32) ~ 0)
469 {
470 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100471
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 dpo_set (&dpo,
473 DPO_CLASSIFY,
474 DPO_PROTO_IP4,
475 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100476
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477 fib_table_entry_special_dpo_add (fib_index,
478 &pfx,
479 FIB_SOURCE_CLASSIFY,
480 FIB_ENTRY_FLAG_NONE, &dpo);
481 dpo_reset (&dpo);
482 }
483 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100484
Neale Ranns32e1c012016-11-22 17:07:28 +0000485 fib_table_entry_update_one_path (fib_index, &pfx,
486 FIB_SOURCE_INTERFACE,
487 (FIB_ENTRY_FLAG_CONNECTED |
488 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700489 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000490 &pfx.fp_addr,
491 sw_if_index,
492 // invalid FIB index
493 ~0,
494 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500495 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496}
497
498static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500499ip4_del_interface_prefix_routes (ip4_main_t * im,
500 u32 sw_if_index,
501 u32 fib_index,
502 ip4_address_t * address,
503 u32 address_length)
504{
505 ip_lookup_main_t *lm = &im->lookup_main;
506 ip_interface_prefix_t *if_prefix;
507
508 ip_interface_prefix_key_t key = {
509 .prefix = {
510 .fp_len = address_length,
511 .fp_proto = FIB_PROTOCOL_IP4,
512 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
513 },
514 .sw_if_index = sw_if_index,
515 };
516
517 fib_prefix_t pfx_special = {
518 .fp_len = 32,
519 .fp_proto = FIB_PROTOCOL_IP4,
520 };
521
522 if_prefix = ip_get_interface_prefix (lm, &key);
523 if (!if_prefix)
524 {
525 clib_warning ("Prefix not found while deleting %U",
526 format_ip4_address_and_length, address, address_length);
527 return;
528 }
529
530 if_prefix->ref_count -= 1;
531
532 /*
Neale Rannse2fe0972020-11-26 08:37:27 +0000533 * Routes need to be adjusted if deleting last intf addr in prefix
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500534 *
535 * We're done now otherwise
536 */
Neale Rannse2fe0972020-11-26 08:37:27 +0000537 if (if_prefix->ref_count > 0)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500538 return;
539
540 /* length <= 30, delete glean route, first address, last address */
541 if (address_length <= 30)
542 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000543 /* Less work to do in FIB if we remove the covered /32s first */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500544
Neale Rannse2fe0972020-11-26 08:37:27 +0000545 /* first address in prefix */
546 pfx_special.fp_addr.ip4.as_u32 =
547 address->as_u32 & im->fib_masks[address_length];
548 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500549
Neale Rannse2fe0972020-11-26 08:37:27 +0000550 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
551 fib_table_entry_special_remove (fib_index,
552 &pfx_special,
553 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500554
Neale Rannse2fe0972020-11-26 08:37:27 +0000555 /* prefix broadcast address */
556 pfx_special.fp_addr.ip4.as_u32 =
557 address->as_u32 | ~im->fib_masks[address_length];
558 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500559
Neale Rannse2fe0972020-11-26 08:37:27 +0000560 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
561 fib_table_entry_special_remove (fib_index,
562 &pfx_special,
563 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500564 }
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500565 else if (address_length == 31)
566 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000567 /* length == 31, delete attached route for the other address */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500568 pfx_special.fp_addr.ip4.as_u32 =
569 address->as_u32 ^ clib_host_to_net_u32(1);
570
571 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
572 }
573
Neale Rannse2fe0972020-11-26 08:37:27 +0000574 /* remove glean route for prefix */
575 pfx_special.fp_addr.ip4 = *address;
576 pfx_special.fp_len = address_length;
577 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
578
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500579 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
580 pool_put (lm->if_prefix_pool, if_prefix);
581}
582
583static void
584ip4_del_interface_routes (u32 sw_if_index,
585 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100586 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500587 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700588{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500589 fib_prefix_t pfx = {
Neale Rannse2fe0972020-11-26 08:37:27 +0000590 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500591 .fp_proto = FIB_PROTOCOL_IP4,
592 .fp_addr.ip4 = *address,
593 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700594
Neale Rannse2fe0972020-11-26 08:37:27 +0000595 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
596
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500597 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
598 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599}
600
Matthew G Smith88d29a92019-07-17 10:01:17 -0500601#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100602void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500603ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100604{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500605 ip4_main_t *im = &ip4_main;
John Lo4a302ee2020-05-12 22:34:39 -0400606 vnet_main_t *vnm = vnet_get_main ();
607 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100609 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
610
611 /*
612 * enable/disable only on the 1<->0 transition
613 */
614 if (is_enable)
615 {
616 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500617 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100618 }
619 else
620 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500621 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100622 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500623 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100624 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800625 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800626 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100627
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100628
Neale Ranns8269d3d2018-01-30 09:02:20 -0800629 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400630 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000631
John Lo4a302ee2020-05-12 22:34:39 -0400632 if (is_enable)
633 hi->l3_if_count++;
634 else if (hi->l3_if_count)
635 hi->l3_if_count--;
636
Neale Ranns57e53bb2019-05-29 13:58:43 +0000637 {
638 ip4_enable_disable_interface_callback_t *cb;
639 vec_foreach (cb, im->enable_disable_interface_callbacks)
640 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
641 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644static clib_error_t *
645ip4_add_del_interface_address_internal (vlib_main_t * vm,
646 u32 sw_if_index,
647 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500648 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500650 vnet_main_t *vnm = vnet_get_main ();
651 ip4_main_t *im = &ip4_main;
652 ip_lookup_main_t *lm = &im->lookup_main;
653 clib_error_t *error = 0;
Neale Ranns59f71132020-04-08 12:19:38 +0000654 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500655 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656
Pim van Pelt76b19ce2021-08-10 23:44:44 +0200657 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
658 if (error)
Matthew Smith1b6c7932021-09-24 15:27:36 -0500659 {
660 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
661 return error;
662 }
Pavel Kotucek57808982017-08-02 08:20:19 +0200663
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664 ip4_addr_fib_init (&ip4_af, address,
665 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
666 vec_add1 (addr_fib, ip4_af);
667
Neale Ranns744902e2017-08-14 10:35:44 -0700668 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100669 * there is no support for adj-fib handling in the presence of overlapping
670 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
671 * most routers do.
672 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000673 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500674 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700675 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100676 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700677 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500678 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700679 vnet_sw_interface_t *sif;
680
Damjan Marionb2c31b62020-12-13 21:47:40 +0100681 pool_foreach (sif, vnm->interface_main.sw_interfaces)
682 {
Neale Ranns744902e2017-08-14 10:35:44 -0700683 if (im->fib_index_by_sw_if_index[sw_if_index] ==
684 im->fib_index_by_sw_if_index[sif->sw_if_index])
685 {
686 foreach_ip_interface_address
687 (&im->lookup_main, ia, sif->sw_if_index,
688 0 /* honor unnumbered */ ,
689 ({
690 ip4_address_t * x =
691 ip_interface_address_get_address
692 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000693
Neale Ranns744902e2017-08-14 10:35:44 -0700694 if (ip4_destination_matches_route
695 (im, address, x, ia->address_length) ||
696 ip4_destination_matches_route (im,
697 x,
698 address,
699 address_length))
700 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500701 /* an intf may have >1 addr from the same prefix */
702 if ((sw_if_index == sif->sw_if_index) &&
703 (ia->address_length == address_length) &&
704 (x->as_u32 != address->as_u32))
705 continue;
706
Neale Ranns59f71132020-04-08 12:19:38 +0000707 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
708 /* if the address we're comparing against is stale
709 * then the CP has not added this one back yet, maybe
710 * it never will, so we have to assume it won't and
711 * ignore it. if it does add it back, then it will fail
712 * because this one is now present */
713 continue;
Neale Ranns744902e2017-08-14 10:35:44 -0700714
Neale Ranns59f71132020-04-08 12:19:38 +0000715 /* error if the length or intf was different */
716 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
717
718 error = clib_error_create
Ole Troan33a58172019-09-04 09:12:29 +0200719 ("failed to add %U on %U which conflicts with %U for interface %U",
Neale Ranns744902e2017-08-14 10:35:44 -0700720 format_ip4_address_and_length, address,
721 address_length,
Ole Troan33a58172019-09-04 09:12:29 +0200722 format_vnet_sw_if_index_name, vnm,
723 sw_if_index,
Neale Ranns744902e2017-08-14 10:35:44 -0700724 format_ip4_address_and_length, x,
725 ia->address_length,
726 format_vnet_sw_if_index_name, vnm,
727 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000728 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700729 }
730 }));
731 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100732 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000734 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735
Neale Ranns59f71132020-04-08 12:19:38 +0000736 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737
Neale Ranns59f71132020-04-08 12:19:38 +0000738 if (is_del)
739 {
740 if (~0 == if_address_index)
741 {
742 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
743 error = clib_error_create ("%U not found for interface %U",
744 lm->format_address_and_length,
745 addr_fib, address_length,
746 format_vnet_sw_if_index_name, vnm,
747 sw_if_index);
748 goto done;
749 }
750
yedgdbd366b2020-05-14 10:51:53 +0800751 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
752 address_length, sw_if_index);
753 if (error)
754 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000755 }
756 else
757 {
758 if (~0 != if_address_index)
759 {
760 ip_interface_address_t *ia;
761
762 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
763
764 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
765 {
766 if (ia->sw_if_index == sw_if_index)
767 {
768 /* re-adding an address during the replace action.
769 * consdier this the update. clear the flag and
770 * we're done */
771 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
772 goto done;
773 }
774 else
775 {
776 /* The prefix is moving from one interface to another.
777 * delete the stale and add the new */
778 ip4_add_del_interface_address_internal (vm,
779 ia->sw_if_index,
780 address,
781 address_length, 1);
782 ia = NULL;
783 error = ip_interface_address_add (lm, sw_if_index,
784 addr_fib, address_length,
785 &if_address_index);
786 }
787 }
788 else
789 {
790 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
791 error = clib_error_create
792 ("Prefix %U already found on interface %U",
793 lm->format_address_and_length, addr_fib, address_length,
794 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
795 }
796 }
797 else
798 error = ip_interface_address_add (lm, sw_if_index,
799 addr_fib, address_length,
800 &if_address_index);
801 }
802
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 if (error)
804 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400805
Dave Barachd7cb1b52016-12-09 09:52:16 -0500806 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns03c254e2020-03-17 14:25:10 +0000807 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100808
Matthew G Smith88d29a92019-07-17 10:01:17 -0500809 /* intf addr routes are added/deleted on admin up/down */
810 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
811 {
812 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500813 ip4_del_interface_routes (sw_if_index,
814 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500815 address_length);
816 else
817 ip4_add_interface_routes (sw_if_index,
818 im, ip4_af.fib_index,
819 pool_elt_at_index
820 (lm->if_address_pool, if_address_index));
821 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822
Neale Ranns59f71132020-04-08 12:19:38 +0000823 ip4_add_del_interface_address_callback_t *cb;
824 vec_foreach (cb, im->add_del_interface_address_callbacks)
825 cb->function (im, cb->function_opaque, sw_if_index,
826 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827
Dave Barachd7cb1b52016-12-09 09:52:16 -0500828done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700829 vec_free (addr_fib);
830 return error;
831}
832
833clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000834ip4_add_del_interface_address (vlib_main_t * vm,
835 u32 sw_if_index,
836 ip4_address_t * address,
837 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838{
839 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500840 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700841}
842
Neale Ranns1855b8e2018-07-11 10:31:26 -0700843void
844ip4_directed_broadcast (u32 sw_if_index, u8 enable)
845{
846 ip_interface_address_t *ia;
847 ip4_main_t *im;
848
849 im = &ip4_main;
850
851 /*
852 * when directed broadcast is enabled, the subnet braodcast route will forward
853 * packets using an adjacency with a broadcast MAC. otherwise it drops
854 */
855 /* *INDENT-OFF* */
856 foreach_ip_interface_address(&im->lookup_main, ia,
857 sw_if_index, 0,
858 ({
859 if (ia->address_length <= 30)
860 {
861 ip4_address_t *ipa;
862
863 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
864
865 fib_prefix_t pfx = {
866 .fp_len = 32,
867 .fp_proto = FIB_PROTOCOL_IP4,
868 .fp_addr = {
869 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
870 },
871 };
872
873 ip4_add_subnet_bcast_route
874 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
875 sw_if_index),
876 &pfx, sw_if_index);
877 }
878 }));
879 /* *INDENT-ON* */
880}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200881#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700882
Matthew G Smith88d29a92019-07-17 10:01:17 -0500883static clib_error_t *
884ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
885{
886 ip4_main_t *im = &ip4_main;
887 ip_interface_address_t *ia;
888 ip4_address_t *a;
889 u32 is_admin_up, fib_index;
890
Matthew G Smith88d29a92019-07-17 10:01:17 -0500891 vec_validate_init_empty (im->
892 lookup_main.if_address_pool_index_by_sw_if_index,
893 sw_if_index, ~0);
894
895 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
896
897 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
898
899 /* *INDENT-OFF* */
900 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
901 0 /* honor unnumbered */,
902 ({
903 a = ip_interface_address_get_address (&im->lookup_main, ia);
904 if (is_admin_up)
905 ip4_add_interface_routes (sw_if_index,
906 im, fib_index,
907 ia);
908 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500909 ip4_del_interface_routes (sw_if_index,
910 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500911 a, ia->address_length);
912 }));
913 /* *INDENT-ON* */
914
915 return 0;
916}
917
918VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
919
Dave Barachd6534602016-06-14 18:38:02 -0400920/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500921/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100922VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
923{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500924 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100925 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500926 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100927 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
928};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100929
Dave Barachd7cb1b52016-12-09 09:52:16 -0500930VNET_FEATURE_INIT (ip4_flow_classify, static) =
931{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100932 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700933 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100934 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700935};
936
Dave Barachd7cb1b52016-12-09 09:52:16 -0500937VNET_FEATURE_INIT (ip4_inacl, static) =
938{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100939 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400940 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100941 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400942};
943
Dave Barachd7cb1b52016-12-09 09:52:16 -0500944VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
945{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100946 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400947 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100948 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400949};
950
Dave Barachd7cb1b52016-12-09 09:52:16 -0500951VNET_FEATURE_INIT (ip4_policer_classify, static) =
952{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100953 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700954 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100955 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700956};
957
Dave Barachd7cb1b52016-12-09 09:52:16 -0500958VNET_FEATURE_INIT (ip4_ipsec, static) =
959{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100960 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100961 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100962 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400963};
964
Dave Barachd7cb1b52016-12-09 09:52:16 -0500965VNET_FEATURE_INIT (ip4_vpath, static) =
966{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100967 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400968 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500969 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
970};
971
Dave Barachd7cb1b52016-12-09 09:52:16 -0500972VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
973{
John Lo37682e12016-11-30 12:51:39 -0500974 .arc_name = "ip4-unicast",
975 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100976 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400977};
978
Neale Ranns8269d3d2018-01-30 09:02:20 -0800979VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500980{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100981 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800982 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400983 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100984};
985
Neale Ranns180279b2017-03-16 15:49:09 -0400986VNET_FEATURE_INIT (ip4_lookup, static) =
987{
988 .arc_name = "ip4-unicast",
989 .node_name = "ip4-lookup",
990 .runs_before = 0, /* not before any other features */
991};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100992
Dave Barachd6534602016-06-14 18:38:02 -0400993/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100994VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
995{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500996 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100997 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500998 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100999 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1000};
1001
Dave Barachd7cb1b52016-12-09 09:52:16 -05001002VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1003{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001004 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001005 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001006 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001007};
1008
Neale Ranns8269d3d2018-01-30 09:02:20 -08001009VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001010{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001011 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -08001012 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -04001013 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1014};
1015
1016VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1017{
1018 .arc_name = "ip4-multicast",
1019 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001020 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001021};
Dave Barach5331c722016-08-17 11:54:30 -04001022
1023/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001024VNET_FEATURE_ARC_INIT (ip4_output, static) =
1025{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001027 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001028 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001029 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1030};
Dave Barach5331c722016-08-17 11:54:30 -04001031
Dave Barachd7cb1b52016-12-09 09:52:16 -05001032VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1033{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001034 .arc_name = "ip4-output",
1035 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001036 .runs_before = VNET_FEATURES ("ip4-outacl"),
1037};
1038
1039VNET_FEATURE_INIT (ip4_outacl, static) =
1040{
1041 .arc_name = "ip4-output",
1042 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001043 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001044};
1045
Dave Barachd7cb1b52016-12-09 09:52:16 -05001046VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1047{
Matus Fabian08a6f012016-11-15 06:08:51 -08001048 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001049 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001050 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001051};
1052
1053/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001054VNET_FEATURE_INIT (ip4_interface_output, static) =
1055{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001056 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001057 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001058 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001059};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001060/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001061
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001063ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001064{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001065 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001067 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1068 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001069
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001070 if (is_add)
1071 {
1072 /* Fill in lookup tables with default table (0). */
1073 im->fib_index_by_sw_if_index[sw_if_index] = 0;
1074 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1075 }
1076 else
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001077 {
1078 ip4_main_t *im4 = &ip4_main;
1079 ip_lookup_main_t *lm4 = &im4->lookup_main;
1080 ip_interface_address_t *ia = 0;
1081 ip4_address_t *address;
1082 vlib_main_t *vm = vlib_get_main ();
1083
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001084 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001085 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001086 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001087 ({
1088 address = ip_interface_address_get_address (lm4, ia);
1089 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1090 }));
1091 /* *INDENT-ON* */
Neale Ranns03c254e2020-03-17 14:25:10 +00001092 ip4_mfib_interface_enable_disable (sw_if_index, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001093 }
1094
Neale Ranns8269d3d2018-01-30 09:02:20 -08001095 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001096 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097
Neale Ranns8269d3d2018-01-30 09:02:20 -08001098 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1099 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101 return /* no error */ 0;
1102}
1103
1104VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1105
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001107#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001109#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001111static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112ip4_lookup_init (vlib_main_t * vm)
1113{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001114 ip4_main_t *im = &ip4_main;
1115 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 uword i;
1117
Damjan Marion8b3191e2016-11-09 19:54:20 +01001118 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1119 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001120 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1121 return (error);
1122 if ((error = vlib_call_init_function (vm, fib_module_init)))
1123 return error;
1124 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1125 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001126
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1128 {
1129 u32 m;
1130
1131 if (i < 32)
1132 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001133 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001134 m = ~0;
1135 im->fib_masks[i] = clib_host_to_net_u32 (m);
1136 }
1137
Ed Warnickecb9cada2015-12-08 15:45:58 -07001138 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1139
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001140 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001141 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1142 FIB_SOURCE_DEFAULT_ROUTE);
1143 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1144 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001145
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001147 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148 pn = pg_get_node (ip4_lookup_node.index);
1149 pn->unformat_edit = unformat_pg_ip4_header;
1150 }
1151
1152 {
1153 ethernet_arp_header_t h;
1154
Dave Barachb7b92992018-10-17 10:38:51 -04001155 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156
Ed Warnickecb9cada2015-12-08 15:45:58 -07001157#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1158#define _8(f,v) h.f = v;
1159 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1160 _16 (l3_type, ETHERNET_TYPE_IP4);
1161 _8 (n_l2_address_bytes, 6);
1162 _8 (n_l3_address_bytes, 4);
1163 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1164#undef _16
1165#undef _8
1166
Dave Barachd7cb1b52016-12-09 09:52:16 -05001167 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 /* data */ &h,
1169 sizeof (h),
1170 /* alloc chunk size */ 8,
1171 "ip4 arp");
1172 }
1173
Dave Barach203c6322016-06-26 10:29:03 -04001174 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175}
1176
1177VLIB_INIT_FUNCTION (ip4_lookup_init);
1178
Dave Barachd7cb1b52016-12-09 09:52:16 -05001179typedef struct
1180{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001182 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001183 u32 flow_hash;
1184 u32 fib_index;
1185
1186 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001187 u8 packet_data[64 - 1 * sizeof (u32)];
1188}
1189ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001191#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001192u8 *
1193format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001194{
1195 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1196 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001197 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001198 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001199 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001200 format_white_space, indent,
1201 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001202 return s;
1203}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001204#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001205
Dave Barachd7cb1b52016-12-09 09:52:16 -05001206static u8 *
1207format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001208{
1209 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1210 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001212 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213
John Loac8146c2016-09-27 17:44:02 -04001214 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001215 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001216 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001217 format_white_space, indent,
1218 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001219 return s;
1220}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222static u8 *
1223format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001224{
1225 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1226 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001227 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001228 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229
Vengada Govindanf1544482016-09-28 02:45:57 -07001230 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001231 t->fib_index, t->dpo_index, format_ip_adjacency,
1232 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001233 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001234 format_white_space, indent,
1235 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001236 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237 return s;
1238}
1239
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001240#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241/* Common trace function for all ip4-forward next nodes. */
1242void
1243ip4_forward_next_trace (vlib_main_t * vm,
1244 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001245 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001246{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001247 u32 *from, n_left;
1248 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249
1250 n_left = frame->n_vectors;
1251 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001252
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253 while (n_left >= 4)
1254 {
1255 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001256 vlib_buffer_t *b0, *b1;
1257 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258
1259 /* Prefetch next iteration. */
1260 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1261 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1262
1263 bi0 = from[0];
1264 bi1 = from[1];
1265
1266 b0 = vlib_get_buffer (vm, bi0);
1267 b1 = vlib_get_buffer (vm, bi1);
1268
1269 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1270 {
1271 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001272 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001273 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001274 t0->fib_index =
1275 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1276 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1277 vec_elt (im->fib_index_by_sw_if_index,
1278 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001279
Dave Barach178cf492018-11-13 16:34:13 -05001280 clib_memcpy_fast (t0->packet_data,
1281 vlib_buffer_get_current (b0),
1282 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283 }
1284 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1285 {
1286 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001287 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001288 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001289 t1->fib_index =
1290 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1291 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1292 vec_elt (im->fib_index_by_sw_if_index,
1293 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001294 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1295 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296 }
1297 from += 2;
1298 n_left -= 2;
1299 }
1300
1301 while (n_left >= 1)
1302 {
1303 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001304 vlib_buffer_t *b0;
1305 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306
1307 bi0 = from[0];
1308
1309 b0 = vlib_get_buffer (vm, bi0);
1310
1311 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1312 {
1313 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001314 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001315 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001316 t0->fib_index =
1317 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1318 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1319 vec_elt (im->fib_index_by_sw_if_index,
1320 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001321 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1322 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 }
1324 from += 1;
1325 n_left -= 1;
1326 }
1327}
1328
Ed Warnickecb9cada2015-12-08 15:45:58 -07001329/* Compute TCP/UDP/ICMP4 checksum in software. */
1330u16
1331ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1332 ip4_header_t * ip0)
1333{
1334 ip_csum_t sum0;
1335 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001336
Ed Warnickecb9cada2015-12-08 15:45:58 -07001337 /* Initialize checksum with ip header. */
1338 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001339 payload_length_host_byte_order =
1340 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1341 sum0 =
1342 clib_host_to_net_u32 (payload_length_host_byte_order +
1343 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001344
1345 if (BITS (uword) == 32)
1346 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001347 sum0 =
1348 ip_csum_with_carry (sum0,
1349 clib_mem_unaligned (&ip0->src_address, u32));
1350 sum0 =
1351 ip_csum_with_carry (sum0,
1352 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001353 }
1354 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001355 sum0 =
1356 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001357
Srikanth A02833ff2019-10-02 17:48:58 -07001358 return ip_calculate_l4_checksum (vm, p0, sum0,
1359 payload_length_host_byte_order, (u8 *) ip0,
1360 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001361}
1362
John Lo37682e12016-11-30 12:51:39 -05001363u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1365{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001366 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1367 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001368 u16 sum16;
1369
1370 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1371 || ip0->protocol == IP_PROTOCOL_UDP);
1372
1373 udp0 = (void *) (ip0 + 1);
1374 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1375 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001376 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1377 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001378 return p0->flags;
1379 }
1380
1381 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1382
Damjan Marion213b5aa2017-07-13 21:19:27 +02001383 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1384 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001385
1386 return p0->flags;
1387}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001388#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389
Dave Barach68b0fb02017-02-28 15:15:56 -05001390/* *INDENT-OFF* */
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001391VNET_FEATURE_ARC_INIT (ip4_local) = {
1392 .arc_name = "ip4-local",
1393 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
Dave Baracha25def72018-11-26 11:04:45 -05001394 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001395};
1396/* *INDENT-ON* */
1397
Florin Coras20a14b92017-08-15 22:47:22 -07001398static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001399ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1400 ip4_header_t * ip, u8 is_udp, u8 * error,
1401 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001402{
1403 u32 flags0;
1404 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1405 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1406 if (is_udp)
1407 {
1408 udp_header_t *udp;
1409 u32 ip_len, udp_len;
1410 i32 len_diff;
1411 udp = ip4_next_header (ip);
1412 /* Verify UDP length. */
1413 ip_len = clib_net_to_host_u16 (ip->length);
1414 udp_len = clib_net_to_host_u16 (udp->length);
1415
1416 len_diff = ip_len - udp_len;
1417 *good_tcp_udp &= len_diff >= 0;
1418 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1419 }
1420}
1421
Mohsin Kazmi68095382021-02-10 11:26:24 +01001422#define ip4_local_csum_is_offloaded(_b) \
1423 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001424 (vnet_buffer (_b)->oflags & \
Mohsin Kazmi68095382021-02-10 11:26:24 +01001425 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
Florin Coras1b255522018-06-01 12:22:23 -07001426
1427#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1428 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1429 || ip4_local_csum_is_offloaded (_b)))
1430
1431#define ip4_local_csum_is_valid(_b) \
1432 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1433 || (ip4_local_csum_is_offloaded (_b))) != 0
1434
1435static inline void
1436ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1437 ip4_header_t * ih, u8 * error)
1438{
1439 u8 is_udp, is_tcp_udp, good_tcp_udp;
1440
1441 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1442 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1443
1444 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1445 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1446 else
1447 good_tcp_udp = ip4_local_csum_is_valid (b);
1448
1449 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1450 *error = (is_tcp_udp && !good_tcp_udp
1451 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1452}
1453
1454static inline void
1455ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1456 ip4_header_t ** ih, u8 * error)
1457{
1458 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1459
1460 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1461 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1462
1463 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1464 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1465
1466 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1467 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1468
1469 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1470 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1471 {
1472 if (is_tcp_udp[0])
1473 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1474 &good_tcp_udp[0]);
1475 if (is_tcp_udp[1])
1476 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1477 &good_tcp_udp[1]);
1478 }
1479
1480 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1481 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1482 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1483 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1484}
1485
1486static inline void
1487ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1488 vlib_buffer_t * b, u16 * next, u8 error,
1489 u8 head_of_feature_arc)
1490{
1491 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1492 u32 next_index;
1493
1494 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1495 b->error = error ? error_node->errors[error] : 0;
1496 if (head_of_feature_arc)
1497 {
1498 next_index = *next;
1499 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1500 {
1501 vnet_feature_arc_start (arc_index,
1502 vnet_buffer (b)->sw_if_index[VLIB_RX],
1503 &next_index, b);
1504 *next = next_index;
1505 }
1506 }
1507}
1508
1509typedef struct
1510{
1511 ip4_address_t src;
1512 u32 lbi;
1513 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001514 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001515} ip4_local_last_check_t;
1516
1517static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001518ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1519 ip4_local_last_check_t *last_check, u8 *error0,
1520 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001521{
Florin Coras1b255522018-06-01 12:22:23 -07001522 const dpo_id_t *dpo0;
1523 load_balance_t *lb0;
1524 u32 lbi0;
1525
1526 vnet_buffer (b)->ip.fib_index =
1527 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1528 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1529
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001530 if (is_receive_dpo)
1531 {
1532 receive_dpo_t *rd;
1533 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
1534 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
1535 }
1536 else
Florin Coras904638f2021-11-10 07:39:51 -08001537 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001538
Matthew Smith44e60462019-07-06 19:27:29 -05001539 /*
1540 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1541 * adjacency for the destination address (the local interface address).
1542 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1543 * adjacency for the source address (the remote sender's address)
1544 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301545 if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
1546 last_check->first)
Florin Coras1b255522018-06-01 12:22:23 -07001547 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001548 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1549 &ip0->src_address);
Florin Coras1b255522018-06-01 12:22:23 -07001550
Matthew Smith44e60462019-07-06 19:27:29 -05001551 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1552 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001553 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001554
1555 lb0 = load_balance_get (lbi0);
1556 dpo0 = load_balance_get_bucket_i (lb0, 0);
1557
1558 /*
1559 * Must have a route to source otherwise we drop the packet.
1560 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1561 *
1562 * The checks are:
1563 * - the source is a recieve => it's from us => bogus, do this
1564 * first since it sets a different error code.
1565 * - uRPF check for any route to source - accept if passes.
1566 * - allow packets destined to the broadcast address from unknown sources
1567 */
1568
1569 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1570 && dpo0->dpoi_type == DPO_RECEIVE) ?
1571 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1572 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1573 && !fib_urpf_check_size (lb0->lb_urpf)
1574 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1575 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1576
1577 last_check->src.as_u32 = ip0->src_address.as_u32;
1578 last_check->lbi = lbi0;
1579 last_check->error = *error0;
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301580 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001581 }
1582 else
1583 {
Matthew Smith44e60462019-07-06 19:27:29 -05001584 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1585 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001586 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001587 *error0 = last_check->error;
1588 }
1589}
1590
1591static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001592ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1593 ip4_local_last_check_t *last_check, u8 *error,
1594 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001595{
Florin Coras1b255522018-06-01 12:22:23 -07001596 const dpo_id_t *dpo[2];
1597 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001598 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001599 u32 lbi[2];
1600
Neale Rannsbe2286b2018-12-09 12:54:51 -08001601 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001602 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1603 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1604
1605 vnet_buffer (b[0])->ip.fib_index =
1606 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1607 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1608 vnet_buffer (b[0])->ip.fib_index;
1609
1610 vnet_buffer (b[1])->ip.fib_index =
1611 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1612 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1613 vnet_buffer (b[1])->ip.fib_index;
1614
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001615 if (is_receive_dpo)
1616 {
1617 const receive_dpo_t *rd0, *rd1;
1618 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1619 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1620 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1621 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1622 }
1623 else
1624 {
Florin Coras904638f2021-11-10 07:39:51 -08001625 vnet_buffer (b[0])->ip.rx_sw_if_index =
1626 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1627 vnet_buffer (b[1])->ip.rx_sw_if_index =
1628 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001629 }
1630
Matthew Smith44e60462019-07-06 19:27:29 -05001631 /*
1632 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1633 * adjacency for the destination address (the local interface address).
1634 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1635 * adjacency for the source address (the remote sender's address)
1636 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301637 if (PREDICT_TRUE (not_last_hit))
Florin Coras1b255522018-06-01 12:22:23 -07001638 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001639 ip4_fib_forwarding_lookup_x2 (
1640 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1641 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001642
Matthew Smith44e60462019-07-06 19:27:29 -05001643 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1644 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001645 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001646
Matthew Smith44e60462019-07-06 19:27:29 -05001647 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1648 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001649 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001650
1651 lb[0] = load_balance_get (lbi[0]);
1652 lb[1] = load_balance_get (lbi[1]);
1653
1654 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1655 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1656
1657 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1658 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1659 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1660 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1661 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1662 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1663 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1664
1665 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1666 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1667 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1668 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1669 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1670 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1671 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1672
1673 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1674 last_check->lbi = lbi[1];
1675 last_check->error = error[1];
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301676 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001677 }
1678 else
1679 {
Matthew Smith44e60462019-07-06 19:27:29 -05001680 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1681 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001682 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001683
Matthew Smith44e60462019-07-06 19:27:29 -05001684 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1685 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001686 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001687
1688 error[0] = last_check->error;
1689 error[1] = last_check->error;
1690 }
1691}
Florin Coras20a14b92017-08-15 22:47:22 -07001692
Florin Corasc67cfd22018-10-01 21:59:18 -07001693enum ip_local_packet_type_e
1694{
1695 IP_LOCAL_PACKET_TYPE_L4,
1696 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001697 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001698};
1699
1700/**
1701 * Determine packet type and next node.
1702 *
1703 * The expectation is that all packets that are not L4 will skip
1704 * checksums and source checks.
1705 */
1706always_inline u8
1707ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1708{
1709 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1710
Juraj Sloboda3048b632018-10-02 11:13:53 +02001711 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1712 {
1713 *next = IP_LOCAL_NEXT_REASSEMBLY;
1714 return IP_LOCAL_PACKET_TYPE_FRAG;
1715 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001716 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1717 {
1718 *next = lm->local_next_by_ip_protocol[ip->protocol];
1719 return IP_LOCAL_PACKET_TYPE_NAT;
1720 }
1721
1722 *next = lm->local_next_by_ip_protocol[ip->protocol];
1723 return IP_LOCAL_PACKET_TYPE_L4;
1724}
1725
Dave Barach68b0fb02017-02-28 15:15:56 -05001726static inline uword
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001727ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1728 vlib_frame_t *frame, int head_of_feature_arc,
1729 int is_receive_dpo)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730{
Florin Coras1b255522018-06-01 12:22:23 -07001731 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001732 vlib_node_runtime_t *error_node =
Florin Corasfa2a3162020-02-11 03:01:19 +00001733 vlib_node_get_runtime (vm, ip4_local_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001734 u16 nexts[VLIB_FRAME_SIZE], *next;
1735 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1736 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001737 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001738
1739 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001740 /*
1741 * 0.0.0.0 can appear as the source address of an IP packet,
1742 * as can any other address, hence the need to use the 'first'
1743 * member to make sure the .lbi is initialised for the first
1744 * packet.
1745 */
Florin Coras1b255522018-06-01 12:22:23 -07001746 .src = {.as_u32 = 0},
1747 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001748 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1749 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001750 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751
1752 from = vlib_frame_vector_args (frame);
1753 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001754
Ed Warnickecb9cada2015-12-08 15:45:58 -07001755 if (node->flags & VLIB_NODE_FLAG_TRACE)
1756 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1757
Florin Coras1b255522018-06-01 12:22:23 -07001758 vlib_get_buffers (vm, from, bufs, n_left_from);
1759 b = bufs;
1760 next = nexts;
1761
1762 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001763 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001764 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765
Florin Coras1b255522018-06-01 12:22:23 -07001766 /* Prefetch next iteration. */
1767 {
1768 vlib_prefetch_buffer_header (b[4], LOAD);
1769 vlib_prefetch_buffer_header (b[5], LOAD);
1770
Damjan Marionaf7fb042021-07-15 11:54:41 +02001771 clib_prefetch_load (b[4]->data);
1772 clib_prefetch_load (b[5]->data);
Florin Coras1b255522018-06-01 12:22:23 -07001773 }
1774
1775 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1776
1777 ip[0] = vlib_buffer_get_current (b[0]);
1778 ip[1] = vlib_buffer_get_current (b[1]);
1779
1780 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1781 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1782
Florin Corasc67cfd22018-10-01 21:59:18 -07001783 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1784 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001785
Florin Corasc67cfd22018-10-01 21:59:18 -07001786 not_batch = pt[0] ^ pt[1];
1787
1788 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001789 goto skip_checks;
1790
1791 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001792 {
Florin Coras1b255522018-06-01 12:22:23 -07001793 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001794 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001795 }
1796 else
1797 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001798 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001799 {
Florin Coras1b255522018-06-01 12:22:23 -07001800 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001801 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1802 is_receive_dpo);
Florin Coras20a14b92017-08-15 22:47:22 -07001803 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001804 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001805 {
Florin Coras1b255522018-06-01 12:22:23 -07001806 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001807 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1808 is_receive_dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001809 }
1810 }
1811
Florin Coras1b255522018-06-01 12:22:23 -07001812 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001813
Florin Coras1b255522018-06-01 12:22:23 -07001814 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1815 head_of_feature_arc);
1816 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1817 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001818
Florin Coras1b255522018-06-01 12:22:23 -07001819 b += 2;
1820 next += 2;
1821 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001822 }
1823
Florin Coras1b255522018-06-01 12:22:23 -07001824 while (n_left_from > 0)
1825 {
1826 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1827
1828 ip[0] = vlib_buffer_get_current (b[0]);
1829 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001830 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001831
Florin Corasc67cfd22018-10-01 21:59:18 -07001832 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001833 goto skip_check;
1834
1835 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001836 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1837 is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001838
1839 skip_check:
1840
Florin Coras1b255522018-06-01 12:22:23 -07001841 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1842 head_of_feature_arc);
1843
1844 b += 1;
1845 next += 1;
1846 n_left_from -= 1;
1847 }
1848
1849 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001850 return frame->n_vectors;
1851}
1852
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001853VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1854 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001855{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001856 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1857 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001858}
1859
Neale Ranns32e1c012016-11-22 17:07:28 +00001860VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861{
Dave Barach68b0fb02017-02-28 15:15:56 -05001862 .name = "ip4-local",
1863 .vector_size = sizeof (u32),
1864 .format_trace = format_ip4_forward_next_trace,
Florin Corasfa2a3162020-02-11 03:01:19 +00001865 .n_errors = IP4_N_ERROR,
1866 .error_strings = ip4_error_strings,
Dave Barach68b0fb02017-02-28 15:15:56 -05001867 .n_next_nodes = IP_LOCAL_N_NEXT,
1868 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001869 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001870 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1871 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001872 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001873 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001874 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001875 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001876};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001877
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001878VLIB_NODE_FN (ip4_receive_local_node)
1879(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1880{
1881 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1882 1 /* is_receive_dpo */);
1883}
1884
1885VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1886 .name = "ip4-receive",
1887 .vector_size = sizeof (u32),
1888 .format_trace = format_ip4_forward_next_trace,
1889 .sibling_of = "ip4-local"
1890};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001891
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001892VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1893 vlib_node_runtime_t * node,
1894 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001895{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001896 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1897 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001898}
1899
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001900VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001901 .name = "ip4-local-end-of-arc",
1902 .vector_size = sizeof (u32),
1903
1904 .format_trace = format_ip4_forward_next_trace,
1905 .sibling_of = "ip4-local",
1906};
1907
Dave Barach68b0fb02017-02-28 15:15:56 -05001908VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1909 .arc_name = "ip4-local",
1910 .node_name = "ip4-local-end-of-arc",
1911 .runs_before = 0, /* not before any other features */
1912};
Dave Barach68b0fb02017-02-28 15:15:56 -05001913
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001914#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001915void
1916ip4_register_protocol (u32 protocol, u32 node_index)
1917{
1918 vlib_main_t *vm = vlib_get_main ();
1919 ip4_main_t *im = &ip4_main;
1920 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921
1922 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001923 lm->local_next_by_ip_protocol[protocol] =
1924 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001925}
Neale Rannsb538dd82019-05-21 06:54:54 -07001926
1927void
1928ip4_unregister_protocol (u32 protocol)
1929{
1930 ip4_main_t *im = &ip4_main;
1931 ip_lookup_main_t *lm = &im->lookup_main;
1932
1933 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1934 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1935}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001936#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001937
1938static clib_error_t *
1939show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001940 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001942 ip4_main_t *im = &ip4_main;
1943 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001944 int i;
1945
1946 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001947 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948 {
1949 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001950 {
1951 u32 node_index = vlib_get_node (vm,
1952 ip4_local_node.index)->
1953 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001954 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1955 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001956 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001957 }
1958 return 0;
1959}
1960
1961
1962
Billy McFall0683c9c2016-10-13 08:27:31 -04001963/*?
1964 * Display the set of protocols handled by the local IPv4 stack.
1965 *
1966 * @cliexpar
1967 * Example of how to display local protocol table:
1968 * @cliexstart{show ip local}
1969 * Protocols handled by ip4_local
1970 * 1
1971 * 17
1972 * 47
1973 * @cliexend
1974?*/
1975/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001976VLIB_CLI_COMMAND (show_ip_local, static) =
1977{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001978 .path = "show ip local",
1979 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001980 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001981};
Billy McFall0683c9c2016-10-13 08:27:31 -04001982/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983
Dave Barachd7cb1b52016-12-09 09:52:16 -05001984typedef enum
1985{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001986 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001987 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001988 IP4_REWRITE_NEXT_FRAGMENT,
1989 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001990} ip4_rewrite_next_t;
1991
Neale Ranns889fe942017-06-01 05:43:19 -04001992/**
1993 * This bits of an IPv4 address to mask to construct a multicast
1994 * MAC address
1995 */
1996#if CLIB_ARCH_IS_BIG_ENDIAN
1997#define IP4_MCAST_ADDR_MASK 0x007fffff
1998#else
1999#define IP4_MCAST_ADDR_MASK 0xffff7f00
2000#endif
2001
Ole Troan8a9c8f12018-05-18 11:01:31 +02002002always_inline void
2003ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Ole Troaneb284a12019-10-09 13:33:19 +02002004 u16 adj_packet_bytes, bool df, u16 * next,
2005 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002006{
2007 if (packet_len > adj_packet_bytes)
2008 {
2009 *error = IP4_ERROR_MTU_EXCEEDED;
2010 if (df)
2011 {
2012 icmp4_error_set_vnet_buffer
2013 (b, ICMP4_destination_unreachable,
2014 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2015 adj_packet_bytes);
2016 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2017 }
2018 else
2019 {
Ole Troan313f7e22018-04-10 16:02:51 +02002020 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002021 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00002022 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02002023 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2024 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002025 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002026 }
2027 }
2028}
2029
Neale Ranns0b6a8572019-10-30 17:34:14 +00002030/* increment TTL & update checksum.
2031 Works either endian, so no need for byte swap. */
2032static_always_inline void
2033ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2034{
2035 i32 ttl;
2036 u32 checksum;
2037 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002038 return;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002039
2040 ttl = ip->ttl;
2041
2042 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2043 checksum += checksum >= 0xffff;
2044
2045 ip->checksum = checksum;
2046 ttl += 1;
2047 ip->ttl = ttl;
2048
Benoît Ganne6e334e32020-08-31 18:59:34 +02002049 ASSERT (ip4_header_checksum_is_valid (ip));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002050}
2051
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002052/* Decrement TTL & update checksum.
2053 Works either endian, so no need for byte swap. */
2054static_always_inline void
2055ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2056 u32 * error)
2057{
2058 i32 ttl;
2059 u32 checksum;
2060 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002061 return;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002062
2063 ttl = ip->ttl;
2064
2065 /* Input node should have reject packets with ttl 0. */
2066 ASSERT (ip->ttl > 0);
2067
2068 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2069 checksum += checksum >= 0xffff;
2070
2071 ip->checksum = checksum;
2072 ttl -= 1;
2073 ip->ttl = ttl;
2074
2075 /*
2076 * If the ttl drops below 1 when forwarding, generate
2077 * an ICMP response.
2078 */
2079 if (PREDICT_FALSE (ttl <= 0))
2080 {
2081 *error = IP4_ERROR_TIME_EXPIRED;
2082 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2083 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2084 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2085 0);
2086 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2087 }
2088
2089 /* Verify checksum. */
Benoît Ganne6e334e32020-08-31 18:59:34 +02002090 ASSERT (ip4_header_checksum_is_valid (ip) ||
Mohsin Kazmi4fd9f102021-06-17 17:29:27 +00002091 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2092 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002093}
2094
Ed Warnickecb9cada2015-12-08 15:45:58 -07002095always_inline uword
Damjan Mariond06e2eb2021-04-21 23:44:40 +02002096ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2097 vlib_frame_t *frame, int do_counters, int is_midchain,
2098 int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002099{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002100 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2101 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002102 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2103 u16 nexts[VLIB_FRAME_SIZE], *next;
2104 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002105 vlib_node_runtime_t *error_node =
2106 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002107
2108 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002109 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002110
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002111 vlib_get_buffers (vm, from, bufs, n_left_from);
2112 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2113
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002114#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002115 if (n_left_from >= 6)
2116 {
2117 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002118 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002119 vlib_prefetch_buffer_header (bufs[i], LOAD);
2120 }
2121
2122 next = nexts;
2123 b = bufs;
2124 while (n_left_from >= 8)
2125 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002126 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002127 ip4_header_t *ip0, *ip1;
2128 u32 rw_len0, error0, adj_index0;
2129 u32 rw_len1, error1, adj_index1;
2130 u32 tx_sw_if_index0, tx_sw_if_index1;
2131 u8 *p;
2132
PiotrX Kleskib801cd12020-12-09 14:32:26 +01002133 if (is_midchain)
2134 {
2135 vlib_prefetch_buffer_header (b[6], LOAD);
2136 vlib_prefetch_buffer_header (b[7], LOAD);
2137 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002138
2139 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2140 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2141
2142 /*
2143 * pre-fetch the per-adjacency counters
2144 */
2145 if (do_counters)
2146 {
2147 vlib_prefetch_combined_counter (&adjacency_counters,
2148 thread_index, adj_index0);
2149 vlib_prefetch_combined_counter (&adjacency_counters,
2150 thread_index, adj_index1);
2151 }
2152
2153 ip0 = vlib_buffer_get_current (b[0]);
2154 ip1 = vlib_buffer_get_current (b[1]);
2155
2156 error0 = error1 = IP4_ERROR_NONE;
2157
2158 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2159 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2160
2161 /* Rewrite packet header and updates lengths. */
2162 adj0 = adj_get (adj_index0);
2163 adj1 = adj_get (adj_index1);
2164
2165 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2166 rw_len0 = adj0[0].rewrite_header.data_bytes;
2167 rw_len1 = adj1[0].rewrite_header.data_bytes;
2168 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2169 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2170
2171 p = vlib_buffer_get_current (b[2]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002172 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2173 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002174
2175 p = vlib_buffer_get_current (b[3]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002176 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2177 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002178
2179 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002180 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2181 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2182
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002183 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002184 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002185 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002186 ip1_len = gso_mtu_sz (b[1]);
2187
2188 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002189 adj0[0].rewrite_header.max_l3_packet_bytes,
2190 ip0->flags_and_fragment_offset &
2191 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002192 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002193 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002194 adj1[0].rewrite_header.max_l3_packet_bytes,
2195 ip1->flags_and_fragment_offset &
2196 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002197 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002198
2199 if (is_mcast)
2200 {
2201 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2202 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2203 IP4_ERROR_SAME_INTERFACE : error0);
2204 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2205 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2206 IP4_ERROR_SAME_INTERFACE : error1);
2207 }
2208
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002209 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002210 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002211 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2212 {
2213 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002214 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002215
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002216 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2217 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2218
2219 if (PREDICT_FALSE
2220 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002221 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2222 tx_sw_if_index0,
2223 &next_index, b[0],
2224 adj0->ia_cfg_index);
2225
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002226 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002227 if (is_midchain)
Dave Barach1bd2c012020-04-12 08:31:39 -04002228 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002229 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002230 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002231 else
2232 {
2233 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002234 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2235 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002236 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002237 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2238 {
2239 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002240 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002241
2242 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2243 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2244
2245 if (PREDICT_FALSE
2246 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002247 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2248 tx_sw_if_index1,
2249 &next_index, b[1],
2250 adj1->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002251 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002252 if (is_midchain)
Neale Rannsfc746972020-05-20 19:58:20 +00002253 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002254 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002255 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002256 else
2257 {
2258 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002259 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2260 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002261 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002262
Neale Ranns4ec36c52020-03-31 09:21:29 -04002263 if (is_midchain)
2264 /* Guess we are only writing on ipv4 header. */
2265 vnet_rewrite_two_headers (adj0[0], adj1[0],
2266 ip0, ip1, sizeof (ip4_header_t));
2267 else
2268 /* Guess we are only writing on simple Ethernet header. */
2269 vnet_rewrite_two_headers (adj0[0], adj1[0],
2270 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002271
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002272 if (do_counters)
2273 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002274 if (error0 == IP4_ERROR_NONE)
2275 vlib_increment_combined_counter
2276 (&adjacency_counters,
2277 thread_index,
2278 adj_index0, 1,
2279 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002280
Neale Ranns0b6a8572019-10-30 17:34:14 +00002281 if (error1 == IP4_ERROR_NONE)
2282 vlib_increment_combined_counter
2283 (&adjacency_counters,
2284 thread_index,
2285 adj_index1, 1,
2286 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002287 }
2288
2289 if (is_midchain)
2290 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002291 if (error0 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002292 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns4ec36c52020-03-31 09:21:29 -04002293 if (error1 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002294 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002295 }
2296
2297 if (is_mcast)
2298 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002299 /* copy bytes from the IP address into the MAC rewrite */
2300 if (error0 == IP4_ERROR_NONE)
2301 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2302 adj0->rewrite_header.dst_mcast_offset,
2303 &ip0->dst_address.as_u32, (u8 *) ip0);
2304 if (error1 == IP4_ERROR_NONE)
2305 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2306 adj1->rewrite_header.dst_mcast_offset,
2307 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002308 }
2309
2310 next += 2;
2311 b += 2;
2312 n_left_from -= 2;
2313 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002314#elif (CLIB_N_PREFETCHES >= 4)
2315 next = nexts;
2316 b = bufs;
2317 while (n_left_from >= 1)
2318 {
2319 ip_adjacency_t *adj0;
2320 ip4_header_t *ip0;
2321 u32 rw_len0, error0, adj_index0;
2322 u32 tx_sw_if_index0;
2323 u8 *p;
2324
2325 /* Prefetch next iteration */
2326 if (PREDICT_TRUE (n_left_from >= 4))
2327 {
2328 ip_adjacency_t *adj2;
2329 u32 adj_index2;
2330
2331 vlib_prefetch_buffer_header (b[3], LOAD);
2332 vlib_prefetch_buffer_data (b[2], LOAD);
2333
2334 /* Prefetch adj->rewrite_header */
2335 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2336 adj2 = adj_get (adj_index2);
2337 p = (u8 *) adj2;
2338 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2339 LOAD);
2340 }
2341
2342 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2343
2344 /*
2345 * Prefetch the per-adjacency counters
2346 */
2347 if (do_counters)
2348 {
2349 vlib_prefetch_combined_counter (&adjacency_counters,
2350 thread_index, adj_index0);
2351 }
2352
2353 ip0 = vlib_buffer_get_current (b[0]);
2354
2355 error0 = IP4_ERROR_NONE;
2356
2357 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2358
2359 /* Rewrite packet header and updates lengths. */
2360 adj0 = adj_get (adj_index0);
2361
2362 /* Rewrite header was prefetched. */
2363 rw_len0 = adj0[0].rewrite_header.data_bytes;
2364 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2365
2366 /* Check MTU of outgoing interface. */
2367 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2368
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002369 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002370 ip0_len = gso_mtu_sz (b[0]);
2371
2372 ip4_mtu_check (b[0], ip0_len,
2373 adj0[0].rewrite_header.max_l3_packet_bytes,
2374 ip0->flags_and_fragment_offset &
2375 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002376 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002377
2378 if (is_mcast)
2379 {
2380 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2381 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2382 IP4_ERROR_SAME_INTERFACE : error0);
2383 }
2384
2385 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2386 * to see the IP header */
2387 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2388 {
2389 u32 next_index = adj0[0].rewrite_header.next_index;
2390 vlib_buffer_advance (b[0], -(word) rw_len0);
2391 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2392 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2393
2394 if (PREDICT_FALSE
2395 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002396 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2397 tx_sw_if_index0,
2398 &next_index, b[0],
2399 adj0->ia_cfg_index);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002400 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002401
2402 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002403 {
2404 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002405 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002406
Neale Ranns4ec36c52020-03-31 09:21:29 -04002407 /* Guess we are only writing on ipv4 header. */
2408 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2409 }
2410 else
2411 /* Guess we are only writing on simple Ethernet header. */
2412 vnet_rewrite_one_header (adj0[0], ip0,
2413 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002414
2415 /*
2416 * Bump the per-adjacency counters
2417 */
2418 if (do_counters)
2419 vlib_increment_combined_counter
2420 (&adjacency_counters,
2421 thread_index,
2422 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2423 b[0]) + rw_len0);
2424
Neale Ranns4ec36c52020-03-31 09:21:29 -04002425 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002426 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002427
2428 if (is_mcast)
2429 /* copy bytes from the IP address into the MAC rewrite */
2430 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2431 adj0->rewrite_header.dst_mcast_offset,
2432 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002433 }
2434 else
2435 {
2436 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002437 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2438 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002439 }
2440
2441 next += 1;
2442 b += 1;
2443 n_left_from -= 1;
2444 }
2445#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002446
Ed Warnickecb9cada2015-12-08 15:45:58 -07002447 while (n_left_from > 0)
2448 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002449 ip_adjacency_t *adj0;
2450 ip4_header_t *ip0;
2451 u32 rw_len0, adj_index0, error0;
2452 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002453
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002454 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2455
2456 adj0 = adj_get (adj_index0);
2457
2458 if (do_counters)
2459 vlib_prefetch_combined_counter (&adjacency_counters,
2460 thread_index, adj_index0);
2461
2462 ip0 = vlib_buffer_get_current (b[0]);
2463
2464 error0 = IP4_ERROR_NONE;
2465
2466 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2467
2468
2469 /* Update packet buffer attributes/set output interface. */
2470 rw_len0 = adj0[0].rewrite_header.data_bytes;
2471 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2472
2473 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002474 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002475 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002476 ip0_len = gso_mtu_sz (b[0]);
2477
2478 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002479 adj0[0].rewrite_header.max_l3_packet_bytes,
2480 ip0->flags_and_fragment_offset &
2481 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002482 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002483
2484 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002485 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002486 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2487 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2488 IP4_ERROR_SAME_INTERFACE : error0);
2489 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002490
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002491 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002492 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002493 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2494 {
2495 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002496 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002497 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2498 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002499
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002500 if (PREDICT_FALSE
2501 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002502 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2503 tx_sw_if_index0,
2504 &next_index, b[0],
2505 adj0->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002506 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002507
2508 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002509 {
2510 /* this acts on the packet that is about to be encapped */
2511 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002512 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002513
Neale Ranns4ec36c52020-03-31 09:21:29 -04002514 /* Guess we are only writing on ipv4 header. */
2515 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2516 }
2517 else
2518 /* Guess we are only writing on simple Ethernet header. */
2519 vnet_rewrite_one_header (adj0[0], ip0,
2520 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002521
2522 if (do_counters)
2523 vlib_increment_combined_counter
2524 (&adjacency_counters,
2525 thread_index, adj_index0, 1,
2526 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2527
Neale Rannse2fe0972020-11-26 08:37:27 +00002528 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002529 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002530
2531 if (is_mcast)
2532 /* copy bytes from the IP address into the MAC rewrite */
2533 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2534 adj0->rewrite_header.dst_mcast_offset,
2535 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002536 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002537 else
2538 {
2539 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002540 /* undo the TTL decrement - we'll be back to do it again */
2541 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2542 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002543 }
2544
2545 next += 1;
2546 b += 1;
2547 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002548 }
2549
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002550
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551 /* Need to do trace after rewrites to pick up new packet data. */
2552 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002553 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002554
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002555 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002556 return frame->n_vectors;
2557}
2558
Neale Rannsf06aea52016-11-29 06:51:37 -08002559/** @brief IPv4 rewrite node.
2560 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002561
2562 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2563 header checksum, fetch the ip adjacency, check the outbound mtu,
2564 apply the adjacency rewrite, and send pkts to the adjacency
2565 rewrite header's rewrite_next_index.
2566
2567 @param vm vlib_main_t corresponding to the current thread
2568 @param node vlib_node_runtime_t
2569 @param frame vlib_frame_t whose contents should be dispatched
2570
2571 @par Graph mechanics: buffer metadata, next index usage
2572
2573 @em Uses:
2574 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2575 - the rewrite adjacency index
2576 - <code>adj->lookup_next_index</code>
2577 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002578 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002579 - <code>adj->rewrite_header</code>
2580 - Rewrite string length, rewrite string, next_index
2581
2582 @em Sets:
2583 - <code>b->current_data, b->current_length</code>
2584 - Updated net of applying the rewrite string
2585
2586 <em>Next Indices:</em>
2587 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002588 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002589*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002590
2591VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2592 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002593{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002594 if (adj_are_counters_enabled ())
2595 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2596 else
2597 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002598}
2599
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002600VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2601 vlib_node_runtime_t * node,
2602 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002603{
2604 if (adj_are_counters_enabled ())
2605 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2606 else
2607 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2608}
2609
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002610VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2611 vlib_node_runtime_t * node,
2612 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002613{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002614 if (adj_are_counters_enabled ())
2615 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2616 else
2617 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002618}
2619
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002620VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2621 vlib_node_runtime_t * node,
2622 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002623{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002624 if (adj_are_counters_enabled ())
2625 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2626 else
2627 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002628}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002630VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2631 vlib_node_runtime_t * node,
2632 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002633{
2634 if (adj_are_counters_enabled ())
2635 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2636 else
2637 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2638}
2639
Neale Ranns32e1c012016-11-22 17:07:28 +00002640/* *INDENT-OFF* */
2641VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002642 .name = "ip4-rewrite",
2643 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002644
Neale Ranns32e1c012016-11-22 17:07:28 +00002645 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002646
Ole Troan313f7e22018-04-10 16:02:51 +02002647 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002648 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002649 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002650 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002651 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002652 },
2653};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002654
2655VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002656 .name = "ip4-rewrite-bcast",
2657 .vector_size = sizeof (u32),
2658
2659 .format_trace = format_ip4_rewrite_trace,
2660 .sibling_of = "ip4-rewrite",
2661};
Neale Ranns32e1c012016-11-22 17:07:28 +00002662
2663VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002664 .name = "ip4-rewrite-mcast",
2665 .vector_size = sizeof (u32),
2666
2667 .format_trace = format_ip4_rewrite_trace,
2668 .sibling_of = "ip4-rewrite",
2669};
Neale Ranns32e1c012016-11-22 17:07:28 +00002670
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002671VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002672 .name = "ip4-mcast-midchain",
2673 .vector_size = sizeof (u32),
2674
2675 .format_trace = format_ip4_rewrite_trace,
2676 .sibling_of = "ip4-rewrite",
2677};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002678
Neale Ranns32e1c012016-11-22 17:07:28 +00002679VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002680 .name = "ip4-midchain",
2681 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002682 .format_trace = format_ip4_rewrite_trace,
2683 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002684};
Neale Ranns32e1c012016-11-22 17:07:28 +00002685/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002686
Ed Warnickecb9cada2015-12-08 15:45:58 -07002687static clib_error_t *
2688set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002689 unformat_input_t * input,
2690 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002691{
2692 int matched = 0;
2693 u32 table_id = 0;
2694 u32 flow_hash_config = 0;
2695 int rv;
2696
Dave Barachd7cb1b52016-12-09 09:52:16 -05002697 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2698 {
2699 if (unformat (input, "table %d", &table_id))
2700 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002701#define _(a, b, v) \
2702 else if (unformat (input, #a)) \
2703 { \
2704 flow_hash_config |= v; \
2705 matched = 1; \
2706 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002707 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002708#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002709 else
2710 break;
2711 }
Dave Barach75fc8542016-10-11 16:16:02 -04002712
Ed Warnickecb9cada2015-12-08 15:45:58 -07002713 if (matched == 0)
2714 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002715 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002716
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002717 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002718 switch (rv)
2719 {
2720 case 0:
2721 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002722
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723 case VNET_API_ERROR_NO_SUCH_FIB:
2724 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002725
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726 default:
2727 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2728 break;
2729 }
Dave Barach75fc8542016-10-11 16:16:02 -04002730
Ed Warnickecb9cada2015-12-08 15:45:58 -07002731 return 0;
2732}
Dave Barach75fc8542016-10-11 16:16:02 -04002733
Billy McFall0683c9c2016-10-13 08:27:31 -04002734/*?
2735 * Configure the set of IPv4 fields used by the flow hash.
2736 *
2737 * @cliexpar
2738 * Example of how to set the flow hash on a given table:
2739 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2740 * Example of display the configured flow hash:
2741 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002742 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2743 * 0.0.0.0/0
2744 * unicast-ip4-chain
2745 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2746 * [0] [@0]: dpo-drop ip6
2747 * 0.0.0.0/32
2748 * unicast-ip4-chain
2749 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2750 * [0] [@0]: dpo-drop ip6
2751 * 224.0.0.0/8
2752 * unicast-ip4-chain
2753 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2754 * [0] [@0]: dpo-drop ip6
2755 * 6.0.1.2/32
2756 * unicast-ip4-chain
2757 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2758 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2759 * 7.0.0.1/32
2760 * unicast-ip4-chain
2761 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2762 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2763 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2764 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2765 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2766 * 240.0.0.0/8
2767 * unicast-ip4-chain
2768 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2769 * [0] [@0]: dpo-drop ip6
2770 * 255.255.255.255/32
2771 * unicast-ip4-chain
2772 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2773 * [0] [@0]: dpo-drop ip6
2774 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2775 * 0.0.0.0/0
2776 * unicast-ip4-chain
2777 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2778 * [0] [@0]: dpo-drop ip6
2779 * 0.0.0.0/32
2780 * unicast-ip4-chain
2781 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2782 * [0] [@0]: dpo-drop ip6
2783 * 172.16.1.0/24
2784 * unicast-ip4-chain
2785 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2786 * [0] [@4]: ipv4-glean: af_packet0
2787 * 172.16.1.1/32
2788 * unicast-ip4-chain
2789 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2790 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2791 * 172.16.1.2/32
2792 * unicast-ip4-chain
2793 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2794 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2795 * 172.16.2.0/24
2796 * unicast-ip4-chain
2797 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2798 * [0] [@4]: ipv4-glean: af_packet1
2799 * 172.16.2.1/32
2800 * unicast-ip4-chain
2801 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2802 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2803 * 224.0.0.0/8
2804 * unicast-ip4-chain
2805 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2806 * [0] [@0]: dpo-drop ip6
2807 * 240.0.0.0/8
2808 * unicast-ip4-chain
2809 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2810 * [0] [@0]: dpo-drop ip6
2811 * 255.255.255.255/32
2812 * unicast-ip4-chain
2813 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2814 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002815 * @cliexend
2816?*/
2817/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002818VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2819{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002820 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002821 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002822 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002823 .function = set_ip_flow_hash_command_fn,
2824};
Billy McFall0683c9c2016-10-13 08:27:31 -04002825/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002826
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002827#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002828int
2829vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2830 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002831{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002832 vnet_main_t *vnm = vnet_get_main ();
2833 vnet_interface_main_t *im = &vnm->interface_main;
2834 ip4_main_t *ipm = &ip4_main;
2835 ip_lookup_main_t *lm = &ipm->lookup_main;
2836 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002837 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002838
2839 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2840 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2841
2842 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2843 return VNET_API_ERROR_NO_SUCH_ENTRY;
2844
2845 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002846 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002847
Neale Rannsdf089a82016-10-02 16:39:06 +01002848 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2849
2850 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002851 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002852 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002853 .fp_len = 32,
2854 .fp_proto = FIB_PROTOCOL_IP4,
2855 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002856 };
2857 u32 fib_index;
2858
Dave Barachd7cb1b52016-12-09 09:52:16 -05002859 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2860 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002861
2862
Dave Barachd7cb1b52016-12-09 09:52:16 -05002863 if (table_index != (u32) ~ 0)
2864 {
2865 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002866
Dave Barachd7cb1b52016-12-09 09:52:16 -05002867 dpo_set (&dpo,
2868 DPO_CLASSIFY,
2869 DPO_PROTO_IP4,
2870 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002871
Dave Barachd7cb1b52016-12-09 09:52:16 -05002872 fib_table_entry_special_dpo_add (fib_index,
2873 &pfx,
2874 FIB_SOURCE_CLASSIFY,
2875 FIB_ENTRY_FLAG_NONE, &dpo);
2876 dpo_reset (&dpo);
2877 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002878 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002879 {
2880 fib_table_entry_special_remove (fib_index,
2881 &pfx, FIB_SOURCE_CLASSIFY);
2882 }
2883 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002884
Ed Warnickecb9cada2015-12-08 15:45:58 -07002885 return 0;
2886}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002887#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002888
2889static clib_error_t *
2890set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002891 unformat_input_t * input,
2892 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002893{
2894 u32 table_index = ~0;
2895 int table_index_set = 0;
2896 u32 sw_if_index = ~0;
2897 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002898
Dave Barachd7cb1b52016-12-09 09:52:16 -05002899 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2900 {
2901 if (unformat (input, "table-index %d", &table_index))
2902 table_index_set = 1;
2903 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2904 vnet_get_main (), &sw_if_index))
2905 ;
2906 else
2907 break;
2908 }
Dave Barach75fc8542016-10-11 16:16:02 -04002909
Ed Warnickecb9cada2015-12-08 15:45:58 -07002910 if (table_index_set == 0)
2911 return clib_error_return (0, "classify table-index must be specified");
2912
2913 if (sw_if_index == ~0)
2914 return clib_error_return (0, "interface / subif must be specified");
2915
2916 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2917
2918 switch (rv)
2919 {
2920 case 0:
2921 break;
2922
2923 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2924 return clib_error_return (0, "No such interface");
2925
2926 case VNET_API_ERROR_NO_SUCH_ENTRY:
2927 return clib_error_return (0, "No such classifier table");
2928 }
2929 return 0;
2930}
2931
Billy McFall0683c9c2016-10-13 08:27:31 -04002932/*?
2933 * Assign a classification table to an interface. The classification
2934 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2935 * commands. Once the table is create, use this command to filter packets
2936 * on an interface.
2937 *
2938 * @cliexpar
2939 * Example of how to assign a classification table to an interface:
2940 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2941?*/
2942/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002943VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2944{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002945 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002946 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002947 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002948 .function = set_ip_classify_command_fn,
2949};
Billy McFall0683c9c2016-10-13 08:27:31 -04002950/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002951
2952/*
2953 * fd.io coding-style-patch-verification: ON
2954 *
2955 * Local Variables:
2956 * eval: (c-set-style "gnu")
2957 * End:
2958 */