blob: 9ed9453648b37f2ab2ce9ada5184f1131360c23d [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{
Damjan Marionaca64c92016-04-13 09:48:56 +020095 return ip4_lookup_inline (vm, node, frame,
Dave Barachd7cb1b52016-12-09 09:52:16 -050096 /* lookup_for_responses_to_locally_received_packets */
97 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99}
100
Dave Barachd7cb1b52016-12-09 09:52:16 -0500101static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100102
Neale Rannsf8686322017-11-29 02:39:53 -0800103/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500104VLIB_REGISTER_NODE (ip4_lookup_node) =
105{
Neale Rannsf8686322017-11-29 02:39:53 -0800106 .name = "ip4-lookup",
107 .vector_size = sizeof (u32),
108 .format_trace = format_ip4_lookup_trace,
109 .n_next_nodes = IP_LOOKUP_N_NEXT,
110 .next_nodes = IP4_LOOKUP_NEXT_NODES,
111};
112/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100113
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200114VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
115 vlib_node_runtime_t * node,
116 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500118 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
119 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100120 ip_lookup_next_t next;
Damjan Marion067cd622018-07-11 12:47:43 +0200121 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800122 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100124 from = vlib_frame_vector_args (frame);
125 n_left_from = frame->n_vectors;
126 next = node->cached_next_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800127 vlib_get_buffers (vm, from, bufs, n_left_from);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100128
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100129 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500131 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100132
Neale Ranns2be95c12016-11-19 13:50:04 +0000133 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500134 {
135 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000136 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500137 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000138 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
139 const ip4_header_t *ip0, *ip1;
140 const dpo_id_t *dpo0, *dpo1;
141
Dave Barachd7cb1b52016-12-09 09:52:16 -0500142 /* Prefetch next iteration. */
143 {
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800144 vlib_prefetch_buffer_header (b[2], STORE);
145 vlib_prefetch_buffer_header (b[3], STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000146
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800147 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
148 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500149 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000150
151 pi0 = to_next[0] = from[0];
152 pi1 = to_next[1] = from[1];
153
154 from += 2;
155 n_left_from -= 2;
156 to_next += 2;
157 n_left_to_next -= 2;
158
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800159 p0 = b[0];
160 p1 = b[1];
161 b += 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000162
163 ip0 = vlib_buffer_get_current (p0);
164 ip1 = vlib_buffer_get_current (p1);
165 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
166 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
167
Dave Barachd7cb1b52016-12-09 09:52:16 -0500168 lb0 = load_balance_get (lbi0);
169 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000170
Dave Barachd7cb1b52016-12-09 09:52:16 -0500171 /*
172 * this node is for via FIBs we can re-use the hash value from the
173 * to node if present.
174 * We don't want to use the same hash value at each level in the recursion
175 * graph as that would lead to polarisation
176 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000177 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000178
Dave Barachd7cb1b52016-12-09 09:52:16 -0500179 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
180 {
181 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
182 {
183 hc0 = vnet_buffer (p0)->ip.flow_hash =
184 vnet_buffer (p0)->ip.flow_hash >> 1;
185 }
186 else
187 {
188 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000189 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500190 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700191 dpo0 = load_balance_get_fwd_bucket
192 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
193 }
194 else
195 {
196 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500197 }
198 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
199 {
200 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
201 {
202 hc1 = vnet_buffer (p1)->ip.flow_hash =
203 vnet_buffer (p1)->ip.flow_hash >> 1;
204 }
205 else
206 {
207 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000208 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500209 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700210 dpo1 = load_balance_get_fwd_bucket
211 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500212 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700213 else
214 {
215 dpo1 = load_balance_get_bucket_i (lb1, 0);
216 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000217
218 next0 = dpo0->dpoi_next_node;
219 next1 = dpo1->dpoi_next_node;
220
221 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
222 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
223
224 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200225 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000226 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200227 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000228
229 vlib_validate_buffer_enqueue_x2 (vm, node, next,
230 to_next, n_left_to_next,
231 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500232 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000233
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100234 while (n_left_from > 0 && n_left_to_next > 0)
235 {
236 ip_lookup_next_t next0;
237 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500238 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100239 u32 pi0, lbi0, hc0;
240 const ip4_header_t *ip0;
241 const dpo_id_t *dpo0;
242
243 pi0 = from[0];
244 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000245 from += 1;
246 to_next += 1;
247 n_left_to_next -= 1;
248 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100249
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800250 p0 = b[0];
251 b += 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100252
253 ip0 = vlib_buffer_get_current (p0);
254 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
255
Dave Barachd7cb1b52016-12-09 09:52:16 -0500256 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100257
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000258 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500259 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
260 {
261 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
262 {
263 hc0 = vnet_buffer (p0)->ip.flow_hash =
264 vnet_buffer (p0)->ip.flow_hash >> 1;
265 }
266 else
267 {
268 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000269 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500270 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700271 dpo0 = load_balance_get_fwd_bucket
272 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500273 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700274 else
275 {
276 dpo0 = load_balance_get_bucket_i (lb0, 0);
277 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100278
279 next0 = dpo0->dpoi_next_node;
280 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
281
Dave Barach75fc8542016-10-11 16:16:02 -0400282 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200283 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100284
Neale Ranns2be95c12016-11-19 13:50:04 +0000285 vlib_validate_buffer_enqueue_x1 (vm, node, next,
286 to_next, n_left_to_next,
287 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100288 }
289
290 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 }
292
Neale Rannsa71844f2018-11-08 07:31:36 -0800293 if (node->flags & VLIB_NODE_FLAG_TRACE)
294 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
295
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100296 return frame->n_vectors;
297}
298
Neale Rannsf8686322017-11-29 02:39:53 -0800299/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500300VLIB_REGISTER_NODE (ip4_load_balance_node) =
301{
Neale Rannsf8686322017-11-29 02:39:53 -0800302 .name = "ip4-load-balance",
303 .vector_size = sizeof (u32),
304 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200305 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800306};
307/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100308
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200309#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100310/* get first interface address */
311ip4_address_t *
312ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500313 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100314{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500315 ip_lookup_main_t *lm = &im->lookup_main;
316 ip_interface_address_t *ia = 0;
317 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100318
Neale Ranns32e1c012016-11-22 17:07:28 +0000319 /* *INDENT-OFF* */
320 foreach_ip_interface_address
321 (lm, ia, sw_if_index,
322 1 /* honor unnumbered */ ,
323 ({
324 ip4_address_t * a =
325 ip_interface_address_get_address (lm, ia);
326 result = a;
327 break;
328 }));
329 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100330 if (result_ia)
331 *result_ia = result ? ia : 0;
332 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333}
334
335static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700336ip4_add_subnet_bcast_route (u32 fib_index,
337 fib_prefix_t *pfx,
338 u32 sw_if_index)
339{
340 vnet_sw_interface_flags_t iflags;
341
342 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
343
344 fib_table_entry_special_remove(fib_index,
345 pfx,
346 FIB_SOURCE_INTERFACE);
347
348 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
349 {
350 fib_table_entry_update_one_path (fib_index, pfx,
351 FIB_SOURCE_INTERFACE,
352 FIB_ENTRY_FLAG_NONE,
353 DPO_PROTO_IP4,
354 /* No next-hop address */
355 &ADJ_BCAST_ADDR,
356 sw_if_index,
357 // invalid FIB index
358 ~0,
359 1,
360 // no out-label stack
361 NULL,
362 FIB_ROUTE_PATH_FLAG_NONE);
363 }
364 else
365 {
366 fib_table_entry_special_add(fib_index,
367 pfx,
368 FIB_SOURCE_INTERFACE,
369 (FIB_ENTRY_FLAG_DROP |
370 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
371 }
372}
373
374static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700375ip4_add_interface_routes (u32 sw_if_index,
376 ip4_main_t * im, u32 fib_index,
377 ip_interface_address_t * a)
378{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500379 ip_lookup_main_t *lm = &im->lookup_main;
380 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100381 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500382 .fp_len = a->address_length,
383 .fp_proto = FIB_PROTOCOL_IP4,
384 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100385 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386
Neale Ranns9a69a602017-03-26 10:56:33 -0700387 if (pfx.fp_len <= 30)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500388 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700389 /* a /30 or shorter - add a glean for the network address */
Neale Ranns7a272742017-05-30 02:08:14 -0700390 fib_table_entry_update_one_path (fib_index, &pfx,
391 FIB_SOURCE_INTERFACE,
392 (FIB_ENTRY_FLAG_CONNECTED |
393 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700394 DPO_PROTO_IP4,
Neale Ranns7a272742017-05-30 02:08:14 -0700395 /* No next-hop address */
396 NULL,
397 sw_if_index,
398 // invalid FIB index
399 ~0,
400 1,
401 // no out-label stack
402 NULL,
403 FIB_ROUTE_PATH_FLAG_NONE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100404
Neale Ranns9a69a602017-03-26 10:56:33 -0700405 /* Add the two broadcast addresses as drop */
406 fib_prefix_t net_pfx = {
407 .fp_len = 32,
408 .fp_proto = FIB_PROTOCOL_IP4,
409 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
410 };
411 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
412 fib_table_entry_special_add(fib_index,
413 &net_pfx,
414 FIB_SOURCE_INTERFACE,
415 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700416 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700417 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
418 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
Neale Ranns1855b8e2018-07-11 10:31:26 -0700419 ip4_add_subnet_bcast_route(fib_index, &net_pfx, sw_if_index);
Neale Ranns9a69a602017-03-26 10:56:33 -0700420 }
421 else if (pfx.fp_len == 31)
422 {
423 u32 mask = clib_host_to_net_u32(1);
424 fib_prefix_t net_pfx = pfx;
425
426 net_pfx.fp_len = 32;
427 net_pfx.fp_addr.ip4.as_u32 ^= mask;
428
429 /* a /31 - add the other end as an attached host */
430 fib_table_entry_update_one_path (fib_index, &net_pfx,
431 FIB_SOURCE_INTERFACE,
432 (FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700433 DPO_PROTO_IP4,
Neale Ranns9a69a602017-03-26 10:56:33 -0700434 &net_pfx.fp_addr,
435 sw_if_index,
436 // invalid FIB index
437 ~0,
438 1,
439 NULL,
440 FIB_ROUTE_PATH_FLAG_NONE);
441 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100442 pfx.fp_len = 32;
443
444 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500445 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100446 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500447 lm->classify_table_index_by_sw_if_index[sw_if_index];
448 if (classify_table_index != (u32) ~ 0)
449 {
450 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100451
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 dpo_set (&dpo,
453 DPO_CLASSIFY,
454 DPO_PROTO_IP4,
455 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100456
Dave Barachd7cb1b52016-12-09 09:52:16 -0500457 fib_table_entry_special_dpo_add (fib_index,
458 &pfx,
459 FIB_SOURCE_CLASSIFY,
460 FIB_ENTRY_FLAG_NONE, &dpo);
461 dpo_reset (&dpo);
462 }
463 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100464
Neale Ranns32e1c012016-11-22 17:07:28 +0000465 fib_table_entry_update_one_path (fib_index, &pfx,
466 FIB_SOURCE_INTERFACE,
467 (FIB_ENTRY_FLAG_CONNECTED |
468 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700469 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000470 &pfx.fp_addr,
471 sw_if_index,
472 // invalid FIB index
473 ~0,
474 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500475 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476}
477
478static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100479ip4_del_interface_routes (ip4_main_t * im,
480 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500481 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700482{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500483 fib_prefix_t pfx = {
484 .fp_len = address_length,
485 .fp_proto = FIB_PROTOCOL_IP4,
486 .fp_addr.ip4 = *address,
487 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488
Neale Ranns9a69a602017-03-26 10:56:33 -0700489 if (pfx.fp_len <= 30)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100490 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700491 fib_prefix_t net_pfx = {
492 .fp_len = 32,
493 .fp_proto = FIB_PROTOCOL_IP4,
494 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
495 };
496 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
497 fib_table_entry_special_remove(fib_index,
498 &net_pfx,
499 FIB_SOURCE_INTERFACE);
500 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
501 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
502 fib_table_entry_special_remove(fib_index,
503 &net_pfx,
504 FIB_SOURCE_INTERFACE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500505 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100506 }
Neale Ranns9a69a602017-03-26 10:56:33 -0700507 else if (pfx.fp_len == 31)
508 {
509 u32 mask = clib_host_to_net_u32(1);
510 fib_prefix_t net_pfx = pfx;
511
512 net_pfx.fp_len = 32;
513 net_pfx.fp_addr.ip4.as_u32 ^= mask;
514
515 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
516 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517
Dave Barachd7cb1b52016-12-09 09:52:16 -0500518 pfx.fp_len = 32;
519 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520}
521
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100522void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500523ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100524{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500525 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100527 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
528
529 /*
530 * enable/disable only on the 1<->0 transition
531 */
532 if (is_enable)
533 {
534 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500535 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100536 }
537 else
538 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500539 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100540 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500541 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100542 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800543 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800544 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100545
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100546
Neale Ranns8269d3d2018-01-30 09:02:20 -0800547 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400548 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100549}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551static clib_error_t *
552ip4_add_del_interface_address_internal (vlib_main_t * vm,
553 u32 sw_if_index,
554 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500555 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500557 vnet_main_t *vnm = vnet_get_main ();
558 ip4_main_t *im = &ip4_main;
559 ip_lookup_main_t *lm = &im->lookup_main;
560 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500562 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563
Pavel Kotucek57808982017-08-02 08:20:19 +0200564 /* local0 interface doesn't support IP addressing */
565 if (sw_if_index == 0)
566 {
567 return
568 clib_error_create ("local0 interface doesn't support IP addressing");
569 }
570
Ed Warnickecb9cada2015-12-08 15:45:58 -0700571 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
572 ip4_addr_fib_init (&ip4_af, address,
573 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
574 vec_add1 (addr_fib, ip4_af);
575
Neale Ranns744902e2017-08-14 10:35:44 -0700576 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100577 * there is no support for adj-fib handling in the presence of overlapping
578 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
579 * most routers do.
580 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000581 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500582 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700583 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100584 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700585 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500586 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700587 vnet_sw_interface_t *sif;
588
589 pool_foreach(sif, vnm->interface_main.sw_interfaces,
590 ({
591 if (im->fib_index_by_sw_if_index[sw_if_index] ==
592 im->fib_index_by_sw_if_index[sif->sw_if_index])
593 {
594 foreach_ip_interface_address
595 (&im->lookup_main, ia, sif->sw_if_index,
596 0 /* honor unnumbered */ ,
597 ({
598 ip4_address_t * x =
599 ip_interface_address_get_address
600 (&im->lookup_main, ia);
601 if (ip4_destination_matches_route
602 (im, address, x, ia->address_length) ||
603 ip4_destination_matches_route (im,
604 x,
605 address,
606 address_length))
607 {
608 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
609
610 return
611 clib_error_create
612 ("failed to add %U which conflicts with %U for interface %U",
613 format_ip4_address_and_length, address,
614 address_length,
615 format_ip4_address_and_length, x,
616 ia->address_length,
617 format_vnet_sw_if_index_name, vnm,
618 sif->sw_if_index);
619 }
620 }));
621 }
622 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000624 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626 elts_before = pool_elts (lm->if_address_pool);
627
628 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500629 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700630 if (error)
631 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400632
Dave Barachd7cb1b52016-12-09 09:52:16 -0500633 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100634
635 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500636 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500638 ip4_add_interface_routes (sw_if_index,
639 im, ip4_af.fib_index,
640 pool_elt_at_index
641 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642
643 /* If pool did not grow/shrink: add duplicate address. */
644 if (elts_before != pool_elts (lm->if_address_pool))
645 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500646 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647 vec_foreach (cb, im->add_del_interface_address_callbacks)
648 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500649 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650 }
651
Dave Barachd7cb1b52016-12-09 09:52:16 -0500652done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653 vec_free (addr_fib);
654 return error;
655}
656
657clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000658ip4_add_del_interface_address (vlib_main_t * vm,
659 u32 sw_if_index,
660 ip4_address_t * address,
661 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700662{
663 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500664 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665}
666
Neale Ranns1855b8e2018-07-11 10:31:26 -0700667void
668ip4_directed_broadcast (u32 sw_if_index, u8 enable)
669{
670 ip_interface_address_t *ia;
671 ip4_main_t *im;
672
673 im = &ip4_main;
674
675 /*
676 * when directed broadcast is enabled, the subnet braodcast route will forward
677 * packets using an adjacency with a broadcast MAC. otherwise it drops
678 */
679 /* *INDENT-OFF* */
680 foreach_ip_interface_address(&im->lookup_main, ia,
681 sw_if_index, 0,
682 ({
683 if (ia->address_length <= 30)
684 {
685 ip4_address_t *ipa;
686
687 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
688
689 fib_prefix_t pfx = {
690 .fp_len = 32,
691 .fp_proto = FIB_PROTOCOL_IP4,
692 .fp_addr = {
693 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
694 },
695 };
696
697 ip4_add_subnet_bcast_route
698 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
699 sw_if_index),
700 &pfx, sw_if_index);
701 }
702 }));
703 /* *INDENT-ON* */
704}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200705#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700706
Dave Barachd6534602016-06-14 18:38:02 -0400707/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500708/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100709VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
710{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500711 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100712 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500713 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100714 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
715};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100716
Dave Barachd7cb1b52016-12-09 09:52:16 -0500717VNET_FEATURE_INIT (ip4_flow_classify, static) =
718{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100719 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700720 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100721 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700722};
723
Dave Barachd7cb1b52016-12-09 09:52:16 -0500724VNET_FEATURE_INIT (ip4_inacl, static) =
725{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100726 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400727 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100728 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400729};
730
Dave Barachd7cb1b52016-12-09 09:52:16 -0500731VNET_FEATURE_INIT (ip4_source_check_1, static) =
732{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100733 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400734 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100735 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400736};
737
Dave Barachd7cb1b52016-12-09 09:52:16 -0500738VNET_FEATURE_INIT (ip4_source_check_2, static) =
739{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100740 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400741 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100742 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400743};
744
Dave Barachd7cb1b52016-12-09 09:52:16 -0500745VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
746{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100747 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400748 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100749 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400750};
751
Dave Barachd7cb1b52016-12-09 09:52:16 -0500752VNET_FEATURE_INIT (ip4_policer_classify, static) =
753{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100754 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700755 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100756 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700757};
758
Dave Barachd7cb1b52016-12-09 09:52:16 -0500759VNET_FEATURE_INIT (ip4_ipsec, static) =
760{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100761 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100762 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100763 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400764};
765
Dave Barachd7cb1b52016-12-09 09:52:16 -0500766VNET_FEATURE_INIT (ip4_vpath, static) =
767{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100768 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400769 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500770 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
771};
772
Dave Barachd7cb1b52016-12-09 09:52:16 -0500773VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
774{
John Lo37682e12016-11-30 12:51:39 -0500775 .arc_name = "ip4-unicast",
776 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100777 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400778};
779
Neale Ranns8269d3d2018-01-30 09:02:20 -0800780VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500781{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100782 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800783 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400784 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100785};
786
Neale Ranns180279b2017-03-16 15:49:09 -0400787VNET_FEATURE_INIT (ip4_lookup, static) =
788{
789 .arc_name = "ip4-unicast",
790 .node_name = "ip4-lookup",
791 .runs_before = 0, /* not before any other features */
792};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100793
Dave Barachd6534602016-06-14 18:38:02 -0400794/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100795VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
796{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500797 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100798 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500799 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100800 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
801};
802
Dave Barachd7cb1b52016-12-09 09:52:16 -0500803VNET_FEATURE_INIT (ip4_vpath_mc, static) =
804{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100805 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400806 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000807 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400808};
809
Neale Ranns8269d3d2018-01-30 09:02:20 -0800810VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500811{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100812 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800813 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400814 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
815};
816
817VNET_FEATURE_INIT (ip4_lookup_mc, static) =
818{
819 .arc_name = "ip4-multicast",
820 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500821 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100822};
Dave Barach5331c722016-08-17 11:54:30 -0400823
824/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100825VNET_FEATURE_ARC_INIT (ip4_output, static) =
826{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500827 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800828 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -0500829 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100830 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
831};
Dave Barach5331c722016-08-17 11:54:30 -0400832
Dave Barachd7cb1b52016-12-09 09:52:16 -0500833VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
834{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100835 .arc_name = "ip4-output",
836 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100837 .runs_before = VNET_FEATURES ("ip4-outacl"),
838};
839
840VNET_FEATURE_INIT (ip4_outacl, static) =
841{
842 .arc_name = "ip4-output",
843 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +0100844 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -0800845};
846
Dave Barachd7cb1b52016-12-09 09:52:16 -0500847VNET_FEATURE_INIT (ip4_ipsec_output, static) =
848{
Matus Fabian08a6f012016-11-15 06:08:51 -0800849 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +0100850 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100851 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -0400852};
853
854/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500855VNET_FEATURE_INIT (ip4_interface_output, static) =
856{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100857 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -0400858 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500859 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -0400860};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500861/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400862
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500864ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500866 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100868 /* Fill in lookup tables with default table (0). */
869 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000870 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100871
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200872 if (!is_add)
873 {
874 ip4_main_t *im4 = &ip4_main;
875 ip_lookup_main_t *lm4 = &im4->lookup_main;
876 ip_interface_address_t *ia = 0;
877 ip4_address_t *address;
878 vlib_main_t *vm = vlib_get_main ();
879
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700880 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200881 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700882 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200883 ({
884 address = ip_interface_address_get_address (lm4, ia);
885 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
886 }));
887 /* *INDENT-ON* */
888 }
889
Neale Ranns8269d3d2018-01-30 09:02:20 -0800890 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100891 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700892
Neale Ranns8269d3d2018-01-30 09:02:20 -0800893 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
894 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700895
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896 return /* no error */ 0;
897}
898
899VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
900
Ed Warnickecb9cada2015-12-08 15:45:58 -0700901/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +0100902#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +0100904#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700905
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200906static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907ip4_lookup_init (vlib_main_t * vm)
908{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500909 ip4_main_t *im = &ip4_main;
910 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700911 uword i;
912
Damjan Marion8b3191e2016-11-09 19:54:20 +0100913 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
914 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -0800915 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
916 return (error);
917 if ((error = vlib_call_init_function (vm, fib_module_init)))
918 return error;
919 if ((error = vlib_call_init_function (vm, mfib_module_init)))
920 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100921
Ed Warnickecb9cada2015-12-08 15:45:58 -0700922 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
923 {
924 u32 m;
925
926 if (i < 32)
927 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -0400928 else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700929 m = ~0;
930 im->fib_masks[i] = clib_host_to_net_u32 (m);
931 }
932
Ed Warnickecb9cada2015-12-08 15:45:58 -0700933 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
934
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100935 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -0700936 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
937 FIB_SOURCE_DEFAULT_ROUTE);
938 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
939 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100940
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500942 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943 pn = pg_get_node (ip4_lookup_node.index);
944 pn->unformat_edit = unformat_pg_ip4_header;
945 }
946
947 {
948 ethernet_arp_header_t h;
949
Dave Barachb7b92992018-10-17 10:38:51 -0400950 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952#define _16(f,v) h.f = clib_host_to_net_u16 (v);
953#define _8(f,v) h.f = v;
954 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
955 _16 (l3_type, ETHERNET_TYPE_IP4);
956 _8 (n_l2_address_bytes, 6);
957 _8 (n_l3_address_bytes, 4);
958 _16 (opcode, ETHERNET_ARP_OPCODE_request);
959#undef _16
960#undef _8
961
Dave Barachd7cb1b52016-12-09 09:52:16 -0500962 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 /* data */ &h,
964 sizeof (h),
965 /* alloc chunk size */ 8,
966 "ip4 arp");
967 }
968
Dave Barach203c6322016-06-26 10:29:03 -0400969 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700970}
971
972VLIB_INIT_FUNCTION (ip4_lookup_init);
973
Dave Barachd7cb1b52016-12-09 09:52:16 -0500974typedef struct
975{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -0700977 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978 u32 flow_hash;
979 u32 fib_index;
980
981 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500982 u8 packet_data[64 - 1 * sizeof (u32)];
983}
984ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200986#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -0500987u8 *
988format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989{
990 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
991 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500992 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200993 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100994 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -0400995 format_white_space, indent,
996 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100997 return s;
998}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200999#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001000
Dave Barachd7cb1b52016-12-09 09:52:16 -05001001static u8 *
1002format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001003{
1004 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1005 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001006 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001007 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008
John Loac8146c2016-09-27 17:44:02 -04001009 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001010 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001011 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001012 format_white_space, indent,
1013 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001014 return s;
1015}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016
Dave Barachd7cb1b52016-12-09 09:52:16 -05001017static u8 *
1018format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001019{
1020 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1021 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001022 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001023 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001024
Vengada Govindanf1544482016-09-28 02:45:57 -07001025 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026 t->fib_index, t->dpo_index, format_ip_adjacency,
1027 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001028 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001029 format_white_space, indent,
1030 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001031 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032 return s;
1033}
1034
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001035#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036/* Common trace function for all ip4-forward next nodes. */
1037void
1038ip4_forward_next_trace (vlib_main_t * vm,
1039 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001040 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042 u32 *from, n_left;
1043 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044
1045 n_left = frame->n_vectors;
1046 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001047
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 while (n_left >= 4)
1049 {
1050 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001051 vlib_buffer_t *b0, *b1;
1052 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053
1054 /* Prefetch next iteration. */
1055 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1056 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1057
1058 bi0 = from[0];
1059 bi1 = from[1];
1060
1061 b0 = vlib_get_buffer (vm, bi0);
1062 b1 = vlib_get_buffer (vm, bi1);
1063
1064 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1065 {
1066 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001067 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001069 t0->fib_index =
1070 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1071 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1072 vec_elt (im->fib_index_by_sw_if_index,
1073 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001074
Dave Barach178cf492018-11-13 16:34:13 -05001075 clib_memcpy_fast (t0->packet_data,
1076 vlib_buffer_get_current (b0),
1077 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001078 }
1079 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1080 {
1081 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001082 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001084 t1->fib_index =
1085 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1086 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1087 vec_elt (im->fib_index_by_sw_if_index,
1088 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001089 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1090 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091 }
1092 from += 2;
1093 n_left -= 2;
1094 }
1095
1096 while (n_left >= 1)
1097 {
1098 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001099 vlib_buffer_t *b0;
1100 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101
1102 bi0 = from[0];
1103
1104 b0 = vlib_get_buffer (vm, bi0);
1105
1106 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1107 {
1108 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001109 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001111 t0->fib_index =
1112 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1113 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1114 vec_elt (im->fib_index_by_sw_if_index,
1115 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001116 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1117 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118 }
1119 from += 1;
1120 n_left -= 1;
1121 }
1122}
1123
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124/* Compute TCP/UDP/ICMP4 checksum in software. */
1125u16
1126ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1127 ip4_header_t * ip0)
1128{
1129 ip_csum_t sum0;
1130 u32 ip_header_length, payload_length_host_byte_order;
Florin Corasb2215d62017-08-01 16:56:58 -07001131 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001133 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001134
Ed Warnickecb9cada2015-12-08 15:45:58 -07001135 /* Initialize checksum with ip header. */
1136 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001137 payload_length_host_byte_order =
1138 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1139 sum0 =
1140 clib_host_to_net_u32 (payload_length_host_byte_order +
1141 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142
1143 if (BITS (uword) == 32)
1144 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001145 sum0 =
1146 ip_csum_with_carry (sum0,
1147 clib_mem_unaligned (&ip0->src_address, u32));
1148 sum0 =
1149 ip_csum_with_carry (sum0,
1150 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 }
1152 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001153 sum0 =
1154 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155
1156 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1157 data_this_buffer = (void *) ip0 + ip_header_length;
Neale Rannsd91c1db2017-07-31 02:30:50 -07001158 n_ip_bytes_this_buffer =
1159 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
Florin Corasb2215d62017-08-01 16:56:58 -07001160 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1161 {
1162 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
Neale Rannsd91c1db2017-07-31 02:30:50 -07001163 n_ip_bytes_this_buffer - ip_header_length : 0;
Florin Corasb2215d62017-08-01 16:56:58 -07001164 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 while (1)
1166 {
1167 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1168 n_bytes_left -= n_this_buffer;
1169 if (n_bytes_left == 0)
1170 break;
1171
1172 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1173 p0 = vlib_get_buffer (vm, p0->next_buffer);
1174 data_this_buffer = vlib_buffer_get_current (p0);
John Lo1cf00072019-04-09 10:23:56 -04001175 n_this_buffer = clib_min (p0->current_length, n_bytes_left);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176 }
1177
Dave Barachd7cb1b52016-12-09 09:52:16 -05001178 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179
1180 return sum16;
1181}
1182
John Lo37682e12016-11-30 12:51:39 -05001183u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1185{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001186 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1187 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188 u16 sum16;
1189
1190 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1191 || ip0->protocol == IP_PROTOCOL_UDP);
1192
1193 udp0 = (void *) (ip0 + 1);
1194 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1195 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001196 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1197 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198 return p0->flags;
1199 }
1200
1201 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1202
Damjan Marion213b5aa2017-07-13 21:19:27 +02001203 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1204 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001205
1206 return p0->flags;
1207}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001208#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209
Dave Barach68b0fb02017-02-28 15:15:56 -05001210/* *INDENT-OFF* */
1211VNET_FEATURE_ARC_INIT (ip4_local) =
1212{
1213 .arc_name = "ip4-local",
1214 .start_nodes = VNET_FEATURES ("ip4-local"),
Dave Baracha25def72018-11-26 11:04:45 -05001215 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001216};
1217/* *INDENT-ON* */
1218
Florin Coras20a14b92017-08-15 22:47:22 -07001219static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001220ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1221 ip4_header_t * ip, u8 is_udp, u8 * error,
1222 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001223{
1224 u32 flags0;
1225 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1226 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1227 if (is_udp)
1228 {
1229 udp_header_t *udp;
1230 u32 ip_len, udp_len;
1231 i32 len_diff;
1232 udp = ip4_next_header (ip);
1233 /* Verify UDP length. */
1234 ip_len = clib_net_to_host_u16 (ip->length);
1235 udp_len = clib_net_to_host_u16 (udp->length);
1236
1237 len_diff = ip_len - udp_len;
1238 *good_tcp_udp &= len_diff >= 0;
1239 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1240 }
1241}
1242
Florin Coras1b255522018-06-01 12:22:23 -07001243#define ip4_local_csum_is_offloaded(_b) \
1244 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1245 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1246
1247#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1248 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1249 || ip4_local_csum_is_offloaded (_b)))
1250
1251#define ip4_local_csum_is_valid(_b) \
1252 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1253 || (ip4_local_csum_is_offloaded (_b))) != 0
1254
1255static inline void
1256ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1257 ip4_header_t * ih, u8 * error)
1258{
1259 u8 is_udp, is_tcp_udp, good_tcp_udp;
1260
1261 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1262 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1263
1264 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1265 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1266 else
1267 good_tcp_udp = ip4_local_csum_is_valid (b);
1268
1269 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1270 *error = (is_tcp_udp && !good_tcp_udp
1271 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1272}
1273
1274static inline void
1275ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1276 ip4_header_t ** ih, u8 * error)
1277{
1278 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1279
1280 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1281 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1282
1283 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1284 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1285
1286 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1287 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1288
1289 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1290 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1291 {
1292 if (is_tcp_udp[0])
1293 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1294 &good_tcp_udp[0]);
1295 if (is_tcp_udp[1])
1296 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1297 &good_tcp_udp[1]);
1298 }
1299
1300 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1301 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1302 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1303 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1304}
1305
1306static inline void
1307ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1308 vlib_buffer_t * b, u16 * next, u8 error,
1309 u8 head_of_feature_arc)
1310{
1311 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1312 u32 next_index;
1313
1314 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1315 b->error = error ? error_node->errors[error] : 0;
1316 if (head_of_feature_arc)
1317 {
1318 next_index = *next;
1319 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1320 {
1321 vnet_feature_arc_start (arc_index,
1322 vnet_buffer (b)->sw_if_index[VLIB_RX],
1323 &next_index, b);
1324 *next = next_index;
1325 }
1326 }
1327}
1328
1329typedef struct
1330{
1331 ip4_address_t src;
1332 u32 lbi;
1333 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001334 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001335} ip4_local_last_check_t;
1336
1337static inline void
1338ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1339 ip4_local_last_check_t * last_check, u8 * error0)
1340{
1341 ip4_fib_mtrie_leaf_t leaf0;
1342 ip4_fib_mtrie_t *mtrie0;
1343 const dpo_id_t *dpo0;
1344 load_balance_t *lb0;
1345 u32 lbi0;
1346
1347 vnet_buffer (b)->ip.fib_index =
1348 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1349 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1350
Neale Rannsbe2286b2018-12-09 12:54:51 -08001351 if (PREDICT_FALSE (last_check->first ||
1352 (last_check->src.as_u32 != ip0->src_address.as_u32)))
Florin Coras1b255522018-06-01 12:22:23 -07001353 {
1354 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1355 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1356 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1357 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1358 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1359
1360 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1361 vnet_buffer (b)->ip.adj_index[VLIB_RX] = lbi0;
1362
1363 lb0 = load_balance_get (lbi0);
1364 dpo0 = load_balance_get_bucket_i (lb0, 0);
1365
1366 /*
1367 * Must have a route to source otherwise we drop the packet.
1368 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1369 *
1370 * The checks are:
1371 * - the source is a recieve => it's from us => bogus, do this
1372 * first since it sets a different error code.
1373 * - uRPF check for any route to source - accept if passes.
1374 * - allow packets destined to the broadcast address from unknown sources
1375 */
1376
1377 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1378 && dpo0->dpoi_type == DPO_RECEIVE) ?
1379 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1380 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1381 && !fib_urpf_check_size (lb0->lb_urpf)
1382 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1383 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1384
1385 last_check->src.as_u32 = ip0->src_address.as_u32;
1386 last_check->lbi = lbi0;
1387 last_check->error = *error0;
1388 }
1389 else
1390 {
1391 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1392 vnet_buffer (b)->ip.adj_index[VLIB_RX] = last_check->lbi;
1393 *error0 = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001394 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001395 }
1396}
1397
1398static inline void
1399ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1400 ip4_local_last_check_t * last_check, u8 * error)
1401{
1402 ip4_fib_mtrie_leaf_t leaf[2];
1403 ip4_fib_mtrie_t *mtrie[2];
1404 const dpo_id_t *dpo[2];
1405 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001406 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001407 u32 lbi[2];
1408
Neale Rannsbe2286b2018-12-09 12:54:51 -08001409 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001410 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1411 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1412
1413 vnet_buffer (b[0])->ip.fib_index =
1414 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1415 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1416 vnet_buffer (b[0])->ip.fib_index;
1417
1418 vnet_buffer (b[1])->ip.fib_index =
1419 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1420 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1421 vnet_buffer (b[1])->ip.fib_index;
1422
1423 if (PREDICT_FALSE (not_last_hit))
1424 {
1425 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1426 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1427
1428 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1429 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1430
1431 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1432 &ip[0]->src_address, 2);
1433 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1434 &ip[1]->src_address, 2);
1435
1436 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1437 &ip[0]->src_address, 3);
1438 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1439 &ip[1]->src_address, 3);
1440
1441 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1442 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1443
1444 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1445 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = lbi[0];
1446
1447 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1448 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = lbi[1];
1449
1450 lb[0] = load_balance_get (lbi[0]);
1451 lb[1] = load_balance_get (lbi[1]);
1452
1453 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1454 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1455
1456 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1457 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1458 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1459 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1460 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1461 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1462 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1463
1464 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1465 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1466 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1467 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1468 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1469 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1470 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1471
1472 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1473 last_check->lbi = lbi[1];
1474 last_check->error = error[1];
1475 }
1476 else
1477 {
1478 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1479 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = last_check->lbi;
1480
1481 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1482 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = last_check->lbi;
1483
1484 error[0] = last_check->error;
1485 error[1] = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001486 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001487 }
1488}
Florin Coras20a14b92017-08-15 22:47:22 -07001489
Florin Corasc67cfd22018-10-01 21:59:18 -07001490enum ip_local_packet_type_e
1491{
1492 IP_LOCAL_PACKET_TYPE_L4,
1493 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001494 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001495};
1496
1497/**
1498 * Determine packet type and next node.
1499 *
1500 * The expectation is that all packets that are not L4 will skip
1501 * checksums and source checks.
1502 */
1503always_inline u8
1504ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1505{
1506 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1507
Juraj Sloboda3048b632018-10-02 11:13:53 +02001508 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1509 {
1510 *next = IP_LOCAL_NEXT_REASSEMBLY;
1511 return IP_LOCAL_PACKET_TYPE_FRAG;
1512 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001513 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1514 {
1515 *next = lm->local_next_by_ip_protocol[ip->protocol];
1516 return IP_LOCAL_PACKET_TYPE_NAT;
1517 }
1518
1519 *next = lm->local_next_by_ip_protocol[ip->protocol];
1520 return IP_LOCAL_PACKET_TYPE_L4;
1521}
1522
Dave Barach68b0fb02017-02-28 15:15:56 -05001523static inline uword
1524ip4_local_inline (vlib_main_t * vm,
1525 vlib_node_runtime_t * node,
1526 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001527{
Florin Coras1b255522018-06-01 12:22:23 -07001528 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001529 vlib_node_runtime_t *error_node =
1530 vlib_node_get_runtime (vm, ip4_input_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001531 u16 nexts[VLIB_FRAME_SIZE], *next;
1532 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1533 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001534 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001535
1536 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001537 /*
1538 * 0.0.0.0 can appear as the source address of an IP packet,
1539 * as can any other address, hence the need to use the 'first'
1540 * member to make sure the .lbi is initialised for the first
1541 * packet.
1542 */
Florin Coras1b255522018-06-01 12:22:23 -07001543 .src = {.as_u32 = 0},
1544 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001545 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1546 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001547 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001548
1549 from = vlib_frame_vector_args (frame);
1550 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001551
Ed Warnickecb9cada2015-12-08 15:45:58 -07001552 if (node->flags & VLIB_NODE_FLAG_TRACE)
1553 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1554
Florin Coras1b255522018-06-01 12:22:23 -07001555 vlib_get_buffers (vm, from, bufs, n_left_from);
1556 b = bufs;
1557 next = nexts;
1558
1559 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001560 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001561 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001562
Florin Coras1b255522018-06-01 12:22:23 -07001563 /* Prefetch next iteration. */
1564 {
1565 vlib_prefetch_buffer_header (b[4], LOAD);
1566 vlib_prefetch_buffer_header (b[5], LOAD);
1567
1568 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1569 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1570 }
1571
1572 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1573
1574 ip[0] = vlib_buffer_get_current (b[0]);
1575 ip[1] = vlib_buffer_get_current (b[1]);
1576
1577 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1578 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1579
Florin Corasc67cfd22018-10-01 21:59:18 -07001580 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1581 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001582
Florin Corasc67cfd22018-10-01 21:59:18 -07001583 not_batch = pt[0] ^ pt[1];
1584
1585 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001586 goto skip_checks;
1587
1588 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001589 {
Florin Coras1b255522018-06-01 12:22:23 -07001590 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1591 ip4_local_check_src_x2 (b, ip, &last_check, error);
1592 }
1593 else
1594 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001595 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001596 {
Florin Coras1b255522018-06-01 12:22:23 -07001597 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1598 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
Florin Coras20a14b92017-08-15 22:47:22 -07001599 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001600 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601 {
Florin Coras1b255522018-06-01 12:22:23 -07001602 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1603 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001604 }
1605 }
1606
Florin Coras1b255522018-06-01 12:22:23 -07001607 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001608
Florin Coras1b255522018-06-01 12:22:23 -07001609 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1610 head_of_feature_arc);
1611 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1612 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001613
Florin Coras1b255522018-06-01 12:22:23 -07001614 b += 2;
1615 next += 2;
1616 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617 }
1618
Florin Coras1b255522018-06-01 12:22:23 -07001619 while (n_left_from > 0)
1620 {
1621 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1622
1623 ip[0] = vlib_buffer_get_current (b[0]);
1624 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001625 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001626
Florin Corasc67cfd22018-10-01 21:59:18 -07001627 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001628 goto skip_check;
1629
1630 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1631 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1632
1633 skip_check:
1634
Florin Coras1b255522018-06-01 12:22:23 -07001635 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1636 head_of_feature_arc);
1637
1638 b += 1;
1639 next += 1;
1640 n_left_from -= 1;
1641 }
1642
1643 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001644 return frame->n_vectors;
1645}
1646
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001647VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1648 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001649{
1650 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1651}
1652
1653/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001654VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001655{
Dave Barach68b0fb02017-02-28 15:15:56 -05001656 .name = "ip4-local",
1657 .vector_size = sizeof (u32),
1658 .format_trace = format_ip4_forward_next_trace,
1659 .n_next_nodes = IP_LOCAL_N_NEXT,
1660 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001661 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001662 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1663 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001664 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001665 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Juraj Sloboda3048b632018-10-02 11:13:53 +02001666 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001667 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001668};
1669/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001670
Dave Barachd7cb1b52016-12-09 09:52:16 -05001671
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001672VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1673 vlib_node_runtime_t * node,
1674 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001675{
1676 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1677}
1678
1679/* *INDENT-OFF* */
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001680VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001681 .name = "ip4-local-end-of-arc",
1682 .vector_size = sizeof (u32),
1683
1684 .format_trace = format_ip4_forward_next_trace,
1685 .sibling_of = "ip4-local",
1686};
1687
Dave Barach68b0fb02017-02-28 15:15:56 -05001688VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1689 .arc_name = "ip4-local",
1690 .node_name = "ip4-local-end-of-arc",
1691 .runs_before = 0, /* not before any other features */
1692};
1693/* *INDENT-ON* */
1694
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001695#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001696void
1697ip4_register_protocol (u32 protocol, u32 node_index)
1698{
1699 vlib_main_t *vm = vlib_get_main ();
1700 ip4_main_t *im = &ip4_main;
1701 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001702
1703 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001704 lm->local_next_by_ip_protocol[protocol] =
1705 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001706}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001707#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708
1709static clib_error_t *
1710show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001711 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001712{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001713 ip4_main_t *im = &ip4_main;
1714 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001715 int i;
1716
1717 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001718 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001719 {
1720 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001721 {
1722 u32 node_index = vlib_get_node (vm,
1723 ip4_local_node.index)->
1724 next_nodes[lm->local_next_by_ip_protocol[i]];
1725 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1726 node_index);
1727 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728 }
1729 return 0;
1730}
1731
1732
1733
Billy McFall0683c9c2016-10-13 08:27:31 -04001734/*?
1735 * Display the set of protocols handled by the local IPv4 stack.
1736 *
1737 * @cliexpar
1738 * Example of how to display local protocol table:
1739 * @cliexstart{show ip local}
1740 * Protocols handled by ip4_local
1741 * 1
1742 * 17
1743 * 47
1744 * @cliexend
1745?*/
1746/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001747VLIB_CLI_COMMAND (show_ip_local, static) =
1748{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001749 .path = "show ip local",
1750 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001751 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001752};
Billy McFall0683c9c2016-10-13 08:27:31 -04001753/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001754
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001755always_inline uword
1756ip4_arp_inline (vlib_main_t * vm,
1757 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001758 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 vnet_main_t *vnm = vnet_get_main ();
1761 ip4_main_t *im = &ip4_main;
1762 ip_lookup_main_t *lm = &im->lookup_main;
1763 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764 uword n_left_from, n_left_to_next_drop, next_index;
Dave Barach49433ad2018-08-08 17:59:03 -04001765 u32 thread_index = vm->thread_index;
Neale Rannscd35e532018-08-31 02:51:45 -07001766 u64 seed;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001767
1768 if (node->flags & VLIB_NODE_FLAG_TRACE)
1769 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1770
Neale Rannsc8352bc2018-08-29 10:23:58 -07001771 seed = throttle_seed (&im->arp_throttle, thread_index, vlib_time_now (vm));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772
1773 from = vlib_frame_vector_args (frame);
1774 n_left_from = frame->n_vectors;
1775 next_index = node->cached_next_index;
1776 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001777 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001778
1779 while (n_left_from > 0)
1780 {
1781 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1782 to_next_drop, n_left_to_next_drop);
1783
1784 while (n_left_from > 0 && n_left_to_next_drop > 0)
1785 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001786 u32 pi0, bi0, adj_index0, sw_if_index0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001787 ip_adjacency_t *adj0;
Eyal Baribf9f02c2018-10-31 13:19:11 +02001788 vlib_buffer_t *p0, *b0;
1789 ip4_address_t resolve0;
1790 ethernet_arp_header_t *h0;
1791 vnet_hw_interface_t *hw_if0;
Neale Rannscd35e532018-08-31 02:51:45 -07001792 u64 r0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001793
1794 pi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001795 p0 = vlib_get_buffer (vm, pi0);
1796
Ed Warnickecb9cada2015-12-08 15:45:58 -07001797 from += 1;
1798 n_left_from -= 1;
1799 to_next_drop[0] = pi0;
1800 to_next_drop += 1;
1801 n_left_to_next_drop -= 1;
1802
Eyal Baribf9f02c2018-10-31 13:19:11 +02001803 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1804 adj0 = adj_get (adj_index0);
1805
1806 if (is_glean)
1807 {
1808 /* resolve the packet's destination */
1809 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1810 resolve0 = ip0->dst_address;
1811 }
1812 else
1813 {
1814 /* resolve the incomplete adj */
1815 resolve0 = adj0->sub_type.nbr.next_hop.ip4;
1816 }
1817
1818 /* combine the address and interface for the hash key */
1819 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1820 r0 = (u64) resolve0.data_u32 << 32;
1821 r0 |= sw_if_index0;
1822
1823 if (throttle_check (&im->arp_throttle, thread_index, r0, seed))
1824 {
1825 p0->error = node->errors[IP4_ARP_ERROR_THROTTLED];
1826 continue;
1827 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001828
Neale Rannsb80c5362016-10-08 13:03:40 +01001829 /*
1830 * the adj has been updated to a rewrite but the node the DPO that got
1831 * us here hasn't - yet. no big deal. we'll drop while we wait.
1832 */
1833 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
Eyal Baribf9f02c2018-10-31 13:19:11 +02001834 {
1835 p0->error = node->errors[IP4_ARP_ERROR_RESOLVED];
1836 continue;
1837 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001838
Dave Barachd7cb1b52016-12-09 09:52:16 -05001839 /*
1840 * Can happen if the control-plane is programming tables
1841 * with traffic flowing; at least that's today's lame excuse.
1842 */
Neale Ranns32e1c012016-11-22 17:07:28 +00001843 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1844 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001845 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001846 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Eyal Baribf9f02c2018-10-31 13:19:11 +02001847 continue;
1848 }
1849 /* Send ARP request. */
1850 h0 =
1851 vlib_packet_template_get_packet (vm,
1852 &im->ip4_arp_request_packet_template,
1853 &bi0);
Neale Ranns45db8852019-01-09 00:04:04 -08001854 b0 = vlib_get_buffer (vm, bi0);
1855
1856 /* copy the persistent fields from the original */
1857 clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
Eyal Baribf9f02c2018-10-31 13:19:11 +02001858
1859 /* Seems we're out of buffers */
1860 if (PREDICT_FALSE (!h0))
1861 {
1862 p0->error = node->errors[IP4_ARP_ERROR_NO_BUFFERS];
1863 continue;
1864 }
1865
1866 /* Add rewrite/encap string for ARP packet. */
1867 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
1868
1869 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1870
1871 /* Src ethernet address in ARP header. */
Neale Ranns37029302018-08-10 05:30:06 -07001872 mac_address_from_bytes (&h0->ip4_over_ethernet[0].mac,
1873 hw_if0->hw_address);
Eyal Baribf9f02c2018-10-31 13:19:11 +02001874 if (is_glean)
1875 {
1876 /* The interface's source address is stashed in the Glean Adj */
1877 h0->ip4_over_ethernet[0].ip4 =
1878 adj0->sub_type.glean.receive_addr.ip4;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001879 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001880 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001881 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001882 /* Src IP address in ARP header. */
1883 if (ip4_src_address_for_packet (lm, sw_if_index0,
1884 &h0->ip4_over_ethernet[0].ip4))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001885 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001886 /* No source address available */
1887 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1888 vlib_buffer_free (vm, &bi0, 1);
1889 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001890 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001891 }
Eyal Baribf9f02c2018-10-31 13:19:11 +02001892 h0->ip4_over_ethernet[1].ip4 = resolve0;
1893
1894 p0->error = node->errors[IP4_ARP_ERROR_REQUEST_SENT];
1895
1896 vlib_buffer_copy_trace_flag (vm, p0, bi0);
Eyal Baribf9f02c2018-10-31 13:19:11 +02001897 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
1898 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1899
1900 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1901
1902 vlib_set_next_frame_buffer (vm, node,
1903 adj0->rewrite_header.next_index, bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001904 }
1905
1906 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1907 }
1908
1909 return frame->n_vectors;
1910}
1911
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001912VLIB_NODE_FN (ip4_arp_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1913 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001914{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001915 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001916}
1917
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001918VLIB_NODE_FN (ip4_glean_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1919 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001920{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001921 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001922}
1923
Dave Barachd7cb1b52016-12-09 09:52:16 -05001924static char *ip4_arp_error_strings[] = {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001925 [IP4_ARP_ERROR_THROTTLED] = "ARP requests throttled",
1926 [IP4_ARP_ERROR_RESOLVED] = "ARP requests resolved",
1927 [IP4_ARP_ERROR_NO_BUFFERS] = "ARP requests out of buffer",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1929 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001930 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001931};
1932
Neale Rannsf8686322017-11-29 02:39:53 -08001933/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001934VLIB_REGISTER_NODE (ip4_arp_node) =
1935{
Neale Rannsf8686322017-11-29 02:39:53 -08001936 .name = "ip4-arp",
1937 .vector_size = sizeof (u32),
1938 .format_trace = format_ip4_forward_next_trace,
1939 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1940 .error_strings = ip4_arp_error_strings,
1941 .n_next_nodes = IP4_ARP_N_NEXT,
1942 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001943 {
Neale Rannsf8686322017-11-29 02:39:53 -08001944 [IP4_ARP_NEXT_DROP] = "error-drop",
1945 },
1946};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001947
Dave Barachd7cb1b52016-12-09 09:52:16 -05001948VLIB_REGISTER_NODE (ip4_glean_node) =
1949{
Neale Rannsf8686322017-11-29 02:39:53 -08001950 .name = "ip4-glean",
1951 .vector_size = sizeof (u32),
1952 .format_trace = format_ip4_forward_next_trace,
1953 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1954 .error_strings = ip4_arp_error_strings,
1955 .n_next_nodes = IP4_ARP_N_NEXT,
1956 .next_nodes = {
1957 [IP4_ARP_NEXT_DROP] = "error-drop",
1958 },
1959};
1960/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001961
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962#define foreach_notrace_ip4_arp_error \
Eyal Baribf9f02c2018-10-31 13:19:11 +02001963_(THROTTLED) \
1964_(RESOLVED) \
1965_(NO_BUFFERS) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001966_(REQUEST_SENT) \
Eyal Baribf9f02c2018-10-31 13:19:11 +02001967_(NON_ARP_ADJ) \
1968_(NO_SOURCE_ADDRESS)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001969
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001970static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001971arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001972{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001973 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001974
1975 /* don't trace ARP request packets */
1976#define _(a) \
1977 vnet_pcap_drop_trace_filter_add_del \
1978 (rt->errors[IP4_ARP_ERROR_##a], \
1979 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001980 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001981#undef _
1982 return 0;
1983}
1984
Dave Barachd7cb1b52016-12-09 09:52:16 -05001985VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001986
1987
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001988#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001989/* Send an ARP request to see if given destination is reachable on given interface. */
1990clib_error_t *
John Lo86376342018-06-11 20:14:49 -04001991ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index,
1992 u8 refresh)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001993{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001994 vnet_main_t *vnm = vnet_get_main ();
1995 ip4_main_t *im = &ip4_main;
1996 ethernet_arp_header_t *h;
1997 ip4_address_t *src;
1998 ip_interface_address_t *ia;
1999 ip_adjacency_t *adj;
2000 vnet_hw_interface_t *hi;
2001 vnet_sw_interface_t *si;
2002 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002003 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002004 u32 bi = 0;
John Lo86376342018-06-11 20:14:49 -04002005 u8 unicast_rewrite = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006
2007 si = vnet_get_sw_interface (vnm, sw_if_index);
2008
2009 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2010 {
2011 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002012 format_ip4_address, dst,
2013 format_vnet_sw_if_index_name, vnm,
2014 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002015 }
2016
Dave Barachd7cb1b52016-12-09 09:52:16 -05002017 src =
2018 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2019 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002020 {
2021 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002022 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002023 (0,
2024 "no matching interface address for destination %U (interface %U)",
2025 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2026 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002027 }
2028
Neale Ranns7a272742017-05-30 02:08:14 -07002029 h = vlib_packet_template_get_packet (vm,
2030 &im->ip4_arp_request_packet_template,
2031 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002032
John Lo084606b2018-06-19 15:27:48 -04002033 if (!h)
2034 return clib_error_return (0, "ARP request packet allocation failed");
2035
Ed Warnickecb9cada2015-12-08 15:45:58 -07002036 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002037 if (PREDICT_FALSE (!hi->hw_address))
2038 {
2039 return clib_error_return (0, "%U: interface %U do not support ip probe",
2040 format_ip4_address, dst,
2041 format_vnet_sw_if_index_name, vnm,
2042 sw_if_index);
2043 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044
Neale Ranns37029302018-08-10 05:30:06 -07002045 mac_address_from_bytes (&h->ip4_over_ethernet[0].mac, hi->hw_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046
2047 h->ip4_over_ethernet[0].ip4 = src[0];
2048 h->ip4_over_ethernet[1].ip4 = dst[0];
2049
2050 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002051 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2052 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002053
Dave Barach59b25652017-09-10 15:04:27 -04002054 ip46_address_t nh = {
2055 .ip4 = *dst,
2056 };
2057
2058 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2059 VNET_LINK_IP4, &nh, sw_if_index);
2060 adj = adj_get (ai);
2061
2062 /* Peer has been previously resolved, retrieve glean adj instead */
2063 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2064 {
John Lo86376342018-06-11 20:14:49 -04002065 if (refresh)
2066 unicast_rewrite = 1;
2067 else
2068 {
2069 adj_unlock (ai);
2070 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
2071 VNET_LINK_IP4, sw_if_index, &nh);
2072 adj = adj_get (ai);
2073 }
Dave Barach59b25652017-09-10 15:04:27 -04002074 }
2075
Ed Warnickecb9cada2015-12-08 15:45:58 -07002076 /* Add encapsulation string for software interface (e.g. ethernet header). */
2077 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
John Lo86376342018-06-11 20:14:49 -04002078 if (unicast_rewrite)
2079 {
2080 u16 *etype = vlib_buffer_get_current (b) - 2;
2081 etype[0] = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
2082 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002083 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2084
2085 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002086 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2087 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002088 to_next[0] = bi;
2089 f->n_vectors = 1;
2090 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2091 }
2092
Neale Ranns7a272742017-05-30 02:08:14 -07002093 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002094 return /* no error */ 0;
2095}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002096#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002097
Dave Barachd7cb1b52016-12-09 09:52:16 -05002098typedef enum
2099{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002100 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002101 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02002102 IP4_REWRITE_NEXT_FRAGMENT,
2103 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104} ip4_rewrite_next_t;
2105
Neale Ranns889fe942017-06-01 05:43:19 -04002106/**
2107 * This bits of an IPv4 address to mask to construct a multicast
2108 * MAC address
2109 */
2110#if CLIB_ARCH_IS_BIG_ENDIAN
2111#define IP4_MCAST_ADDR_MASK 0x007fffff
2112#else
2113#define IP4_MCAST_ADDR_MASK 0xffff7f00
2114#endif
2115
Ole Troan8a9c8f12018-05-18 11:01:31 +02002116always_inline void
2117ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002118 u16 adj_packet_bytes, bool df, u16 * next, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002119{
2120 if (packet_len > adj_packet_bytes)
2121 {
2122 *error = IP4_ERROR_MTU_EXCEEDED;
2123 if (df)
2124 {
2125 icmp4_error_set_vnet_buffer
2126 (b, ICMP4_destination_unreachable,
2127 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2128 adj_packet_bytes);
2129 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2130 }
2131 else
2132 {
Ole Troan313f7e22018-04-10 16:02:51 +02002133 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002134 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troanb3655e52018-08-16 22:08:49 +02002135 IP4_FRAG_NEXT_IP4_REWRITE, 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002136 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002137 }
2138 }
2139}
2140
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002141/* Decrement TTL & update checksum.
2142 Works either endian, so no need for byte swap. */
2143static_always_inline void
2144ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2145 u32 * error)
2146{
2147 i32 ttl;
2148 u32 checksum;
2149 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2150 {
2151 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2152 return;
2153 }
2154
2155 ttl = ip->ttl;
2156
2157 /* Input node should have reject packets with ttl 0. */
2158 ASSERT (ip->ttl > 0);
2159
2160 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2161 checksum += checksum >= 0xffff;
2162
2163 ip->checksum = checksum;
2164 ttl -= 1;
2165 ip->ttl = ttl;
2166
2167 /*
2168 * If the ttl drops below 1 when forwarding, generate
2169 * an ICMP response.
2170 */
2171 if (PREDICT_FALSE (ttl <= 0))
2172 {
2173 *error = IP4_ERROR_TIME_EXPIRED;
2174 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2175 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2176 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2177 0);
2178 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2179 }
2180
2181 /* Verify checksum. */
2182 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2183 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2184}
2185
2186
Ed Warnickecb9cada2015-12-08 15:45:58 -07002187always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002188ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2189 vlib_node_runtime_t * node,
2190 vlib_frame_t * frame,
2191 int do_counters, int is_midchain, int is_mcast,
2192 int do_gso)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002193{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002194 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2195 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002196 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2197 u16 nexts[VLIB_FRAME_SIZE], *next;
2198 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002199 vlib_node_runtime_t *error_node =
2200 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002201
2202 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002203 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002204
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002205 vlib_get_buffers (vm, from, bufs, n_left_from);
2206 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2207
2208 if (n_left_from >= 6)
2209 {
2210 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002211 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002212 vlib_prefetch_buffer_header (bufs[i], LOAD);
2213 }
2214
2215 next = nexts;
2216 b = bufs;
2217 while (n_left_from >= 8)
2218 {
2219 ip_adjacency_t *adj0, *adj1;
2220 ip4_header_t *ip0, *ip1;
2221 u32 rw_len0, error0, adj_index0;
2222 u32 rw_len1, error1, adj_index1;
2223 u32 tx_sw_if_index0, tx_sw_if_index1;
2224 u8 *p;
2225
2226 vlib_prefetch_buffer_header (b[6], LOAD);
2227 vlib_prefetch_buffer_header (b[7], LOAD);
2228
2229 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2230 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2231
2232 /*
2233 * pre-fetch the per-adjacency counters
2234 */
2235 if (do_counters)
2236 {
2237 vlib_prefetch_combined_counter (&adjacency_counters,
2238 thread_index, adj_index0);
2239 vlib_prefetch_combined_counter (&adjacency_counters,
2240 thread_index, adj_index1);
2241 }
2242
2243 ip0 = vlib_buffer_get_current (b[0]);
2244 ip1 = vlib_buffer_get_current (b[1]);
2245
2246 error0 = error1 = IP4_ERROR_NONE;
2247
2248 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2249 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2250
2251 /* Rewrite packet header and updates lengths. */
2252 adj0 = adj_get (adj_index0);
2253 adj1 = adj_get (adj_index1);
2254
2255 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2256 rw_len0 = adj0[0].rewrite_header.data_bytes;
2257 rw_len1 = adj1[0].rewrite_header.data_bytes;
2258 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2259 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2260
2261 p = vlib_buffer_get_current (b[2]);
2262 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2263 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2264
2265 p = vlib_buffer_get_current (b[3]);
2266 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2267 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2268
2269 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002270 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2271 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2272
2273 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2274 ip0_len = gso_mtu_sz (b[0]);
2275 if (do_gso && (b[1]->flags & VNET_BUFFER_F_GSO))
2276 ip1_len = gso_mtu_sz (b[1]);
2277
2278 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002279 adj0[0].rewrite_header.max_l3_packet_bytes,
2280 ip0->flags_and_fragment_offset &
2281 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2282 next + 0, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002283 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002284 adj1[0].rewrite_header.max_l3_packet_bytes,
2285 ip1->flags_and_fragment_offset &
2286 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2287 next + 1, &error1);
2288
2289 if (is_mcast)
2290 {
2291 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2292 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2293 IP4_ERROR_SAME_INTERFACE : error0);
2294 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2295 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2296 IP4_ERROR_SAME_INTERFACE : error1);
2297 }
2298
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002299 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002300 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002301 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2302 {
2303 u32 next_index = adj0[0].rewrite_header.next_index;
2304 b[0]->current_data -= rw_len0;
2305 b[0]->current_length += rw_len0;
2306 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2307 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2308
2309 if (PREDICT_FALSE
2310 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2311 vnet_feature_arc_start (lm->output_feature_arc_index,
2312 tx_sw_if_index0, &next_index, b[0]);
2313 next[0] = next_index;
2314 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002315 else
2316 {
2317 b[0]->error = error_node->errors[error0];
2318 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002319 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2320 {
2321 u32 next_index = adj1[0].rewrite_header.next_index;
2322 b[1]->current_data -= rw_len1;
2323 b[1]->current_length += rw_len1;
2324
2325 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2326 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2327
2328 if (PREDICT_FALSE
2329 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2330 vnet_feature_arc_start (lm->output_feature_arc_index,
2331 tx_sw_if_index1, &next_index, b[1]);
2332 next[1] = next_index;
2333 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002334 else
2335 {
2336 b[1]->error = error_node->errors[error1];
2337 }
Neale Ranns25edf142019-03-22 08:12:48 +00002338 if (is_midchain)
2339 {
2340 calc_checksums (vm, b[0]);
2341 calc_checksums (vm, b[1]);
2342 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002343 /* Guess we are only writing on simple Ethernet header. */
2344 vnet_rewrite_two_headers (adj0[0], adj1[0],
2345 ip0, ip1, sizeof (ethernet_header_t));
2346
2347 /*
2348 * Bump the per-adjacency counters
2349 */
2350 if (do_counters)
2351 {
2352 vlib_increment_combined_counter
2353 (&adjacency_counters,
2354 thread_index,
2355 adj_index0, 1, vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2356
2357 vlib_increment_combined_counter
2358 (&adjacency_counters,
2359 thread_index,
2360 adj_index1, 1, vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2361 }
2362
2363 if (is_midchain)
2364 {
Neale Ranns25edf142019-03-22 08:12:48 +00002365 if (adj0->sub_type.midchain.fixup_func)
2366 adj0->sub_type.midchain.fixup_func
2367 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2368 if (adj1->sub_type.midchain.fixup_func)
2369 adj1->sub_type.midchain.fixup_func
2370 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002371 }
2372
2373 if (is_mcast)
2374 {
2375 /*
2376 * copy bytes from the IP address into the MAC rewrite
2377 */
2378 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2379 adj0->rewrite_header.dst_mcast_offset,
2380 &ip0->dst_address.as_u32, (u8 *) ip0);
2381 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
Zhiyong Yangb2ecc5d2018-12-13 14:09:40 +08002382 adj1->rewrite_header.dst_mcast_offset,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002383 &ip1->dst_address.as_u32, (u8 *) ip1);
2384 }
2385
2386 next += 2;
2387 b += 2;
2388 n_left_from -= 2;
2389 }
2390
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391 while (n_left_from > 0)
2392 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002393 ip_adjacency_t *adj0;
2394 ip4_header_t *ip0;
2395 u32 rw_len0, adj_index0, error0;
2396 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002397
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002398 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2399
2400 adj0 = adj_get (adj_index0);
2401
2402 if (do_counters)
2403 vlib_prefetch_combined_counter (&adjacency_counters,
2404 thread_index, adj_index0);
2405
2406 ip0 = vlib_buffer_get_current (b[0]);
2407
2408 error0 = IP4_ERROR_NONE;
2409
2410 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2411
2412
2413 /* Update packet buffer attributes/set output interface. */
2414 rw_len0 = adj0[0].rewrite_header.data_bytes;
2415 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2416
2417 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002418 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2419 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2420 ip0_len = gso_mtu_sz (b[0]);
2421
2422 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002423 adj0[0].rewrite_header.max_l3_packet_bytes,
2424 ip0->flags_and_fragment_offset &
2425 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2426 next + 0, &error0);
2427
2428 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002429 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002430 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2431 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2432 IP4_ERROR_SAME_INTERFACE : error0);
2433 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002434
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002435 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002436 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002437 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2438 {
2439 u32 next_index = adj0[0].rewrite_header.next_index;
2440 b[0]->current_data -= rw_len0;
2441 b[0]->current_length += rw_len0;
2442 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2443 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002444
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002445 if (PREDICT_FALSE
2446 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2447 vnet_feature_arc_start (lm->output_feature_arc_index,
2448 tx_sw_if_index0, &next_index, b[0]);
2449 next[0] = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002450 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002451 else
2452 {
2453 b[0]->error = error_node->errors[error0];
2454 }
Neale Ranns25edf142019-03-22 08:12:48 +00002455 if (is_midchain)
2456 {
2457 calc_checksums (vm, b[0]);
2458 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002459 /* Guess we are only writing on simple Ethernet header. */
2460 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2461
2462 if (do_counters)
2463 vlib_increment_combined_counter
2464 (&adjacency_counters,
2465 thread_index, adj_index0, 1,
2466 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2467
2468 if (is_midchain)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002469 {
Neale Ranns25edf142019-03-22 08:12:48 +00002470 if (adj0->sub_type.midchain.fixup_func)
2471 adj0->sub_type.midchain.fixup_func
2472 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002473 }
Dave Barach75fc8542016-10-11 16:16:02 -04002474
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002475 if (is_mcast)
2476 {
2477 /*
2478 * copy bytes from the IP address into the MAC rewrite
2479 */
2480 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2481 adj0->rewrite_header.dst_mcast_offset,
2482 &ip0->dst_address.as_u32, (u8 *) ip0);
2483 }
2484
2485 next += 1;
2486 b += 1;
2487 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002488 }
2489
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002490
Ed Warnickecb9cada2015-12-08 15:45:58 -07002491 /* Need to do trace after rewrites to pick up new packet data. */
2492 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002493 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002494
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002495 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002496 return frame->n_vectors;
2497}
2498
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002499always_inline uword
2500ip4_rewrite_inline (vlib_main_t * vm,
2501 vlib_node_runtime_t * node,
2502 vlib_frame_t * frame,
2503 int do_counters, int is_midchain, int is_mcast)
2504{
2505 vnet_main_t *vnm = vnet_get_main ();
2506 if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
2507 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2508 is_midchain, is_mcast,
2509 1 /* do_gso */ );
2510 else
2511 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2512 is_midchain, is_mcast,
2513 0 /* no do_gso */ );
2514}
2515
Dave Barach132d51d2016-07-07 10:10:17 -04002516
Neale Rannsf06aea52016-11-29 06:51:37 -08002517/** @brief IPv4 rewrite node.
2518 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002519
2520 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2521 header checksum, fetch the ip adjacency, check the outbound mtu,
2522 apply the adjacency rewrite, and send pkts to the adjacency
2523 rewrite header's rewrite_next_index.
2524
2525 @param vm vlib_main_t corresponding to the current thread
2526 @param node vlib_node_runtime_t
2527 @param frame vlib_frame_t whose contents should be dispatched
2528
2529 @par Graph mechanics: buffer metadata, next index usage
2530
2531 @em Uses:
2532 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2533 - the rewrite adjacency index
2534 - <code>adj->lookup_next_index</code>
2535 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002536 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002537 - <code>adj->rewrite_header</code>
2538 - Rewrite string length, rewrite string, next_index
2539
2540 @em Sets:
2541 - <code>b->current_data, b->current_length</code>
2542 - Updated net of applying the rewrite string
2543
2544 <em>Next Indices:</em>
2545 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002546 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002547*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002548
2549VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2550 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002551{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002552 if (adj_are_counters_enabled ())
2553 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2554 else
2555 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002556}
2557
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002558VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2559 vlib_node_runtime_t * node,
2560 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002561{
2562 if (adj_are_counters_enabled ())
2563 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2564 else
2565 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2566}
2567
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002568VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2569 vlib_node_runtime_t * node,
2570 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002571{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002572 if (adj_are_counters_enabled ())
2573 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2574 else
2575 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002576}
2577
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002578VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2579 vlib_node_runtime_t * node,
2580 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002581{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002582 if (adj_are_counters_enabled ())
2583 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2584 else
2585 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002586}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002587
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002588VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2589 vlib_node_runtime_t * node,
2590 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002591{
2592 if (adj_are_counters_enabled ())
2593 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2594 else
2595 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2596}
2597
Neale Ranns32e1c012016-11-22 17:07:28 +00002598/* *INDENT-OFF* */
2599VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002600 .name = "ip4-rewrite",
2601 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002602
Neale Ranns32e1c012016-11-22 17:07:28 +00002603 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002604
Ole Troan313f7e22018-04-10 16:02:51 +02002605 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002606 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002607 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002608 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002609 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002610 },
2611};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002612
2613VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002614 .name = "ip4-rewrite-bcast",
2615 .vector_size = sizeof (u32),
2616
2617 .format_trace = format_ip4_rewrite_trace,
2618 .sibling_of = "ip4-rewrite",
2619};
Neale Ranns32e1c012016-11-22 17:07:28 +00002620
2621VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002622 .name = "ip4-rewrite-mcast",
2623 .vector_size = sizeof (u32),
2624
2625 .format_trace = format_ip4_rewrite_trace,
2626 .sibling_of = "ip4-rewrite",
2627};
Neale Ranns32e1c012016-11-22 17:07:28 +00002628
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002629VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002630 .name = "ip4-mcast-midchain",
2631 .vector_size = sizeof (u32),
2632
2633 .format_trace = format_ip4_rewrite_trace,
2634 .sibling_of = "ip4-rewrite",
2635};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002636
Neale Ranns32e1c012016-11-22 17:07:28 +00002637VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002638 .name = "ip4-midchain",
2639 .vector_size = sizeof (u32),
2640 .format_trace = format_ip4_forward_next_trace,
2641 .sibling_of = "ip4-rewrite",
2642};
Neale Ranns32e1c012016-11-22 17:07:28 +00002643/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002644
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002645static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002646ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2647{
2648 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002649 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002650 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002651
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002652 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002653
Neale Ranns04a75e32017-03-23 06:46:01 -07002654 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2656 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002657
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002658 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002659
Dave Barachd7cb1b52016-12-09 09:52:16 -05002660 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002661}
Dave Barach75fc8542016-10-11 16:16:02 -04002662
Ed Warnickecb9cada2015-12-08 15:45:58 -07002663static clib_error_t *
2664test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002665 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002666{
Billy McFall309fe062016-10-14 07:37:33 -04002667 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002668 u32 table_id = 0;
2669 f64 count = 1;
2670 u32 n;
2671 int i;
2672 ip4_address_t ip4_base_address;
2673 u64 errors = 0;
2674
Dave Barachd7cb1b52016-12-09 09:52:16 -05002675 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2676 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002678 {
2679 /* Make sure the entry exists. */
2680 fib = ip4_fib_get (table_id);
2681 if ((fib) && (fib->index != table_id))
2682 return clib_error_return (0, "<fib-index> %d does not exist",
2683 table_id);
2684 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002685 else if (unformat (input, "count %f", &count))
2686 ;
2687
2688 else if (unformat (input, "%U",
2689 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002690 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002691 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002692 return clib_error_return (0, "unknown input `%U'",
2693 format_unformat_error, input);
2694 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002695
2696 n = count;
2697
2698 for (i = 0; i < n; i++)
2699 {
2700 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002701 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002702
Dave Barach75fc8542016-10-11 16:16:02 -04002703 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002704 clib_host_to_net_u32 (1 +
2705 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002706 }
2707
Dave Barach75fc8542016-10-11 16:16:02 -04002708 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002709 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2710 else
2711 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2712
2713 return 0;
2714}
2715
Billy McFall0683c9c2016-10-13 08:27:31 -04002716/*?
2717 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2718 * given FIB table to determine if there is a conflict with the
2719 * adjacency table. The fib-id can be determined by using the
2720 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2721 * of 0 is used.
2722 *
2723 * @todo This command uses fib-id, other commands use table-id (not
2724 * just a name, they are different indexes). Would like to change this
2725 * to table-id for consistency.
2726 *
2727 * @cliexpar
2728 * Example of how to run the test lookup command:
2729 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2730 * No errors in 2 lookups
2731 * @cliexend
2732?*/
2733/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002734VLIB_CLI_COMMAND (lookup_test_command, static) =
2735{
2736 .path = "test lookup",
2737 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2738 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002739};
Billy McFall0683c9c2016-10-13 08:27:31 -04002740/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002741
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002742#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002743int
2744vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002745{
Neale Ranns107e7d42017-04-11 09:55:19 -07002746 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002747
Neale Ranns107e7d42017-04-11 09:55:19 -07002748 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2749
2750 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002751 return VNET_API_ERROR_NO_SUCH_FIB;
2752
Neale Ranns227038a2017-04-21 01:07:59 -07002753 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2754 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002755
Ed Warnickecb9cada2015-12-08 15:45:58 -07002756 return 0;
2757}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002758#endif
Dave Barach75fc8542016-10-11 16:16:02 -04002759
Ed Warnickecb9cada2015-12-08 15:45:58 -07002760static clib_error_t *
2761set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002762 unformat_input_t * input,
2763 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002764{
2765 int matched = 0;
2766 u32 table_id = 0;
2767 u32 flow_hash_config = 0;
2768 int rv;
2769
Dave Barachd7cb1b52016-12-09 09:52:16 -05002770 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2771 {
2772 if (unformat (input, "table %d", &table_id))
2773 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002774#define _(a,v) \
2775 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002776 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002777#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002778 else
2779 break;
2780 }
Dave Barach75fc8542016-10-11 16:16:02 -04002781
Ed Warnickecb9cada2015-12-08 15:45:58 -07002782 if (matched == 0)
2783 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002784 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002785
Ed Warnickecb9cada2015-12-08 15:45:58 -07002786 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2787 switch (rv)
2788 {
2789 case 0:
2790 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002791
Ed Warnickecb9cada2015-12-08 15:45:58 -07002792 case VNET_API_ERROR_NO_SUCH_FIB:
2793 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002794
Ed Warnickecb9cada2015-12-08 15:45:58 -07002795 default:
2796 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2797 break;
2798 }
Dave Barach75fc8542016-10-11 16:16:02 -04002799
Ed Warnickecb9cada2015-12-08 15:45:58 -07002800 return 0;
2801}
Dave Barach75fc8542016-10-11 16:16:02 -04002802
Billy McFall0683c9c2016-10-13 08:27:31 -04002803/*?
2804 * Configure the set of IPv4 fields used by the flow hash.
2805 *
2806 * @cliexpar
2807 * Example of how to set the flow hash on a given table:
2808 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2809 * Example of display the configured flow hash:
2810 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002811 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2812 * 0.0.0.0/0
2813 * unicast-ip4-chain
2814 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2815 * [0] [@0]: dpo-drop ip6
2816 * 0.0.0.0/32
2817 * unicast-ip4-chain
2818 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2819 * [0] [@0]: dpo-drop ip6
2820 * 224.0.0.0/8
2821 * unicast-ip4-chain
2822 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2823 * [0] [@0]: dpo-drop ip6
2824 * 6.0.1.2/32
2825 * unicast-ip4-chain
2826 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2827 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2828 * 7.0.0.1/32
2829 * unicast-ip4-chain
2830 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2831 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2832 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2833 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2834 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2835 * 240.0.0.0/8
2836 * unicast-ip4-chain
2837 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2838 * [0] [@0]: dpo-drop ip6
2839 * 255.255.255.255/32
2840 * unicast-ip4-chain
2841 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2842 * [0] [@0]: dpo-drop ip6
2843 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2844 * 0.0.0.0/0
2845 * unicast-ip4-chain
2846 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2847 * [0] [@0]: dpo-drop ip6
2848 * 0.0.0.0/32
2849 * unicast-ip4-chain
2850 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2851 * [0] [@0]: dpo-drop ip6
2852 * 172.16.1.0/24
2853 * unicast-ip4-chain
2854 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2855 * [0] [@4]: ipv4-glean: af_packet0
2856 * 172.16.1.1/32
2857 * unicast-ip4-chain
2858 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2859 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2860 * 172.16.1.2/32
2861 * unicast-ip4-chain
2862 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2863 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2864 * 172.16.2.0/24
2865 * unicast-ip4-chain
2866 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2867 * [0] [@4]: ipv4-glean: af_packet1
2868 * 172.16.2.1/32
2869 * unicast-ip4-chain
2870 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2871 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2872 * 224.0.0.0/8
2873 * unicast-ip4-chain
2874 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2875 * [0] [@0]: dpo-drop ip6
2876 * 240.0.0.0/8
2877 * unicast-ip4-chain
2878 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2879 * [0] [@0]: dpo-drop ip6
2880 * 255.255.255.255/32
2881 * unicast-ip4-chain
2882 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2883 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002884 * @cliexend
2885?*/
2886/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002887VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2888{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002890 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002891 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002892 .function = set_ip_flow_hash_command_fn,
2893};
Billy McFall0683c9c2016-10-13 08:27:31 -04002894/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002895
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002896#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002897int
2898vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2899 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002900{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002901 vnet_main_t *vnm = vnet_get_main ();
2902 vnet_interface_main_t *im = &vnm->interface_main;
2903 ip4_main_t *ipm = &ip4_main;
2904 ip_lookup_main_t *lm = &ipm->lookup_main;
2905 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002906 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002907
2908 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2909 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2910
2911 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2912 return VNET_API_ERROR_NO_SUCH_ENTRY;
2913
2914 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002915 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002916
Neale Rannsdf089a82016-10-02 16:39:06 +01002917 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2918
2919 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002920 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002921 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002922 .fp_len = 32,
2923 .fp_proto = FIB_PROTOCOL_IP4,
2924 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002925 };
2926 u32 fib_index;
2927
Dave Barachd7cb1b52016-12-09 09:52:16 -05002928 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2929 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002930
2931
Dave Barachd7cb1b52016-12-09 09:52:16 -05002932 if (table_index != (u32) ~ 0)
2933 {
2934 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002935
Dave Barachd7cb1b52016-12-09 09:52:16 -05002936 dpo_set (&dpo,
2937 DPO_CLASSIFY,
2938 DPO_PROTO_IP4,
2939 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002940
Dave Barachd7cb1b52016-12-09 09:52:16 -05002941 fib_table_entry_special_dpo_add (fib_index,
2942 &pfx,
2943 FIB_SOURCE_CLASSIFY,
2944 FIB_ENTRY_FLAG_NONE, &dpo);
2945 dpo_reset (&dpo);
2946 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002947 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002948 {
2949 fib_table_entry_special_remove (fib_index,
2950 &pfx, FIB_SOURCE_CLASSIFY);
2951 }
2952 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002953
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954 return 0;
2955}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002956#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002957
2958static clib_error_t *
2959set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002960 unformat_input_t * input,
2961 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002962{
2963 u32 table_index = ~0;
2964 int table_index_set = 0;
2965 u32 sw_if_index = ~0;
2966 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002967
Dave Barachd7cb1b52016-12-09 09:52:16 -05002968 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2969 {
2970 if (unformat (input, "table-index %d", &table_index))
2971 table_index_set = 1;
2972 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2973 vnet_get_main (), &sw_if_index))
2974 ;
2975 else
2976 break;
2977 }
Dave Barach75fc8542016-10-11 16:16:02 -04002978
Ed Warnickecb9cada2015-12-08 15:45:58 -07002979 if (table_index_set == 0)
2980 return clib_error_return (0, "classify table-index must be specified");
2981
2982 if (sw_if_index == ~0)
2983 return clib_error_return (0, "interface / subif must be specified");
2984
2985 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2986
2987 switch (rv)
2988 {
2989 case 0:
2990 break;
2991
2992 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2993 return clib_error_return (0, "No such interface");
2994
2995 case VNET_API_ERROR_NO_SUCH_ENTRY:
2996 return clib_error_return (0, "No such classifier table");
2997 }
2998 return 0;
2999}
3000
Billy McFall0683c9c2016-10-13 08:27:31 -04003001/*?
3002 * Assign a classification table to an interface. The classification
3003 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3004 * commands. Once the table is create, use this command to filter packets
3005 * on an interface.
3006 *
3007 * @cliexpar
3008 * Example of how to assign a classification table to an interface:
3009 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3010?*/
3011/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003012VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3013{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003014 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003015 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003016 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003017 .function = set_ip_classify_command_fn,
3018};
Billy McFall0683c9c2016-10-13 08:27:31 -04003019/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003020
Neale Ranns1ec36522017-11-29 05:20:37 -08003021static clib_error_t *
3022ip4_config (vlib_main_t * vm, unformat_input_t * input)
3023{
3024 ip4_main_t *im = &ip4_main;
3025 uword heapsize = 0;
3026
3027 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3028 {
3029 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3030 ;
3031 else
3032 return clib_error_return (0,
3033 "invalid heap-size parameter `%U'",
3034 format_unformat_error, input);
3035 }
3036
3037 im->mtrie_heap_size = heapsize;
3038
3039 return 0;
3040}
3041
3042VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3043
Dave Barachd7cb1b52016-12-09 09:52:16 -05003044/*
3045 * fd.io coding-style-patch-verification: ON
3046 *
3047 * Local Variables:
3048 * eval: (c-set-style "gnu")
3049 * End:
3050 */