blob: bb036c8e969e39b666266051d44a5fbb5552485c [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 Ranns0b6a8572019-10-30 17:34:14 +00001206 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,
Ole Troaneb284a12019-10-09 13:33:19 +02002296 u16 adj_packet_bytes, bool df, u16 * next,
2297 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002298{
2299 if (packet_len > adj_packet_bytes)
2300 {
2301 *error = IP4_ERROR_MTU_EXCEEDED;
2302 if (df)
2303 {
2304 icmp4_error_set_vnet_buffer
2305 (b, ICMP4_destination_unreachable,
2306 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2307 adj_packet_bytes);
2308 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2309 }
2310 else
2311 {
Ole Troan313f7e22018-04-10 16:02:51 +02002312 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002313 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00002314 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02002315 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2316 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002317 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002318 }
2319 }
2320}
2321
Neale Ranns0b6a8572019-10-30 17:34:14 +00002322/* increment TTL & update checksum.
2323 Works either endian, so no need for byte swap. */
2324static_always_inline void
2325ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2326{
2327 i32 ttl;
2328 u32 checksum;
2329 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2330 {
2331 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2332 return;
2333 }
2334
2335 ttl = ip->ttl;
2336
2337 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2338 checksum += checksum >= 0xffff;
2339
2340 ip->checksum = checksum;
2341 ttl += 1;
2342 ip->ttl = ttl;
2343
2344 ASSERT (ip->checksum == ip4_header_checksum (ip));
2345}
2346
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002347/* Decrement TTL & update checksum.
2348 Works either endian, so no need for byte swap. */
2349static_always_inline void
2350ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2351 u32 * error)
2352{
2353 i32 ttl;
2354 u32 checksum;
2355 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2356 {
2357 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2358 return;
2359 }
2360
2361 ttl = ip->ttl;
2362
2363 /* Input node should have reject packets with ttl 0. */
2364 ASSERT (ip->ttl > 0);
2365
2366 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2367 checksum += checksum >= 0xffff;
2368
2369 ip->checksum = checksum;
2370 ttl -= 1;
2371 ip->ttl = ttl;
2372
2373 /*
2374 * If the ttl drops below 1 when forwarding, generate
2375 * an ICMP response.
2376 */
2377 if (PREDICT_FALSE (ttl <= 0))
2378 {
2379 *error = IP4_ERROR_TIME_EXPIRED;
2380 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2381 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2382 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2383 0);
2384 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2385 }
2386
2387 /* Verify checksum. */
2388 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2389 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2390}
2391
2392
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002394ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2395 vlib_node_runtime_t * node,
2396 vlib_frame_t * frame,
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002397 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002398{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002399 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2400 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002401 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2402 u16 nexts[VLIB_FRAME_SIZE], *next;
2403 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002404 vlib_node_runtime_t *error_node =
2405 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002406
2407 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002408 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002409
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002410 vlib_get_buffers (vm, from, bufs, n_left_from);
2411 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2412
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002413#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002414 if (n_left_from >= 6)
2415 {
2416 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002417 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002418 vlib_prefetch_buffer_header (bufs[i], LOAD);
2419 }
2420
2421 next = nexts;
2422 b = bufs;
2423 while (n_left_from >= 8)
2424 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002425 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002426 ip4_header_t *ip0, *ip1;
2427 u32 rw_len0, error0, adj_index0;
2428 u32 rw_len1, error1, adj_index1;
2429 u32 tx_sw_if_index0, tx_sw_if_index1;
2430 u8 *p;
2431
2432 vlib_prefetch_buffer_header (b[6], LOAD);
2433 vlib_prefetch_buffer_header (b[7], LOAD);
2434
2435 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2436 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2437
2438 /*
2439 * pre-fetch the per-adjacency counters
2440 */
2441 if (do_counters)
2442 {
2443 vlib_prefetch_combined_counter (&adjacency_counters,
2444 thread_index, adj_index0);
2445 vlib_prefetch_combined_counter (&adjacency_counters,
2446 thread_index, adj_index1);
2447 }
2448
2449 ip0 = vlib_buffer_get_current (b[0]);
2450 ip1 = vlib_buffer_get_current (b[1]);
2451
2452 error0 = error1 = IP4_ERROR_NONE;
2453
2454 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2455 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2456
2457 /* Rewrite packet header and updates lengths. */
2458 adj0 = adj_get (adj_index0);
2459 adj1 = adj_get (adj_index1);
2460
2461 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2462 rw_len0 = adj0[0].rewrite_header.data_bytes;
2463 rw_len1 = adj1[0].rewrite_header.data_bytes;
2464 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2465 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2466
2467 p = vlib_buffer_get_current (b[2]);
2468 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2469 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2470
2471 p = vlib_buffer_get_current (b[3]);
2472 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2473 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2474
2475 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002476 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2477 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2478
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002479 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002480 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002481 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002482 ip1_len = gso_mtu_sz (b[1]);
2483
2484 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002485 adj0[0].rewrite_header.max_l3_packet_bytes,
2486 ip0->flags_and_fragment_offset &
2487 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002488 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002489 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002490 adj1[0].rewrite_header.max_l3_packet_bytes,
2491 ip1->flags_and_fragment_offset &
2492 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002493 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002494
2495 if (is_mcast)
2496 {
2497 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2498 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2499 IP4_ERROR_SAME_INTERFACE : error0);
2500 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2501 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2502 IP4_ERROR_SAME_INTERFACE : error1);
2503 }
2504
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002505 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002506 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002507 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2508 {
2509 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002510 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002511
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002512 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2513 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2514
2515 if (PREDICT_FALSE
2516 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2517 vnet_feature_arc_start (lm->output_feature_arc_index,
2518 tx_sw_if_index0, &next_index, b[0]);
2519 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002520 if (is_midchain)
2521 calc_checksums (vm, b[0]);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002522 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002523 else
2524 {
2525 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002526 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2527 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002528 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002529 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2530 {
2531 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002532 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002533
2534 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2535 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2536
2537 if (PREDICT_FALSE
2538 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2539 vnet_feature_arc_start (lm->output_feature_arc_index,
2540 tx_sw_if_index1, &next_index, b[1]);
2541 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002542 if (is_midchain)
2543 calc_checksums (vm, b[1]);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002544 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002545 else
2546 {
2547 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002548 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2549 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002550 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002551
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002552 /* Guess we are only writing on simple Ethernet header. */
2553 vnet_rewrite_two_headers (adj0[0], adj1[0],
2554 ip0, ip1, sizeof (ethernet_header_t));
2555
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002556 if (do_counters)
2557 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002558 if (error0 == IP4_ERROR_NONE)
2559 vlib_increment_combined_counter
2560 (&adjacency_counters,
2561 thread_index,
2562 adj_index0, 1,
2563 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002564
Neale Ranns0b6a8572019-10-30 17:34:14 +00002565 if (error1 == IP4_ERROR_NONE)
2566 vlib_increment_combined_counter
2567 (&adjacency_counters,
2568 thread_index,
2569 adj_index1, 1,
2570 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002571 }
2572
2573 if (is_midchain)
2574 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002575 if (error0 == IP4_ERROR_NONE && adj0->sub_type.midchain.fixup_func)
Neale Ranns25edf142019-03-22 08:12:48 +00002576 adj0->sub_type.midchain.fixup_func
2577 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002578 if (error1 == IP4_ERROR_NONE && adj1->sub_type.midchain.fixup_func)
Neale Ranns25edf142019-03-22 08:12:48 +00002579 adj1->sub_type.midchain.fixup_func
2580 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002581 }
2582
2583 if (is_mcast)
2584 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002585 /* copy bytes from the IP address into the MAC rewrite */
2586 if (error0 == IP4_ERROR_NONE)
2587 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2588 adj0->rewrite_header.dst_mcast_offset,
2589 &ip0->dst_address.as_u32, (u8 *) ip0);
2590 if (error1 == IP4_ERROR_NONE)
2591 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2592 adj1->rewrite_header.dst_mcast_offset,
2593 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002594 }
2595
2596 next += 2;
2597 b += 2;
2598 n_left_from -= 2;
2599 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002600#elif (CLIB_N_PREFETCHES >= 4)
2601 next = nexts;
2602 b = bufs;
2603 while (n_left_from >= 1)
2604 {
2605 ip_adjacency_t *adj0;
2606 ip4_header_t *ip0;
2607 u32 rw_len0, error0, adj_index0;
2608 u32 tx_sw_if_index0;
2609 u8 *p;
2610
2611 /* Prefetch next iteration */
2612 if (PREDICT_TRUE (n_left_from >= 4))
2613 {
2614 ip_adjacency_t *adj2;
2615 u32 adj_index2;
2616
2617 vlib_prefetch_buffer_header (b[3], LOAD);
2618 vlib_prefetch_buffer_data (b[2], LOAD);
2619
2620 /* Prefetch adj->rewrite_header */
2621 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2622 adj2 = adj_get (adj_index2);
2623 p = (u8 *) adj2;
2624 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2625 LOAD);
2626 }
2627
2628 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2629
2630 /*
2631 * Prefetch the per-adjacency counters
2632 */
2633 if (do_counters)
2634 {
2635 vlib_prefetch_combined_counter (&adjacency_counters,
2636 thread_index, adj_index0);
2637 }
2638
2639 ip0 = vlib_buffer_get_current (b[0]);
2640
2641 error0 = IP4_ERROR_NONE;
2642
2643 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2644
2645 /* Rewrite packet header and updates lengths. */
2646 adj0 = adj_get (adj_index0);
2647
2648 /* Rewrite header was prefetched. */
2649 rw_len0 = adj0[0].rewrite_header.data_bytes;
2650 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2651
2652 /* Check MTU of outgoing interface. */
2653 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2654
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002655 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002656 ip0_len = gso_mtu_sz (b[0]);
2657
2658 ip4_mtu_check (b[0], ip0_len,
2659 adj0[0].rewrite_header.max_l3_packet_bytes,
2660 ip0->flags_and_fragment_offset &
2661 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002662 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002663
2664 if (is_mcast)
2665 {
2666 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2667 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2668 IP4_ERROR_SAME_INTERFACE : error0);
2669 }
2670
2671 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2672 * to see the IP header */
2673 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2674 {
2675 u32 next_index = adj0[0].rewrite_header.next_index;
2676 vlib_buffer_advance (b[0], -(word) rw_len0);
2677 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2678 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2679
2680 if (PREDICT_FALSE
2681 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2682 vnet_feature_arc_start (lm->output_feature_arc_index,
2683 tx_sw_if_index0, &next_index, b[0]);
2684 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002685
2686 if (is_midchain)
2687 calc_checksums (vm, b[0]);
2688
2689 /* Guess we are only writing on simple Ethernet header. */
2690 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2691
2692 /*
2693 * Bump the per-adjacency counters
2694 */
2695 if (do_counters)
2696 vlib_increment_combined_counter
2697 (&adjacency_counters,
2698 thread_index,
2699 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2700 b[0]) + rw_len0);
2701
2702 if (is_midchain && adj0->sub_type.midchain.fixup_func)
2703 adj0->sub_type.midchain.fixup_func
2704 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2705
2706 if (is_mcast)
2707 /* copy bytes from the IP address into the MAC rewrite */
2708 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2709 adj0->rewrite_header.dst_mcast_offset,
2710 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002711 }
2712 else
2713 {
2714 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002715 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2716 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002717 }
2718
2719 next += 1;
2720 b += 1;
2721 n_left_from -= 1;
2722 }
2723#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002724
Ed Warnickecb9cada2015-12-08 15:45:58 -07002725 while (n_left_from > 0)
2726 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002727 ip_adjacency_t *adj0;
2728 ip4_header_t *ip0;
2729 u32 rw_len0, adj_index0, error0;
2730 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002731
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002732 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2733
2734 adj0 = adj_get (adj_index0);
2735
2736 if (do_counters)
2737 vlib_prefetch_combined_counter (&adjacency_counters,
2738 thread_index, adj_index0);
2739
2740 ip0 = vlib_buffer_get_current (b[0]);
2741
2742 error0 = IP4_ERROR_NONE;
2743
2744 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2745
2746
2747 /* Update packet buffer attributes/set output interface. */
2748 rw_len0 = adj0[0].rewrite_header.data_bytes;
2749 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2750
2751 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002752 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002753 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002754 ip0_len = gso_mtu_sz (b[0]);
2755
2756 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002757 adj0[0].rewrite_header.max_l3_packet_bytes,
2758 ip0->flags_and_fragment_offset &
2759 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002760 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002761
2762 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002763 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002764 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2765 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2766 IP4_ERROR_SAME_INTERFACE : error0);
2767 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002768
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002769 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002770 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002771 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2772 {
2773 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002774 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002775 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2776 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002777
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002778 if (PREDICT_FALSE
2779 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2780 vnet_feature_arc_start (lm->output_feature_arc_index,
2781 tx_sw_if_index0, &next_index, b[0]);
2782 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002783
2784 if (is_midchain)
2785 /* this acts on the packet that is about to be encapped */
2786 calc_checksums (vm, b[0]);
2787
2788 /* Guess we are only writing on simple Ethernet header. */
2789 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2790
2791 if (do_counters)
2792 vlib_increment_combined_counter
2793 (&adjacency_counters,
2794 thread_index, adj_index0, 1,
2795 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2796
2797 if (is_midchain && adj0->sub_type.midchain.fixup_func)
2798 adj0->sub_type.midchain.fixup_func
2799 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2800
2801 if (is_mcast)
2802 /* copy bytes from the IP address into the MAC rewrite */
2803 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2804 adj0->rewrite_header.dst_mcast_offset,
2805 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002806 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002807 else
2808 {
2809 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002810 /* undo the TTL decrement - we'll be back to do it again */
2811 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2812 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002813 }
2814
2815 next += 1;
2816 b += 1;
2817 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002818 }
2819
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002820
Ed Warnickecb9cada2015-12-08 15:45:58 -07002821 /* Need to do trace after rewrites to pick up new packet data. */
2822 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002823 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002824
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002825 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002826 return frame->n_vectors;
2827}
2828
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002829always_inline uword
2830ip4_rewrite_inline (vlib_main_t * vm,
2831 vlib_node_runtime_t * node,
2832 vlib_frame_t * frame,
2833 int do_counters, int is_midchain, int is_mcast)
2834{
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002835 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2836 is_midchain, is_mcast);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002837}
2838
Dave Barach132d51d2016-07-07 10:10:17 -04002839
Neale Rannsf06aea52016-11-29 06:51:37 -08002840/** @brief IPv4 rewrite node.
2841 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002842
2843 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2844 header checksum, fetch the ip adjacency, check the outbound mtu,
2845 apply the adjacency rewrite, and send pkts to the adjacency
2846 rewrite header's rewrite_next_index.
2847
2848 @param vm vlib_main_t corresponding to the current thread
2849 @param node vlib_node_runtime_t
2850 @param frame vlib_frame_t whose contents should be dispatched
2851
2852 @par Graph mechanics: buffer metadata, next index usage
2853
2854 @em Uses:
2855 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2856 - the rewrite adjacency index
2857 - <code>adj->lookup_next_index</code>
2858 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002859 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002860 - <code>adj->rewrite_header</code>
2861 - Rewrite string length, rewrite string, next_index
2862
2863 @em Sets:
2864 - <code>b->current_data, b->current_length</code>
2865 - Updated net of applying the rewrite string
2866
2867 <em>Next Indices:</em>
2868 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002869 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002870*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002871
2872VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2873 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002874{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002875 if (adj_are_counters_enabled ())
2876 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2877 else
2878 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002879}
2880
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002881VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2882 vlib_node_runtime_t * node,
2883 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002884{
2885 if (adj_are_counters_enabled ())
2886 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2887 else
2888 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2889}
2890
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002891VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2892 vlib_node_runtime_t * node,
2893 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002894{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002895 if (adj_are_counters_enabled ())
2896 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2897 else
2898 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002899}
2900
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002901VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2902 vlib_node_runtime_t * node,
2903 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002904{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002905 if (adj_are_counters_enabled ())
2906 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2907 else
2908 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002909}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002910
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002911VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2912 vlib_node_runtime_t * node,
2913 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002914{
2915 if (adj_are_counters_enabled ())
2916 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2917 else
2918 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2919}
2920
Neale Ranns32e1c012016-11-22 17:07:28 +00002921/* *INDENT-OFF* */
2922VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002923 .name = "ip4-rewrite",
2924 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925
Neale Ranns32e1c012016-11-22 17:07:28 +00002926 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002927
Ole Troan313f7e22018-04-10 16:02:51 +02002928 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002929 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002930 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002931 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002932 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002933 },
2934};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002935
2936VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002937 .name = "ip4-rewrite-bcast",
2938 .vector_size = sizeof (u32),
2939
2940 .format_trace = format_ip4_rewrite_trace,
2941 .sibling_of = "ip4-rewrite",
2942};
Neale Ranns32e1c012016-11-22 17:07:28 +00002943
2944VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002945 .name = "ip4-rewrite-mcast",
2946 .vector_size = sizeof (u32),
2947
2948 .format_trace = format_ip4_rewrite_trace,
2949 .sibling_of = "ip4-rewrite",
2950};
Neale Ranns32e1c012016-11-22 17:07:28 +00002951
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002952VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002953 .name = "ip4-mcast-midchain",
2954 .vector_size = sizeof (u32),
2955
2956 .format_trace = format_ip4_rewrite_trace,
2957 .sibling_of = "ip4-rewrite",
2958};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002959
Neale Ranns32e1c012016-11-22 17:07:28 +00002960VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002961 .name = "ip4-midchain",
2962 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002963 .format_trace = format_ip4_rewrite_trace,
2964 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002965};
Neale Ranns32e1c012016-11-22 17:07:28 +00002966/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002967
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002968static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002969ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2970{
2971 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002972 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002973 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002974
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002975 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002976
Neale Ranns04a75e32017-03-23 06:46:01 -07002977 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002978 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2979 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002980
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002981 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002982
Dave Barachd7cb1b52016-12-09 09:52:16 -05002983 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002984}
Dave Barach75fc8542016-10-11 16:16:02 -04002985
Ed Warnickecb9cada2015-12-08 15:45:58 -07002986static clib_error_t *
2987test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002988 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002989{
Billy McFall309fe062016-10-14 07:37:33 -04002990 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002991 u32 table_id = 0;
2992 f64 count = 1;
2993 u32 n;
2994 int i;
2995 ip4_address_t ip4_base_address;
2996 u64 errors = 0;
2997
Dave Barachd7cb1b52016-12-09 09:52:16 -05002998 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2999 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07003000 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003001 {
3002 /* Make sure the entry exists. */
3003 fib = ip4_fib_get (table_id);
3004 if ((fib) && (fib->index != table_id))
3005 return clib_error_return (0, "<fib-index> %d does not exist",
3006 table_id);
3007 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003008 else if (unformat (input, "count %f", &count))
3009 ;
3010
3011 else if (unformat (input, "%U",
3012 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003013 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003014 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003015 return clib_error_return (0, "unknown input `%U'",
3016 format_unformat_error, input);
3017 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003018
3019 n = count;
3020
3021 for (i = 0; i < n; i++)
3022 {
3023 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003024 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025
Dave Barach75fc8542016-10-11 16:16:02 -04003026 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05003027 clib_host_to_net_u32 (1 +
3028 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003029 }
3030
Dave Barach75fc8542016-10-11 16:16:02 -04003031 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3033 else
3034 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3035
3036 return 0;
3037}
3038
Billy McFall0683c9c2016-10-13 08:27:31 -04003039/*?
3040 * Perform a lookup of an IPv4 Address (or range of addresses) in the
3041 * given FIB table to determine if there is a conflict with the
3042 * adjacency table. The fib-id can be determined by using the
3043 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
3044 * of 0 is used.
3045 *
3046 * @todo This command uses fib-id, other commands use table-id (not
3047 * just a name, they are different indexes). Would like to change this
3048 * to table-id for consistency.
3049 *
3050 * @cliexpar
3051 * Example of how to run the test lookup command:
3052 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3053 * No errors in 2 lookups
3054 * @cliexend
3055?*/
3056/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003057VLIB_CLI_COMMAND (lookup_test_command, static) =
3058{
3059 .path = "test lookup",
3060 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3061 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003062};
Billy McFall0683c9c2016-10-13 08:27:31 -04003063/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003064
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003065#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003066int
3067vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003068{
Neale Ranns107e7d42017-04-11 09:55:19 -07003069 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070
Neale Ranns107e7d42017-04-11 09:55:19 -07003071 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
3072
3073 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003074 return VNET_API_ERROR_NO_SUCH_FIB;
3075
Neale Ranns227038a2017-04-21 01:07:59 -07003076 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
3077 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003078
Ed Warnickecb9cada2015-12-08 15:45:58 -07003079 return 0;
3080}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003081#endif
Dave Barach75fc8542016-10-11 16:16:02 -04003082
Ed Warnickecb9cada2015-12-08 15:45:58 -07003083static clib_error_t *
3084set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003085 unformat_input_t * input,
3086 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087{
3088 int matched = 0;
3089 u32 table_id = 0;
3090 u32 flow_hash_config = 0;
3091 int rv;
3092
Dave Barachd7cb1b52016-12-09 09:52:16 -05003093 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3094 {
3095 if (unformat (input, "table %d", &table_id))
3096 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003097#define _(a,v) \
3098 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003099 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003100#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003101 else
3102 break;
3103 }
Dave Barach75fc8542016-10-11 16:16:02 -04003104
Ed Warnickecb9cada2015-12-08 15:45:58 -07003105 if (matched == 0)
3106 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003107 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003108
Ed Warnickecb9cada2015-12-08 15:45:58 -07003109 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3110 switch (rv)
3111 {
3112 case 0:
3113 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003114
Ed Warnickecb9cada2015-12-08 15:45:58 -07003115 case VNET_API_ERROR_NO_SUCH_FIB:
3116 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003117
Ed Warnickecb9cada2015-12-08 15:45:58 -07003118 default:
3119 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3120 break;
3121 }
Dave Barach75fc8542016-10-11 16:16:02 -04003122
Ed Warnickecb9cada2015-12-08 15:45:58 -07003123 return 0;
3124}
Dave Barach75fc8542016-10-11 16:16:02 -04003125
Billy McFall0683c9c2016-10-13 08:27:31 -04003126/*?
3127 * Configure the set of IPv4 fields used by the flow hash.
3128 *
3129 * @cliexpar
3130 * Example of how to set the flow hash on a given table:
3131 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3132 * Example of display the configured flow hash:
3133 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003134 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3135 * 0.0.0.0/0
3136 * unicast-ip4-chain
3137 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3138 * [0] [@0]: dpo-drop ip6
3139 * 0.0.0.0/32
3140 * unicast-ip4-chain
3141 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3142 * [0] [@0]: dpo-drop ip6
3143 * 224.0.0.0/8
3144 * unicast-ip4-chain
3145 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3146 * [0] [@0]: dpo-drop ip6
3147 * 6.0.1.2/32
3148 * unicast-ip4-chain
3149 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3150 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3151 * 7.0.0.1/32
3152 * unicast-ip4-chain
3153 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3154 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3155 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3156 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3157 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3158 * 240.0.0.0/8
3159 * unicast-ip4-chain
3160 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3161 * [0] [@0]: dpo-drop ip6
3162 * 255.255.255.255/32
3163 * unicast-ip4-chain
3164 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3165 * [0] [@0]: dpo-drop ip6
3166 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3167 * 0.0.0.0/0
3168 * unicast-ip4-chain
3169 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3170 * [0] [@0]: dpo-drop ip6
3171 * 0.0.0.0/32
3172 * unicast-ip4-chain
3173 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3174 * [0] [@0]: dpo-drop ip6
3175 * 172.16.1.0/24
3176 * unicast-ip4-chain
3177 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3178 * [0] [@4]: ipv4-glean: af_packet0
3179 * 172.16.1.1/32
3180 * unicast-ip4-chain
3181 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3182 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3183 * 172.16.1.2/32
3184 * unicast-ip4-chain
3185 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3186 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3187 * 172.16.2.0/24
3188 * unicast-ip4-chain
3189 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3190 * [0] [@4]: ipv4-glean: af_packet1
3191 * 172.16.2.1/32
3192 * unicast-ip4-chain
3193 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3194 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3195 * 224.0.0.0/8
3196 * unicast-ip4-chain
3197 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3198 * [0] [@0]: dpo-drop ip6
3199 * 240.0.0.0/8
3200 * unicast-ip4-chain
3201 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3202 * [0] [@0]: dpo-drop ip6
3203 * 255.255.255.255/32
3204 * unicast-ip4-chain
3205 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3206 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003207 * @cliexend
3208?*/
3209/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003210VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3211{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003212 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003213 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003214 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003215 .function = set_ip_flow_hash_command_fn,
3216};
Billy McFall0683c9c2016-10-13 08:27:31 -04003217/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003218
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003219#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003220int
3221vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3222 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003223{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003224 vnet_main_t *vnm = vnet_get_main ();
3225 vnet_interface_main_t *im = &vnm->interface_main;
3226 ip4_main_t *ipm = &ip4_main;
3227 ip_lookup_main_t *lm = &ipm->lookup_main;
3228 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003229 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003230
3231 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3232 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3233
3234 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3235 return VNET_API_ERROR_NO_SUCH_ENTRY;
3236
3237 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003238 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003239
Neale Rannsdf089a82016-10-02 16:39:06 +01003240 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3241
3242 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003243 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003244 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003245 .fp_len = 32,
3246 .fp_proto = FIB_PROTOCOL_IP4,
3247 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003248 };
3249 u32 fib_index;
3250
Dave Barachd7cb1b52016-12-09 09:52:16 -05003251 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3252 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003253
3254
Dave Barachd7cb1b52016-12-09 09:52:16 -05003255 if (table_index != (u32) ~ 0)
3256 {
3257 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003258
Dave Barachd7cb1b52016-12-09 09:52:16 -05003259 dpo_set (&dpo,
3260 DPO_CLASSIFY,
3261 DPO_PROTO_IP4,
3262 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003263
Dave Barachd7cb1b52016-12-09 09:52:16 -05003264 fib_table_entry_special_dpo_add (fib_index,
3265 &pfx,
3266 FIB_SOURCE_CLASSIFY,
3267 FIB_ENTRY_FLAG_NONE, &dpo);
3268 dpo_reset (&dpo);
3269 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003270 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003271 {
3272 fib_table_entry_special_remove (fib_index,
3273 &pfx, FIB_SOURCE_CLASSIFY);
3274 }
3275 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003276
Ed Warnickecb9cada2015-12-08 15:45:58 -07003277 return 0;
3278}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003279#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003280
3281static clib_error_t *
3282set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003283 unformat_input_t * input,
3284 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003285{
3286 u32 table_index = ~0;
3287 int table_index_set = 0;
3288 u32 sw_if_index = ~0;
3289 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003290
Dave Barachd7cb1b52016-12-09 09:52:16 -05003291 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3292 {
3293 if (unformat (input, "table-index %d", &table_index))
3294 table_index_set = 1;
3295 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3296 vnet_get_main (), &sw_if_index))
3297 ;
3298 else
3299 break;
3300 }
Dave Barach75fc8542016-10-11 16:16:02 -04003301
Ed Warnickecb9cada2015-12-08 15:45:58 -07003302 if (table_index_set == 0)
3303 return clib_error_return (0, "classify table-index must be specified");
3304
3305 if (sw_if_index == ~0)
3306 return clib_error_return (0, "interface / subif must be specified");
3307
3308 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3309
3310 switch (rv)
3311 {
3312 case 0:
3313 break;
3314
3315 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3316 return clib_error_return (0, "No such interface");
3317
3318 case VNET_API_ERROR_NO_SUCH_ENTRY:
3319 return clib_error_return (0, "No such classifier table");
3320 }
3321 return 0;
3322}
3323
Billy McFall0683c9c2016-10-13 08:27:31 -04003324/*?
3325 * Assign a classification table to an interface. The classification
3326 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3327 * commands. Once the table is create, use this command to filter packets
3328 * on an interface.
3329 *
3330 * @cliexpar
3331 * Example of how to assign a classification table to an interface:
3332 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3333?*/
3334/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003335VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3336{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003337 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003338 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003339 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003340 .function = set_ip_classify_command_fn,
3341};
Billy McFall0683c9c2016-10-13 08:27:31 -04003342/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003343
Neale Ranns1ec36522017-11-29 05:20:37 -08003344static clib_error_t *
3345ip4_config (vlib_main_t * vm, unformat_input_t * input)
3346{
3347 ip4_main_t *im = &ip4_main;
3348 uword heapsize = 0;
3349
3350 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3351 {
3352 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3353 ;
3354 else
3355 return clib_error_return (0,
3356 "invalid heap-size parameter `%U'",
3357 format_unformat_error, input);
3358 }
3359
3360 im->mtrie_heap_size = heapsize;
3361
3362 return 0;
3363}
3364
3365VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3366
Dave Barachd7cb1b52016-12-09 09:52:16 -05003367/*
3368 * fd.io coding-style-patch-verification: ON
3369 *
3370 * Local Variables:
3371 * eval: (c-set-style "gnu")
3372 * End:
3373 */