blob: 40c396c4f3b40444067be822f790d6a0e48c9aad [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>
52#include <vnet/dpo/load_balance.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070053#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010054#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000055#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Ed Warnickecb9cada2015-12-08 15:45:58 -070056
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080057#include <vnet/ip/ip4_forward.h>
Neale Ranns25edf142019-03-22 08:12:48 +000058#include <vnet/interface_output.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
Chris Luke8e5b0412016-07-26 13:06:10 -040060/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040061 @node ip4-lookup
62
63 This is the main IPv4 lookup dispatch node.
64
65 @param vm vlib_main_t corresponding to the current thread
66 @param node vlib_node_runtime_t
67 @param frame vlib_frame_t whose contents should be dispatched
68
69 @par Graph mechanics: buffer metadata, next index usage
70
71 @em Uses:
72 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
73 - Indicates the @c sw_if_index value of the interface that the
74 packet was received on.
75 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
76 - When the value is @c ~0 then the node performs a longest prefix
77 match (LPM) for the packet destination address in the FIB attached
78 to the receive interface.
79 - Otherwise perform LPM for the packet destination address in the
80 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
81 value (0, 1, ...) and not a VRF id.
82
83 @em Sets:
84 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
85 - The lookup result adjacency index.
86
87 <em>Next Index:</em>
88 - Dispatches the packet to the node index found in
89 ip_adjacency_t @c adj->lookup_next_index
90 (where @c adj is the lookup result adjacency).
91*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020092VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
93 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070094{
Neale Rannscb54e3c2019-06-19 07:14:10 +000095 return ip4_lookup_inline (vm, node, frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -070096}
97
Dave Barachd7cb1b52016-12-09 09:52:16 -050098static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010099
Neale Rannsf8686322017-11-29 02:39:53 -0800100/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500101VLIB_REGISTER_NODE (ip4_lookup_node) =
102{
Neale Rannsf8686322017-11-29 02:39:53 -0800103 .name = "ip4-lookup",
104 .vector_size = sizeof (u32),
105 .format_trace = format_ip4_lookup_trace,
106 .n_next_nodes = IP_LOOKUP_N_NEXT,
107 .next_nodes = IP4_LOOKUP_NEXT_NODES,
108};
109/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100110
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200111VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
112 vlib_node_runtime_t * node,
113 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500115 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400116 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200117 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800118 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400119 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100121 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400122 n_left = frame->n_vectors;
123 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100124
Neale Ranns3ce72b22019-05-27 08:21:32 -0400125 vlib_get_buffers (vm, from, bufs, n_left);
126
127 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400129 const load_balance_t *lb0, *lb1;
130 const ip4_header_t *ip0, *ip1;
131 u32 lbi0, hc0, lbi1, hc1;
132 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100133
Neale Ranns3ce72b22019-05-27 08:21:32 -0400134 /* Prefetch next iteration. */
135 {
136 vlib_prefetch_buffer_header (b[2], LOAD);
137 vlib_prefetch_buffer_header (b[3], LOAD);
138
139 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
140 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
141 }
142
143 ip0 = vlib_buffer_get_current (b[0]);
144 ip1 = vlib_buffer_get_current (b[1]);
145 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
146 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
147
148 lb0 = load_balance_get (lbi0);
149 lb1 = load_balance_get (lbi1);
150
151 /*
152 * this node is for via FIBs we can re-use the hash value from the
153 * to node if present.
154 * We don't want to use the same hash value at each level in the recursion
155 * graph as that would lead to polarisation
156 */
157 hc0 = hc1 = 0;
158
159 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500160 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400161 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500162 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400163 hc0 = vnet_buffer (b[0])->ip.flow_hash =
164 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700165 }
166 else
167 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400168 hc0 = vnet_buffer (b[0])->ip.flow_hash =
169 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500170 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400171 dpo0 = load_balance_get_fwd_bucket
172 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
173 }
174 else
175 {
176 dpo0 = load_balance_get_bucket_i (lb0, 0);
177 }
178 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
179 {
180 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400182 hc1 = vnet_buffer (b[1])->ip.flow_hash =
183 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500184 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700185 else
186 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400187 hc1 = vnet_buffer (b[1])->ip.flow_hash =
188 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700189 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400190 dpo1 = load_balance_get_fwd_bucket
191 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
192 }
193 else
194 {
195 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500196 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000197
Neale Ranns3ce72b22019-05-27 08:21:32 -0400198 next[0] = dpo0->dpoi_next_node;
199 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100200
Neale Ranns3ce72b22019-05-27 08:21:32 -0400201 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
202 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100203
Neale Ranns3ce72b22019-05-27 08:21:32 -0400204 vlib_increment_combined_counter
205 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
206 vlib_increment_combined_counter
207 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100208
Neale Ranns3ce72b22019-05-27 08:21:32 -0400209 b += 2;
210 next += 2;
211 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 }
213
Neale Ranns3ce72b22019-05-27 08:21:32 -0400214 while (n_left > 0)
215 {
216 const load_balance_t *lb0;
217 const ip4_header_t *ip0;
218 const dpo_id_t *dpo0;
219 u32 lbi0, hc0;
220
221 ip0 = vlib_buffer_get_current (b[0]);
222 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
223
224 lb0 = load_balance_get (lbi0);
225
226 hc0 = 0;
227 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
228 {
229 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
230 {
231 hc0 = vnet_buffer (b[0])->ip.flow_hash =
232 vnet_buffer (b[0])->ip.flow_hash >> 1;
233 }
234 else
235 {
236 hc0 = vnet_buffer (b[0])->ip.flow_hash =
237 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
238 }
239 dpo0 = load_balance_get_fwd_bucket
240 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
241 }
242 else
243 {
244 dpo0 = load_balance_get_bucket_i (lb0, 0);
245 }
246
247 next[0] = dpo0->dpoi_next_node;
248 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
249
250 vlib_increment_combined_counter
251 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
252
253 b += 1;
254 next += 1;
255 n_left -= 1;
256 }
257
258 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800259 if (node->flags & VLIB_NODE_FLAG_TRACE)
260 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
261
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100262 return frame->n_vectors;
263}
264
Neale Rannsf8686322017-11-29 02:39:53 -0800265/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500266VLIB_REGISTER_NODE (ip4_load_balance_node) =
267{
Neale Rannsf8686322017-11-29 02:39:53 -0800268 .name = "ip4-load-balance",
269 .vector_size = sizeof (u32),
270 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200271 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800272};
273/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100274
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200275#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100276/* get first interface address */
277ip4_address_t *
278ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500279 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500281 ip_lookup_main_t *lm = &im->lookup_main;
282 ip_interface_address_t *ia = 0;
283 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100284
Neale Ranns32e1c012016-11-22 17:07:28 +0000285 /* *INDENT-OFF* */
286 foreach_ip_interface_address
287 (lm, ia, sw_if_index,
288 1 /* honor unnumbered */ ,
289 ({
290 ip4_address_t * a =
291 ip_interface_address_get_address (lm, ia);
292 result = a;
293 break;
294 }));
295 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100296 if (result_ia)
297 *result_ia = result ? ia : 0;
298 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500300#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301
302static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700303ip4_add_subnet_bcast_route (u32 fib_index,
304 fib_prefix_t *pfx,
305 u32 sw_if_index)
306{
307 vnet_sw_interface_flags_t iflags;
308
309 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
310
311 fib_table_entry_special_remove(fib_index,
312 pfx,
313 FIB_SOURCE_INTERFACE);
314
315 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
316 {
317 fib_table_entry_update_one_path (fib_index, pfx,
318 FIB_SOURCE_INTERFACE,
319 FIB_ENTRY_FLAG_NONE,
320 DPO_PROTO_IP4,
321 /* No next-hop address */
322 &ADJ_BCAST_ADDR,
323 sw_if_index,
324 // invalid FIB index
325 ~0,
326 1,
327 // no out-label stack
328 NULL,
329 FIB_ROUTE_PATH_FLAG_NONE);
330 }
331 else
332 {
333 fib_table_entry_special_add(fib_index,
334 pfx,
335 FIB_SOURCE_INTERFACE,
336 (FIB_ENTRY_FLAG_DROP |
337 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
338 }
339}
340
341static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500342ip4_add_interface_prefix_routes (ip4_main_t *im,
343 u32 sw_if_index,
344 u32 fib_index,
345 ip_interface_address_t * a)
346{
347 ip_lookup_main_t *lm = &im->lookup_main;
348 ip_interface_prefix_t *if_prefix;
349 ip4_address_t *address = ip_interface_address_get_address (lm, a);
350
351 ip_interface_prefix_key_t key = {
352 .prefix = {
353 .fp_len = a->address_length,
354 .fp_proto = FIB_PROTOCOL_IP4,
355 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
356 },
357 .sw_if_index = sw_if_index,
358 };
359
360 fib_prefix_t pfx_special = {
361 .fp_proto = FIB_PROTOCOL_IP4,
362 };
363
364 /* If prefix already set on interface, just increment ref count & return */
365 if_prefix = ip_get_interface_prefix (lm, &key);
366 if (if_prefix)
367 {
368 if_prefix->ref_count += 1;
369 return;
370 }
371
372 /* New prefix - allocate a pool entry, initialize it, add to the hash */
373 pool_get (lm->if_prefix_pool, if_prefix);
374 if_prefix->ref_count = 1;
375 if_prefix->src_ia_index = a - lm->if_address_pool;
376 clib_memcpy (&if_prefix->key, &key, sizeof (key));
377 mhash_set (&lm->prefix_to_if_prefix_index, &key,
378 if_prefix - lm->if_prefix_pool, 0 /* old value */);
379
380 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
381 if (a->address_length <= 30)
382 {
383 pfx_special.fp_len = a->address_length;
384 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
385
386 /* set the glean route for the prefix */
387 fib_table_entry_update_one_path (fib_index, &pfx_special,
388 FIB_SOURCE_INTERFACE,
389 (FIB_ENTRY_FLAG_CONNECTED |
390 FIB_ENTRY_FLAG_ATTACHED),
391 DPO_PROTO_IP4,
392 /* No next-hop address */
393 NULL,
394 sw_if_index,
395 /* invalid FIB index */
396 ~0,
397 1,
398 /* no out-label stack */
399 NULL,
400 FIB_ROUTE_PATH_FLAG_NONE);
401
402 /* set a drop route for the base address of the prefix */
403 pfx_special.fp_len = 32;
404 pfx_special.fp_addr.ip4.as_u32 =
405 address->as_u32 & im->fib_masks[a->address_length];
406
407 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
408 fib_table_entry_special_add (fib_index, &pfx_special,
409 FIB_SOURCE_INTERFACE,
410 (FIB_ENTRY_FLAG_DROP |
411 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
412
413 /* set a route for the broadcast address of the prefix */
414 pfx_special.fp_len = 32;
415 pfx_special.fp_addr.ip4.as_u32 =
416 address->as_u32 | ~im->fib_masks[a->address_length];
417 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
418 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
419
420
421 }
422 /* length == 31 - add an attached route for the other address */
423 else if (a->address_length == 31)
424 {
425 pfx_special.fp_len = 32;
426 pfx_special.fp_addr.ip4.as_u32 =
427 address->as_u32 ^ clib_host_to_net_u32(1);
428
429 fib_table_entry_update_one_path (fib_index, &pfx_special,
430 FIB_SOURCE_INTERFACE,
431 (FIB_ENTRY_FLAG_ATTACHED),
432 DPO_PROTO_IP4,
433 &pfx_special.fp_addr,
434 sw_if_index,
435 /* invalid FIB index */
436 ~0,
437 1,
438 NULL,
439 FIB_ROUTE_PATH_FLAG_NONE);
440 }
441}
442
443static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444ip4_add_interface_routes (u32 sw_if_index,
445 ip4_main_t * im, u32 fib_index,
446 ip_interface_address_t * a)
447{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500448 ip_lookup_main_t *lm = &im->lookup_main;
449 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100450 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500451 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 .fp_proto = FIB_PROTOCOL_IP4,
453 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500456 /* set special routes for the prefix if needed */
457 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100458
459 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100461 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500462 lm->classify_table_index_by_sw_if_index[sw_if_index];
463 if (classify_table_index != (u32) ~ 0)
464 {
465 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467 dpo_set (&dpo,
468 DPO_CLASSIFY,
469 DPO_PROTO_IP4,
470 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100471
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 fib_table_entry_special_dpo_add (fib_index,
473 &pfx,
474 FIB_SOURCE_CLASSIFY,
475 FIB_ENTRY_FLAG_NONE, &dpo);
476 dpo_reset (&dpo);
477 }
478 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100479
Neale Ranns32e1c012016-11-22 17:07:28 +0000480 fib_table_entry_update_one_path (fib_index, &pfx,
481 FIB_SOURCE_INTERFACE,
482 (FIB_ENTRY_FLAG_CONNECTED |
483 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700484 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000485 &pfx.fp_addr,
486 sw_if_index,
487 // invalid FIB index
488 ~0,
489 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500490 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491}
492
493static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500494ip4_del_interface_prefix_routes (ip4_main_t * im,
495 u32 sw_if_index,
496 u32 fib_index,
497 ip4_address_t * address,
498 u32 address_length)
499{
500 ip_lookup_main_t *lm = &im->lookup_main;
501 ip_interface_prefix_t *if_prefix;
502
503 ip_interface_prefix_key_t key = {
504 .prefix = {
505 .fp_len = address_length,
506 .fp_proto = FIB_PROTOCOL_IP4,
507 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
508 },
509 .sw_if_index = sw_if_index,
510 };
511
512 fib_prefix_t pfx_special = {
513 .fp_len = 32,
514 .fp_proto = FIB_PROTOCOL_IP4,
515 };
516
517 if_prefix = ip_get_interface_prefix (lm, &key);
518 if (!if_prefix)
519 {
520 clib_warning ("Prefix not found while deleting %U",
521 format_ip4_address_and_length, address, address_length);
522 return;
523 }
524
525 if_prefix->ref_count -= 1;
526
527 /*
528 * Routes need to be adjusted if:
529 * - deleting last intf addr in prefix
530 * - deleting intf addr used as default source address in glean adjacency
531 *
532 * We're done now otherwise
533 */
534 if ((if_prefix->ref_count > 0) &&
535 !pool_is_free_index (lm->if_address_pool, if_prefix->src_ia_index))
536 return;
537
538 /* length <= 30, delete glean route, first address, last address */
539 if (address_length <= 30)
540 {
541
542 /* remove glean route for prefix */
543 pfx_special.fp_addr.ip4 = *address;
544 pfx_special.fp_len = address_length;
545 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
546
547 /* if no more intf addresses in prefix, remove other special routes */
548 if (!if_prefix->ref_count)
549 {
550 /* first address in prefix */
551 pfx_special.fp_addr.ip4.as_u32 =
552 address->as_u32 & im->fib_masks[address_length];
553 pfx_special.fp_len = 32;
554
555 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
556 fib_table_entry_special_remove (fib_index,
557 &pfx_special,
558 FIB_SOURCE_INTERFACE);
559
560 /* prefix broadcast address */
561 pfx_special.fp_addr.ip4.as_u32 =
562 address->as_u32 | ~im->fib_masks[address_length];
563 pfx_special.fp_len = 32;
564
565 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
566 fib_table_entry_special_remove (fib_index,
567 &pfx_special,
568 FIB_SOURCE_INTERFACE);
569 }
570 else
571 /* default source addr just got deleted, find another */
572 {
573 ip_interface_address_t *new_src_ia = NULL;
574 ip4_address_t *new_src_addr = NULL;
575
576 new_src_addr =
577 ip4_interface_address_matching_destination
578 (im, address, sw_if_index, &new_src_ia);
579
580 if_prefix->src_ia_index = new_src_ia - lm->if_address_pool;
581
582 pfx_special.fp_len = address_length;
583 pfx_special.fp_addr.ip4 = *new_src_addr;
584
585 /* set new glean route for the prefix */
586 fib_table_entry_update_one_path (fib_index, &pfx_special,
587 FIB_SOURCE_INTERFACE,
588 (FIB_ENTRY_FLAG_CONNECTED |
589 FIB_ENTRY_FLAG_ATTACHED),
590 DPO_PROTO_IP4,
591 /* No next-hop address */
592 NULL,
593 sw_if_index,
594 /* invalid FIB index */
595 ~0,
596 1,
597 /* no out-label stack */
598 NULL,
599 FIB_ROUTE_PATH_FLAG_NONE);
600 return;
601 }
602 }
603 /* length == 31, delete attached route for the other address */
604 else if (address_length == 31)
605 {
606 pfx_special.fp_addr.ip4.as_u32 =
607 address->as_u32 ^ clib_host_to_net_u32(1);
608
609 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
610 }
611
612 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
613 pool_put (lm->if_prefix_pool, if_prefix);
614}
615
616static void
617ip4_del_interface_routes (u32 sw_if_index,
618 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100619 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500620 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700621{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500622 fib_prefix_t pfx = {
623 .fp_len = address_length,
624 .fp_proto = FIB_PROTOCOL_IP4,
625 .fp_addr.ip4 = *address,
626 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500628 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
629 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700630
Dave Barachd7cb1b52016-12-09 09:52:16 -0500631 pfx.fp_len = 32;
632 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633}
634
Matthew G Smith88d29a92019-07-17 10:01:17 -0500635#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100636void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500637ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100638{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500639 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
642
643 /*
644 * enable/disable only on the 1<->0 transition
645 */
646 if (is_enable)
647 {
648 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500649 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100650 }
651 else
652 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500653 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100654 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500655 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800657 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800658 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100659
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100660
Neale Ranns8269d3d2018-01-30 09:02:20 -0800661 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400662 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000663
664 {
665 ip4_enable_disable_interface_callback_t *cb;
666 vec_foreach (cb, im->enable_disable_interface_callbacks)
667 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
668 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100669}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671static clib_error_t *
672ip4_add_del_interface_address_internal (vlib_main_t * vm,
673 u32 sw_if_index,
674 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500675 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500677 vnet_main_t *vnm = vnet_get_main ();
678 ip4_main_t *im = &ip4_main;
679 ip_lookup_main_t *lm = &im->lookup_main;
680 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500682 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683
Pavel Kotucek57808982017-08-02 08:20:19 +0200684 /* local0 interface doesn't support IP addressing */
685 if (sw_if_index == 0)
686 {
687 return
688 clib_error_create ("local0 interface doesn't support IP addressing");
689 }
690
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
692 ip4_addr_fib_init (&ip4_af, address,
693 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
694 vec_add1 (addr_fib, ip4_af);
695
Neale Ranns744902e2017-08-14 10:35:44 -0700696 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100697 * there is no support for adj-fib handling in the presence of overlapping
698 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
699 * most routers do.
700 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000701 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500702 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100704 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700705 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700707 vnet_sw_interface_t *sif;
708
709 pool_foreach(sif, vnm->interface_main.sw_interfaces,
710 ({
711 if (im->fib_index_by_sw_if_index[sw_if_index] ==
712 im->fib_index_by_sw_if_index[sif->sw_if_index])
713 {
714 foreach_ip_interface_address
715 (&im->lookup_main, ia, sif->sw_if_index,
716 0 /* honor unnumbered */ ,
717 ({
718 ip4_address_t * x =
719 ip_interface_address_get_address
720 (&im->lookup_main, ia);
721 if (ip4_destination_matches_route
722 (im, address, x, ia->address_length) ||
723 ip4_destination_matches_route (im,
724 x,
725 address,
726 address_length))
727 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500728 /* an intf may have >1 addr from the same prefix */
729 if ((sw_if_index == sif->sw_if_index) &&
730 (ia->address_length == address_length) &&
731 (x->as_u32 != address->as_u32))
732 continue;
733
734 /* error if the length or intf was different */
Neale Ranns744902e2017-08-14 10:35:44 -0700735 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
736
737 return
738 clib_error_create
Ole Troan33a58172019-09-04 09:12:29 +0200739 ("failed to add %U on %U which conflicts with %U for interface %U",
Neale Ranns744902e2017-08-14 10:35:44 -0700740 format_ip4_address_and_length, address,
741 address_length,
Ole Troan33a58172019-09-04 09:12:29 +0200742 format_vnet_sw_if_index_name, vnm,
743 sw_if_index,
Neale Ranns744902e2017-08-14 10:35:44 -0700744 format_ip4_address_and_length, x,
745 ia->address_length,
746 format_vnet_sw_if_index_name, vnm,
747 sif->sw_if_index);
748 }
749 }));
750 }
751 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000753 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755 elts_before = pool_elts (lm->if_address_pool);
756
757 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500758 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700759 if (error)
760 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400761
Dave Barachd7cb1b52016-12-09 09:52:16 -0500762 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100763
Matthew G Smith88d29a92019-07-17 10:01:17 -0500764 /* intf addr routes are added/deleted on admin up/down */
765 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
766 {
767 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500768 ip4_del_interface_routes (sw_if_index,
769 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500770 address_length);
771 else
772 ip4_add_interface_routes (sw_if_index,
773 im, ip4_af.fib_index,
774 pool_elt_at_index
775 (lm->if_address_pool, if_address_index));
776 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700777
778 /* If pool did not grow/shrink: add duplicate address. */
779 if (elts_before != pool_elts (lm->if_address_pool))
780 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500781 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700782 vec_foreach (cb, im->add_del_interface_address_callbacks)
783 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500784 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700785 }
786
Dave Barachd7cb1b52016-12-09 09:52:16 -0500787done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700788 vec_free (addr_fib);
789 return error;
790}
791
792clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000793ip4_add_del_interface_address (vlib_main_t * vm,
794 u32 sw_if_index,
795 ip4_address_t * address,
796 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700797{
798 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500799 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800}
801
Neale Ranns1855b8e2018-07-11 10:31:26 -0700802void
803ip4_directed_broadcast (u32 sw_if_index, u8 enable)
804{
805 ip_interface_address_t *ia;
806 ip4_main_t *im;
807
808 im = &ip4_main;
809
810 /*
811 * when directed broadcast is enabled, the subnet braodcast route will forward
812 * packets using an adjacency with a broadcast MAC. otherwise it drops
813 */
814 /* *INDENT-OFF* */
815 foreach_ip_interface_address(&im->lookup_main, ia,
816 sw_if_index, 0,
817 ({
818 if (ia->address_length <= 30)
819 {
820 ip4_address_t *ipa;
821
822 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
823
824 fib_prefix_t pfx = {
825 .fp_len = 32,
826 .fp_proto = FIB_PROTOCOL_IP4,
827 .fp_addr = {
828 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
829 },
830 };
831
832 ip4_add_subnet_bcast_route
833 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
834 sw_if_index),
835 &pfx, sw_if_index);
836 }
837 }));
838 /* *INDENT-ON* */
839}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200840#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700841
Matthew G Smith88d29a92019-07-17 10:01:17 -0500842static clib_error_t *
843ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
844{
845 ip4_main_t *im = &ip4_main;
846 ip_interface_address_t *ia;
847 ip4_address_t *a;
848 u32 is_admin_up, fib_index;
849
850 /* Fill in lookup tables with default table (0). */
851 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
852
853 vec_validate_init_empty (im->
854 lookup_main.if_address_pool_index_by_sw_if_index,
855 sw_if_index, ~0);
856
857 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
858
859 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
860
861 /* *INDENT-OFF* */
862 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
863 0 /* honor unnumbered */,
864 ({
865 a = ip_interface_address_get_address (&im->lookup_main, ia);
866 if (is_admin_up)
867 ip4_add_interface_routes (sw_if_index,
868 im, fib_index,
869 ia);
870 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500871 ip4_del_interface_routes (sw_if_index,
872 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500873 a, ia->address_length);
874 }));
875 /* *INDENT-ON* */
876
877 return 0;
878}
879
880VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
881
Dave Barachd6534602016-06-14 18:38:02 -0400882/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500883/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100884VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
885{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500886 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100887 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500888 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100889 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
890};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100891
Dave Barachd7cb1b52016-12-09 09:52:16 -0500892VNET_FEATURE_INIT (ip4_flow_classify, static) =
893{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100894 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700895 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100896 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700897};
898
Dave Barachd7cb1b52016-12-09 09:52:16 -0500899VNET_FEATURE_INIT (ip4_inacl, static) =
900{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100901 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400902 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100903 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400904};
905
Dave Barachd7cb1b52016-12-09 09:52:16 -0500906VNET_FEATURE_INIT (ip4_source_check_1, static) =
907{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100908 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400909 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100910 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400911};
912
Dave Barachd7cb1b52016-12-09 09:52:16 -0500913VNET_FEATURE_INIT (ip4_source_check_2, static) =
914{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100915 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400916 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100917 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400918};
919
Dave Barachd7cb1b52016-12-09 09:52:16 -0500920VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
921{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100922 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400923 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100924 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400925};
926
Dave Barachd7cb1b52016-12-09 09:52:16 -0500927VNET_FEATURE_INIT (ip4_policer_classify, static) =
928{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100929 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700930 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100931 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700932};
933
Dave Barachd7cb1b52016-12-09 09:52:16 -0500934VNET_FEATURE_INIT (ip4_ipsec, static) =
935{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100936 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100937 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100938 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400939};
940
Dave Barachd7cb1b52016-12-09 09:52:16 -0500941VNET_FEATURE_INIT (ip4_vpath, static) =
942{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100943 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400944 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500945 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
946};
947
Dave Barachd7cb1b52016-12-09 09:52:16 -0500948VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
949{
John Lo37682e12016-11-30 12:51:39 -0500950 .arc_name = "ip4-unicast",
951 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100952 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400953};
954
Neale Ranns8269d3d2018-01-30 09:02:20 -0800955VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500956{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100957 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800958 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400959 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100960};
961
Neale Ranns180279b2017-03-16 15:49:09 -0400962VNET_FEATURE_INIT (ip4_lookup, static) =
963{
964 .arc_name = "ip4-unicast",
965 .node_name = "ip4-lookup",
966 .runs_before = 0, /* not before any other features */
967};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100968
Dave Barachd6534602016-06-14 18:38:02 -0400969/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100970VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
971{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500972 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100973 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500974 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100975 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
976};
977
Dave Barachd7cb1b52016-12-09 09:52:16 -0500978VNET_FEATURE_INIT (ip4_vpath_mc, static) =
979{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100980 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400981 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000982 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400983};
984
Neale Ranns8269d3d2018-01-30 09:02:20 -0800985VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500986{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100987 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800988 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400989 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
990};
991
992VNET_FEATURE_INIT (ip4_lookup_mc, static) =
993{
994 .arc_name = "ip4-multicast",
995 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500996 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100997};
Dave Barach5331c722016-08-17 11:54:30 -0400998
999/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001000VNET_FEATURE_ARC_INIT (ip4_output, static) =
1001{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001002 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001003 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001004 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001005 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1006};
Dave Barach5331c722016-08-17 11:54:30 -04001007
Dave Barachd7cb1b52016-12-09 09:52:16 -05001008VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1009{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001010 .arc_name = "ip4-output",
1011 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001012 .runs_before = VNET_FEATURES ("ip4-outacl"),
1013};
1014
1015VNET_FEATURE_INIT (ip4_outacl, static) =
1016{
1017 .arc_name = "ip4-output",
1018 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001019 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001020};
1021
Dave Barachd7cb1b52016-12-09 09:52:16 -05001022VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1023{
Matus Fabian08a6f012016-11-15 06:08:51 -08001024 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001025 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001026 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001027};
1028
1029/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001030VNET_FEATURE_INIT (ip4_interface_output, static) =
1031{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001032 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001033 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001034 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001035};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001036/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001037
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001039ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001041 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001043 /* Fill in lookup tables with default table (0). */
1044 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001045 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001046
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001047 if (!is_add)
1048 {
1049 ip4_main_t *im4 = &ip4_main;
1050 ip_lookup_main_t *lm4 = &im4->lookup_main;
1051 ip_interface_address_t *ia = 0;
1052 ip4_address_t *address;
1053 vlib_main_t *vm = vlib_get_main ();
1054
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001055 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001056 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001057 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001058 ({
1059 address = ip_interface_address_get_address (lm4, ia);
1060 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1061 }));
1062 /* *INDENT-ON* */
1063 }
1064
Neale Ranns8269d3d2018-01-30 09:02:20 -08001065 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001066 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067
Neale Ranns8269d3d2018-01-30 09:02:20 -08001068 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1069 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071 return /* no error */ 0;
1072}
1073
1074VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1075
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001077#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001078ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001079#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001081static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082ip4_lookup_init (vlib_main_t * vm)
1083{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001084 ip4_main_t *im = &ip4_main;
1085 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001086 uword i;
1087
Damjan Marion8b3191e2016-11-09 19:54:20 +01001088 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1089 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001090 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1091 return (error);
1092 if ((error = vlib_call_init_function (vm, fib_module_init)))
1093 return error;
1094 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1095 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001096
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1098 {
1099 u32 m;
1100
1101 if (i < 32)
1102 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001103 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104 m = ~0;
1105 im->fib_masks[i] = clib_host_to_net_u32 (m);
1106 }
1107
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1109
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001110 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001111 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1112 FIB_SOURCE_DEFAULT_ROUTE);
1113 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1114 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001115
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001117 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118 pn = pg_get_node (ip4_lookup_node.index);
1119 pn->unformat_edit = unformat_pg_ip4_header;
1120 }
1121
1122 {
1123 ethernet_arp_header_t h;
1124
Dave Barachb7b92992018-10-17 10:38:51 -04001125 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1128#define _8(f,v) h.f = v;
1129 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1130 _16 (l3_type, ETHERNET_TYPE_IP4);
1131 _8 (n_l2_address_bytes, 6);
1132 _8 (n_l3_address_bytes, 4);
1133 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1134#undef _16
1135#undef _8
1136
Dave Barachd7cb1b52016-12-09 09:52:16 -05001137 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001138 /* data */ &h,
1139 sizeof (h),
1140 /* alloc chunk size */ 8,
1141 "ip4 arp");
1142 }
1143
Dave Barach203c6322016-06-26 10:29:03 -04001144 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145}
1146
1147VLIB_INIT_FUNCTION (ip4_lookup_init);
1148
Dave Barachd7cb1b52016-12-09 09:52:16 -05001149typedef struct
1150{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001152 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153 u32 flow_hash;
1154 u32 fib_index;
1155
1156 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001157 u8 packet_data[64 - 1 * sizeof (u32)];
1158}
1159ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001161#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001162u8 *
1163format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001164{
1165 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1166 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001167 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001168 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001169 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001170 format_white_space, indent,
1171 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001172 return s;
1173}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001174#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001175
Dave Barachd7cb1b52016-12-09 09:52:16 -05001176static u8 *
1177format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001178{
1179 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1180 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001181 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001182 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001183
John Loac8146c2016-09-27 17:44:02 -04001184 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001185 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001186 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001187 format_white_space, indent,
1188 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001189 return s;
1190}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191
Dave Barachd7cb1b52016-12-09 09:52:16 -05001192static u8 *
1193format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001194{
1195 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1196 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001197 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001198 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
Vengada Govindanf1544482016-09-28 02:45:57 -07001200 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001201 t->fib_index, t->dpo_index, format_ip_adjacency,
1202 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001203 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001204 format_white_space, indent,
1205 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001206 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001207 return s;
1208}
1209
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001210#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211/* Common trace function for all ip4-forward next nodes. */
1212void
1213ip4_forward_next_trace (vlib_main_t * vm,
1214 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001215 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001216{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001217 u32 *from, n_left;
1218 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219
1220 n_left = frame->n_vectors;
1221 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001222
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223 while (n_left >= 4)
1224 {
1225 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001226 vlib_buffer_t *b0, *b1;
1227 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228
1229 /* Prefetch next iteration. */
1230 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1231 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1232
1233 bi0 = from[0];
1234 bi1 = from[1];
1235
1236 b0 = vlib_get_buffer (vm, bi0);
1237 b1 = vlib_get_buffer (vm, bi1);
1238
1239 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1240 {
1241 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001242 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001244 t0->fib_index =
1245 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1246 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1247 vec_elt (im->fib_index_by_sw_if_index,
1248 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001249
Dave Barach178cf492018-11-13 16:34:13 -05001250 clib_memcpy_fast (t0->packet_data,
1251 vlib_buffer_get_current (b0),
1252 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253 }
1254 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1255 {
1256 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001257 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001259 t1->fib_index =
1260 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1261 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1262 vec_elt (im->fib_index_by_sw_if_index,
1263 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001264 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1265 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001266 }
1267 from += 2;
1268 n_left -= 2;
1269 }
1270
1271 while (n_left >= 1)
1272 {
1273 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001274 vlib_buffer_t *b0;
1275 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001276
1277 bi0 = from[0];
1278
1279 b0 = vlib_get_buffer (vm, bi0);
1280
1281 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1282 {
1283 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001284 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001286 t0->fib_index =
1287 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1288 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1289 vec_elt (im->fib_index_by_sw_if_index,
1290 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001291 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1292 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293 }
1294 from += 1;
1295 n_left -= 1;
1296 }
1297}
1298
Ed Warnickecb9cada2015-12-08 15:45:58 -07001299/* Compute TCP/UDP/ICMP4 checksum in software. */
1300u16
1301ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1302 ip4_header_t * ip0)
1303{
1304 ip_csum_t sum0;
1305 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001306
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307 /* Initialize checksum with ip header. */
1308 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001309 payload_length_host_byte_order =
1310 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1311 sum0 =
1312 clib_host_to_net_u32 (payload_length_host_byte_order +
1313 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001314
1315 if (BITS (uword) == 32)
1316 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001317 sum0 =
1318 ip_csum_with_carry (sum0,
1319 clib_mem_unaligned (&ip0->src_address, u32));
1320 sum0 =
1321 ip_csum_with_carry (sum0,
1322 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 }
1324 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001325 sum0 =
1326 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001327
Srikanth A02833ff2019-10-02 17:48:58 -07001328 return ip_calculate_l4_checksum (vm, p0, sum0,
1329 payload_length_host_byte_order, (u8 *) ip0,
1330 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001331}
1332
John Lo37682e12016-11-30 12:51:39 -05001333u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001334ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1335{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001336 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1337 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338 u16 sum16;
1339
1340 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1341 || ip0->protocol == IP_PROTOCOL_UDP);
1342
1343 udp0 = (void *) (ip0 + 1);
1344 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1345 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001346 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1347 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001348 return p0->flags;
1349 }
1350
1351 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1352
Damjan Marion213b5aa2017-07-13 21:19:27 +02001353 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1354 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001355
1356 return p0->flags;
1357}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001358#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001359
Dave Barach68b0fb02017-02-28 15:15:56 -05001360/* *INDENT-OFF* */
1361VNET_FEATURE_ARC_INIT (ip4_local) =
1362{
1363 .arc_name = "ip4-local",
1364 .start_nodes = VNET_FEATURES ("ip4-local"),
Dave Baracha25def72018-11-26 11:04:45 -05001365 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001366};
1367/* *INDENT-ON* */
1368
Florin Coras20a14b92017-08-15 22:47:22 -07001369static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001370ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1371 ip4_header_t * ip, u8 is_udp, u8 * error,
1372 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001373{
1374 u32 flags0;
1375 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1376 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1377 if (is_udp)
1378 {
1379 udp_header_t *udp;
1380 u32 ip_len, udp_len;
1381 i32 len_diff;
1382 udp = ip4_next_header (ip);
1383 /* Verify UDP length. */
1384 ip_len = clib_net_to_host_u16 (ip->length);
1385 udp_len = clib_net_to_host_u16 (udp->length);
1386
1387 len_diff = ip_len - udp_len;
1388 *good_tcp_udp &= len_diff >= 0;
1389 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1390 }
1391}
1392
Florin Coras1b255522018-06-01 12:22:23 -07001393#define ip4_local_csum_is_offloaded(_b) \
1394 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1395 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1396
1397#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1398 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1399 || ip4_local_csum_is_offloaded (_b)))
1400
1401#define ip4_local_csum_is_valid(_b) \
1402 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1403 || (ip4_local_csum_is_offloaded (_b))) != 0
1404
1405static inline void
1406ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1407 ip4_header_t * ih, u8 * error)
1408{
1409 u8 is_udp, is_tcp_udp, good_tcp_udp;
1410
1411 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1412 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1413
1414 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1415 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1416 else
1417 good_tcp_udp = ip4_local_csum_is_valid (b);
1418
1419 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1420 *error = (is_tcp_udp && !good_tcp_udp
1421 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1422}
1423
1424static inline void
1425ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1426 ip4_header_t ** ih, u8 * error)
1427{
1428 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1429
1430 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1431 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1432
1433 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1434 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1435
1436 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1437 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1438
1439 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1440 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1441 {
1442 if (is_tcp_udp[0])
1443 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1444 &good_tcp_udp[0]);
1445 if (is_tcp_udp[1])
1446 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1447 &good_tcp_udp[1]);
1448 }
1449
1450 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1451 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1452 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1453 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1454}
1455
1456static inline void
1457ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1458 vlib_buffer_t * b, u16 * next, u8 error,
1459 u8 head_of_feature_arc)
1460{
1461 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1462 u32 next_index;
1463
1464 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1465 b->error = error ? error_node->errors[error] : 0;
1466 if (head_of_feature_arc)
1467 {
1468 next_index = *next;
1469 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1470 {
1471 vnet_feature_arc_start (arc_index,
1472 vnet_buffer (b)->sw_if_index[VLIB_RX],
1473 &next_index, b);
1474 *next = next_index;
1475 }
1476 }
1477}
1478
1479typedef struct
1480{
1481 ip4_address_t src;
1482 u32 lbi;
1483 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001484 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001485} ip4_local_last_check_t;
1486
1487static inline void
1488ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1489 ip4_local_last_check_t * last_check, u8 * error0)
1490{
1491 ip4_fib_mtrie_leaf_t leaf0;
1492 ip4_fib_mtrie_t *mtrie0;
1493 const dpo_id_t *dpo0;
1494 load_balance_t *lb0;
1495 u32 lbi0;
1496
1497 vnet_buffer (b)->ip.fib_index =
1498 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1499 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1500
Matthew Smith44e60462019-07-06 19:27:29 -05001501 /*
1502 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1503 * adjacency for the destination address (the local interface address).
1504 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1505 * adjacency for the source address (the remote sender's address)
1506 */
Neale Rannsbe2286b2018-12-09 12:54:51 -08001507 if (PREDICT_FALSE (last_check->first ||
1508 (last_check->src.as_u32 != ip0->src_address.as_u32)))
Florin Coras1b255522018-06-01 12:22:23 -07001509 {
1510 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1511 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1512 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1513 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1514 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1515
Matthew Smith44e60462019-07-06 19:27:29 -05001516 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1517 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001518 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001519
1520 lb0 = load_balance_get (lbi0);
1521 dpo0 = load_balance_get_bucket_i (lb0, 0);
1522
1523 /*
1524 * Must have a route to source otherwise we drop the packet.
1525 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1526 *
1527 * The checks are:
1528 * - the source is a recieve => it's from us => bogus, do this
1529 * first since it sets a different error code.
1530 * - uRPF check for any route to source - accept if passes.
1531 * - allow packets destined to the broadcast address from unknown sources
1532 */
1533
1534 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1535 && dpo0->dpoi_type == DPO_RECEIVE) ?
1536 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1537 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1538 && !fib_urpf_check_size (lb0->lb_urpf)
1539 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1540 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1541
1542 last_check->src.as_u32 = ip0->src_address.as_u32;
1543 last_check->lbi = lbi0;
1544 last_check->error = *error0;
1545 }
1546 else
1547 {
Matthew Smith44e60462019-07-06 19:27:29 -05001548 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1549 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001550 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001551 *error0 = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001552 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001553 }
1554}
1555
1556static inline void
1557ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1558 ip4_local_last_check_t * last_check, u8 * error)
1559{
1560 ip4_fib_mtrie_leaf_t leaf[2];
1561 ip4_fib_mtrie_t *mtrie[2];
1562 const dpo_id_t *dpo[2];
1563 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001564 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001565 u32 lbi[2];
1566
Neale Rannsbe2286b2018-12-09 12:54:51 -08001567 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001568 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1569 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1570
1571 vnet_buffer (b[0])->ip.fib_index =
1572 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1573 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1574 vnet_buffer (b[0])->ip.fib_index;
1575
1576 vnet_buffer (b[1])->ip.fib_index =
1577 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1578 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1579 vnet_buffer (b[1])->ip.fib_index;
1580
Matthew Smith44e60462019-07-06 19:27:29 -05001581 /*
1582 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1583 * adjacency for the destination address (the local interface address).
1584 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1585 * adjacency for the source address (the remote sender's address)
1586 */
Florin Coras1b255522018-06-01 12:22:23 -07001587 if (PREDICT_FALSE (not_last_hit))
1588 {
1589 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1590 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1591
1592 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1593 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1594
1595 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1596 &ip[0]->src_address, 2);
1597 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1598 &ip[1]->src_address, 2);
1599
1600 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1601 &ip[0]->src_address, 3);
1602 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1603 &ip[1]->src_address, 3);
1604
1605 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1606 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1607
Matthew Smith44e60462019-07-06 19:27:29 -05001608 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1609 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001610 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001611
Matthew Smith44e60462019-07-06 19:27:29 -05001612 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1613 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001614 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001615
1616 lb[0] = load_balance_get (lbi[0]);
1617 lb[1] = load_balance_get (lbi[1]);
1618
1619 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1620 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1621
1622 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1623 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1624 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1625 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1626 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1627 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1628 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1629
1630 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1631 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1632 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1633 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1634 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1635 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1636 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1637
1638 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1639 last_check->lbi = lbi[1];
1640 last_check->error = error[1];
1641 }
1642 else
1643 {
Matthew Smith44e60462019-07-06 19:27:29 -05001644 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1645 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001646 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001647
Matthew Smith44e60462019-07-06 19:27:29 -05001648 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1649 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001650 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001651
1652 error[0] = last_check->error;
1653 error[1] = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001654 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001655 }
1656}
Florin Coras20a14b92017-08-15 22:47:22 -07001657
Florin Corasc67cfd22018-10-01 21:59:18 -07001658enum ip_local_packet_type_e
1659{
1660 IP_LOCAL_PACKET_TYPE_L4,
1661 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001662 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001663};
1664
1665/**
1666 * Determine packet type and next node.
1667 *
1668 * The expectation is that all packets that are not L4 will skip
1669 * checksums and source checks.
1670 */
1671always_inline u8
1672ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1673{
1674 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1675
Juraj Sloboda3048b632018-10-02 11:13:53 +02001676 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1677 {
1678 *next = IP_LOCAL_NEXT_REASSEMBLY;
1679 return IP_LOCAL_PACKET_TYPE_FRAG;
1680 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001681 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1682 {
1683 *next = lm->local_next_by_ip_protocol[ip->protocol];
1684 return IP_LOCAL_PACKET_TYPE_NAT;
1685 }
1686
1687 *next = lm->local_next_by_ip_protocol[ip->protocol];
1688 return IP_LOCAL_PACKET_TYPE_L4;
1689}
1690
Dave Barach68b0fb02017-02-28 15:15:56 -05001691static inline uword
1692ip4_local_inline (vlib_main_t * vm,
1693 vlib_node_runtime_t * node,
1694 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001695{
Florin Coras1b255522018-06-01 12:22:23 -07001696 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001697 vlib_node_runtime_t *error_node =
1698 vlib_node_get_runtime (vm, ip4_input_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001699 u16 nexts[VLIB_FRAME_SIZE], *next;
1700 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1701 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001702 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001703
1704 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001705 /*
1706 * 0.0.0.0 can appear as the source address of an IP packet,
1707 * as can any other address, hence the need to use the 'first'
1708 * member to make sure the .lbi is initialised for the first
1709 * packet.
1710 */
Florin Coras1b255522018-06-01 12:22:23 -07001711 .src = {.as_u32 = 0},
1712 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001713 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1714 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001715 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001716
1717 from = vlib_frame_vector_args (frame);
1718 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001719
Ed Warnickecb9cada2015-12-08 15:45:58 -07001720 if (node->flags & VLIB_NODE_FLAG_TRACE)
1721 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1722
Florin Coras1b255522018-06-01 12:22:23 -07001723 vlib_get_buffers (vm, from, bufs, n_left_from);
1724 b = bufs;
1725 next = nexts;
1726
1727 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001729 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730
Florin Coras1b255522018-06-01 12:22:23 -07001731 /* Prefetch next iteration. */
1732 {
1733 vlib_prefetch_buffer_header (b[4], LOAD);
1734 vlib_prefetch_buffer_header (b[5], LOAD);
1735
1736 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1737 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1738 }
1739
1740 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1741
1742 ip[0] = vlib_buffer_get_current (b[0]);
1743 ip[1] = vlib_buffer_get_current (b[1]);
1744
1745 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1746 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1747
Florin Corasc67cfd22018-10-01 21:59:18 -07001748 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1749 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001750
Florin Corasc67cfd22018-10-01 21:59:18 -07001751 not_batch = pt[0] ^ pt[1];
1752
1753 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001754 goto skip_checks;
1755
1756 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001757 {
Florin Coras1b255522018-06-01 12:22:23 -07001758 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1759 ip4_local_check_src_x2 (b, ip, &last_check, error);
1760 }
1761 else
1762 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001763 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001764 {
Florin Coras1b255522018-06-01 12:22:23 -07001765 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1766 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
Florin Coras20a14b92017-08-15 22:47:22 -07001767 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001768 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769 {
Florin Coras1b255522018-06-01 12:22:23 -07001770 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1771 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772 }
1773 }
1774
Florin Coras1b255522018-06-01 12:22:23 -07001775 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001776
Florin Coras1b255522018-06-01 12:22:23 -07001777 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1778 head_of_feature_arc);
1779 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1780 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001781
Florin Coras1b255522018-06-01 12:22:23 -07001782 b += 2;
1783 next += 2;
1784 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001785 }
1786
Florin Coras1b255522018-06-01 12:22:23 -07001787 while (n_left_from > 0)
1788 {
1789 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1790
1791 ip[0] = vlib_buffer_get_current (b[0]);
1792 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001793 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001794
Florin Corasc67cfd22018-10-01 21:59:18 -07001795 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001796 goto skip_check;
1797
1798 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1799 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1800
1801 skip_check:
1802
Florin Coras1b255522018-06-01 12:22:23 -07001803 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1804 head_of_feature_arc);
1805
1806 b += 1;
1807 next += 1;
1808 n_left_from -= 1;
1809 }
1810
1811 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001812 return frame->n_vectors;
1813}
1814
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001815VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1816 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001817{
1818 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1819}
1820
1821/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001822VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001823{
Dave Barach68b0fb02017-02-28 15:15:56 -05001824 .name = "ip4-local",
1825 .vector_size = sizeof (u32),
1826 .format_trace = format_ip4_forward_next_trace,
1827 .n_next_nodes = IP_LOCAL_N_NEXT,
1828 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001829 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001830 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1831 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001832 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001833 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001834 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001835 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001836};
1837/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001838
Dave Barachd7cb1b52016-12-09 09:52:16 -05001839
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001840VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1841 vlib_node_runtime_t * node,
1842 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001843{
1844 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1845}
1846
1847/* *INDENT-OFF* */
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001848VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001849 .name = "ip4-local-end-of-arc",
1850 .vector_size = sizeof (u32),
1851
1852 .format_trace = format_ip4_forward_next_trace,
1853 .sibling_of = "ip4-local",
1854};
1855
Dave Barach68b0fb02017-02-28 15:15:56 -05001856VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1857 .arc_name = "ip4-local",
1858 .node_name = "ip4-local-end-of-arc",
1859 .runs_before = 0, /* not before any other features */
1860};
1861/* *INDENT-ON* */
1862
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001863#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001864void
1865ip4_register_protocol (u32 protocol, u32 node_index)
1866{
1867 vlib_main_t *vm = vlib_get_main ();
1868 ip4_main_t *im = &ip4_main;
1869 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870
1871 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001872 lm->local_next_by_ip_protocol[protocol] =
1873 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001874}
Neale Rannsb538dd82019-05-21 06:54:54 -07001875
1876void
1877ip4_unregister_protocol (u32 protocol)
1878{
1879 ip4_main_t *im = &ip4_main;
1880 ip_lookup_main_t *lm = &im->lookup_main;
1881
1882 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1883 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1884}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001885#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001886
1887static clib_error_t *
1888show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001889 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001890{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001891 ip4_main_t *im = &ip4_main;
1892 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001893 int i;
1894
1895 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001896 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001897 {
1898 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001899 {
1900 u32 node_index = vlib_get_node (vm,
1901 ip4_local_node.index)->
1902 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001903 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1904 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001905 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001906 }
1907 return 0;
1908}
1909
1910
1911
Billy McFall0683c9c2016-10-13 08:27:31 -04001912/*?
1913 * Display the set of protocols handled by the local IPv4 stack.
1914 *
1915 * @cliexpar
1916 * Example of how to display local protocol table:
1917 * @cliexstart{show ip local}
1918 * Protocols handled by ip4_local
1919 * 1
1920 * 17
1921 * 47
1922 * @cliexend
1923?*/
1924/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001925VLIB_CLI_COMMAND (show_ip_local, static) =
1926{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001927 .path = "show ip local",
1928 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001929 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001930};
Billy McFall0683c9c2016-10-13 08:27:31 -04001931/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001932
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001933always_inline uword
1934ip4_arp_inline (vlib_main_t * vm,
1935 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001936 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001937{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001938 vnet_main_t *vnm = vnet_get_main ();
1939 ip4_main_t *im = &ip4_main;
1940 ip_lookup_main_t *lm = &im->lookup_main;
1941 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942 uword n_left_from, n_left_to_next_drop, next_index;
Dave Barach49433ad2018-08-08 17:59:03 -04001943 u32 thread_index = vm->thread_index;
Neale Rannscd35e532018-08-31 02:51:45 -07001944 u64 seed;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001945
1946 if (node->flags & VLIB_NODE_FLAG_TRACE)
1947 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1948
Neale Rannsc8352bc2018-08-29 10:23:58 -07001949 seed = throttle_seed (&im->arp_throttle, thread_index, vlib_time_now (vm));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001950
1951 from = vlib_frame_vector_args (frame);
1952 n_left_from = frame->n_vectors;
1953 next_index = node->cached_next_index;
1954 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001955 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956
1957 while (n_left_from > 0)
1958 {
1959 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1960 to_next_drop, n_left_to_next_drop);
1961
1962 while (n_left_from > 0 && n_left_to_next_drop > 0)
1963 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001964 u32 pi0, bi0, adj_index0, sw_if_index0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001965 ip_adjacency_t *adj0;
Eyal Baribf9f02c2018-10-31 13:19:11 +02001966 vlib_buffer_t *p0, *b0;
1967 ip4_address_t resolve0;
1968 ethernet_arp_header_t *h0;
1969 vnet_hw_interface_t *hw_if0;
Neale Rannscd35e532018-08-31 02:51:45 -07001970 u64 r0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001971
1972 pi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001973 p0 = vlib_get_buffer (vm, pi0);
1974
Ed Warnickecb9cada2015-12-08 15:45:58 -07001975 from += 1;
1976 n_left_from -= 1;
1977 to_next_drop[0] = pi0;
1978 to_next_drop += 1;
1979 n_left_to_next_drop -= 1;
1980
Eyal Baribf9f02c2018-10-31 13:19:11 +02001981 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1982 adj0 = adj_get (adj_index0);
1983
1984 if (is_glean)
1985 {
1986 /* resolve the packet's destination */
1987 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1988 resolve0 = ip0->dst_address;
1989 }
1990 else
1991 {
1992 /* resolve the incomplete adj */
1993 resolve0 = adj0->sub_type.nbr.next_hop.ip4;
1994 }
1995
1996 /* combine the address and interface for the hash key */
1997 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1998 r0 = (u64) resolve0.data_u32 << 32;
1999 r0 |= sw_if_index0;
2000
2001 if (throttle_check (&im->arp_throttle, thread_index, r0, seed))
2002 {
2003 p0->error = node->errors[IP4_ARP_ERROR_THROTTLED];
2004 continue;
2005 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006
Neale Rannsb80c5362016-10-08 13:03:40 +01002007 /*
2008 * the adj has been updated to a rewrite but the node the DPO that got
2009 * us here hasn't - yet. no big deal. we'll drop while we wait.
2010 */
2011 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
Eyal Baribf9f02c2018-10-31 13:19:11 +02002012 {
2013 p0->error = node->errors[IP4_ARP_ERROR_RESOLVED];
2014 continue;
2015 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016
Dave Barachd7cb1b52016-12-09 09:52:16 -05002017 /*
2018 * Can happen if the control-plane is programming tables
2019 * with traffic flowing; at least that's today's lame excuse.
2020 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002021 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2022 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002023 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002024 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Eyal Baribf9f02c2018-10-31 13:19:11 +02002025 continue;
2026 }
2027 /* Send ARP request. */
2028 h0 =
2029 vlib_packet_template_get_packet (vm,
2030 &im->ip4_arp_request_packet_template,
2031 &bi0);
Eyal Baribf9f02c2018-10-31 13:19:11 +02002032 /* Seems we're out of buffers */
2033 if (PREDICT_FALSE (!h0))
2034 {
2035 p0->error = node->errors[IP4_ARP_ERROR_NO_BUFFERS];
2036 continue;
2037 }
2038
Dave Barachb19bf8d2019-05-31 08:41:34 -04002039 b0 = vlib_get_buffer (vm, bi0);
2040
2041 /* copy the persistent fields from the original */
2042 clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
2043
Eyal Baribf9f02c2018-10-31 13:19:11 +02002044 /* Add rewrite/encap string for ARP packet. */
2045 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
2046
2047 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2048
2049 /* Src ethernet address in ARP header. */
Neale Ranns37029302018-08-10 05:30:06 -07002050 mac_address_from_bytes (&h0->ip4_over_ethernet[0].mac,
2051 hw_if0->hw_address);
Eyal Baribf9f02c2018-10-31 13:19:11 +02002052 if (is_glean)
2053 {
2054 /* The interface's source address is stashed in the Glean Adj */
2055 h0->ip4_over_ethernet[0].ip4 =
2056 adj0->sub_type.glean.receive_addr.ip4;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002057 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002058 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002059 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02002060 /* Src IP address in ARP header. */
2061 if (ip4_src_address_for_packet (lm, sw_if_index0,
2062 &h0->ip4_over_ethernet[0].ip4))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002063 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02002064 /* No source address available */
2065 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2066 vlib_buffer_free (vm, &bi0, 1);
2067 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002068 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002069 }
Eyal Baribf9f02c2018-10-31 13:19:11 +02002070 h0->ip4_over_ethernet[1].ip4 = resolve0;
2071
2072 p0->error = node->errors[IP4_ARP_ERROR_REQUEST_SENT];
2073
2074 vlib_buffer_copy_trace_flag (vm, p0, bi0);
Eyal Baribf9f02c2018-10-31 13:19:11 +02002075 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
2076 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2077
2078 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2079
2080 vlib_set_next_frame_buffer (vm, node,
2081 adj0->rewrite_header.next_index, bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002082 }
2083
2084 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2085 }
2086
2087 return frame->n_vectors;
2088}
2089
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002090VLIB_NODE_FN (ip4_arp_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2091 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002092{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002093 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002094}
2095
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002096VLIB_NODE_FN (ip4_glean_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2097 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002098{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002099 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002100}
2101
Dave Barachd7cb1b52016-12-09 09:52:16 -05002102static char *ip4_arp_error_strings[] = {
Eyal Baribf9f02c2018-10-31 13:19:11 +02002103 [IP4_ARP_ERROR_THROTTLED] = "ARP requests throttled",
2104 [IP4_ARP_ERROR_RESOLVED] = "ARP requests resolved",
2105 [IP4_ARP_ERROR_NO_BUFFERS] = "ARP requests out of buffer",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002106 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2107 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002108 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002109};
2110
Neale Rannsf8686322017-11-29 02:39:53 -08002111/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002112VLIB_REGISTER_NODE (ip4_arp_node) =
2113{
Neale Rannsf8686322017-11-29 02:39:53 -08002114 .name = "ip4-arp",
2115 .vector_size = sizeof (u32),
2116 .format_trace = format_ip4_forward_next_trace,
2117 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2118 .error_strings = ip4_arp_error_strings,
2119 .n_next_nodes = IP4_ARP_N_NEXT,
2120 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002121 {
Neale Rannsf8686322017-11-29 02:39:53 -08002122 [IP4_ARP_NEXT_DROP] = "error-drop",
2123 },
2124};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002125
Dave Barachd7cb1b52016-12-09 09:52:16 -05002126VLIB_REGISTER_NODE (ip4_glean_node) =
2127{
Neale Rannsf8686322017-11-29 02:39:53 -08002128 .name = "ip4-glean",
2129 .vector_size = sizeof (u32),
2130 .format_trace = format_ip4_forward_next_trace,
2131 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2132 .error_strings = ip4_arp_error_strings,
2133 .n_next_nodes = IP4_ARP_N_NEXT,
2134 .next_nodes = {
2135 [IP4_ARP_NEXT_DROP] = "error-drop",
2136 },
2137};
2138/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002139
Ed Warnickecb9cada2015-12-08 15:45:58 -07002140#define foreach_notrace_ip4_arp_error \
Eyal Baribf9f02c2018-10-31 13:19:11 +02002141_(THROTTLED) \
2142_(RESOLVED) \
2143_(NO_BUFFERS) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07002144_(REQUEST_SENT) \
Eyal Baribf9f02c2018-10-31 13:19:11 +02002145_(NON_ARP_ADJ) \
2146_(NO_SOURCE_ADDRESS)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002147
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002148static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05002149arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002150{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002151 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002152
2153 /* don't trace ARP request packets */
2154#define _(a) \
2155 vnet_pcap_drop_trace_filter_add_del \
2156 (rt->errors[IP4_ARP_ERROR_##a], \
2157 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002158 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002159#undef _
2160 return 0;
2161}
2162
Dave Barachd7cb1b52016-12-09 09:52:16 -05002163VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002164
2165
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002166#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07002167/* Send an ARP request to see if given destination is reachable on given interface. */
2168clib_error_t *
John Lo86376342018-06-11 20:14:49 -04002169ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index,
2170 u8 refresh)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002171{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002172 vnet_main_t *vnm = vnet_get_main ();
2173 ip4_main_t *im = &ip4_main;
2174 ethernet_arp_header_t *h;
2175 ip4_address_t *src;
2176 ip_interface_address_t *ia;
2177 ip_adjacency_t *adj;
2178 vnet_hw_interface_t *hi;
2179 vnet_sw_interface_t *si;
2180 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002181 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002182 u32 bi = 0;
John Lo86376342018-06-11 20:14:49 -04002183 u8 unicast_rewrite = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002184
2185 si = vnet_get_sw_interface (vnm, sw_if_index);
2186
2187 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2188 {
2189 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002190 format_ip4_address, dst,
2191 format_vnet_sw_if_index_name, vnm,
2192 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002193 }
2194
Dave Barachd7cb1b52016-12-09 09:52:16 -05002195 src =
2196 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2197 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002198 {
2199 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002200 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002201 (0,
2202 "no matching interface address for destination %U (interface %U)",
2203 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2204 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002205 }
2206
Neale Ranns7a272742017-05-30 02:08:14 -07002207 h = vlib_packet_template_get_packet (vm,
2208 &im->ip4_arp_request_packet_template,
2209 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002210
John Lo084606b2018-06-19 15:27:48 -04002211 if (!h)
2212 return clib_error_return (0, "ARP request packet allocation failed");
2213
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002215 if (PREDICT_FALSE (!hi->hw_address))
2216 {
2217 return clib_error_return (0, "%U: interface %U do not support ip probe",
2218 format_ip4_address, dst,
2219 format_vnet_sw_if_index_name, vnm,
2220 sw_if_index);
2221 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222
Neale Ranns37029302018-08-10 05:30:06 -07002223 mac_address_from_bytes (&h->ip4_over_ethernet[0].mac, hi->hw_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002224
2225 h->ip4_over_ethernet[0].ip4 = src[0];
2226 h->ip4_over_ethernet[1].ip4 = dst[0];
2227
2228 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002229 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2230 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002231
Dave Barach59b25652017-09-10 15:04:27 -04002232 ip46_address_t nh = {
2233 .ip4 = *dst,
2234 };
2235
2236 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2237 VNET_LINK_IP4, &nh, sw_if_index);
2238 adj = adj_get (ai);
2239
2240 /* Peer has been previously resolved, retrieve glean adj instead */
2241 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2242 {
John Lo86376342018-06-11 20:14:49 -04002243 if (refresh)
2244 unicast_rewrite = 1;
2245 else
2246 {
2247 adj_unlock (ai);
2248 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
2249 VNET_LINK_IP4, sw_if_index, &nh);
2250 adj = adj_get (ai);
2251 }
Dave Barach59b25652017-09-10 15:04:27 -04002252 }
2253
Ed Warnickecb9cada2015-12-08 15:45:58 -07002254 /* Add encapsulation string for software interface (e.g. ethernet header). */
2255 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
John Lo86376342018-06-11 20:14:49 -04002256 if (unicast_rewrite)
2257 {
2258 u16 *etype = vlib_buffer_get_current (b) - 2;
2259 etype[0] = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
2260 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002261 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2262
2263 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002264 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2265 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002266 to_next[0] = bi;
2267 f->n_vectors = 1;
2268 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2269 }
2270
Neale Ranns7a272742017-05-30 02:08:14 -07002271 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 return /* no error */ 0;
2273}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002274#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002275
Dave Barachd7cb1b52016-12-09 09:52:16 -05002276typedef enum
2277{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002279 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02002280 IP4_REWRITE_NEXT_FRAGMENT,
2281 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002282} ip4_rewrite_next_t;
2283
Neale Ranns889fe942017-06-01 05:43:19 -04002284/**
2285 * This bits of an IPv4 address to mask to construct a multicast
2286 * MAC address
2287 */
2288#if CLIB_ARCH_IS_BIG_ENDIAN
2289#define IP4_MCAST_ADDR_MASK 0x007fffff
2290#else
2291#define IP4_MCAST_ADDR_MASK 0xffff7f00
2292#endif
2293
Ole Troan8a9c8f12018-05-18 11:01:31 +02002294always_inline void
2295ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002296 u16 adj_packet_bytes, bool df, u16 * next, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002297{
2298 if (packet_len > adj_packet_bytes)
2299 {
2300 *error = IP4_ERROR_MTU_EXCEEDED;
2301 if (df)
2302 {
2303 icmp4_error_set_vnet_buffer
2304 (b, ICMP4_destination_unreachable,
2305 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2306 adj_packet_bytes);
2307 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2308 }
2309 else
2310 {
Ole Troan313f7e22018-04-10 16:02:51 +02002311 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002312 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troanb3655e52018-08-16 22:08:49 +02002313 IP4_FRAG_NEXT_IP4_REWRITE, 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002314 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002315 }
2316 }
2317}
2318
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002319/* Decrement TTL & update checksum.
2320 Works either endian, so no need for byte swap. */
2321static_always_inline void
2322ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2323 u32 * error)
2324{
2325 i32 ttl;
2326 u32 checksum;
2327 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2328 {
2329 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2330 return;
2331 }
2332
2333 ttl = ip->ttl;
2334
2335 /* Input node should have reject packets with ttl 0. */
2336 ASSERT (ip->ttl > 0);
2337
2338 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2339 checksum += checksum >= 0xffff;
2340
2341 ip->checksum = checksum;
2342 ttl -= 1;
2343 ip->ttl = ttl;
2344
2345 /*
2346 * If the ttl drops below 1 when forwarding, generate
2347 * an ICMP response.
2348 */
2349 if (PREDICT_FALSE (ttl <= 0))
2350 {
2351 *error = IP4_ERROR_TIME_EXPIRED;
2352 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2353 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2354 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2355 0);
2356 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2357 }
2358
2359 /* Verify checksum. */
2360 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2361 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2362}
2363
2364
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002366ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2367 vlib_node_runtime_t * node,
2368 vlib_frame_t * frame,
2369 int do_counters, int is_midchain, int is_mcast,
2370 int do_gso)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002371{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002372 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2373 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002374 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2375 u16 nexts[VLIB_FRAME_SIZE], *next;
2376 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002377 vlib_node_runtime_t *error_node =
2378 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002379
2380 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002381 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002382
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002383 vlib_get_buffers (vm, from, bufs, n_left_from);
2384 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2385
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002386#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002387 if (n_left_from >= 6)
2388 {
2389 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002390 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002391 vlib_prefetch_buffer_header (bufs[i], LOAD);
2392 }
2393
2394 next = nexts;
2395 b = bufs;
2396 while (n_left_from >= 8)
2397 {
2398 ip_adjacency_t *adj0, *adj1;
2399 ip4_header_t *ip0, *ip1;
2400 u32 rw_len0, error0, adj_index0;
2401 u32 rw_len1, error1, adj_index1;
2402 u32 tx_sw_if_index0, tx_sw_if_index1;
2403 u8 *p;
2404
2405 vlib_prefetch_buffer_header (b[6], LOAD);
2406 vlib_prefetch_buffer_header (b[7], LOAD);
2407
2408 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2409 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2410
2411 /*
2412 * pre-fetch the per-adjacency counters
2413 */
2414 if (do_counters)
2415 {
2416 vlib_prefetch_combined_counter (&adjacency_counters,
2417 thread_index, adj_index0);
2418 vlib_prefetch_combined_counter (&adjacency_counters,
2419 thread_index, adj_index1);
2420 }
2421
2422 ip0 = vlib_buffer_get_current (b[0]);
2423 ip1 = vlib_buffer_get_current (b[1]);
2424
2425 error0 = error1 = IP4_ERROR_NONE;
2426
2427 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2428 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2429
2430 /* Rewrite packet header and updates lengths. */
2431 adj0 = adj_get (adj_index0);
2432 adj1 = adj_get (adj_index1);
2433
2434 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2435 rw_len0 = adj0[0].rewrite_header.data_bytes;
2436 rw_len1 = adj1[0].rewrite_header.data_bytes;
2437 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2438 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2439
2440 p = vlib_buffer_get_current (b[2]);
2441 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2442 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2443
2444 p = vlib_buffer_get_current (b[3]);
2445 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2446 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2447
2448 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002449 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2450 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2451
2452 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2453 ip0_len = gso_mtu_sz (b[0]);
2454 if (do_gso && (b[1]->flags & VNET_BUFFER_F_GSO))
2455 ip1_len = gso_mtu_sz (b[1]);
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),
2461 next + 0, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002462 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002463 adj1[0].rewrite_header.max_l3_packet_bytes,
2464 ip1->flags_and_fragment_offset &
2465 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2466 next + 1, &error1);
2467
2468 if (is_mcast)
2469 {
2470 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2471 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2472 IP4_ERROR_SAME_INTERFACE : error0);
2473 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2474 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2475 IP4_ERROR_SAME_INTERFACE : error1);
2476 }
2477
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002478 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002479 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002480 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2481 {
2482 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002483 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002484 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2485 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2486
2487 if (PREDICT_FALSE
2488 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2489 vnet_feature_arc_start (lm->output_feature_arc_index,
2490 tx_sw_if_index0, &next_index, b[0]);
2491 next[0] = next_index;
2492 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002493 else
2494 {
2495 b[0]->error = error_node->errors[error0];
2496 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002497 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2498 {
2499 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002500 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002501
2502 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2503 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2504
2505 if (PREDICT_FALSE
2506 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2507 vnet_feature_arc_start (lm->output_feature_arc_index,
2508 tx_sw_if_index1, &next_index, b[1]);
2509 next[1] = next_index;
2510 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002511 else
2512 {
2513 b[1]->error = error_node->errors[error1];
2514 }
Neale Ranns25edf142019-03-22 08:12:48 +00002515 if (is_midchain)
2516 {
2517 calc_checksums (vm, b[0]);
2518 calc_checksums (vm, b[1]);
2519 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002520 /* Guess we are only writing on simple Ethernet header. */
2521 vnet_rewrite_two_headers (adj0[0], adj1[0],
2522 ip0, ip1, sizeof (ethernet_header_t));
2523
2524 /*
2525 * Bump the per-adjacency counters
2526 */
2527 if (do_counters)
2528 {
2529 vlib_increment_combined_counter
2530 (&adjacency_counters,
2531 thread_index,
2532 adj_index0, 1, vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2533
2534 vlib_increment_combined_counter
2535 (&adjacency_counters,
2536 thread_index,
2537 adj_index1, 1, vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2538 }
2539
2540 if (is_midchain)
2541 {
Neale Ranns25edf142019-03-22 08:12:48 +00002542 if (adj0->sub_type.midchain.fixup_func)
2543 adj0->sub_type.midchain.fixup_func
2544 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2545 if (adj1->sub_type.midchain.fixup_func)
2546 adj1->sub_type.midchain.fixup_func
2547 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002548 }
2549
2550 if (is_mcast)
2551 {
2552 /*
2553 * copy bytes from the IP address into the MAC rewrite
2554 */
2555 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2556 adj0->rewrite_header.dst_mcast_offset,
2557 &ip0->dst_address.as_u32, (u8 *) ip0);
2558 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
Zhiyong Yangb2ecc5d2018-12-13 14:09:40 +08002559 adj1->rewrite_header.dst_mcast_offset,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002560 &ip1->dst_address.as_u32, (u8 *) ip1);
2561 }
2562
2563 next += 2;
2564 b += 2;
2565 n_left_from -= 2;
2566 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002567#elif (CLIB_N_PREFETCHES >= 4)
2568 next = nexts;
2569 b = bufs;
2570 while (n_left_from >= 1)
2571 {
2572 ip_adjacency_t *adj0;
2573 ip4_header_t *ip0;
2574 u32 rw_len0, error0, adj_index0;
2575 u32 tx_sw_if_index0;
2576 u8 *p;
2577
2578 /* Prefetch next iteration */
2579 if (PREDICT_TRUE (n_left_from >= 4))
2580 {
2581 ip_adjacency_t *adj2;
2582 u32 adj_index2;
2583
2584 vlib_prefetch_buffer_header (b[3], LOAD);
2585 vlib_prefetch_buffer_data (b[2], LOAD);
2586
2587 /* Prefetch adj->rewrite_header */
2588 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2589 adj2 = adj_get (adj_index2);
2590 p = (u8 *) adj2;
2591 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2592 LOAD);
2593 }
2594
2595 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2596
2597 /*
2598 * Prefetch the per-adjacency counters
2599 */
2600 if (do_counters)
2601 {
2602 vlib_prefetch_combined_counter (&adjacency_counters,
2603 thread_index, adj_index0);
2604 }
2605
2606 ip0 = vlib_buffer_get_current (b[0]);
2607
2608 error0 = IP4_ERROR_NONE;
2609
2610 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2611
2612 /* Rewrite packet header and updates lengths. */
2613 adj0 = adj_get (adj_index0);
2614
2615 /* Rewrite header was prefetched. */
2616 rw_len0 = adj0[0].rewrite_header.data_bytes;
2617 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2618
2619 /* Check MTU of outgoing interface. */
2620 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2621
2622 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2623 ip0_len = gso_mtu_sz (b[0]);
2624
2625 ip4_mtu_check (b[0], ip0_len,
2626 adj0[0].rewrite_header.max_l3_packet_bytes,
2627 ip0->flags_and_fragment_offset &
2628 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2629 next + 0, &error0);
2630
2631 if (is_mcast)
2632 {
2633 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2634 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2635 IP4_ERROR_SAME_INTERFACE : error0);
2636 }
2637
2638 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2639 * to see the IP header */
2640 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2641 {
2642 u32 next_index = adj0[0].rewrite_header.next_index;
2643 vlib_buffer_advance (b[0], -(word) rw_len0);
2644 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2645 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2646
2647 if (PREDICT_FALSE
2648 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2649 vnet_feature_arc_start (lm->output_feature_arc_index,
2650 tx_sw_if_index0, &next_index, b[0]);
2651 next[0] = next_index;
2652 }
2653 else
2654 {
2655 b[0]->error = error_node->errors[error0];
2656 }
2657 if (is_midchain)
2658 {
2659 calc_checksums (vm, b[0]);
2660 }
2661 /* Guess we are only writing on simple Ethernet header. */
2662 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2663
2664 /*
2665 * Bump the per-adjacency counters
2666 */
2667 if (do_counters)
2668 {
2669 vlib_increment_combined_counter
2670 (&adjacency_counters,
2671 thread_index,
2672 adj_index0, 1, vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2673 }
2674
2675 if (is_midchain)
2676 {
2677 if (adj0->sub_type.midchain.fixup_func)
2678 adj0->sub_type.midchain.fixup_func
2679 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2680 }
2681
2682 if (is_mcast)
2683 {
2684 /*
2685 * copy bytes from the IP address into the MAC rewrite
2686 */
2687 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2688 adj0->rewrite_header.dst_mcast_offset,
2689 &ip0->dst_address.as_u32, (u8 *) ip0);
2690 }
2691
2692 next += 1;
2693 b += 1;
2694 n_left_from -= 1;
2695 }
2696#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002697
Ed Warnickecb9cada2015-12-08 15:45:58 -07002698 while (n_left_from > 0)
2699 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002700 ip_adjacency_t *adj0;
2701 ip4_header_t *ip0;
2702 u32 rw_len0, adj_index0, error0;
2703 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002704
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002705 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2706
2707 adj0 = adj_get (adj_index0);
2708
2709 if (do_counters)
2710 vlib_prefetch_combined_counter (&adjacency_counters,
2711 thread_index, adj_index0);
2712
2713 ip0 = vlib_buffer_get_current (b[0]);
2714
2715 error0 = IP4_ERROR_NONE;
2716
2717 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2718
2719
2720 /* Update packet buffer attributes/set output interface. */
2721 rw_len0 = adj0[0].rewrite_header.data_bytes;
2722 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2723
2724 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002725 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2726 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2727 ip0_len = gso_mtu_sz (b[0]);
2728
2729 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002730 adj0[0].rewrite_header.max_l3_packet_bytes,
2731 ip0->flags_and_fragment_offset &
2732 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2733 next + 0, &error0);
2734
2735 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002736 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002737 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2738 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2739 IP4_ERROR_SAME_INTERFACE : error0);
2740 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002741
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002742 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002743 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002744 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2745 {
2746 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002747 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002748 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2749 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002750
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002751 if (PREDICT_FALSE
2752 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2753 vnet_feature_arc_start (lm->output_feature_arc_index,
2754 tx_sw_if_index0, &next_index, b[0]);
2755 next[0] = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002756 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002757 else
2758 {
2759 b[0]->error = error_node->errors[error0];
2760 }
Neale Ranns25edf142019-03-22 08:12:48 +00002761 if (is_midchain)
2762 {
2763 calc_checksums (vm, b[0]);
2764 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002765 /* Guess we are only writing on simple Ethernet header. */
2766 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2767
2768 if (do_counters)
2769 vlib_increment_combined_counter
2770 (&adjacency_counters,
2771 thread_index, adj_index0, 1,
2772 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2773
2774 if (is_midchain)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002775 {
Neale Ranns25edf142019-03-22 08:12:48 +00002776 if (adj0->sub_type.midchain.fixup_func)
2777 adj0->sub_type.midchain.fixup_func
2778 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002779 }
Dave Barach75fc8542016-10-11 16:16:02 -04002780
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002781 if (is_mcast)
2782 {
2783 /*
2784 * copy bytes from the IP address into the MAC rewrite
2785 */
2786 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2787 adj0->rewrite_header.dst_mcast_offset,
2788 &ip0->dst_address.as_u32, (u8 *) ip0);
2789 }
2790
2791 next += 1;
2792 b += 1;
2793 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002794 }
2795
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002796
Ed Warnickecb9cada2015-12-08 15:45:58 -07002797 /* Need to do trace after rewrites to pick up new packet data. */
2798 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002799 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002800
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002801 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002802 return frame->n_vectors;
2803}
2804
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002805always_inline uword
2806ip4_rewrite_inline (vlib_main_t * vm,
2807 vlib_node_runtime_t * node,
2808 vlib_frame_t * frame,
2809 int do_counters, int is_midchain, int is_mcast)
2810{
2811 vnet_main_t *vnm = vnet_get_main ();
2812 if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
2813 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2814 is_midchain, is_mcast,
2815 1 /* do_gso */ );
2816 else
2817 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2818 is_midchain, is_mcast,
2819 0 /* no do_gso */ );
2820}
2821
Dave Barach132d51d2016-07-07 10:10:17 -04002822
Neale Rannsf06aea52016-11-29 06:51:37 -08002823/** @brief IPv4 rewrite node.
2824 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002825
2826 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2827 header checksum, fetch the ip adjacency, check the outbound mtu,
2828 apply the adjacency rewrite, and send pkts to the adjacency
2829 rewrite header's rewrite_next_index.
2830
2831 @param vm vlib_main_t corresponding to the current thread
2832 @param node vlib_node_runtime_t
2833 @param frame vlib_frame_t whose contents should be dispatched
2834
2835 @par Graph mechanics: buffer metadata, next index usage
2836
2837 @em Uses:
2838 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2839 - the rewrite adjacency index
2840 - <code>adj->lookup_next_index</code>
2841 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002842 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002843 - <code>adj->rewrite_header</code>
2844 - Rewrite string length, rewrite string, next_index
2845
2846 @em Sets:
2847 - <code>b->current_data, b->current_length</code>
2848 - Updated net of applying the rewrite string
2849
2850 <em>Next Indices:</em>
2851 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002852 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002853*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002854
2855VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2856 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002857{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002858 if (adj_are_counters_enabled ())
2859 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2860 else
2861 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002862}
2863
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002864VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2865 vlib_node_runtime_t * node,
2866 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002867{
2868 if (adj_are_counters_enabled ())
2869 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2870 else
2871 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2872}
2873
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002874VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2875 vlib_node_runtime_t * node,
2876 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002877{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002878 if (adj_are_counters_enabled ())
2879 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2880 else
2881 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002882}
2883
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002884VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2885 vlib_node_runtime_t * node,
2886 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002887{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002888 if (adj_are_counters_enabled ())
2889 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2890 else
2891 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002892}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002893
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002894VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2895 vlib_node_runtime_t * node,
2896 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002897{
2898 if (adj_are_counters_enabled ())
2899 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2900 else
2901 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2902}
2903
Neale Ranns32e1c012016-11-22 17:07:28 +00002904/* *INDENT-OFF* */
2905VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002906 .name = "ip4-rewrite",
2907 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002908
Neale Ranns32e1c012016-11-22 17:07:28 +00002909 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002910
Ole Troan313f7e22018-04-10 16:02:51 +02002911 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002912 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002913 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002914 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002915 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002916 },
2917};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002918
2919VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002920 .name = "ip4-rewrite-bcast",
2921 .vector_size = sizeof (u32),
2922
2923 .format_trace = format_ip4_rewrite_trace,
2924 .sibling_of = "ip4-rewrite",
2925};
Neale Ranns32e1c012016-11-22 17:07:28 +00002926
2927VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002928 .name = "ip4-rewrite-mcast",
2929 .vector_size = sizeof (u32),
2930
2931 .format_trace = format_ip4_rewrite_trace,
2932 .sibling_of = "ip4-rewrite",
2933};
Neale Ranns32e1c012016-11-22 17:07:28 +00002934
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002935VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002936 .name = "ip4-mcast-midchain",
2937 .vector_size = sizeof (u32),
2938
2939 .format_trace = format_ip4_rewrite_trace,
2940 .sibling_of = "ip4-rewrite",
2941};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002942
Neale Ranns32e1c012016-11-22 17:07:28 +00002943VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002944 .name = "ip4-midchain",
2945 .vector_size = sizeof (u32),
2946 .format_trace = format_ip4_forward_next_trace,
2947 .sibling_of = "ip4-rewrite",
2948};
Neale Ranns32e1c012016-11-22 17:07:28 +00002949/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002950
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002951static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2953{
2954 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002955 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002956 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002957
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002958 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002959
Neale Ranns04a75e32017-03-23 06:46:01 -07002960 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002961 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2962 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002963
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002964 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002965
Dave Barachd7cb1b52016-12-09 09:52:16 -05002966 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002967}
Dave Barach75fc8542016-10-11 16:16:02 -04002968
Ed Warnickecb9cada2015-12-08 15:45:58 -07002969static clib_error_t *
2970test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002971 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002972{
Billy McFall309fe062016-10-14 07:37:33 -04002973 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002974 u32 table_id = 0;
2975 f64 count = 1;
2976 u32 n;
2977 int i;
2978 ip4_address_t ip4_base_address;
2979 u64 errors = 0;
2980
Dave Barachd7cb1b52016-12-09 09:52:16 -05002981 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2982 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002983 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002984 {
2985 /* Make sure the entry exists. */
2986 fib = ip4_fib_get (table_id);
2987 if ((fib) && (fib->index != table_id))
2988 return clib_error_return (0, "<fib-index> %d does not exist",
2989 table_id);
2990 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002991 else if (unformat (input, "count %f", &count))
2992 ;
2993
2994 else if (unformat (input, "%U",
2995 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002996 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002997 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002998 return clib_error_return (0, "unknown input `%U'",
2999 format_unformat_error, input);
3000 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003001
3002 n = count;
3003
3004 for (i = 0; i < n; i++)
3005 {
3006 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003007 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003008
Dave Barach75fc8542016-10-11 16:16:02 -04003009 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05003010 clib_host_to_net_u32 (1 +
3011 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003012 }
3013
Dave Barach75fc8542016-10-11 16:16:02 -04003014 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003015 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3016 else
3017 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3018
3019 return 0;
3020}
3021
Billy McFall0683c9c2016-10-13 08:27:31 -04003022/*?
3023 * Perform a lookup of an IPv4 Address (or range of addresses) in the
3024 * given FIB table to determine if there is a conflict with the
3025 * adjacency table. The fib-id can be determined by using the
3026 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
3027 * of 0 is used.
3028 *
3029 * @todo This command uses fib-id, other commands use table-id (not
3030 * just a name, they are different indexes). Would like to change this
3031 * to table-id for consistency.
3032 *
3033 * @cliexpar
3034 * Example of how to run the test lookup command:
3035 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3036 * No errors in 2 lookups
3037 * @cliexend
3038?*/
3039/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003040VLIB_CLI_COMMAND (lookup_test_command, static) =
3041{
3042 .path = "test lookup",
3043 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3044 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003045};
Billy McFall0683c9c2016-10-13 08:27:31 -04003046/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003047
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003048#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003049int
3050vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003051{
Neale Ranns107e7d42017-04-11 09:55:19 -07003052 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003053
Neale Ranns107e7d42017-04-11 09:55:19 -07003054 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
3055
3056 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003057 return VNET_API_ERROR_NO_SUCH_FIB;
3058
Neale Ranns227038a2017-04-21 01:07:59 -07003059 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
3060 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061
Ed Warnickecb9cada2015-12-08 15:45:58 -07003062 return 0;
3063}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003064#endif
Dave Barach75fc8542016-10-11 16:16:02 -04003065
Ed Warnickecb9cada2015-12-08 15:45:58 -07003066static clib_error_t *
3067set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003068 unformat_input_t * input,
3069 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070{
3071 int matched = 0;
3072 u32 table_id = 0;
3073 u32 flow_hash_config = 0;
3074 int rv;
3075
Dave Barachd7cb1b52016-12-09 09:52:16 -05003076 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3077 {
3078 if (unformat (input, "table %d", &table_id))
3079 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003080#define _(a,v) \
3081 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003082 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003083#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003084 else
3085 break;
3086 }
Dave Barach75fc8542016-10-11 16:16:02 -04003087
Ed Warnickecb9cada2015-12-08 15:45:58 -07003088 if (matched == 0)
3089 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003090 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003091
Ed Warnickecb9cada2015-12-08 15:45:58 -07003092 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3093 switch (rv)
3094 {
3095 case 0:
3096 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003097
Ed Warnickecb9cada2015-12-08 15:45:58 -07003098 case VNET_API_ERROR_NO_SUCH_FIB:
3099 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003100
Ed Warnickecb9cada2015-12-08 15:45:58 -07003101 default:
3102 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3103 break;
3104 }
Dave Barach75fc8542016-10-11 16:16:02 -04003105
Ed Warnickecb9cada2015-12-08 15:45:58 -07003106 return 0;
3107}
Dave Barach75fc8542016-10-11 16:16:02 -04003108
Billy McFall0683c9c2016-10-13 08:27:31 -04003109/*?
3110 * Configure the set of IPv4 fields used by the flow hash.
3111 *
3112 * @cliexpar
3113 * Example of how to set the flow hash on a given table:
3114 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3115 * Example of display the configured flow hash:
3116 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003117 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3118 * 0.0.0.0/0
3119 * unicast-ip4-chain
3120 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3121 * [0] [@0]: dpo-drop ip6
3122 * 0.0.0.0/32
3123 * unicast-ip4-chain
3124 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3125 * [0] [@0]: dpo-drop ip6
3126 * 224.0.0.0/8
3127 * unicast-ip4-chain
3128 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3129 * [0] [@0]: dpo-drop ip6
3130 * 6.0.1.2/32
3131 * unicast-ip4-chain
3132 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3133 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3134 * 7.0.0.1/32
3135 * unicast-ip4-chain
3136 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3137 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3138 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3139 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3140 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3141 * 240.0.0.0/8
3142 * unicast-ip4-chain
3143 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3144 * [0] [@0]: dpo-drop ip6
3145 * 255.255.255.255/32
3146 * unicast-ip4-chain
3147 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3148 * [0] [@0]: dpo-drop ip6
3149 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3150 * 0.0.0.0/0
3151 * unicast-ip4-chain
3152 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3153 * [0] [@0]: dpo-drop ip6
3154 * 0.0.0.0/32
3155 * unicast-ip4-chain
3156 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3157 * [0] [@0]: dpo-drop ip6
3158 * 172.16.1.0/24
3159 * unicast-ip4-chain
3160 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3161 * [0] [@4]: ipv4-glean: af_packet0
3162 * 172.16.1.1/32
3163 * unicast-ip4-chain
3164 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3165 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3166 * 172.16.1.2/32
3167 * unicast-ip4-chain
3168 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3169 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3170 * 172.16.2.0/24
3171 * unicast-ip4-chain
3172 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3173 * [0] [@4]: ipv4-glean: af_packet1
3174 * 172.16.2.1/32
3175 * unicast-ip4-chain
3176 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3177 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3178 * 224.0.0.0/8
3179 * unicast-ip4-chain
3180 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3181 * [0] [@0]: dpo-drop ip6
3182 * 240.0.0.0/8
3183 * unicast-ip4-chain
3184 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3185 * [0] [@0]: dpo-drop ip6
3186 * 255.255.255.255/32
3187 * unicast-ip4-chain
3188 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3189 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003190 * @cliexend
3191?*/
3192/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003193VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3194{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003195 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003196 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003197 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003198 .function = set_ip_flow_hash_command_fn,
3199};
Billy McFall0683c9c2016-10-13 08:27:31 -04003200/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003201
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003202#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003203int
3204vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3205 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003206{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003207 vnet_main_t *vnm = vnet_get_main ();
3208 vnet_interface_main_t *im = &vnm->interface_main;
3209 ip4_main_t *ipm = &ip4_main;
3210 ip_lookup_main_t *lm = &ipm->lookup_main;
3211 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003212 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003213
3214 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3215 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3216
3217 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3218 return VNET_API_ERROR_NO_SUCH_ENTRY;
3219
3220 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003221 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003222
Neale Rannsdf089a82016-10-02 16:39:06 +01003223 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3224
3225 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003226 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003227 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003228 .fp_len = 32,
3229 .fp_proto = FIB_PROTOCOL_IP4,
3230 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003231 };
3232 u32 fib_index;
3233
Dave Barachd7cb1b52016-12-09 09:52:16 -05003234 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3235 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003236
3237
Dave Barachd7cb1b52016-12-09 09:52:16 -05003238 if (table_index != (u32) ~ 0)
3239 {
3240 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003241
Dave Barachd7cb1b52016-12-09 09:52:16 -05003242 dpo_set (&dpo,
3243 DPO_CLASSIFY,
3244 DPO_PROTO_IP4,
3245 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003246
Dave Barachd7cb1b52016-12-09 09:52:16 -05003247 fib_table_entry_special_dpo_add (fib_index,
3248 &pfx,
3249 FIB_SOURCE_CLASSIFY,
3250 FIB_ENTRY_FLAG_NONE, &dpo);
3251 dpo_reset (&dpo);
3252 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003253 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003254 {
3255 fib_table_entry_special_remove (fib_index,
3256 &pfx, FIB_SOURCE_CLASSIFY);
3257 }
3258 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003259
Ed Warnickecb9cada2015-12-08 15:45:58 -07003260 return 0;
3261}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003262#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003263
3264static clib_error_t *
3265set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003266 unformat_input_t * input,
3267 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003268{
3269 u32 table_index = ~0;
3270 int table_index_set = 0;
3271 u32 sw_if_index = ~0;
3272 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003273
Dave Barachd7cb1b52016-12-09 09:52:16 -05003274 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3275 {
3276 if (unformat (input, "table-index %d", &table_index))
3277 table_index_set = 1;
3278 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3279 vnet_get_main (), &sw_if_index))
3280 ;
3281 else
3282 break;
3283 }
Dave Barach75fc8542016-10-11 16:16:02 -04003284
Ed Warnickecb9cada2015-12-08 15:45:58 -07003285 if (table_index_set == 0)
3286 return clib_error_return (0, "classify table-index must be specified");
3287
3288 if (sw_if_index == ~0)
3289 return clib_error_return (0, "interface / subif must be specified");
3290
3291 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3292
3293 switch (rv)
3294 {
3295 case 0:
3296 break;
3297
3298 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3299 return clib_error_return (0, "No such interface");
3300
3301 case VNET_API_ERROR_NO_SUCH_ENTRY:
3302 return clib_error_return (0, "No such classifier table");
3303 }
3304 return 0;
3305}
3306
Billy McFall0683c9c2016-10-13 08:27:31 -04003307/*?
3308 * Assign a classification table to an interface. The classification
3309 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3310 * commands. Once the table is create, use this command to filter packets
3311 * on an interface.
3312 *
3313 * @cliexpar
3314 * Example of how to assign a classification table to an interface:
3315 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3316?*/
3317/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003318VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3319{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003320 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003321 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003322 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003323 .function = set_ip_classify_command_fn,
3324};
Billy McFall0683c9c2016-10-13 08:27:31 -04003325/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003326
Neale Ranns1ec36522017-11-29 05:20:37 -08003327static clib_error_t *
3328ip4_config (vlib_main_t * vm, unformat_input_t * input)
3329{
3330 ip4_main_t *im = &ip4_main;
3331 uword heapsize = 0;
3332
3333 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3334 {
3335 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3336 ;
3337 else
3338 return clib_error_return (0,
3339 "invalid heap-size parameter `%U'",
3340 format_unformat_error, input);
3341 }
3342
3343 im->mtrie_heap_size = heapsize;
3344
3345 return 0;
3346}
3347
3348VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3349
Dave Barachd7cb1b52016-12-09 09:52:16 -05003350/*
3351 * fd.io coding-style-patch-verification: ON
3352 *
3353 * Local Variables:
3354 * eval: (c-set-style "gnu")
3355 * End:
3356 */