blob: 3556d357f502c5d7683ea60589062ad21998817a [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
Aloys Augustin0b77e312022-02-24 15:44:23 +00002058 ASSERT (ip4_header_checksum_is_valid (ip) ||
2059 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2060 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002061}
2062
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002063/* Decrement TTL & update checksum.
2064 Works either endian, so no need for byte swap. */
2065static_always_inline void
2066ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2067 u32 * error)
2068{
2069 i32 ttl;
2070 u32 checksum;
2071 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002072 return;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002073
2074 ttl = ip->ttl;
2075
2076 /* Input node should have reject packets with ttl 0. */
2077 ASSERT (ip->ttl > 0);
2078
2079 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2080 checksum += checksum >= 0xffff;
2081
2082 ip->checksum = checksum;
2083 ttl -= 1;
2084 ip->ttl = ttl;
2085
2086 /*
2087 * If the ttl drops below 1 when forwarding, generate
2088 * an ICMP response.
2089 */
2090 if (PREDICT_FALSE (ttl <= 0))
2091 {
2092 *error = IP4_ERROR_TIME_EXPIRED;
2093 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2094 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2095 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2096 0);
2097 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2098 }
2099
2100 /* Verify checksum. */
Benoît Ganne6e334e32020-08-31 18:59:34 +02002101 ASSERT (ip4_header_checksum_is_valid (ip) ||
Mohsin Kazmi4fd9f102021-06-17 17:29:27 +00002102 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2103 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002104}
2105
Ed Warnickecb9cada2015-12-08 15:45:58 -07002106always_inline uword
Damjan Mariond06e2eb2021-04-21 23:44:40 +02002107ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2108 vlib_frame_t *frame, int do_counters, int is_midchain,
2109 int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002110{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002111 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2112 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002113 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2114 u16 nexts[VLIB_FRAME_SIZE], *next;
2115 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002116 vlib_node_runtime_t *error_node =
2117 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002118
2119 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002120 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002121
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002122 vlib_get_buffers (vm, from, bufs, n_left_from);
2123 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2124
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002125#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002126 if (n_left_from >= 6)
2127 {
2128 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002129 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002130 vlib_prefetch_buffer_header (bufs[i], LOAD);
2131 }
2132
2133 next = nexts;
2134 b = bufs;
2135 while (n_left_from >= 8)
2136 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002137 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002138 ip4_header_t *ip0, *ip1;
2139 u32 rw_len0, error0, adj_index0;
2140 u32 rw_len1, error1, adj_index1;
2141 u32 tx_sw_if_index0, tx_sw_if_index1;
2142 u8 *p;
2143
PiotrX Kleskib801cd12020-12-09 14:32:26 +01002144 if (is_midchain)
2145 {
2146 vlib_prefetch_buffer_header (b[6], LOAD);
2147 vlib_prefetch_buffer_header (b[7], LOAD);
2148 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002149
2150 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2151 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2152
2153 /*
2154 * pre-fetch the per-adjacency counters
2155 */
2156 if (do_counters)
2157 {
2158 vlib_prefetch_combined_counter (&adjacency_counters,
2159 thread_index, adj_index0);
2160 vlib_prefetch_combined_counter (&adjacency_counters,
2161 thread_index, adj_index1);
2162 }
2163
2164 ip0 = vlib_buffer_get_current (b[0]);
2165 ip1 = vlib_buffer_get_current (b[1]);
2166
2167 error0 = error1 = IP4_ERROR_NONE;
2168
2169 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2170 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2171
2172 /* Rewrite packet header and updates lengths. */
2173 adj0 = adj_get (adj_index0);
2174 adj1 = adj_get (adj_index1);
2175
2176 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2177 rw_len0 = adj0[0].rewrite_header.data_bytes;
2178 rw_len1 = adj1[0].rewrite_header.data_bytes;
2179 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2180 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2181
2182 p = vlib_buffer_get_current (b[2]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002183 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2184 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002185
2186 p = vlib_buffer_get_current (b[3]);
Damjan Marionaf7fb042021-07-15 11:54:41 +02002187 clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2188 clib_prefetch_load (p);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002189
2190 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002191 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2192 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2193
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002194 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002195 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002196 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002197 ip1_len = gso_mtu_sz (b[1]);
2198
2199 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002200 adj0[0].rewrite_header.max_l3_packet_bytes,
2201 ip0->flags_and_fragment_offset &
2202 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002203 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002204 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002205 adj1[0].rewrite_header.max_l3_packet_bytes,
2206 ip1->flags_and_fragment_offset &
2207 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002208 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002209
2210 if (is_mcast)
2211 {
2212 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2213 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2214 IP4_ERROR_SAME_INTERFACE : error0);
2215 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2216 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2217 IP4_ERROR_SAME_INTERFACE : error1);
2218 }
2219
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002220 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002221 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002222 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2223 {
2224 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002225 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002226
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002227 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2228 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2229
2230 if (PREDICT_FALSE
2231 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002232 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2233 tx_sw_if_index0,
2234 &next_index, b[0],
2235 adj0->ia_cfg_index);
2236
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002237 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002238 if (is_midchain)
Dave Barach1bd2c012020-04-12 08:31:39 -04002239 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002240 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002241 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002242 else
2243 {
2244 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002245 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2246 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002247 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002248 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2249 {
2250 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002251 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002252
2253 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2254 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2255
2256 if (PREDICT_FALSE
2257 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002258 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2259 tx_sw_if_index1,
2260 &next_index, b[1],
2261 adj1->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002262 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002263 if (is_midchain)
Neale Rannsfc746972020-05-20 19:58:20 +00002264 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002265 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002266 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002267 else
2268 {
2269 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002270 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2271 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002272 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002273
Neale Ranns4ec36c52020-03-31 09:21:29 -04002274 if (is_midchain)
2275 /* Guess we are only writing on ipv4 header. */
2276 vnet_rewrite_two_headers (adj0[0], adj1[0],
2277 ip0, ip1, sizeof (ip4_header_t));
2278 else
2279 /* Guess we are only writing on simple Ethernet header. */
2280 vnet_rewrite_two_headers (adj0[0], adj1[0],
2281 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002282
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002283 if (do_counters)
2284 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002285 if (error0 == IP4_ERROR_NONE)
2286 vlib_increment_combined_counter
2287 (&adjacency_counters,
2288 thread_index,
2289 adj_index0, 1,
2290 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002291
Neale Ranns0b6a8572019-10-30 17:34:14 +00002292 if (error1 == IP4_ERROR_NONE)
2293 vlib_increment_combined_counter
2294 (&adjacency_counters,
2295 thread_index,
2296 adj_index1, 1,
2297 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002298 }
2299
2300 if (is_midchain)
2301 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002302 if (error0 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002303 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns4ec36c52020-03-31 09:21:29 -04002304 if (error1 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002305 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002306 }
2307
2308 if (is_mcast)
2309 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002310 /* copy bytes from the IP address into the MAC rewrite */
2311 if (error0 == IP4_ERROR_NONE)
2312 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2313 adj0->rewrite_header.dst_mcast_offset,
2314 &ip0->dst_address.as_u32, (u8 *) ip0);
2315 if (error1 == IP4_ERROR_NONE)
2316 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2317 adj1->rewrite_header.dst_mcast_offset,
2318 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002319 }
2320
2321 next += 2;
2322 b += 2;
2323 n_left_from -= 2;
2324 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002325#elif (CLIB_N_PREFETCHES >= 4)
2326 next = nexts;
2327 b = bufs;
2328 while (n_left_from >= 1)
2329 {
2330 ip_adjacency_t *adj0;
2331 ip4_header_t *ip0;
2332 u32 rw_len0, error0, adj_index0;
2333 u32 tx_sw_if_index0;
2334 u8 *p;
2335
2336 /* Prefetch next iteration */
2337 if (PREDICT_TRUE (n_left_from >= 4))
2338 {
2339 ip_adjacency_t *adj2;
2340 u32 adj_index2;
2341
2342 vlib_prefetch_buffer_header (b[3], LOAD);
2343 vlib_prefetch_buffer_data (b[2], LOAD);
2344
2345 /* Prefetch adj->rewrite_header */
2346 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2347 adj2 = adj_get (adj_index2);
2348 p = (u8 *) adj2;
2349 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2350 LOAD);
2351 }
2352
2353 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2354
2355 /*
2356 * Prefetch the per-adjacency counters
2357 */
2358 if (do_counters)
2359 {
2360 vlib_prefetch_combined_counter (&adjacency_counters,
2361 thread_index, adj_index0);
2362 }
2363
2364 ip0 = vlib_buffer_get_current (b[0]);
2365
2366 error0 = IP4_ERROR_NONE;
2367
2368 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2369
2370 /* Rewrite packet header and updates lengths. */
2371 adj0 = adj_get (adj_index0);
2372
2373 /* Rewrite header was prefetched. */
2374 rw_len0 = adj0[0].rewrite_header.data_bytes;
2375 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2376
2377 /* Check MTU of outgoing interface. */
2378 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2379
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002380 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002381 ip0_len = gso_mtu_sz (b[0]);
2382
2383 ip4_mtu_check (b[0], ip0_len,
2384 adj0[0].rewrite_header.max_l3_packet_bytes,
2385 ip0->flags_and_fragment_offset &
2386 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002387 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002388
2389 if (is_mcast)
2390 {
2391 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2392 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2393 IP4_ERROR_SAME_INTERFACE : error0);
2394 }
2395
2396 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2397 * to see the IP header */
2398 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2399 {
2400 u32 next_index = adj0[0].rewrite_header.next_index;
2401 vlib_buffer_advance (b[0], -(word) rw_len0);
2402 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2403 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2404
2405 if (PREDICT_FALSE
2406 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002407 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2408 tx_sw_if_index0,
2409 &next_index, b[0],
2410 adj0->ia_cfg_index);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002411 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002412
2413 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002414 {
2415 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002416 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002417
Neale Ranns4ec36c52020-03-31 09:21:29 -04002418 /* Guess we are only writing on ipv4 header. */
2419 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2420 }
2421 else
2422 /* Guess we are only writing on simple Ethernet header. */
2423 vnet_rewrite_one_header (adj0[0], ip0,
2424 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002425
2426 /*
2427 * Bump the per-adjacency counters
2428 */
2429 if (do_counters)
2430 vlib_increment_combined_counter
2431 (&adjacency_counters,
2432 thread_index,
2433 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2434 b[0]) + rw_len0);
2435
Neale Ranns4ec36c52020-03-31 09:21:29 -04002436 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002437 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002438
2439 if (is_mcast)
2440 /* copy bytes from the IP address into the MAC rewrite */
2441 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2442 adj0->rewrite_header.dst_mcast_offset,
2443 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002444 }
2445 else
2446 {
2447 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002448 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2449 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002450 }
2451
2452 next += 1;
2453 b += 1;
2454 n_left_from -= 1;
2455 }
2456#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002457
Ed Warnickecb9cada2015-12-08 15:45:58 -07002458 while (n_left_from > 0)
2459 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002460 ip_adjacency_t *adj0;
2461 ip4_header_t *ip0;
2462 u32 rw_len0, adj_index0, error0;
2463 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002464
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002465 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2466
2467 adj0 = adj_get (adj_index0);
2468
2469 if (do_counters)
2470 vlib_prefetch_combined_counter (&adjacency_counters,
2471 thread_index, adj_index0);
2472
2473 ip0 = vlib_buffer_get_current (b[0]);
2474
2475 error0 = IP4_ERROR_NONE;
2476
2477 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2478
2479
2480 /* Update packet buffer attributes/set output interface. */
2481 rw_len0 = adj0[0].rewrite_header.data_bytes;
2482 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2483
2484 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002485 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002486 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002487 ip0_len = gso_mtu_sz (b[0]);
2488
2489 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002490 adj0[0].rewrite_header.max_l3_packet_bytes,
2491 ip0->flags_and_fragment_offset &
2492 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002493 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002494
2495 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002496 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002497 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2498 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2499 IP4_ERROR_SAME_INTERFACE : error0);
2500 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002501
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002502 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002503 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002504 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2505 {
2506 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002507 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002508 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2509 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002510
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002511 if (PREDICT_FALSE
2512 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002513 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2514 tx_sw_if_index0,
2515 &next_index, b[0],
2516 adj0->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002517 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002518
2519 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002520 {
2521 /* this acts on the packet that is about to be encapped */
2522 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002523 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002524
Neale Ranns4ec36c52020-03-31 09:21:29 -04002525 /* Guess we are only writing on ipv4 header. */
2526 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2527 }
2528 else
2529 /* Guess we are only writing on simple Ethernet header. */
2530 vnet_rewrite_one_header (adj0[0], ip0,
2531 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002532
2533 if (do_counters)
2534 vlib_increment_combined_counter
2535 (&adjacency_counters,
2536 thread_index, adj_index0, 1,
2537 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2538
Neale Rannse2fe0972020-11-26 08:37:27 +00002539 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002540 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002541
2542 if (is_mcast)
2543 /* copy bytes from the IP address into the MAC rewrite */
2544 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2545 adj0->rewrite_header.dst_mcast_offset,
2546 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002547 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002548 else
2549 {
2550 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002551 /* undo the TTL decrement - we'll be back to do it again */
2552 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2553 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002554 }
2555
2556 next += 1;
2557 b += 1;
2558 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002559 }
2560
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002561
Ed Warnickecb9cada2015-12-08 15:45:58 -07002562 /* Need to do trace after rewrites to pick up new packet data. */
2563 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002564 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002565
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002566 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002567 return frame->n_vectors;
2568}
2569
Neale Rannsf06aea52016-11-29 06:51:37 -08002570/** @brief IPv4 rewrite node.
2571 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002572
2573 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2574 header checksum, fetch the ip adjacency, check the outbound mtu,
2575 apply the adjacency rewrite, and send pkts to the adjacency
2576 rewrite header's rewrite_next_index.
2577
2578 @param vm vlib_main_t corresponding to the current thread
2579 @param node vlib_node_runtime_t
2580 @param frame vlib_frame_t whose contents should be dispatched
2581
2582 @par Graph mechanics: buffer metadata, next index usage
2583
2584 @em Uses:
2585 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2586 - the rewrite adjacency index
2587 - <code>adj->lookup_next_index</code>
2588 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002589 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002590 - <code>adj->rewrite_header</code>
2591 - Rewrite string length, rewrite string, next_index
2592
2593 @em Sets:
2594 - <code>b->current_data, b->current_length</code>
2595 - Updated net of applying the rewrite string
2596
2597 <em>Next Indices:</em>
2598 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002599 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002600*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002601
2602VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2603 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002604{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002605 if (adj_are_counters_enabled ())
2606 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2607 else
2608 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002609}
2610
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002611VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2612 vlib_node_runtime_t * node,
2613 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002614{
2615 if (adj_are_counters_enabled ())
2616 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2617 else
2618 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2619}
2620
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002621VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2622 vlib_node_runtime_t * node,
2623 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002624{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002625 if (adj_are_counters_enabled ())
2626 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2627 else
2628 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002629}
2630
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002631VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2632 vlib_node_runtime_t * node,
2633 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002634{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002635 if (adj_are_counters_enabled ())
2636 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2637 else
2638 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002639}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002640
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002641VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2642 vlib_node_runtime_t * node,
2643 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002644{
2645 if (adj_are_counters_enabled ())
2646 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2647 else
2648 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2649}
2650
Neale Ranns32e1c012016-11-22 17:07:28 +00002651/* *INDENT-OFF* */
2652VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002653 .name = "ip4-rewrite",
2654 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655
Neale Ranns32e1c012016-11-22 17:07:28 +00002656 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002657
Ole Troan313f7e22018-04-10 16:02:51 +02002658 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002659 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002660 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002661 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002662 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002663 },
2664};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002665
2666VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002667 .name = "ip4-rewrite-bcast",
2668 .vector_size = sizeof (u32),
2669
2670 .format_trace = format_ip4_rewrite_trace,
2671 .sibling_of = "ip4-rewrite",
2672};
Neale Ranns32e1c012016-11-22 17:07:28 +00002673
2674VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002675 .name = "ip4-rewrite-mcast",
2676 .vector_size = sizeof (u32),
2677
2678 .format_trace = format_ip4_rewrite_trace,
2679 .sibling_of = "ip4-rewrite",
2680};
Neale Ranns32e1c012016-11-22 17:07:28 +00002681
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002682VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002683 .name = "ip4-mcast-midchain",
2684 .vector_size = sizeof (u32),
2685
2686 .format_trace = format_ip4_rewrite_trace,
2687 .sibling_of = "ip4-rewrite",
2688};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002689
Neale Ranns32e1c012016-11-22 17:07:28 +00002690VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002691 .name = "ip4-midchain",
2692 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002693 .format_trace = format_ip4_rewrite_trace,
2694 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002695};
Neale Ranns32e1c012016-11-22 17:07:28 +00002696/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002697
Ed Warnickecb9cada2015-12-08 15:45:58 -07002698static clib_error_t *
2699set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002700 unformat_input_t * input,
2701 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002702{
2703 int matched = 0;
2704 u32 table_id = 0;
2705 u32 flow_hash_config = 0;
2706 int rv;
2707
Dave Barachd7cb1b52016-12-09 09:52:16 -05002708 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2709 {
2710 if (unformat (input, "table %d", &table_id))
2711 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002712#define _(a, b, v) \
2713 else if (unformat (input, #a)) \
2714 { \
2715 flow_hash_config |= v; \
2716 matched = 1; \
2717 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002718 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002719#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002720 else
2721 break;
2722 }
Dave Barach75fc8542016-10-11 16:16:02 -04002723
Ed Warnickecb9cada2015-12-08 15:45:58 -07002724 if (matched == 0)
2725 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002726 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002727
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002728 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002729 switch (rv)
2730 {
2731 case 0:
2732 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002733
Ed Warnickecb9cada2015-12-08 15:45:58 -07002734 case VNET_API_ERROR_NO_SUCH_FIB:
2735 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002736
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737 default:
2738 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2739 break;
2740 }
Dave Barach75fc8542016-10-11 16:16:02 -04002741
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742 return 0;
2743}
Dave Barach75fc8542016-10-11 16:16:02 -04002744
Billy McFall0683c9c2016-10-13 08:27:31 -04002745/*?
2746 * Configure the set of IPv4 fields used by the flow hash.
2747 *
2748 * @cliexpar
2749 * Example of how to set the flow hash on a given table:
2750 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2751 * Example of display the configured flow hash:
2752 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002753 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2754 * 0.0.0.0/0
2755 * unicast-ip4-chain
2756 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2757 * [0] [@0]: dpo-drop ip6
2758 * 0.0.0.0/32
2759 * unicast-ip4-chain
2760 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2761 * [0] [@0]: dpo-drop ip6
2762 * 224.0.0.0/8
2763 * unicast-ip4-chain
2764 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2765 * [0] [@0]: dpo-drop ip6
2766 * 6.0.1.2/32
2767 * unicast-ip4-chain
2768 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2769 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2770 * 7.0.0.1/32
2771 * unicast-ip4-chain
2772 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2773 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2774 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2775 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2776 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2777 * 240.0.0.0/8
2778 * unicast-ip4-chain
2779 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2780 * [0] [@0]: dpo-drop ip6
2781 * 255.255.255.255/32
2782 * unicast-ip4-chain
2783 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2784 * [0] [@0]: dpo-drop ip6
2785 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2786 * 0.0.0.0/0
2787 * unicast-ip4-chain
2788 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2789 * [0] [@0]: dpo-drop ip6
2790 * 0.0.0.0/32
2791 * unicast-ip4-chain
2792 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2793 * [0] [@0]: dpo-drop ip6
2794 * 172.16.1.0/24
2795 * unicast-ip4-chain
2796 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2797 * [0] [@4]: ipv4-glean: af_packet0
2798 * 172.16.1.1/32
2799 * unicast-ip4-chain
2800 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2801 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2802 * 172.16.1.2/32
2803 * unicast-ip4-chain
2804 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2805 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2806 * 172.16.2.0/24
2807 * unicast-ip4-chain
2808 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2809 * [0] [@4]: ipv4-glean: af_packet1
2810 * 172.16.2.1/32
2811 * unicast-ip4-chain
2812 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2813 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2814 * 224.0.0.0/8
2815 * unicast-ip4-chain
2816 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2817 * [0] [@0]: dpo-drop ip6
2818 * 240.0.0.0/8
2819 * unicast-ip4-chain
2820 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2821 * [0] [@0]: dpo-drop ip6
2822 * 255.255.255.255/32
2823 * unicast-ip4-chain
2824 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2825 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002826 * @cliexend
2827?*/
2828/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002829VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2830{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002831 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002832 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002833 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002834 .function = set_ip_flow_hash_command_fn,
2835};
Billy McFall0683c9c2016-10-13 08:27:31 -04002836/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002837
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002838#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002839int
2840vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2841 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002843 vnet_main_t *vnm = vnet_get_main ();
2844 vnet_interface_main_t *im = &vnm->interface_main;
2845 ip4_main_t *ipm = &ip4_main;
2846 ip_lookup_main_t *lm = &ipm->lookup_main;
2847 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002848 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002849
2850 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2851 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2852
2853 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2854 return VNET_API_ERROR_NO_SUCH_ENTRY;
2855
2856 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002857 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002858
Neale Rannsdf089a82016-10-02 16:39:06 +01002859 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2860
2861 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002862 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002863 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002864 .fp_len = 32,
2865 .fp_proto = FIB_PROTOCOL_IP4,
2866 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002867 };
2868 u32 fib_index;
2869
Dave Barachd7cb1b52016-12-09 09:52:16 -05002870 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2871 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002872
2873
Dave Barachd7cb1b52016-12-09 09:52:16 -05002874 if (table_index != (u32) ~ 0)
2875 {
2876 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002877
Dave Barachd7cb1b52016-12-09 09:52:16 -05002878 dpo_set (&dpo,
2879 DPO_CLASSIFY,
2880 DPO_PROTO_IP4,
2881 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002882
Dave Barachd7cb1b52016-12-09 09:52:16 -05002883 fib_table_entry_special_dpo_add (fib_index,
2884 &pfx,
2885 FIB_SOURCE_CLASSIFY,
2886 FIB_ENTRY_FLAG_NONE, &dpo);
2887 dpo_reset (&dpo);
2888 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002889 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002890 {
2891 fib_table_entry_special_remove (fib_index,
2892 &pfx, FIB_SOURCE_CLASSIFY);
2893 }
2894 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002895
Ed Warnickecb9cada2015-12-08 15:45:58 -07002896 return 0;
2897}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002898#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002899
2900static clib_error_t *
2901set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002902 unformat_input_t * input,
2903 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002904{
2905 u32 table_index = ~0;
2906 int table_index_set = 0;
2907 u32 sw_if_index = ~0;
2908 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002909
Dave Barachd7cb1b52016-12-09 09:52:16 -05002910 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2911 {
2912 if (unformat (input, "table-index %d", &table_index))
2913 table_index_set = 1;
2914 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2915 vnet_get_main (), &sw_if_index))
2916 ;
2917 else
2918 break;
2919 }
Dave Barach75fc8542016-10-11 16:16:02 -04002920
Ed Warnickecb9cada2015-12-08 15:45:58 -07002921 if (table_index_set == 0)
2922 return clib_error_return (0, "classify table-index must be specified");
2923
2924 if (sw_if_index == ~0)
2925 return clib_error_return (0, "interface / subif must be specified");
2926
2927 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2928
2929 switch (rv)
2930 {
2931 case 0:
2932 break;
2933
2934 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2935 return clib_error_return (0, "No such interface");
2936
2937 case VNET_API_ERROR_NO_SUCH_ENTRY:
2938 return clib_error_return (0, "No such classifier table");
2939 }
2940 return 0;
2941}
2942
Billy McFall0683c9c2016-10-13 08:27:31 -04002943/*?
2944 * Assign a classification table to an interface. The classification
2945 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2946 * commands. Once the table is create, use this command to filter packets
2947 * on an interface.
2948 *
2949 * @cliexpar
2950 * Example of how to assign a classification table to an interface:
2951 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2952?*/
2953/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002954VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2955{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002956 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002957 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002958 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002959 .function = set_ip_classify_command_fn,
2960};
Billy McFall0683c9c2016-10-13 08:27:31 -04002961/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002962
2963/*
2964 * fd.io coding-style-patch-verification: ON
2965 *
2966 * Local Variables:
2967 * eval: (c-set-style "gnu")
2968 * End:
2969 */