blob: ec4eda4e96ac922539ffe8a3e0214c71fa07bb40 [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>
Ed Warnickecb9cada2015-12-08 15:45:58 -070058
Chris Luke8e5b0412016-07-26 13:06:10 -040059/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040060 @node ip4-lookup
61
62 This is the main IPv4 lookup dispatch node.
63
64 @param vm vlib_main_t corresponding to the current thread
65 @param node vlib_node_runtime_t
66 @param frame vlib_frame_t whose contents should be dispatched
67
68 @par Graph mechanics: buffer metadata, next index usage
69
70 @em Uses:
71 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
72 - Indicates the @c sw_if_index value of the interface that the
73 packet was received on.
74 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
75 - When the value is @c ~0 then the node performs a longest prefix
76 match (LPM) for the packet destination address in the FIB attached
77 to the receive interface.
78 - Otherwise perform LPM for the packet destination address in the
79 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
80 value (0, 1, ...) and not a VRF id.
81
82 @em Sets:
83 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
84 - The lookup result adjacency index.
85
86 <em>Next Index:</em>
87 - Dispatches the packet to the node index found in
88 ip_adjacency_t @c adj->lookup_next_index
89 (where @c adj is the lookup result adjacency).
90*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020091VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
92 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070093{
Damjan Marionaca64c92016-04-13 09:48:56 +020094 return ip4_lookup_inline (vm, node, frame,
Dave Barachd7cb1b52016-12-09 09:52:16 -050095 /* lookup_for_responses_to_locally_received_packets */
96 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
98}
99
Dave Barachd7cb1b52016-12-09 09:52:16 -0500100static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100101
Neale Rannsf8686322017-11-29 02:39:53 -0800102/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500103VLIB_REGISTER_NODE (ip4_lookup_node) =
104{
Neale Rannsf8686322017-11-29 02:39:53 -0800105 .name = "ip4-lookup",
106 .vector_size = sizeof (u32),
107 .format_trace = format_ip4_lookup_trace,
108 .n_next_nodes = IP_LOOKUP_N_NEXT,
109 .next_nodes = IP4_LOOKUP_NEXT_NODES,
110};
111/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100112
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200113VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
114 vlib_node_runtime_t * node,
115 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500117 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
118 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100119 ip_lookup_next_t next;
Damjan Marion067cd622018-07-11 12:47:43 +0200120 u32 thread_index = vm->thread_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100122 from = vlib_frame_vector_args (frame);
123 n_left_from = frame->n_vectors;
124 next = node->cached_next_index;
125
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100126 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500128 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100129
Dave Barach75fc8542016-10-11 16:16:02 -0400130
Neale Ranns2be95c12016-11-19 13:50:04 +0000131 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500132 {
133 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000134 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500135 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000136 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
137 const ip4_header_t *ip0, *ip1;
138 const dpo_id_t *dpo0, *dpo1;
139
Dave Barachd7cb1b52016-12-09 09:52:16 -0500140 /* Prefetch next iteration. */
141 {
142 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000143
144 p2 = vlib_get_buffer (vm, from[2]);
145 p3 = vlib_get_buffer (vm, from[3]);
146
147 vlib_prefetch_buffer_header (p2, STORE);
148 vlib_prefetch_buffer_header (p3, STORE);
149
150 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
151 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500152 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000153
154 pi0 = to_next[0] = from[0];
155 pi1 = to_next[1] = from[1];
156
157 from += 2;
158 n_left_from -= 2;
159 to_next += 2;
160 n_left_to_next -= 2;
161
162 p0 = vlib_get_buffer (vm, pi0);
163 p1 = vlib_get_buffer (vm, pi1);
164
165 ip0 = vlib_buffer_get_current (p0);
166 ip1 = vlib_buffer_get_current (p1);
167 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
168 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
169
Dave Barachd7cb1b52016-12-09 09:52:16 -0500170 lb0 = load_balance_get (lbi0);
171 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000172
Dave Barachd7cb1b52016-12-09 09:52:16 -0500173 /*
174 * this node is for via FIBs we can re-use the hash value from the
175 * to node if present.
176 * We don't want to use the same hash value at each level in the recursion
177 * graph as that would lead to polarisation
178 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000179 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000180
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
182 {
183 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
184 {
185 hc0 = vnet_buffer (p0)->ip.flow_hash =
186 vnet_buffer (p0)->ip.flow_hash >> 1;
187 }
188 else
189 {
190 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000191 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500192 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700193 dpo0 = load_balance_get_fwd_bucket
194 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
195 }
196 else
197 {
198 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500199 }
200 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
201 {
202 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
203 {
204 hc1 = vnet_buffer (p1)->ip.flow_hash =
205 vnet_buffer (p1)->ip.flow_hash >> 1;
206 }
207 else
208 {
209 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000210 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500211 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700212 dpo1 = load_balance_get_fwd_bucket
213 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500214 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700215 else
216 {
217 dpo1 = load_balance_get_bucket_i (lb1, 0);
218 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000219
220 next0 = dpo0->dpoi_next_node;
221 next1 = dpo1->dpoi_next_node;
222
223 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
224 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
225
226 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200227 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000228 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200229 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000230
231 vlib_validate_buffer_enqueue_x2 (vm, node, next,
232 to_next, n_left_to_next,
233 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500234 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000235
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100236 while (n_left_from > 0 && n_left_to_next > 0)
237 {
238 ip_lookup_next_t next0;
239 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500240 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100241 u32 pi0, lbi0, hc0;
242 const ip4_header_t *ip0;
243 const dpo_id_t *dpo0;
244
245 pi0 = from[0];
246 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000247 from += 1;
248 to_next += 1;
249 n_left_to_next -= 1;
250 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100251
252 p0 = vlib_get_buffer (vm, pi0);
253
254 ip0 = vlib_buffer_get_current (p0);
255 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
256
Dave Barachd7cb1b52016-12-09 09:52:16 -0500257 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100258
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000259 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500260 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
261 {
262 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
263 {
264 hc0 = vnet_buffer (p0)->ip.flow_hash =
265 vnet_buffer (p0)->ip.flow_hash >> 1;
266 }
267 else
268 {
269 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000270 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500271 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700272 dpo0 = load_balance_get_fwd_bucket
273 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500274 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700275 else
276 {
277 dpo0 = load_balance_get_bucket_i (lb0, 0);
278 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100279
280 next0 = dpo0->dpoi_next_node;
281 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
282
Dave Barach75fc8542016-10-11 16:16:02 -0400283 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200284 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100285
Neale Ranns2be95c12016-11-19 13:50:04 +0000286 vlib_validate_buffer_enqueue_x1 (vm, node, next,
287 to_next, n_left_to_next,
288 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100289 }
290
291 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 }
293
Neale Rannsa71844f2018-11-08 07:31:36 -0800294 if (node->flags & VLIB_NODE_FLAG_TRACE)
295 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
296
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 return frame->n_vectors;
298}
299
Neale Rannsf8686322017-11-29 02:39:53 -0800300/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500301VLIB_REGISTER_NODE (ip4_load_balance_node) =
302{
Neale Rannsf8686322017-11-29 02:39:53 -0800303 .name = "ip4-load-balance",
304 .vector_size = sizeof (u32),
305 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200306 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800307};
308/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100309
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200310#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100311/* get first interface address */
312ip4_address_t *
313ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500314 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100315{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500316 ip_lookup_main_t *lm = &im->lookup_main;
317 ip_interface_address_t *ia = 0;
318 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100319
Neale Ranns32e1c012016-11-22 17:07:28 +0000320 /* *INDENT-OFF* */
321 foreach_ip_interface_address
322 (lm, ia, sw_if_index,
323 1 /* honor unnumbered */ ,
324 ({
325 ip4_address_t * a =
326 ip_interface_address_get_address (lm, ia);
327 result = a;
328 break;
329 }));
330 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100331 if (result_ia)
332 *result_ia = result ? ia : 0;
333 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334}
335
336static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700337ip4_add_subnet_bcast_route (u32 fib_index,
338 fib_prefix_t *pfx,
339 u32 sw_if_index)
340{
341 vnet_sw_interface_flags_t iflags;
342
343 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
344
345 fib_table_entry_special_remove(fib_index,
346 pfx,
347 FIB_SOURCE_INTERFACE);
348
349 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
350 {
351 fib_table_entry_update_one_path (fib_index, pfx,
352 FIB_SOURCE_INTERFACE,
353 FIB_ENTRY_FLAG_NONE,
354 DPO_PROTO_IP4,
355 /* No next-hop address */
356 &ADJ_BCAST_ADDR,
357 sw_if_index,
358 // invalid FIB index
359 ~0,
360 1,
361 // no out-label stack
362 NULL,
363 FIB_ROUTE_PATH_FLAG_NONE);
364 }
365 else
366 {
367 fib_table_entry_special_add(fib_index,
368 pfx,
369 FIB_SOURCE_INTERFACE,
370 (FIB_ENTRY_FLAG_DROP |
371 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
372 }
373}
374
375static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376ip4_add_interface_routes (u32 sw_if_index,
377 ip4_main_t * im, u32 fib_index,
378 ip_interface_address_t * a)
379{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500380 ip_lookup_main_t *lm = &im->lookup_main;
381 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100382 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500383 .fp_len = a->address_length,
384 .fp_proto = FIB_PROTOCOL_IP4,
385 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100386 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387
Neale Ranns9a69a602017-03-26 10:56:33 -0700388 if (pfx.fp_len <= 30)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500389 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700390 /* a /30 or shorter - add a glean for the network address */
Neale Ranns7a272742017-05-30 02:08:14 -0700391 fib_table_entry_update_one_path (fib_index, &pfx,
392 FIB_SOURCE_INTERFACE,
393 (FIB_ENTRY_FLAG_CONNECTED |
394 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700395 DPO_PROTO_IP4,
Neale Ranns7a272742017-05-30 02:08:14 -0700396 /* No next-hop address */
397 NULL,
398 sw_if_index,
399 // invalid FIB index
400 ~0,
401 1,
402 // no out-label stack
403 NULL,
404 FIB_ROUTE_PATH_FLAG_NONE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100405
Neale Ranns9a69a602017-03-26 10:56:33 -0700406 /* Add the two broadcast addresses as drop */
407 fib_prefix_t net_pfx = {
408 .fp_len = 32,
409 .fp_proto = FIB_PROTOCOL_IP4,
410 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
411 };
412 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
413 fib_table_entry_special_add(fib_index,
414 &net_pfx,
415 FIB_SOURCE_INTERFACE,
416 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700417 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700418 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
419 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
Neale Ranns1855b8e2018-07-11 10:31:26 -0700420 ip4_add_subnet_bcast_route(fib_index, &net_pfx, sw_if_index);
Neale Ranns9a69a602017-03-26 10:56:33 -0700421 }
422 else if (pfx.fp_len == 31)
423 {
424 u32 mask = clib_host_to_net_u32(1);
425 fib_prefix_t net_pfx = pfx;
426
427 net_pfx.fp_len = 32;
428 net_pfx.fp_addr.ip4.as_u32 ^= mask;
429
430 /* a /31 - add the other end as an attached host */
431 fib_table_entry_update_one_path (fib_index, &net_pfx,
432 FIB_SOURCE_INTERFACE,
433 (FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700434 DPO_PROTO_IP4,
Neale Ranns9a69a602017-03-26 10:56:33 -0700435 &net_pfx.fp_addr,
436 sw_if_index,
437 // invalid FIB index
438 ~0,
439 1,
440 NULL,
441 FIB_ROUTE_PATH_FLAG_NONE);
442 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100443 pfx.fp_len = 32;
444
445 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500446 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100447 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500448 lm->classify_table_index_by_sw_if_index[sw_if_index];
449 if (classify_table_index != (u32) ~ 0)
450 {
451 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100452
Dave Barachd7cb1b52016-12-09 09:52:16 -0500453 dpo_set (&dpo,
454 DPO_CLASSIFY,
455 DPO_PROTO_IP4,
456 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100457
Dave Barachd7cb1b52016-12-09 09:52:16 -0500458 fib_table_entry_special_dpo_add (fib_index,
459 &pfx,
460 FIB_SOURCE_CLASSIFY,
461 FIB_ENTRY_FLAG_NONE, &dpo);
462 dpo_reset (&dpo);
463 }
464 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100465
Neale Ranns32e1c012016-11-22 17:07:28 +0000466 fib_table_entry_update_one_path (fib_index, &pfx,
467 FIB_SOURCE_INTERFACE,
468 (FIB_ENTRY_FLAG_CONNECTED |
469 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700470 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000471 &pfx.fp_addr,
472 sw_if_index,
473 // invalid FIB index
474 ~0,
475 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500476 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700477}
478
479static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100480ip4_del_interface_routes (ip4_main_t * im,
481 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500484 fib_prefix_t pfx = {
485 .fp_len = address_length,
486 .fp_proto = FIB_PROTOCOL_IP4,
487 .fp_addr.ip4 = *address,
488 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489
Neale Ranns9a69a602017-03-26 10:56:33 -0700490 if (pfx.fp_len <= 30)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100491 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700492 fib_prefix_t net_pfx = {
493 .fp_len = 32,
494 .fp_proto = FIB_PROTOCOL_IP4,
495 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
496 };
497 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
498 fib_table_entry_special_remove(fib_index,
499 &net_pfx,
500 FIB_SOURCE_INTERFACE);
501 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
502 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
503 fib_table_entry_special_remove(fib_index,
504 &net_pfx,
505 FIB_SOURCE_INTERFACE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500506 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100507 }
Neale Ranns9a69a602017-03-26 10:56:33 -0700508 else if (pfx.fp_len == 31)
509 {
510 u32 mask = clib_host_to_net_u32(1);
511 fib_prefix_t net_pfx = pfx;
512
513 net_pfx.fp_len = 32;
514 net_pfx.fp_addr.ip4.as_u32 ^= mask;
515
516 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
517 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
Dave Barachd7cb1b52016-12-09 09:52:16 -0500519 pfx.fp_len = 32;
520 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521}
522
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100523void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500524ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100525{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500526 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100528 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
529
530 /*
531 * enable/disable only on the 1<->0 transition
532 */
533 if (is_enable)
534 {
535 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500536 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100537 }
538 else
539 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500540 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100541 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500542 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100543 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800544 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800545 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100546
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100547
Neale Ranns8269d3d2018-01-30 09:02:20 -0800548 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400549 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100550}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552static clib_error_t *
553ip4_add_del_interface_address_internal (vlib_main_t * vm,
554 u32 sw_if_index,
555 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500556 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700557{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500558 vnet_main_t *vnm = vnet_get_main ();
559 ip4_main_t *im = &ip4_main;
560 ip_lookup_main_t *lm = &im->lookup_main;
561 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700562 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500563 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564
Pavel Kotucek57808982017-08-02 08:20:19 +0200565 /* local0 interface doesn't support IP addressing */
566 if (sw_if_index == 0)
567 {
568 return
569 clib_error_create ("local0 interface doesn't support IP addressing");
570 }
571
Ed Warnickecb9cada2015-12-08 15:45:58 -0700572 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
573 ip4_addr_fib_init (&ip4_af, address,
574 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
575 vec_add1 (addr_fib, ip4_af);
576
Neale Ranns744902e2017-08-14 10:35:44 -0700577 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100578 * there is no support for adj-fib handling in the presence of overlapping
579 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
580 * most routers do.
581 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000582 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500583 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700584 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100585 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700586 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500587 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700588 vnet_sw_interface_t *sif;
589
590 pool_foreach(sif, vnm->interface_main.sw_interfaces,
591 ({
592 if (im->fib_index_by_sw_if_index[sw_if_index] ==
593 im->fib_index_by_sw_if_index[sif->sw_if_index])
594 {
595 foreach_ip_interface_address
596 (&im->lookup_main, ia, sif->sw_if_index,
597 0 /* honor unnumbered */ ,
598 ({
599 ip4_address_t * x =
600 ip_interface_address_get_address
601 (&im->lookup_main, ia);
602 if (ip4_destination_matches_route
603 (im, address, x, ia->address_length) ||
604 ip4_destination_matches_route (im,
605 x,
606 address,
607 address_length))
608 {
609 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
610
611 return
612 clib_error_create
613 ("failed to add %U which conflicts with %U for interface %U",
614 format_ip4_address_and_length, address,
615 address_length,
616 format_ip4_address_and_length, x,
617 ia->address_length,
618 format_vnet_sw_if_index_name, vnm,
619 sif->sw_if_index);
620 }
621 }));
622 }
623 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700624 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000625 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627 elts_before = pool_elts (lm->if_address_pool);
628
629 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500630 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 if (error)
632 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400633
Dave Barachd7cb1b52016-12-09 09:52:16 -0500634 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100635
636 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500637 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100638 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500639 ip4_add_interface_routes (sw_if_index,
640 im, ip4_af.fib_index,
641 pool_elt_at_index
642 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643
644 /* If pool did not grow/shrink: add duplicate address. */
645 if (elts_before != pool_elts (lm->if_address_pool))
646 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500647 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648 vec_foreach (cb, im->add_del_interface_address_callbacks)
649 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500650 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651 }
652
Dave Barachd7cb1b52016-12-09 09:52:16 -0500653done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654 vec_free (addr_fib);
655 return error;
656}
657
658clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000659ip4_add_del_interface_address (vlib_main_t * vm,
660 u32 sw_if_index,
661 ip4_address_t * address,
662 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663{
664 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500665 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700666}
667
Neale Ranns1855b8e2018-07-11 10:31:26 -0700668void
669ip4_directed_broadcast (u32 sw_if_index, u8 enable)
670{
671 ip_interface_address_t *ia;
672 ip4_main_t *im;
673
674 im = &ip4_main;
675
676 /*
677 * when directed broadcast is enabled, the subnet braodcast route will forward
678 * packets using an adjacency with a broadcast MAC. otherwise it drops
679 */
680 /* *INDENT-OFF* */
681 foreach_ip_interface_address(&im->lookup_main, ia,
682 sw_if_index, 0,
683 ({
684 if (ia->address_length <= 30)
685 {
686 ip4_address_t *ipa;
687
688 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
689
690 fib_prefix_t pfx = {
691 .fp_len = 32,
692 .fp_proto = FIB_PROTOCOL_IP4,
693 .fp_addr = {
694 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
695 },
696 };
697
698 ip4_add_subnet_bcast_route
699 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
700 sw_if_index),
701 &pfx, sw_if_index);
702 }
703 }));
704 /* *INDENT-ON* */
705}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200706#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700707
Dave Barachd6534602016-06-14 18:38:02 -0400708/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500709/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100710VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
711{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500712 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100713 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500714 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100715 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
716};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100717
Dave Barachd7cb1b52016-12-09 09:52:16 -0500718VNET_FEATURE_INIT (ip4_flow_classify, static) =
719{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100720 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700721 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100722 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700723};
724
Dave Barachd7cb1b52016-12-09 09:52:16 -0500725VNET_FEATURE_INIT (ip4_inacl, static) =
726{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100727 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400728 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100729 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400730};
731
Dave Barachd7cb1b52016-12-09 09:52:16 -0500732VNET_FEATURE_INIT (ip4_source_check_1, static) =
733{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100734 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400735 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100736 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400737};
738
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739VNET_FEATURE_INIT (ip4_source_check_2, static) =
740{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100741 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400742 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100743 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400744};
745
Dave Barachd7cb1b52016-12-09 09:52:16 -0500746VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
747{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100748 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400749 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100750 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400751};
752
Dave Barachd7cb1b52016-12-09 09:52:16 -0500753VNET_FEATURE_INIT (ip4_policer_classify, static) =
754{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100755 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700756 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100757 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700758};
759
Dave Barachd7cb1b52016-12-09 09:52:16 -0500760VNET_FEATURE_INIT (ip4_ipsec, static) =
761{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100762 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100763 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100764 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400765};
766
Dave Barachd7cb1b52016-12-09 09:52:16 -0500767VNET_FEATURE_INIT (ip4_vpath, static) =
768{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100769 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400770 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500771 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
772};
773
Dave Barachd7cb1b52016-12-09 09:52:16 -0500774VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
775{
John Lo37682e12016-11-30 12:51:39 -0500776 .arc_name = "ip4-unicast",
777 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100778 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400779};
780
Neale Ranns8269d3d2018-01-30 09:02:20 -0800781VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100783 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800784 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400785 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100786};
787
Neale Ranns180279b2017-03-16 15:49:09 -0400788VNET_FEATURE_INIT (ip4_lookup, static) =
789{
790 .arc_name = "ip4-unicast",
791 .node_name = "ip4-lookup",
792 .runs_before = 0, /* not before any other features */
793};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100794
Dave Barachd6534602016-06-14 18:38:02 -0400795/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100796VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
797{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500798 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100799 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500800 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100801 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
802};
803
Dave Barachd7cb1b52016-12-09 09:52:16 -0500804VNET_FEATURE_INIT (ip4_vpath_mc, static) =
805{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100806 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400807 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000808 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400809};
810
Neale Ranns8269d3d2018-01-30 09:02:20 -0800811VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100813 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800814 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400815 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
816};
817
818VNET_FEATURE_INIT (ip4_lookup_mc, static) =
819{
820 .arc_name = "ip4-multicast",
821 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500822 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100823};
Dave Barach5331c722016-08-17 11:54:30 -0400824
825/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100826VNET_FEATURE_ARC_INIT (ip4_output, static) =
827{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500828 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800829 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -0500830 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100831 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
832};
Dave Barach5331c722016-08-17 11:54:30 -0400833
Dave Barachd7cb1b52016-12-09 09:52:16 -0500834VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
835{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100836 .arc_name = "ip4-output",
837 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100838 .runs_before = VNET_FEATURES ("ip4-outacl"),
839};
840
841VNET_FEATURE_INIT (ip4_outacl, static) =
842{
843 .arc_name = "ip4-output",
844 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +0100845 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -0800846};
847
Dave Barachd7cb1b52016-12-09 09:52:16 -0500848VNET_FEATURE_INIT (ip4_ipsec_output, static) =
849{
Matus Fabian08a6f012016-11-15 06:08:51 -0800850 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +0100851 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100852 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -0400853};
854
855/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500856VNET_FEATURE_INIT (ip4_interface_output, static) =
857{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100858 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -0400859 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500860 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -0400861};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500862/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400863
Ed Warnickecb9cada2015-12-08 15:45:58 -0700864static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500865ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700866{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500867 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100869 /* Fill in lookup tables with default table (0). */
870 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000871 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100872
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200873 if (!is_add)
874 {
875 ip4_main_t *im4 = &ip4_main;
876 ip_lookup_main_t *lm4 = &im4->lookup_main;
877 ip_interface_address_t *ia = 0;
878 ip4_address_t *address;
879 vlib_main_t *vm = vlib_get_main ();
880
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700881 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200882 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700883 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200884 ({
885 address = ip_interface_address_get_address (lm4, ia);
886 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
887 }));
888 /* *INDENT-ON* */
889 }
890
Neale Ranns8269d3d2018-01-30 09:02:20 -0800891 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100892 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893
Neale Ranns8269d3d2018-01-30 09:02:20 -0800894 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
895 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896
Ed Warnickecb9cada2015-12-08 15:45:58 -0700897 return /* no error */ 0;
898}
899
900VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
901
Ed Warnickecb9cada2015-12-08 15:45:58 -0700902/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +0100903#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -0700904ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +0100905#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700906
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200907static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908ip4_lookup_init (vlib_main_t * vm)
909{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500910 ip4_main_t *im = &ip4_main;
911 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700912 uword i;
913
Damjan Marion8b3191e2016-11-09 19:54:20 +0100914 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
915 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -0800916 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
917 return (error);
918 if ((error = vlib_call_init_function (vm, fib_module_init)))
919 return error;
920 if ((error = vlib_call_init_function (vm, mfib_module_init)))
921 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100922
Ed Warnickecb9cada2015-12-08 15:45:58 -0700923 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
924 {
925 u32 m;
926
927 if (i < 32)
928 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -0400929 else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700930 m = ~0;
931 im->fib_masks[i] = clib_host_to_net_u32 (m);
932 }
933
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
935
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100936 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -0700937 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
938 FIB_SOURCE_DEFAULT_ROUTE);
939 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
940 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100941
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500943 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944 pn = pg_get_node (ip4_lookup_node.index);
945 pn->unformat_edit = unformat_pg_ip4_header;
946 }
947
948 {
949 ethernet_arp_header_t h;
950
Dave Barachb7b92992018-10-17 10:38:51 -0400951 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953#define _16(f,v) h.f = clib_host_to_net_u16 (v);
954#define _8(f,v) h.f = v;
955 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
956 _16 (l3_type, ETHERNET_TYPE_IP4);
957 _8 (n_l2_address_bytes, 6);
958 _8 (n_l3_address_bytes, 4);
959 _16 (opcode, ETHERNET_ARP_OPCODE_request);
960#undef _16
961#undef _8
962
Dave Barachd7cb1b52016-12-09 09:52:16 -0500963 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700964 /* data */ &h,
965 sizeof (h),
966 /* alloc chunk size */ 8,
967 "ip4 arp");
968 }
969
Dave Barach203c6322016-06-26 10:29:03 -0400970 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971}
972
973VLIB_INIT_FUNCTION (ip4_lookup_init);
974
Dave Barachd7cb1b52016-12-09 09:52:16 -0500975typedef struct
976{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700977 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -0700978 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700979 u32 flow_hash;
980 u32 fib_index;
981
982 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500983 u8 packet_data[64 - 1 * sizeof (u32)];
984}
985ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200987#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -0500988u8 *
989format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990{
991 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
992 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500993 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200994 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100995 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -0400996 format_white_space, indent,
997 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100998 return s;
999}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001000#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001001
Dave Barachd7cb1b52016-12-09 09:52:16 -05001002static u8 *
1003format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001004{
1005 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1006 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001007 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001008 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009
John Loac8146c2016-09-27 17:44:02 -04001010 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001011 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001012 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001013 format_white_space, indent,
1014 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001015 return s;
1016}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017
Dave Barachd7cb1b52016-12-09 09:52:16 -05001018static u8 *
1019format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001020{
1021 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1022 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001023 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001024 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025
Vengada Govindanf1544482016-09-28 02:45:57 -07001026 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001027 t->fib_index, t->dpo_index, format_ip_adjacency,
1028 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001029 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001030 format_white_space, indent,
1031 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001032 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 return s;
1034}
1035
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001036#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037/* Common trace function for all ip4-forward next nodes. */
1038void
1039ip4_forward_next_trace (vlib_main_t * vm,
1040 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001041 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001043 u32 *from, n_left;
1044 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045
1046 n_left = frame->n_vectors;
1047 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001048
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 while (n_left >= 4)
1050 {
1051 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001052 vlib_buffer_t *b0, *b1;
1053 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054
1055 /* Prefetch next iteration. */
1056 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1057 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1058
1059 bi0 = from[0];
1060 bi1 = from[1];
1061
1062 b0 = vlib_get_buffer (vm, bi0);
1063 b1 = vlib_get_buffer (vm, bi1);
1064
1065 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1066 {
1067 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001068 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001070 t0->fib_index =
1071 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1072 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1073 vec_elt (im->fib_index_by_sw_if_index,
1074 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001075
Dave Barach178cf492018-11-13 16:34:13 -05001076 clib_memcpy_fast (t0->packet_data,
1077 vlib_buffer_get_current (b0),
1078 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079 }
1080 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1081 {
1082 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001083 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085 t1->fib_index =
1086 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1087 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1088 vec_elt (im->fib_index_by_sw_if_index,
1089 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001090 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1091 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001092 }
1093 from += 2;
1094 n_left -= 2;
1095 }
1096
1097 while (n_left >= 1)
1098 {
1099 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001100 vlib_buffer_t *b0;
1101 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102
1103 bi0 = from[0];
1104
1105 b0 = vlib_get_buffer (vm, bi0);
1106
1107 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1108 {
1109 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001110 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001112 t0->fib_index =
1113 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1114 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1115 vec_elt (im->fib_index_by_sw_if_index,
1116 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001117 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1118 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119 }
1120 from += 1;
1121 n_left -= 1;
1122 }
1123}
1124
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125/* Compute TCP/UDP/ICMP4 checksum in software. */
1126u16
1127ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1128 ip4_header_t * ip0)
1129{
1130 ip_csum_t sum0;
1131 u32 ip_header_length, payload_length_host_byte_order;
Florin Corasb2215d62017-08-01 16:56:58 -07001132 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001133 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001134 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001135
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136 /* Initialize checksum with ip header. */
1137 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001138 payload_length_host_byte_order =
1139 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1140 sum0 =
1141 clib_host_to_net_u32 (payload_length_host_byte_order +
1142 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001143
1144 if (BITS (uword) == 32)
1145 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001146 sum0 =
1147 ip_csum_with_carry (sum0,
1148 clib_mem_unaligned (&ip0->src_address, u32));
1149 sum0 =
1150 ip_csum_with_carry (sum0,
1151 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001152 }
1153 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001154 sum0 =
1155 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156
1157 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1158 data_this_buffer = (void *) ip0 + ip_header_length;
Neale Rannsd91c1db2017-07-31 02:30:50 -07001159 n_ip_bytes_this_buffer =
1160 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
Florin Corasb2215d62017-08-01 16:56:58 -07001161 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1162 {
1163 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
Neale Rannsd91c1db2017-07-31 02:30:50 -07001164 n_ip_bytes_this_buffer - ip_header_length : 0;
Florin Corasb2215d62017-08-01 16:56:58 -07001165 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 while (1)
1167 {
1168 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1169 n_bytes_left -= n_this_buffer;
1170 if (n_bytes_left == 0)
1171 break;
1172
1173 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1174 p0 = vlib_get_buffer (vm, p0->next_buffer);
1175 data_this_buffer = vlib_buffer_get_current (p0);
1176 n_this_buffer = p0->current_length;
1177 }
1178
Dave Barachd7cb1b52016-12-09 09:52:16 -05001179 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180
1181 return sum16;
1182}
1183
John Lo37682e12016-11-30 12:51:39 -05001184u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1186{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001187 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1188 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189 u16 sum16;
1190
1191 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1192 || ip0->protocol == IP_PROTOCOL_UDP);
1193
1194 udp0 = (void *) (ip0 + 1);
1195 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1196 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001197 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1198 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199 return p0->flags;
1200 }
1201
1202 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1203
Damjan Marion213b5aa2017-07-13 21:19:27 +02001204 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1205 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001206
1207 return p0->flags;
1208}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001209#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210
Dave Barach68b0fb02017-02-28 15:15:56 -05001211/* *INDENT-OFF* */
1212VNET_FEATURE_ARC_INIT (ip4_local) =
1213{
1214 .arc_name = "ip4-local",
1215 .start_nodes = VNET_FEATURES ("ip4-local"),
Dave Baracha25def72018-11-26 11:04:45 -05001216 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001217};
1218/* *INDENT-ON* */
1219
Florin Coras20a14b92017-08-15 22:47:22 -07001220static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001221ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1222 ip4_header_t * ip, u8 is_udp, u8 * error,
1223 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001224{
1225 u32 flags0;
1226 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1227 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1228 if (is_udp)
1229 {
1230 udp_header_t *udp;
1231 u32 ip_len, udp_len;
1232 i32 len_diff;
1233 udp = ip4_next_header (ip);
1234 /* Verify UDP length. */
1235 ip_len = clib_net_to_host_u16 (ip->length);
1236 udp_len = clib_net_to_host_u16 (udp->length);
1237
1238 len_diff = ip_len - udp_len;
1239 *good_tcp_udp &= len_diff >= 0;
1240 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1241 }
1242}
1243
Florin Coras1b255522018-06-01 12:22:23 -07001244#define ip4_local_csum_is_offloaded(_b) \
1245 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1246 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1247
1248#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1249 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1250 || ip4_local_csum_is_offloaded (_b)))
1251
1252#define ip4_local_csum_is_valid(_b) \
1253 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1254 || (ip4_local_csum_is_offloaded (_b))) != 0
1255
1256static inline void
1257ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1258 ip4_header_t * ih, u8 * error)
1259{
1260 u8 is_udp, is_tcp_udp, good_tcp_udp;
1261
1262 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1263 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1264
1265 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1266 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1267 else
1268 good_tcp_udp = ip4_local_csum_is_valid (b);
1269
1270 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1271 *error = (is_tcp_udp && !good_tcp_udp
1272 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1273}
1274
1275static inline void
1276ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1277 ip4_header_t ** ih, u8 * error)
1278{
1279 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1280
1281 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1282 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1283
1284 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1285 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1286
1287 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1288 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1289
1290 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1291 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1292 {
1293 if (is_tcp_udp[0])
1294 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1295 &good_tcp_udp[0]);
1296 if (is_tcp_udp[1])
1297 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1298 &good_tcp_udp[1]);
1299 }
1300
1301 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1302 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1303 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1304 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1305}
1306
1307static inline void
1308ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1309 vlib_buffer_t * b, u16 * next, u8 error,
1310 u8 head_of_feature_arc)
1311{
1312 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1313 u32 next_index;
1314
1315 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1316 b->error = error ? error_node->errors[error] : 0;
1317 if (head_of_feature_arc)
1318 {
1319 next_index = *next;
1320 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1321 {
1322 vnet_feature_arc_start (arc_index,
1323 vnet_buffer (b)->sw_if_index[VLIB_RX],
1324 &next_index, b);
1325 *next = next_index;
1326 }
1327 }
1328}
1329
1330typedef struct
1331{
1332 ip4_address_t src;
1333 u32 lbi;
1334 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001335 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001336} ip4_local_last_check_t;
1337
1338static inline void
1339ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1340 ip4_local_last_check_t * last_check, u8 * error0)
1341{
1342 ip4_fib_mtrie_leaf_t leaf0;
1343 ip4_fib_mtrie_t *mtrie0;
1344 const dpo_id_t *dpo0;
1345 load_balance_t *lb0;
1346 u32 lbi0;
1347
1348 vnet_buffer (b)->ip.fib_index =
1349 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1350 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1351
Neale Rannsbe2286b2018-12-09 12:54:51 -08001352 if (PREDICT_FALSE (last_check->first ||
1353 (last_check->src.as_u32 != ip0->src_address.as_u32)))
Florin Coras1b255522018-06-01 12:22:23 -07001354 {
1355 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1356 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1357 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1358 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1359 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1360
1361 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1362 vnet_buffer (b)->ip.adj_index[VLIB_RX] = lbi0;
1363
1364 lb0 = load_balance_get (lbi0);
1365 dpo0 = load_balance_get_bucket_i (lb0, 0);
1366
1367 /*
1368 * Must have a route to source otherwise we drop the packet.
1369 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1370 *
1371 * The checks are:
1372 * - the source is a recieve => it's from us => bogus, do this
1373 * first since it sets a different error code.
1374 * - uRPF check for any route to source - accept if passes.
1375 * - allow packets destined to the broadcast address from unknown sources
1376 */
1377
1378 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1379 && dpo0->dpoi_type == DPO_RECEIVE) ?
1380 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1381 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1382 && !fib_urpf_check_size (lb0->lb_urpf)
1383 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1384 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1385
1386 last_check->src.as_u32 = ip0->src_address.as_u32;
1387 last_check->lbi = lbi0;
1388 last_check->error = *error0;
1389 }
1390 else
1391 {
1392 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1393 vnet_buffer (b)->ip.adj_index[VLIB_RX] = last_check->lbi;
1394 *error0 = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001395 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001396 }
1397}
1398
1399static inline void
1400ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1401 ip4_local_last_check_t * last_check, u8 * error)
1402{
1403 ip4_fib_mtrie_leaf_t leaf[2];
1404 ip4_fib_mtrie_t *mtrie[2];
1405 const dpo_id_t *dpo[2];
1406 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001407 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001408 u32 lbi[2];
1409
Neale Rannsbe2286b2018-12-09 12:54:51 -08001410 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001411 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1412 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1413
1414 vnet_buffer (b[0])->ip.fib_index =
1415 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1416 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1417 vnet_buffer (b[0])->ip.fib_index;
1418
1419 vnet_buffer (b[1])->ip.fib_index =
1420 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1421 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1422 vnet_buffer (b[1])->ip.fib_index;
1423
1424 if (PREDICT_FALSE (not_last_hit))
1425 {
1426 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1427 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1428
1429 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1430 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1431
1432 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1433 &ip[0]->src_address, 2);
1434 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1435 &ip[1]->src_address, 2);
1436
1437 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1438 &ip[0]->src_address, 3);
1439 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1440 &ip[1]->src_address, 3);
1441
1442 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1443 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1444
1445 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1446 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = lbi[0];
1447
1448 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1449 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = lbi[1];
1450
1451 lb[0] = load_balance_get (lbi[0]);
1452 lb[1] = load_balance_get (lbi[1]);
1453
1454 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1455 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1456
1457 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1458 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1459 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1460 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1461 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1462 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1463 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1464
1465 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1466 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1467 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1468 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1469 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1470 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1471 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1472
1473 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1474 last_check->lbi = lbi[1];
1475 last_check->error = error[1];
1476 }
1477 else
1478 {
1479 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1480 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = last_check->lbi;
1481
1482 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1483 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = last_check->lbi;
1484
1485 error[0] = last_check->error;
1486 error[1] = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001487 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001488 }
1489}
Florin Coras20a14b92017-08-15 22:47:22 -07001490
Florin Corasc67cfd22018-10-01 21:59:18 -07001491enum ip_local_packet_type_e
1492{
1493 IP_LOCAL_PACKET_TYPE_L4,
1494 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001495 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001496};
1497
1498/**
1499 * Determine packet type and next node.
1500 *
1501 * The expectation is that all packets that are not L4 will skip
1502 * checksums and source checks.
1503 */
1504always_inline u8
1505ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1506{
1507 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1508
Juraj Sloboda3048b632018-10-02 11:13:53 +02001509 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1510 {
1511 *next = IP_LOCAL_NEXT_REASSEMBLY;
1512 return IP_LOCAL_PACKET_TYPE_FRAG;
1513 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001514 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1515 {
1516 *next = lm->local_next_by_ip_protocol[ip->protocol];
1517 return IP_LOCAL_PACKET_TYPE_NAT;
1518 }
1519
1520 *next = lm->local_next_by_ip_protocol[ip->protocol];
1521 return IP_LOCAL_PACKET_TYPE_L4;
1522}
1523
Dave Barach68b0fb02017-02-28 15:15:56 -05001524static inline uword
1525ip4_local_inline (vlib_main_t * vm,
1526 vlib_node_runtime_t * node,
1527 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001528{
Florin Coras1b255522018-06-01 12:22:23 -07001529 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001530 vlib_node_runtime_t *error_node =
1531 vlib_node_get_runtime (vm, ip4_input_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001532 u16 nexts[VLIB_FRAME_SIZE], *next;
1533 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1534 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001535 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001536
1537 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001538 /*
1539 * 0.0.0.0 can appear as the source address of an IP packet,
1540 * as can any other address, hence the need to use the 'first'
1541 * member to make sure the .lbi is initialised for the first
1542 * packet.
1543 */
Florin Coras1b255522018-06-01 12:22:23 -07001544 .src = {.as_u32 = 0},
1545 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001546 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1547 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001548 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001549
1550 from = vlib_frame_vector_args (frame);
1551 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001552
Ed Warnickecb9cada2015-12-08 15:45:58 -07001553 if (node->flags & VLIB_NODE_FLAG_TRACE)
1554 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1555
Florin Coras1b255522018-06-01 12:22:23 -07001556 vlib_get_buffers (vm, from, bufs, n_left_from);
1557 b = bufs;
1558 next = nexts;
1559
1560 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001561 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001562 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001563
Florin Coras1b255522018-06-01 12:22:23 -07001564 /* Prefetch next iteration. */
1565 {
1566 vlib_prefetch_buffer_header (b[4], LOAD);
1567 vlib_prefetch_buffer_header (b[5], LOAD);
1568
1569 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1570 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1571 }
1572
1573 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1574
1575 ip[0] = vlib_buffer_get_current (b[0]);
1576 ip[1] = vlib_buffer_get_current (b[1]);
1577
1578 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1579 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1580
Florin Corasc67cfd22018-10-01 21:59:18 -07001581 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1582 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001583
Florin Corasc67cfd22018-10-01 21:59:18 -07001584 not_batch = pt[0] ^ pt[1];
1585
1586 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001587 goto skip_checks;
1588
1589 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001590 {
Florin Coras1b255522018-06-01 12:22:23 -07001591 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1592 ip4_local_check_src_x2 (b, ip, &last_check, error);
1593 }
1594 else
1595 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001596 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001597 {
Florin Coras1b255522018-06-01 12:22:23 -07001598 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1599 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
Florin Coras20a14b92017-08-15 22:47:22 -07001600 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001601 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001602 {
Florin Coras1b255522018-06-01 12:22:23 -07001603 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1604 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605 }
1606 }
1607
Florin Coras1b255522018-06-01 12:22:23 -07001608 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001609
Florin Coras1b255522018-06-01 12:22:23 -07001610 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1611 head_of_feature_arc);
1612 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1613 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001614
Florin Coras1b255522018-06-01 12:22:23 -07001615 b += 2;
1616 next += 2;
1617 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001618 }
1619
Florin Coras1b255522018-06-01 12:22:23 -07001620 while (n_left_from > 0)
1621 {
1622 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1623
1624 ip[0] = vlib_buffer_get_current (b[0]);
1625 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001626 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001627
Florin Corasc67cfd22018-10-01 21:59:18 -07001628 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001629 goto skip_check;
1630
1631 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1632 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1633
1634 skip_check:
1635
Florin Coras1b255522018-06-01 12:22:23 -07001636 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1637 head_of_feature_arc);
1638
1639 b += 1;
1640 next += 1;
1641 n_left_from -= 1;
1642 }
1643
1644 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001645 return frame->n_vectors;
1646}
1647
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001648VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1649 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001650{
1651 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1652}
1653
1654/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001655VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001656{
Dave Barach68b0fb02017-02-28 15:15:56 -05001657 .name = "ip4-local",
1658 .vector_size = sizeof (u32),
1659 .format_trace = format_ip4_forward_next_trace,
1660 .n_next_nodes = IP_LOCAL_N_NEXT,
1661 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001662 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001663 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1664 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001665 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001666 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Juraj Sloboda3048b632018-10-02 11:13:53 +02001667 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001668 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001669};
1670/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001671
Dave Barachd7cb1b52016-12-09 09:52:16 -05001672
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001673VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1674 vlib_node_runtime_t * node,
1675 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001676{
1677 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1678}
1679
1680/* *INDENT-OFF* */
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001681VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001682 .name = "ip4-local-end-of-arc",
1683 .vector_size = sizeof (u32),
1684
1685 .format_trace = format_ip4_forward_next_trace,
1686 .sibling_of = "ip4-local",
1687};
1688
Dave Barach68b0fb02017-02-28 15:15:56 -05001689VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1690 .arc_name = "ip4-local",
1691 .node_name = "ip4-local-end-of-arc",
1692 .runs_before = 0, /* not before any other features */
1693};
1694/* *INDENT-ON* */
1695
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001696#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001697void
1698ip4_register_protocol (u32 protocol, u32 node_index)
1699{
1700 vlib_main_t *vm = vlib_get_main ();
1701 ip4_main_t *im = &ip4_main;
1702 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001703
1704 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001705 lm->local_next_by_ip_protocol[protocol] =
1706 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001707}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001708#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001709
1710static clib_error_t *
1711show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001712 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001713{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001714 ip4_main_t *im = &ip4_main;
1715 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001716 int i;
1717
1718 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001719 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001720 {
1721 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001722 {
1723 u32 node_index = vlib_get_node (vm,
1724 ip4_local_node.index)->
1725 next_nodes[lm->local_next_by_ip_protocol[i]];
1726 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1727 node_index);
1728 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001729 }
1730 return 0;
1731}
1732
1733
1734
Billy McFall0683c9c2016-10-13 08:27:31 -04001735/*?
1736 * Display the set of protocols handled by the local IPv4 stack.
1737 *
1738 * @cliexpar
1739 * Example of how to display local protocol table:
1740 * @cliexstart{show ip local}
1741 * Protocols handled by ip4_local
1742 * 1
1743 * 17
1744 * 47
1745 * @cliexend
1746?*/
1747/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001748VLIB_CLI_COMMAND (show_ip_local, static) =
1749{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001750 .path = "show ip local",
1751 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001752 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001753};
Billy McFall0683c9c2016-10-13 08:27:31 -04001754/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001755
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001756always_inline uword
1757ip4_arp_inline (vlib_main_t * vm,
1758 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001759 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001760{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001761 vnet_main_t *vnm = vnet_get_main ();
1762 ip4_main_t *im = &ip4_main;
1763 ip_lookup_main_t *lm = &im->lookup_main;
1764 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765 uword n_left_from, n_left_to_next_drop, next_index;
Dave Barach49433ad2018-08-08 17:59:03 -04001766 u32 thread_index = vm->thread_index;
Neale Rannscd35e532018-08-31 02:51:45 -07001767 u64 seed;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768
1769 if (node->flags & VLIB_NODE_FLAG_TRACE)
1770 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1771
Neale Rannsc8352bc2018-08-29 10:23:58 -07001772 seed = throttle_seed (&im->arp_throttle, thread_index, vlib_time_now (vm));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773
1774 from = vlib_frame_vector_args (frame);
1775 n_left_from = frame->n_vectors;
1776 next_index = node->cached_next_index;
1777 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001778 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001779
1780 while (n_left_from > 0)
1781 {
1782 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1783 to_next_drop, n_left_to_next_drop);
1784
1785 while (n_left_from > 0 && n_left_to_next_drop > 0)
1786 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001787 u32 pi0, bi0, adj_index0, sw_if_index0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001788 ip_adjacency_t *adj0;
Eyal Baribf9f02c2018-10-31 13:19:11 +02001789 vlib_buffer_t *p0, *b0;
1790 ip4_address_t resolve0;
1791 ethernet_arp_header_t *h0;
1792 vnet_hw_interface_t *hw_if0;
Neale Rannscd35e532018-08-31 02:51:45 -07001793 u64 r0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001794
1795 pi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796 p0 = vlib_get_buffer (vm, pi0);
1797
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798 from += 1;
1799 n_left_from -= 1;
1800 to_next_drop[0] = pi0;
1801 to_next_drop += 1;
1802 n_left_to_next_drop -= 1;
1803
Eyal Baribf9f02c2018-10-31 13:19:11 +02001804 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1805 adj0 = adj_get (adj_index0);
1806
1807 if (is_glean)
1808 {
1809 /* resolve the packet's destination */
1810 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1811 resolve0 = ip0->dst_address;
1812 }
1813 else
1814 {
1815 /* resolve the incomplete adj */
1816 resolve0 = adj0->sub_type.nbr.next_hop.ip4;
1817 }
1818
1819 /* combine the address and interface for the hash key */
1820 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1821 r0 = (u64) resolve0.data_u32 << 32;
1822 r0 |= sw_if_index0;
1823
1824 if (throttle_check (&im->arp_throttle, thread_index, r0, seed))
1825 {
1826 p0->error = node->errors[IP4_ARP_ERROR_THROTTLED];
1827 continue;
1828 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829
Neale Rannsb80c5362016-10-08 13:03:40 +01001830 /*
1831 * the adj has been updated to a rewrite but the node the DPO that got
1832 * us here hasn't - yet. no big deal. we'll drop while we wait.
1833 */
1834 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
Eyal Baribf9f02c2018-10-31 13:19:11 +02001835 {
1836 p0->error = node->errors[IP4_ARP_ERROR_RESOLVED];
1837 continue;
1838 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001839
Dave Barachd7cb1b52016-12-09 09:52:16 -05001840 /*
1841 * Can happen if the control-plane is programming tables
1842 * with traffic flowing; at least that's today's lame excuse.
1843 */
Neale Ranns32e1c012016-11-22 17:07:28 +00001844 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1845 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001846 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001847 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Eyal Baribf9f02c2018-10-31 13:19:11 +02001848 continue;
1849 }
1850 /* Send ARP request. */
1851 h0 =
1852 vlib_packet_template_get_packet (vm,
1853 &im->ip4_arp_request_packet_template,
1854 &bi0);
Neale Ranns45db8852019-01-09 00:04:04 -08001855 b0 = vlib_get_buffer (vm, bi0);
1856
1857 /* copy the persistent fields from the original */
1858 clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
Eyal Baribf9f02c2018-10-31 13:19:11 +02001859
1860 /* Seems we're out of buffers */
1861 if (PREDICT_FALSE (!h0))
1862 {
1863 p0->error = node->errors[IP4_ARP_ERROR_NO_BUFFERS];
1864 continue;
1865 }
1866
1867 /* Add rewrite/encap string for ARP packet. */
1868 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
1869
1870 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1871
1872 /* Src ethernet address in ARP header. */
Neale Ranns37029302018-08-10 05:30:06 -07001873 mac_address_from_bytes (&h0->ip4_over_ethernet[0].mac,
1874 hw_if0->hw_address);
Eyal Baribf9f02c2018-10-31 13:19:11 +02001875 if (is_glean)
1876 {
1877 /* The interface's source address is stashed in the Glean Adj */
1878 h0->ip4_over_ethernet[0].ip4 =
1879 adj0->sub_type.glean.receive_addr.ip4;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001880 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001881 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001882 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001883 /* Src IP address in ARP header. */
1884 if (ip4_src_address_for_packet (lm, sw_if_index0,
1885 &h0->ip4_over_ethernet[0].ip4))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001886 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001887 /* No source address available */
1888 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1889 vlib_buffer_free (vm, &bi0, 1);
1890 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001891 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001892 }
Eyal Baribf9f02c2018-10-31 13:19:11 +02001893 h0->ip4_over_ethernet[1].ip4 = resolve0;
1894
1895 p0->error = node->errors[IP4_ARP_ERROR_REQUEST_SENT];
1896
1897 vlib_buffer_copy_trace_flag (vm, p0, bi0);
Eyal Baribf9f02c2018-10-31 13:19:11 +02001898 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
1899 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1900
1901 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1902
1903 vlib_set_next_frame_buffer (vm, node,
1904 adj0->rewrite_header.next_index, bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001905 }
1906
1907 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1908 }
1909
1910 return frame->n_vectors;
1911}
1912
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001913VLIB_NODE_FN (ip4_arp_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1914 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001915{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001916 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001917}
1918
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001919VLIB_NODE_FN (ip4_glean_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1920 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001921{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001923}
1924
Dave Barachd7cb1b52016-12-09 09:52:16 -05001925static char *ip4_arp_error_strings[] = {
Eyal Baribf9f02c2018-10-31 13:19:11 +02001926 [IP4_ARP_ERROR_THROTTLED] = "ARP requests throttled",
1927 [IP4_ARP_ERROR_RESOLVED] = "ARP requests resolved",
1928 [IP4_ARP_ERROR_NO_BUFFERS] = "ARP requests out of buffer",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001929 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1930 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001931 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001932};
1933
Neale Rannsf8686322017-11-29 02:39:53 -08001934/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001935VLIB_REGISTER_NODE (ip4_arp_node) =
1936{
Neale Rannsf8686322017-11-29 02:39:53 -08001937 .name = "ip4-arp",
1938 .vector_size = sizeof (u32),
1939 .format_trace = format_ip4_forward_next_trace,
1940 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1941 .error_strings = ip4_arp_error_strings,
1942 .n_next_nodes = IP4_ARP_N_NEXT,
1943 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001944 {
Neale Rannsf8686322017-11-29 02:39:53 -08001945 [IP4_ARP_NEXT_DROP] = "error-drop",
1946 },
1947};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948
Dave Barachd7cb1b52016-12-09 09:52:16 -05001949VLIB_REGISTER_NODE (ip4_glean_node) =
1950{
Neale Rannsf8686322017-11-29 02:39:53 -08001951 .name = "ip4-glean",
1952 .vector_size = sizeof (u32),
1953 .format_trace = format_ip4_forward_next_trace,
1954 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1955 .error_strings = ip4_arp_error_strings,
1956 .n_next_nodes = IP4_ARP_N_NEXT,
1957 .next_nodes = {
1958 [IP4_ARP_NEXT_DROP] = "error-drop",
1959 },
1960};
1961/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001962
Ed Warnickecb9cada2015-12-08 15:45:58 -07001963#define foreach_notrace_ip4_arp_error \
Eyal Baribf9f02c2018-10-31 13:19:11 +02001964_(THROTTLED) \
1965_(RESOLVED) \
1966_(NO_BUFFERS) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001967_(REQUEST_SENT) \
Eyal Baribf9f02c2018-10-31 13:19:11 +02001968_(NON_ARP_ADJ) \
1969_(NO_SOURCE_ADDRESS)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001970
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001971static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001972arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001973{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001974 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001975
1976 /* don't trace ARP request packets */
1977#define _(a) \
1978 vnet_pcap_drop_trace_filter_add_del \
1979 (rt->errors[IP4_ARP_ERROR_##a], \
1980 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001982#undef _
1983 return 0;
1984}
1985
Dave Barachd7cb1b52016-12-09 09:52:16 -05001986VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987
1988
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001989#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001990/* Send an ARP request to see if given destination is reachable on given interface. */
1991clib_error_t *
John Lo86376342018-06-11 20:14:49 -04001992ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index,
1993 u8 refresh)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001994{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001995 vnet_main_t *vnm = vnet_get_main ();
1996 ip4_main_t *im = &ip4_main;
1997 ethernet_arp_header_t *h;
1998 ip4_address_t *src;
1999 ip_interface_address_t *ia;
2000 ip_adjacency_t *adj;
2001 vnet_hw_interface_t *hi;
2002 vnet_sw_interface_t *si;
2003 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002004 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002005 u32 bi = 0;
John Lo86376342018-06-11 20:14:49 -04002006 u8 unicast_rewrite = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002007
2008 si = vnet_get_sw_interface (vnm, sw_if_index);
2009
2010 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2011 {
2012 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002013 format_ip4_address, dst,
2014 format_vnet_sw_if_index_name, vnm,
2015 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016 }
2017
Dave Barachd7cb1b52016-12-09 09:52:16 -05002018 src =
2019 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2020 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002021 {
2022 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002023 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002024 (0,
2025 "no matching interface address for destination %U (interface %U)",
2026 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2027 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028 }
2029
Neale Ranns7a272742017-05-30 02:08:14 -07002030 h = vlib_packet_template_get_packet (vm,
2031 &im->ip4_arp_request_packet_template,
2032 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002033
John Lo084606b2018-06-19 15:27:48 -04002034 if (!h)
2035 return clib_error_return (0, "ARP request packet allocation failed");
2036
Ed Warnickecb9cada2015-12-08 15:45:58 -07002037 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002038 if (PREDICT_FALSE (!hi->hw_address))
2039 {
2040 return clib_error_return (0, "%U: interface %U do not support ip probe",
2041 format_ip4_address, dst,
2042 format_vnet_sw_if_index_name, vnm,
2043 sw_if_index);
2044 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002045
Neale Ranns37029302018-08-10 05:30:06 -07002046 mac_address_from_bytes (&h->ip4_over_ethernet[0].mac, hi->hw_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002047
2048 h->ip4_over_ethernet[0].ip4 = src[0];
2049 h->ip4_over_ethernet[1].ip4 = dst[0];
2050
2051 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002052 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2053 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054
Dave Barach59b25652017-09-10 15:04:27 -04002055 ip46_address_t nh = {
2056 .ip4 = *dst,
2057 };
2058
2059 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2060 VNET_LINK_IP4, &nh, sw_if_index);
2061 adj = adj_get (ai);
2062
2063 /* Peer has been previously resolved, retrieve glean adj instead */
2064 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2065 {
John Lo86376342018-06-11 20:14:49 -04002066 if (refresh)
2067 unicast_rewrite = 1;
2068 else
2069 {
2070 adj_unlock (ai);
2071 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
2072 VNET_LINK_IP4, sw_if_index, &nh);
2073 adj = adj_get (ai);
2074 }
Dave Barach59b25652017-09-10 15:04:27 -04002075 }
2076
Ed Warnickecb9cada2015-12-08 15:45:58 -07002077 /* Add encapsulation string for software interface (e.g. ethernet header). */
2078 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
John Lo86376342018-06-11 20:14:49 -04002079 if (unicast_rewrite)
2080 {
2081 u16 *etype = vlib_buffer_get_current (b) - 2;
2082 etype[0] = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
2083 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002084 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2085
2086 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002087 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2088 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002089 to_next[0] = bi;
2090 f->n_vectors = 1;
2091 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2092 }
2093
Neale Ranns7a272742017-05-30 02:08:14 -07002094 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002095 return /* no error */ 0;
2096}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002097#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002098
Dave Barachd7cb1b52016-12-09 09:52:16 -05002099typedef enum
2100{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002101 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002102 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02002103 IP4_REWRITE_NEXT_FRAGMENT,
2104 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002105} ip4_rewrite_next_t;
2106
Neale Ranns889fe942017-06-01 05:43:19 -04002107/**
2108 * This bits of an IPv4 address to mask to construct a multicast
2109 * MAC address
2110 */
2111#if CLIB_ARCH_IS_BIG_ENDIAN
2112#define IP4_MCAST_ADDR_MASK 0x007fffff
2113#else
2114#define IP4_MCAST_ADDR_MASK 0xffff7f00
2115#endif
2116
Ole Troan8a9c8f12018-05-18 11:01:31 +02002117always_inline void
2118ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002119 u16 adj_packet_bytes, bool df, u16 * next, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002120{
2121 if (packet_len > adj_packet_bytes)
2122 {
2123 *error = IP4_ERROR_MTU_EXCEEDED;
2124 if (df)
2125 {
2126 icmp4_error_set_vnet_buffer
2127 (b, ICMP4_destination_unreachable,
2128 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2129 adj_packet_bytes);
2130 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2131 }
2132 else
2133 {
Ole Troan313f7e22018-04-10 16:02:51 +02002134 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002135 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troanb3655e52018-08-16 22:08:49 +02002136 IP4_FRAG_NEXT_IP4_REWRITE, 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002137 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002138 }
2139 }
2140}
2141
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002142/* Decrement TTL & update checksum.
2143 Works either endian, so no need for byte swap. */
2144static_always_inline void
2145ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2146 u32 * error)
2147{
2148 i32 ttl;
2149 u32 checksum;
2150 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2151 {
2152 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2153 return;
2154 }
2155
2156 ttl = ip->ttl;
2157
2158 /* Input node should have reject packets with ttl 0. */
2159 ASSERT (ip->ttl > 0);
2160
2161 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2162 checksum += checksum >= 0xffff;
2163
2164 ip->checksum = checksum;
2165 ttl -= 1;
2166 ip->ttl = ttl;
2167
2168 /*
2169 * If the ttl drops below 1 when forwarding, generate
2170 * an ICMP response.
2171 */
2172 if (PREDICT_FALSE (ttl <= 0))
2173 {
2174 *error = IP4_ERROR_TIME_EXPIRED;
2175 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2176 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2177 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2178 0);
2179 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2180 }
2181
2182 /* Verify checksum. */
2183 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2184 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2185}
2186
2187
Ed Warnickecb9cada2015-12-08 15:45:58 -07002188always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002189ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2190 vlib_node_runtime_t * node,
2191 vlib_frame_t * frame,
2192 int do_counters, int is_midchain, int is_mcast,
2193 int do_gso)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002194{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002195 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2196 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002197 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2198 u16 nexts[VLIB_FRAME_SIZE], *next;
2199 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002200 vlib_node_runtime_t *error_node =
2201 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002202
2203 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002204 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002205
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002206 vlib_get_buffers (vm, from, bufs, n_left_from);
2207 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2208
2209 if (n_left_from >= 6)
2210 {
2211 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002212 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002213 vlib_prefetch_buffer_header (bufs[i], LOAD);
2214 }
2215
2216 next = nexts;
2217 b = bufs;
2218 while (n_left_from >= 8)
2219 {
2220 ip_adjacency_t *adj0, *adj1;
2221 ip4_header_t *ip0, *ip1;
2222 u32 rw_len0, error0, adj_index0;
2223 u32 rw_len1, error1, adj_index1;
2224 u32 tx_sw_if_index0, tx_sw_if_index1;
2225 u8 *p;
2226
2227 vlib_prefetch_buffer_header (b[6], LOAD);
2228 vlib_prefetch_buffer_header (b[7], LOAD);
2229
2230 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2231 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2232
2233 /*
2234 * pre-fetch the per-adjacency counters
2235 */
2236 if (do_counters)
2237 {
2238 vlib_prefetch_combined_counter (&adjacency_counters,
2239 thread_index, adj_index0);
2240 vlib_prefetch_combined_counter (&adjacency_counters,
2241 thread_index, adj_index1);
2242 }
2243
2244 ip0 = vlib_buffer_get_current (b[0]);
2245 ip1 = vlib_buffer_get_current (b[1]);
2246
2247 error0 = error1 = IP4_ERROR_NONE;
2248
2249 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2250 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2251
2252 /* Rewrite packet header and updates lengths. */
2253 adj0 = adj_get (adj_index0);
2254 adj1 = adj_get (adj_index1);
2255
2256 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2257 rw_len0 = adj0[0].rewrite_header.data_bytes;
2258 rw_len1 = adj1[0].rewrite_header.data_bytes;
2259 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2260 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2261
2262 p = vlib_buffer_get_current (b[2]);
2263 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2264 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2265
2266 p = vlib_buffer_get_current (b[3]);
2267 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2268 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2269
2270 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002271 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2272 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2273
2274 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2275 ip0_len = gso_mtu_sz (b[0]);
2276 if (do_gso && (b[1]->flags & VNET_BUFFER_F_GSO))
2277 ip1_len = gso_mtu_sz (b[1]);
2278
2279 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002280 adj0[0].rewrite_header.max_l3_packet_bytes,
2281 ip0->flags_and_fragment_offset &
2282 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2283 next + 0, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002284 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002285 adj1[0].rewrite_header.max_l3_packet_bytes,
2286 ip1->flags_and_fragment_offset &
2287 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2288 next + 1, &error1);
2289
2290 if (is_mcast)
2291 {
2292 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2293 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2294 IP4_ERROR_SAME_INTERFACE : error0);
2295 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2296 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2297 IP4_ERROR_SAME_INTERFACE : error1);
2298 }
2299
2300 b[0]->error = error_node->errors[error0];
2301 b[1]->error = error_node->errors[error1];
2302 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2303 * to see the IP headerr */
2304 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2305 {
2306 u32 next_index = adj0[0].rewrite_header.next_index;
2307 b[0]->current_data -= rw_len0;
2308 b[0]->current_length += rw_len0;
2309 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2310 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2311
2312 if (PREDICT_FALSE
2313 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2314 vnet_feature_arc_start (lm->output_feature_arc_index,
2315 tx_sw_if_index0, &next_index, b[0]);
2316 next[0] = next_index;
2317 }
2318 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2319 {
2320 u32 next_index = adj1[0].rewrite_header.next_index;
2321 b[1]->current_data -= rw_len1;
2322 b[1]->current_length += rw_len1;
2323
2324 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2325 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2326
2327 if (PREDICT_FALSE
2328 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2329 vnet_feature_arc_start (lm->output_feature_arc_index,
2330 tx_sw_if_index1, &next_index, b[1]);
2331 next[1] = next_index;
2332 }
2333
2334 /* Guess we are only writing on simple Ethernet header. */
2335 vnet_rewrite_two_headers (adj0[0], adj1[0],
2336 ip0, ip1, sizeof (ethernet_header_t));
2337
2338 /*
2339 * Bump the per-adjacency counters
2340 */
2341 if (do_counters)
2342 {
2343 vlib_increment_combined_counter
2344 (&adjacency_counters,
2345 thread_index,
2346 adj_index0, 1, vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2347
2348 vlib_increment_combined_counter
2349 (&adjacency_counters,
2350 thread_index,
2351 adj_index1, 1, vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2352 }
2353
2354 if (is_midchain)
2355 {
2356 adj0->sub_type.midchain.fixup_func
2357 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2358 adj1->sub_type.midchain.fixup_func
Zhiyong Yangb2ecc5d2018-12-13 14:09:40 +08002359 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002360 }
2361
2362 if (is_mcast)
2363 {
2364 /*
2365 * copy bytes from the IP address into the MAC rewrite
2366 */
2367 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2368 adj0->rewrite_header.dst_mcast_offset,
2369 &ip0->dst_address.as_u32, (u8 *) ip0);
2370 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
Zhiyong Yangb2ecc5d2018-12-13 14:09:40 +08002371 adj1->rewrite_header.dst_mcast_offset,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002372 &ip1->dst_address.as_u32, (u8 *) ip1);
2373 }
2374
2375 next += 2;
2376 b += 2;
2377 n_left_from -= 2;
2378 }
2379
Ed Warnickecb9cada2015-12-08 15:45:58 -07002380 while (n_left_from > 0)
2381 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002382 ip_adjacency_t *adj0;
2383 ip4_header_t *ip0;
2384 u32 rw_len0, adj_index0, error0;
2385 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002386
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002387 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2388
2389 adj0 = adj_get (adj_index0);
2390
2391 if (do_counters)
2392 vlib_prefetch_combined_counter (&adjacency_counters,
2393 thread_index, adj_index0);
2394
2395 ip0 = vlib_buffer_get_current (b[0]);
2396
2397 error0 = IP4_ERROR_NONE;
2398
2399 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2400
2401
2402 /* Update packet buffer attributes/set output interface. */
2403 rw_len0 = adj0[0].rewrite_header.data_bytes;
2404 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2405
2406 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002407 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2408 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2409 ip0_len = gso_mtu_sz (b[0]);
2410
2411 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002412 adj0[0].rewrite_header.max_l3_packet_bytes,
2413 ip0->flags_and_fragment_offset &
2414 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2415 next + 0, &error0);
2416
2417 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002418 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002419 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2420 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2421 IP4_ERROR_SAME_INTERFACE : error0);
2422 }
2423 b[0]->error = error_node->errors[error0];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002424
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002425 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2426 * to see the IP headerr */
2427 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2428 {
2429 u32 next_index = adj0[0].rewrite_header.next_index;
2430 b[0]->current_data -= rw_len0;
2431 b[0]->current_length += rw_len0;
2432 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2433 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002434
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002435 if (PREDICT_FALSE
2436 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2437 vnet_feature_arc_start (lm->output_feature_arc_index,
2438 tx_sw_if_index0, &next_index, b[0]);
2439 next[0] = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002440 }
2441
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002442 /* Guess we are only writing on simple Ethernet header. */
2443 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2444
2445 if (do_counters)
2446 vlib_increment_combined_counter
2447 (&adjacency_counters,
2448 thread_index, adj_index0, 1,
2449 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2450
2451 if (is_midchain)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002452 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002453 adj0->sub_type.midchain.fixup_func
2454 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002455 }
Dave Barach75fc8542016-10-11 16:16:02 -04002456
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002457 if (is_mcast)
2458 {
2459 /*
2460 * copy bytes from the IP address into the MAC rewrite
2461 */
2462 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2463 adj0->rewrite_header.dst_mcast_offset,
2464 &ip0->dst_address.as_u32, (u8 *) ip0);
2465 }
2466
2467 next += 1;
2468 b += 1;
2469 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002470 }
2471
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002472
Ed Warnickecb9cada2015-12-08 15:45:58 -07002473 /* Need to do trace after rewrites to pick up new packet data. */
2474 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002475 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002477 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002478 return frame->n_vectors;
2479}
2480
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002481always_inline uword
2482ip4_rewrite_inline (vlib_main_t * vm,
2483 vlib_node_runtime_t * node,
2484 vlib_frame_t * frame,
2485 int do_counters, int is_midchain, int is_mcast)
2486{
2487 vnet_main_t *vnm = vnet_get_main ();
2488 if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
2489 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2490 is_midchain, is_mcast,
2491 1 /* do_gso */ );
2492 else
2493 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2494 is_midchain, is_mcast,
2495 0 /* no do_gso */ );
2496}
2497
Dave Barach132d51d2016-07-07 10:10:17 -04002498
Neale Rannsf06aea52016-11-29 06:51:37 -08002499/** @brief IPv4 rewrite node.
2500 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002501
2502 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2503 header checksum, fetch the ip adjacency, check the outbound mtu,
2504 apply the adjacency rewrite, and send pkts to the adjacency
2505 rewrite header's rewrite_next_index.
2506
2507 @param vm vlib_main_t corresponding to the current thread
2508 @param node vlib_node_runtime_t
2509 @param frame vlib_frame_t whose contents should be dispatched
2510
2511 @par Graph mechanics: buffer metadata, next index usage
2512
2513 @em Uses:
2514 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2515 - the rewrite adjacency index
2516 - <code>adj->lookup_next_index</code>
2517 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002518 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002519 - <code>adj->rewrite_header</code>
2520 - Rewrite string length, rewrite string, next_index
2521
2522 @em Sets:
2523 - <code>b->current_data, b->current_length</code>
2524 - Updated net of applying the rewrite string
2525
2526 <em>Next Indices:</em>
2527 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002528 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002529*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002530
2531VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2532 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002533{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002534 if (adj_are_counters_enabled ())
2535 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2536 else
2537 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002538}
2539
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002540VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2541 vlib_node_runtime_t * node,
2542 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002543{
2544 if (adj_are_counters_enabled ())
2545 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2546 else
2547 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2548}
2549
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002550VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2551 vlib_node_runtime_t * node,
2552 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002553{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002554 if (adj_are_counters_enabled ())
2555 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2556 else
2557 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002558}
2559
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002560VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2561 vlib_node_runtime_t * node,
2562 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002563{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002564 if (adj_are_counters_enabled ())
2565 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2566 else
2567 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002568}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002569
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002570VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2571 vlib_node_runtime_t * node,
2572 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002573{
2574 if (adj_are_counters_enabled ())
2575 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2576 else
2577 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2578}
2579
Neale Ranns32e1c012016-11-22 17:07:28 +00002580/* *INDENT-OFF* */
2581VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002582 .name = "ip4-rewrite",
2583 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002584
Neale Ranns32e1c012016-11-22 17:07:28 +00002585 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002586
Ole Troan313f7e22018-04-10 16:02:51 +02002587 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002588 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002589 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002590 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002591 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002592 },
2593};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002594
2595VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002596 .name = "ip4-rewrite-bcast",
2597 .vector_size = sizeof (u32),
2598
2599 .format_trace = format_ip4_rewrite_trace,
2600 .sibling_of = "ip4-rewrite",
2601};
Neale Ranns32e1c012016-11-22 17:07:28 +00002602
2603VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002604 .name = "ip4-rewrite-mcast",
2605 .vector_size = sizeof (u32),
2606
2607 .format_trace = format_ip4_rewrite_trace,
2608 .sibling_of = "ip4-rewrite",
2609};
Neale Ranns32e1c012016-11-22 17:07:28 +00002610
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002611VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002612 .name = "ip4-mcast-midchain",
2613 .vector_size = sizeof (u32),
2614
2615 .format_trace = format_ip4_rewrite_trace,
2616 .sibling_of = "ip4-rewrite",
2617};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002618
Neale Ranns32e1c012016-11-22 17:07:28 +00002619VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002620 .name = "ip4-midchain",
2621 .vector_size = sizeof (u32),
2622 .format_trace = format_ip4_forward_next_trace,
2623 .sibling_of = "ip4-rewrite",
2624};
Neale Ranns32e1c012016-11-22 17:07:28 +00002625/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002626
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002627static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002628ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2629{
2630 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002631 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002632 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002633
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002634 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002635
Neale Ranns04a75e32017-03-23 06:46:01 -07002636 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002637 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2638 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002639
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002640 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002641
Dave Barachd7cb1b52016-12-09 09:52:16 -05002642 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002643}
Dave Barach75fc8542016-10-11 16:16:02 -04002644
Ed Warnickecb9cada2015-12-08 15:45:58 -07002645static clib_error_t *
2646test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002647 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002648{
Billy McFall309fe062016-10-14 07:37:33 -04002649 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002650 u32 table_id = 0;
2651 f64 count = 1;
2652 u32 n;
2653 int i;
2654 ip4_address_t ip4_base_address;
2655 u64 errors = 0;
2656
Dave Barachd7cb1b52016-12-09 09:52:16 -05002657 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2658 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002659 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002660 {
2661 /* Make sure the entry exists. */
2662 fib = ip4_fib_get (table_id);
2663 if ((fib) && (fib->index != table_id))
2664 return clib_error_return (0, "<fib-index> %d does not exist",
2665 table_id);
2666 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002667 else if (unformat (input, "count %f", &count))
2668 ;
2669
2670 else if (unformat (input, "%U",
2671 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002672 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002673 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002674 return clib_error_return (0, "unknown input `%U'",
2675 format_unformat_error, input);
2676 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677
2678 n = count;
2679
2680 for (i = 0; i < n; i++)
2681 {
2682 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002683 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002684
Dave Barach75fc8542016-10-11 16:16:02 -04002685 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002686 clib_host_to_net_u32 (1 +
2687 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002688 }
2689
Dave Barach75fc8542016-10-11 16:16:02 -04002690 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002691 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2692 else
2693 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2694
2695 return 0;
2696}
2697
Billy McFall0683c9c2016-10-13 08:27:31 -04002698/*?
2699 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2700 * given FIB table to determine if there is a conflict with the
2701 * adjacency table. The fib-id can be determined by using the
2702 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2703 * of 0 is used.
2704 *
2705 * @todo This command uses fib-id, other commands use table-id (not
2706 * just a name, they are different indexes). Would like to change this
2707 * to table-id for consistency.
2708 *
2709 * @cliexpar
2710 * Example of how to run the test lookup command:
2711 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2712 * No errors in 2 lookups
2713 * @cliexend
2714?*/
2715/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002716VLIB_CLI_COMMAND (lookup_test_command, static) =
2717{
2718 .path = "test lookup",
2719 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2720 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002721};
Billy McFall0683c9c2016-10-13 08:27:31 -04002722/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002724#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002725int
2726vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002727{
Neale Ranns107e7d42017-04-11 09:55:19 -07002728 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002729
Neale Ranns107e7d42017-04-11 09:55:19 -07002730 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2731
2732 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002733 return VNET_API_ERROR_NO_SUCH_FIB;
2734
Neale Ranns227038a2017-04-21 01:07:59 -07002735 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2736 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737
Ed Warnickecb9cada2015-12-08 15:45:58 -07002738 return 0;
2739}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002740#endif
Dave Barach75fc8542016-10-11 16:16:02 -04002741
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742static clib_error_t *
2743set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002744 unformat_input_t * input,
2745 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002746{
2747 int matched = 0;
2748 u32 table_id = 0;
2749 u32 flow_hash_config = 0;
2750 int rv;
2751
Dave Barachd7cb1b52016-12-09 09:52:16 -05002752 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2753 {
2754 if (unformat (input, "table %d", &table_id))
2755 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002756#define _(a,v) \
2757 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002758 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002759#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002760 else
2761 break;
2762 }
Dave Barach75fc8542016-10-11 16:16:02 -04002763
Ed Warnickecb9cada2015-12-08 15:45:58 -07002764 if (matched == 0)
2765 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002766 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002767
Ed Warnickecb9cada2015-12-08 15:45:58 -07002768 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2769 switch (rv)
2770 {
2771 case 0:
2772 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002773
Ed Warnickecb9cada2015-12-08 15:45:58 -07002774 case VNET_API_ERROR_NO_SUCH_FIB:
2775 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002776
Ed Warnickecb9cada2015-12-08 15:45:58 -07002777 default:
2778 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2779 break;
2780 }
Dave Barach75fc8542016-10-11 16:16:02 -04002781
Ed Warnickecb9cada2015-12-08 15:45:58 -07002782 return 0;
2783}
Dave Barach75fc8542016-10-11 16:16:02 -04002784
Billy McFall0683c9c2016-10-13 08:27:31 -04002785/*?
2786 * Configure the set of IPv4 fields used by the flow hash.
2787 *
2788 * @cliexpar
2789 * Example of how to set the flow hash on a given table:
2790 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2791 * Example of display the configured flow hash:
2792 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002793 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2794 * 0.0.0.0/0
2795 * unicast-ip4-chain
2796 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2797 * [0] [@0]: dpo-drop ip6
2798 * 0.0.0.0/32
2799 * unicast-ip4-chain
2800 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2801 * [0] [@0]: dpo-drop ip6
2802 * 224.0.0.0/8
2803 * unicast-ip4-chain
2804 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2805 * [0] [@0]: dpo-drop ip6
2806 * 6.0.1.2/32
2807 * unicast-ip4-chain
2808 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2809 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2810 * 7.0.0.1/32
2811 * unicast-ip4-chain
2812 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2813 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2814 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2815 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2816 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2817 * 240.0.0.0/8
2818 * unicast-ip4-chain
2819 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2820 * [0] [@0]: dpo-drop ip6
2821 * 255.255.255.255/32
2822 * unicast-ip4-chain
2823 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2824 * [0] [@0]: dpo-drop ip6
2825 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2826 * 0.0.0.0/0
2827 * unicast-ip4-chain
2828 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2829 * [0] [@0]: dpo-drop ip6
2830 * 0.0.0.0/32
2831 * unicast-ip4-chain
2832 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2833 * [0] [@0]: dpo-drop ip6
2834 * 172.16.1.0/24
2835 * unicast-ip4-chain
2836 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2837 * [0] [@4]: ipv4-glean: af_packet0
2838 * 172.16.1.1/32
2839 * unicast-ip4-chain
2840 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2841 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2842 * 172.16.1.2/32
2843 * unicast-ip4-chain
2844 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2845 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2846 * 172.16.2.0/24
2847 * unicast-ip4-chain
2848 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2849 * [0] [@4]: ipv4-glean: af_packet1
2850 * 172.16.2.1/32
2851 * unicast-ip4-chain
2852 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2853 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2854 * 224.0.0.0/8
2855 * unicast-ip4-chain
2856 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2857 * [0] [@0]: dpo-drop ip6
2858 * 240.0.0.0/8
2859 * unicast-ip4-chain
2860 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2861 * [0] [@0]: dpo-drop ip6
2862 * 255.255.255.255/32
2863 * unicast-ip4-chain
2864 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2865 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002866 * @cliexend
2867?*/
2868/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002869VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2870{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002871 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002872 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002873 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002874 .function = set_ip_flow_hash_command_fn,
2875};
Billy McFall0683c9c2016-10-13 08:27:31 -04002876/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002877
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002878#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002879int
2880vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2881 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002882{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002883 vnet_main_t *vnm = vnet_get_main ();
2884 vnet_interface_main_t *im = &vnm->interface_main;
2885 ip4_main_t *ipm = &ip4_main;
2886 ip_lookup_main_t *lm = &ipm->lookup_main;
2887 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002888 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889
2890 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2891 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2892
2893 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2894 return VNET_API_ERROR_NO_SUCH_ENTRY;
2895
2896 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002897 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002898
Neale Rannsdf089a82016-10-02 16:39:06 +01002899 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2900
2901 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002902 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002903 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002904 .fp_len = 32,
2905 .fp_proto = FIB_PROTOCOL_IP4,
2906 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002907 };
2908 u32 fib_index;
2909
Dave Barachd7cb1b52016-12-09 09:52:16 -05002910 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2911 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002912
2913
Dave Barachd7cb1b52016-12-09 09:52:16 -05002914 if (table_index != (u32) ~ 0)
2915 {
2916 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002917
Dave Barachd7cb1b52016-12-09 09:52:16 -05002918 dpo_set (&dpo,
2919 DPO_CLASSIFY,
2920 DPO_PROTO_IP4,
2921 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002922
Dave Barachd7cb1b52016-12-09 09:52:16 -05002923 fib_table_entry_special_dpo_add (fib_index,
2924 &pfx,
2925 FIB_SOURCE_CLASSIFY,
2926 FIB_ENTRY_FLAG_NONE, &dpo);
2927 dpo_reset (&dpo);
2928 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002929 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002930 {
2931 fib_table_entry_special_remove (fib_index,
2932 &pfx, FIB_SOURCE_CLASSIFY);
2933 }
2934 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002935
Ed Warnickecb9cada2015-12-08 15:45:58 -07002936 return 0;
2937}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002938#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002939
2940static clib_error_t *
2941set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002942 unformat_input_t * input,
2943 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002944{
2945 u32 table_index = ~0;
2946 int table_index_set = 0;
2947 u32 sw_if_index = ~0;
2948 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002949
Dave Barachd7cb1b52016-12-09 09:52:16 -05002950 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2951 {
2952 if (unformat (input, "table-index %d", &table_index))
2953 table_index_set = 1;
2954 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2955 vnet_get_main (), &sw_if_index))
2956 ;
2957 else
2958 break;
2959 }
Dave Barach75fc8542016-10-11 16:16:02 -04002960
Ed Warnickecb9cada2015-12-08 15:45:58 -07002961 if (table_index_set == 0)
2962 return clib_error_return (0, "classify table-index must be specified");
2963
2964 if (sw_if_index == ~0)
2965 return clib_error_return (0, "interface / subif must be specified");
2966
2967 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2968
2969 switch (rv)
2970 {
2971 case 0:
2972 break;
2973
2974 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2975 return clib_error_return (0, "No such interface");
2976
2977 case VNET_API_ERROR_NO_SUCH_ENTRY:
2978 return clib_error_return (0, "No such classifier table");
2979 }
2980 return 0;
2981}
2982
Billy McFall0683c9c2016-10-13 08:27:31 -04002983/*?
2984 * Assign a classification table to an interface. The classification
2985 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2986 * commands. Once the table is create, use this command to filter packets
2987 * on an interface.
2988 *
2989 * @cliexpar
2990 * Example of how to assign a classification table to an interface:
2991 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2992?*/
2993/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002994VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2995{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002996 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002997 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002998 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002999 .function = set_ip_classify_command_fn,
3000};
Billy McFall0683c9c2016-10-13 08:27:31 -04003001/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003002
Neale Ranns1ec36522017-11-29 05:20:37 -08003003static clib_error_t *
3004ip4_config (vlib_main_t * vm, unformat_input_t * input)
3005{
3006 ip4_main_t *im = &ip4_main;
3007 uword heapsize = 0;
3008
3009 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3010 {
3011 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3012 ;
3013 else
3014 return clib_error_return (0,
3015 "invalid heap-size parameter `%U'",
3016 format_unformat_error, input);
3017 }
3018
3019 im->mtrie_heap_size = heapsize;
3020
3021 return 0;
3022}
3023
3024VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3025
Dave Barachd7cb1b52016-12-09 09:52:16 -05003026/*
3027 * fd.io coding-style-patch-verification: ON
3028 *
3029 * Local Variables:
3030 * eval: (c-set-style "gnu")
3031 * End:
3032 */