blob: a67b0618f86dc037a9f720facc1c47d5bb0fa07c [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,
2397 int do_counters, int is_midchain, int is_mcast,
2398 int do_gso)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002399{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002400 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2401 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002402 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2403 u16 nexts[VLIB_FRAME_SIZE], *next;
2404 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002405 vlib_node_runtime_t *error_node =
2406 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002407
2408 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002409 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002410
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002411 vlib_get_buffers (vm, from, bufs, n_left_from);
2412 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2413
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002414#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002415 if (n_left_from >= 6)
2416 {
2417 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002418 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002419 vlib_prefetch_buffer_header (bufs[i], LOAD);
2420 }
2421
2422 next = nexts;
2423 b = bufs;
2424 while (n_left_from >= 8)
2425 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002426 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002427 ip4_header_t *ip0, *ip1;
2428 u32 rw_len0, error0, adj_index0;
2429 u32 rw_len1, error1, adj_index1;
2430 u32 tx_sw_if_index0, tx_sw_if_index1;
2431 u8 *p;
2432
2433 vlib_prefetch_buffer_header (b[6], LOAD);
2434 vlib_prefetch_buffer_header (b[7], LOAD);
2435
2436 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2437 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2438
2439 /*
2440 * pre-fetch the per-adjacency counters
2441 */
2442 if (do_counters)
2443 {
2444 vlib_prefetch_combined_counter (&adjacency_counters,
2445 thread_index, adj_index0);
2446 vlib_prefetch_combined_counter (&adjacency_counters,
2447 thread_index, adj_index1);
2448 }
2449
2450 ip0 = vlib_buffer_get_current (b[0]);
2451 ip1 = vlib_buffer_get_current (b[1]);
2452
2453 error0 = error1 = IP4_ERROR_NONE;
2454
2455 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2456 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2457
2458 /* Rewrite packet header and updates lengths. */
2459 adj0 = adj_get (adj_index0);
2460 adj1 = adj_get (adj_index1);
2461
2462 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2463 rw_len0 = adj0[0].rewrite_header.data_bytes;
2464 rw_len1 = adj1[0].rewrite_header.data_bytes;
2465 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2466 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2467
2468 p = vlib_buffer_get_current (b[2]);
2469 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2470 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2471
2472 p = vlib_buffer_get_current (b[3]);
2473 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2474 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2475
2476 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002477 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2478 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2479
2480 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2481 ip0_len = gso_mtu_sz (b[0]);
2482 if (do_gso && (b[1]->flags & VNET_BUFFER_F_GSO))
2483 ip1_len = gso_mtu_sz (b[1]);
2484
2485 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002486 adj0[0].rewrite_header.max_l3_packet_bytes,
2487 ip0->flags_and_fragment_offset &
2488 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002489 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002490 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002491 adj1[0].rewrite_header.max_l3_packet_bytes,
2492 ip1->flags_and_fragment_offset &
2493 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002494 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002495
2496 if (is_mcast)
2497 {
2498 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2499 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2500 IP4_ERROR_SAME_INTERFACE : error0);
2501 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2502 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2503 IP4_ERROR_SAME_INTERFACE : error1);
2504 }
2505
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002506 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002507 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002508 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2509 {
2510 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002511 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002512
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002513 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2514 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2515
2516 if (PREDICT_FALSE
2517 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2518 vnet_feature_arc_start (lm->output_feature_arc_index,
2519 tx_sw_if_index0, &next_index, b[0]);
2520 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002521 if (is_midchain)
2522 calc_checksums (vm, b[0]);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002523 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002524 else
2525 {
2526 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002527 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2528 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002529 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002530 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2531 {
2532 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002533 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002534
2535 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2536 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2537
2538 if (PREDICT_FALSE
2539 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2540 vnet_feature_arc_start (lm->output_feature_arc_index,
2541 tx_sw_if_index1, &next_index, b[1]);
2542 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002543 if (is_midchain)
2544 calc_checksums (vm, b[1]);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002545 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002546 else
2547 {
2548 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002549 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2550 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002551 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002552
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002553 /* Guess we are only writing on simple Ethernet header. */
2554 vnet_rewrite_two_headers (adj0[0], adj1[0],
2555 ip0, ip1, sizeof (ethernet_header_t));
2556
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002557 if (do_counters)
2558 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002559 if (error0 == IP4_ERROR_NONE)
2560 vlib_increment_combined_counter
2561 (&adjacency_counters,
2562 thread_index,
2563 adj_index0, 1,
2564 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002565
Neale Ranns0b6a8572019-10-30 17:34:14 +00002566 if (error1 == IP4_ERROR_NONE)
2567 vlib_increment_combined_counter
2568 (&adjacency_counters,
2569 thread_index,
2570 adj_index1, 1,
2571 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002572 }
2573
2574 if (is_midchain)
2575 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002576 if (error0 == IP4_ERROR_NONE && adj0->sub_type.midchain.fixup_func)
Neale Ranns25edf142019-03-22 08:12:48 +00002577 adj0->sub_type.midchain.fixup_func
2578 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002579 if (error1 == IP4_ERROR_NONE && adj1->sub_type.midchain.fixup_func)
Neale Ranns25edf142019-03-22 08:12:48 +00002580 adj1->sub_type.midchain.fixup_func
2581 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002582 }
2583
2584 if (is_mcast)
2585 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002586 /* copy bytes from the IP address into the MAC rewrite */
2587 if (error0 == IP4_ERROR_NONE)
2588 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2589 adj0->rewrite_header.dst_mcast_offset,
2590 &ip0->dst_address.as_u32, (u8 *) ip0);
2591 if (error1 == IP4_ERROR_NONE)
2592 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2593 adj1->rewrite_header.dst_mcast_offset,
2594 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002595 }
2596
2597 next += 2;
2598 b += 2;
2599 n_left_from -= 2;
2600 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002601#elif (CLIB_N_PREFETCHES >= 4)
2602 next = nexts;
2603 b = bufs;
2604 while (n_left_from >= 1)
2605 {
2606 ip_adjacency_t *adj0;
2607 ip4_header_t *ip0;
2608 u32 rw_len0, error0, adj_index0;
2609 u32 tx_sw_if_index0;
2610 u8 *p;
2611
2612 /* Prefetch next iteration */
2613 if (PREDICT_TRUE (n_left_from >= 4))
2614 {
2615 ip_adjacency_t *adj2;
2616 u32 adj_index2;
2617
2618 vlib_prefetch_buffer_header (b[3], LOAD);
2619 vlib_prefetch_buffer_data (b[2], LOAD);
2620
2621 /* Prefetch adj->rewrite_header */
2622 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2623 adj2 = adj_get (adj_index2);
2624 p = (u8 *) adj2;
2625 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2626 LOAD);
2627 }
2628
2629 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2630
2631 /*
2632 * Prefetch the per-adjacency counters
2633 */
2634 if (do_counters)
2635 {
2636 vlib_prefetch_combined_counter (&adjacency_counters,
2637 thread_index, adj_index0);
2638 }
2639
2640 ip0 = vlib_buffer_get_current (b[0]);
2641
2642 error0 = IP4_ERROR_NONE;
2643
2644 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2645
2646 /* Rewrite packet header and updates lengths. */
2647 adj0 = adj_get (adj_index0);
2648
2649 /* Rewrite header was prefetched. */
2650 rw_len0 = adj0[0].rewrite_header.data_bytes;
2651 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2652
2653 /* Check MTU of outgoing interface. */
2654 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2655
2656 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2657 ip0_len = gso_mtu_sz (b[0]);
2658
2659 ip4_mtu_check (b[0], ip0_len,
2660 adj0[0].rewrite_header.max_l3_packet_bytes,
2661 ip0->flags_and_fragment_offset &
2662 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002663 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002664
2665 if (is_mcast)
2666 {
2667 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2668 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2669 IP4_ERROR_SAME_INTERFACE : error0);
2670 }
2671
2672 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2673 * to see the IP header */
2674 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2675 {
2676 u32 next_index = adj0[0].rewrite_header.next_index;
2677 vlib_buffer_advance (b[0], -(word) rw_len0);
2678 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2679 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2680
2681 if (PREDICT_FALSE
2682 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2683 vnet_feature_arc_start (lm->output_feature_arc_index,
2684 tx_sw_if_index0, &next_index, b[0]);
2685 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002686
2687 if (is_midchain)
2688 calc_checksums (vm, b[0]);
2689
2690 /* Guess we are only writing on simple Ethernet header. */
2691 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2692
2693 /*
2694 * Bump the per-adjacency counters
2695 */
2696 if (do_counters)
2697 vlib_increment_combined_counter
2698 (&adjacency_counters,
2699 thread_index,
2700 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2701 b[0]) + rw_len0);
2702
2703 if (is_midchain && adj0->sub_type.midchain.fixup_func)
2704 adj0->sub_type.midchain.fixup_func
2705 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2706
2707 if (is_mcast)
2708 /* copy bytes from the IP address into the MAC rewrite */
2709 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2710 adj0->rewrite_header.dst_mcast_offset,
2711 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002712 }
2713 else
2714 {
2715 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002716 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2717 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002718 }
2719
2720 next += 1;
2721 b += 1;
2722 n_left_from -= 1;
2723 }
2724#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002725
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726 while (n_left_from > 0)
2727 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002728 ip_adjacency_t *adj0;
2729 ip4_header_t *ip0;
2730 u32 rw_len0, adj_index0, error0;
2731 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002733 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2734
2735 adj0 = adj_get (adj_index0);
2736
2737 if (do_counters)
2738 vlib_prefetch_combined_counter (&adjacency_counters,
2739 thread_index, adj_index0);
2740
2741 ip0 = vlib_buffer_get_current (b[0]);
2742
2743 error0 = IP4_ERROR_NONE;
2744
2745 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2746
2747
2748 /* Update packet buffer attributes/set output interface. */
2749 rw_len0 = adj0[0].rewrite_header.data_bytes;
2750 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2751
2752 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002753 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2754 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2755 ip0_len = gso_mtu_sz (b[0]);
2756
2757 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002758 adj0[0].rewrite_header.max_l3_packet_bytes,
2759 ip0->flags_and_fragment_offset &
2760 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002761 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002762
2763 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002764 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002765 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2766 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2767 IP4_ERROR_SAME_INTERFACE : error0);
2768 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002769
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002770 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002771 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002772 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2773 {
2774 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002775 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002776 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2777 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002778
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002779 if (PREDICT_FALSE
2780 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2781 vnet_feature_arc_start (lm->output_feature_arc_index,
2782 tx_sw_if_index0, &next_index, b[0]);
2783 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002784
2785 if (is_midchain)
2786 /* this acts on the packet that is about to be encapped */
2787 calc_checksums (vm, b[0]);
2788
2789 /* Guess we are only writing on simple Ethernet header. */
2790 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2791
2792 if (do_counters)
2793 vlib_increment_combined_counter
2794 (&adjacency_counters,
2795 thread_index, adj_index0, 1,
2796 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2797
2798 if (is_midchain && adj0->sub_type.midchain.fixup_func)
2799 adj0->sub_type.midchain.fixup_func
2800 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2801
2802 if (is_mcast)
2803 /* copy bytes from the IP address into the MAC rewrite */
2804 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2805 adj0->rewrite_header.dst_mcast_offset,
2806 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002807 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002808 else
2809 {
2810 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002811 /* undo the TTL decrement - we'll be back to do it again */
2812 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2813 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002814 }
2815
2816 next += 1;
2817 b += 1;
2818 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002819 }
2820
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002821
Ed Warnickecb9cada2015-12-08 15:45:58 -07002822 /* Need to do trace after rewrites to pick up new packet data. */
2823 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002824 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002825
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002826 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002827 return frame->n_vectors;
2828}
2829
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002830always_inline uword
2831ip4_rewrite_inline (vlib_main_t * vm,
2832 vlib_node_runtime_t * node,
2833 vlib_frame_t * frame,
2834 int do_counters, int is_midchain, int is_mcast)
2835{
2836 vnet_main_t *vnm = vnet_get_main ();
2837 if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
2838 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2839 is_midchain, is_mcast,
2840 1 /* do_gso */ );
2841 else
2842 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2843 is_midchain, is_mcast,
2844 0 /* no do_gso */ );
2845}
2846
Dave Barach132d51d2016-07-07 10:10:17 -04002847
Neale Rannsf06aea52016-11-29 06:51:37 -08002848/** @brief IPv4 rewrite node.
2849 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002850
2851 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2852 header checksum, fetch the ip adjacency, check the outbound mtu,
2853 apply the adjacency rewrite, and send pkts to the adjacency
2854 rewrite header's rewrite_next_index.
2855
2856 @param vm vlib_main_t corresponding to the current thread
2857 @param node vlib_node_runtime_t
2858 @param frame vlib_frame_t whose contents should be dispatched
2859
2860 @par Graph mechanics: buffer metadata, next index usage
2861
2862 @em Uses:
2863 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2864 - the rewrite adjacency index
2865 - <code>adj->lookup_next_index</code>
2866 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002867 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002868 - <code>adj->rewrite_header</code>
2869 - Rewrite string length, rewrite string, next_index
2870
2871 @em Sets:
2872 - <code>b->current_data, b->current_length</code>
2873 - Updated net of applying the rewrite string
2874
2875 <em>Next Indices:</em>
2876 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002877 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002878*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002879
2880VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2881 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002882{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002883 if (adj_are_counters_enabled ())
2884 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2885 else
2886 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002887}
2888
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002889VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2890 vlib_node_runtime_t * node,
2891 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002892{
2893 if (adj_are_counters_enabled ())
2894 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2895 else
2896 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2897}
2898
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002899VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2900 vlib_node_runtime_t * node,
2901 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002902{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002903 if (adj_are_counters_enabled ())
2904 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2905 else
2906 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002907}
2908
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002909VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2910 vlib_node_runtime_t * node,
2911 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002912{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002913 if (adj_are_counters_enabled ())
2914 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2915 else
2916 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002917}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002918
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002919VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2920 vlib_node_runtime_t * node,
2921 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002922{
2923 if (adj_are_counters_enabled ())
2924 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2925 else
2926 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2927}
2928
Neale Ranns32e1c012016-11-22 17:07:28 +00002929/* *INDENT-OFF* */
2930VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002931 .name = "ip4-rewrite",
2932 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002933
Neale Ranns32e1c012016-11-22 17:07:28 +00002934 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002935
Ole Troan313f7e22018-04-10 16:02:51 +02002936 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002937 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002938 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002939 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002940 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002941 },
2942};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002943
2944VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002945 .name = "ip4-rewrite-bcast",
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
2952VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002953 .name = "ip4-rewrite-mcast",
2954 .vector_size = sizeof (u32),
2955
2956 .format_trace = format_ip4_rewrite_trace,
2957 .sibling_of = "ip4-rewrite",
2958};
Neale Ranns32e1c012016-11-22 17:07:28 +00002959
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002960VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002961 .name = "ip4-mcast-midchain",
2962 .vector_size = sizeof (u32),
2963
2964 .format_trace = format_ip4_rewrite_trace,
2965 .sibling_of = "ip4-rewrite",
2966};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002967
Neale Ranns32e1c012016-11-22 17:07:28 +00002968VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002969 .name = "ip4-midchain",
2970 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002971 .format_trace = format_ip4_rewrite_trace,
2972 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002973};
Neale Ranns32e1c012016-11-22 17:07:28 +00002974/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002975
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002976static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002977ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2978{
2979 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002980 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002981 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002982
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002983 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002984
Neale Ranns04a75e32017-03-23 06:46:01 -07002985 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002986 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2987 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002988
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002989 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002990
Dave Barachd7cb1b52016-12-09 09:52:16 -05002991 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002992}
Dave Barach75fc8542016-10-11 16:16:02 -04002993
Ed Warnickecb9cada2015-12-08 15:45:58 -07002994static clib_error_t *
2995test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002996 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002997{
Billy McFall309fe062016-10-14 07:37:33 -04002998 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002999 u32 table_id = 0;
3000 f64 count = 1;
3001 u32 n;
3002 int i;
3003 ip4_address_t ip4_base_address;
3004 u64 errors = 0;
3005
Dave Barachd7cb1b52016-12-09 09:52:16 -05003006 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3007 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07003008 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003009 {
3010 /* Make sure the entry exists. */
3011 fib = ip4_fib_get (table_id);
3012 if ((fib) && (fib->index != table_id))
3013 return clib_error_return (0, "<fib-index> %d does not exist",
3014 table_id);
3015 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003016 else if (unformat (input, "count %f", &count))
3017 ;
3018
3019 else if (unformat (input, "%U",
3020 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003021 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003023 return clib_error_return (0, "unknown input `%U'",
3024 format_unformat_error, input);
3025 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003026
3027 n = count;
3028
3029 for (i = 0; i < n; i++)
3030 {
3031 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05003032 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003033
Dave Barach75fc8542016-10-11 16:16:02 -04003034 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05003035 clib_host_to_net_u32 (1 +
3036 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003037 }
3038
Dave Barach75fc8542016-10-11 16:16:02 -04003039 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003040 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3041 else
3042 vlib_cli_output (vm, "No errors in %d lookups\n", n);
3043
3044 return 0;
3045}
3046
Billy McFall0683c9c2016-10-13 08:27:31 -04003047/*?
3048 * Perform a lookup of an IPv4 Address (or range of addresses) in the
3049 * given FIB table to determine if there is a conflict with the
3050 * adjacency table. The fib-id can be determined by using the
3051 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
3052 * of 0 is used.
3053 *
3054 * @todo This command uses fib-id, other commands use table-id (not
3055 * just a name, they are different indexes). Would like to change this
3056 * to table-id for consistency.
3057 *
3058 * @cliexpar
3059 * Example of how to run the test lookup command:
3060 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3061 * No errors in 2 lookups
3062 * @cliexend
3063?*/
3064/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003065VLIB_CLI_COMMAND (lookup_test_command, static) =
3066{
3067 .path = "test lookup",
3068 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3069 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070};
Billy McFall0683c9c2016-10-13 08:27:31 -04003071/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003072
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003073#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003074int
3075vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003076{
Neale Ranns107e7d42017-04-11 09:55:19 -07003077 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003078
Neale Ranns107e7d42017-04-11 09:55:19 -07003079 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
3080
3081 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003082 return VNET_API_ERROR_NO_SUCH_FIB;
3083
Neale Ranns227038a2017-04-21 01:07:59 -07003084 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
3085 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003086
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087 return 0;
3088}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003089#endif
Dave Barach75fc8542016-10-11 16:16:02 -04003090
Ed Warnickecb9cada2015-12-08 15:45:58 -07003091static clib_error_t *
3092set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003093 unformat_input_t * input,
3094 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095{
3096 int matched = 0;
3097 u32 table_id = 0;
3098 u32 flow_hash_config = 0;
3099 int rv;
3100
Dave Barachd7cb1b52016-12-09 09:52:16 -05003101 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3102 {
3103 if (unformat (input, "table %d", &table_id))
3104 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003105#define _(a,v) \
3106 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003107 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003108#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003109 else
3110 break;
3111 }
Dave Barach75fc8542016-10-11 16:16:02 -04003112
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113 if (matched == 0)
3114 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003115 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003116
Ed Warnickecb9cada2015-12-08 15:45:58 -07003117 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3118 switch (rv)
3119 {
3120 case 0:
3121 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003122
Ed Warnickecb9cada2015-12-08 15:45:58 -07003123 case VNET_API_ERROR_NO_SUCH_FIB:
3124 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003125
Ed Warnickecb9cada2015-12-08 15:45:58 -07003126 default:
3127 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3128 break;
3129 }
Dave Barach75fc8542016-10-11 16:16:02 -04003130
Ed Warnickecb9cada2015-12-08 15:45:58 -07003131 return 0;
3132}
Dave Barach75fc8542016-10-11 16:16:02 -04003133
Billy McFall0683c9c2016-10-13 08:27:31 -04003134/*?
3135 * Configure the set of IPv4 fields used by the flow hash.
3136 *
3137 * @cliexpar
3138 * Example of how to set the flow hash on a given table:
3139 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3140 * Example of display the configured flow hash:
3141 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003142 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3143 * 0.0.0.0/0
3144 * unicast-ip4-chain
3145 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3146 * [0] [@0]: dpo-drop ip6
3147 * 0.0.0.0/32
3148 * unicast-ip4-chain
3149 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3150 * [0] [@0]: dpo-drop ip6
3151 * 224.0.0.0/8
3152 * unicast-ip4-chain
3153 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3154 * [0] [@0]: dpo-drop ip6
3155 * 6.0.1.2/32
3156 * unicast-ip4-chain
3157 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3158 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3159 * 7.0.0.1/32
3160 * unicast-ip4-chain
3161 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3162 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3163 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3164 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3165 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3166 * 240.0.0.0/8
3167 * unicast-ip4-chain
3168 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3169 * [0] [@0]: dpo-drop ip6
3170 * 255.255.255.255/32
3171 * unicast-ip4-chain
3172 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3173 * [0] [@0]: dpo-drop ip6
3174 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3175 * 0.0.0.0/0
3176 * unicast-ip4-chain
3177 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3178 * [0] [@0]: dpo-drop ip6
3179 * 0.0.0.0/32
3180 * unicast-ip4-chain
3181 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3182 * [0] [@0]: dpo-drop ip6
3183 * 172.16.1.0/24
3184 * unicast-ip4-chain
3185 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3186 * [0] [@4]: ipv4-glean: af_packet0
3187 * 172.16.1.1/32
3188 * unicast-ip4-chain
3189 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3190 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3191 * 172.16.1.2/32
3192 * unicast-ip4-chain
3193 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3194 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3195 * 172.16.2.0/24
3196 * unicast-ip4-chain
3197 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3198 * [0] [@4]: ipv4-glean: af_packet1
3199 * 172.16.2.1/32
3200 * unicast-ip4-chain
3201 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3202 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3203 * 224.0.0.0/8
3204 * unicast-ip4-chain
3205 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3206 * [0] [@0]: dpo-drop ip6
3207 * 240.0.0.0/8
3208 * unicast-ip4-chain
3209 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3210 * [0] [@0]: dpo-drop ip6
3211 * 255.255.255.255/32
3212 * unicast-ip4-chain
3213 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3214 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003215 * @cliexend
3216?*/
3217/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003218VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3219{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003220 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003221 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003222 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003223 .function = set_ip_flow_hash_command_fn,
3224};
Billy McFall0683c9c2016-10-13 08:27:31 -04003225/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003226
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003227#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003228int
3229vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3230 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003231{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003232 vnet_main_t *vnm = vnet_get_main ();
3233 vnet_interface_main_t *im = &vnm->interface_main;
3234 ip4_main_t *ipm = &ip4_main;
3235 ip_lookup_main_t *lm = &ipm->lookup_main;
3236 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003237 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003238
3239 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3240 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3241
3242 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3243 return VNET_API_ERROR_NO_SUCH_ENTRY;
3244
3245 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003246 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003247
Neale Rannsdf089a82016-10-02 16:39:06 +01003248 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3249
3250 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003251 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003252 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003253 .fp_len = 32,
3254 .fp_proto = FIB_PROTOCOL_IP4,
3255 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003256 };
3257 u32 fib_index;
3258
Dave Barachd7cb1b52016-12-09 09:52:16 -05003259 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3260 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003261
3262
Dave Barachd7cb1b52016-12-09 09:52:16 -05003263 if (table_index != (u32) ~ 0)
3264 {
3265 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003266
Dave Barachd7cb1b52016-12-09 09:52:16 -05003267 dpo_set (&dpo,
3268 DPO_CLASSIFY,
3269 DPO_PROTO_IP4,
3270 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003271
Dave Barachd7cb1b52016-12-09 09:52:16 -05003272 fib_table_entry_special_dpo_add (fib_index,
3273 &pfx,
3274 FIB_SOURCE_CLASSIFY,
3275 FIB_ENTRY_FLAG_NONE, &dpo);
3276 dpo_reset (&dpo);
3277 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003278 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003279 {
3280 fib_table_entry_special_remove (fib_index,
3281 &pfx, FIB_SOURCE_CLASSIFY);
3282 }
3283 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003284
Ed Warnickecb9cada2015-12-08 15:45:58 -07003285 return 0;
3286}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003287#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003288
3289static clib_error_t *
3290set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003291 unformat_input_t * input,
3292 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003293{
3294 u32 table_index = ~0;
3295 int table_index_set = 0;
3296 u32 sw_if_index = ~0;
3297 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003298
Dave Barachd7cb1b52016-12-09 09:52:16 -05003299 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3300 {
3301 if (unformat (input, "table-index %d", &table_index))
3302 table_index_set = 1;
3303 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3304 vnet_get_main (), &sw_if_index))
3305 ;
3306 else
3307 break;
3308 }
Dave Barach75fc8542016-10-11 16:16:02 -04003309
Ed Warnickecb9cada2015-12-08 15:45:58 -07003310 if (table_index_set == 0)
3311 return clib_error_return (0, "classify table-index must be specified");
3312
3313 if (sw_if_index == ~0)
3314 return clib_error_return (0, "interface / subif must be specified");
3315
3316 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3317
3318 switch (rv)
3319 {
3320 case 0:
3321 break;
3322
3323 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3324 return clib_error_return (0, "No such interface");
3325
3326 case VNET_API_ERROR_NO_SUCH_ENTRY:
3327 return clib_error_return (0, "No such classifier table");
3328 }
3329 return 0;
3330}
3331
Billy McFall0683c9c2016-10-13 08:27:31 -04003332/*?
3333 * Assign a classification table to an interface. The classification
3334 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3335 * commands. Once the table is create, use this command to filter packets
3336 * on an interface.
3337 *
3338 * @cliexpar
3339 * Example of how to assign a classification table to an interface:
3340 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3341?*/
3342/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003343VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3344{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003345 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003346 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003347 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003348 .function = set_ip_classify_command_fn,
3349};
Billy McFall0683c9c2016-10-13 08:27:31 -04003350/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003351
Neale Ranns1ec36522017-11-29 05:20:37 -08003352static clib_error_t *
3353ip4_config (vlib_main_t * vm, unformat_input_t * input)
3354{
3355 ip4_main_t *im = &ip4_main;
3356 uword heapsize = 0;
3357
3358 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3359 {
3360 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3361 ;
3362 else
3363 return clib_error_return (0,
3364 "invalid heap-size parameter `%U'",
3365 format_unformat_error, input);
3366 }
3367
3368 im->mtrie_heap_size = heapsize;
3369
3370 return 0;
3371}
3372
3373VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3374
Dave Barachd7cb1b52016-12-09 09:52:16 -05003375/*
3376 * fd.io coding-style-patch-verification: ON
3377 *
3378 * Local Variables:
3379 * eval: (c-set-style "gnu")
3380 * End:
3381 */