blob: 3c67bb3d4e77d471f803f8cf0f2faf01a56a8271 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ip/ip4_forward.c: IP v4 forwarding
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vnet/vnet.h>
41#include <vnet/ip/ip.h>
Ole Troan313f7e22018-04-10 16:02:51 +020042#include <vnet/ip/ip_frag.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010043#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
44#include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#include <vnet/ppp/ppp.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010046#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
Dave Barachd7cb1b52016-12-09 09:52:16 -050047#include <vnet/api_errno.h> /* for API error numbers */
48#include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
49#include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
50#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010051#include <vnet/fib/ip4_fib.h>
Neale Ranns03c254e2020-03-17 14:25:10 +000052#include <vnet/mfib/ip4_mfib.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010053#include <vnet/dpo/load_balance.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070054#include <vnet/dpo/load_balance_map.h>
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +020055#include <vnet/dpo/receive_dpo.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010056#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000057#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Neale Ranns4ec36c52020-03-31 09:21:29 -040058#include <vnet/adj/adj_dp.h>
Neale Ranns68d48d92021-06-03 14:59:47 +000059#include <vnet/pg/pg.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070060
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080061#include <vnet/ip/ip4_forward.h>
Neale Ranns25edf142019-03-22 08:12:48 +000062#include <vnet/interface_output.h>
Neale Rannsba4a5bf2020-01-09 06:43:14 +000063#include <vnet/classify/vnet_classify.h>
Klement Sekera01c1fa42021-12-14 18:25:11 +000064#include <vnet/ip/reass/ip4_full_reass.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070065
Chris Luke8e5b0412016-07-26 13:06:10 -040066/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040067 @node ip4-lookup
68
69 This is the main IPv4 lookup dispatch node.
70
71 @param vm vlib_main_t corresponding to the current thread
72 @param node vlib_node_runtime_t
73 @param frame vlib_frame_t whose contents should be dispatched
74
75 @par Graph mechanics: buffer metadata, next index usage
76
77 @em Uses:
78 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
79 - Indicates the @c sw_if_index value of the interface that the
80 packet was received on.
81 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
82 - When the value is @c ~0 then the node performs a longest prefix
83 match (LPM) for the packet destination address in the FIB attached
84 to the receive interface.
85 - Otherwise perform LPM for the packet destination address in the
86 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
87 value (0, 1, ...) and not a VRF id.
88
89 @em Sets:
90 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
91 - The lookup result adjacency index.
92
93 <em>Next Index:</em>
94 - Dispatches the packet to the node index found in
95 ip_adjacency_t @c adj->lookup_next_index
96 (where @c adj is the lookup result adjacency).
97*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020098VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
99 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100{
Neale Rannscb54e3c2019-06-19 07:14:10 +0000101 return ip4_lookup_inline (vm, node, frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102}
103
Dave Barachd7cb1b52016-12-09 09:52:16 -0500104static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100105
Neale Rannsf8686322017-11-29 02:39:53 -0800106/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500107VLIB_REGISTER_NODE (ip4_lookup_node) =
108{
Neale Rannsf8686322017-11-29 02:39:53 -0800109 .name = "ip4-lookup",
110 .vector_size = sizeof (u32),
111 .format_trace = format_ip4_lookup_trace,
112 .n_next_nodes = IP_LOOKUP_N_NEXT,
113 .next_nodes = IP4_LOOKUP_NEXT_NODES,
114};
115/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100116
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200117VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
118 vlib_node_runtime_t * node,
119 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500121 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400122 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200123 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800124 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400125 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100127 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400128 n_left = frame->n_vectors;
129 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100130
Neale Ranns3ce72b22019-05-27 08:21:32 -0400131 vlib_get_buffers (vm, from, bufs, n_left);
132
133 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400135 const load_balance_t *lb0, *lb1;
136 const ip4_header_t *ip0, *ip1;
137 u32 lbi0, hc0, lbi1, hc1;
138 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100139
Neale Ranns3ce72b22019-05-27 08:21:32 -0400140 /* Prefetch next iteration. */
141 {
142 vlib_prefetch_buffer_header (b[2], LOAD);
143 vlib_prefetch_buffer_header (b[3], LOAD);
144
145 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
146 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
147 }
148
149 ip0 = vlib_buffer_get_current (b[0]);
150 ip1 = vlib_buffer_get_current (b[1]);
151 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
152 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
153
154 lb0 = load_balance_get (lbi0);
155 lb1 = load_balance_get (lbi1);
156
157 /*
158 * this node is for via FIBs we can re-use the hash value from the
159 * to node if present.
160 * We don't want to use the same hash value at each level in the recursion
161 * graph as that would lead to polarisation
162 */
163 hc0 = hc1 = 0;
164
165 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500166 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400167 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500168 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400169 hc0 = vnet_buffer (b[0])->ip.flow_hash =
170 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700171 }
172 else
173 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400174 hc0 = vnet_buffer (b[0])->ip.flow_hash =
175 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500176 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400177 dpo0 = load_balance_get_fwd_bucket
178 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
179 }
180 else
181 {
182 dpo0 = load_balance_get_bucket_i (lb0, 0);
183 }
184 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
185 {
186 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500187 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400188 hc1 = vnet_buffer (b[1])->ip.flow_hash =
189 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500190 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700191 else
192 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400193 hc1 = vnet_buffer (b[1])->ip.flow_hash =
194 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700195 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400196 dpo1 = load_balance_get_fwd_bucket
197 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
198 }
199 else
200 {
201 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500202 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000203
Neale Ranns3ce72b22019-05-27 08:21:32 -0400204 next[0] = dpo0->dpoi_next_node;
205 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100206
Neale Ranns3ce72b22019-05-27 08:21:32 -0400207 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
208 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100209
Neale Ranns3ce72b22019-05-27 08:21:32 -0400210 vlib_increment_combined_counter
211 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
212 vlib_increment_combined_counter
213 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100214
Neale Ranns3ce72b22019-05-27 08:21:32 -0400215 b += 2;
216 next += 2;
217 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218 }
219
Neale Ranns3ce72b22019-05-27 08:21:32 -0400220 while (n_left > 0)
221 {
222 const load_balance_t *lb0;
223 const ip4_header_t *ip0;
224 const dpo_id_t *dpo0;
225 u32 lbi0, hc0;
226
227 ip0 = vlib_buffer_get_current (b[0]);
228 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
229
230 lb0 = load_balance_get (lbi0);
231
232 hc0 = 0;
233 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
234 {
235 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
236 {
237 hc0 = vnet_buffer (b[0])->ip.flow_hash =
238 vnet_buffer (b[0])->ip.flow_hash >> 1;
239 }
240 else
241 {
242 hc0 = vnet_buffer (b[0])->ip.flow_hash =
243 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
244 }
245 dpo0 = load_balance_get_fwd_bucket
246 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
247 }
248 else
249 {
250 dpo0 = load_balance_get_bucket_i (lb0, 0);
251 }
252
253 next[0] = dpo0->dpoi_next_node;
254 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
255
256 vlib_increment_combined_counter
257 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
258
259 b += 1;
260 next += 1;
261 n_left -= 1;
262 }
263
264 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800265 if (node->flags & VLIB_NODE_FLAG_TRACE)
266 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
267
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100268 return frame->n_vectors;
269}
270
Neale Rannsf8686322017-11-29 02:39:53 -0800271/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500272VLIB_REGISTER_NODE (ip4_load_balance_node) =
273{
Neale Rannsf8686322017-11-29 02:39:53 -0800274 .name = "ip4-load-balance",
275 .vector_size = sizeof (u32),
276 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200277 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800278};
279/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200281#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100282/* get first interface address */
283ip4_address_t *
284ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500285 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100286{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500287 ip_lookup_main_t *lm = &im->lookup_main;
288 ip_interface_address_t *ia = 0;
289 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100290
Neale Ranns32e1c012016-11-22 17:07:28 +0000291 /* *INDENT-OFF* */
292 foreach_ip_interface_address
293 (lm, ia, sw_if_index,
294 1 /* honor unnumbered */ ,
295 ({
296 ip4_address_t * a =
297 ip_interface_address_get_address (lm, ia);
298 result = a;
299 break;
300 }));
301 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100302 if (result_ia)
303 *result_ia = result ? ia : 0;
304 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500306#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307
308static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700309ip4_add_subnet_bcast_route (u32 fib_index,
310 fib_prefix_t *pfx,
311 u32 sw_if_index)
312{
313 vnet_sw_interface_flags_t iflags;
314
315 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
316
317 fib_table_entry_special_remove(fib_index,
318 pfx,
319 FIB_SOURCE_INTERFACE);
320
321 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
322 {
323 fib_table_entry_update_one_path (fib_index, pfx,
324 FIB_SOURCE_INTERFACE,
325 FIB_ENTRY_FLAG_NONE,
326 DPO_PROTO_IP4,
327 /* No next-hop address */
328 &ADJ_BCAST_ADDR,
329 sw_if_index,
330 // invalid FIB index
331 ~0,
332 1,
333 // no out-label stack
334 NULL,
335 FIB_ROUTE_PATH_FLAG_NONE);
336 }
337 else
338 {
339 fib_table_entry_special_add(fib_index,
340 pfx,
341 FIB_SOURCE_INTERFACE,
342 (FIB_ENTRY_FLAG_DROP |
343 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
344 }
345}
346
347static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500348ip4_add_interface_prefix_routes (ip4_main_t *im,
349 u32 sw_if_index,
350 u32 fib_index,
351 ip_interface_address_t * a)
352{
353 ip_lookup_main_t *lm = &im->lookup_main;
354 ip_interface_prefix_t *if_prefix;
355 ip4_address_t *address = ip_interface_address_get_address (lm, a);
356
357 ip_interface_prefix_key_t key = {
358 .prefix = {
359 .fp_len = a->address_length,
360 .fp_proto = FIB_PROTOCOL_IP4,
361 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
362 },
363 .sw_if_index = sw_if_index,
364 };
365
366 fib_prefix_t pfx_special = {
367 .fp_proto = FIB_PROTOCOL_IP4,
368 };
369
370 /* If prefix already set on interface, just increment ref count & return */
371 if_prefix = ip_get_interface_prefix (lm, &key);
372 if (if_prefix)
373 {
374 if_prefix->ref_count += 1;
375 return;
376 }
377
378 /* New prefix - allocate a pool entry, initialize it, add to the hash */
379 pool_get (lm->if_prefix_pool, if_prefix);
380 if_prefix->ref_count = 1;
381 if_prefix->src_ia_index = a - lm->if_address_pool;
382 clib_memcpy (&if_prefix->key, &key, sizeof (key));
383 mhash_set (&lm->prefix_to_if_prefix_index, &key,
384 if_prefix - lm->if_prefix_pool, 0 /* old value */);
385
Neale Rannse2fe0972020-11-26 08:37:27 +0000386 pfx_special.fp_len = a->address_length;
387 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
388
389 /* set the glean route for the prefix */
390 fib_table_entry_update_one_path (fib_index, &pfx_special,
391 FIB_SOURCE_INTERFACE,
392 (FIB_ENTRY_FLAG_CONNECTED |
393 FIB_ENTRY_FLAG_ATTACHED),
394 DPO_PROTO_IP4,
395 /* No next-hop address */
396 NULL,
397 sw_if_index,
398 /* invalid FIB index */
399 ~0,
400 1,
401 /* no out-label stack */
402 NULL,
403 FIB_ROUTE_PATH_FLAG_NONE);
404
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500405 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
406 if (a->address_length <= 30)
407 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500408 /* set a drop route for the base address of the prefix */
409 pfx_special.fp_len = 32;
410 pfx_special.fp_addr.ip4.as_u32 =
411 address->as_u32 & im->fib_masks[a->address_length];
412
413 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
414 fib_table_entry_special_add (fib_index, &pfx_special,
415 FIB_SOURCE_INTERFACE,
416 (FIB_ENTRY_FLAG_DROP |
417 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
418
419 /* set a route for the broadcast address of the prefix */
420 pfx_special.fp_len = 32;
421 pfx_special.fp_addr.ip4.as_u32 =
422 address->as_u32 | ~im->fib_masks[a->address_length];
423 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
424 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
425
426
427 }
428 /* length == 31 - add an attached route for the other address */
429 else if (a->address_length == 31)
430 {
431 pfx_special.fp_len = 32;
432 pfx_special.fp_addr.ip4.as_u32 =
433 address->as_u32 ^ clib_host_to_net_u32(1);
434
435 fib_table_entry_update_one_path (fib_index, &pfx_special,
436 FIB_SOURCE_INTERFACE,
437 (FIB_ENTRY_FLAG_ATTACHED),
438 DPO_PROTO_IP4,
439 &pfx_special.fp_addr,
440 sw_if_index,
441 /* invalid FIB index */
442 ~0,
443 1,
444 NULL,
445 FIB_ROUTE_PATH_FLAG_NONE);
446 }
447}
448
449static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450ip4_add_interface_routes (u32 sw_if_index,
451 ip4_main_t * im, u32 fib_index,
452 ip_interface_address_t * a)
453{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500454 ip_lookup_main_t *lm = &im->lookup_main;
455 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100456 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500457 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500458 .fp_proto = FIB_PROTOCOL_IP4,
459 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100460 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500462 /* set special routes for the prefix if needed */
463 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100464
465 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500466 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100467 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500468 lm->classify_table_index_by_sw_if_index[sw_if_index];
469 if (classify_table_index != (u32) ~ 0)
470 {
471 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100472
Dave Barachd7cb1b52016-12-09 09:52:16 -0500473 dpo_set (&dpo,
474 DPO_CLASSIFY,
475 DPO_PROTO_IP4,
476 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100477
Dave Barachd7cb1b52016-12-09 09:52:16 -0500478 fib_table_entry_special_dpo_add (fib_index,
479 &pfx,
480 FIB_SOURCE_CLASSIFY,
481 FIB_ENTRY_FLAG_NONE, &dpo);
482 dpo_reset (&dpo);
483 }
484 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100485
Neale Ranns32e1c012016-11-22 17:07:28 +0000486 fib_table_entry_update_one_path (fib_index, &pfx,
487 FIB_SOURCE_INTERFACE,
488 (FIB_ENTRY_FLAG_CONNECTED |
489 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700490 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000491 &pfx.fp_addr,
492 sw_if_index,
493 // invalid FIB index
494 ~0,
495 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500496 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497}
498
499static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500500ip4_del_interface_prefix_routes (ip4_main_t * im,
501 u32 sw_if_index,
502 u32 fib_index,
503 ip4_address_t * address,
504 u32 address_length)
505{
506 ip_lookup_main_t *lm = &im->lookup_main;
507 ip_interface_prefix_t *if_prefix;
508
509 ip_interface_prefix_key_t key = {
510 .prefix = {
511 .fp_len = address_length,
512 .fp_proto = FIB_PROTOCOL_IP4,
513 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
514 },
515 .sw_if_index = sw_if_index,
516 };
517
518 fib_prefix_t pfx_special = {
519 .fp_len = 32,
520 .fp_proto = FIB_PROTOCOL_IP4,
521 };
522
523 if_prefix = ip_get_interface_prefix (lm, &key);
524 if (!if_prefix)
525 {
526 clib_warning ("Prefix not found while deleting %U",
527 format_ip4_address_and_length, address, address_length);
528 return;
529 }
530
531 if_prefix->ref_count -= 1;
532
533 /*
Neale Rannse2fe0972020-11-26 08:37:27 +0000534 * Routes need to be adjusted if deleting last intf addr in prefix
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500535 *
536 * We're done now otherwise
537 */
Neale Rannse2fe0972020-11-26 08:37:27 +0000538 if (if_prefix->ref_count > 0)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500539 return;
540
541 /* length <= 30, delete glean route, first address, last address */
542 if (address_length <= 30)
543 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000544 /* Less work to do in FIB if we remove the covered /32s first */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500545
Neale Rannse2fe0972020-11-26 08:37:27 +0000546 /* first address in prefix */
547 pfx_special.fp_addr.ip4.as_u32 =
548 address->as_u32 & im->fib_masks[address_length];
549 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500550
Neale Rannse2fe0972020-11-26 08:37:27 +0000551 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
552 fib_table_entry_special_remove (fib_index,
553 &pfx_special,
554 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500555
Neale Rannse2fe0972020-11-26 08:37:27 +0000556 /* prefix broadcast address */
557 pfx_special.fp_addr.ip4.as_u32 =
558 address->as_u32 | ~im->fib_masks[address_length];
559 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500560
Neale Rannse2fe0972020-11-26 08:37:27 +0000561 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
562 fib_table_entry_special_remove (fib_index,
563 &pfx_special,
564 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500565 }
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500566 else if (address_length == 31)
567 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000568 /* length == 31, delete attached route for the other address */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500569 pfx_special.fp_addr.ip4.as_u32 =
570 address->as_u32 ^ clib_host_to_net_u32(1);
571
572 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
573 }
574
Neale Rannse2fe0972020-11-26 08:37:27 +0000575 /* remove glean route for prefix */
576 pfx_special.fp_addr.ip4 = *address;
577 pfx_special.fp_len = address_length;
578 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
579
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500580 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
581 pool_put (lm->if_prefix_pool, if_prefix);
582}
583
584static void
585ip4_del_interface_routes (u32 sw_if_index,
586 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100587 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700589{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500590 fib_prefix_t pfx = {
Neale Rannse2fe0972020-11-26 08:37:27 +0000591 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500592 .fp_proto = FIB_PROTOCOL_IP4,
593 .fp_addr.ip4 = *address,
594 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595
Neale Rannse2fe0972020-11-26 08:37:27 +0000596 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
597
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500598 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
599 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700600}
601
Matthew G Smith88d29a92019-07-17 10:01:17 -0500602#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100603void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500604ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100605{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500606 ip4_main_t *im = &ip4_main;
John Lo4a302ee2020-05-12 22:34:39 -0400607 vnet_main_t *vnm = vnet_get_main ();
608 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100610 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
611
612 /*
613 * enable/disable only on the 1<->0 transition
614 */
615 if (is_enable)
616 {
617 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500618 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100619 }
620 else
621 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500622 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100623 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500624 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100625 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800626 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800627 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100628
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100629
Neale Ranns8269d3d2018-01-30 09:02:20 -0800630 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400631 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000632
John Lo4a302ee2020-05-12 22:34:39 -0400633 if (is_enable)
634 hi->l3_if_count++;
635 else if (hi->l3_if_count)
636 hi->l3_if_count--;
637
Neale Ranns57e53bb2019-05-29 13:58:43 +0000638 {
639 ip4_enable_disable_interface_callback_t *cb;
640 vec_foreach (cb, im->enable_disable_interface_callbacks)
641 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
642 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100643}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644
Ed Warnickecb9cada2015-12-08 15:45:58 -0700645static clib_error_t *
646ip4_add_del_interface_address_internal (vlib_main_t * vm,
647 u32 sw_if_index,
648 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500649 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500651 vnet_main_t *vnm = vnet_get_main ();
652 ip4_main_t *im = &ip4_main;
653 ip_lookup_main_t *lm = &im->lookup_main;
654 clib_error_t *error = 0;
Neale Ranns59f71132020-04-08 12:19:38 +0000655 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500656 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657
Pim van Pelt76b19ce2021-08-10 23:44:44 +0200658 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
659 if (error)
Matthew Smith1b6c7932021-09-24 15:27:36 -0500660 {
661 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
662 return error;
663 }
Pavel Kotucek57808982017-08-02 08:20:19 +0200664
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665 ip4_addr_fib_init (&ip4_af, address,
666 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
667 vec_add1 (addr_fib, ip4_af);
668
Neale Ranns744902e2017-08-14 10:35:44 -0700669 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100670 * there is no support for adj-fib handling in the presence of overlapping
671 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
672 * most routers do.
673 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000674 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500675 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100677 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700678 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500679 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700680 vnet_sw_interface_t *sif;
681
Damjan Marionb2c31b62020-12-13 21:47:40 +0100682 pool_foreach (sif, vnm->interface_main.sw_interfaces)
683 {
Neale Ranns744902e2017-08-14 10:35:44 -0700684 if (im->fib_index_by_sw_if_index[sw_if_index] ==
685 im->fib_index_by_sw_if_index[sif->sw_if_index])
686 {
687 foreach_ip_interface_address
688 (&im->lookup_main, ia, sif->sw_if_index,
689 0 /* honor unnumbered */ ,
690 ({
691 ip4_address_t * x =
692 ip_interface_address_get_address
693 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000694
Neale Ranns744902e2017-08-14 10:35:44 -0700695 if (ip4_destination_matches_route
696 (im, address, x, ia->address_length) ||
697 ip4_destination_matches_route (im,
698 x,
699 address,
700 address_length))
701 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500702 /* an intf may have >1 addr from the same prefix */
703 if ((sw_if_index == sif->sw_if_index) &&
704 (ia->address_length == address_length) &&
705 (x->as_u32 != address->as_u32))
706 continue;
707
Neale Ranns59f71132020-04-08 12:19:38 +0000708 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
709 /* if the address we're comparing against is stale
710 * then the CP has not added this one back yet, maybe
711 * it never will, so we have to assume it won't and
712 * ignore it. if it does add it back, then it will fail
713 * because this one is now present */
714 continue;
Neale Ranns744902e2017-08-14 10:35:44 -0700715
Neale Ranns59f71132020-04-08 12:19:38 +0000716 /* error if the length or intf was different */
717 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
718
719 error = clib_error_create
Ole Troan33a58172019-09-04 09:12:29 +0200720 ("failed to add %U on %U which conflicts with %U for interface %U",
Neale Ranns744902e2017-08-14 10:35:44 -0700721 format_ip4_address_and_length, address,
722 address_length,
Ole Troan33a58172019-09-04 09:12:29 +0200723 format_vnet_sw_if_index_name, vnm,
724 sw_if_index,
Neale Ranns744902e2017-08-14 10:35:44 -0700725 format_ip4_address_and_length, x,
726 ia->address_length,
727 format_vnet_sw_if_index_name, vnm,
728 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000729 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700730 }
731 }));
732 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100733 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000735 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736
Neale Ranns59f71132020-04-08 12:19:38 +0000737 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738
Neale Ranns59f71132020-04-08 12:19:38 +0000739 if (is_del)
740 {
741 if (~0 == if_address_index)
742 {
743 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
744 error = clib_error_create ("%U not found for interface %U",
745 lm->format_address_and_length,
746 addr_fib, address_length,
747 format_vnet_sw_if_index_name, vnm,
748 sw_if_index);
749 goto done;
750 }
751
yedgdbd366b2020-05-14 10:51:53 +0800752 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
753 address_length, sw_if_index);
754 if (error)
755 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000756 }
757 else
758 {
759 if (~0 != if_address_index)
760 {
761 ip_interface_address_t *ia;
762
763 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
764
765 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
766 {
767 if (ia->sw_if_index == sw_if_index)
768 {
769 /* re-adding an address during the replace action.
770 * consdier this the update. clear the flag and
771 * we're done */
772 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
773 goto done;
774 }
775 else
776 {
777 /* The prefix is moving from one interface to another.
778 * delete the stale and add the new */
779 ip4_add_del_interface_address_internal (vm,
780 ia->sw_if_index,
781 address,
782 address_length, 1);
783 ia = NULL;
784 error = ip_interface_address_add (lm, sw_if_index,
785 addr_fib, address_length,
786 &if_address_index);
787 }
788 }
789 else
790 {
791 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
792 error = clib_error_create
793 ("Prefix %U already found on interface %U",
794 lm->format_address_and_length, addr_fib, address_length,
795 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
796 }
797 }
798 else
799 error = ip_interface_address_add (lm, sw_if_index,
800 addr_fib, address_length,
801 &if_address_index);
802 }
803
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804 if (error)
805 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400806
Dave Barachd7cb1b52016-12-09 09:52:16 -0500807 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns03c254e2020-03-17 14:25:10 +0000808 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100809
Matthew G Smith88d29a92019-07-17 10:01:17 -0500810 /* intf addr routes are added/deleted on admin up/down */
811 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
812 {
813 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500814 ip4_del_interface_routes (sw_if_index,
815 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500816 address_length);
817 else
818 ip4_add_interface_routes (sw_if_index,
819 im, ip4_af.fib_index,
820 pool_elt_at_index
821 (lm->if_address_pool, if_address_index));
822 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823
Neale Ranns59f71132020-04-08 12:19:38 +0000824 ip4_add_del_interface_address_callback_t *cb;
825 vec_foreach (cb, im->add_del_interface_address_callbacks)
826 cb->function (im, cb->function_opaque, sw_if_index,
827 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828
Dave Barachd7cb1b52016-12-09 09:52:16 -0500829done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830 vec_free (addr_fib);
831 return error;
832}
833
834clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000835ip4_add_del_interface_address (vlib_main_t * vm,
836 u32 sw_if_index,
837 ip4_address_t * address,
838 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839{
840 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500841 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700842}
843
Neale Ranns1855b8e2018-07-11 10:31:26 -0700844void
845ip4_directed_broadcast (u32 sw_if_index, u8 enable)
846{
847 ip_interface_address_t *ia;
848 ip4_main_t *im;
849
850 im = &ip4_main;
851
852 /*
853 * when directed broadcast is enabled, the subnet braodcast route will forward
854 * packets using an adjacency with a broadcast MAC. otherwise it drops
855 */
856 /* *INDENT-OFF* */
857 foreach_ip_interface_address(&im->lookup_main, ia,
858 sw_if_index, 0,
859 ({
860 if (ia->address_length <= 30)
861 {
862 ip4_address_t *ipa;
863
864 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
865
866 fib_prefix_t pfx = {
867 .fp_len = 32,
868 .fp_proto = FIB_PROTOCOL_IP4,
869 .fp_addr = {
870 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
871 },
872 };
873
874 ip4_add_subnet_bcast_route
875 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
876 sw_if_index),
877 &pfx, sw_if_index);
878 }
879 }));
880 /* *INDENT-ON* */
881}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200882#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700883
Matthew G Smith88d29a92019-07-17 10:01:17 -0500884static clib_error_t *
885ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
886{
887 ip4_main_t *im = &ip4_main;
888 ip_interface_address_t *ia;
889 ip4_address_t *a;
890 u32 is_admin_up, fib_index;
891
Matthew G Smith88d29a92019-07-17 10:01:17 -0500892 vec_validate_init_empty (im->
893 lookup_main.if_address_pool_index_by_sw_if_index,
894 sw_if_index, ~0);
895
896 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
897
898 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
899
900 /* *INDENT-OFF* */
901 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
902 0 /* honor unnumbered */,
903 ({
904 a = ip_interface_address_get_address (&im->lookup_main, ia);
905 if (is_admin_up)
906 ip4_add_interface_routes (sw_if_index,
907 im, fib_index,
908 ia);
909 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500910 ip4_del_interface_routes (sw_if_index,
911 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500912 a, ia->address_length);
913 }));
914 /* *INDENT-ON* */
915
916 return 0;
917}
918
919VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
920
Dave Barachd6534602016-06-14 18:38:02 -0400921/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500922/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100923VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
924{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500925 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100926 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500927 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100928 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
929};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100930
Dave Barachd7cb1b52016-12-09 09:52:16 -0500931VNET_FEATURE_INIT (ip4_flow_classify, static) =
932{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100933 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700934 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100935 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700936};
937
Dave Barachd7cb1b52016-12-09 09:52:16 -0500938VNET_FEATURE_INIT (ip4_inacl, static) =
939{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100940 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400941 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100942 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400943};
944
Dave Barachd7cb1b52016-12-09 09:52:16 -0500945VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
946{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100947 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400948 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100949 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400950};
951
Dave Barachd7cb1b52016-12-09 09:52:16 -0500952VNET_FEATURE_INIT (ip4_policer_classify, static) =
953{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100954 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700955 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100956 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700957};
958
Dave Barachd7cb1b52016-12-09 09:52:16 -0500959VNET_FEATURE_INIT (ip4_ipsec, static) =
960{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100961 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100962 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100963 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400964};
965
Dave Barachd7cb1b52016-12-09 09:52:16 -0500966VNET_FEATURE_INIT (ip4_vpath, static) =
967{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100968 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400969 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500970 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
971};
972
Dave Barachd7cb1b52016-12-09 09:52:16 -0500973VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
974{
John Lo37682e12016-11-30 12:51:39 -0500975 .arc_name = "ip4-unicast",
976 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100977 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400978};
979
Neale Ranns8269d3d2018-01-30 09:02:20 -0800980VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500981{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100982 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800983 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400984 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100985};
986
Neale Ranns180279b2017-03-16 15:49:09 -0400987VNET_FEATURE_INIT (ip4_lookup, static) =
988{
989 .arc_name = "ip4-unicast",
990 .node_name = "ip4-lookup",
991 .runs_before = 0, /* not before any other features */
992};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100993
Dave Barachd6534602016-06-14 18:38:02 -0400994/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100995VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
996{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500997 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100998 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500999 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001000 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1001};
1002
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1004{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001005 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001006 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001007 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001008};
1009
Neale Ranns8269d3d2018-01-30 09:02:20 -08001010VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001011{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001012 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -08001013 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -04001014 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1015};
1016
1017VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1018{
1019 .arc_name = "ip4-multicast",
1020 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001022};
Dave Barach5331c722016-08-17 11:54:30 -04001023
1024/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001025VNET_FEATURE_ARC_INIT (ip4_output, static) =
1026{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001027 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001028 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001029 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001030 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1031};
Dave Barach5331c722016-08-17 11:54:30 -04001032
Dave Barachd7cb1b52016-12-09 09:52:16 -05001033VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1034{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001035 .arc_name = "ip4-output",
1036 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001037 .runs_before = VNET_FEATURES ("ip4-outacl"),
1038};
1039
1040VNET_FEATURE_INIT (ip4_outacl, static) =
1041{
1042 .arc_name = "ip4-output",
1043 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001044 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001045};
1046
Dave Barachd7cb1b52016-12-09 09:52:16 -05001047VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1048{
Matus Fabian08a6f012016-11-15 06:08:51 -08001049 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001050 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001051 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001052};
1053
1054/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001055VNET_FEATURE_INIT (ip4_interface_output, static) =
1056{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001057 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001058 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001059 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001060};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001061/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001062
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001064ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001065{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001066 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001068 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1069 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001070
Nathan Skrzypczak7854b462021-08-16 16:13:40 +02001071 if (is_add)
1072 {
1073 /* Fill in lookup tables with default table (0). */
1074 im->fib_index_by_sw_if_index[sw_if_index] = 0;
1075 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1076 }
1077 else
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001078 {
1079 ip4_main_t *im4 = &ip4_main;
1080 ip_lookup_main_t *lm4 = &im4->lookup_main;
1081 ip_interface_address_t *ia = 0;
1082 ip4_address_t *address;
1083 vlib_main_t *vm = vlib_get_main ();
1084
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001085 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001086 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001087 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001088 ({
1089 address = ip_interface_address_get_address (lm4, ia);
1090 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1091 }));
1092 /* *INDENT-ON* */
Neale Ranns03c254e2020-03-17 14:25:10 +00001093 ip4_mfib_interface_enable_disable (sw_if_index, 0);
Nathan Skrzypczaka424dd12021-08-20 15:53:43 +02001094
1095 if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
1096 fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1097 if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
1098 mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1099
1100 /* Erase the lookup tables just in case */
1101 im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
1102 im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001103 }
1104
Neale Ranns8269d3d2018-01-30 09:02:20 -08001105 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001106 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001107
Neale Ranns8269d3d2018-01-30 09:02:20 -08001108 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1109 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111 return /* no error */ 0;
1112}
1113
1114VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1115
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001117#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001119#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001121static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122ip4_lookup_init (vlib_main_t * vm)
1123{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001124 ip4_main_t *im = &ip4_main;
1125 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126 uword i;
1127
Damjan Marion8b3191e2016-11-09 19:54:20 +01001128 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1129 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001130 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1131 return (error);
1132 if ((error = vlib_call_init_function (vm, fib_module_init)))
1133 return error;
1134 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1135 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001136
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1138 {
1139 u32 m;
1140
1141 if (i < 32)
1142 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001143 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144 m = ~0;
1145 im->fib_masks[i] = clib_host_to_net_u32 (m);
1146 }
1147
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1149
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001150 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001151 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1152 FIB_SOURCE_DEFAULT_ROUTE);
1153 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1154 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001155
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001157 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158 pn = pg_get_node (ip4_lookup_node.index);
1159 pn->unformat_edit = unformat_pg_ip4_header;
1160 }
1161
1162 {
1163 ethernet_arp_header_t h;
1164
Dave Barachb7b92992018-10-17 10:38:51 -04001165 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1168#define _8(f,v) h.f = v;
1169 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1170 _16 (l3_type, ETHERNET_TYPE_IP4);
1171 _8 (n_l2_address_bytes, 6);
1172 _8 (n_l3_address_bytes, 4);
1173 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1174#undef _16
1175#undef _8
1176
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178 /* data */ &h,
1179 sizeof (h),
1180 /* alloc chunk size */ 8,
1181 "ip4 arp");
1182 }
1183
Dave Barach203c6322016-06-26 10:29:03 -04001184 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185}
1186
1187VLIB_INIT_FUNCTION (ip4_lookup_init);
1188
Dave Barachd7cb1b52016-12-09 09:52:16 -05001189typedef struct
1190{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001192 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193 u32 flow_hash;
1194 u32 fib_index;
1195
1196 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001197 u8 packet_data[64 - 1 * sizeof (u32)];
1198}
1199ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001201#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001202u8 *
1203format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204{
1205 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1206 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001207 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001208 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001209 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001210 format_white_space, indent,
1211 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001212 return s;
1213}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001214#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001215
Dave Barachd7cb1b52016-12-09 09:52:16 -05001216static u8 *
1217format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001218{
1219 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1220 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001221 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001222 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223
John Loac8146c2016-09-27 17:44:02 -04001224 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001225 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001226 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001227 format_white_space, indent,
1228 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001229 return s;
1230}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231
Dave Barachd7cb1b52016-12-09 09:52:16 -05001232static u8 *
1233format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001234{
1235 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1236 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001237 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001238 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239
Vengada Govindanf1544482016-09-28 02:45:57 -07001240 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001241 t->fib_index, t->dpo_index, format_ip_adjacency,
1242 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001243 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001244 format_white_space, indent,
1245 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001246 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 return s;
1248}
1249
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001250#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001251/* Common trace function for all ip4-forward next nodes. */
1252void
1253ip4_forward_next_trace (vlib_main_t * vm,
1254 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001255 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001257 u32 *from, n_left;
1258 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001259
1260 n_left = frame->n_vectors;
1261 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001262
Ed Warnickecb9cada2015-12-08 15:45:58 -07001263 while (n_left >= 4)
1264 {
1265 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001266 vlib_buffer_t *b0, *b1;
1267 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001268
1269 /* Prefetch next iteration. */
1270 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1271 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1272
1273 bi0 = from[0];
1274 bi1 = from[1];
1275
1276 b0 = vlib_get_buffer (vm, bi0);
1277 b1 = vlib_get_buffer (vm, bi1);
1278
1279 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1280 {
1281 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001282 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001284 t0->fib_index =
1285 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1286 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1287 vec_elt (im->fib_index_by_sw_if_index,
1288 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001289
Dave Barach178cf492018-11-13 16:34:13 -05001290 clib_memcpy_fast (t0->packet_data,
1291 vlib_buffer_get_current (b0),
1292 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293 }
1294 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1295 {
1296 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001297 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001299 t1->fib_index =
1300 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1301 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1302 vec_elt (im->fib_index_by_sw_if_index,
1303 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001304 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1305 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 }
1307 from += 2;
1308 n_left -= 2;
1309 }
1310
1311 while (n_left >= 1)
1312 {
1313 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001314 vlib_buffer_t *b0;
1315 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316
1317 bi0 = from[0];
1318
1319 b0 = vlib_get_buffer (vm, bi0);
1320
1321 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1322 {
1323 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001324 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001326 t0->fib_index =
1327 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1328 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1329 vec_elt (im->fib_index_by_sw_if_index,
1330 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001331 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1332 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001333 }
1334 from += 1;
1335 n_left -= 1;
1336 }
1337}
1338
Ed Warnickecb9cada2015-12-08 15:45:58 -07001339/* Compute TCP/UDP/ICMP4 checksum in software. */
1340u16
1341ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1342 ip4_header_t * ip0)
1343{
1344 ip_csum_t sum0;
1345 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001346
Ed Warnickecb9cada2015-12-08 15:45:58 -07001347 /* Initialize checksum with ip header. */
1348 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001349 payload_length_host_byte_order =
1350 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1351 sum0 =
1352 clib_host_to_net_u32 (payload_length_host_byte_order +
1353 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354
1355 if (BITS (uword) == 32)
1356 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001357 sum0 =
1358 ip_csum_with_carry (sum0,
1359 clib_mem_unaligned (&ip0->src_address, u32));
1360 sum0 =
1361 ip_csum_with_carry (sum0,
1362 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363 }
1364 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001365 sum0 =
1366 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367
Srikanth A02833ff2019-10-02 17:48:58 -07001368 return ip_calculate_l4_checksum (vm, p0, sum0,
1369 payload_length_host_byte_order, (u8 *) ip0,
1370 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001371}
1372
John Lo37682e12016-11-30 12:51:39 -05001373u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001374ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1375{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001376 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1377 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001378 u16 sum16;
1379
1380 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1381 || ip0->protocol == IP_PROTOCOL_UDP);
1382
1383 udp0 = (void *) (ip0 + 1);
1384 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1385 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001386 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1387 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388 return p0->flags;
1389 }
1390
1391 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1392
Damjan Marion213b5aa2017-07-13 21:19:27 +02001393 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1394 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395
1396 return p0->flags;
1397}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001398#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399
Dave Barach68b0fb02017-02-28 15:15:56 -05001400/* *INDENT-OFF* */
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001401VNET_FEATURE_ARC_INIT (ip4_local) = {
1402 .arc_name = "ip4-local",
1403 .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
Dave Baracha25def72018-11-26 11:04:45 -05001404 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001405};
1406/* *INDENT-ON* */
1407
Florin Coras20a14b92017-08-15 22:47:22 -07001408static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001409ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1410 ip4_header_t * ip, u8 is_udp, u8 * error,
1411 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001412{
1413 u32 flags0;
1414 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1415 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1416 if (is_udp)
1417 {
1418 udp_header_t *udp;
1419 u32 ip_len, udp_len;
1420 i32 len_diff;
1421 udp = ip4_next_header (ip);
1422 /* Verify UDP length. */
1423 ip_len = clib_net_to_host_u16 (ip->length);
1424 udp_len = clib_net_to_host_u16 (udp->length);
1425
1426 len_diff = ip_len - udp_len;
1427 *good_tcp_udp &= len_diff >= 0;
1428 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1429 }
1430}
1431
Mohsin Kazmi68095382021-02-10 11:26:24 +01001432#define ip4_local_csum_is_offloaded(_b) \
1433 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001434 (vnet_buffer (_b)->oflags & \
Mohsin Kazmi68095382021-02-10 11:26:24 +01001435 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
Florin Coras1b255522018-06-01 12:22:23 -07001436
1437#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1438 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1439 || ip4_local_csum_is_offloaded (_b)))
1440
1441#define ip4_local_csum_is_valid(_b) \
1442 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1443 || (ip4_local_csum_is_offloaded (_b))) != 0
1444
1445static inline void
1446ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1447 ip4_header_t * ih, u8 * error)
1448{
1449 u8 is_udp, is_tcp_udp, good_tcp_udp;
1450
1451 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1452 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1453
1454 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1455 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1456 else
1457 good_tcp_udp = ip4_local_csum_is_valid (b);
1458
1459 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1460 *error = (is_tcp_udp && !good_tcp_udp
1461 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1462}
1463
1464static inline void
1465ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1466 ip4_header_t ** ih, u8 * error)
1467{
1468 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1469
1470 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1471 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1472
1473 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1474 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1475
1476 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1477 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1478
1479 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1480 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1481 {
1482 if (is_tcp_udp[0])
1483 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1484 &good_tcp_udp[0]);
1485 if (is_tcp_udp[1])
1486 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1487 &good_tcp_udp[1]);
1488 }
1489
1490 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1491 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1492 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1493 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1494}
1495
1496static inline void
1497ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1498 vlib_buffer_t * b, u16 * next, u8 error,
1499 u8 head_of_feature_arc)
1500{
1501 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1502 u32 next_index;
1503
1504 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1505 b->error = error ? error_node->errors[error] : 0;
1506 if (head_of_feature_arc)
1507 {
1508 next_index = *next;
1509 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1510 {
Florin Corasf8408802021-11-09 18:29:03 -08001511 vnet_feature_arc_start (
1512 arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
Florin Coras1b255522018-06-01 12:22:23 -07001513 *next = next_index;
1514 }
1515 }
1516}
1517
1518typedef struct
1519{
1520 ip4_address_t src;
1521 u32 lbi;
1522 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001523 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001524} ip4_local_last_check_t;
1525
1526static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001527ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1528 ip4_local_last_check_t *last_check, u8 *error0,
1529 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001530{
Florin Coras1b255522018-06-01 12:22:23 -07001531 const dpo_id_t *dpo0;
1532 load_balance_t *lb0;
1533 u32 lbi0;
1534
1535 vnet_buffer (b)->ip.fib_index =
1536 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1537 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1538
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001539 if (is_receive_dpo)
1540 {
1541 receive_dpo_t *rd;
1542 rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
1543 vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
1544 }
1545 else
Florin Coras904638f2021-11-10 07:39:51 -08001546 vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001547
Matthew Smith44e60462019-07-06 19:27:29 -05001548 /*
1549 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1550 * adjacency for the destination address (the local interface address).
1551 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1552 * adjacency for the source address (the remote sender's address)
1553 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301554 if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
1555 last_check->first)
Florin Coras1b255522018-06-01 12:22:23 -07001556 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001557 lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1558 &ip0->src_address);
Florin Coras1b255522018-06-01 12:22:23 -07001559
Matthew Smith44e60462019-07-06 19:27:29 -05001560 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1561 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001562 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001563
1564 lb0 = load_balance_get (lbi0);
1565 dpo0 = load_balance_get_bucket_i (lb0, 0);
1566
1567 /*
1568 * Must have a route to source otherwise we drop the packet.
1569 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1570 *
1571 * The checks are:
1572 * - the source is a recieve => it's from us => bogus, do this
1573 * first since it sets a different error code.
1574 * - uRPF check for any route to source - accept if passes.
1575 * - allow packets destined to the broadcast address from unknown sources
1576 */
1577
1578 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1579 && dpo0->dpoi_type == DPO_RECEIVE) ?
1580 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1581 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1582 && !fib_urpf_check_size (lb0->lb_urpf)
1583 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1584 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1585
1586 last_check->src.as_u32 = ip0->src_address.as_u32;
1587 last_check->lbi = lbi0;
1588 last_check->error = *error0;
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301589 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001590 }
1591 else
1592 {
Matthew Smith44e60462019-07-06 19:27:29 -05001593 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1594 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001595 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001596 *error0 = last_check->error;
1597 }
1598}
1599
1600static inline void
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001601ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1602 ip4_local_last_check_t *last_check, u8 *error,
1603 int is_receive_dpo)
Florin Coras1b255522018-06-01 12:22:23 -07001604{
Florin Coras1b255522018-06-01 12:22:23 -07001605 const dpo_id_t *dpo[2];
1606 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001607 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001608 u32 lbi[2];
1609
Neale Rannsbe2286b2018-12-09 12:54:51 -08001610 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001611 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1612 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1613
1614 vnet_buffer (b[0])->ip.fib_index =
1615 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1616 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1617 vnet_buffer (b[0])->ip.fib_index;
1618
1619 vnet_buffer (b[1])->ip.fib_index =
1620 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1621 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1622 vnet_buffer (b[1])->ip.fib_index;
1623
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001624 if (is_receive_dpo)
1625 {
1626 const receive_dpo_t *rd0, *rd1;
1627 rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1628 rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1629 vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1630 vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1631 }
1632 else
1633 {
Florin Coras904638f2021-11-10 07:39:51 -08001634 vnet_buffer (b[0])->ip.rx_sw_if_index =
1635 vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1636 vnet_buffer (b[1])->ip.rx_sw_if_index =
1637 vnet_buffer (b[1])->sw_if_index[VLIB_RX];
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001638 }
1639
Matthew Smith44e60462019-07-06 19:27:29 -05001640 /*
1641 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1642 * adjacency for the destination address (the local interface address).
1643 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1644 * adjacency for the source address (the remote sender's address)
1645 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301646 if (PREDICT_TRUE (not_last_hit))
Florin Coras1b255522018-06-01 12:22:23 -07001647 {
Neale Ranns31a4aa72021-08-10 12:35:57 +00001648 ip4_fib_forwarding_lookup_x2 (
1649 vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1650 &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001651
Matthew Smith44e60462019-07-06 19:27:29 -05001652 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1653 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001654 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001655
Matthew Smith44e60462019-07-06 19:27:29 -05001656 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1657 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001658 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001659
1660 lb[0] = load_balance_get (lbi[0]);
1661 lb[1] = load_balance_get (lbi[1]);
1662
1663 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1664 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1665
1666 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1667 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1668 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1669 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1670 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1671 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1672 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1673
1674 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1675 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1676 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1677 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1678 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1679 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1680 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1681
1682 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1683 last_check->lbi = lbi[1];
1684 last_check->error = error[1];
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301685 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001686 }
1687 else
1688 {
Matthew Smith44e60462019-07-06 19:27:29 -05001689 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1690 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001691 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001692
Matthew Smith44e60462019-07-06 19:27:29 -05001693 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1694 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001695 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001696
1697 error[0] = last_check->error;
1698 error[1] = last_check->error;
1699 }
1700}
Florin Coras20a14b92017-08-15 22:47:22 -07001701
Florin Corasc67cfd22018-10-01 21:59:18 -07001702enum ip_local_packet_type_e
1703{
1704 IP_LOCAL_PACKET_TYPE_L4,
1705 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001706 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001707};
1708
1709/**
1710 * Determine packet type and next node.
1711 *
1712 * The expectation is that all packets that are not L4 will skip
1713 * checksums and source checks.
1714 */
1715always_inline u8
1716ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1717{
1718 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1719
Juraj Sloboda3048b632018-10-02 11:13:53 +02001720 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1721 {
1722 *next = IP_LOCAL_NEXT_REASSEMBLY;
1723 return IP_LOCAL_PACKET_TYPE_FRAG;
1724 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001725 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1726 {
1727 *next = lm->local_next_by_ip_protocol[ip->protocol];
1728 return IP_LOCAL_PACKET_TYPE_NAT;
1729 }
1730
1731 *next = lm->local_next_by_ip_protocol[ip->protocol];
1732 return IP_LOCAL_PACKET_TYPE_L4;
1733}
1734
Dave Barach68b0fb02017-02-28 15:15:56 -05001735static inline uword
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001736ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1737 vlib_frame_t *frame, int head_of_feature_arc,
1738 int is_receive_dpo)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001739{
Florin Coras1b255522018-06-01 12:22:23 -07001740 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001741 vlib_node_runtime_t *error_node =
Florin Corasfa2a3162020-02-11 03:01:19 +00001742 vlib_node_get_runtime (vm, ip4_local_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001743 u16 nexts[VLIB_FRAME_SIZE], *next;
1744 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1745 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001746 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001747
1748 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001749 /*
1750 * 0.0.0.0 can appear as the source address of an IP packet,
1751 * as can any other address, hence the need to use the 'first'
1752 * member to make sure the .lbi is initialised for the first
1753 * packet.
1754 */
Florin Coras1b255522018-06-01 12:22:23 -07001755 .src = {.as_u32 = 0},
1756 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001757 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1758 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001759 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001760
1761 from = vlib_frame_vector_args (frame);
1762 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001763
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764 if (node->flags & VLIB_NODE_FLAG_TRACE)
1765 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1766
Florin Coras1b255522018-06-01 12:22:23 -07001767 vlib_get_buffers (vm, from, bufs, n_left_from);
1768 b = bufs;
1769 next = nexts;
1770
1771 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001773 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774
Florin Coras1b255522018-06-01 12:22:23 -07001775 /* Prefetch next iteration. */
1776 {
1777 vlib_prefetch_buffer_header (b[4], LOAD);
1778 vlib_prefetch_buffer_header (b[5], LOAD);
1779
Damjan Marionaf7fb042021-07-15 11:54:41 +02001780 clib_prefetch_load (b[4]->data);
1781 clib_prefetch_load (b[5]->data);
Florin Coras1b255522018-06-01 12:22:23 -07001782 }
1783
1784 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1785
1786 ip[0] = vlib_buffer_get_current (b[0]);
1787 ip[1] = vlib_buffer_get_current (b[1]);
1788
1789 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1790 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1791
Florin Corasc67cfd22018-10-01 21:59:18 -07001792 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1793 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001794
Florin Corasc67cfd22018-10-01 21:59:18 -07001795 not_batch = pt[0] ^ pt[1];
1796
1797 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001798 goto skip_checks;
1799
1800 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001801 {
Florin Coras1b255522018-06-01 12:22:23 -07001802 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001803 ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001804 }
1805 else
1806 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001807 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001808 {
Florin Coras1b255522018-06-01 12:22:23 -07001809 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001810 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1811 is_receive_dpo);
Florin Coras20a14b92017-08-15 22:47:22 -07001812 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001813 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001814 {
Florin Coras1b255522018-06-01 12:22:23 -07001815 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001816 ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1817 is_receive_dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001818 }
1819 }
1820
Florin Coras1b255522018-06-01 12:22:23 -07001821 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001822
Florin Coras1b255522018-06-01 12:22:23 -07001823 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1824 head_of_feature_arc);
1825 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1826 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001827
Florin Coras1b255522018-06-01 12:22:23 -07001828 b += 2;
1829 next += 2;
1830 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001831 }
1832
Florin Coras1b255522018-06-01 12:22:23 -07001833 while (n_left_from > 0)
1834 {
1835 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1836
1837 ip[0] = vlib_buffer_get_current (b[0]);
1838 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001839 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001840
Florin Corasc67cfd22018-10-01 21:59:18 -07001841 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001842 goto skip_check;
1843
1844 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001845 ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1846 is_receive_dpo);
Florin Coras1b255522018-06-01 12:22:23 -07001847
1848 skip_check:
1849
Florin Coras1b255522018-06-01 12:22:23 -07001850 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1851 head_of_feature_arc);
1852
1853 b += 1;
1854 next += 1;
1855 n_left_from -= 1;
1856 }
1857
1858 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859 return frame->n_vectors;
1860}
1861
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001862VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1863 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001864{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001865 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1866 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001867}
1868
Neale Ranns32e1c012016-11-22 17:07:28 +00001869VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870{
Dave Barach68b0fb02017-02-28 15:15:56 -05001871 .name = "ip4-local",
1872 .vector_size = sizeof (u32),
1873 .format_trace = format_ip4_forward_next_trace,
Florin Corasfa2a3162020-02-11 03:01:19 +00001874 .n_errors = IP4_N_ERROR,
1875 .error_strings = ip4_error_strings,
Dave Barach68b0fb02017-02-28 15:15:56 -05001876 .n_next_nodes = IP_LOCAL_N_NEXT,
1877 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001878 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001879 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1880 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001881 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001882 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera01c1fa42021-12-14 18:25:11 +00001883 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001884 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001885};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001886
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001887VLIB_NODE_FN (ip4_receive_local_node)
1888(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1889{
1890 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1891 1 /* is_receive_dpo */);
1892}
1893
1894VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1895 .name = "ip4-receive",
1896 .vector_size = sizeof (u32),
1897 .format_trace = format_ip4_forward_next_trace,
1898 .sibling_of = "ip4-local"
1899};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001900
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001901VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1902 vlib_node_runtime_t * node,
1903 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001904{
Nathan Skrzypczakbfa86082021-09-09 18:31:36 +02001905 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1906 0 /* is_receive_dpo */);
Dave Barach68b0fb02017-02-28 15:15:56 -05001907}
1908
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001909VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001910 .name = "ip4-local-end-of-arc",
1911 .vector_size = sizeof (u32),
1912
1913 .format_trace = format_ip4_forward_next_trace,
1914 .sibling_of = "ip4-local",
1915};
1916
Dave Barach68b0fb02017-02-28 15:15:56 -05001917VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1918 .arc_name = "ip4-local",
1919 .node_name = "ip4-local-end-of-arc",
1920 .runs_before = 0, /* not before any other features */
1921};
Dave Barach68b0fb02017-02-28 15:15:56 -05001922
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001923#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001924void
1925ip4_register_protocol (u32 protocol, u32 node_index)
1926{
1927 vlib_main_t *vm = vlib_get_main ();
1928 ip4_main_t *im = &ip4_main;
1929 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001930
1931 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001932 lm->local_next_by_ip_protocol[protocol] =
1933 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001934}
Neale Rannsb538dd82019-05-21 06:54:54 -07001935
1936void
1937ip4_unregister_protocol (u32 protocol)
1938{
1939 ip4_main_t *im = &ip4_main;
1940 ip_lookup_main_t *lm = &im->lookup_main;
1941
1942 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1943 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1944}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001945#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001946
1947static clib_error_t *
1948show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001949 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001950{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001951 ip4_main_t *im = &ip4_main;
1952 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001953 int i;
1954
1955 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001956 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001957 {
1958 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001959 {
1960 u32 node_index = vlib_get_node (vm,
1961 ip4_local_node.index)->
1962 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001963 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1964 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001965 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001966 }
1967 return 0;
1968}
1969
1970
1971
Billy McFall0683c9c2016-10-13 08:27:31 -04001972/*?
1973 * Display the set of protocols handled by the local IPv4 stack.
1974 *
1975 * @cliexpar
1976 * Example of how to display local protocol table:
1977 * @cliexstart{show ip local}
1978 * Protocols handled by ip4_local
1979 * 1
1980 * 17
1981 * 47
1982 * @cliexend
1983?*/
1984/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001985VLIB_CLI_COMMAND (show_ip_local, static) =
1986{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987 .path = "show ip local",
1988 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001989 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001990};
Billy McFall0683c9c2016-10-13 08:27:31 -04001991/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001992
Dave Barachd7cb1b52016-12-09 09:52:16 -05001993typedef enum
1994{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001996 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001997 IP4_REWRITE_NEXT_FRAGMENT,
1998 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001999} ip4_rewrite_next_t;
2000
Neale Ranns889fe942017-06-01 05:43:19 -04002001/**
2002 * This bits of an IPv4 address to mask to construct a multicast
2003 * MAC address
2004 */
2005#if CLIB_ARCH_IS_BIG_ENDIAN
2006#define IP4_MCAST_ADDR_MASK 0x007fffff
2007#else
2008#define IP4_MCAST_ADDR_MASK 0xffff7f00
2009#endif
2010
Ole Troan8a9c8f12018-05-18 11:01:31 +02002011always_inline void
2012ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Ole Troaneb284a12019-10-09 13:33:19 +02002013 u16 adj_packet_bytes, bool df, u16 * next,
2014 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002015{
2016 if (packet_len > adj_packet_bytes)
2017 {
2018 *error = IP4_ERROR_MTU_EXCEEDED;
2019 if (df)
2020 {
2021 icmp4_error_set_vnet_buffer
2022 (b, ICMP4_destination_unreachable,
2023 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2024 adj_packet_bytes);
2025 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2026 }
2027 else
2028 {
Ole Troan313f7e22018-04-10 16:02:51 +02002029 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002030 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00002031 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02002032 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2033 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002034 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002035 }
2036 }
2037}
2038
Neale Ranns0b6a8572019-10-30 17:34:14 +00002039/* increment TTL & update checksum.
2040 Works either endian, so no need for byte swap. */
2041static_always_inline void
2042ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2043{
2044 i32 ttl;
2045 u32 checksum;
2046 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002047 return;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002048
2049 ttl = ip->ttl;
2050
2051 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2052 checksum += checksum >= 0xffff;
2053
2054 ip->checksum = checksum;
2055 ttl += 1;
2056 ip->ttl = ttl;
2057
Benoît Ganne6e334e32020-08-31 18:59:34 +02002058 ASSERT (ip4_header_checksum_is_valid (ip));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002059}
2060
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002061/* Decrement TTL & update checksum.
2062 Works either endian, so no need for byte swap. */
2063static_always_inline void
2064ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2065 u32 * error)
2066{
2067 i32 ttl;
2068 u32 checksum;
2069 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002070 return;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002071
2072 ttl = ip->ttl;
2073
2074 /* Input node should have reject packets with ttl 0. */
2075 ASSERT (ip->ttl > 0);
2076
2077 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2078 checksum += checksum >= 0xffff;
2079
2080 ip->checksum = checksum;
2081 ttl -= 1;
2082 ip->ttl = ttl;
2083
2084 /*
2085 * If the ttl drops below 1 when forwarding, generate
2086 * an ICMP response.
2087 */
2088 if (PREDICT_FALSE (ttl <= 0))
2089 {
2090 *error = IP4_ERROR_TIME_EXPIRED;
2091 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2092 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2093 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2094 0);
2095 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2096 }
2097
2098 /* Verify checksum. */
Benoît Ganne6e334e32020-08-31 18:59:34 +02002099 ASSERT (ip4_header_checksum_is_valid (ip) ||
Mohsin Kazmi4fd9f102021-06-17 17:29:27 +00002100 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2101 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002102}
2103
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104always_inline uword
Damjan Mariond06e2eb2021-04-21 23:44:40 +02002105ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2106 vlib_frame_t *frame, int do_counters, int is_midchain,
2107 int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002108{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002109 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2110 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002111 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2112 u16 nexts[VLIB_FRAME_SIZE], *next;
2113 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002114 vlib_node_runtime_t *error_node =
2115 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002116
2117 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002118 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002119
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002120 vlib_get_buffers (vm, from, bufs, n_left_from);
2121 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2122
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002123#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002124 if (n_left_from >= 6)
2125 {
2126 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002127 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002128 vlib_prefetch_buffer_header (bufs[i], LOAD);
2129 }
2130
2131 next = nexts;
2132 b = bufs;
2133 while (n_left_from >= 8)
2134 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002135 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002136 ip4_header_t *ip0, *ip1;
2137 u32 rw_len0, error0, adj_index0;
2138 u32 rw_len1, error1, adj_index1;
2139 u32 tx_sw_if_index0, tx_sw_if_index1;
2140 u8 *p;
2141
PiotrX Kleskib801cd12020-12-09 14:32:26 +01002142 if (is_midchain)
2143 {
2144 vlib_prefetch_buffer_header (b[6], LOAD);
2145 vlib_prefetch_buffer_header (b[7], LOAD);
2146 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002147
2148 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2149 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2150
2151 /*
2152 * pre-fetch the per-adjacency counters
2153 */
2154 if (do_counters)
2155 {
2156 vlib_prefetch_combined_counter (&adjacency_counters,
2157 thread_index, adj_index0);
2158 vlib_prefetch_combined_counter (&adjacency_counters,
2159 thread_index, adj_index1);
2160 }
2161
2162 ip0 = vlib_buffer_get_current (b[0]);
2163 ip1 = vlib_buffer_get_current (b[1]);
2164
2165 error0 = error1 = IP4_ERROR_NONE;
2166
2167 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2168 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2169
2170 /* Rewrite packet header and updates lengths. */
2171 adj0 = adj_get (adj_index0);
2172 adj1 = adj_get (adj_index1);
2173
2174 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2175 rw_len0 = adj0[0].rewrite_header.data_bytes;
2176 rw_len1 = adj1[0].rewrite_header.data_bytes;
2177 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2178 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2179
2180 p = vlib_buffer_get_current (b[2]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002181 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2182 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002183
2184 p = vlib_buffer_get_current (b[3]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002185 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2186 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002187
2188 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002189 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2190 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2191
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002192 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002193 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002194 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002195 ip1_len = gso_mtu_sz (b[1]);
2196
2197 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002198 adj0[0].rewrite_header.max_l3_packet_bytes,
2199 ip0->flags_and_fragment_offset &
2200 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002201 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002202 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002203 adj1[0].rewrite_header.max_l3_packet_bytes,
2204 ip1->flags_and_fragment_offset &
2205 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002206 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002207
2208 if (is_mcast)
2209 {
2210 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2211 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2212 IP4_ERROR_SAME_INTERFACE : error0);
2213 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2214 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2215 IP4_ERROR_SAME_INTERFACE : error1);
2216 }
2217
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002218 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002219 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002220 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2221 {
2222 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002223 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002224
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002225 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2226 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2227
2228 if (PREDICT_FALSE
2229 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002230 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2231 tx_sw_if_index0,
2232 &next_index, b[0],
2233 adj0->ia_cfg_index);
2234
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002235 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002236 if (is_midchain)
Dave Barach1bd2c012020-04-12 08:31:39 -04002237 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002238 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002239 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002240 else
2241 {
2242 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002243 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2244 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002245 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002246 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2247 {
2248 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002249 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002250
2251 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2252 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2253
2254 if (PREDICT_FALSE
2255 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002256 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2257 tx_sw_if_index1,
2258 &next_index, b[1],
2259 adj1->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002260 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002261 if (is_midchain)
Neale Rannsfc746972020-05-20 19:58:20 +00002262 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002263 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002264 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002265 else
2266 {
2267 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002268 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2269 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002270 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002271
Neale Ranns4ec36c52020-03-31 09:21:29 -04002272 if (is_midchain)
2273 /* Guess we are only writing on ipv4 header. */
2274 vnet_rewrite_two_headers (adj0[0], adj1[0],
2275 ip0, ip1, sizeof (ip4_header_t));
2276 else
2277 /* Guess we are only writing on simple Ethernet header. */
2278 vnet_rewrite_two_headers (adj0[0], adj1[0],
2279 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002280
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002281 if (do_counters)
2282 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002283 if (error0 == IP4_ERROR_NONE)
2284 vlib_increment_combined_counter
2285 (&adjacency_counters,
2286 thread_index,
2287 adj_index0, 1,
2288 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002289
Neale Ranns0b6a8572019-10-30 17:34:14 +00002290 if (error1 == IP4_ERROR_NONE)
2291 vlib_increment_combined_counter
2292 (&adjacency_counters,
2293 thread_index,
2294 adj_index1, 1,
2295 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002296 }
2297
2298 if (is_midchain)
2299 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002300 if (error0 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002301 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns4ec36c52020-03-31 09:21:29 -04002302 if (error1 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002303 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002304 }
2305
2306 if (is_mcast)
2307 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002308 /* copy bytes from the IP address into the MAC rewrite */
2309 if (error0 == IP4_ERROR_NONE)
2310 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2311 adj0->rewrite_header.dst_mcast_offset,
2312 &ip0->dst_address.as_u32, (u8 *) ip0);
2313 if (error1 == IP4_ERROR_NONE)
2314 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2315 adj1->rewrite_header.dst_mcast_offset,
2316 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002317 }
2318
2319 next += 2;
2320 b += 2;
2321 n_left_from -= 2;
2322 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002323#elif (CLIB_N_PREFETCHES >= 4)
2324 next = nexts;
2325 b = bufs;
2326 while (n_left_from >= 1)
2327 {
2328 ip_adjacency_t *adj0;
2329 ip4_header_t *ip0;
2330 u32 rw_len0, error0, adj_index0;
2331 u32 tx_sw_if_index0;
2332 u8 *p;
2333
2334 /* Prefetch next iteration */
2335 if (PREDICT_TRUE (n_left_from >= 4))
2336 {
2337 ip_adjacency_t *adj2;
2338 u32 adj_index2;
2339
2340 vlib_prefetch_buffer_header (b[3], LOAD);
2341 vlib_prefetch_buffer_data (b[2], LOAD);
2342
2343 /* Prefetch adj->rewrite_header */
2344 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2345 adj2 = adj_get (adj_index2);
2346 p = (u8 *) adj2;
2347 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2348 LOAD);
2349 }
2350
2351 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2352
2353 /*
2354 * Prefetch the per-adjacency counters
2355 */
2356 if (do_counters)
2357 {
2358 vlib_prefetch_combined_counter (&adjacency_counters,
2359 thread_index, adj_index0);
2360 }
2361
2362 ip0 = vlib_buffer_get_current (b[0]);
2363
2364 error0 = IP4_ERROR_NONE;
2365
2366 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2367
2368 /* Rewrite packet header and updates lengths. */
2369 adj0 = adj_get (adj_index0);
2370
2371 /* Rewrite header was prefetched. */
2372 rw_len0 = adj0[0].rewrite_header.data_bytes;
2373 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2374
2375 /* Check MTU of outgoing interface. */
2376 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2377
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002378 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002379 ip0_len = gso_mtu_sz (b[0]);
2380
2381 ip4_mtu_check (b[0], ip0_len,
2382 adj0[0].rewrite_header.max_l3_packet_bytes,
2383 ip0->flags_and_fragment_offset &
2384 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002385 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002386
2387 if (is_mcast)
2388 {
2389 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2390 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2391 IP4_ERROR_SAME_INTERFACE : error0);
2392 }
2393
2394 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2395 * to see the IP header */
2396 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2397 {
2398 u32 next_index = adj0[0].rewrite_header.next_index;
2399 vlib_buffer_advance (b[0], -(word) rw_len0);
2400 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2401 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2402
2403 if (PREDICT_FALSE
2404 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002405 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2406 tx_sw_if_index0,
2407 &next_index, b[0],
2408 adj0->ia_cfg_index);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002409 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002410
2411 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002412 {
2413 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002414 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002415
Neale Ranns4ec36c52020-03-31 09:21:29 -04002416 /* Guess we are only writing on ipv4 header. */
2417 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2418 }
2419 else
2420 /* Guess we are only writing on simple Ethernet header. */
2421 vnet_rewrite_one_header (adj0[0], ip0,
2422 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002423
2424 /*
2425 * Bump the per-adjacency counters
2426 */
2427 if (do_counters)
2428 vlib_increment_combined_counter
2429 (&adjacency_counters,
2430 thread_index,
2431 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2432 b[0]) + rw_len0);
2433
Neale Ranns4ec36c52020-03-31 09:21:29 -04002434 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002435 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002436
2437 if (is_mcast)
2438 /* copy bytes from the IP address into the MAC rewrite */
2439 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2440 adj0->rewrite_header.dst_mcast_offset,
2441 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002442 }
2443 else
2444 {
2445 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002446 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2447 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002448 }
2449
2450 next += 1;
2451 b += 1;
2452 n_left_from -= 1;
2453 }
2454#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002455
Ed Warnickecb9cada2015-12-08 15:45:58 -07002456 while (n_left_from > 0)
2457 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002458 ip_adjacency_t *adj0;
2459 ip4_header_t *ip0;
2460 u32 rw_len0, adj_index0, error0;
2461 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002462
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002463 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2464
2465 adj0 = adj_get (adj_index0);
2466
2467 if (do_counters)
2468 vlib_prefetch_combined_counter (&adjacency_counters,
2469 thread_index, adj_index0);
2470
2471 ip0 = vlib_buffer_get_current (b[0]);
2472
2473 error0 = IP4_ERROR_NONE;
2474
2475 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2476
2477
2478 /* Update packet buffer attributes/set output interface. */
2479 rw_len0 = adj0[0].rewrite_header.data_bytes;
2480 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2481
2482 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002483 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002484 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002485 ip0_len = gso_mtu_sz (b[0]);
2486
2487 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002488 adj0[0].rewrite_header.max_l3_packet_bytes,
2489 ip0->flags_and_fragment_offset &
2490 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002491 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002492
2493 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002494 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002495 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2496 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2497 IP4_ERROR_SAME_INTERFACE : error0);
2498 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002499
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002500 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002501 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002502 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2503 {
2504 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002505 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002506 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2507 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002508
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002509 if (PREDICT_FALSE
2510 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002511 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2512 tx_sw_if_index0,
2513 &next_index, b[0],
2514 adj0->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002515 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002516
2517 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002518 {
2519 /* this acts on the packet that is about to be encapped */
2520 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002521 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002522
Neale Ranns4ec36c52020-03-31 09:21:29 -04002523 /* Guess we are only writing on ipv4 header. */
2524 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2525 }
2526 else
2527 /* Guess we are only writing on simple Ethernet header. */
2528 vnet_rewrite_one_header (adj0[0], ip0,
2529 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002530
2531 if (do_counters)
2532 vlib_increment_combined_counter
2533 (&adjacency_counters,
2534 thread_index, adj_index0, 1,
2535 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2536
Neale Rannse2fe0972020-11-26 08:37:27 +00002537 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002538 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002539
2540 if (is_mcast)
2541 /* copy bytes from the IP address into the MAC rewrite */
2542 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2543 adj0->rewrite_header.dst_mcast_offset,
2544 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002545 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002546 else
2547 {
2548 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002549 /* undo the TTL decrement - we'll be back to do it again */
2550 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2551 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002552 }
2553
2554 next += 1;
2555 b += 1;
2556 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002557 }
2558
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002559
Ed Warnickecb9cada2015-12-08 15:45:58 -07002560 /* Need to do trace after rewrites to pick up new packet data. */
2561 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002562 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002563
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002564 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002565 return frame->n_vectors;
2566}
2567
Neale Rannsf06aea52016-11-29 06:51:37 -08002568/** @brief IPv4 rewrite node.
2569 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002570
2571 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2572 header checksum, fetch the ip adjacency, check the outbound mtu,
2573 apply the adjacency rewrite, and send pkts to the adjacency
2574 rewrite header's rewrite_next_index.
2575
2576 @param vm vlib_main_t corresponding to the current thread
2577 @param node vlib_node_runtime_t
2578 @param frame vlib_frame_t whose contents should be dispatched
2579
2580 @par Graph mechanics: buffer metadata, next index usage
2581
2582 @em Uses:
2583 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2584 - the rewrite adjacency index
2585 - <code>adj->lookup_next_index</code>
2586 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002587 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002588 - <code>adj->rewrite_header</code>
2589 - Rewrite string length, rewrite string, next_index
2590
2591 @em Sets:
2592 - <code>b->current_data, b->current_length</code>
2593 - Updated net of applying the rewrite string
2594
2595 <em>Next Indices:</em>
2596 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002597 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002598*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002599
2600VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2601 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002602{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002603 if (adj_are_counters_enabled ())
2604 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2605 else
2606 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002607}
2608
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002609VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2610 vlib_node_runtime_t * node,
2611 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002612{
2613 if (adj_are_counters_enabled ())
2614 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2615 else
2616 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2617}
2618
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002619VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2620 vlib_node_runtime_t * node,
2621 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002622{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002623 if (adj_are_counters_enabled ())
2624 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2625 else
2626 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002627}
2628
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002629VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2630 vlib_node_runtime_t * node,
2631 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002632{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002633 if (adj_are_counters_enabled ())
2634 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2635 else
2636 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002637}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002638
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002639VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2640 vlib_node_runtime_t * node,
2641 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002642{
2643 if (adj_are_counters_enabled ())
2644 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2645 else
2646 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2647}
2648
Neale Ranns32e1c012016-11-22 17:07:28 +00002649/* *INDENT-OFF* */
2650VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002651 .name = "ip4-rewrite",
2652 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002653
Neale Ranns32e1c012016-11-22 17:07:28 +00002654 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655
Ole Troan313f7e22018-04-10 16:02:51 +02002656 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002657 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002658 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002659 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002660 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002661 },
2662};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002663
2664VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002665 .name = "ip4-rewrite-bcast",
2666 .vector_size = sizeof (u32),
2667
2668 .format_trace = format_ip4_rewrite_trace,
2669 .sibling_of = "ip4-rewrite",
2670};
Neale Ranns32e1c012016-11-22 17:07:28 +00002671
2672VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002673 .name = "ip4-rewrite-mcast",
2674 .vector_size = sizeof (u32),
2675
2676 .format_trace = format_ip4_rewrite_trace,
2677 .sibling_of = "ip4-rewrite",
2678};
Neale Ranns32e1c012016-11-22 17:07:28 +00002679
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002680VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002681 .name = "ip4-mcast-midchain",
2682 .vector_size = sizeof (u32),
2683
2684 .format_trace = format_ip4_rewrite_trace,
2685 .sibling_of = "ip4-rewrite",
2686};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002687
Neale Ranns32e1c012016-11-22 17:07:28 +00002688VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002689 .name = "ip4-midchain",
2690 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002691 .format_trace = format_ip4_rewrite_trace,
2692 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002693};
Neale Ranns32e1c012016-11-22 17:07:28 +00002694/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002695
Ed Warnickecb9cada2015-12-08 15:45:58 -07002696static clib_error_t *
2697set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002698 unformat_input_t * input,
2699 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002700{
2701 int matched = 0;
2702 u32 table_id = 0;
2703 u32 flow_hash_config = 0;
2704 int rv;
2705
Dave Barachd7cb1b52016-12-09 09:52:16 -05002706 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2707 {
2708 if (unformat (input, "table %d", &table_id))
2709 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002710#define _(a, b, v) \
2711 else if (unformat (input, #a)) \
2712 { \
2713 flow_hash_config |= v; \
2714 matched = 1; \
2715 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002716 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002717#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002718 else
2719 break;
2720 }
Dave Barach75fc8542016-10-11 16:16:02 -04002721
Ed Warnickecb9cada2015-12-08 15:45:58 -07002722 if (matched == 0)
2723 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002724 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002725
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002726 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727 switch (rv)
2728 {
2729 case 0:
2730 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002731
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732 case VNET_API_ERROR_NO_SUCH_FIB:
2733 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002734
Ed Warnickecb9cada2015-12-08 15:45:58 -07002735 default:
2736 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2737 break;
2738 }
Dave Barach75fc8542016-10-11 16:16:02 -04002739
Ed Warnickecb9cada2015-12-08 15:45:58 -07002740 return 0;
2741}
Dave Barach75fc8542016-10-11 16:16:02 -04002742
Billy McFall0683c9c2016-10-13 08:27:31 -04002743/*?
2744 * Configure the set of IPv4 fields used by the flow hash.
2745 *
2746 * @cliexpar
2747 * Example of how to set the flow hash on a given table:
2748 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2749 * Example of display the configured flow hash:
2750 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002751 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2752 * 0.0.0.0/0
2753 * unicast-ip4-chain
2754 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2755 * [0] [@0]: dpo-drop ip6
2756 * 0.0.0.0/32
2757 * unicast-ip4-chain
2758 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2759 * [0] [@0]: dpo-drop ip6
2760 * 224.0.0.0/8
2761 * unicast-ip4-chain
2762 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2763 * [0] [@0]: dpo-drop ip6
2764 * 6.0.1.2/32
2765 * unicast-ip4-chain
2766 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2767 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2768 * 7.0.0.1/32
2769 * unicast-ip4-chain
2770 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2771 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2772 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2773 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2774 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2775 * 240.0.0.0/8
2776 * unicast-ip4-chain
2777 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2778 * [0] [@0]: dpo-drop ip6
2779 * 255.255.255.255/32
2780 * unicast-ip4-chain
2781 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2782 * [0] [@0]: dpo-drop ip6
2783 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2784 * 0.0.0.0/0
2785 * unicast-ip4-chain
2786 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2787 * [0] [@0]: dpo-drop ip6
2788 * 0.0.0.0/32
2789 * unicast-ip4-chain
2790 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2791 * [0] [@0]: dpo-drop ip6
2792 * 172.16.1.0/24
2793 * unicast-ip4-chain
2794 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2795 * [0] [@4]: ipv4-glean: af_packet0
2796 * 172.16.1.1/32
2797 * unicast-ip4-chain
2798 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2799 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2800 * 172.16.1.2/32
2801 * unicast-ip4-chain
2802 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2803 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2804 * 172.16.2.0/24
2805 * unicast-ip4-chain
2806 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2807 * [0] [@4]: ipv4-glean: af_packet1
2808 * 172.16.2.1/32
2809 * unicast-ip4-chain
2810 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2811 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2812 * 224.0.0.0/8
2813 * unicast-ip4-chain
2814 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2815 * [0] [@0]: dpo-drop ip6
2816 * 240.0.0.0/8
2817 * unicast-ip4-chain
2818 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2819 * [0] [@0]: dpo-drop ip6
2820 * 255.255.255.255/32
2821 * unicast-ip4-chain
2822 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2823 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002824 * @cliexend
2825?*/
2826/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002827VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2828{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002829 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002830 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002831 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002832 .function = set_ip_flow_hash_command_fn,
2833};
Billy McFall0683c9c2016-10-13 08:27:31 -04002834/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002835
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002836#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002837int
2838vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2839 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002840{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002841 vnet_main_t *vnm = vnet_get_main ();
2842 vnet_interface_main_t *im = &vnm->interface_main;
2843 ip4_main_t *ipm = &ip4_main;
2844 ip_lookup_main_t *lm = &ipm->lookup_main;
2845 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002846 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002847
2848 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2849 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2850
2851 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2852 return VNET_API_ERROR_NO_SUCH_ENTRY;
2853
2854 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002855 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002856
Neale Rannsdf089a82016-10-02 16:39:06 +01002857 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2858
2859 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002861 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002862 .fp_len = 32,
2863 .fp_proto = FIB_PROTOCOL_IP4,
2864 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002865 };
2866 u32 fib_index;
2867
Dave Barachd7cb1b52016-12-09 09:52:16 -05002868 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2869 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002870
2871
Dave Barachd7cb1b52016-12-09 09:52:16 -05002872 if (table_index != (u32) ~ 0)
2873 {
2874 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002875
Dave Barachd7cb1b52016-12-09 09:52:16 -05002876 dpo_set (&dpo,
2877 DPO_CLASSIFY,
2878 DPO_PROTO_IP4,
2879 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002880
Dave Barachd7cb1b52016-12-09 09:52:16 -05002881 fib_table_entry_special_dpo_add (fib_index,
2882 &pfx,
2883 FIB_SOURCE_CLASSIFY,
2884 FIB_ENTRY_FLAG_NONE, &dpo);
2885 dpo_reset (&dpo);
2886 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002887 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002888 {
2889 fib_table_entry_special_remove (fib_index,
2890 &pfx, FIB_SOURCE_CLASSIFY);
2891 }
2892 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002893
Ed Warnickecb9cada2015-12-08 15:45:58 -07002894 return 0;
2895}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002896#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002897
2898static clib_error_t *
2899set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002900 unformat_input_t * input,
2901 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002902{
2903 u32 table_index = ~0;
2904 int table_index_set = 0;
2905 u32 sw_if_index = ~0;
2906 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002907
Dave Barachd7cb1b52016-12-09 09:52:16 -05002908 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2909 {
2910 if (unformat (input, "table-index %d", &table_index))
2911 table_index_set = 1;
2912 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2913 vnet_get_main (), &sw_if_index))
2914 ;
2915 else
2916 break;
2917 }
Dave Barach75fc8542016-10-11 16:16:02 -04002918
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919 if (table_index_set == 0)
2920 return clib_error_return (0, "classify table-index must be specified");
2921
2922 if (sw_if_index == ~0)
2923 return clib_error_return (0, "interface / subif must be specified");
2924
2925 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2926
2927 switch (rv)
2928 {
2929 case 0:
2930 break;
2931
2932 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2933 return clib_error_return (0, "No such interface");
2934
2935 case VNET_API_ERROR_NO_SUCH_ENTRY:
2936 return clib_error_return (0, "No such classifier table");
2937 }
2938 return 0;
2939}
2940
Billy McFall0683c9c2016-10-13 08:27:31 -04002941/*?
2942 * Assign a classification table to an interface. The classification
2943 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2944 * commands. Once the table is create, use this command to filter packets
2945 * on an interface.
2946 *
2947 * @cliexpar
2948 * Example of how to assign a classification table to an interface:
2949 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2950?*/
2951/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2953{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002955 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002956 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002957 .function = set_ip_classify_command_fn,
2958};
Billy McFall0683c9c2016-10-13 08:27:31 -04002959/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002960
2961/*
2962 * fd.io coding-style-patch-verification: ON
2963 *
2964 * Local Variables:
2965 * eval: (c-set-style "gnu")
2966 * End:
2967 */