blob: 36f05a27820eb65a54cd06bcd6c88290129b9af2 [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>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010055#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000056#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Neale Ranns4ec36c52020-03-31 09:21:29 -040057#include <vnet/adj/adj_dp.h>
Neale Ranns68d48d92021-06-03 14:59:47 +000058#include <vnet/pg/pg.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080060#include <vnet/ip/ip4_forward.h>
Neale Ranns25edf142019-03-22 08:12:48 +000061#include <vnet/interface_output.h>
Neale Rannsba4a5bf2020-01-09 06:43:14 +000062#include <vnet/classify/vnet_classify.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070063
Chris Luke8e5b0412016-07-26 13:06:10 -040064/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040065 @node ip4-lookup
66
67 This is the main IPv4 lookup dispatch node.
68
69 @param vm vlib_main_t corresponding to the current thread
70 @param node vlib_node_runtime_t
71 @param frame vlib_frame_t whose contents should be dispatched
72
73 @par Graph mechanics: buffer metadata, next index usage
74
75 @em Uses:
76 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
77 - Indicates the @c sw_if_index value of the interface that the
78 packet was received on.
79 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
80 - When the value is @c ~0 then the node performs a longest prefix
81 match (LPM) for the packet destination address in the FIB attached
82 to the receive interface.
83 - Otherwise perform LPM for the packet destination address in the
84 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
85 value (0, 1, ...) and not a VRF id.
86
87 @em Sets:
88 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
89 - The lookup result adjacency index.
90
91 <em>Next Index:</em>
92 - Dispatches the packet to the node index found in
93 ip_adjacency_t @c adj->lookup_next_index
94 (where @c adj is the lookup result adjacency).
95*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020096VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
97 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070098{
Neale Rannscb54e3c2019-06-19 07:14:10 +000099 return ip4_lookup_inline (vm, node, frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100}
101
Dave Barachd7cb1b52016-12-09 09:52:16 -0500102static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100103
Neale Rannsf8686322017-11-29 02:39:53 -0800104/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500105VLIB_REGISTER_NODE (ip4_lookup_node) =
106{
Neale Rannsf8686322017-11-29 02:39:53 -0800107 .name = "ip4-lookup",
108 .vector_size = sizeof (u32),
109 .format_trace = format_ip4_lookup_trace,
110 .n_next_nodes = IP_LOOKUP_N_NEXT,
111 .next_nodes = IP4_LOOKUP_NEXT_NODES,
112};
113/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100114
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200115VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
116 vlib_node_runtime_t * node,
117 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500119 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400120 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200121 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800122 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400123 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100125 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400126 n_left = frame->n_vectors;
127 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100128
Neale Ranns3ce72b22019-05-27 08:21:32 -0400129 vlib_get_buffers (vm, from, bufs, n_left);
130
131 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400133 const load_balance_t *lb0, *lb1;
134 const ip4_header_t *ip0, *ip1;
135 u32 lbi0, hc0, lbi1, hc1;
136 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100137
Neale Ranns3ce72b22019-05-27 08:21:32 -0400138 /* Prefetch next iteration. */
139 {
140 vlib_prefetch_buffer_header (b[2], LOAD);
141 vlib_prefetch_buffer_header (b[3], LOAD);
142
143 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
144 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
145 }
146
147 ip0 = vlib_buffer_get_current (b[0]);
148 ip1 = vlib_buffer_get_current (b[1]);
149 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
150 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
151
152 lb0 = load_balance_get (lbi0);
153 lb1 = load_balance_get (lbi1);
154
155 /*
156 * this node is for via FIBs we can re-use the hash value from the
157 * to node if present.
158 * We don't want to use the same hash value at each level in the recursion
159 * graph as that would lead to polarisation
160 */
161 hc0 = hc1 = 0;
162
163 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500164 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400165 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500166 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400167 hc0 = vnet_buffer (b[0])->ip.flow_hash =
168 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700169 }
170 else
171 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400172 hc0 = vnet_buffer (b[0])->ip.flow_hash =
173 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500174 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400175 dpo0 = load_balance_get_fwd_bucket
176 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
177 }
178 else
179 {
180 dpo0 = load_balance_get_bucket_i (lb0, 0);
181 }
182 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
183 {
184 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500185 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400186 hc1 = vnet_buffer (b[1])->ip.flow_hash =
187 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500188 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700189 else
190 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400191 hc1 = vnet_buffer (b[1])->ip.flow_hash =
192 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700193 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400194 dpo1 = load_balance_get_fwd_bucket
195 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
196 }
197 else
198 {
199 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500200 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000201
Neale Ranns3ce72b22019-05-27 08:21:32 -0400202 next[0] = dpo0->dpoi_next_node;
203 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100204
Neale Ranns3ce72b22019-05-27 08:21:32 -0400205 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
206 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100207
Neale Ranns3ce72b22019-05-27 08:21:32 -0400208 vlib_increment_combined_counter
209 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
210 vlib_increment_combined_counter
211 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100212
Neale Ranns3ce72b22019-05-27 08:21:32 -0400213 b += 2;
214 next += 2;
215 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 }
217
Neale Ranns3ce72b22019-05-27 08:21:32 -0400218 while (n_left > 0)
219 {
220 const load_balance_t *lb0;
221 const ip4_header_t *ip0;
222 const dpo_id_t *dpo0;
223 u32 lbi0, hc0;
224
225 ip0 = vlib_buffer_get_current (b[0]);
226 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
227
228 lb0 = load_balance_get (lbi0);
229
230 hc0 = 0;
231 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
232 {
233 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
234 {
235 hc0 = vnet_buffer (b[0])->ip.flow_hash =
236 vnet_buffer (b[0])->ip.flow_hash >> 1;
237 }
238 else
239 {
240 hc0 = vnet_buffer (b[0])->ip.flow_hash =
241 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
242 }
243 dpo0 = load_balance_get_fwd_bucket
244 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
245 }
246 else
247 {
248 dpo0 = load_balance_get_bucket_i (lb0, 0);
249 }
250
251 next[0] = dpo0->dpoi_next_node;
252 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
253
254 vlib_increment_combined_counter
255 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
256
257 b += 1;
258 next += 1;
259 n_left -= 1;
260 }
261
262 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800263 if (node->flags & VLIB_NODE_FLAG_TRACE)
264 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
265
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100266 return frame->n_vectors;
267}
268
Neale Rannsf8686322017-11-29 02:39:53 -0800269/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500270VLIB_REGISTER_NODE (ip4_load_balance_node) =
271{
Neale Rannsf8686322017-11-29 02:39:53 -0800272 .name = "ip4-load-balance",
273 .vector_size = sizeof (u32),
274 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200275 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800276};
277/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100278
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200279#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280/* get first interface address */
281ip4_address_t *
282ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500283 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100284{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500285 ip_lookup_main_t *lm = &im->lookup_main;
286 ip_interface_address_t *ia = 0;
287 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100288
Neale Ranns32e1c012016-11-22 17:07:28 +0000289 /* *INDENT-OFF* */
290 foreach_ip_interface_address
291 (lm, ia, sw_if_index,
292 1 /* honor unnumbered */ ,
293 ({
294 ip4_address_t * a =
295 ip_interface_address_get_address (lm, ia);
296 result = a;
297 break;
298 }));
299 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100300 if (result_ia)
301 *result_ia = result ? ia : 0;
302 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500304#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305
306static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700307ip4_add_subnet_bcast_route (u32 fib_index,
308 fib_prefix_t *pfx,
309 u32 sw_if_index)
310{
311 vnet_sw_interface_flags_t iflags;
312
313 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
314
315 fib_table_entry_special_remove(fib_index,
316 pfx,
317 FIB_SOURCE_INTERFACE);
318
319 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
320 {
321 fib_table_entry_update_one_path (fib_index, pfx,
322 FIB_SOURCE_INTERFACE,
323 FIB_ENTRY_FLAG_NONE,
324 DPO_PROTO_IP4,
325 /* No next-hop address */
326 &ADJ_BCAST_ADDR,
327 sw_if_index,
328 // invalid FIB index
329 ~0,
330 1,
331 // no out-label stack
332 NULL,
333 FIB_ROUTE_PATH_FLAG_NONE);
334 }
335 else
336 {
337 fib_table_entry_special_add(fib_index,
338 pfx,
339 FIB_SOURCE_INTERFACE,
340 (FIB_ENTRY_FLAG_DROP |
341 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
342 }
343}
344
345static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500346ip4_add_interface_prefix_routes (ip4_main_t *im,
347 u32 sw_if_index,
348 u32 fib_index,
349 ip_interface_address_t * a)
350{
351 ip_lookup_main_t *lm = &im->lookup_main;
352 ip_interface_prefix_t *if_prefix;
353 ip4_address_t *address = ip_interface_address_get_address (lm, a);
354
355 ip_interface_prefix_key_t key = {
356 .prefix = {
357 .fp_len = a->address_length,
358 .fp_proto = FIB_PROTOCOL_IP4,
359 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
360 },
361 .sw_if_index = sw_if_index,
362 };
363
364 fib_prefix_t pfx_special = {
365 .fp_proto = FIB_PROTOCOL_IP4,
366 };
367
368 /* If prefix already set on interface, just increment ref count & return */
369 if_prefix = ip_get_interface_prefix (lm, &key);
370 if (if_prefix)
371 {
372 if_prefix->ref_count += 1;
373 return;
374 }
375
376 /* New prefix - allocate a pool entry, initialize it, add to the hash */
377 pool_get (lm->if_prefix_pool, if_prefix);
378 if_prefix->ref_count = 1;
379 if_prefix->src_ia_index = a - lm->if_address_pool;
380 clib_memcpy (&if_prefix->key, &key, sizeof (key));
381 mhash_set (&lm->prefix_to_if_prefix_index, &key,
382 if_prefix - lm->if_prefix_pool, 0 /* old value */);
383
Neale Rannse2fe0972020-11-26 08:37:27 +0000384 pfx_special.fp_len = a->address_length;
385 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
386
387 /* set the glean route for the prefix */
388 fib_table_entry_update_one_path (fib_index, &pfx_special,
389 FIB_SOURCE_INTERFACE,
390 (FIB_ENTRY_FLAG_CONNECTED |
391 FIB_ENTRY_FLAG_ATTACHED),
392 DPO_PROTO_IP4,
393 /* No next-hop address */
394 NULL,
395 sw_if_index,
396 /* invalid FIB index */
397 ~0,
398 1,
399 /* no out-label stack */
400 NULL,
401 FIB_ROUTE_PATH_FLAG_NONE);
402
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500403 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
404 if (a->address_length <= 30)
405 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500406 /* set a drop route for the base address of the prefix */
407 pfx_special.fp_len = 32;
408 pfx_special.fp_addr.ip4.as_u32 =
409 address->as_u32 & im->fib_masks[a->address_length];
410
411 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
412 fib_table_entry_special_add (fib_index, &pfx_special,
413 FIB_SOURCE_INTERFACE,
414 (FIB_ENTRY_FLAG_DROP |
415 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
416
417 /* set a route for the broadcast address of the prefix */
418 pfx_special.fp_len = 32;
419 pfx_special.fp_addr.ip4.as_u32 =
420 address->as_u32 | ~im->fib_masks[a->address_length];
421 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
422 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
423
424
425 }
426 /* length == 31 - add an attached route for the other address */
427 else if (a->address_length == 31)
428 {
429 pfx_special.fp_len = 32;
430 pfx_special.fp_addr.ip4.as_u32 =
431 address->as_u32 ^ clib_host_to_net_u32(1);
432
433 fib_table_entry_update_one_path (fib_index, &pfx_special,
434 FIB_SOURCE_INTERFACE,
435 (FIB_ENTRY_FLAG_ATTACHED),
436 DPO_PROTO_IP4,
437 &pfx_special.fp_addr,
438 sw_if_index,
439 /* invalid FIB index */
440 ~0,
441 1,
442 NULL,
443 FIB_ROUTE_PATH_FLAG_NONE);
444 }
445}
446
447static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448ip4_add_interface_routes (u32 sw_if_index,
449 ip4_main_t * im, u32 fib_index,
450 ip_interface_address_t * a)
451{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 ip_lookup_main_t *lm = &im->lookup_main;
453 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500455 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500456 .fp_proto = FIB_PROTOCOL_IP4,
457 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100458 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500460 /* set special routes for the prefix if needed */
461 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100462
463 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500464 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100465 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500466 lm->classify_table_index_by_sw_if_index[sw_if_index];
467 if (classify_table_index != (u32) ~ 0)
468 {
469 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100470
Dave Barachd7cb1b52016-12-09 09:52:16 -0500471 dpo_set (&dpo,
472 DPO_CLASSIFY,
473 DPO_PROTO_IP4,
474 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100475
Dave Barachd7cb1b52016-12-09 09:52:16 -0500476 fib_table_entry_special_dpo_add (fib_index,
477 &pfx,
478 FIB_SOURCE_CLASSIFY,
479 FIB_ENTRY_FLAG_NONE, &dpo);
480 dpo_reset (&dpo);
481 }
482 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100483
Neale Ranns32e1c012016-11-22 17:07:28 +0000484 fib_table_entry_update_one_path (fib_index, &pfx,
485 FIB_SOURCE_INTERFACE,
486 (FIB_ENTRY_FLAG_CONNECTED |
487 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700488 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000489 &pfx.fp_addr,
490 sw_if_index,
491 // invalid FIB index
492 ~0,
493 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500494 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495}
496
497static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500498ip4_del_interface_prefix_routes (ip4_main_t * im,
499 u32 sw_if_index,
500 u32 fib_index,
501 ip4_address_t * address,
502 u32 address_length)
503{
504 ip_lookup_main_t *lm = &im->lookup_main;
505 ip_interface_prefix_t *if_prefix;
506
507 ip_interface_prefix_key_t key = {
508 .prefix = {
509 .fp_len = address_length,
510 .fp_proto = FIB_PROTOCOL_IP4,
511 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
512 },
513 .sw_if_index = sw_if_index,
514 };
515
516 fib_prefix_t pfx_special = {
517 .fp_len = 32,
518 .fp_proto = FIB_PROTOCOL_IP4,
519 };
520
521 if_prefix = ip_get_interface_prefix (lm, &key);
522 if (!if_prefix)
523 {
524 clib_warning ("Prefix not found while deleting %U",
525 format_ip4_address_and_length, address, address_length);
526 return;
527 }
528
529 if_prefix->ref_count -= 1;
530
531 /*
Neale Rannse2fe0972020-11-26 08:37:27 +0000532 * Routes need to be adjusted if deleting last intf addr in prefix
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500533 *
534 * We're done now otherwise
535 */
Neale Rannse2fe0972020-11-26 08:37:27 +0000536 if (if_prefix->ref_count > 0)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500537 return;
538
539 /* length <= 30, delete glean route, first address, last address */
540 if (address_length <= 30)
541 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000542 /* Less work to do in FIB if we remove the covered /32s first */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500543
Neale Rannse2fe0972020-11-26 08:37:27 +0000544 /* first address in prefix */
545 pfx_special.fp_addr.ip4.as_u32 =
546 address->as_u32 & im->fib_masks[address_length];
547 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500548
Neale Rannse2fe0972020-11-26 08:37:27 +0000549 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
550 fib_table_entry_special_remove (fib_index,
551 &pfx_special,
552 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500553
Neale Rannse2fe0972020-11-26 08:37:27 +0000554 /* prefix broadcast address */
555 pfx_special.fp_addr.ip4.as_u32 =
556 address->as_u32 | ~im->fib_masks[address_length];
557 pfx_special.fp_len = 32;
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500558
Neale Rannse2fe0972020-11-26 08:37:27 +0000559 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
560 fib_table_entry_special_remove (fib_index,
561 &pfx_special,
562 FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500563 }
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500564 else if (address_length == 31)
565 {
Neale Rannse2fe0972020-11-26 08:37:27 +0000566 /* length == 31, delete attached route for the other address */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500567 pfx_special.fp_addr.ip4.as_u32 =
568 address->as_u32 ^ clib_host_to_net_u32(1);
569
570 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
571 }
572
Neale Rannse2fe0972020-11-26 08:37:27 +0000573 /* remove glean route for prefix */
574 pfx_special.fp_addr.ip4 = *address;
575 pfx_special.fp_len = address_length;
576 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
577
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500578 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
579 pool_put (lm->if_prefix_pool, if_prefix);
580}
581
582static void
583ip4_del_interface_routes (u32 sw_if_index,
584 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100585 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500586 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700587{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 fib_prefix_t pfx = {
Neale Rannse2fe0972020-11-26 08:37:27 +0000589 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500590 .fp_proto = FIB_PROTOCOL_IP4,
591 .fp_addr.ip4 = *address,
592 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700593
Neale Rannse2fe0972020-11-26 08:37:27 +0000594 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
595
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500596 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
597 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700598}
599
Matthew G Smith88d29a92019-07-17 10:01:17 -0500600#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100601void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500602ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100603{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500604 ip4_main_t *im = &ip4_main;
John Lo4a302ee2020-05-12 22:34:39 -0400605 vnet_main_t *vnm = vnet_get_main ();
606 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700607
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100608 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
609
610 /*
611 * enable/disable only on the 1<->0 transition
612 */
613 if (is_enable)
614 {
615 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500616 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100617 }
618 else
619 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500620 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100621 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500622 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100623 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800624 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800625 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100626
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100627
Neale Ranns8269d3d2018-01-30 09:02:20 -0800628 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400629 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000630
John Lo4a302ee2020-05-12 22:34:39 -0400631 if (is_enable)
632 hi->l3_if_count++;
633 else if (hi->l3_if_count)
634 hi->l3_if_count--;
635
Neale Ranns57e53bb2019-05-29 13:58:43 +0000636 {
637 ip4_enable_disable_interface_callback_t *cb;
638 vec_foreach (cb, im->enable_disable_interface_callbacks)
639 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
640 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643static clib_error_t *
644ip4_add_del_interface_address_internal (vlib_main_t * vm,
645 u32 sw_if_index,
646 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500647 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500649 vnet_main_t *vnm = vnet_get_main ();
650 ip4_main_t *im = &ip4_main;
651 ip_lookup_main_t *lm = &im->lookup_main;
652 clib_error_t *error = 0;
Neale Ranns59f71132020-04-08 12:19:38 +0000653 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500654 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655
Pavel Kotucek57808982017-08-02 08:20:19 +0200656 /* local0 interface doesn't support IP addressing */
657 if (sw_if_index == 0)
658 {
659 return
660 clib_error_create ("local0 interface doesn't support IP addressing");
661 }
662
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
664 ip4_addr_fib_init (&ip4_af, address,
665 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
666 vec_add1 (addr_fib, ip4_af);
667
Neale Ranns744902e2017-08-14 10:35:44 -0700668 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100669 * there is no support for adj-fib handling in the presence of overlapping
670 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
671 * most routers do.
672 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000673 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500674 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700675 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100676 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700677 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500678 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700679 vnet_sw_interface_t *sif;
680
Damjan Marionb2c31b62020-12-13 21:47:40 +0100681 pool_foreach (sif, vnm->interface_main.sw_interfaces)
682 {
Neale Ranns744902e2017-08-14 10:35:44 -0700683 if (im->fib_index_by_sw_if_index[sw_if_index] ==
684 im->fib_index_by_sw_if_index[sif->sw_if_index])
685 {
686 foreach_ip_interface_address
687 (&im->lookup_main, ia, sif->sw_if_index,
688 0 /* honor unnumbered */ ,
689 ({
690 ip4_address_t * x =
691 ip_interface_address_get_address
692 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000693
Neale Ranns744902e2017-08-14 10:35:44 -0700694 if (ip4_destination_matches_route
695 (im, address, x, ia->address_length) ||
696 ip4_destination_matches_route (im,
697 x,
698 address,
699 address_length))
700 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500701 /* an intf may have >1 addr from the same prefix */
702 if ((sw_if_index == sif->sw_if_index) &&
703 (ia->address_length == address_length) &&
704 (x->as_u32 != address->as_u32))
705 continue;
706
Neale Ranns59f71132020-04-08 12:19:38 +0000707 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
708 /* if the address we're comparing against is stale
709 * then the CP has not added this one back yet, maybe
710 * it never will, so we have to assume it won't and
711 * ignore it. if it does add it back, then it will fail
712 * because this one is now present */
713 continue;
Neale Ranns744902e2017-08-14 10:35:44 -0700714
Neale Ranns59f71132020-04-08 12:19:38 +0000715 /* error if the length or intf was different */
716 vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
717
718 error = clib_error_create
Ole Troan33a58172019-09-04 09:12:29 +0200719 ("failed to add %U on %U which conflicts with %U for interface %U",
Neale Ranns744902e2017-08-14 10:35:44 -0700720 format_ip4_address_and_length, address,
721 address_length,
Ole Troan33a58172019-09-04 09:12:29 +0200722 format_vnet_sw_if_index_name, vnm,
723 sw_if_index,
Neale Ranns744902e2017-08-14 10:35:44 -0700724 format_ip4_address_and_length, x,
725 ia->address_length,
726 format_vnet_sw_if_index_name, vnm,
727 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000728 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700729 }
730 }));
731 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100732 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000734 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735
Neale Ranns59f71132020-04-08 12:19:38 +0000736 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737
Neale Ranns59f71132020-04-08 12:19:38 +0000738 if (is_del)
739 {
740 if (~0 == if_address_index)
741 {
742 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
743 error = clib_error_create ("%U not found for interface %U",
744 lm->format_address_and_length,
745 addr_fib, address_length,
746 format_vnet_sw_if_index_name, vnm,
747 sw_if_index);
748 goto done;
749 }
750
yedgdbd366b2020-05-14 10:51:53 +0800751 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
752 address_length, sw_if_index);
753 if (error)
754 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000755 }
756 else
757 {
758 if (~0 != if_address_index)
759 {
760 ip_interface_address_t *ia;
761
762 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
763
764 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
765 {
766 if (ia->sw_if_index == sw_if_index)
767 {
768 /* re-adding an address during the replace action.
769 * consdier this the update. clear the flag and
770 * we're done */
771 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
772 goto done;
773 }
774 else
775 {
776 /* The prefix is moving from one interface to another.
777 * delete the stale and add the new */
778 ip4_add_del_interface_address_internal (vm,
779 ia->sw_if_index,
780 address,
781 address_length, 1);
782 ia = NULL;
783 error = ip_interface_address_add (lm, sw_if_index,
784 addr_fib, address_length,
785 &if_address_index);
786 }
787 }
788 else
789 {
790 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
791 error = clib_error_create
792 ("Prefix %U already found on interface %U",
793 lm->format_address_and_length, addr_fib, address_length,
794 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
795 }
796 }
797 else
798 error = ip_interface_address_add (lm, sw_if_index,
799 addr_fib, address_length,
800 &if_address_index);
801 }
802
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 if (error)
804 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400805
Dave Barachd7cb1b52016-12-09 09:52:16 -0500806 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns03c254e2020-03-17 14:25:10 +0000807 ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100808
Matthew G Smith88d29a92019-07-17 10:01:17 -0500809 /* intf addr routes are added/deleted on admin up/down */
810 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
811 {
812 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500813 ip4_del_interface_routes (sw_if_index,
814 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500815 address_length);
816 else
817 ip4_add_interface_routes (sw_if_index,
818 im, ip4_af.fib_index,
819 pool_elt_at_index
820 (lm->if_address_pool, if_address_index));
821 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822
Neale Ranns59f71132020-04-08 12:19:38 +0000823 ip4_add_del_interface_address_callback_t *cb;
824 vec_foreach (cb, im->add_del_interface_address_callbacks)
825 cb->function (im, cb->function_opaque, sw_if_index,
826 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827
Dave Barachd7cb1b52016-12-09 09:52:16 -0500828done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700829 vec_free (addr_fib);
830 return error;
831}
832
833clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000834ip4_add_del_interface_address (vlib_main_t * vm,
835 u32 sw_if_index,
836 ip4_address_t * address,
837 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838{
839 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500840 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700841}
842
Neale Ranns1855b8e2018-07-11 10:31:26 -0700843void
844ip4_directed_broadcast (u32 sw_if_index, u8 enable)
845{
846 ip_interface_address_t *ia;
847 ip4_main_t *im;
848
849 im = &ip4_main;
850
851 /*
852 * when directed broadcast is enabled, the subnet braodcast route will forward
853 * packets using an adjacency with a broadcast MAC. otherwise it drops
854 */
855 /* *INDENT-OFF* */
856 foreach_ip_interface_address(&im->lookup_main, ia,
857 sw_if_index, 0,
858 ({
859 if (ia->address_length <= 30)
860 {
861 ip4_address_t *ipa;
862
863 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
864
865 fib_prefix_t pfx = {
866 .fp_len = 32,
867 .fp_proto = FIB_PROTOCOL_IP4,
868 .fp_addr = {
869 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
870 },
871 };
872
873 ip4_add_subnet_bcast_route
874 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
875 sw_if_index),
876 &pfx, sw_if_index);
877 }
878 }));
879 /* *INDENT-ON* */
880}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200881#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700882
Matthew G Smith88d29a92019-07-17 10:01:17 -0500883static clib_error_t *
884ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
885{
886 ip4_main_t *im = &ip4_main;
887 ip_interface_address_t *ia;
888 ip4_address_t *a;
889 u32 is_admin_up, fib_index;
890
891 /* Fill in lookup tables with default table (0). */
892 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
893
894 vec_validate_init_empty (im->
895 lookup_main.if_address_pool_index_by_sw_if_index,
896 sw_if_index, ~0);
897
898 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
899
900 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
901
902 /* *INDENT-OFF* */
903 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
904 0 /* honor unnumbered */,
905 ({
906 a = ip_interface_address_get_address (&im->lookup_main, ia);
907 if (is_admin_up)
908 ip4_add_interface_routes (sw_if_index,
909 im, fib_index,
910 ia);
911 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500912 ip4_del_interface_routes (sw_if_index,
913 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500914 a, ia->address_length);
915 }));
916 /* *INDENT-ON* */
917
918 return 0;
919}
920
921VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
922
Dave Barachd6534602016-06-14 18:38:02 -0400923/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500924/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100925VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
926{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500927 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100928 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500929 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100930 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
931};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100932
Dave Barachd7cb1b52016-12-09 09:52:16 -0500933VNET_FEATURE_INIT (ip4_flow_classify, static) =
934{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100935 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700936 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100937 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700938};
939
Dave Barachd7cb1b52016-12-09 09:52:16 -0500940VNET_FEATURE_INIT (ip4_inacl, static) =
941{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100942 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400943 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100944 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400945};
946
Dave Barachd7cb1b52016-12-09 09:52:16 -0500947VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
948{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100949 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400950 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100951 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400952};
953
Dave Barachd7cb1b52016-12-09 09:52:16 -0500954VNET_FEATURE_INIT (ip4_policer_classify, static) =
955{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100956 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700957 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100958 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700959};
960
Dave Barachd7cb1b52016-12-09 09:52:16 -0500961VNET_FEATURE_INIT (ip4_ipsec, static) =
962{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100963 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100964 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100965 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400966};
967
Dave Barachd7cb1b52016-12-09 09:52:16 -0500968VNET_FEATURE_INIT (ip4_vpath, static) =
969{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100970 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400971 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500972 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
973};
974
Dave Barachd7cb1b52016-12-09 09:52:16 -0500975VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
976{
John Lo37682e12016-11-30 12:51:39 -0500977 .arc_name = "ip4-unicast",
978 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100979 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400980};
981
Neale Ranns8269d3d2018-01-30 09:02:20 -0800982VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500983{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100984 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800985 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400986 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100987};
988
Neale Ranns180279b2017-03-16 15:49:09 -0400989VNET_FEATURE_INIT (ip4_lookup, static) =
990{
991 .arc_name = "ip4-unicast",
992 .node_name = "ip4-lookup",
993 .runs_before = 0, /* not before any other features */
994};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100995
Dave Barachd6534602016-06-14 18:38:02 -0400996/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100997VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
998{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500999 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001000 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -05001001 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001002 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1003};
1004
Dave Barachd7cb1b52016-12-09 09:52:16 -05001005VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1006{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001007 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -04001008 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +00001009 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -04001010};
1011
Neale Ranns8269d3d2018-01-30 09:02:20 -08001012VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001013{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001014 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -08001015 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -04001016 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1017};
1018
1019VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1020{
1021 .arc_name = "ip4-multicast",
1022 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001023 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +01001024};
Dave Barach5331c722016-08-17 11:54:30 -04001025
1026/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001027VNET_FEATURE_ARC_INIT (ip4_output, static) =
1028{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001029 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001030 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001031 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001032 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1033};
Dave Barach5331c722016-08-17 11:54:30 -04001034
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1036{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001037 .arc_name = "ip4-output",
1038 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001039 .runs_before = VNET_FEATURES ("ip4-outacl"),
1040};
1041
1042VNET_FEATURE_INIT (ip4_outacl, static) =
1043{
1044 .arc_name = "ip4-output",
1045 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001046 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001047};
1048
Dave Barachd7cb1b52016-12-09 09:52:16 -05001049VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1050{
Matus Fabian08a6f012016-11-15 06:08:51 -08001051 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001052 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001053 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001054};
1055
1056/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001057VNET_FEATURE_INIT (ip4_interface_output, static) =
1058{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001059 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001060 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001061 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001062};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001063/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001064
Ed Warnickecb9cada2015-12-08 15:45:58 -07001065static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001066ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001068 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001070 /* Fill in lookup tables with default table (0). */
1071 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001072 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001073
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001074 if (!is_add)
1075 {
1076 ip4_main_t *im4 = &ip4_main;
1077 ip_lookup_main_t *lm4 = &im4->lookup_main;
1078 ip_interface_address_t *ia = 0;
1079 ip4_address_t *address;
1080 vlib_main_t *vm = vlib_get_main ();
1081
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001082 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001083 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001084 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001085 ({
1086 address = ip_interface_address_get_address (lm4, ia);
1087 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1088 }));
1089 /* *INDENT-ON* */
Neale Ranns03c254e2020-03-17 14:25:10 +00001090 ip4_mfib_interface_enable_disable (sw_if_index, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001091 }
1092
Neale Ranns8269d3d2018-01-30 09:02:20 -08001093 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001094 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095
Neale Ranns8269d3d2018-01-30 09:02:20 -08001096 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1097 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099 return /* no error */ 0;
1100}
1101
1102VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1103
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001105#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001107#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001109static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110ip4_lookup_init (vlib_main_t * vm)
1111{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001112 ip4_main_t *im = &ip4_main;
1113 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001114 uword i;
1115
Damjan Marion8b3191e2016-11-09 19:54:20 +01001116 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1117 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001118 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1119 return (error);
1120 if ((error = vlib_call_init_function (vm, fib_module_init)))
1121 return error;
1122 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1123 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001124
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1126 {
1127 u32 m;
1128
1129 if (i < 32)
1130 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001131 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132 m = ~0;
1133 im->fib_masks[i] = clib_host_to_net_u32 (m);
1134 }
1135
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1137
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001138 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001139 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1140 FIB_SOURCE_DEFAULT_ROUTE);
1141 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1142 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001143
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001145 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146 pn = pg_get_node (ip4_lookup_node.index);
1147 pn->unformat_edit = unformat_pg_ip4_header;
1148 }
1149
1150 {
1151 ethernet_arp_header_t h;
1152
Dave Barachb7b92992018-10-17 10:38:51 -04001153 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1156#define _8(f,v) h.f = v;
1157 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1158 _16 (l3_type, ETHERNET_TYPE_IP4);
1159 _8 (n_l2_address_bytes, 6);
1160 _8 (n_l3_address_bytes, 4);
1161 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1162#undef _16
1163#undef _8
1164
Dave Barachd7cb1b52016-12-09 09:52:16 -05001165 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 /* data */ &h,
1167 sizeof (h),
1168 /* alloc chunk size */ 8,
1169 "ip4 arp");
1170 }
1171
Dave Barach203c6322016-06-26 10:29:03 -04001172 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173}
1174
1175VLIB_INIT_FUNCTION (ip4_lookup_init);
1176
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177typedef struct
1178{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001180 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181 u32 flow_hash;
1182 u32 fib_index;
1183
1184 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001185 u8 packet_data[64 - 1 * sizeof (u32)];
1186}
1187ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001189#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001190u8 *
1191format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192{
1193 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1194 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001195 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001196 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001197 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001198 format_white_space, indent,
1199 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001200 return s;
1201}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001202#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001203
Dave Barachd7cb1b52016-12-09 09:52:16 -05001204static u8 *
1205format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001206{
1207 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1208 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001209 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001210 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211
John Loac8146c2016-09-27 17:44:02 -04001212 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001213 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001214 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001215 format_white_space, indent,
1216 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001217 return s;
1218}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219
Dave Barachd7cb1b52016-12-09 09:52:16 -05001220static u8 *
1221format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001222{
1223 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1224 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001225 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001226 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227
Vengada Govindanf1544482016-09-28 02:45:57 -07001228 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001229 t->fib_index, t->dpo_index, format_ip_adjacency,
1230 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001231 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001232 format_white_space, indent,
1233 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001234 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001235 return s;
1236}
1237
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001238#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239/* Common trace function for all ip4-forward next nodes. */
1240void
1241ip4_forward_next_trace (vlib_main_t * vm,
1242 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001243 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001244{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001245 u32 *from, n_left;
1246 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247
1248 n_left = frame->n_vectors;
1249 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001250
Ed Warnickecb9cada2015-12-08 15:45:58 -07001251 while (n_left >= 4)
1252 {
1253 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001254 vlib_buffer_t *b0, *b1;
1255 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256
1257 /* Prefetch next iteration. */
1258 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1259 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1260
1261 bi0 = from[0];
1262 bi1 = from[1];
1263
1264 b0 = vlib_get_buffer (vm, bi0);
1265 b1 = vlib_get_buffer (vm, bi1);
1266
1267 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1268 {
1269 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001270 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001272 t0->fib_index =
1273 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1274 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1275 vec_elt (im->fib_index_by_sw_if_index,
1276 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001277
Dave Barach178cf492018-11-13 16:34:13 -05001278 clib_memcpy_fast (t0->packet_data,
1279 vlib_buffer_get_current (b0),
1280 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001281 }
1282 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1283 {
1284 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001285 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001287 t1->fib_index =
1288 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1289 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1290 vec_elt (im->fib_index_by_sw_if_index,
1291 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001292 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1293 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294 }
1295 from += 2;
1296 n_left -= 2;
1297 }
1298
1299 while (n_left >= 1)
1300 {
1301 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001302 vlib_buffer_t *b0;
1303 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001304
1305 bi0 = from[0];
1306
1307 b0 = vlib_get_buffer (vm, bi0);
1308
1309 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1310 {
1311 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001312 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001314 t0->fib_index =
1315 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1316 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1317 vec_elt (im->fib_index_by_sw_if_index,
1318 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001319 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1320 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001321 }
1322 from += 1;
1323 n_left -= 1;
1324 }
1325}
1326
Ed Warnickecb9cada2015-12-08 15:45:58 -07001327/* Compute TCP/UDP/ICMP4 checksum in software. */
1328u16
1329ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1330 ip4_header_t * ip0)
1331{
1332 ip_csum_t sum0;
1333 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001334
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335 /* Initialize checksum with ip header. */
1336 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001337 payload_length_host_byte_order =
1338 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1339 sum0 =
1340 clib_host_to_net_u32 (payload_length_host_byte_order +
1341 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342
1343 if (BITS (uword) == 32)
1344 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001345 sum0 =
1346 ip_csum_with_carry (sum0,
1347 clib_mem_unaligned (&ip0->src_address, u32));
1348 sum0 =
1349 ip_csum_with_carry (sum0,
1350 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351 }
1352 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001353 sum0 =
1354 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001355
Srikanth A02833ff2019-10-02 17:48:58 -07001356 return ip_calculate_l4_checksum (vm, p0, sum0,
1357 payload_length_host_byte_order, (u8 *) ip0,
1358 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001359}
1360
John Lo37682e12016-11-30 12:51:39 -05001361u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1363{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001364 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1365 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001366 u16 sum16;
1367
1368 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1369 || ip0->protocol == IP_PROTOCOL_UDP);
1370
1371 udp0 = (void *) (ip0 + 1);
1372 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1373 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001374 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1375 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001376 return p0->flags;
1377 }
1378
1379 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1380
Damjan Marion213b5aa2017-07-13 21:19:27 +02001381 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1382 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001383
1384 return p0->flags;
1385}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001386#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001387
Dave Barach68b0fb02017-02-28 15:15:56 -05001388/* *INDENT-OFF* */
1389VNET_FEATURE_ARC_INIT (ip4_local) =
1390{
1391 .arc_name = "ip4-local",
1392 .start_nodes = VNET_FEATURES ("ip4-local"),
Dave Baracha25def72018-11-26 11:04:45 -05001393 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001394};
1395/* *INDENT-ON* */
1396
Florin Coras20a14b92017-08-15 22:47:22 -07001397static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001398ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1399 ip4_header_t * ip, u8 is_udp, u8 * error,
1400 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001401{
1402 u32 flags0;
1403 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1404 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1405 if (is_udp)
1406 {
1407 udp_header_t *udp;
1408 u32 ip_len, udp_len;
1409 i32 len_diff;
1410 udp = ip4_next_header (ip);
1411 /* Verify UDP length. */
1412 ip_len = clib_net_to_host_u16 (ip->length);
1413 udp_len = clib_net_to_host_u16 (udp->length);
1414
1415 len_diff = ip_len - udp_len;
1416 *good_tcp_udp &= len_diff >= 0;
1417 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1418 }
1419}
1420
Mohsin Kazmi68095382021-02-10 11:26:24 +01001421#define ip4_local_csum_is_offloaded(_b) \
1422 ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001423 (vnet_buffer (_b)->oflags & \
Mohsin Kazmi68095382021-02-10 11:26:24 +01001424 (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
Florin Coras1b255522018-06-01 12:22:23 -07001425
1426#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1427 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1428 || ip4_local_csum_is_offloaded (_b)))
1429
1430#define ip4_local_csum_is_valid(_b) \
1431 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1432 || (ip4_local_csum_is_offloaded (_b))) != 0
1433
1434static inline void
1435ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1436 ip4_header_t * ih, u8 * error)
1437{
1438 u8 is_udp, is_tcp_udp, good_tcp_udp;
1439
1440 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1441 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1442
1443 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1444 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1445 else
1446 good_tcp_udp = ip4_local_csum_is_valid (b);
1447
1448 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1449 *error = (is_tcp_udp && !good_tcp_udp
1450 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1451}
1452
1453static inline void
1454ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1455 ip4_header_t ** ih, u8 * error)
1456{
1457 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1458
1459 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1460 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1461
1462 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1463 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1464
1465 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1466 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1467
1468 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1469 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1470 {
1471 if (is_tcp_udp[0])
1472 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1473 &good_tcp_udp[0]);
1474 if (is_tcp_udp[1])
1475 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1476 &good_tcp_udp[1]);
1477 }
1478
1479 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1480 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1481 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1482 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1483}
1484
1485static inline void
1486ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1487 vlib_buffer_t * b, u16 * next, u8 error,
1488 u8 head_of_feature_arc)
1489{
1490 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1491 u32 next_index;
1492
1493 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1494 b->error = error ? error_node->errors[error] : 0;
1495 if (head_of_feature_arc)
1496 {
1497 next_index = *next;
1498 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1499 {
1500 vnet_feature_arc_start (arc_index,
1501 vnet_buffer (b)->sw_if_index[VLIB_RX],
1502 &next_index, b);
1503 *next = next_index;
1504 }
1505 }
1506}
1507
1508typedef struct
1509{
1510 ip4_address_t src;
1511 u32 lbi;
1512 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001513 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001514} ip4_local_last_check_t;
1515
1516static inline void
1517ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1518 ip4_local_last_check_t * last_check, u8 * error0)
1519{
1520 ip4_fib_mtrie_leaf_t leaf0;
1521 ip4_fib_mtrie_t *mtrie0;
1522 const dpo_id_t *dpo0;
1523 load_balance_t *lb0;
1524 u32 lbi0;
1525
1526 vnet_buffer (b)->ip.fib_index =
1527 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1528 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1529
Matthew Smith44e60462019-07-06 19:27:29 -05001530 /*
1531 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1532 * adjacency for the destination address (the local interface address).
1533 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1534 * adjacency for the source address (the remote sender's address)
1535 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301536 if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
1537 last_check->first)
Florin Coras1b255522018-06-01 12:22:23 -07001538 {
1539 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1540 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1541 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1542 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1543 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1544
Matthew Smith44e60462019-07-06 19:27:29 -05001545 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1546 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001547 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001548
1549 lb0 = load_balance_get (lbi0);
1550 dpo0 = load_balance_get_bucket_i (lb0, 0);
1551
1552 /*
1553 * Must have a route to source otherwise we drop the packet.
1554 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1555 *
1556 * The checks are:
1557 * - the source is a recieve => it's from us => bogus, do this
1558 * first since it sets a different error code.
1559 * - uRPF check for any route to source - accept if passes.
1560 * - allow packets destined to the broadcast address from unknown sources
1561 */
1562
1563 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1564 && dpo0->dpoi_type == DPO_RECEIVE) ?
1565 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1566 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1567 && !fib_urpf_check_size (lb0->lb_urpf)
1568 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1569 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1570
1571 last_check->src.as_u32 = ip0->src_address.as_u32;
1572 last_check->lbi = lbi0;
1573 last_check->error = *error0;
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301574 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001575 }
1576 else
1577 {
Matthew Smith44e60462019-07-06 19:27:29 -05001578 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1579 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001580 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001581 *error0 = last_check->error;
1582 }
1583}
1584
1585static inline void
1586ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1587 ip4_local_last_check_t * last_check, u8 * error)
1588{
1589 ip4_fib_mtrie_leaf_t leaf[2];
1590 ip4_fib_mtrie_t *mtrie[2];
1591 const dpo_id_t *dpo[2];
1592 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001593 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001594 u32 lbi[2];
1595
Neale Rannsbe2286b2018-12-09 12:54:51 -08001596 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001597 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1598 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1599
1600 vnet_buffer (b[0])->ip.fib_index =
1601 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1602 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1603 vnet_buffer (b[0])->ip.fib_index;
1604
1605 vnet_buffer (b[1])->ip.fib_index =
1606 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1607 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1608 vnet_buffer (b[1])->ip.fib_index;
1609
Matthew Smith44e60462019-07-06 19:27:29 -05001610 /*
1611 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1612 * adjacency for the destination address (the local interface address).
1613 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1614 * adjacency for the source address (the remote sender's address)
1615 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301616 if (PREDICT_TRUE (not_last_hit))
Florin Coras1b255522018-06-01 12:22:23 -07001617 {
1618 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1619 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1620
1621 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1622 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1623
1624 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1625 &ip[0]->src_address, 2);
1626 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1627 &ip[1]->src_address, 2);
1628
1629 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1630 &ip[0]->src_address, 3);
1631 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1632 &ip[1]->src_address, 3);
1633
1634 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1635 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1636
Matthew Smith44e60462019-07-06 19:27:29 -05001637 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1638 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001639 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001640
Matthew Smith44e60462019-07-06 19:27:29 -05001641 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1642 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001643 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001644
1645 lb[0] = load_balance_get (lbi[0]);
1646 lb[1] = load_balance_get (lbi[1]);
1647
1648 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1649 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1650
1651 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1652 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1653 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1654 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1655 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1656 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1657 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1658
1659 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1660 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1661 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1662 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1663 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1664 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1665 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1666
1667 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1668 last_check->lbi = lbi[1];
1669 last_check->error = error[1];
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301670 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001671 }
1672 else
1673 {
Matthew Smith44e60462019-07-06 19:27:29 -05001674 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1675 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001676 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001677
Matthew Smith44e60462019-07-06 19:27:29 -05001678 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1679 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001680 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001681
1682 error[0] = last_check->error;
1683 error[1] = last_check->error;
1684 }
1685}
Florin Coras20a14b92017-08-15 22:47:22 -07001686
Florin Corasc67cfd22018-10-01 21:59:18 -07001687enum ip_local_packet_type_e
1688{
1689 IP_LOCAL_PACKET_TYPE_L4,
1690 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001691 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001692};
1693
1694/**
1695 * Determine packet type and next node.
1696 *
1697 * The expectation is that all packets that are not L4 will skip
1698 * checksums and source checks.
1699 */
1700always_inline u8
1701ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1702{
1703 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1704
Juraj Sloboda3048b632018-10-02 11:13:53 +02001705 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1706 {
1707 *next = IP_LOCAL_NEXT_REASSEMBLY;
1708 return IP_LOCAL_PACKET_TYPE_FRAG;
1709 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001710 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1711 {
1712 *next = lm->local_next_by_ip_protocol[ip->protocol];
1713 return IP_LOCAL_PACKET_TYPE_NAT;
1714 }
1715
1716 *next = lm->local_next_by_ip_protocol[ip->protocol];
1717 return IP_LOCAL_PACKET_TYPE_L4;
1718}
1719
Dave Barach68b0fb02017-02-28 15:15:56 -05001720static inline uword
1721ip4_local_inline (vlib_main_t * vm,
1722 vlib_node_runtime_t * node,
1723 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001724{
Florin Coras1b255522018-06-01 12:22:23 -07001725 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001726 vlib_node_runtime_t *error_node =
Florin Corasfa2a3162020-02-11 03:01:19 +00001727 vlib_node_get_runtime (vm, ip4_local_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001728 u16 nexts[VLIB_FRAME_SIZE], *next;
1729 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1730 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001731 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001732
1733 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001734 /*
1735 * 0.0.0.0 can appear as the source address of an IP packet,
1736 * as can any other address, hence the need to use the 'first'
1737 * member to make sure the .lbi is initialised for the first
1738 * packet.
1739 */
Florin Coras1b255522018-06-01 12:22:23 -07001740 .src = {.as_u32 = 0},
1741 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001742 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1743 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001744 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001745
1746 from = vlib_frame_vector_args (frame);
1747 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001748
Ed Warnickecb9cada2015-12-08 15:45:58 -07001749 if (node->flags & VLIB_NODE_FLAG_TRACE)
1750 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1751
Florin Coras1b255522018-06-01 12:22:23 -07001752 vlib_get_buffers (vm, from, bufs, n_left_from);
1753 b = bufs;
1754 next = nexts;
1755
1756 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001757 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001758 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759
Florin Coras1b255522018-06-01 12:22:23 -07001760 /* Prefetch next iteration. */
1761 {
1762 vlib_prefetch_buffer_header (b[4], LOAD);
1763 vlib_prefetch_buffer_header (b[5], LOAD);
1764
1765 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1766 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1767 }
1768
1769 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1770
1771 ip[0] = vlib_buffer_get_current (b[0]);
1772 ip[1] = vlib_buffer_get_current (b[1]);
1773
1774 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1775 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1776
Florin Corasc67cfd22018-10-01 21:59:18 -07001777 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1778 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001779
Florin Corasc67cfd22018-10-01 21:59:18 -07001780 not_batch = pt[0] ^ pt[1];
1781
1782 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001783 goto skip_checks;
1784
1785 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001786 {
Florin Coras1b255522018-06-01 12:22:23 -07001787 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1788 ip4_local_check_src_x2 (b, ip, &last_check, error);
1789 }
1790 else
1791 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001792 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001793 {
Florin Coras1b255522018-06-01 12:22:23 -07001794 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1795 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
Florin Coras20a14b92017-08-15 22:47:22 -07001796 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001797 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798 {
Florin Coras1b255522018-06-01 12:22:23 -07001799 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1800 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001801 }
1802 }
1803
Florin Coras1b255522018-06-01 12:22:23 -07001804 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001805
Florin Coras1b255522018-06-01 12:22:23 -07001806 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1807 head_of_feature_arc);
1808 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1809 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001810
Florin Coras1b255522018-06-01 12:22:23 -07001811 b += 2;
1812 next += 2;
1813 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001814 }
1815
Florin Coras1b255522018-06-01 12:22:23 -07001816 while (n_left_from > 0)
1817 {
1818 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1819
1820 ip[0] = vlib_buffer_get_current (b[0]);
1821 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001822 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001823
Florin Corasc67cfd22018-10-01 21:59:18 -07001824 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001825 goto skip_check;
1826
1827 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1828 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1829
1830 skip_check:
1831
Florin Coras1b255522018-06-01 12:22:23 -07001832 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1833 head_of_feature_arc);
1834
1835 b += 1;
1836 next += 1;
1837 n_left_from -= 1;
1838 }
1839
1840 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841 return frame->n_vectors;
1842}
1843
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001844VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1845 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001846{
1847 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1848}
1849
1850/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001851VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001852{
Dave Barach68b0fb02017-02-28 15:15:56 -05001853 .name = "ip4-local",
1854 .vector_size = sizeof (u32),
1855 .format_trace = format_ip4_forward_next_trace,
Florin Corasfa2a3162020-02-11 03:01:19 +00001856 .n_errors = IP4_N_ERROR,
1857 .error_strings = ip4_error_strings,
Dave Barach68b0fb02017-02-28 15:15:56 -05001858 .n_next_nodes = IP_LOCAL_N_NEXT,
1859 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001860 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001861 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1862 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001863 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001864 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001865 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001866 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001867};
1868/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001869
Dave Barachd7cb1b52016-12-09 09:52:16 -05001870
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001871VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1872 vlib_node_runtime_t * node,
1873 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001874{
1875 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1876}
1877
1878/* *INDENT-OFF* */
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001879VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001880 .name = "ip4-local-end-of-arc",
1881 .vector_size = sizeof (u32),
1882
1883 .format_trace = format_ip4_forward_next_trace,
1884 .sibling_of = "ip4-local",
1885};
1886
Dave Barach68b0fb02017-02-28 15:15:56 -05001887VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1888 .arc_name = "ip4-local",
1889 .node_name = "ip4-local-end-of-arc",
1890 .runs_before = 0, /* not before any other features */
1891};
1892/* *INDENT-ON* */
1893
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001894#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001895void
1896ip4_register_protocol (u32 protocol, u32 node_index)
1897{
1898 vlib_main_t *vm = vlib_get_main ();
1899 ip4_main_t *im = &ip4_main;
1900 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001901
1902 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001903 lm->local_next_by_ip_protocol[protocol] =
1904 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001905}
Neale Rannsb538dd82019-05-21 06:54:54 -07001906
1907void
1908ip4_unregister_protocol (u32 protocol)
1909{
1910 ip4_main_t *im = &ip4_main;
1911 ip_lookup_main_t *lm = &im->lookup_main;
1912
1913 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1914 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1915}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001916#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001917
1918static clib_error_t *
1919show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001920 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 ip4_main_t *im = &ip4_main;
1923 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001924 int i;
1925
1926 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001927 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928 {
1929 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001930 {
1931 u32 node_index = vlib_get_node (vm,
1932 ip4_local_node.index)->
1933 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001934 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1935 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001936 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001937 }
1938 return 0;
1939}
1940
1941
1942
Billy McFall0683c9c2016-10-13 08:27:31 -04001943/*?
1944 * Display the set of protocols handled by the local IPv4 stack.
1945 *
1946 * @cliexpar
1947 * Example of how to display local protocol table:
1948 * @cliexstart{show ip local}
1949 * Protocols handled by ip4_local
1950 * 1
1951 * 17
1952 * 47
1953 * @cliexend
1954?*/
1955/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001956VLIB_CLI_COMMAND (show_ip_local, static) =
1957{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958 .path = "show ip local",
1959 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001960 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001961};
Billy McFall0683c9c2016-10-13 08:27:31 -04001962/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001963
Dave Barachd7cb1b52016-12-09 09:52:16 -05001964typedef enum
1965{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001966 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001967 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001968 IP4_REWRITE_NEXT_FRAGMENT,
1969 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001970} ip4_rewrite_next_t;
1971
Neale Ranns889fe942017-06-01 05:43:19 -04001972/**
1973 * This bits of an IPv4 address to mask to construct a multicast
1974 * MAC address
1975 */
1976#if CLIB_ARCH_IS_BIG_ENDIAN
1977#define IP4_MCAST_ADDR_MASK 0x007fffff
1978#else
1979#define IP4_MCAST_ADDR_MASK 0xffff7f00
1980#endif
1981
Ole Troan8a9c8f12018-05-18 11:01:31 +02001982always_inline void
1983ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Ole Troaneb284a12019-10-09 13:33:19 +02001984 u16 adj_packet_bytes, bool df, u16 * next,
1985 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02001986{
1987 if (packet_len > adj_packet_bytes)
1988 {
1989 *error = IP4_ERROR_MTU_EXCEEDED;
1990 if (df)
1991 {
1992 icmp4_error_set_vnet_buffer
1993 (b, ICMP4_destination_unreachable,
1994 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
1995 adj_packet_bytes);
1996 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
1997 }
1998 else
1999 {
Ole Troan313f7e22018-04-10 16:02:51 +02002000 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002001 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00002002 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02002003 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2004 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002005 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002006 }
2007 }
2008}
2009
Neale Ranns0b6a8572019-10-30 17:34:14 +00002010/* increment TTL & update checksum.
2011 Works either endian, so no need for byte swap. */
2012static_always_inline void
2013ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2014{
2015 i32 ttl;
2016 u32 checksum;
2017 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002018 return;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002019
2020 ttl = ip->ttl;
2021
2022 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2023 checksum += checksum >= 0xffff;
2024
2025 ip->checksum = checksum;
2026 ttl += 1;
2027 ip->ttl = ttl;
2028
Benoît Ganne6e334e32020-08-31 18:59:34 +02002029 ASSERT (ip4_header_checksum_is_valid (ip));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002030}
2031
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002032/* Decrement TTL & update checksum.
2033 Works either endian, so no need for byte swap. */
2034static_always_inline void
2035ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2036 u32 * error)
2037{
2038 i32 ttl;
2039 u32 checksum;
2040 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
Neale Ranns88cecfa2020-04-08 08:28:06 -04002041 return;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002042
2043 ttl = ip->ttl;
2044
2045 /* Input node should have reject packets with ttl 0. */
2046 ASSERT (ip->ttl > 0);
2047
2048 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2049 checksum += checksum >= 0xffff;
2050
2051 ip->checksum = checksum;
2052 ttl -= 1;
2053 ip->ttl = ttl;
2054
2055 /*
2056 * If the ttl drops below 1 when forwarding, generate
2057 * an ICMP response.
2058 */
2059 if (PREDICT_FALSE (ttl <= 0))
2060 {
2061 *error = IP4_ERROR_TIME_EXPIRED;
2062 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2063 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2064 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2065 0);
2066 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2067 }
2068
2069 /* Verify checksum. */
Benoît Ganne6e334e32020-08-31 18:59:34 +02002070 ASSERT (ip4_header_checksum_is_valid (ip) ||
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02002071 (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002072}
2073
Ed Warnickecb9cada2015-12-08 15:45:58 -07002074always_inline uword
Damjan Mariond06e2eb2021-04-21 23:44:40 +02002075ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2076 vlib_frame_t *frame, int do_counters, int is_midchain,
2077 int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002078{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002079 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2080 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002081 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2082 u16 nexts[VLIB_FRAME_SIZE], *next;
2083 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002084 vlib_node_runtime_t *error_node =
2085 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002086
2087 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002088 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002089
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002090 vlib_get_buffers (vm, from, bufs, n_left_from);
2091 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2092
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002093#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002094 if (n_left_from >= 6)
2095 {
2096 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002097 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002098 vlib_prefetch_buffer_header (bufs[i], LOAD);
2099 }
2100
2101 next = nexts;
2102 b = bufs;
2103 while (n_left_from >= 8)
2104 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002105 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002106 ip4_header_t *ip0, *ip1;
2107 u32 rw_len0, error0, adj_index0;
2108 u32 rw_len1, error1, adj_index1;
2109 u32 tx_sw_if_index0, tx_sw_if_index1;
2110 u8 *p;
2111
PiotrX Kleskib801cd12020-12-09 14:32:26 +01002112 if (is_midchain)
2113 {
2114 vlib_prefetch_buffer_header (b[6], LOAD);
2115 vlib_prefetch_buffer_header (b[7], LOAD);
2116 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002117
2118 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2119 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2120
2121 /*
2122 * pre-fetch the per-adjacency counters
2123 */
2124 if (do_counters)
2125 {
2126 vlib_prefetch_combined_counter (&adjacency_counters,
2127 thread_index, adj_index0);
2128 vlib_prefetch_combined_counter (&adjacency_counters,
2129 thread_index, adj_index1);
2130 }
2131
2132 ip0 = vlib_buffer_get_current (b[0]);
2133 ip1 = vlib_buffer_get_current (b[1]);
2134
2135 error0 = error1 = IP4_ERROR_NONE;
2136
2137 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2138 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2139
2140 /* Rewrite packet header and updates lengths. */
2141 adj0 = adj_get (adj_index0);
2142 adj1 = adj_get (adj_index1);
2143
2144 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2145 rw_len0 = adj0[0].rewrite_header.data_bytes;
2146 rw_len1 = adj1[0].rewrite_header.data_bytes;
2147 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2148 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2149
2150 p = vlib_buffer_get_current (b[2]);
2151 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2152 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2153
2154 p = vlib_buffer_get_current (b[3]);
2155 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2156 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2157
2158 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002159 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2160 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2161
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002162 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002163 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002164 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002165 ip1_len = gso_mtu_sz (b[1]);
2166
2167 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002168 adj0[0].rewrite_header.max_l3_packet_bytes,
2169 ip0->flags_and_fragment_offset &
2170 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002171 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002172 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002173 adj1[0].rewrite_header.max_l3_packet_bytes,
2174 ip1->flags_and_fragment_offset &
2175 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002176 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002177
2178 if (is_mcast)
2179 {
2180 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2181 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2182 IP4_ERROR_SAME_INTERFACE : error0);
2183 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2184 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2185 IP4_ERROR_SAME_INTERFACE : error1);
2186 }
2187
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002188 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002189 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002190 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2191 {
2192 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002193 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002194
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002195 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2196 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2197
2198 if (PREDICT_FALSE
2199 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002200 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2201 tx_sw_if_index0,
2202 &next_index, b[0],
2203 adj0->ia_cfg_index);
2204
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002205 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002206 if (is_midchain)
Dave Barach1bd2c012020-04-12 08:31:39 -04002207 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002208 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002209 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002210 else
2211 {
2212 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002213 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2214 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002215 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002216 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2217 {
2218 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002219 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002220
2221 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2222 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2223
2224 if (PREDICT_FALSE
2225 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002226 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2227 tx_sw_if_index1,
2228 &next_index, b[1],
2229 adj1->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002230 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002231 if (is_midchain)
Neale Rannsfc746972020-05-20 19:58:20 +00002232 vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002233 0 /* is_ip6 */ );
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002234 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002235 else
2236 {
2237 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002238 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2239 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002240 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002241
Neale Ranns4ec36c52020-03-31 09:21:29 -04002242 if (is_midchain)
2243 /* Guess we are only writing on ipv4 header. */
2244 vnet_rewrite_two_headers (adj0[0], adj1[0],
2245 ip0, ip1, sizeof (ip4_header_t));
2246 else
2247 /* Guess we are only writing on simple Ethernet header. */
2248 vnet_rewrite_two_headers (adj0[0], adj1[0],
2249 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002250
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002251 if (do_counters)
2252 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002253 if (error0 == IP4_ERROR_NONE)
2254 vlib_increment_combined_counter
2255 (&adjacency_counters,
2256 thread_index,
2257 adj_index0, 1,
2258 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002259
Neale Ranns0b6a8572019-10-30 17:34:14 +00002260 if (error1 == IP4_ERROR_NONE)
2261 vlib_increment_combined_counter
2262 (&adjacency_counters,
2263 thread_index,
2264 adj_index1, 1,
2265 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002266 }
2267
2268 if (is_midchain)
2269 {
Neale Ranns4ec36c52020-03-31 09:21:29 -04002270 if (error0 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002271 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns4ec36c52020-03-31 09:21:29 -04002272 if (error1 == IP4_ERROR_NONE)
Neale Ranns5c544c82020-11-17 09:47:07 +00002273 adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002274 }
2275
2276 if (is_mcast)
2277 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002278 /* copy bytes from the IP address into the MAC rewrite */
2279 if (error0 == IP4_ERROR_NONE)
2280 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2281 adj0->rewrite_header.dst_mcast_offset,
2282 &ip0->dst_address.as_u32, (u8 *) ip0);
2283 if (error1 == IP4_ERROR_NONE)
2284 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2285 adj1->rewrite_header.dst_mcast_offset,
2286 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002287 }
2288
2289 next += 2;
2290 b += 2;
2291 n_left_from -= 2;
2292 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002293#elif (CLIB_N_PREFETCHES >= 4)
2294 next = nexts;
2295 b = bufs;
2296 while (n_left_from >= 1)
2297 {
2298 ip_adjacency_t *adj0;
2299 ip4_header_t *ip0;
2300 u32 rw_len0, error0, adj_index0;
2301 u32 tx_sw_if_index0;
2302 u8 *p;
2303
2304 /* Prefetch next iteration */
2305 if (PREDICT_TRUE (n_left_from >= 4))
2306 {
2307 ip_adjacency_t *adj2;
2308 u32 adj_index2;
2309
2310 vlib_prefetch_buffer_header (b[3], LOAD);
2311 vlib_prefetch_buffer_data (b[2], LOAD);
2312
2313 /* Prefetch adj->rewrite_header */
2314 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2315 adj2 = adj_get (adj_index2);
2316 p = (u8 *) adj2;
2317 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2318 LOAD);
2319 }
2320
2321 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2322
2323 /*
2324 * Prefetch the per-adjacency counters
2325 */
2326 if (do_counters)
2327 {
2328 vlib_prefetch_combined_counter (&adjacency_counters,
2329 thread_index, adj_index0);
2330 }
2331
2332 ip0 = vlib_buffer_get_current (b[0]);
2333
2334 error0 = IP4_ERROR_NONE;
2335
2336 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2337
2338 /* Rewrite packet header and updates lengths. */
2339 adj0 = adj_get (adj_index0);
2340
2341 /* Rewrite header was prefetched. */
2342 rw_len0 = adj0[0].rewrite_header.data_bytes;
2343 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2344
2345 /* Check MTU of outgoing interface. */
2346 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2347
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002348 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002349 ip0_len = gso_mtu_sz (b[0]);
2350
2351 ip4_mtu_check (b[0], ip0_len,
2352 adj0[0].rewrite_header.max_l3_packet_bytes,
2353 ip0->flags_and_fragment_offset &
2354 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002355 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002356
2357 if (is_mcast)
2358 {
2359 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2360 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2361 IP4_ERROR_SAME_INTERFACE : error0);
2362 }
2363
2364 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2365 * to see the IP header */
2366 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2367 {
2368 u32 next_index = adj0[0].rewrite_header.next_index;
2369 vlib_buffer_advance (b[0], -(word) rw_len0);
2370 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2371 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2372
2373 if (PREDICT_FALSE
2374 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002375 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2376 tx_sw_if_index0,
2377 &next_index, b[0],
2378 adj0->ia_cfg_index);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002379 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002380
2381 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002382 {
2383 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002384 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002385
Neale Ranns4ec36c52020-03-31 09:21:29 -04002386 /* Guess we are only writing on ipv4 header. */
2387 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2388 }
2389 else
2390 /* Guess we are only writing on simple Ethernet header. */
2391 vnet_rewrite_one_header (adj0[0], ip0,
2392 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002393
2394 /*
2395 * Bump the per-adjacency counters
2396 */
2397 if (do_counters)
2398 vlib_increment_combined_counter
2399 (&adjacency_counters,
2400 thread_index,
2401 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2402 b[0]) + rw_len0);
2403
Neale Ranns4ec36c52020-03-31 09:21:29 -04002404 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002405 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002406
2407 if (is_mcast)
2408 /* copy bytes from the IP address into the MAC rewrite */
2409 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2410 adj0->rewrite_header.dst_mcast_offset,
2411 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002412 }
2413 else
2414 {
2415 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002416 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2417 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002418 }
2419
2420 next += 1;
2421 b += 1;
2422 n_left_from -= 1;
2423 }
2424#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002425
Ed Warnickecb9cada2015-12-08 15:45:58 -07002426 while (n_left_from > 0)
2427 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002428 ip_adjacency_t *adj0;
2429 ip4_header_t *ip0;
2430 u32 rw_len0, adj_index0, error0;
2431 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002432
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002433 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2434
2435 adj0 = adj_get (adj_index0);
2436
2437 if (do_counters)
2438 vlib_prefetch_combined_counter (&adjacency_counters,
2439 thread_index, adj_index0);
2440
2441 ip0 = vlib_buffer_get_current (b[0]);
2442
2443 error0 = IP4_ERROR_NONE;
2444
2445 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2446
2447
2448 /* Update packet buffer attributes/set output interface. */
2449 rw_len0 = adj0[0].rewrite_header.data_bytes;
2450 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2451
2452 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002453 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002454 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002455 ip0_len = gso_mtu_sz (b[0]);
2456
2457 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002458 adj0[0].rewrite_header.max_l3_packet_bytes,
2459 ip0->flags_and_fragment_offset &
2460 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002461 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002462
2463 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002464 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002465 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2466 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2467 IP4_ERROR_SAME_INTERFACE : error0);
2468 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002469
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002470 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002471 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002472 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2473 {
2474 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002475 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002476 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2477 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002478
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002479 if (PREDICT_FALSE
2480 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002481 vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2482 tx_sw_if_index0,
2483 &next_index, b[0],
2484 adj0->ia_cfg_index);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002485 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002486
2487 if (is_midchain)
Neale Ranns4ec36c52020-03-31 09:21:29 -04002488 {
2489 /* this acts on the packet that is about to be encapped */
2490 vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002491 0 /* is_ip6 */ );
Neale Ranns0b6a8572019-10-30 17:34:14 +00002492
Neale Ranns4ec36c52020-03-31 09:21:29 -04002493 /* Guess we are only writing on ipv4 header. */
2494 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2495 }
2496 else
2497 /* Guess we are only writing on simple Ethernet header. */
2498 vnet_rewrite_one_header (adj0[0], ip0,
2499 sizeof (ethernet_header_t));
Neale Ranns0b6a8572019-10-30 17:34:14 +00002500
2501 if (do_counters)
2502 vlib_increment_combined_counter
2503 (&adjacency_counters,
2504 thread_index, adj_index0, 1,
2505 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2506
Neale Rannse2fe0972020-11-26 08:37:27 +00002507 if (is_midchain)
Neale Ranns5c544c82020-11-17 09:47:07 +00002508 adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002509
2510 if (is_mcast)
2511 /* copy bytes from the IP address into the MAC rewrite */
2512 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2513 adj0->rewrite_header.dst_mcast_offset,
2514 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002515 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002516 else
2517 {
2518 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002519 /* undo the TTL decrement - we'll be back to do it again */
2520 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2521 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002522 }
2523
2524 next += 1;
2525 b += 1;
2526 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002527 }
2528
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002529
Ed Warnickecb9cada2015-12-08 15:45:58 -07002530 /* Need to do trace after rewrites to pick up new packet data. */
2531 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002532 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002533
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002534 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002535 return frame->n_vectors;
2536}
2537
Neale Rannsf06aea52016-11-29 06:51:37 -08002538/** @brief IPv4 rewrite node.
2539 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002540
2541 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2542 header checksum, fetch the ip adjacency, check the outbound mtu,
2543 apply the adjacency rewrite, and send pkts to the adjacency
2544 rewrite header's rewrite_next_index.
2545
2546 @param vm vlib_main_t corresponding to the current thread
2547 @param node vlib_node_runtime_t
2548 @param frame vlib_frame_t whose contents should be dispatched
2549
2550 @par Graph mechanics: buffer metadata, next index usage
2551
2552 @em Uses:
2553 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2554 - the rewrite adjacency index
2555 - <code>adj->lookup_next_index</code>
2556 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002557 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002558 - <code>adj->rewrite_header</code>
2559 - Rewrite string length, rewrite string, next_index
2560
2561 @em Sets:
2562 - <code>b->current_data, b->current_length</code>
2563 - Updated net of applying the rewrite string
2564
2565 <em>Next Indices:</em>
2566 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002567 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002568*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002569
2570VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2571 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002572{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002573 if (adj_are_counters_enabled ())
2574 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2575 else
2576 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002577}
2578
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002579VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2580 vlib_node_runtime_t * node,
2581 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002582{
2583 if (adj_are_counters_enabled ())
2584 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2585 else
2586 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2587}
2588
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002589VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2590 vlib_node_runtime_t * node,
2591 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002592{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002593 if (adj_are_counters_enabled ())
2594 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2595 else
2596 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002597}
2598
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002599VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2600 vlib_node_runtime_t * node,
2601 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002602{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002603 if (adj_are_counters_enabled ())
2604 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2605 else
2606 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002607}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002608
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002609VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2610 vlib_node_runtime_t * node,
2611 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002612{
2613 if (adj_are_counters_enabled ())
2614 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2615 else
2616 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2617}
2618
Neale Ranns32e1c012016-11-22 17:07:28 +00002619/* *INDENT-OFF* */
2620VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002621 .name = "ip4-rewrite",
2622 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002623
Neale Ranns32e1c012016-11-22 17:07:28 +00002624 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002625
Ole Troan313f7e22018-04-10 16:02:51 +02002626 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002627 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002628 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002629 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002630 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002631 },
2632};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002633
2634VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002635 .name = "ip4-rewrite-bcast",
2636 .vector_size = sizeof (u32),
2637
2638 .format_trace = format_ip4_rewrite_trace,
2639 .sibling_of = "ip4-rewrite",
2640};
Neale Ranns32e1c012016-11-22 17:07:28 +00002641
2642VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002643 .name = "ip4-rewrite-mcast",
2644 .vector_size = sizeof (u32),
2645
2646 .format_trace = format_ip4_rewrite_trace,
2647 .sibling_of = "ip4-rewrite",
2648};
Neale Ranns32e1c012016-11-22 17:07:28 +00002649
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002650VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002651 .name = "ip4-mcast-midchain",
2652 .vector_size = sizeof (u32),
2653
2654 .format_trace = format_ip4_rewrite_trace,
2655 .sibling_of = "ip4-rewrite",
2656};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002657
Neale Ranns32e1c012016-11-22 17:07:28 +00002658VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002659 .name = "ip4-midchain",
2660 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002661 .format_trace = format_ip4_rewrite_trace,
2662 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002663};
Neale Ranns32e1c012016-11-22 17:07:28 +00002664/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002665
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002666static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002667ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2668{
2669 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002670 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002671 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002672
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002673 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002674
Neale Ranns04a75e32017-03-23 06:46:01 -07002675 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002676 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2677 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002678
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002679 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002680
Dave Barachd7cb1b52016-12-09 09:52:16 -05002681 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002682}
Dave Barach75fc8542016-10-11 16:16:02 -04002683
Ed Warnickecb9cada2015-12-08 15:45:58 -07002684static clib_error_t *
2685test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002686 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002687{
Billy McFall309fe062016-10-14 07:37:33 -04002688 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002689 u32 table_id = 0;
2690 f64 count = 1;
2691 u32 n;
2692 int i;
2693 ip4_address_t ip4_base_address;
2694 u64 errors = 0;
2695
Dave Barachd7cb1b52016-12-09 09:52:16 -05002696 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2697 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002698 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002699 {
2700 /* Make sure the entry exists. */
2701 fib = ip4_fib_get (table_id);
2702 if ((fib) && (fib->index != table_id))
2703 return clib_error_return (0, "<fib-index> %d does not exist",
2704 table_id);
2705 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002706 else if (unformat (input, "count %f", &count))
2707 ;
2708
2709 else if (unformat (input, "%U",
2710 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002711 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002712 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002713 return clib_error_return (0, "unknown input `%U'",
2714 format_unformat_error, input);
2715 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002716
2717 n = count;
2718
2719 for (i = 0; i < n; i++)
2720 {
2721 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002722 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723
Dave Barach75fc8542016-10-11 16:16:02 -04002724 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002725 clib_host_to_net_u32 (1 +
2726 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727 }
2728
Dave Barach75fc8542016-10-11 16:16:02 -04002729 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002730 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2731 else
2732 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2733
2734 return 0;
2735}
2736
Billy McFall0683c9c2016-10-13 08:27:31 -04002737/*?
2738 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2739 * given FIB table to determine if there is a conflict with the
2740 * adjacency table. The fib-id can be determined by using the
2741 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2742 * of 0 is used.
2743 *
2744 * @todo This command uses fib-id, other commands use table-id (not
2745 * just a name, they are different indexes). Would like to change this
2746 * to table-id for consistency.
2747 *
2748 * @cliexpar
2749 * Example of how to run the test lookup command:
2750 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2751 * No errors in 2 lookups
2752 * @cliexend
2753?*/
2754/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002755VLIB_CLI_COMMAND (lookup_test_command, static) =
2756{
2757 .path = "test lookup",
2758 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2759 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002760};
Billy McFall0683c9c2016-10-13 08:27:31 -04002761/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002762
Ed Warnickecb9cada2015-12-08 15:45:58 -07002763static clib_error_t *
2764set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002765 unformat_input_t * input,
2766 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002767{
2768 int matched = 0;
2769 u32 table_id = 0;
2770 u32 flow_hash_config = 0;
2771 int rv;
2772
Dave Barachd7cb1b52016-12-09 09:52:16 -05002773 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2774 {
2775 if (unformat (input, "table %d", &table_id))
2776 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002777#define _(a, b, v) \
2778 else if (unformat (input, #a)) \
2779 { \
2780 flow_hash_config |= v; \
2781 matched = 1; \
2782 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002783 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002784#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002785 else
2786 break;
2787 }
Dave Barach75fc8542016-10-11 16:16:02 -04002788
Ed Warnickecb9cada2015-12-08 15:45:58 -07002789 if (matched == 0)
2790 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002791 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002792
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002793 rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002794 switch (rv)
2795 {
2796 case 0:
2797 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002798
Ed Warnickecb9cada2015-12-08 15:45:58 -07002799 case VNET_API_ERROR_NO_SUCH_FIB:
2800 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002801
Ed Warnickecb9cada2015-12-08 15:45:58 -07002802 default:
2803 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2804 break;
2805 }
Dave Barach75fc8542016-10-11 16:16:02 -04002806
Ed Warnickecb9cada2015-12-08 15:45:58 -07002807 return 0;
2808}
Dave Barach75fc8542016-10-11 16:16:02 -04002809
Billy McFall0683c9c2016-10-13 08:27:31 -04002810/*?
2811 * Configure the set of IPv4 fields used by the flow hash.
2812 *
2813 * @cliexpar
2814 * Example of how to set the flow hash on a given table:
2815 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2816 * Example of display the configured flow hash:
2817 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002818 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2819 * 0.0.0.0/0
2820 * unicast-ip4-chain
2821 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2822 * [0] [@0]: dpo-drop ip6
2823 * 0.0.0.0/32
2824 * unicast-ip4-chain
2825 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2826 * [0] [@0]: dpo-drop ip6
2827 * 224.0.0.0/8
2828 * unicast-ip4-chain
2829 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2830 * [0] [@0]: dpo-drop ip6
2831 * 6.0.1.2/32
2832 * unicast-ip4-chain
2833 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2834 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2835 * 7.0.0.1/32
2836 * unicast-ip4-chain
2837 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2838 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2839 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2840 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2841 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2842 * 240.0.0.0/8
2843 * unicast-ip4-chain
2844 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2845 * [0] [@0]: dpo-drop ip6
2846 * 255.255.255.255/32
2847 * unicast-ip4-chain
2848 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2849 * [0] [@0]: dpo-drop ip6
2850 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2851 * 0.0.0.0/0
2852 * unicast-ip4-chain
2853 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2854 * [0] [@0]: dpo-drop ip6
2855 * 0.0.0.0/32
2856 * unicast-ip4-chain
2857 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2858 * [0] [@0]: dpo-drop ip6
2859 * 172.16.1.0/24
2860 * unicast-ip4-chain
2861 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2862 * [0] [@4]: ipv4-glean: af_packet0
2863 * 172.16.1.1/32
2864 * unicast-ip4-chain
2865 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2866 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2867 * 172.16.1.2/32
2868 * unicast-ip4-chain
2869 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2870 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2871 * 172.16.2.0/24
2872 * unicast-ip4-chain
2873 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2874 * [0] [@4]: ipv4-glean: af_packet1
2875 * 172.16.2.1/32
2876 * unicast-ip4-chain
2877 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2878 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2879 * 224.0.0.0/8
2880 * unicast-ip4-chain
2881 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2882 * [0] [@0]: dpo-drop ip6
2883 * 240.0.0.0/8
2884 * unicast-ip4-chain
2885 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2886 * [0] [@0]: dpo-drop ip6
2887 * 255.255.255.255/32
2888 * unicast-ip4-chain
2889 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2890 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002891 * @cliexend
2892?*/
2893/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002894VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2895{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002896 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002897 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002898 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002899 .function = set_ip_flow_hash_command_fn,
2900};
Billy McFall0683c9c2016-10-13 08:27:31 -04002901/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002902
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002903#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002904int
2905vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2906 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002907{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002908 vnet_main_t *vnm = vnet_get_main ();
2909 vnet_interface_main_t *im = &vnm->interface_main;
2910 ip4_main_t *ipm = &ip4_main;
2911 ip_lookup_main_t *lm = &ipm->lookup_main;
2912 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002913 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002914
2915 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2916 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2917
2918 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2919 return VNET_API_ERROR_NO_SUCH_ENTRY;
2920
2921 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002922 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002923
Neale Rannsdf089a82016-10-02 16:39:06 +01002924 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2925
2926 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002927 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002928 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002929 .fp_len = 32,
2930 .fp_proto = FIB_PROTOCOL_IP4,
2931 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002932 };
2933 u32 fib_index;
2934
Dave Barachd7cb1b52016-12-09 09:52:16 -05002935 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2936 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002937
2938
Dave Barachd7cb1b52016-12-09 09:52:16 -05002939 if (table_index != (u32) ~ 0)
2940 {
2941 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002942
Dave Barachd7cb1b52016-12-09 09:52:16 -05002943 dpo_set (&dpo,
2944 DPO_CLASSIFY,
2945 DPO_PROTO_IP4,
2946 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002947
Dave Barachd7cb1b52016-12-09 09:52:16 -05002948 fib_table_entry_special_dpo_add (fib_index,
2949 &pfx,
2950 FIB_SOURCE_CLASSIFY,
2951 FIB_ENTRY_FLAG_NONE, &dpo);
2952 dpo_reset (&dpo);
2953 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002954 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002955 {
2956 fib_table_entry_special_remove (fib_index,
2957 &pfx, FIB_SOURCE_CLASSIFY);
2958 }
2959 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002960
Ed Warnickecb9cada2015-12-08 15:45:58 -07002961 return 0;
2962}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002963#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002964
2965static clib_error_t *
2966set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002967 unformat_input_t * input,
2968 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002969{
2970 u32 table_index = ~0;
2971 int table_index_set = 0;
2972 u32 sw_if_index = ~0;
2973 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002974
Dave Barachd7cb1b52016-12-09 09:52:16 -05002975 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2976 {
2977 if (unformat (input, "table-index %d", &table_index))
2978 table_index_set = 1;
2979 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2980 vnet_get_main (), &sw_if_index))
2981 ;
2982 else
2983 break;
2984 }
Dave Barach75fc8542016-10-11 16:16:02 -04002985
Ed Warnickecb9cada2015-12-08 15:45:58 -07002986 if (table_index_set == 0)
2987 return clib_error_return (0, "classify table-index must be specified");
2988
2989 if (sw_if_index == ~0)
2990 return clib_error_return (0, "interface / subif must be specified");
2991
2992 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2993
2994 switch (rv)
2995 {
2996 case 0:
2997 break;
2998
2999 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3000 return clib_error_return (0, "No such interface");
3001
3002 case VNET_API_ERROR_NO_SUCH_ENTRY:
3003 return clib_error_return (0, "No such classifier table");
3004 }
3005 return 0;
3006}
3007
Billy McFall0683c9c2016-10-13 08:27:31 -04003008/*?
3009 * Assign a classification table to an interface. The classification
3010 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3011 * commands. Once the table is create, use this command to filter packets
3012 * on an interface.
3013 *
3014 * @cliexpar
3015 * Example of how to assign a classification table to an interface:
3016 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3017?*/
3018/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003019VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3020{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003021 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003022 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003023 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024 .function = set_ip_classify_command_fn,
3025};
Billy McFall0683c9c2016-10-13 08:27:31 -04003026/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003027
3028/*
3029 * fd.io coding-style-patch-verification: ON
3030 *
3031 * Local Variables:
3032 * eval: (c-set-style "gnu")
3033 * End:
3034 */