blob: 985db21d6b0fcd0aebab5bfc7028002714a4d39e [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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100123 from = vlib_frame_vector_args (frame);
124 n_left_from = frame->n_vectors;
125 next = node->cached_next_index;
126
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100127 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500129 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100130
Dave Barach75fc8542016-10-11 16:16:02 -0400131
Neale Ranns2be95c12016-11-19 13:50:04 +0000132 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500133 {
134 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000135 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500136 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000137 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
138 const ip4_header_t *ip0, *ip1;
139 const dpo_id_t *dpo0, *dpo1;
140
Dave Barachd7cb1b52016-12-09 09:52:16 -0500141 /* Prefetch next iteration. */
142 {
143 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000144
145 p2 = vlib_get_buffer (vm, from[2]);
146 p3 = vlib_get_buffer (vm, from[3]);
147
148 vlib_prefetch_buffer_header (p2, STORE);
149 vlib_prefetch_buffer_header (p3, STORE);
150
151 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
152 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500153 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000154
155 pi0 = to_next[0] = from[0];
156 pi1 = to_next[1] = from[1];
157
158 from += 2;
159 n_left_from -= 2;
160 to_next += 2;
161 n_left_to_next -= 2;
162
163 p0 = vlib_get_buffer (vm, pi0);
164 p1 = vlib_get_buffer (vm, pi1);
165
166 ip0 = vlib_buffer_get_current (p0);
167 ip1 = vlib_buffer_get_current (p1);
168 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
169 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
170
Dave Barachd7cb1b52016-12-09 09:52:16 -0500171 lb0 = load_balance_get (lbi0);
172 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000173
Dave Barachd7cb1b52016-12-09 09:52:16 -0500174 /*
175 * this node is for via FIBs we can re-use the hash value from the
176 * to node if present.
177 * We don't want to use the same hash value at each level in the recursion
178 * graph as that would lead to polarisation
179 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000180 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000181
Dave Barachd7cb1b52016-12-09 09:52:16 -0500182 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
183 {
184 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
185 {
186 hc0 = vnet_buffer (p0)->ip.flow_hash =
187 vnet_buffer (p0)->ip.flow_hash >> 1;
188 }
189 else
190 {
191 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000192 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500193 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700194 dpo0 = load_balance_get_fwd_bucket
195 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
196 }
197 else
198 {
199 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500200 }
201 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
202 {
203 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
204 {
205 hc1 = vnet_buffer (p1)->ip.flow_hash =
206 vnet_buffer (p1)->ip.flow_hash >> 1;
207 }
208 else
209 {
210 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000211 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500212 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700213 dpo1 = load_balance_get_fwd_bucket
214 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500215 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700216 else
217 {
218 dpo1 = load_balance_get_bucket_i (lb1, 0);
219 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000220
221 next0 = dpo0->dpoi_next_node;
222 next1 = dpo1->dpoi_next_node;
223
224 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
225 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
226
227 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200228 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000229 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200230 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000231
232 vlib_validate_buffer_enqueue_x2 (vm, node, next,
233 to_next, n_left_to_next,
234 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500235 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000236
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100237 while (n_left_from > 0 && n_left_to_next > 0)
238 {
239 ip_lookup_next_t next0;
240 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500241 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100242 u32 pi0, lbi0, hc0;
243 const ip4_header_t *ip0;
244 const dpo_id_t *dpo0;
245
246 pi0 = from[0];
247 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000248 from += 1;
249 to_next += 1;
250 n_left_to_next -= 1;
251 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100252
253 p0 = vlib_get_buffer (vm, pi0);
254
255 ip0 = vlib_buffer_get_current (p0);
256 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
257
Dave Barachd7cb1b52016-12-09 09:52:16 -0500258 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100259
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000260 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500261 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
262 {
263 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
264 {
265 hc0 = vnet_buffer (p0)->ip.flow_hash =
266 vnet_buffer (p0)->ip.flow_hash >> 1;
267 }
268 else
269 {
270 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000271 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500272 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700273 dpo0 = load_balance_get_fwd_bucket
274 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500275 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700276 else
277 {
278 dpo0 = load_balance_get_bucket_i (lb0, 0);
279 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280
281 next0 = dpo0->dpoi_next_node;
282 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
283
Dave Barach75fc8542016-10-11 16:16:02 -0400284 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200285 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100286
Neale Ranns2be95c12016-11-19 13:50:04 +0000287 vlib_validate_buffer_enqueue_x1 (vm, node, next,
288 to_next, n_left_to_next,
289 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100290 }
291
292 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293 }
294
Neale Rannsa71844f2018-11-08 07:31:36 -0800295 if (node->flags & VLIB_NODE_FLAG_TRACE)
296 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
297
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100298 return frame->n_vectors;
299}
300
Neale Rannsf8686322017-11-29 02:39:53 -0800301/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500302VLIB_REGISTER_NODE (ip4_load_balance_node) =
303{
Neale Rannsf8686322017-11-29 02:39:53 -0800304 .name = "ip4-load-balance",
305 .vector_size = sizeof (u32),
306 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200307 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800308};
309/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100310
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200311#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100312/* get first interface address */
313ip4_address_t *
314ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500315 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100316{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500317 ip_lookup_main_t *lm = &im->lookup_main;
318 ip_interface_address_t *ia = 0;
319 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100320
Neale Ranns32e1c012016-11-22 17:07:28 +0000321 /* *INDENT-OFF* */
322 foreach_ip_interface_address
323 (lm, ia, sw_if_index,
324 1 /* honor unnumbered */ ,
325 ({
326 ip4_address_t * a =
327 ip_interface_address_get_address (lm, ia);
328 result = a;
329 break;
330 }));
331 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100332 if (result_ia)
333 *result_ia = result ? ia : 0;
334 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335}
336
337static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700338ip4_add_subnet_bcast_route (u32 fib_index,
339 fib_prefix_t *pfx,
340 u32 sw_if_index)
341{
342 vnet_sw_interface_flags_t iflags;
343
344 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
345
346 fib_table_entry_special_remove(fib_index,
347 pfx,
348 FIB_SOURCE_INTERFACE);
349
350 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
351 {
352 fib_table_entry_update_one_path (fib_index, pfx,
353 FIB_SOURCE_INTERFACE,
354 FIB_ENTRY_FLAG_NONE,
355 DPO_PROTO_IP4,
356 /* No next-hop address */
357 &ADJ_BCAST_ADDR,
358 sw_if_index,
359 // invalid FIB index
360 ~0,
361 1,
362 // no out-label stack
363 NULL,
364 FIB_ROUTE_PATH_FLAG_NONE);
365 }
366 else
367 {
368 fib_table_entry_special_add(fib_index,
369 pfx,
370 FIB_SOURCE_INTERFACE,
371 (FIB_ENTRY_FLAG_DROP |
372 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
373 }
374}
375
376static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377ip4_add_interface_routes (u32 sw_if_index,
378 ip4_main_t * im, u32 fib_index,
379 ip_interface_address_t * a)
380{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500381 ip_lookup_main_t *lm = &im->lookup_main;
382 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100383 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500384 .fp_len = a->address_length,
385 .fp_proto = FIB_PROTOCOL_IP4,
386 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100387 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388
Neale Ranns9a69a602017-03-26 10:56:33 -0700389 if (pfx.fp_len <= 30)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500390 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700391 /* a /30 or shorter - add a glean for the network address */
Neale Ranns7a272742017-05-30 02:08:14 -0700392 fib_table_entry_update_one_path (fib_index, &pfx,
393 FIB_SOURCE_INTERFACE,
394 (FIB_ENTRY_FLAG_CONNECTED |
395 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700396 DPO_PROTO_IP4,
Neale Ranns7a272742017-05-30 02:08:14 -0700397 /* No next-hop address */
398 NULL,
399 sw_if_index,
400 // invalid FIB index
401 ~0,
402 1,
403 // no out-label stack
404 NULL,
405 FIB_ROUTE_PATH_FLAG_NONE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100406
Neale Ranns9a69a602017-03-26 10:56:33 -0700407 /* Add the two broadcast addresses as drop */
408 fib_prefix_t net_pfx = {
409 .fp_len = 32,
410 .fp_proto = FIB_PROTOCOL_IP4,
411 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
412 };
413 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
414 fib_table_entry_special_add(fib_index,
415 &net_pfx,
416 FIB_SOURCE_INTERFACE,
417 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700418 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700419 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
420 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
Neale Ranns1855b8e2018-07-11 10:31:26 -0700421 ip4_add_subnet_bcast_route(fib_index, &net_pfx, sw_if_index);
Neale Ranns9a69a602017-03-26 10:56:33 -0700422 }
423 else if (pfx.fp_len == 31)
424 {
425 u32 mask = clib_host_to_net_u32(1);
426 fib_prefix_t net_pfx = pfx;
427
428 net_pfx.fp_len = 32;
429 net_pfx.fp_addr.ip4.as_u32 ^= mask;
430
431 /* a /31 - add the other end as an attached host */
432 fib_table_entry_update_one_path (fib_index, &net_pfx,
433 FIB_SOURCE_INTERFACE,
434 (FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700435 DPO_PROTO_IP4,
Neale Ranns9a69a602017-03-26 10:56:33 -0700436 &net_pfx.fp_addr,
437 sw_if_index,
438 // invalid FIB index
439 ~0,
440 1,
441 NULL,
442 FIB_ROUTE_PATH_FLAG_NONE);
443 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100444 pfx.fp_len = 32;
445
446 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500447 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100448 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500449 lm->classify_table_index_by_sw_if_index[sw_if_index];
450 if (classify_table_index != (u32) ~ 0)
451 {
452 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100453
Dave Barachd7cb1b52016-12-09 09:52:16 -0500454 dpo_set (&dpo,
455 DPO_CLASSIFY,
456 DPO_PROTO_IP4,
457 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100458
Dave Barachd7cb1b52016-12-09 09:52:16 -0500459 fib_table_entry_special_dpo_add (fib_index,
460 &pfx,
461 FIB_SOURCE_CLASSIFY,
462 FIB_ENTRY_FLAG_NONE, &dpo);
463 dpo_reset (&dpo);
464 }
465 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466
Neale Ranns32e1c012016-11-22 17:07:28 +0000467 fib_table_entry_update_one_path (fib_index, &pfx,
468 FIB_SOURCE_INTERFACE,
469 (FIB_ENTRY_FLAG_CONNECTED |
470 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700471 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000472 &pfx.fp_addr,
473 sw_if_index,
474 // invalid FIB index
475 ~0,
476 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478}
479
480static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100481ip4_del_interface_routes (ip4_main_t * im,
482 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500483 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500485 fib_prefix_t pfx = {
486 .fp_len = address_length,
487 .fp_proto = FIB_PROTOCOL_IP4,
488 .fp_addr.ip4 = *address,
489 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490
Neale Ranns9a69a602017-03-26 10:56:33 -0700491 if (pfx.fp_len <= 30)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100492 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700493 fib_prefix_t net_pfx = {
494 .fp_len = 32,
495 .fp_proto = FIB_PROTOCOL_IP4,
496 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
497 };
498 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
499 fib_table_entry_special_remove(fib_index,
500 &net_pfx,
501 FIB_SOURCE_INTERFACE);
502 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
503 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
504 fib_table_entry_special_remove(fib_index,
505 &net_pfx,
506 FIB_SOURCE_INTERFACE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500507 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100508 }
Neale Ranns9a69a602017-03-26 10:56:33 -0700509 else if (pfx.fp_len == 31)
510 {
511 u32 mask = clib_host_to_net_u32(1);
512 fib_prefix_t net_pfx = pfx;
513
514 net_pfx.fp_len = 32;
515 net_pfx.fp_addr.ip4.as_u32 ^= mask;
516
517 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
518 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519
Dave Barachd7cb1b52016-12-09 09:52:16 -0500520 pfx.fp_len = 32;
521 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522}
523
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100524void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500525ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100526{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500527 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100529 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
530
531 /*
532 * enable/disable only on the 1<->0 transition
533 */
534 if (is_enable)
535 {
536 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500537 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100538 }
539 else
540 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500541 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100542 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500543 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100544 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800545 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800546 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100547
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100548
Neale Ranns8269d3d2018-01-30 09:02:20 -0800549 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400550 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100551}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552
Ed Warnickecb9cada2015-12-08 15:45:58 -0700553static clib_error_t *
554ip4_add_del_interface_address_internal (vlib_main_t * vm,
555 u32 sw_if_index,
556 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500557 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500559 vnet_main_t *vnm = vnet_get_main ();
560 ip4_main_t *im = &ip4_main;
561 ip_lookup_main_t *lm = &im->lookup_main;
562 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500564 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565
Pavel Kotucek57808982017-08-02 08:20:19 +0200566 /* local0 interface doesn't support IP addressing */
567 if (sw_if_index == 0)
568 {
569 return
570 clib_error_create ("local0 interface doesn't support IP addressing");
571 }
572
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
574 ip4_addr_fib_init (&ip4_af, address,
575 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
576 vec_add1 (addr_fib, ip4_af);
577
Neale Ranns744902e2017-08-14 10:35:44 -0700578 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100579 * there is no support for adj-fib handling in the presence of overlapping
580 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
581 * most routers do.
582 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000583 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500584 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700585 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100586 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700587 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700589 vnet_sw_interface_t *sif;
590
591 pool_foreach(sif, vnm->interface_main.sw_interfaces,
592 ({
593 if (im->fib_index_by_sw_if_index[sw_if_index] ==
594 im->fib_index_by_sw_if_index[sif->sw_if_index])
595 {
596 foreach_ip_interface_address
597 (&im->lookup_main, ia, sif->sw_if_index,
598 0 /* honor unnumbered */ ,
599 ({
600 ip4_address_t * x =
601 ip_interface_address_get_address
602 (&im->lookup_main, ia);
603 if (ip4_destination_matches_route
604 (im, address, x, ia->address_length) ||
605 ip4_destination_matches_route (im,
606 x,
607 address,
608 address_length))
609 {
610 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
611
612 return
613 clib_error_create
614 ("failed to add %U which conflicts with %U for interface %U",
615 format_ip4_address_and_length, address,
616 address_length,
617 format_ip4_address_and_length, x,
618 ia->address_length,
619 format_vnet_sw_if_index_name, vnm,
620 sif->sw_if_index);
621 }
622 }));
623 }
624 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000626 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628 elts_before = pool_elts (lm->if_address_pool);
629
630 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500631 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 if (error)
633 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400634
Dave Barachd7cb1b52016-12-09 09:52:16 -0500635 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100636
637 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500638 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100639 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500640 ip4_add_interface_routes (sw_if_index,
641 im, ip4_af.fib_index,
642 pool_elt_at_index
643 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644
645 /* If pool did not grow/shrink: add duplicate address. */
646 if (elts_before != pool_elts (lm->if_address_pool))
647 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500648 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649 vec_foreach (cb, im->add_del_interface_address_callbacks)
650 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500651 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652 }
653
Dave Barachd7cb1b52016-12-09 09:52:16 -0500654done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655 vec_free (addr_fib);
656 return error;
657}
658
659clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000660ip4_add_del_interface_address (vlib_main_t * vm,
661 u32 sw_if_index,
662 ip4_address_t * address,
663 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664{
665 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500666 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700667}
668
Neale Ranns1855b8e2018-07-11 10:31:26 -0700669void
670ip4_directed_broadcast (u32 sw_if_index, u8 enable)
671{
672 ip_interface_address_t *ia;
673 ip4_main_t *im;
674
675 im = &ip4_main;
676
677 /*
678 * when directed broadcast is enabled, the subnet braodcast route will forward
679 * packets using an adjacency with a broadcast MAC. otherwise it drops
680 */
681 /* *INDENT-OFF* */
682 foreach_ip_interface_address(&im->lookup_main, ia,
683 sw_if_index, 0,
684 ({
685 if (ia->address_length <= 30)
686 {
687 ip4_address_t *ipa;
688
689 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
690
691 fib_prefix_t pfx = {
692 .fp_len = 32,
693 .fp_proto = FIB_PROTOCOL_IP4,
694 .fp_addr = {
695 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
696 },
697 };
698
699 ip4_add_subnet_bcast_route
700 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
701 sw_if_index),
702 &pfx, sw_if_index);
703 }
704 }));
705 /* *INDENT-ON* */
706}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200707#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700708
Dave Barachd6534602016-06-14 18:38:02 -0400709/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500710/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100711VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
712{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500713 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100714 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500715 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100716 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
717};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100718
Dave Barachd7cb1b52016-12-09 09:52:16 -0500719VNET_FEATURE_INIT (ip4_flow_classify, static) =
720{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100721 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700722 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100723 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700724};
725
Dave Barachd7cb1b52016-12-09 09:52:16 -0500726VNET_FEATURE_INIT (ip4_inacl, static) =
727{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100728 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400729 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100730 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400731};
732
Dave Barachd7cb1b52016-12-09 09:52:16 -0500733VNET_FEATURE_INIT (ip4_source_check_1, static) =
734{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100735 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400736 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100737 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400738};
739
Dave Barachd7cb1b52016-12-09 09:52:16 -0500740VNET_FEATURE_INIT (ip4_source_check_2, static) =
741{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100742 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400743 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100744 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400745};
746
Dave Barachd7cb1b52016-12-09 09:52:16 -0500747VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
748{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100749 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400750 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100751 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400752};
753
Dave Barachd7cb1b52016-12-09 09:52:16 -0500754VNET_FEATURE_INIT (ip4_policer_classify, static) =
755{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100756 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700757 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100758 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700759};
760
Dave Barachd7cb1b52016-12-09 09:52:16 -0500761VNET_FEATURE_INIT (ip4_ipsec, static) =
762{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100763 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100764 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100765 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400766};
767
Dave Barachd7cb1b52016-12-09 09:52:16 -0500768VNET_FEATURE_INIT (ip4_vpath, static) =
769{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100770 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400771 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500772 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
773};
774
Dave Barachd7cb1b52016-12-09 09:52:16 -0500775VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
776{
John Lo37682e12016-11-30 12:51:39 -0500777 .arc_name = "ip4-unicast",
778 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100779 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400780};
781
Neale Ranns8269d3d2018-01-30 09:02:20 -0800782VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500783{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100784 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800785 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400786 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100787};
788
Neale Ranns180279b2017-03-16 15:49:09 -0400789VNET_FEATURE_INIT (ip4_lookup, static) =
790{
791 .arc_name = "ip4-unicast",
792 .node_name = "ip4-lookup",
793 .runs_before = 0, /* not before any other features */
794};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100795
Dave Barachd6534602016-06-14 18:38:02 -0400796/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100797VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
798{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500799 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100800 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500801 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100802 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
803};
804
Dave Barachd7cb1b52016-12-09 09:52:16 -0500805VNET_FEATURE_INIT (ip4_vpath_mc, static) =
806{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100807 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400808 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000809 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400810};
811
Neale Ranns8269d3d2018-01-30 09:02:20 -0800812VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500813{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100814 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800815 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400816 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
817};
818
819VNET_FEATURE_INIT (ip4_lookup_mc, static) =
820{
821 .arc_name = "ip4-multicast",
822 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100824};
Dave Barach5331c722016-08-17 11:54:30 -0400825
826/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100827VNET_FEATURE_ARC_INIT (ip4_output, static) =
828{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500829 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800830 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -0500831 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100832 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
833};
Dave Barach5331c722016-08-17 11:54:30 -0400834
Dave Barachd7cb1b52016-12-09 09:52:16 -0500835VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
836{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100837 .arc_name = "ip4-output",
838 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100839 .runs_before = VNET_FEATURES ("ip4-outacl"),
840};
841
842VNET_FEATURE_INIT (ip4_outacl, static) =
843{
844 .arc_name = "ip4-output",
845 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +0100846 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -0800847};
848
Dave Barachd7cb1b52016-12-09 09:52:16 -0500849VNET_FEATURE_INIT (ip4_ipsec_output, static) =
850{
Matus Fabian08a6f012016-11-15 06:08:51 -0800851 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +0100852 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100853 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -0400854};
855
856/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500857VNET_FEATURE_INIT (ip4_interface_output, static) =
858{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100859 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -0400860 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500861 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -0400862};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500863/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400864
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500866ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500868 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100870 /* Fill in lookup tables with default table (0). */
871 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000872 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100873
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200874 if (!is_add)
875 {
876 ip4_main_t *im4 = &ip4_main;
877 ip_lookup_main_t *lm4 = &im4->lookup_main;
878 ip_interface_address_t *ia = 0;
879 ip4_address_t *address;
880 vlib_main_t *vm = vlib_get_main ();
881
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700882 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200883 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700884 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200885 ({
886 address = ip_interface_address_get_address (lm4, ia);
887 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
888 }));
889 /* *INDENT-ON* */
890 }
891
Neale Ranns8269d3d2018-01-30 09:02:20 -0800892 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100893 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700894
Neale Ranns8269d3d2018-01-30 09:02:20 -0800895 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
896 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700897
Ed Warnickecb9cada2015-12-08 15:45:58 -0700898 return /* no error */ 0;
899}
900
901VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
902
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +0100904#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -0700905ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +0100906#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200908static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700909ip4_lookup_init (vlib_main_t * vm)
910{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500911 ip4_main_t *im = &ip4_main;
912 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700913 uword i;
914
Damjan Marion8b3191e2016-11-09 19:54:20 +0100915 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
916 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -0800917 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
918 return (error);
919 if ((error = vlib_call_init_function (vm, fib_module_init)))
920 return error;
921 if ((error = vlib_call_init_function (vm, mfib_module_init)))
922 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100923
Ed Warnickecb9cada2015-12-08 15:45:58 -0700924 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
925 {
926 u32 m;
927
928 if (i < 32)
929 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -0400930 else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931 m = ~0;
932 im->fib_masks[i] = clib_host_to_net_u32 (m);
933 }
934
Ed Warnickecb9cada2015-12-08 15:45:58 -0700935 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
936
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100937 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -0700938 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
939 FIB_SOURCE_DEFAULT_ROUTE);
940 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
941 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100942
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500944 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700945 pn = pg_get_node (ip4_lookup_node.index);
946 pn->unformat_edit = unformat_pg_ip4_header;
947 }
948
949 {
950 ethernet_arp_header_t h;
951
Dave Barachb7b92992018-10-17 10:38:51 -0400952 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954#define _16(f,v) h.f = clib_host_to_net_u16 (v);
955#define _8(f,v) h.f = v;
956 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
957 _16 (l3_type, ETHERNET_TYPE_IP4);
958 _8 (n_l2_address_bytes, 6);
959 _8 (n_l3_address_bytes, 4);
960 _16 (opcode, ETHERNET_ARP_OPCODE_request);
961#undef _16
962#undef _8
963
Dave Barachd7cb1b52016-12-09 09:52:16 -0500964 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700965 /* data */ &h,
966 sizeof (h),
967 /* alloc chunk size */ 8,
968 "ip4 arp");
969 }
970
Dave Barach203c6322016-06-26 10:29:03 -0400971 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972}
973
974VLIB_INIT_FUNCTION (ip4_lookup_init);
975
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976typedef struct
977{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -0700979 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980 u32 flow_hash;
981 u32 fib_index;
982
983 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500984 u8 packet_data[64 - 1 * sizeof (u32)];
985}
986ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700987
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200988#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -0500989u8 *
990format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700991{
992 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
993 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500994 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200995 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100996 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -0400997 format_white_space, indent,
998 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100999 return s;
1000}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001001#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001002
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003static u8 *
1004format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001005{
1006 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1007 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001008 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001009 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001010
John Loac8146c2016-09-27 17:44:02 -04001011 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001012 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001013 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014 format_white_space, indent,
1015 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001016 return s;
1017}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001018
Dave Barachd7cb1b52016-12-09 09:52:16 -05001019static u8 *
1020format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001021{
1022 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1023 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001024 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001025 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001026
Vengada Govindanf1544482016-09-28 02:45:57 -07001027 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001028 t->fib_index, t->dpo_index, format_ip_adjacency,
1029 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001030 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031 format_white_space, indent,
1032 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001033 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001034 return s;
1035}
1036
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001037#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038/* Common trace function for all ip4-forward next nodes. */
1039void
1040ip4_forward_next_trace (vlib_main_t * vm,
1041 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001044 u32 *from, n_left;
1045 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046
1047 n_left = frame->n_vectors;
1048 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001049
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 while (n_left >= 4)
1051 {
1052 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001053 vlib_buffer_t *b0, *b1;
1054 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055
1056 /* Prefetch next iteration. */
1057 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1058 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1059
1060 bi0 = from[0];
1061 bi1 = from[1];
1062
1063 b0 = vlib_get_buffer (vm, bi0);
1064 b1 = vlib_get_buffer (vm, bi1);
1065
1066 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1067 {
1068 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001069 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001071 t0->fib_index =
1072 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1073 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1074 vec_elt (im->fib_index_by_sw_if_index,
1075 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001076
Dave Barach178cf492018-11-13 16:34:13 -05001077 clib_memcpy_fast (t0->packet_data,
1078 vlib_buffer_get_current (b0),
1079 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 }
1081 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1082 {
1083 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001084 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001086 t1->fib_index =
1087 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1088 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1089 vec_elt (im->fib_index_by_sw_if_index,
1090 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001091 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1092 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093 }
1094 from += 2;
1095 n_left -= 2;
1096 }
1097
1098 while (n_left >= 1)
1099 {
1100 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001101 vlib_buffer_t *b0;
1102 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103
1104 bi0 = from[0];
1105
1106 b0 = vlib_get_buffer (vm, bi0);
1107
1108 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1109 {
1110 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001111 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001113 t0->fib_index =
1114 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1115 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1116 vec_elt (im->fib_index_by_sw_if_index,
1117 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001118 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1119 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120 }
1121 from += 1;
1122 n_left -= 1;
1123 }
1124}
1125
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126/* Compute TCP/UDP/ICMP4 checksum in software. */
1127u16
1128ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1129 ip4_header_t * ip0)
1130{
1131 ip_csum_t sum0;
1132 u32 ip_header_length, payload_length_host_byte_order;
Florin Corasb2215d62017-08-01 16:56:58 -07001133 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001134 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001135 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001136
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137 /* Initialize checksum with ip header. */
1138 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001139 payload_length_host_byte_order =
1140 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1141 sum0 =
1142 clib_host_to_net_u32 (payload_length_host_byte_order +
1143 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144
1145 if (BITS (uword) == 32)
1146 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001147 sum0 =
1148 ip_csum_with_carry (sum0,
1149 clib_mem_unaligned (&ip0->src_address, u32));
1150 sum0 =
1151 ip_csum_with_carry (sum0,
1152 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153 }
1154 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001155 sum0 =
1156 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001157
1158 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1159 data_this_buffer = (void *) ip0 + ip_header_length;
Neale Rannsd91c1db2017-07-31 02:30:50 -07001160 n_ip_bytes_this_buffer =
1161 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
Florin Corasb2215d62017-08-01 16:56:58 -07001162 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1163 {
1164 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
Neale Rannsd91c1db2017-07-31 02:30:50 -07001165 n_ip_bytes_this_buffer - ip_header_length : 0;
Florin Corasb2215d62017-08-01 16:56:58 -07001166 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167 while (1)
1168 {
1169 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1170 n_bytes_left -= n_this_buffer;
1171 if (n_bytes_left == 0)
1172 break;
1173
1174 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1175 p0 = vlib_get_buffer (vm, p0->next_buffer);
1176 data_this_buffer = vlib_buffer_get_current (p0);
1177 n_this_buffer = p0->current_length;
1178 }
1179
Dave Barachd7cb1b52016-12-09 09:52:16 -05001180 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
1182 return sum16;
1183}
1184
John Lo37682e12016-11-30 12:51:39 -05001185u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1187{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001188 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1189 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 u16 sum16;
1191
1192 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1193 || ip0->protocol == IP_PROTOCOL_UDP);
1194
1195 udp0 = (void *) (ip0 + 1);
1196 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1197 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001198 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1199 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200 return p0->flags;
1201 }
1202
1203 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1204
Damjan Marion213b5aa2017-07-13 21:19:27 +02001205 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1206 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001207
1208 return p0->flags;
1209}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001210#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211
Dave Barach68b0fb02017-02-28 15:15:56 -05001212/* *INDENT-OFF* */
1213VNET_FEATURE_ARC_INIT (ip4_local) =
1214{
1215 .arc_name = "ip4-local",
1216 .start_nodes = VNET_FEATURES ("ip4-local"),
Dave Baracha25def72018-11-26 11:04:45 -05001217 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001218};
1219/* *INDENT-ON* */
1220
Florin Coras20a14b92017-08-15 22:47:22 -07001221static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001222ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1223 ip4_header_t * ip, u8 is_udp, u8 * error,
1224 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001225{
1226 u32 flags0;
1227 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1228 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1229 if (is_udp)
1230 {
1231 udp_header_t *udp;
1232 u32 ip_len, udp_len;
1233 i32 len_diff;
1234 udp = ip4_next_header (ip);
1235 /* Verify UDP length. */
1236 ip_len = clib_net_to_host_u16 (ip->length);
1237 udp_len = clib_net_to_host_u16 (udp->length);
1238
1239 len_diff = ip_len - udp_len;
1240 *good_tcp_udp &= len_diff >= 0;
1241 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1242 }
1243}
1244
Florin Coras1b255522018-06-01 12:22:23 -07001245#define ip4_local_csum_is_offloaded(_b) \
1246 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1247 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1248
1249#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1250 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1251 || ip4_local_csum_is_offloaded (_b)))
1252
1253#define ip4_local_csum_is_valid(_b) \
1254 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1255 || (ip4_local_csum_is_offloaded (_b))) != 0
1256
1257static inline void
1258ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1259 ip4_header_t * ih, u8 * error)
1260{
1261 u8 is_udp, is_tcp_udp, good_tcp_udp;
1262
1263 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1264 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1265
1266 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1267 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1268 else
1269 good_tcp_udp = ip4_local_csum_is_valid (b);
1270
1271 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1272 *error = (is_tcp_udp && !good_tcp_udp
1273 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1274}
1275
1276static inline void
1277ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1278 ip4_header_t ** ih, u8 * error)
1279{
1280 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1281
1282 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1283 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1284
1285 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1286 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1287
1288 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1289 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1290
1291 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1292 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1293 {
1294 if (is_tcp_udp[0])
1295 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1296 &good_tcp_udp[0]);
1297 if (is_tcp_udp[1])
1298 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1299 &good_tcp_udp[1]);
1300 }
1301
1302 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1303 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1304 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1305 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1306}
1307
1308static inline void
1309ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1310 vlib_buffer_t * b, u16 * next, u8 error,
1311 u8 head_of_feature_arc)
1312{
1313 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1314 u32 next_index;
1315
1316 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1317 b->error = error ? error_node->errors[error] : 0;
1318 if (head_of_feature_arc)
1319 {
1320 next_index = *next;
1321 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1322 {
1323 vnet_feature_arc_start (arc_index,
1324 vnet_buffer (b)->sw_if_index[VLIB_RX],
1325 &next_index, b);
1326 *next = next_index;
1327 }
1328 }
1329}
1330
1331typedef struct
1332{
1333 ip4_address_t src;
1334 u32 lbi;
1335 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001336 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001337} ip4_local_last_check_t;
1338
1339static inline void
1340ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1341 ip4_local_last_check_t * last_check, u8 * error0)
1342{
1343 ip4_fib_mtrie_leaf_t leaf0;
1344 ip4_fib_mtrie_t *mtrie0;
1345 const dpo_id_t *dpo0;
1346 load_balance_t *lb0;
1347 u32 lbi0;
1348
1349 vnet_buffer (b)->ip.fib_index =
1350 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1351 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1352
Neale Rannsbe2286b2018-12-09 12:54:51 -08001353 if (PREDICT_FALSE (last_check->first ||
1354 (last_check->src.as_u32 != ip0->src_address.as_u32)))
Florin Coras1b255522018-06-01 12:22:23 -07001355 {
1356 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1357 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1358 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1359 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1360 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1361
1362 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1363 vnet_buffer (b)->ip.adj_index[VLIB_RX] = lbi0;
1364
1365 lb0 = load_balance_get (lbi0);
1366 dpo0 = load_balance_get_bucket_i (lb0, 0);
1367
1368 /*
1369 * Must have a route to source otherwise we drop the packet.
1370 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1371 *
1372 * The checks are:
1373 * - the source is a recieve => it's from us => bogus, do this
1374 * first since it sets a different error code.
1375 * - uRPF check for any route to source - accept if passes.
1376 * - allow packets destined to the broadcast address from unknown sources
1377 */
1378
1379 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1380 && dpo0->dpoi_type == DPO_RECEIVE) ?
1381 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1382 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1383 && !fib_urpf_check_size (lb0->lb_urpf)
1384 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1385 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1386
1387 last_check->src.as_u32 = ip0->src_address.as_u32;
1388 last_check->lbi = lbi0;
1389 last_check->error = *error0;
1390 }
1391 else
1392 {
1393 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1394 vnet_buffer (b)->ip.adj_index[VLIB_RX] = last_check->lbi;
1395 *error0 = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001396 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001397 }
1398}
1399
1400static inline void
1401ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1402 ip4_local_last_check_t * last_check, u8 * error)
1403{
1404 ip4_fib_mtrie_leaf_t leaf[2];
1405 ip4_fib_mtrie_t *mtrie[2];
1406 const dpo_id_t *dpo[2];
1407 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001408 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001409 u32 lbi[2];
1410
Neale Rannsbe2286b2018-12-09 12:54:51 -08001411 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001412 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1413 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1414
1415 vnet_buffer (b[0])->ip.fib_index =
1416 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1417 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1418 vnet_buffer (b[0])->ip.fib_index;
1419
1420 vnet_buffer (b[1])->ip.fib_index =
1421 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1422 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1423 vnet_buffer (b[1])->ip.fib_index;
1424
1425 if (PREDICT_FALSE (not_last_hit))
1426 {
1427 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1428 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1429
1430 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1431 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1432
1433 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1434 &ip[0]->src_address, 2);
1435 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1436 &ip[1]->src_address, 2);
1437
1438 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1439 &ip[0]->src_address, 3);
1440 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1441 &ip[1]->src_address, 3);
1442
1443 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1444 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1445
1446 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1447 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = lbi[0];
1448
1449 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1450 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = lbi[1];
1451
1452 lb[0] = load_balance_get (lbi[0]);
1453 lb[1] = load_balance_get (lbi[1]);
1454
1455 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1456 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1457
1458 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1459 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1460 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1461 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1462 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1463 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1464 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1465
1466 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1467 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1468 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1469 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1470 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1471 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1472 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1473
1474 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1475 last_check->lbi = lbi[1];
1476 last_check->error = error[1];
1477 }
1478 else
1479 {
1480 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1481 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = last_check->lbi;
1482
1483 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1484 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = last_check->lbi;
1485
1486 error[0] = last_check->error;
1487 error[1] = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001488 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001489 }
1490}
Florin Coras20a14b92017-08-15 22:47:22 -07001491
Florin Corasc67cfd22018-10-01 21:59:18 -07001492enum ip_local_packet_type_e
1493{
1494 IP_LOCAL_PACKET_TYPE_L4,
1495 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001496 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001497};
1498
1499/**
1500 * Determine packet type and next node.
1501 *
1502 * The expectation is that all packets that are not L4 will skip
1503 * checksums and source checks.
1504 */
1505always_inline u8
1506ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1507{
1508 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1509
Juraj Sloboda3048b632018-10-02 11:13:53 +02001510 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1511 {
1512 *next = IP_LOCAL_NEXT_REASSEMBLY;
1513 return IP_LOCAL_PACKET_TYPE_FRAG;
1514 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001515 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1516 {
1517 *next = lm->local_next_by_ip_protocol[ip->protocol];
1518 return IP_LOCAL_PACKET_TYPE_NAT;
1519 }
1520
1521 *next = lm->local_next_by_ip_protocol[ip->protocol];
1522 return IP_LOCAL_PACKET_TYPE_L4;
1523}
1524
Dave Barach68b0fb02017-02-28 15:15:56 -05001525static inline uword
1526ip4_local_inline (vlib_main_t * vm,
1527 vlib_node_runtime_t * node,
1528 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001529{
Florin Coras1b255522018-06-01 12:22:23 -07001530 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001531 vlib_node_runtime_t *error_node =
1532 vlib_node_get_runtime (vm, ip4_input_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001533 u16 nexts[VLIB_FRAME_SIZE], *next;
1534 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1535 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001536 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001537
1538 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001539 /*
1540 * 0.0.0.0 can appear as the source address of an IP packet,
1541 * as can any other address, hence the need to use the 'first'
1542 * member to make sure the .lbi is initialised for the first
1543 * packet.
1544 */
Florin Coras1b255522018-06-01 12:22:23 -07001545 .src = {.as_u32 = 0},
1546 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001547 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1548 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001549 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001550
1551 from = vlib_frame_vector_args (frame);
1552 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001553
Ed Warnickecb9cada2015-12-08 15:45:58 -07001554 if (node->flags & VLIB_NODE_FLAG_TRACE)
1555 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1556
Florin Coras1b255522018-06-01 12:22:23 -07001557 vlib_get_buffers (vm, from, bufs, n_left_from);
1558 b = bufs;
1559 next = nexts;
1560
1561 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001562 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001563 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001564
Florin Coras1b255522018-06-01 12:22:23 -07001565 /* Prefetch next iteration. */
1566 {
1567 vlib_prefetch_buffer_header (b[4], LOAD);
1568 vlib_prefetch_buffer_header (b[5], LOAD);
1569
1570 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1571 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1572 }
1573
1574 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1575
1576 ip[0] = vlib_buffer_get_current (b[0]);
1577 ip[1] = vlib_buffer_get_current (b[1]);
1578
1579 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1580 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1581
Florin Corasc67cfd22018-10-01 21:59:18 -07001582 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1583 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001584
Florin Corasc67cfd22018-10-01 21:59:18 -07001585 not_batch = pt[0] ^ pt[1];
1586
1587 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001588 goto skip_checks;
1589
1590 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001591 {
Florin Coras1b255522018-06-01 12:22:23 -07001592 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1593 ip4_local_check_src_x2 (b, ip, &last_check, error);
1594 }
1595 else
1596 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001597 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001598 {
Florin Coras1b255522018-06-01 12:22:23 -07001599 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1600 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
Florin Coras20a14b92017-08-15 22:47:22 -07001601 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001602 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001603 {
Florin Coras1b255522018-06-01 12:22:23 -07001604 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1605 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001606 }
1607 }
1608
Florin Coras1b255522018-06-01 12:22:23 -07001609 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001610
Florin Coras1b255522018-06-01 12:22:23 -07001611 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1612 head_of_feature_arc);
1613 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1614 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001615
Florin Coras1b255522018-06-01 12:22:23 -07001616 b += 2;
1617 next += 2;
1618 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001619 }
1620
Florin Coras1b255522018-06-01 12:22:23 -07001621 while (n_left_from > 0)
1622 {
1623 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1624
1625 ip[0] = vlib_buffer_get_current (b[0]);
1626 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001627 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001628
Florin Corasc67cfd22018-10-01 21:59:18 -07001629 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001630 goto skip_check;
1631
1632 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1633 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1634
1635 skip_check:
1636
Florin Coras1b255522018-06-01 12:22:23 -07001637 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1638 head_of_feature_arc);
1639
1640 b += 1;
1641 next += 1;
1642 n_left_from -= 1;
1643 }
1644
1645 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 return frame->n_vectors;
1647}
1648
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001649VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1650 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001651{
1652 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1653}
1654
1655/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001656VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001657{
Dave Barach68b0fb02017-02-28 15:15:56 -05001658 .name = "ip4-local",
1659 .vector_size = sizeof (u32),
1660 .format_trace = format_ip4_forward_next_trace,
1661 .n_next_nodes = IP_LOCAL_N_NEXT,
1662 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001663 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001664 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1665 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001666 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001667 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Juraj Sloboda3048b632018-10-02 11:13:53 +02001668 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001669 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001670};
1671/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001672
Dave Barachd7cb1b52016-12-09 09:52:16 -05001673
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001674VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1675 vlib_node_runtime_t * node,
1676 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001677{
1678 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1679}
1680
1681/* *INDENT-OFF* */
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001682VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001683 .name = "ip4-local-end-of-arc",
1684 .vector_size = sizeof (u32),
1685
1686 .format_trace = format_ip4_forward_next_trace,
1687 .sibling_of = "ip4-local",
1688};
1689
Dave Barach68b0fb02017-02-28 15:15:56 -05001690VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1691 .arc_name = "ip4-local",
1692 .node_name = "ip4-local-end-of-arc",
1693 .runs_before = 0, /* not before any other features */
1694};
1695/* *INDENT-ON* */
1696
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001697#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001698void
1699ip4_register_protocol (u32 protocol, u32 node_index)
1700{
1701 vlib_main_t *vm = vlib_get_main ();
1702 ip4_main_t *im = &ip4_main;
1703 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001704
1705 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001706 lm->local_next_by_ip_protocol[protocol] =
1707 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001709#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001710
1711static clib_error_t *
1712show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001713 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001714{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001715 ip4_main_t *im = &ip4_main;
1716 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001717 int i;
1718
1719 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001720 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001721 {
1722 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001723 {
1724 u32 node_index = vlib_get_node (vm,
1725 ip4_local_node.index)->
1726 next_nodes[lm->local_next_by_ip_protocol[i]];
1727 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1728 node_index);
1729 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730 }
1731 return 0;
1732}
1733
1734
1735
Billy McFall0683c9c2016-10-13 08:27:31 -04001736/*?
1737 * Display the set of protocols handled by the local IPv4 stack.
1738 *
1739 * @cliexpar
1740 * Example of how to display local protocol table:
1741 * @cliexstart{show ip local}
1742 * Protocols handled by ip4_local
1743 * 1
1744 * 17
1745 * 47
1746 * @cliexend
1747?*/
1748/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001749VLIB_CLI_COMMAND (show_ip_local, static) =
1750{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751 .path = "show ip local",
1752 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001753 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001754};
Billy McFall0683c9c2016-10-13 08:27:31 -04001755/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001757always_inline uword
1758ip4_arp_inline (vlib_main_t * vm,
1759 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001762 vnet_main_t *vnm = vnet_get_main ();
1763 ip4_main_t *im = &ip4_main;
1764 ip_lookup_main_t *lm = &im->lookup_main;
1765 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766 uword n_left_from, n_left_to_next_drop, next_index;
Dave Barach49433ad2018-08-08 17:59:03 -04001767 u32 thread_index = vm->thread_index;
Neale Rannscd35e532018-08-31 02:51:45 -07001768 u64 seed;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001769
1770 if (node->flags & VLIB_NODE_FLAG_TRACE)
1771 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1772
Neale Rannsc8352bc2018-08-29 10:23:58 -07001773 seed = throttle_seed (&im->arp_throttle, thread_index, vlib_time_now (vm));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774
1775 from = vlib_frame_vector_args (frame);
1776 n_left_from = frame->n_vectors;
1777 next_index = node->cached_next_index;
1778 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001779 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001780
1781 while (n_left_from > 0)
1782 {
1783 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1784 to_next_drop, n_left_to_next_drop);
1785
1786 while (n_left_from > 0 && n_left_to_next_drop > 0)
1787 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001788 u32 pi0, bi0, adj_index0, sw_if_index0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001789 ip_adjacency_t *adj0;
Eyal Baribf9f02c2018-10-31 13:19:11 +02001790 vlib_buffer_t *p0, *b0;
1791 ip4_address_t resolve0;
1792 ethernet_arp_header_t *h0;
1793 vnet_hw_interface_t *hw_if0;
Neale Rannscd35e532018-08-31 02:51:45 -07001794 u64 r0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001795
1796 pi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001797 p0 = vlib_get_buffer (vm, pi0);
1798
Ed Warnickecb9cada2015-12-08 15:45:58 -07001799 from += 1;
1800 n_left_from -= 1;
1801 to_next_drop[0] = pi0;
1802 to_next_drop += 1;
1803 n_left_to_next_drop -= 1;
1804
Eyal Baribf9f02c2018-10-31 13:19:11 +02001805 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1806 adj0 = adj_get (adj_index0);
1807
1808 if (is_glean)
1809 {
1810 /* resolve the packet's destination */
1811 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1812 resolve0 = ip0->dst_address;
1813 }
1814 else
1815 {
1816 /* resolve the incomplete adj */
1817 resolve0 = adj0->sub_type.nbr.next_hop.ip4;
1818 }
1819
1820 /* combine the address and interface for the hash key */
1821 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1822 r0 = (u64) resolve0.data_u32 << 32;
1823 r0 |= sw_if_index0;
1824
1825 if (throttle_check (&im->arp_throttle, thread_index, r0, seed))
1826 {
1827 p0->error = node->errors[IP4_ARP_ERROR_THROTTLED];
1828 continue;
1829 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001830
Neale Rannsb80c5362016-10-08 13:03:40 +01001831 /*
1832 * the adj has been updated to a rewrite but the node the DPO that got
1833 * us here hasn't - yet. no big deal. we'll drop while we wait.
1834 */
1835 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
Eyal Baribf9f02c2018-10-31 13:19:11 +02001836 {
1837 p0->error = node->errors[IP4_ARP_ERROR_RESOLVED];
1838 continue;
1839 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001840
Dave Barachd7cb1b52016-12-09 09:52:16 -05001841 /*
1842 * Can happen if the control-plane is programming tables
1843 * with traffic flowing; at least that's today's lame excuse.
1844 */
Neale Ranns32e1c012016-11-22 17:07:28 +00001845 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1846 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001847 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001848 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Eyal Baribf9f02c2018-10-31 13:19:11 +02001849 continue;
1850 }
1851 /* Send ARP request. */
1852 h0 =
1853 vlib_packet_template_get_packet (vm,
1854 &im->ip4_arp_request_packet_template,
1855 &bi0);
Neale Ranns45db8852019-01-09 00:04:04 -08001856 b0 = vlib_get_buffer (vm, bi0);
1857
1858 /* copy the persistent fields from the original */
1859 clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
Eyal Baribf9f02c2018-10-31 13:19:11 +02001860
1861 /* Seems we're out of buffers */
1862 if (PREDICT_FALSE (!h0))
1863 {
1864 p0->error = node->errors[IP4_ARP_ERROR_NO_BUFFERS];
1865 continue;
1866 }
1867
1868 /* Add rewrite/encap string for ARP packet. */
1869 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
1870
1871 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1872
1873 /* Src ethernet address in ARP header. */
Neale Ranns37029302018-08-10 05:30:06 -07001874 mac_address_from_bytes (&h0->ip4_over_ethernet[0].mac,
1875 hw_if0->hw_address);
Eyal Baribf9f02c2018-10-31 13:19:11 +02001876 if (is_glean)
1877 {
1878 /* The interface's source address is stashed in the Glean Adj */
1879 h0->ip4_over_ethernet[0].ip4 =
1880 adj0->sub_type.glean.receive_addr.ip4;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001881 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001882 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001883 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001884 /* Src IP address in ARP header. */
1885 if (ip4_src_address_for_packet (lm, sw_if_index0,
1886 &h0->ip4_over_ethernet[0].ip4))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001887 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001888 /* No source address available */
1889 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1890 vlib_buffer_free (vm, &bi0, 1);
1891 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001892 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001893 }
Eyal Baribf9f02c2018-10-31 13:19:11 +02001894 h0->ip4_over_ethernet[1].ip4 = resolve0;
1895
1896 p0->error = node->errors[IP4_ARP_ERROR_REQUEST_SENT];
1897
1898 vlib_buffer_copy_trace_flag (vm, p0, bi0);
Eyal Baribf9f02c2018-10-31 13:19:11 +02001899 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
1900 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1901
1902 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1903
1904 vlib_set_next_frame_buffer (vm, node,
1905 adj0->rewrite_header.next_index, bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001906 }
1907
1908 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1909 }
1910
1911 return frame->n_vectors;
1912}
1913
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001914VLIB_NODE_FN (ip4_arp_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1915 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001916{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001917 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001918}
1919
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001920VLIB_NODE_FN (ip4_glean_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1921 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001922{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001923 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001924}
1925
Dave Barachd7cb1b52016-12-09 09:52:16 -05001926static char *ip4_arp_error_strings[] = {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001927 [IP4_ARP_ERROR_THROTTLED] = "ARP requests throttled",
1928 [IP4_ARP_ERROR_RESOLVED] = "ARP requests resolved",
1929 [IP4_ARP_ERROR_NO_BUFFERS] = "ARP requests out of buffer",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001930 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1931 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001932 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001933};
1934
Neale Rannsf8686322017-11-29 02:39:53 -08001935/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001936VLIB_REGISTER_NODE (ip4_arp_node) =
1937{
Neale Rannsf8686322017-11-29 02:39:53 -08001938 .name = "ip4-arp",
1939 .vector_size = sizeof (u32),
1940 .format_trace = format_ip4_forward_next_trace,
1941 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1942 .error_strings = ip4_arp_error_strings,
1943 .n_next_nodes = IP4_ARP_N_NEXT,
1944 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001945 {
Neale Rannsf8686322017-11-29 02:39:53 -08001946 [IP4_ARP_NEXT_DROP] = "error-drop",
1947 },
1948};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001949
Dave Barachd7cb1b52016-12-09 09:52:16 -05001950VLIB_REGISTER_NODE (ip4_glean_node) =
1951{
Neale Rannsf8686322017-11-29 02:39:53 -08001952 .name = "ip4-glean",
1953 .vector_size = sizeof (u32),
1954 .format_trace = format_ip4_forward_next_trace,
1955 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1956 .error_strings = ip4_arp_error_strings,
1957 .n_next_nodes = IP4_ARP_N_NEXT,
1958 .next_nodes = {
1959 [IP4_ARP_NEXT_DROP] = "error-drop",
1960 },
1961};
1962/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001963
Ed Warnickecb9cada2015-12-08 15:45:58 -07001964#define foreach_notrace_ip4_arp_error \
Eyal Baribf9f02c2018-10-31 13:19:11 +02001965_(THROTTLED) \
1966_(RESOLVED) \
1967_(NO_BUFFERS) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968_(REQUEST_SENT) \
Eyal Baribf9f02c2018-10-31 13:19:11 +02001969_(NON_ARP_ADJ) \
1970_(NO_SOURCE_ADDRESS)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001971
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001972static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001973arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001974{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001975 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001976
1977 /* don't trace ARP request packets */
1978#define _(a) \
1979 vnet_pcap_drop_trace_filter_add_del \
1980 (rt->errors[IP4_ARP_ERROR_##a], \
1981 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001982 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983#undef _
1984 return 0;
1985}
1986
Dave Barachd7cb1b52016-12-09 09:52:16 -05001987VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001988
1989
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001990#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001991/* Send an ARP request to see if given destination is reachable on given interface. */
1992clib_error_t *
John Lo86376342018-06-11 20:14:49 -04001993ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index,
1994 u8 refresh)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001996 vnet_main_t *vnm = vnet_get_main ();
1997 ip4_main_t *im = &ip4_main;
1998 ethernet_arp_header_t *h;
1999 ip4_address_t *src;
2000 ip_interface_address_t *ia;
2001 ip_adjacency_t *adj;
2002 vnet_hw_interface_t *hi;
2003 vnet_sw_interface_t *si;
2004 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002005 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006 u32 bi = 0;
John Lo86376342018-06-11 20:14:49 -04002007 u8 unicast_rewrite = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002008
2009 si = vnet_get_sw_interface (vnm, sw_if_index);
2010
2011 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2012 {
2013 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002014 format_ip4_address, dst,
2015 format_vnet_sw_if_index_name, vnm,
2016 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002017 }
2018
Dave Barachd7cb1b52016-12-09 09:52:16 -05002019 src =
2020 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2021 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002022 {
2023 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002024 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002025 (0,
2026 "no matching interface address for destination %U (interface %U)",
2027 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2028 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002029 }
2030
Neale Ranns7a272742017-05-30 02:08:14 -07002031 h = vlib_packet_template_get_packet (vm,
2032 &im->ip4_arp_request_packet_template,
2033 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002034
John Lo084606b2018-06-19 15:27:48 -04002035 if (!h)
2036 return clib_error_return (0, "ARP request packet allocation failed");
2037
Ed Warnickecb9cada2015-12-08 15:45:58 -07002038 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002039 if (PREDICT_FALSE (!hi->hw_address))
2040 {
2041 return clib_error_return (0, "%U: interface %U do not support ip probe",
2042 format_ip4_address, dst,
2043 format_vnet_sw_if_index_name, vnm,
2044 sw_if_index);
2045 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046
Neale Ranns37029302018-08-10 05:30:06 -07002047 mac_address_from_bytes (&h->ip4_over_ethernet[0].mac, hi->hw_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002048
2049 h->ip4_over_ethernet[0].ip4 = src[0];
2050 h->ip4_over_ethernet[1].ip4 = dst[0];
2051
2052 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002053 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2054 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002055
Dave Barach59b25652017-09-10 15:04:27 -04002056 ip46_address_t nh = {
2057 .ip4 = *dst,
2058 };
2059
2060 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2061 VNET_LINK_IP4, &nh, sw_if_index);
2062 adj = adj_get (ai);
2063
2064 /* Peer has been previously resolved, retrieve glean adj instead */
2065 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2066 {
John Lo86376342018-06-11 20:14:49 -04002067 if (refresh)
2068 unicast_rewrite = 1;
2069 else
2070 {
2071 adj_unlock (ai);
2072 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
2073 VNET_LINK_IP4, sw_if_index, &nh);
2074 adj = adj_get (ai);
2075 }
Dave Barach59b25652017-09-10 15:04:27 -04002076 }
2077
Ed Warnickecb9cada2015-12-08 15:45:58 -07002078 /* Add encapsulation string for software interface (e.g. ethernet header). */
2079 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
John Lo86376342018-06-11 20:14:49 -04002080 if (unicast_rewrite)
2081 {
2082 u16 *etype = vlib_buffer_get_current (b) - 2;
2083 etype[0] = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
2084 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002085 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2086
2087 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002088 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2089 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002090 to_next[0] = bi;
2091 f->n_vectors = 1;
2092 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2093 }
2094
Neale Ranns7a272742017-05-30 02:08:14 -07002095 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002096 return /* no error */ 0;
2097}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002098#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002099
Dave Barachd7cb1b52016-12-09 09:52:16 -05002100typedef enum
2101{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002102 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002103 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02002104 IP4_REWRITE_NEXT_FRAGMENT,
2105 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002106} ip4_rewrite_next_t;
2107
Neale Ranns889fe942017-06-01 05:43:19 -04002108/**
2109 * This bits of an IPv4 address to mask to construct a multicast
2110 * MAC address
2111 */
2112#if CLIB_ARCH_IS_BIG_ENDIAN
2113#define IP4_MCAST_ADDR_MASK 0x007fffff
2114#else
2115#define IP4_MCAST_ADDR_MASK 0xffff7f00
2116#endif
2117
Ole Troan8a9c8f12018-05-18 11:01:31 +02002118always_inline void
2119ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002120 u16 adj_packet_bytes, bool df, u16 * next, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002121{
2122 if (packet_len > adj_packet_bytes)
2123 {
2124 *error = IP4_ERROR_MTU_EXCEEDED;
2125 if (df)
2126 {
2127 icmp4_error_set_vnet_buffer
2128 (b, ICMP4_destination_unreachable,
2129 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2130 adj_packet_bytes);
2131 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2132 }
2133 else
2134 {
Ole Troan313f7e22018-04-10 16:02:51 +02002135 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002136 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troanb3655e52018-08-16 22:08:49 +02002137 IP4_FRAG_NEXT_IP4_REWRITE, 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002138 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002139 }
2140 }
2141}
2142
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002143/* Decrement TTL & update checksum.
2144 Works either endian, so no need for byte swap. */
2145static_always_inline void
2146ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2147 u32 * error)
2148{
2149 i32 ttl;
2150 u32 checksum;
2151 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2152 {
2153 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2154 return;
2155 }
2156
2157 ttl = ip->ttl;
2158
2159 /* Input node should have reject packets with ttl 0. */
2160 ASSERT (ip->ttl > 0);
2161
2162 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2163 checksum += checksum >= 0xffff;
2164
2165 ip->checksum = checksum;
2166 ttl -= 1;
2167 ip->ttl = ttl;
2168
2169 /*
2170 * If the ttl drops below 1 when forwarding, generate
2171 * an ICMP response.
2172 */
2173 if (PREDICT_FALSE (ttl <= 0))
2174 {
2175 *error = IP4_ERROR_TIME_EXPIRED;
2176 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2177 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2178 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2179 0);
2180 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2181 }
2182
2183 /* Verify checksum. */
2184 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2185 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2186}
2187
2188
Ed Warnickecb9cada2015-12-08 15:45:58 -07002189always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002190ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2191 vlib_node_runtime_t * node,
2192 vlib_frame_t * frame,
2193 int do_counters, int is_midchain, int is_mcast,
2194 int do_gso)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002195{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002196 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2197 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002198 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2199 u16 nexts[VLIB_FRAME_SIZE], *next;
2200 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002201 vlib_node_runtime_t *error_node =
2202 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203
2204 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002205 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002206
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002207 vlib_get_buffers (vm, from, bufs, n_left_from);
2208 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2209
2210 if (n_left_from >= 6)
2211 {
2212 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002213 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002214 vlib_prefetch_buffer_header (bufs[i], LOAD);
2215 }
2216
2217 next = nexts;
2218 b = bufs;
2219 while (n_left_from >= 8)
2220 {
2221 ip_adjacency_t *adj0, *adj1;
2222 ip4_header_t *ip0, *ip1;
2223 u32 rw_len0, error0, adj_index0;
2224 u32 rw_len1, error1, adj_index1;
2225 u32 tx_sw_if_index0, tx_sw_if_index1;
2226 u8 *p;
2227
2228 vlib_prefetch_buffer_header (b[6], LOAD);
2229 vlib_prefetch_buffer_header (b[7], LOAD);
2230
2231 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2232 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2233
2234 /*
2235 * pre-fetch the per-adjacency counters
2236 */
2237 if (do_counters)
2238 {
2239 vlib_prefetch_combined_counter (&adjacency_counters,
2240 thread_index, adj_index0);
2241 vlib_prefetch_combined_counter (&adjacency_counters,
2242 thread_index, adj_index1);
2243 }
2244
2245 ip0 = vlib_buffer_get_current (b[0]);
2246 ip1 = vlib_buffer_get_current (b[1]);
2247
2248 error0 = error1 = IP4_ERROR_NONE;
2249
2250 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2251 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2252
2253 /* Rewrite packet header and updates lengths. */
2254 adj0 = adj_get (adj_index0);
2255 adj1 = adj_get (adj_index1);
2256
2257 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2258 rw_len0 = adj0[0].rewrite_header.data_bytes;
2259 rw_len1 = adj1[0].rewrite_header.data_bytes;
2260 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2261 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2262
2263 p = vlib_buffer_get_current (b[2]);
2264 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2265 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2266
2267 p = vlib_buffer_get_current (b[3]);
2268 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2269 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2270
2271 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002272 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2273 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2274
2275 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2276 ip0_len = gso_mtu_sz (b[0]);
2277 if (do_gso && (b[1]->flags & VNET_BUFFER_F_GSO))
2278 ip1_len = gso_mtu_sz (b[1]);
2279
2280 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002281 adj0[0].rewrite_header.max_l3_packet_bytes,
2282 ip0->flags_and_fragment_offset &
2283 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2284 next + 0, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002285 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002286 adj1[0].rewrite_header.max_l3_packet_bytes,
2287 ip1->flags_and_fragment_offset &
2288 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2289 next + 1, &error1);
2290
2291 if (is_mcast)
2292 {
2293 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2294 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2295 IP4_ERROR_SAME_INTERFACE : error0);
2296 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2297 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2298 IP4_ERROR_SAME_INTERFACE : error1);
2299 }
2300
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002301 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2302 * to see the IP headerr */
2303 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2304 {
2305 u32 next_index = adj0[0].rewrite_header.next_index;
2306 b[0]->current_data -= rw_len0;
2307 b[0]->current_length += rw_len0;
2308 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2309 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2310
2311 if (PREDICT_FALSE
2312 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2313 vnet_feature_arc_start (lm->output_feature_arc_index,
2314 tx_sw_if_index0, &next_index, b[0]);
2315 next[0] = next_index;
2316 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002317 else
2318 {
2319 b[0]->error = error_node->errors[error0];
2320 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002321 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2322 {
2323 u32 next_index = adj1[0].rewrite_header.next_index;
2324 b[1]->current_data -= rw_len1;
2325 b[1]->current_length += rw_len1;
2326
2327 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2328 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2329
2330 if (PREDICT_FALSE
2331 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2332 vnet_feature_arc_start (lm->output_feature_arc_index,
2333 tx_sw_if_index1, &next_index, b[1]);
2334 next[1] = next_index;
2335 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002336 else
2337 {
2338 b[1]->error = error_node->errors[error1];
2339 }
Neale Ranns25edf142019-03-22 08:12:48 +00002340 if (is_midchain)
2341 {
2342 calc_checksums (vm, b[0]);
2343 calc_checksums (vm, b[1]);
2344 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002345 /* Guess we are only writing on simple Ethernet header. */
2346 vnet_rewrite_two_headers (adj0[0], adj1[0],
2347 ip0, ip1, sizeof (ethernet_header_t));
2348
2349 /*
2350 * Bump the per-adjacency counters
2351 */
2352 if (do_counters)
2353 {
2354 vlib_increment_combined_counter
2355 (&adjacency_counters,
2356 thread_index,
2357 adj_index0, 1, vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2358
2359 vlib_increment_combined_counter
2360 (&adjacency_counters,
2361 thread_index,
2362 adj_index1, 1, vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2363 }
2364
2365 if (is_midchain)
2366 {
Neale Ranns25edf142019-03-22 08:12:48 +00002367 if (adj0->sub_type.midchain.fixup_func)
2368 adj0->sub_type.midchain.fixup_func
2369 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2370 if (adj1->sub_type.midchain.fixup_func)
2371 adj1->sub_type.midchain.fixup_func
2372 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002373 }
2374
2375 if (is_mcast)
2376 {
2377 /*
2378 * copy bytes from the IP address into the MAC rewrite
2379 */
2380 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2381 adj0->rewrite_header.dst_mcast_offset,
2382 &ip0->dst_address.as_u32, (u8 *) ip0);
2383 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
Zhiyong Yangb2ecc5d2018-12-13 14:09:40 +08002384 adj1->rewrite_header.dst_mcast_offset,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002385 &ip1->dst_address.as_u32, (u8 *) ip1);
2386 }
2387
2388 next += 2;
2389 b += 2;
2390 n_left_from -= 2;
2391 }
2392
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393 while (n_left_from > 0)
2394 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002395 ip_adjacency_t *adj0;
2396 ip4_header_t *ip0;
2397 u32 rw_len0, adj_index0, error0;
2398 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002399
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002400 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2401
2402 adj0 = adj_get (adj_index0);
2403
2404 if (do_counters)
2405 vlib_prefetch_combined_counter (&adjacency_counters,
2406 thread_index, adj_index0);
2407
2408 ip0 = vlib_buffer_get_current (b[0]);
2409
2410 error0 = IP4_ERROR_NONE;
2411
2412 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2413
2414
2415 /* Update packet buffer attributes/set output interface. */
2416 rw_len0 = adj0[0].rewrite_header.data_bytes;
2417 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2418
2419 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002420 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2421 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2422 ip0_len = gso_mtu_sz (b[0]);
2423
2424 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002425 adj0[0].rewrite_header.max_l3_packet_bytes,
2426 ip0->flags_and_fragment_offset &
2427 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2428 next + 0, &error0);
2429
2430 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002431 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002432 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2433 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2434 IP4_ERROR_SAME_INTERFACE : error0);
2435 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002436
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002437 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2438 * to see the IP headerr */
2439 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2440 {
2441 u32 next_index = adj0[0].rewrite_header.next_index;
2442 b[0]->current_data -= rw_len0;
2443 b[0]->current_length += rw_len0;
2444 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2445 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002446
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002447 if (PREDICT_FALSE
2448 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2449 vnet_feature_arc_start (lm->output_feature_arc_index,
2450 tx_sw_if_index0, &next_index, b[0]);
2451 next[0] = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002452 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002453 else
2454 {
2455 b[0]->error = error_node->errors[error0];
2456 }
Neale Ranns25edf142019-03-22 08:12:48 +00002457 if (is_midchain)
2458 {
2459 calc_checksums (vm, b[0]);
2460 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002461 /* Guess we are only writing on simple Ethernet header. */
2462 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2463
2464 if (do_counters)
2465 vlib_increment_combined_counter
2466 (&adjacency_counters,
2467 thread_index, adj_index0, 1,
2468 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2469
2470 if (is_midchain)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 {
Neale Ranns25edf142019-03-22 08:12:48 +00002472 if (adj0->sub_type.midchain.fixup_func)
2473 adj0->sub_type.midchain.fixup_func
2474 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002475 }
Dave Barach75fc8542016-10-11 16:16:02 -04002476
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002477 if (is_mcast)
2478 {
2479 /*
2480 * copy bytes from the IP address into the MAC rewrite
2481 */
2482 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2483 adj0->rewrite_header.dst_mcast_offset,
2484 &ip0->dst_address.as_u32, (u8 *) ip0);
2485 }
2486
2487 next += 1;
2488 b += 1;
2489 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002490 }
2491
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002492
Ed Warnickecb9cada2015-12-08 15:45:58 -07002493 /* Need to do trace after rewrites to pick up new packet data. */
2494 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002495 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002496
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002497 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002498 return frame->n_vectors;
2499}
2500
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002501always_inline uword
2502ip4_rewrite_inline (vlib_main_t * vm,
2503 vlib_node_runtime_t * node,
2504 vlib_frame_t * frame,
2505 int do_counters, int is_midchain, int is_mcast)
2506{
2507 vnet_main_t *vnm = vnet_get_main ();
2508 if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
2509 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2510 is_midchain, is_mcast,
2511 1 /* do_gso */ );
2512 else
2513 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2514 is_midchain, is_mcast,
2515 0 /* no do_gso */ );
2516}
2517
Dave Barach132d51d2016-07-07 10:10:17 -04002518
Neale Rannsf06aea52016-11-29 06:51:37 -08002519/** @brief IPv4 rewrite node.
2520 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002521
2522 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2523 header checksum, fetch the ip adjacency, check the outbound mtu,
2524 apply the adjacency rewrite, and send pkts to the adjacency
2525 rewrite header's rewrite_next_index.
2526
2527 @param vm vlib_main_t corresponding to the current thread
2528 @param node vlib_node_runtime_t
2529 @param frame vlib_frame_t whose contents should be dispatched
2530
2531 @par Graph mechanics: buffer metadata, next index usage
2532
2533 @em Uses:
2534 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2535 - the rewrite adjacency index
2536 - <code>adj->lookup_next_index</code>
2537 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002538 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002539 - <code>adj->rewrite_header</code>
2540 - Rewrite string length, rewrite string, next_index
2541
2542 @em Sets:
2543 - <code>b->current_data, b->current_length</code>
2544 - Updated net of applying the rewrite string
2545
2546 <em>Next Indices:</em>
2547 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002548 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002549*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002550
2551VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2552 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002553{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002554 if (adj_are_counters_enabled ())
2555 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2556 else
2557 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002558}
2559
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002560VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2561 vlib_node_runtime_t * node,
2562 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002563{
2564 if (adj_are_counters_enabled ())
2565 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2566 else
2567 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2568}
2569
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002570VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2571 vlib_node_runtime_t * node,
2572 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002573{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002574 if (adj_are_counters_enabled ())
2575 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2576 else
2577 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002578}
2579
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002580VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2581 vlib_node_runtime_t * node,
2582 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002583{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002584 if (adj_are_counters_enabled ())
2585 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2586 else
2587 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002588}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002589
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002590VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2591 vlib_node_runtime_t * node,
2592 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002593{
2594 if (adj_are_counters_enabled ())
2595 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2596 else
2597 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2598}
2599
Neale Ranns32e1c012016-11-22 17:07:28 +00002600/* *INDENT-OFF* */
2601VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002602 .name = "ip4-rewrite",
2603 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002604
Neale Ranns32e1c012016-11-22 17:07:28 +00002605 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002606
Ole Troan313f7e22018-04-10 16:02:51 +02002607 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002608 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002609 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002610 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002611 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002612 },
2613};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002614
2615VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002616 .name = "ip4-rewrite-bcast",
2617 .vector_size = sizeof (u32),
2618
2619 .format_trace = format_ip4_rewrite_trace,
2620 .sibling_of = "ip4-rewrite",
2621};
Neale Ranns32e1c012016-11-22 17:07:28 +00002622
2623VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002624 .name = "ip4-rewrite-mcast",
2625 .vector_size = sizeof (u32),
2626
2627 .format_trace = format_ip4_rewrite_trace,
2628 .sibling_of = "ip4-rewrite",
2629};
Neale Ranns32e1c012016-11-22 17:07:28 +00002630
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002631VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002632 .name = "ip4-mcast-midchain",
2633 .vector_size = sizeof (u32),
2634
2635 .format_trace = format_ip4_rewrite_trace,
2636 .sibling_of = "ip4-rewrite",
2637};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002638
Neale Ranns32e1c012016-11-22 17:07:28 +00002639VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002640 .name = "ip4-midchain",
2641 .vector_size = sizeof (u32),
2642 .format_trace = format_ip4_forward_next_trace,
2643 .sibling_of = "ip4-rewrite",
2644};
Neale Ranns32e1c012016-11-22 17:07:28 +00002645/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002646
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002647static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002648ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2649{
2650 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002651 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002652 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002653
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002654 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002655
Neale Ranns04a75e32017-03-23 06:46:01 -07002656 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002657 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2658 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002659
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002660 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002661
Dave Barachd7cb1b52016-12-09 09:52:16 -05002662 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002663}
Dave Barach75fc8542016-10-11 16:16:02 -04002664
Ed Warnickecb9cada2015-12-08 15:45:58 -07002665static clib_error_t *
2666test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002667 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002668{
Billy McFall309fe062016-10-14 07:37:33 -04002669 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002670 u32 table_id = 0;
2671 f64 count = 1;
2672 u32 n;
2673 int i;
2674 ip4_address_t ip4_base_address;
2675 u64 errors = 0;
2676
Dave Barachd7cb1b52016-12-09 09:52:16 -05002677 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2678 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002679 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002680 {
2681 /* Make sure the entry exists. */
2682 fib = ip4_fib_get (table_id);
2683 if ((fib) && (fib->index != table_id))
2684 return clib_error_return (0, "<fib-index> %d does not exist",
2685 table_id);
2686 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002687 else if (unformat (input, "count %f", &count))
2688 ;
2689
2690 else if (unformat (input, "%U",
2691 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002692 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002693 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002694 return clib_error_return (0, "unknown input `%U'",
2695 format_unformat_error, input);
2696 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002697
2698 n = count;
2699
2700 for (i = 0; i < n; i++)
2701 {
2702 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002703 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002704
Dave Barach75fc8542016-10-11 16:16:02 -04002705 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002706 clib_host_to_net_u32 (1 +
2707 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002708 }
2709
Dave Barach75fc8542016-10-11 16:16:02 -04002710 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002711 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2712 else
2713 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2714
2715 return 0;
2716}
2717
Billy McFall0683c9c2016-10-13 08:27:31 -04002718/*?
2719 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2720 * given FIB table to determine if there is a conflict with the
2721 * adjacency table. The fib-id can be determined by using the
2722 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2723 * of 0 is used.
2724 *
2725 * @todo This command uses fib-id, other commands use table-id (not
2726 * just a name, they are different indexes). Would like to change this
2727 * to table-id for consistency.
2728 *
2729 * @cliexpar
2730 * Example of how to run the test lookup command:
2731 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2732 * No errors in 2 lookups
2733 * @cliexend
2734?*/
2735/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002736VLIB_CLI_COMMAND (lookup_test_command, static) =
2737{
2738 .path = "test lookup",
2739 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2740 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002741};
Billy McFall0683c9c2016-10-13 08:27:31 -04002742/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002743
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002744#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002745int
2746vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002747{
Neale Ranns107e7d42017-04-11 09:55:19 -07002748 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002749
Neale Ranns107e7d42017-04-11 09:55:19 -07002750 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2751
2752 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002753 return VNET_API_ERROR_NO_SUCH_FIB;
2754
Neale Ranns227038a2017-04-21 01:07:59 -07002755 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2756 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002757
Ed Warnickecb9cada2015-12-08 15:45:58 -07002758 return 0;
2759}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002760#endif
Dave Barach75fc8542016-10-11 16:16:02 -04002761
Ed Warnickecb9cada2015-12-08 15:45:58 -07002762static clib_error_t *
2763set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002764 unformat_input_t * input,
2765 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002766{
2767 int matched = 0;
2768 u32 table_id = 0;
2769 u32 flow_hash_config = 0;
2770 int rv;
2771
Dave Barachd7cb1b52016-12-09 09:52:16 -05002772 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2773 {
2774 if (unformat (input, "table %d", &table_id))
2775 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002776#define _(a,v) \
2777 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002778 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002779#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002780 else
2781 break;
2782 }
Dave Barach75fc8542016-10-11 16:16:02 -04002783
Ed Warnickecb9cada2015-12-08 15:45:58 -07002784 if (matched == 0)
2785 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002786 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002787
Ed Warnickecb9cada2015-12-08 15:45:58 -07002788 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2789 switch (rv)
2790 {
2791 case 0:
2792 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002793
Ed Warnickecb9cada2015-12-08 15:45:58 -07002794 case VNET_API_ERROR_NO_SUCH_FIB:
2795 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002796
Ed Warnickecb9cada2015-12-08 15:45:58 -07002797 default:
2798 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2799 break;
2800 }
Dave Barach75fc8542016-10-11 16:16:02 -04002801
Ed Warnickecb9cada2015-12-08 15:45:58 -07002802 return 0;
2803}
Dave Barach75fc8542016-10-11 16:16:02 -04002804
Billy McFall0683c9c2016-10-13 08:27:31 -04002805/*?
2806 * Configure the set of IPv4 fields used by the flow hash.
2807 *
2808 * @cliexpar
2809 * Example of how to set the flow hash on a given table:
2810 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2811 * Example of display the configured flow hash:
2812 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002813 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2814 * 0.0.0.0/0
2815 * unicast-ip4-chain
2816 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2817 * [0] [@0]: dpo-drop ip6
2818 * 0.0.0.0/32
2819 * unicast-ip4-chain
2820 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2821 * [0] [@0]: dpo-drop ip6
2822 * 224.0.0.0/8
2823 * unicast-ip4-chain
2824 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2825 * [0] [@0]: dpo-drop ip6
2826 * 6.0.1.2/32
2827 * unicast-ip4-chain
2828 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2829 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2830 * 7.0.0.1/32
2831 * unicast-ip4-chain
2832 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2833 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2834 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2835 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2836 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2837 * 240.0.0.0/8
2838 * unicast-ip4-chain
2839 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2840 * [0] [@0]: dpo-drop ip6
2841 * 255.255.255.255/32
2842 * unicast-ip4-chain
2843 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2844 * [0] [@0]: dpo-drop ip6
2845 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2846 * 0.0.0.0/0
2847 * unicast-ip4-chain
2848 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2849 * [0] [@0]: dpo-drop ip6
2850 * 0.0.0.0/32
2851 * unicast-ip4-chain
2852 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2853 * [0] [@0]: dpo-drop ip6
2854 * 172.16.1.0/24
2855 * unicast-ip4-chain
2856 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2857 * [0] [@4]: ipv4-glean: af_packet0
2858 * 172.16.1.1/32
2859 * unicast-ip4-chain
2860 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2861 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2862 * 172.16.1.2/32
2863 * unicast-ip4-chain
2864 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2865 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2866 * 172.16.2.0/24
2867 * unicast-ip4-chain
2868 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2869 * [0] [@4]: ipv4-glean: af_packet1
2870 * 172.16.2.1/32
2871 * unicast-ip4-chain
2872 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2873 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2874 * 224.0.0.0/8
2875 * unicast-ip4-chain
2876 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2877 * [0] [@0]: dpo-drop ip6
2878 * 240.0.0.0/8
2879 * unicast-ip4-chain
2880 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2881 * [0] [@0]: dpo-drop ip6
2882 * 255.255.255.255/32
2883 * unicast-ip4-chain
2884 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2885 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002886 * @cliexend
2887?*/
2888/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002889VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2890{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002891 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002892 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002893 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002894 .function = set_ip_flow_hash_command_fn,
2895};
Billy McFall0683c9c2016-10-13 08:27:31 -04002896/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002897
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002898#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002899int
2900vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2901 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002902{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002903 vnet_main_t *vnm = vnet_get_main ();
2904 vnet_interface_main_t *im = &vnm->interface_main;
2905 ip4_main_t *ipm = &ip4_main;
2906 ip_lookup_main_t *lm = &ipm->lookup_main;
2907 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002908 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002909
2910 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2911 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2912
2913 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2914 return VNET_API_ERROR_NO_SUCH_ENTRY;
2915
2916 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002917 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002918
Neale Rannsdf089a82016-10-02 16:39:06 +01002919 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2920
2921 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002922 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002923 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002924 .fp_len = 32,
2925 .fp_proto = FIB_PROTOCOL_IP4,
2926 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002927 };
2928 u32 fib_index;
2929
Dave Barachd7cb1b52016-12-09 09:52:16 -05002930 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2931 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002932
2933
Dave Barachd7cb1b52016-12-09 09:52:16 -05002934 if (table_index != (u32) ~ 0)
2935 {
2936 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002937
Dave Barachd7cb1b52016-12-09 09:52:16 -05002938 dpo_set (&dpo,
2939 DPO_CLASSIFY,
2940 DPO_PROTO_IP4,
2941 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002942
Dave Barachd7cb1b52016-12-09 09:52:16 -05002943 fib_table_entry_special_dpo_add (fib_index,
2944 &pfx,
2945 FIB_SOURCE_CLASSIFY,
2946 FIB_ENTRY_FLAG_NONE, &dpo);
2947 dpo_reset (&dpo);
2948 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002949 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002950 {
2951 fib_table_entry_special_remove (fib_index,
2952 &pfx, FIB_SOURCE_CLASSIFY);
2953 }
2954 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002955
Ed Warnickecb9cada2015-12-08 15:45:58 -07002956 return 0;
2957}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002958#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002959
2960static clib_error_t *
2961set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002962 unformat_input_t * input,
2963 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002964{
2965 u32 table_index = ~0;
2966 int table_index_set = 0;
2967 u32 sw_if_index = ~0;
2968 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002969
Dave Barachd7cb1b52016-12-09 09:52:16 -05002970 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2971 {
2972 if (unformat (input, "table-index %d", &table_index))
2973 table_index_set = 1;
2974 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2975 vnet_get_main (), &sw_if_index))
2976 ;
2977 else
2978 break;
2979 }
Dave Barach75fc8542016-10-11 16:16:02 -04002980
Ed Warnickecb9cada2015-12-08 15:45:58 -07002981 if (table_index_set == 0)
2982 return clib_error_return (0, "classify table-index must be specified");
2983
2984 if (sw_if_index == ~0)
2985 return clib_error_return (0, "interface / subif must be specified");
2986
2987 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2988
2989 switch (rv)
2990 {
2991 case 0:
2992 break;
2993
2994 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2995 return clib_error_return (0, "No such interface");
2996
2997 case VNET_API_ERROR_NO_SUCH_ENTRY:
2998 return clib_error_return (0, "No such classifier table");
2999 }
3000 return 0;
3001}
3002
Billy McFall0683c9c2016-10-13 08:27:31 -04003003/*?
3004 * Assign a classification table to an interface. The classification
3005 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3006 * commands. Once the table is create, use this command to filter packets
3007 * on an interface.
3008 *
3009 * @cliexpar
3010 * Example of how to assign a classification table to an interface:
3011 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3012?*/
3013/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003014VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3015{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003016 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003017 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003018 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003019 .function = set_ip_classify_command_fn,
3020};
Billy McFall0683c9c2016-10-13 08:27:31 -04003021/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003022
Neale Ranns1ec36522017-11-29 05:20:37 -08003023static clib_error_t *
3024ip4_config (vlib_main_t * vm, unformat_input_t * input)
3025{
3026 ip4_main_t *im = &ip4_main;
3027 uword heapsize = 0;
3028
3029 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3030 {
3031 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3032 ;
3033 else
3034 return clib_error_return (0,
3035 "invalid heap-size parameter `%U'",
3036 format_unformat_error, input);
3037 }
3038
3039 im->mtrie_heap_size = heapsize;
3040
3041 return 0;
3042}
3043
3044VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3045
Dave Barachd7cb1b52016-12-09 09:52:16 -05003046/*
3047 * fd.io coding-style-patch-verification: ON
3048 *
3049 * Local Variables:
3050 * eval: (c-set-style "gnu")
3051 * End:
3052 */