blob: 7c56a294436fe68f031dda65e28bc0d888e836fb [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>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010042#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
43#include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#include <vnet/ppp/ppp.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010045#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
Dave Barachd7cb1b52016-12-09 09:52:16 -050046#include <vnet/api_errno.h> /* for API error numbers */
47#include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
48#include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
49#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050#include <vnet/fib/ip4_fib.h>
51#include <vnet/dpo/load_balance.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070052#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010053#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000054#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Ed Warnickecb9cada2015-12-08 15:45:58 -070055
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080056#include <vnet/ip/ip4_forward.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070057
Chris Luke8e5b0412016-07-26 13:06:10 -040058/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040059 @node ip4-lookup
60
61 This is the main IPv4 lookup dispatch node.
62
63 @param vm vlib_main_t corresponding to the current thread
64 @param node vlib_node_runtime_t
65 @param frame vlib_frame_t whose contents should be dispatched
66
67 @par Graph mechanics: buffer metadata, next index usage
68
69 @em Uses:
70 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
71 - Indicates the @c sw_if_index value of the interface that the
72 packet was received on.
73 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
74 - When the value is @c ~0 then the node performs a longest prefix
75 match (LPM) for the packet destination address in the FIB attached
76 to the receive interface.
77 - Otherwise perform LPM for the packet destination address in the
78 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
79 value (0, 1, ...) and not a VRF id.
80
81 @em Sets:
82 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
83 - The lookup result adjacency index.
84
85 <em>Next Index:</em>
86 - Dispatches the packet to the node index found in
87 ip_adjacency_t @c adj->lookup_next_index
88 (where @c adj is the lookup result adjacency).
89*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070090static uword
91ip4_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050092 vlib_node_runtime_t * node, 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 .function = ip4_lookup,
106 .name = "ip4-lookup",
107 .vector_size = sizeof (u32),
108 .format_trace = format_ip4_lookup_trace,
109 .n_next_nodes = IP_LOOKUP_N_NEXT,
110 .next_nodes = IP4_LOOKUP_NEXT_NODES,
111};
112/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100113
Dave Barachd7cb1b52016-12-09 09:52:16 -0500114VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100115
116always_inline uword
117ip4_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500118 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500120 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
121 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100122 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200123 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100125 from = vlib_frame_vector_args (frame);
126 n_left_from = frame->n_vectors;
127 next = node->cached_next_index;
128
129 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500130 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100131
132 while (n_left_from > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500134 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100135
Dave Barach75fc8542016-10-11 16:16:02 -0400136
Neale Ranns2be95c12016-11-19 13:50:04 +0000137 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500138 {
139 ip_lookup_next_t next0, next1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000140 const load_balance_t *lb0, *lb1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500141 vlib_buffer_t *p0, *p1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000142 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
143 const ip4_header_t *ip0, *ip1;
144 const dpo_id_t *dpo0, *dpo1;
145
Dave Barachd7cb1b52016-12-09 09:52:16 -0500146 /* Prefetch next iteration. */
147 {
148 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000149
150 p2 = vlib_get_buffer (vm, from[2]);
151 p3 = vlib_get_buffer (vm, from[3]);
152
153 vlib_prefetch_buffer_header (p2, STORE);
154 vlib_prefetch_buffer_header (p3, STORE);
155
156 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
157 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500158 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000159
160 pi0 = to_next[0] = from[0];
161 pi1 = to_next[1] = from[1];
162
163 from += 2;
164 n_left_from -= 2;
165 to_next += 2;
166 n_left_to_next -= 2;
167
168 p0 = vlib_get_buffer (vm, pi0);
169 p1 = vlib_get_buffer (vm, pi1);
170
171 ip0 = vlib_buffer_get_current (p0);
172 ip1 = vlib_buffer_get_current (p1);
173 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
174 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
175
Dave Barachd7cb1b52016-12-09 09:52:16 -0500176 lb0 = load_balance_get (lbi0);
177 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000178
Dave Barachd7cb1b52016-12-09 09:52:16 -0500179 /*
180 * this node is for via FIBs we can re-use the hash value from the
181 * to node if present.
182 * We don't want to use the same hash value at each level in the recursion
183 * graph as that would lead to polarisation
184 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000185 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000186
Dave Barachd7cb1b52016-12-09 09:52:16 -0500187 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
188 {
189 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
190 {
191 hc0 = vnet_buffer (p0)->ip.flow_hash =
192 vnet_buffer (p0)->ip.flow_hash >> 1;
193 }
194 else
195 {
196 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000197 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500198 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700199 dpo0 = load_balance_get_fwd_bucket
200 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
201 }
202 else
203 {
204 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500205 }
206 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
207 {
208 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
209 {
210 hc1 = vnet_buffer (p1)->ip.flow_hash =
211 vnet_buffer (p1)->ip.flow_hash >> 1;
212 }
213 else
214 {
215 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000216 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500217 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700218 dpo1 = load_balance_get_fwd_bucket
219 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500220 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700221 else
222 {
223 dpo1 = load_balance_get_bucket_i (lb1, 0);
224 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000225
226 next0 = dpo0->dpoi_next_node;
227 next1 = dpo1->dpoi_next_node;
228
229 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
230 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
231
232 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200233 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns2be95c12016-11-19 13:50:04 +0000234 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200235 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000236
237 vlib_validate_buffer_enqueue_x2 (vm, node, next,
238 to_next, n_left_to_next,
239 pi0, pi1, next0, next1);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500240 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000241
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100242 while (n_left_from > 0 && n_left_to_next > 0)
243 {
244 ip_lookup_next_t next0;
245 const load_balance_t *lb0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500246 vlib_buffer_t *p0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100247 u32 pi0, lbi0, hc0;
248 const ip4_header_t *ip0;
249 const dpo_id_t *dpo0;
250
251 pi0 = from[0];
252 to_next[0] = pi0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000253 from += 1;
254 to_next += 1;
255 n_left_to_next -= 1;
256 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100257
258 p0 = vlib_get_buffer (vm, pi0);
259
260 ip0 = vlib_buffer_get_current (p0);
261 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
262
Dave Barachd7cb1b52016-12-09 09:52:16 -0500263 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100264
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000265 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500266 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
267 {
268 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
269 {
270 hc0 = vnet_buffer (p0)->ip.flow_hash =
271 vnet_buffer (p0)->ip.flow_hash >> 1;
272 }
273 else
274 {
275 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000276 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500277 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700278 dpo0 = load_balance_get_fwd_bucket
279 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500280 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700281 else
282 {
283 dpo0 = load_balance_get_bucket_i (lb0, 0);
284 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100285
286 next0 = dpo0->dpoi_next_node;
287 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
288
Dave Barach75fc8542016-10-11 16:16:02 -0400289 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200290 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100291
Neale Ranns2be95c12016-11-19 13:50:04 +0000292 vlib_validate_buffer_enqueue_x1 (vm, node, next,
293 to_next, n_left_to_next,
294 pi0, next0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100295 }
296
297 vlib_put_next_frame (vm, node, next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298 }
299
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100300 return frame->n_vectors;
301}
302
Neale Rannsf8686322017-11-29 02:39:53 -0800303/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500304VLIB_REGISTER_NODE (ip4_load_balance_node) =
305{
Neale Rannsf8686322017-11-29 02:39:53 -0800306 .function = ip4_load_balance,
307 .name = "ip4-load-balance",
308 .vector_size = sizeof (u32),
309 .sibling_of = "ip4-lookup",
310 .format_trace =
311 format_ip4_lookup_trace,
312};
313/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100314
Dave Barachd7cb1b52016-12-09 09:52:16 -0500315VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100316
317/* get first interface address */
318ip4_address_t *
319ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500320 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100321{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500322 ip_lookup_main_t *lm = &im->lookup_main;
323 ip_interface_address_t *ia = 0;
324 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100325
Neale Ranns32e1c012016-11-22 17:07:28 +0000326 /* *INDENT-OFF* */
327 foreach_ip_interface_address
328 (lm, ia, sw_if_index,
329 1 /* honor unnumbered */ ,
330 ({
331 ip4_address_t * a =
332 ip_interface_address_get_address (lm, ia);
333 result = a;
334 break;
335 }));
336 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100337 if (result_ia)
338 *result_ia = result ? ia : 0;
339 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340}
341
342static void
343ip4_add_interface_routes (u32 sw_if_index,
344 ip4_main_t * im, u32 fib_index,
345 ip_interface_address_t * a)
346{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500347 ip_lookup_main_t *lm = &im->lookup_main;
348 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100349 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500350 .fp_len = a->address_length,
351 .fp_proto = FIB_PROTOCOL_IP4,
352 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100353 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354
Neale Ranns9a69a602017-03-26 10:56:33 -0700355 if (pfx.fp_len <= 30)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500356 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700357 /* a /30 or shorter - add a glean for the network address */
Neale Ranns7a272742017-05-30 02:08:14 -0700358 fib_table_entry_update_one_path (fib_index, &pfx,
359 FIB_SOURCE_INTERFACE,
360 (FIB_ENTRY_FLAG_CONNECTED |
361 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700362 DPO_PROTO_IP4,
Neale Ranns7a272742017-05-30 02:08:14 -0700363 /* No next-hop address */
364 NULL,
365 sw_if_index,
366 // invalid FIB index
367 ~0,
368 1,
369 // no out-label stack
370 NULL,
371 FIB_ROUTE_PATH_FLAG_NONE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100372
Neale Ranns9a69a602017-03-26 10:56:33 -0700373 /* Add the two broadcast addresses as drop */
374 fib_prefix_t net_pfx = {
375 .fp_len = 32,
376 .fp_proto = FIB_PROTOCOL_IP4,
377 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
378 };
379 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
380 fib_table_entry_special_add(fib_index,
381 &net_pfx,
382 FIB_SOURCE_INTERFACE,
383 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700384 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700385 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
386 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
387 fib_table_entry_special_add(fib_index,
388 &net_pfx,
389 FIB_SOURCE_INTERFACE,
390 (FIB_ENTRY_FLAG_DROP |
Neale Rannsa0558302017-04-13 00:44:52 -0700391 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
Neale Ranns9a69a602017-03-26 10:56:33 -0700392 }
393 else if (pfx.fp_len == 31)
394 {
395 u32 mask = clib_host_to_net_u32(1);
396 fib_prefix_t net_pfx = pfx;
397
398 net_pfx.fp_len = 32;
399 net_pfx.fp_addr.ip4.as_u32 ^= mask;
400
401 /* a /31 - add the other end as an attached host */
402 fib_table_entry_update_one_path (fib_index, &net_pfx,
403 FIB_SOURCE_INTERFACE,
404 (FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700405 DPO_PROTO_IP4,
Neale Ranns9a69a602017-03-26 10:56:33 -0700406 &net_pfx.fp_addr,
407 sw_if_index,
408 // invalid FIB index
409 ~0,
410 1,
411 NULL,
412 FIB_ROUTE_PATH_FLAG_NONE);
413 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100414 pfx.fp_len = 32;
415
416 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500417 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100418 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500419 lm->classify_table_index_by_sw_if_index[sw_if_index];
420 if (classify_table_index != (u32) ~ 0)
421 {
422 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100423
Dave Barachd7cb1b52016-12-09 09:52:16 -0500424 dpo_set (&dpo,
425 DPO_CLASSIFY,
426 DPO_PROTO_IP4,
427 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100428
Dave Barachd7cb1b52016-12-09 09:52:16 -0500429 fib_table_entry_special_dpo_add (fib_index,
430 &pfx,
431 FIB_SOURCE_CLASSIFY,
432 FIB_ENTRY_FLAG_NONE, &dpo);
433 dpo_reset (&dpo);
434 }
435 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100436
Neale Ranns32e1c012016-11-22 17:07:28 +0000437 fib_table_entry_update_one_path (fib_index, &pfx,
438 FIB_SOURCE_INTERFACE,
439 (FIB_ENTRY_FLAG_CONNECTED |
440 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700441 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000442 &pfx.fp_addr,
443 sw_if_index,
444 // invalid FIB index
445 ~0,
446 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500447 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448}
449
450static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100451ip4_del_interface_routes (ip4_main_t * im,
452 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500453 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700454{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500455 fib_prefix_t pfx = {
456 .fp_len = address_length,
457 .fp_proto = FIB_PROTOCOL_IP4,
458 .fp_addr.ip4 = *address,
459 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460
Neale Ranns9a69a602017-03-26 10:56:33 -0700461 if (pfx.fp_len <= 30)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100462 {
Neale Ranns9a69a602017-03-26 10:56:33 -0700463 fib_prefix_t net_pfx = {
464 .fp_len = 32,
465 .fp_proto = FIB_PROTOCOL_IP4,
466 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
467 };
468 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
469 fib_table_entry_special_remove(fib_index,
470 &net_pfx,
471 FIB_SOURCE_INTERFACE);
472 net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
473 if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
474 fib_table_entry_special_remove(fib_index,
475 &net_pfx,
476 FIB_SOURCE_INTERFACE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100478 }
Neale Ranns9a69a602017-03-26 10:56:33 -0700479 else if (pfx.fp_len == 31)
480 {
481 u32 mask = clib_host_to_net_u32(1);
482 fib_prefix_t net_pfx = pfx;
483
484 net_pfx.fp_len = 32;
485 net_pfx.fp_addr.ip4.as_u32 ^= mask;
486
487 fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
488 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489
Dave Barachd7cb1b52016-12-09 09:52:16 -0500490 pfx.fp_len = 32;
491 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492}
493
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100494void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500495ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100496{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500497 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100499 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
500
501 /*
502 * enable/disable only on the 1<->0 transition
503 */
504 if (is_enable)
505 {
506 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500507 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100508 }
509 else
510 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500511 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100512 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500513 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100514 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800515 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800516 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100517
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100518
Neale Ranns8269d3d2018-01-30 09:02:20 -0800519 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400520 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100521}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523static clib_error_t *
524ip4_add_del_interface_address_internal (vlib_main_t * vm,
525 u32 sw_if_index,
526 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500527 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500529 vnet_main_t *vnm = vnet_get_main ();
530 ip4_main_t *im = &ip4_main;
531 ip_lookup_main_t *lm = &im->lookup_main;
532 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535
Pavel Kotucek57808982017-08-02 08:20:19 +0200536 /* local0 interface doesn't support IP addressing */
537 if (sw_if_index == 0)
538 {
539 return
540 clib_error_create ("local0 interface doesn't support IP addressing");
541 }
542
Ed Warnickecb9cada2015-12-08 15:45:58 -0700543 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
544 ip4_addr_fib_init (&ip4_af, address,
545 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
546 vec_add1 (addr_fib, ip4_af);
547
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100548 /* FIXME-LATER
549 * there is no support for adj-fib handling in the presence of overlapping
550 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
551 * most routers do.
552 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000553 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500554 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100556 /* When adding an address check that it does not conflict
Dave Barachd7cb1b52016-12-09 09:52:16 -0500557 with an existing address. */
558 ip_interface_address_t *ia;
Neale Ranns32e1c012016-11-22 17:07:28 +0000559 foreach_ip_interface_address
560 (&im->lookup_main, ia, sw_if_index,
561 0 /* honor unnumbered */ ,
562 ({
563 ip4_address_t * x =
564 ip_interface_address_get_address
565 (&im->lookup_main, ia);
566 if (ip4_destination_matches_route
567 (im, address, x, ia->address_length) ||
568 ip4_destination_matches_route (im,
569 x,
570 address,
571 address_length))
572 return
573 clib_error_create
574 ("failed to add %U which conflicts with %U for interface %U",
575 format_ip4_address_and_length, address,
576 address_length,
577 format_ip4_address_and_length, x,
578 ia->address_length,
579 format_vnet_sw_if_index_name, vnm,
580 sw_if_index);
581 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000583 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700584
Ed Warnickecb9cada2015-12-08 15:45:58 -0700585 elts_before = pool_elts (lm->if_address_pool);
586
587 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700589 if (error)
590 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400591
Dave Barachd7cb1b52016-12-09 09:52:16 -0500592 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100593
594 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500595 ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100596 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500597 ip4_add_interface_routes (sw_if_index,
598 im, ip4_af.fib_index,
599 pool_elt_at_index
600 (lm->if_address_pool, if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700601
602 /* If pool did not grow/shrink: add duplicate address. */
603 if (elts_before != pool_elts (lm->if_address_pool))
604 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500605 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700606 vec_foreach (cb, im->add_del_interface_address_callbacks)
607 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500608 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609 }
610
Dave Barachd7cb1b52016-12-09 09:52:16 -0500611done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700612 vec_free (addr_fib);
613 return error;
614}
615
616clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000617ip4_add_del_interface_address (vlib_main_t * vm,
618 u32 sw_if_index,
619 ip4_address_t * address,
620 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700621{
622 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500623 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700624}
625
Dave Barachd6534602016-06-14 18:38:02 -0400626/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500627/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100628VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
629{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500630 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100631 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
632 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
633};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100634
Dave Barachd7cb1b52016-12-09 09:52:16 -0500635VNET_FEATURE_INIT (ip4_flow_classify, static) =
636{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100637 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700638 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100639 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700640};
641
Dave Barachd7cb1b52016-12-09 09:52:16 -0500642VNET_FEATURE_INIT (ip4_inacl, static) =
643{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100644 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400645 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100646 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400647};
648
Dave Barachd7cb1b52016-12-09 09:52:16 -0500649VNET_FEATURE_INIT (ip4_source_check_1, static) =
650{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100651 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400652 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100653 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400654};
655
Dave Barachd7cb1b52016-12-09 09:52:16 -0500656VNET_FEATURE_INIT (ip4_source_check_2, static) =
657{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100658 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400659 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100660 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400661};
662
Dave Barachd7cb1b52016-12-09 09:52:16 -0500663VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
664{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100665 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400666 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100667 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400668};
669
Dave Barachd7cb1b52016-12-09 09:52:16 -0500670VNET_FEATURE_INIT (ip4_policer_classify, static) =
671{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100672 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700673 .node_name = "ip4-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100674 .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700675};
676
Dave Barachd7cb1b52016-12-09 09:52:16 -0500677VNET_FEATURE_INIT (ip4_ipsec, static) =
678{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100679 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400680 .node_name = "ipsec-input-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100681 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400682};
683
Dave Barachd7cb1b52016-12-09 09:52:16 -0500684VNET_FEATURE_INIT (ip4_vpath, static) =
685{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100686 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400687 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500688 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
689};
690
Dave Barachd7cb1b52016-12-09 09:52:16 -0500691VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
692{
John Lo37682e12016-11-30 12:51:39 -0500693 .arc_name = "ip4-unicast",
694 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100695 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400696};
697
Neale Ranns8269d3d2018-01-30 09:02:20 -0800698VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500699{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100700 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800701 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400702 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100703};
704
Neale Ranns180279b2017-03-16 15:49:09 -0400705VNET_FEATURE_INIT (ip4_lookup, static) =
706{
707 .arc_name = "ip4-unicast",
708 .node_name = "ip4-lookup",
709 .runs_before = 0, /* not before any other features */
710};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100711
Dave Barachd6534602016-06-14 18:38:02 -0400712/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100713VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
714{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500715 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100716 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
717 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
718};
719
Dave Barachd7cb1b52016-12-09 09:52:16 -0500720VNET_FEATURE_INIT (ip4_vpath_mc, static) =
721{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100722 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400723 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000724 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400725};
726
Neale Ranns8269d3d2018-01-30 09:02:20 -0800727VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500728{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100729 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800730 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400731 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
732};
733
734VNET_FEATURE_INIT (ip4_lookup_mc, static) =
735{
736 .arc_name = "ip4-multicast",
737 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500738 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100739};
Dave Barach5331c722016-08-17 11:54:30 -0400740
741/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100742VNET_FEATURE_ARC_INIT (ip4_output, static) =
743{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500744 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800745 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Damjan Marion8b3191e2016-11-09 19:54:20 +0100746 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
747};
Dave Barach5331c722016-08-17 11:54:30 -0400748
Dave Barachd7cb1b52016-12-09 09:52:16 -0500749VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
750{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100751 .arc_name = "ip4-output",
752 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100753 .runs_before = VNET_FEATURES ("ip4-outacl"),
754};
755
756VNET_FEATURE_INIT (ip4_outacl, static) =
757{
758 .arc_name = "ip4-output",
759 .node_name = "ip4-outacl",
Matus Fabian08a6f012016-11-15 06:08:51 -0800760 .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
761};
762
Dave Barachd7cb1b52016-12-09 09:52:16 -0500763VNET_FEATURE_INIT (ip4_ipsec_output, static) =
764{
Matus Fabian08a6f012016-11-15 06:08:51 -0800765 .arc_name = "ip4-output",
766 .node_name = "ipsec-output-ip4",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100767 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -0400768};
769
770/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500771VNET_FEATURE_INIT (ip4_interface_output, static) =
772{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100773 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -0400774 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500775 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -0400776};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500777/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400778
Ed Warnickecb9cada2015-12-08 15:45:58 -0700779static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500780ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700781{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100784 /* Fill in lookup tables with default table (0). */
785 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000786 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100787
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200788 if (!is_add)
789 {
790 ip4_main_t *im4 = &ip4_main;
791 ip_lookup_main_t *lm4 = &im4->lookup_main;
792 ip_interface_address_t *ia = 0;
793 ip4_address_t *address;
794 vlib_main_t *vm = vlib_get_main ();
795
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700796 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200797 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700798 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200799 ({
800 address = ip_interface_address_get_address (lm4, ia);
801 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
802 }));
803 /* *INDENT-ON* */
804 }
805
Neale Ranns8269d3d2018-01-30 09:02:20 -0800806 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100807 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700808
Neale Ranns8269d3d2018-01-30 09:02:20 -0800809 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
810 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700811
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812 return /* no error */ 0;
813}
814
815VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
816
Ed Warnickecb9cada2015-12-08 15:45:58 -0700817/* Global IP4 main. */
818ip4_main_t ip4_main;
819
820clib_error_t *
821ip4_lookup_init (vlib_main_t * vm)
822{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 ip4_main_t *im = &ip4_main;
824 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825 uword i;
826
Damjan Marion8b3191e2016-11-09 19:54:20 +0100827 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
828 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -0800829 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
830 return (error);
831 if ((error = vlib_call_init_function (vm, fib_module_init)))
832 return error;
833 if ((error = vlib_call_init_function (vm, mfib_module_init)))
834 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100835
Ed Warnickecb9cada2015-12-08 15:45:58 -0700836 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
837 {
838 u32 m;
839
840 if (i < 32)
841 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -0400842 else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700843 m = ~0;
844 im->fib_masks[i] = clib_host_to_net_u32 (m);
845 }
846
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
848
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100849 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -0700850 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
851 FIB_SOURCE_DEFAULT_ROUTE);
852 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
853 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100854
Ed Warnickecb9cada2015-12-08 15:45:58 -0700855 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500856 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857 pn = pg_get_node (ip4_lookup_node.index);
858 pn->unformat_edit = unformat_pg_ip4_header;
859 }
860
861 {
862 ethernet_arp_header_t h;
863
864 memset (&h, 0, sizeof (h));
865
866 /* Set target ethernet address to all zeros. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500867 memset (h.ip4_over_ethernet[1].ethernet, 0,
868 sizeof (h.ip4_over_ethernet[1].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869
870#define _16(f,v) h.f = clib_host_to_net_u16 (v);
871#define _8(f,v) h.f = v;
872 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
873 _16 (l3_type, ETHERNET_TYPE_IP4);
874 _8 (n_l2_address_bytes, 6);
875 _8 (n_l3_address_bytes, 4);
876 _16 (opcode, ETHERNET_ARP_OPCODE_request);
877#undef _16
878#undef _8
879
Dave Barachd7cb1b52016-12-09 09:52:16 -0500880 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881 /* data */ &h,
882 sizeof (h),
883 /* alloc chunk size */ 8,
884 "ip4 arp");
885 }
886
Dave Barach203c6322016-06-26 10:29:03 -0400887 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700888}
889
890VLIB_INIT_FUNCTION (ip4_lookup_init);
891
Dave Barachd7cb1b52016-12-09 09:52:16 -0500892typedef struct
893{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700894 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -0700895 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896 u32 flow_hash;
897 u32 fib_index;
898
899 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500900 u8 packet_data[64 - 1 * sizeof (u32)];
901}
902ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903
Dave Barachd7cb1b52016-12-09 09:52:16 -0500904u8 *
905format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700906{
907 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
908 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500909 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200910 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100911 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -0400912 format_white_space, indent,
913 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100914 return s;
915}
916
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917static u8 *
918format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100919{
920 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
921 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500922 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200923 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700924
John Loac8146c2016-09-27 17:44:02 -0400925 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500926 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100927 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500928 format_white_space, indent,
929 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100930 return s;
931}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700932
Dave Barachd7cb1b52016-12-09 09:52:16 -0500933static u8 *
934format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100935{
936 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
937 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500938 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200939 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940
Vengada Govindanf1544482016-09-28 02:45:57 -0700941 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500942 t->fib_index, t->dpo_index, format_ip_adjacency,
943 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100944 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500945 format_white_space, indent,
946 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -0400947 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700948 return s;
949}
950
951/* Common trace function for all ip4-forward next nodes. */
952void
953ip4_forward_next_trace (vlib_main_t * vm,
954 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500955 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500957 u32 *from, n_left;
958 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700959
960 n_left = frame->n_vectors;
961 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -0400962
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 while (n_left >= 4)
964 {
965 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500966 vlib_buffer_t *b0, *b1;
967 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700968
969 /* Prefetch next iteration. */
970 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
971 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
972
973 bi0 = from[0];
974 bi1 = from[1];
975
976 b0 = vlib_get_buffer (vm, bi0);
977 b1 = vlib_get_buffer (vm, bi1);
978
979 if (b0->flags & VLIB_BUFFER_IS_TRACED)
980 {
981 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -0700982 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500984 t0->fib_index =
985 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
986 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
987 vec_elt (im->fib_index_by_sw_if_index,
988 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100989
Damjan Marionf1213b82016-03-13 02:22:06 +0100990 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991 vlib_buffer_get_current (b0),
992 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 }
994 if (b1->flags & VLIB_BUFFER_IS_TRACED)
995 {
996 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -0700997 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700998 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500999 t1->fib_index =
1000 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1001 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1002 vec_elt (im->fib_index_by_sw_if_index,
1003 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1004 clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1005 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006 }
1007 from += 2;
1008 n_left -= 2;
1009 }
1010
1011 while (n_left >= 1)
1012 {
1013 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014 vlib_buffer_t *b0;
1015 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016
1017 bi0 = from[0];
1018
1019 b0 = vlib_get_buffer (vm, bi0);
1020
1021 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1022 {
1023 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001024 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026 t0->fib_index =
1027 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1028 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1029 vec_elt (im->fib_index_by_sw_if_index,
1030 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1031 clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1032 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 }
1034 from += 1;
1035 n_left -= 1;
1036 }
1037}
1038
Ed Warnickecb9cada2015-12-08 15:45:58 -07001039/* Compute TCP/UDP/ICMP4 checksum in software. */
1040u16
1041ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1042 ip4_header_t * ip0)
1043{
1044 ip_csum_t sum0;
1045 u32 ip_header_length, payload_length_host_byte_order;
Florin Corasb2215d62017-08-01 16:56:58 -07001046 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 u16 sum16;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001048 void *data_this_buffer;
Dave Barach75fc8542016-10-11 16:16:02 -04001049
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 /* Initialize checksum with ip header. */
1051 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001052 payload_length_host_byte_order =
1053 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1054 sum0 =
1055 clib_host_to_net_u32 (payload_length_host_byte_order +
1056 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001057
1058 if (BITS (uword) == 32)
1059 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001060 sum0 =
1061 ip_csum_with_carry (sum0,
1062 clib_mem_unaligned (&ip0->src_address, u32));
1063 sum0 =
1064 ip_csum_with_carry (sum0,
1065 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066 }
1067 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001068 sum0 =
1069 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070
1071 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1072 data_this_buffer = (void *) ip0 + ip_header_length;
Neale Rannsd91c1db2017-07-31 02:30:50 -07001073 n_ip_bytes_this_buffer =
1074 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
Florin Corasb2215d62017-08-01 16:56:58 -07001075 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1076 {
1077 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
Neale Rannsd91c1db2017-07-31 02:30:50 -07001078 n_ip_bytes_this_buffer - ip_header_length : 0;
Florin Corasb2215d62017-08-01 16:56:58 -07001079 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 while (1)
1081 {
1082 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1083 n_bytes_left -= n_this_buffer;
1084 if (n_bytes_left == 0)
1085 break;
1086
1087 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1088 p0 = vlib_get_buffer (vm, p0->next_buffer);
1089 data_this_buffer = vlib_buffer_get_current (p0);
1090 n_this_buffer = p0->current_length;
1091 }
1092
Dave Barachd7cb1b52016-12-09 09:52:16 -05001093 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094
1095 return sum16;
1096}
1097
John Lo37682e12016-11-30 12:51:39 -05001098u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1100{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001101 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1102 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103 u16 sum16;
1104
1105 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1106 || ip0->protocol == IP_PROTOCOL_UDP);
1107
1108 udp0 = (void *) (ip0 + 1);
1109 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1110 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001111 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1112 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113 return p0->flags;
1114 }
1115
1116 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1117
Damjan Marion213b5aa2017-07-13 21:19:27 +02001118 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1119 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120
1121 return p0->flags;
1122}
1123
Dave Barach68b0fb02017-02-28 15:15:56 -05001124/* *INDENT-OFF* */
1125VNET_FEATURE_ARC_INIT (ip4_local) =
1126{
1127 .arc_name = "ip4-local",
1128 .start_nodes = VNET_FEATURES ("ip4-local"),
1129};
1130/* *INDENT-ON* */
1131
Florin Coras20a14b92017-08-15 22:47:22 -07001132static inline void
1133ip4_local_validate_l4 (vlib_main_t * vm, vlib_buffer_t * p, ip4_header_t * ip,
1134 u8 is_udp, u8 * error, u8 * good_tcp_udp)
1135{
1136 u32 flags0;
1137 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1138 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1139 if (is_udp)
1140 {
1141 udp_header_t *udp;
1142 u32 ip_len, udp_len;
1143 i32 len_diff;
1144 udp = ip4_next_header (ip);
1145 /* Verify UDP length. */
1146 ip_len = clib_net_to_host_u16 (ip->length);
1147 udp_len = clib_net_to_host_u16 (udp->length);
1148
1149 len_diff = ip_len - udp_len;
1150 *good_tcp_udp &= len_diff >= 0;
1151 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1152 }
1153}
1154
1155#define ip4_local_do_l4_check(is_tcp_udp, flags) \
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001156 (is_tcp_udp && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1157 || flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1158 || flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
Florin Coras20a14b92017-08-15 22:47:22 -07001159
Dave Barach68b0fb02017-02-28 15:15:56 -05001160static inline uword
1161ip4_local_inline (vlib_main_t * vm,
1162 vlib_node_runtime_t * node,
1163 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001164{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001165 ip4_main_t *im = &ip4_main;
1166 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001168 u32 *from, *to_next, n_left_from, n_left_to_next;
1169 vlib_node_runtime_t *error_node =
1170 vlib_node_get_runtime (vm, ip4_input_node.index);
Dave Barach68b0fb02017-02-28 15:15:56 -05001171 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
1173 from = vlib_frame_vector_args (frame);
1174 n_left_from = frame->n_vectors;
1175 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001176
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177 if (node->flags & VLIB_NODE_FLAG_TRACE)
1178 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1179
1180 while (n_left_from > 0)
1181 {
1182 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1183
1184 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001185 {
1186 vlib_buffer_t *p0, *p1;
1187 ip4_header_t *ip0, *ip1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001188 ip4_fib_mtrie_t *mtrie0, *mtrie1;
1189 ip4_fib_mtrie_leaf_t leaf0, leaf1;
1190 const dpo_id_t *dpo0, *dpo1;
1191 const load_balance_t *lb0, *lb1;
Florin Coras20a14b92017-08-15 22:47:22 -07001192 u32 pi0, next0, fib_index0, lbi0;
1193 u32 pi1, next1, fib_index1, lbi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001194 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1195 u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
Dave Barach68b0fb02017-02-28 15:15:56 -05001196 u32 sw_if_index0, sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001197
Dave Barachd7cb1b52016-12-09 09:52:16 -05001198 pi0 = to_next[0] = from[0];
1199 pi1 = to_next[1] = from[1];
1200 from += 2;
1201 n_left_from -= 2;
1202 to_next += 2;
1203 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001204
Dave Barach68b0fb02017-02-28 15:15:56 -05001205 next0 = next1 = IP_LOCAL_NEXT_DROP;
Florin Coras20a14b92017-08-15 22:47:22 -07001206 error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
Dave Barach68b0fb02017-02-28 15:15:56 -05001207
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208 p0 = vlib_get_buffer (vm, pi0);
1209 p1 = vlib_get_buffer (vm, pi1);
1210
1211 ip0 = vlib_buffer_get_current (p0);
1212 ip1 = vlib_buffer_get_current (p1);
1213
Damjan Marion072401e2017-07-13 18:53:27 +02001214 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1215 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001216
Dave Barach68b0fb02017-02-28 15:15:56 -05001217 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1218 sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
1219
Klement Sekera4c533132018-02-22 11:41:12 +01001220 proto0 = ip0->protocol;
1221 proto1 = ip1->protocol;
Florin Coras20a14b92017-08-15 22:47:22 -07001222
1223 if (head_of_feature_arc == 0)
1224 goto skip_checks;
1225
1226 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1227 is_udp1 = proto1 == IP_PROTOCOL_UDP;
1228 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1229 is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1230
1231 good_tcp_udp0 =
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001232 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001233 || (p0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1234 || p0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001235 good_tcp_udp1 = (p1->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001236 || (p1->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1237 || p1->flags &
1238 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
Florin Coras20a14b92017-08-15 22:47:22 -07001239
1240 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)
1241 || ip4_local_do_l4_check (is_tcp_udp1,
1242 p1->flags)))
1243 {
1244 if (is_tcp_udp0)
1245 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1246 &good_tcp_udp0);
1247 if (is_tcp_udp1)
1248 ip4_local_validate_l4 (vm, p1, ip1, is_udp1, &error1,
1249 &good_tcp_udp1);
1250 }
1251
1252 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1253 error0 = (is_tcp_udp0 && !good_tcp_udp0
1254 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1255 error1 = (is_tcp_udp1 && !good_tcp_udp1
1256 ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
Dave Barach68b0fb02017-02-28 15:15:56 -05001257
1258 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
Neale Ranns32e1c012016-11-22 17:07:28 +00001259 fib_index0 =
1260 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1261 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Neale Rannscb630ff2016-12-14 13:31:29 +01001262
Dave Barach68b0fb02017-02-28 15:15:56 -05001263 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001264 fib_index1 =
1265 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1266 (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267
Florin Corascea194d2017-10-02 00:18:51 -07001268 /* TODO maybe move to lookup? */
1269 vnet_buffer (p0)->ip.fib_index = fib_index0;
1270 vnet_buffer (p1)->ip.fib_index = fib_index1;
1271
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001272 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1273 mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001274
Neale Ranns04a75e32017-03-23 06:46:01 -07001275 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1276 leaf1 = ip4_fib_mtrie_lookup_step_one (mtrie1, &ip1->src_address);
Florin Coras20a14b92017-08-15 22:47:22 -07001277 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1278 2);
1279 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1280 2);
1281 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1282 3);
1283 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address,
1284 3);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285
Dave Barachd7cb1b52016-12-09 09:52:16 -05001286 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1287 ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1288 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289
Dave Barachd7cb1b52016-12-09 09:52:16 -05001290 vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1291 ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1292 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293
Dave Barachd7cb1b52016-12-09 09:52:16 -05001294 lb0 = load_balance_get (lbi0);
1295 lb1 = load_balance_get (lbi1);
1296 dpo0 = load_balance_get_bucket_i (lb0, 0);
1297 dpo1 = load_balance_get_bucket_i (lb1, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298
Dave Barach75fc8542016-10-11 16:16:02 -04001299 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001300 * Must have a route to source otherwise we drop the packet.
1301 * ip4 broadcasts are accepted, e.g. to make dhcp client work
Neale Ranns3ee44042016-10-03 13:05:48 +01001302 *
1303 * The checks are:
1304 * - the source is a recieve => it's from us => bogus, do this
1305 * first since it sets a different error code.
1306 * - uRPF check for any route to source - accept if passes.
1307 * - allow packets destined to the broadcast address from unknown sources
Dave Barachd7cb1b52016-12-09 09:52:16 -05001308 */
Matus Fabian87da4762017-10-04 08:03:56 -07001309 if (p0->flags & VNET_BUFFER_F_IS_NATED)
1310 goto skip_check0;
1311
Neale Ranns3ee44042016-10-03 13:05:48 +01001312 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001313 dpo0->dpoi_type == DPO_RECEIVE) ?
1314 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1315 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1316 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001317 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001318 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Matus Fabian87da4762017-10-04 08:03:56 -07001319
1320 skip_check0:
1321 if (p1->flags & VNET_BUFFER_F_IS_NATED)
1322 goto skip_checks;
1323
Neale Ranns3ee44042016-10-03 13:05:48 +01001324 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001325 dpo1->dpoi_type == DPO_RECEIVE) ?
1326 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1327 error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1328 !fib_urpf_check_size (lb1->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001329 ip1->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001330 ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001331
Florin Corasa0b34a72017-03-07 01:20:52 -08001332 skip_checks:
1333
Ed Warnickecb9cada2015-12-08 15:45:58 -07001334 next0 = lm->local_next_by_ip_protocol[proto0];
1335 next1 = lm->local_next_by_ip_protocol[proto1];
1336
Dave Barachd7cb1b52016-12-09 09:52:16 -05001337 next0 =
1338 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1339 next1 =
1340 error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001341
1342 p0->error = error0 ? error_node->errors[error0] : 0;
1343 p1->error = error1 ? error_node->errors[error1] : 0;
1344
Dave Barach68b0fb02017-02-28 15:15:56 -05001345 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001346 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001347 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1348 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
1349 if (PREDICT_TRUE (error1 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1350 vnet_feature_arc_start (arc_index, sw_if_index1, &next1, p1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001352
1353 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
1354 n_left_to_next, pi0, pi1,
1355 next0, next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001356 }
1357
1358 while (n_left_from > 0 && n_left_to_next > 0)
1359 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001360 vlib_buffer_t *p0;
1361 ip4_header_t *ip0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001362 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363 ip4_fib_mtrie_leaf_t leaf0;
Florin Coras20a14b92017-08-15 22:47:22 -07001364 u32 pi0, next0, fib_index0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001365 u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001366 load_balance_t *lb0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001367 const dpo_id_t *dpo0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001368 u32 sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001369
Ed Warnickecb9cada2015-12-08 15:45:58 -07001370 pi0 = to_next[0] = from[0];
1371 from += 1;
1372 n_left_from -= 1;
1373 to_next += 1;
1374 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001375
Dave Barach68b0fb02017-02-28 15:15:56 -05001376 next0 = IP_LOCAL_NEXT_DROP;
Florin Coras20a14b92017-08-15 22:47:22 -07001377 error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
Dave Barach68b0fb02017-02-28 15:15:56 -05001378
Ed Warnickecb9cada2015-12-08 15:45:58 -07001379 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380 ip0 = vlib_buffer_get_current (p0);
Damjan Marion072401e2017-07-13 18:53:27 +02001381 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Dave Barach68b0fb02017-02-28 15:15:56 -05001382 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1383
Klement Sekera4c533132018-02-22 11:41:12 +01001384 proto0 = ip0->protocol;
Dave Barach68b0fb02017-02-28 15:15:56 -05001385
Matus Fabian87da4762017-10-04 08:03:56 -07001386 if (head_of_feature_arc == 0 || p0->flags & VNET_BUFFER_F_IS_NATED)
Florin Coras20a14b92017-08-15 22:47:22 -07001387 goto skip_check;
Dave Barach68b0fb02017-02-28 15:15:56 -05001388
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389 is_udp0 = proto0 == IP_PROTOCOL_UDP;
1390 is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001391
Florin Coras20a14b92017-08-15 22:47:22 -07001392 good_tcp_udp0 =
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001393 (p0->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001394 || (p0->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1395 || p0->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001396
Florin Coras20a14b92017-08-15 22:47:22 -07001397 if (PREDICT_FALSE (ip4_local_do_l4_check (is_tcp_udp0, p0->flags)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001398 {
Florin Coras20a14b92017-08-15 22:47:22 -07001399 ip4_local_validate_l4 (vm, p0, ip0, is_udp0, &error0,
1400 &good_tcp_udp0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001401 }
1402
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001404 error0 = (is_tcp_udp0 && !good_tcp_udp0
1405 ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001406
Florin Coras20a14b92017-08-15 22:47:22 -07001407 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, sw_if_index0);
1408 fib_index0 =
1409 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1410 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Florin Corascea194d2017-10-02 00:18:51 -07001411 vnet_buffer (p0)->ip.fib_index = fib_index0;
Florin Coras20a14b92017-08-15 22:47:22 -07001412 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1413 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1414 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1415 2);
1416 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address,
1417 3);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001418 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001419 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras20a14b92017-08-15 22:47:22 -07001420 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001421
Dave Barachd7cb1b52016-12-09 09:52:16 -05001422 lb0 = load_balance_get (lbi0);
1423 dpo0 = load_balance_get_bucket_i (lb0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001424
Neale Ranns3ee44042016-10-03 13:05:48 +01001425 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001426 dpo0->dpoi_type == DPO_RECEIVE) ?
1427 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1428 error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1429 !fib_urpf_check_size (lb0->lb_urpf) &&
Neale Ranns3ee44042016-10-03 13:05:48 +01001430 ip0->dst_address.as_u32 != 0xFFFFFFFF)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001431 ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432
Dave Barach68b0fb02017-02-28 15:15:56 -05001433 skip_check:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001434 next0 = lm->local_next_by_ip_protocol[proto0];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001435 next0 =
1436 error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001437
Dave Barachd7cb1b52016-12-09 09:52:16 -05001438 p0->error = error0 ? error_node->errors[error0] : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001439
Dave Barach68b0fb02017-02-28 15:15:56 -05001440 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001441 {
Dave Barach68b0fb02017-02-28 15:15:56 -05001442 if (PREDICT_TRUE (error0 == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1443 vnet_feature_arc_start (arc_index, sw_if_index0, &next0, p0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001444 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001445
1446 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1447 n_left_to_next, pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001448 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001449 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1450 }
1451
1452 return frame->n_vectors;
1453}
1454
Dave Barach68b0fb02017-02-28 15:15:56 -05001455static uword
1456ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1457{
1458 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1459}
1460
1461/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001462VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001463{
Dave Barach68b0fb02017-02-28 15:15:56 -05001464 .function = ip4_local,
1465 .name = "ip4-local",
1466 .vector_size = sizeof (u32),
1467 .format_trace = format_ip4_forward_next_trace,
1468 .n_next_nodes = IP_LOCAL_N_NEXT,
1469 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001470 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001471 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1472 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001473 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001474 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1475 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001476};
1477/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001478
1479VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1480
Dave Barach68b0fb02017-02-28 15:15:56 -05001481static uword
1482ip4_local_end_of_arc (vlib_main_t * vm,
1483 vlib_node_runtime_t * node, vlib_frame_t * frame)
1484{
1485 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1486}
1487
1488/* *INDENT-OFF* */
1489VLIB_REGISTER_NODE (ip4_local_end_of_arc_node,static) = {
1490 .function = ip4_local_end_of_arc,
1491 .name = "ip4-local-end-of-arc",
1492 .vector_size = sizeof (u32),
1493
1494 .format_trace = format_ip4_forward_next_trace,
1495 .sibling_of = "ip4-local",
1496};
1497
1498VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_end_of_arc_node, ip4_local_end_of_arc)
1499
1500VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1501 .arc_name = "ip4-local",
1502 .node_name = "ip4-local-end-of-arc",
1503 .runs_before = 0, /* not before any other features */
1504};
1505/* *INDENT-ON* */
1506
Dave Barachd7cb1b52016-12-09 09:52:16 -05001507void
1508ip4_register_protocol (u32 protocol, u32 node_index)
1509{
1510 vlib_main_t *vm = vlib_get_main ();
1511 ip4_main_t *im = &ip4_main;
1512 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001513
1514 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001515 lm->local_next_by_ip_protocol[protocol] =
1516 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001517}
1518
1519static clib_error_t *
1520show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001521 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001522{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001523 ip4_main_t *im = &ip4_main;
1524 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001525 int i;
1526
1527 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001528 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001529 {
1530 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001531 {
1532 u32 node_index = vlib_get_node (vm,
1533 ip4_local_node.index)->
1534 next_nodes[lm->local_next_by_ip_protocol[i]];
1535 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
1536 node_index);
1537 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001538 }
1539 return 0;
1540}
1541
1542
1543
Billy McFall0683c9c2016-10-13 08:27:31 -04001544/*?
1545 * Display the set of protocols handled by the local IPv4 stack.
1546 *
1547 * @cliexpar
1548 * Example of how to display local protocol table:
1549 * @cliexstart{show ip local}
1550 * Protocols handled by ip4_local
1551 * 1
1552 * 17
1553 * 47
1554 * @cliexend
1555?*/
1556/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001557VLIB_CLI_COMMAND (show_ip_local, static) =
1558{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001559 .path = "show ip local",
1560 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001561 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001562};
Billy McFall0683c9c2016-10-13 08:27:31 -04001563/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001564
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001565always_inline uword
1566ip4_arp_inline (vlib_main_t * vm,
1567 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001568 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001569{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001570 vnet_main_t *vnm = vnet_get_main ();
1571 ip4_main_t *im = &ip4_main;
1572 ip_lookup_main_t *lm = &im->lookup_main;
1573 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001574 uword n_left_from, n_left_to_next_drop, next_index;
1575 static f64 time_last_seed_change = -1e100;
1576 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001577 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001578 f64 time_now;
1579
1580 if (node->flags & VLIB_NODE_FLAG_TRACE)
1581 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1582
1583 time_now = vlib_time_now (vm);
1584 if (time_now - time_last_seed_change > 1e-3)
1585 {
1586 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001587 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1588 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001589 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1590 hash_seeds[i] = r[i];
1591
1592 /* Mark all hash keys as been no-seen before. */
1593 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1594 hash_bitmap[i] = 0;
1595
1596 time_last_seed_change = time_now;
1597 }
1598
1599 from = vlib_frame_vector_args (frame);
1600 n_left_from = frame->n_vectors;
1601 next_index = node->cached_next_index;
1602 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001603 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001604
1605 while (n_left_from > 0)
1606 {
1607 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1608 to_next_drop, n_left_to_next_drop);
1609
1610 while (n_left_from > 0 && n_left_to_next_drop > 0)
1611 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001612 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001613 ip_adjacency_t *adj0;
1614 vlib_buffer_t *p0;
1615 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616 uword bm0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617
1618 pi0 = from[0];
1619
1620 p0 = vlib_get_buffer (vm, pi0);
1621
1622 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07001623 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001624 ip0 = vlib_buffer_get_current (p0);
1625
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626 a0 = hash_seeds[0];
1627 b0 = hash_seeds[1];
1628 c0 = hash_seeds[2];
1629
1630 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1631 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1632
Dave Barachd7cb1b52016-12-09 09:52:16 -05001633 if (is_glean)
1634 {
Neale Ranns948e00f2016-10-20 13:39:34 +01001635 /*
1636 * this is the Glean case, so we are ARPing for the
1637 * packet's destination
1638 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001639 a0 ^= ip0->dst_address.data_u32;
1640 }
1641 else
1642 {
1643 a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
1644 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001645 b0 ^= sw_if_index0;
1646
Florin Coras2d3dbc42017-09-08 16:22:38 -04001647 hash_v3_mix32 (a0, b0, c0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001648 hash_v3_finalize32 (a0, b0, c0);
1649
1650 c0 &= BITS (hash_bitmap) - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001651 m0 = (uword) 1 << (c0 % BITS (uword));
Florin Coras2d3dbc42017-09-08 16:22:38 -04001652 c0 = c0 / BITS (uword);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001653
1654 bm0 = hash_bitmap[c0];
1655 drop0 = (bm0 & m0) != 0;
1656
1657 /* Mark it as seen. */
1658 hash_bitmap[c0] = bm0 | m0;
1659
1660 from += 1;
1661 n_left_from -= 1;
1662 to_next_drop[0] = pi0;
1663 to_next_drop += 1;
1664 n_left_to_next_drop -= 1;
1665
Dave Barachd7cb1b52016-12-09 09:52:16 -05001666 p0->error =
1667 node->errors[drop0 ? IP4_ARP_ERROR_DROP :
1668 IP4_ARP_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001669
Neale Rannsb80c5362016-10-08 13:03:40 +01001670 /*
1671 * the adj has been updated to a rewrite but the node the DPO that got
1672 * us here hasn't - yet. no big deal. we'll drop while we wait.
1673 */
1674 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1675 continue;
1676
Ed Warnickecb9cada2015-12-08 15:45:58 -07001677 if (drop0)
1678 continue;
1679
Dave Barachd7cb1b52016-12-09 09:52:16 -05001680 /*
1681 * Can happen if the control-plane is programming tables
1682 * with traffic flowing; at least that's today's lame excuse.
1683 */
Neale Ranns32e1c012016-11-22 17:07:28 +00001684 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1685 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001686 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001687 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001688 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001689 else
1690 /* Send ARP request. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001691 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001692 u32 bi0 = 0;
1693 vlib_buffer_t *b0;
1694 ethernet_arp_header_t *h0;
1695 vnet_hw_interface_t *hw_if0;
1696
1697 h0 =
1698 vlib_packet_template_get_packet (vm,
1699 &im->ip4_arp_request_packet_template,
1700 &bi0);
1701
Florin Corasd172a622017-10-14 11:02:37 -07001702 /* Seems we're out of buffers */
1703 if (PREDICT_FALSE (!h0))
1704 continue;
1705
Dave Barachd7cb1b52016-12-09 09:52:16 -05001706 /* Add rewrite/encap string for ARP packet. */
1707 vnet_rewrite_one_header (adj0[0], h0,
1708 sizeof (ethernet_header_t));
1709
1710 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1711
1712 /* Src ethernet address in ARP header. */
1713 clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
1714 hw_if0->hw_address,
1715 sizeof (h0->ip4_over_ethernet[0].ethernet));
1716
1717 if (is_glean)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001718 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001719 /* The interface's source address is stashed in the Glean Adj */
1720 h0->ip4_over_ethernet[0].ip4 =
1721 adj0->sub_type.glean.receive_addr.ip4;
1722
1723 /* Copy in destination address we are requesting. This is the
1724 * glean case, so it's the packet's destination.*/
1725 h0->ip4_over_ethernet[1].ip4.data_u32 =
1726 ip0->dst_address.data_u32;
1727 }
1728 else
1729 {
1730 /* Src IP address in ARP header. */
1731 if (ip4_src_address_for_packet (lm, sw_if_index0,
1732 &h0->
1733 ip4_over_ethernet[0].ip4))
1734 {
1735 /* No source address available */
1736 p0->error =
1737 node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
1738 vlib_buffer_free (vm, &bi0, 1);
1739 continue;
1740 }
1741
1742 /* Copy in destination address we are requesting from the
1743 incomplete adj */
1744 h0->ip4_over_ethernet[1].ip4.data_u32 =
1745 adj0->sub_type.nbr.next_hop.ip4.as_u32;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001746 }
1747
Dave Barachd7cb1b52016-12-09 09:52:16 -05001748 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1749 b0 = vlib_get_buffer (vm, bi0);
Florin Coras2f9b0c02017-09-11 20:54:15 -04001750 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001751 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
1752
1753 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1754
1755 vlib_set_next_frame_buffer (vm, node,
1756 adj0->rewrite_header.next_index,
1757 bi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001758 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759 }
1760
1761 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
1762 }
1763
1764 return frame->n_vectors;
1765}
1766
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001767static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001768ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001769{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001770 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001771}
1772
1773static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001774ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001775{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001776 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001777}
1778
Dave Barachd7cb1b52016-12-09 09:52:16 -05001779static char *ip4_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001780 [IP4_ARP_ERROR_DROP] = "address overflow drops",
1781 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
1782 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
1783 [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
1784 [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001785 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001786};
1787
Neale Rannsf8686322017-11-29 02:39:53 -08001788/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001789VLIB_REGISTER_NODE (ip4_arp_node) =
1790{
Neale Rannsf8686322017-11-29 02:39:53 -08001791 .function = ip4_arp,
1792 .name = "ip4-arp",
1793 .vector_size = sizeof (u32),
1794 .format_trace = format_ip4_forward_next_trace,
1795 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1796 .error_strings = ip4_arp_error_strings,
1797 .n_next_nodes = IP4_ARP_N_NEXT,
1798 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799 {
Neale Rannsf8686322017-11-29 02:39:53 -08001800 [IP4_ARP_NEXT_DROP] = "error-drop",
1801 },
1802};
Ed Warnickecb9cada2015-12-08 15:45:58 -07001803
Dave Barachd7cb1b52016-12-09 09:52:16 -05001804VLIB_REGISTER_NODE (ip4_glean_node) =
1805{
Neale Rannsf8686322017-11-29 02:39:53 -08001806 .function = ip4_glean,
1807 .name = "ip4-glean",
1808 .vector_size = sizeof (u32),
1809 .format_trace = format_ip4_forward_next_trace,
1810 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
1811 .error_strings = ip4_arp_error_strings,
1812 .n_next_nodes = IP4_ARP_N_NEXT,
1813 .next_nodes = {
1814 [IP4_ARP_NEXT_DROP] = "error-drop",
1815 },
1816};
1817/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001818
Ed Warnickecb9cada2015-12-08 15:45:58 -07001819#define foreach_notrace_ip4_arp_error \
1820_(DROP) \
1821_(REQUEST_SENT) \
1822_(REPLICATE_DROP) \
1823_(REPLICATE_FAIL)
1824
Dave Barachd7cb1b52016-12-09 09:52:16 -05001825clib_error_t *
1826arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001827{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001828 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829
1830 /* don't trace ARP request packets */
1831#define _(a) \
1832 vnet_pcap_drop_trace_filter_add_del \
1833 (rt->errors[IP4_ARP_ERROR_##a], \
1834 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001835 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001836#undef _
1837 return 0;
1838}
1839
Dave Barachd7cb1b52016-12-09 09:52:16 -05001840VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841
1842
1843/* Send an ARP request to see if given destination is reachable on given interface. */
1844clib_error_t *
1845ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
1846{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001847 vnet_main_t *vnm = vnet_get_main ();
1848 ip4_main_t *im = &ip4_main;
1849 ethernet_arp_header_t *h;
1850 ip4_address_t *src;
1851 ip_interface_address_t *ia;
1852 ip_adjacency_t *adj;
1853 vnet_hw_interface_t *hi;
1854 vnet_sw_interface_t *si;
1855 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07001856 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857 u32 bi = 0;
1858
1859 si = vnet_get_sw_interface (vnm, sw_if_index);
1860
1861 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1862 {
1863 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001864 format_ip4_address, dst,
1865 format_vnet_sw_if_index_name, vnm,
1866 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001867 }
1868
Dave Barachd7cb1b52016-12-09 09:52:16 -05001869 src =
1870 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1871 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001872 {
1873 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001874 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00001875 (0,
1876 "no matching interface address for destination %U (interface %U)",
1877 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
1878 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879 }
1880
Neale Ranns7a272742017-05-30 02:08:14 -07001881 h = vlib_packet_template_get_packet (vm,
1882 &im->ip4_arp_request_packet_template,
1883 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001884
1885 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02001886 if (PREDICT_FALSE (!hi->hw_address))
1887 {
1888 return clib_error_return (0, "%U: interface %U do not support ip probe",
1889 format_ip4_address, dst,
1890 format_vnet_sw_if_index_name, vnm,
1891 sw_if_index);
1892 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001893
Dave Barachd7cb1b52016-12-09 09:52:16 -05001894 clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
1895 sizeof (h->ip4_over_ethernet[0].ethernet));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001896
1897 h->ip4_over_ethernet[0].ip4 = src[0];
1898 h->ip4_over_ethernet[1].ip4 = dst[0];
1899
1900 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001901 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1902 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001903
Dave Barach59b25652017-09-10 15:04:27 -04001904 ip46_address_t nh = {
1905 .ip4 = *dst,
1906 };
1907
1908 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
1909 VNET_LINK_IP4, &nh, sw_if_index);
1910 adj = adj_get (ai);
1911
1912 /* Peer has been previously resolved, retrieve glean adj instead */
1913 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1914 {
1915 adj_unlock (ai);
Ole Troan6ee40512018-02-12 18:14:39 +01001916 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
1917 VNET_LINK_IP4, sw_if_index, &nh);
Dave Barach59b25652017-09-10 15:04:27 -04001918 adj = adj_get (ai);
1919 }
1920
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921 /* Add encapsulation string for software interface (e.g. ethernet header). */
1922 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1923 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1924
1925 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001926 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1927 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928 to_next[0] = bi;
1929 f->n_vectors = 1;
1930 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1931 }
1932
Neale Ranns7a272742017-05-30 02:08:14 -07001933 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001934 return /* no error */ 0;
1935}
1936
Dave Barachd7cb1b52016-12-09 09:52:16 -05001937typedef enum
1938{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001939 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001940 IP4_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941} ip4_rewrite_next_t;
1942
1943always_inline uword
1944ip4_rewrite_inline (vlib_main_t * vm,
1945 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001946 vlib_frame_t * frame,
1947 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001949 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1950 u32 *from = vlib_frame_vector_args (frame);
1951 u32 n_left_from, n_left_to_next, *to_next, next_index;
1952 vlib_node_runtime_t *error_node =
1953 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001954
1955 n_left_from = frame->n_vectors;
1956 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02001957 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04001958
Ed Warnickecb9cada2015-12-08 15:45:58 -07001959 while (n_left_from > 0)
1960 {
1961 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1962
1963 while (n_left_from >= 4 && n_left_to_next >= 2)
1964 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001965 ip_adjacency_t *adj0, *adj1;
1966 vlib_buffer_t *p0, *p1;
1967 ip4_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968 u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
1969 u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001970 u32 tx_sw_if_index0, tx_sw_if_index1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001971
Ed Warnickecb9cada2015-12-08 15:45:58 -07001972 /* Prefetch next iteration. */
1973 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001974 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001975
1976 p2 = vlib_get_buffer (vm, from[2]);
1977 p3 = vlib_get_buffer (vm, from[3]);
1978
1979 vlib_prefetch_buffer_header (p2, STORE);
1980 vlib_prefetch_buffer_header (p3, STORE);
1981
1982 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1983 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1984 }
1985
1986 pi0 = to_next[0] = from[0];
1987 pi1 = to_next[1] = from[1];
1988
1989 from += 2;
1990 n_left_from -= 2;
1991 to_next += 2;
1992 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001993
Ed Warnickecb9cada2015-12-08 15:45:58 -07001994 p0 = vlib_get_buffer (vm, pi0);
1995 p1 = vlib_get_buffer (vm, pi1);
1996
Neale Rannsf06aea52016-11-29 06:51:37 -08001997 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1998 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001999
Neale Ranns1bd01092017-03-15 15:41:17 -04002000 /*
2001 * pre-fetch the per-adjacency counters
2002 */
2003 if (do_counters)
2004 {
2005 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002006 thread_index, adj_index0);
Neale Ranns1bd01092017-03-15 15:41:17 -04002007 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002008 thread_index, adj_index1);
Neale Ranns1bd01092017-03-15 15:41:17 -04002009 }
2010
Ed Warnickecb9cada2015-12-08 15:45:58 -07002011 ip0 = vlib_buffer_get_current (p0);
2012 ip1 = vlib_buffer_get_current (p1);
2013
2014 error0 = error1 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002015 next0 = next1 = IP4_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016
2017 /* Decrement TTL & update checksum.
2018 Works either endian, so no need for byte swap. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002019 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002020 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002021 i32 ttl0 = ip0->ttl;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002022
2023 /* Input node should have reject packets with ttl 0. */
2024 ASSERT (ip0->ttl > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002025
2026 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002027 checksum0 += checksum0 >= 0xffff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028
2029 ip0->checksum = checksum0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002030 ttl0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031 ip0->ttl = ttl0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002032
Dave Barachd7cb1b52016-12-09 09:52:16 -05002033 /*
2034 * If the ttl drops below 1 when forwarding, generate
2035 * an ICMP response.
2036 */
2037 if (PREDICT_FALSE (ttl0 <= 0))
2038 {
2039 error0 = IP4_ERROR_TIME_EXPIRED;
2040 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2041 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2042 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2043 0);
2044 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2045 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002046
2047 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002048 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002049 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Neale Rannsf06aea52016-11-29 06:51:37 -08002050 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002051 else
2052 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002053 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002054 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002055 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Neale Rannsf06aea52016-11-29 06:51:37 -08002056 {
2057 i32 ttl1 = ip1->ttl;
2058
2059 /* Input node should have reject packets with ttl 0. */
2060 ASSERT (ip1->ttl > 0);
2061
2062 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2063 checksum1 += checksum1 >= 0xffff;
2064
2065 ip1->checksum = checksum1;
2066 ttl1 -= 1;
2067 ip1->ttl = ttl1;
2068
Dave Barachd7cb1b52016-12-09 09:52:16 -05002069 /*
2070 * If the ttl drops below 1 when forwarding, generate
2071 * an ICMP response.
2072 */
2073 if (PREDICT_FALSE (ttl1 <= 0))
2074 {
2075 error1 = IP4_ERROR_TIME_EXPIRED;
2076 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2077 icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2078 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2079 0);
2080 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2081 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002082
2083 /* Verify checksum. */
Dave Barach2c0a4f42017-06-29 09:30:15 -04002084 ASSERT ((ip1->checksum == ip4_header_checksum (ip1)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002085 (p1->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002086 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002087 else
2088 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002089 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002090 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002091
2092 /* Rewrite packet header and updates lengths. */
Neale Ranns107e7d42017-04-11 09:55:19 -07002093 adj0 = adj_get (adj_index0);
2094 adj1 = adj_get (adj_index1);
Dave Barach75fc8542016-10-11 16:16:02 -04002095
Dave Barachd7cb1b52016-12-09 09:52:16 -05002096 /* Worth pipelining. No guarantee that adj0,1 are hot... */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002097 rw_len0 = adj0[0].rewrite_header.data_bytes;
2098 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002099 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2100 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Chris Lukef2868fc2016-06-14 16:26:22 -04002101
Dave Barachd7cb1b52016-12-09 09:52:16 -05002102 /* Check MTU of outgoing interface. */
Neale Rannsffd78d12018-02-09 06:05:16 -08002103 if (vlib_buffer_length_in_chain (vm, p0) >
2104 adj0[0].rewrite_header.max_l3_packet_bytes)
2105 {
2106 error0 = IP4_ERROR_MTU_EXCEEDED;
2107 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2108 icmp4_error_set_vnet_buffer
2109 (p0, ICMP4_destination_unreachable,
2110 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2111 0);
2112 }
2113 if (vlib_buffer_length_in_chain (vm, p1) >
2114 adj1[0].rewrite_header.max_l3_packet_bytes)
2115 {
2116 error1 = IP4_ERROR_MTU_EXCEEDED;
2117 next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2118 icmp4_error_set_vnet_buffer
2119 (p1, ICMP4_destination_unreachable,
2120 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2121 0);
2122 }
Chris Lukef2868fc2016-06-14 16:26:22 -04002123
Neale Rannscf3561b2017-12-13 01:44:25 -08002124 if (is_mcast)
2125 {
2126 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2127 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2128 IP4_ERROR_SAME_INTERFACE : error0);
2129 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2130 vnet_buffer (p1)->sw_if_index[VLIB_RX]) ?
2131 IP4_ERROR_SAME_INTERFACE : error1);
2132 }
2133
Chun Lief56fae2018-02-07 09:58:28 +08002134 p0->error = error_node->errors[error0];
2135 p1->error = error_node->errors[error1];
Dave Barachd7cb1b52016-12-09 09:52:16 -05002136 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2137 * to see the IP headerr */
2138 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2139 {
Damjan Marion892e0762016-12-09 18:52:05 +01002140 next0 = adj0[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002141 p0->current_data -= rw_len0;
2142 p0->current_length += rw_len0;
2143 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2144 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Dave Barach5331c722016-08-17 11:54:30 -04002145
Neale Rannsb069a692017-03-15 12:34:25 -04002146 if (PREDICT_FALSE
2147 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2148 vnet_feature_arc_start (lm->output_feature_arc_index,
2149 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002150 }
2151 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2152 {
Damjan Marion892e0762016-12-09 18:52:05 +01002153 next1 = adj1[0].rewrite_header.next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002154 p1->current_data -= rw_len1;
2155 p1->current_length += rw_len1;
Dave Barach5331c722016-08-17 11:54:30 -04002156
Dave Barachd7cb1b52016-12-09 09:52:16 -05002157 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2158 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
Dave Barach5331c722016-08-17 11:54:30 -04002159
Neale Rannsb069a692017-03-15 12:34:25 -04002160 if (PREDICT_FALSE
2161 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2162 vnet_feature_arc_start (lm->output_feature_arc_index,
2163 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002164 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002165
2166 /* Guess we are only writing on simple Ethernet header. */
2167 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002168 ip0, ip1, sizeof (ethernet_header_t));
Neale Ranns5e575b12016-10-03 09:40:25 +01002169
Neale Ranns044183f2017-01-24 01:34:25 -08002170 /*
2171 * Bump the per-adjacency counters
2172 */
Neale Ranns9c6a6132017-02-21 05:33:14 -08002173 if (do_counters)
2174 {
2175 vlib_increment_combined_counter
2176 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002177 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002178 adj_index0, 1,
2179 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Neale Ranns044183f2017-01-24 01:34:25 -08002180
Neale Ranns9c6a6132017-02-21 05:33:14 -08002181 vlib_increment_combined_counter
2182 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002183 thread_index,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002184 adj_index1, 1,
2185 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2186 }
Neale Ranns044183f2017-01-24 01:34:25 -08002187
Neale Ranns5e575b12016-10-03 09:40:25 +01002188 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002189 {
Neale Rannsdb14f5a2018-01-29 10:43:33 -08002190 adj0->sub_type.midchain.fixup_func
2191 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2192 adj1->sub_type.midchain.fixup_func
2193 (vm, adj1, p1, adj0->sub_type.midchain.fixup_data);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002194 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002195 if (is_mcast)
2196 {
2197 /*
2198 * copy bytes from the IP address into the MAC rewrite
2199 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002200 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2201 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002202 }
Dave Barach75fc8542016-10-11 16:16:02 -04002203
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2205 to_next, n_left_to_next,
2206 pi0, pi1, next0, next1);
2207 }
2208
2209 while (n_left_from > 0 && n_left_to_next > 0)
2210 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002211 ip_adjacency_t *adj0;
2212 vlib_buffer_t *p0;
2213 ip4_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214 u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002215 u32 tx_sw_if_index0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002216
Ed Warnickecb9cada2015-12-08 15:45:58 -07002217 pi0 = to_next[0] = from[0];
2218
2219 p0 = vlib_get_buffer (vm, pi0);
2220
Neale Rannsf06aea52016-11-29 06:51:37 -08002221 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222
Neale Ranns107e7d42017-04-11 09:55:19 -07002223 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002224
Ed Warnickecb9cada2015-12-08 15:45:58 -07002225 ip0 = vlib_buffer_get_current (p0);
2226
2227 error0 = IP4_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002228 next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002229
2230 /* Decrement TTL & update checksum. */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002231 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002232 {
2233 i32 ttl0 = ip0->ttl;
2234
2235 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2236
2237 checksum0 += checksum0 >= 0xffff;
2238
2239 ip0->checksum = checksum0;
2240
2241 ASSERT (ip0->ttl > 0);
2242
2243 ttl0 -= 1;
2244
2245 ip0->ttl = ttl0;
2246
Dave Barach2c0a4f42017-06-29 09:30:15 -04002247 ASSERT ((ip0->checksum == ip4_header_checksum (ip0)) ||
Damjan Marionfb3288f2017-07-19 15:07:10 +02002248 (p0->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002249
Dave Barachd7cb1b52016-12-09 09:52:16 -05002250 if (PREDICT_FALSE (ttl0 <= 0))
2251 {
2252 /*
2253 * If the ttl drops below 1 when forwarding, generate
2254 * an ICMP response.
2255 */
2256 error0 = IP4_ERROR_TIME_EXPIRED;
2257 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2258 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2259 icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2260 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2261 0);
2262 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002264 else
2265 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002266 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002267 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002268
Neale Ranns1bd01092017-03-15 15:41:17 -04002269 if (do_counters)
2270 vlib_prefetch_combined_counter (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002271 thread_index, adj_index0);
Neale Ranns044183f2017-01-24 01:34:25 -08002272
Ed Warnickecb9cada2015-12-08 15:45:58 -07002273 /* Guess we are only writing on simple Ethernet header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002274 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Neale Ranns32e1c012016-11-22 17:07:28 +00002275 if (is_mcast)
2276 {
2277 /*
2278 * copy bytes from the IP address into the MAC rewrite
2279 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002280 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002281 }
Dave Barach75fc8542016-10-11 16:16:02 -04002282
Dave Barachd7cb1b52016-12-09 09:52:16 -05002283 /* Update packet buffer attributes/set output interface. */
2284 rw_len0 = adj0[0].rewrite_header.data_bytes;
2285 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Dave Barach75fc8542016-10-11 16:16:02 -04002286
Neale Ranns1bd01092017-03-15 15:41:17 -04002287 if (do_counters)
2288 vlib_increment_combined_counter
2289 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002290 thread_index, adj_index0, 1,
Neale Ranns1bd01092017-03-15 15:41:17 -04002291 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Dave Barach75fc8542016-10-11 16:16:02 -04002292
Dave Barachd7cb1b52016-12-09 09:52:16 -05002293 /* Check MTU of outgoing interface. */
Neale Rannsffd78d12018-02-09 06:05:16 -08002294 if (vlib_buffer_length_in_chain (vm, p0) >
2295 adj0[0].rewrite_header.max_l3_packet_bytes)
2296 {
2297 error0 = IP4_ERROR_MTU_EXCEEDED;
2298 next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2299 icmp4_error_set_vnet_buffer
2300 (p0, ICMP4_destination_unreachable,
2301 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2302 0);
2303 }
Neale Rannscf3561b2017-12-13 01:44:25 -08002304 if (is_mcast)
2305 {
2306 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2307 vnet_buffer (p0)->sw_if_index[VLIB_RX]) ?
2308 IP4_ERROR_SAME_INTERFACE : error0);
2309 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310 p0->error = error_node->errors[error0];
Chris Luke816f3e12016-06-14 16:24:47 -04002311
Dave Barachd7cb1b52016-12-09 09:52:16 -05002312 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2313 * to see the IP headerr */
2314 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2315 {
2316 p0->current_data -= rw_len0;
2317 p0->current_length += rw_len0;
2318 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Chris Luke816f3e12016-06-14 16:24:47 -04002319
Dave Barachd7cb1b52016-12-09 09:52:16 -05002320 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2321 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002322
Neale Ranns5e575b12016-10-03 09:40:25 +01002323 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002324 {
Neale Rannsdb14f5a2018-01-29 10:43:33 -08002325 adj0->sub_type.midchain.fixup_func
2326 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
Neale Ranns5e575b12016-10-03 09:40:25 +01002327 }
2328
Neale Rannsb069a692017-03-15 12:34:25 -04002329 if (PREDICT_FALSE
2330 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2331 vnet_feature_arc_start (lm->output_feature_arc_index,
2332 tx_sw_if_index0, &next0, p0);
Damjan Marion8b3191e2016-11-09 19:54:20 +01002333
Dave Barachd7cb1b52016-12-09 09:52:16 -05002334 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002335
Ed Warnickecb9cada2015-12-08 15:45:58 -07002336 from += 1;
2337 n_left_from -= 1;
2338 to_next += 1;
2339 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002340
Ed Warnickecb9cada2015-12-08 15:45:58 -07002341 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2342 to_next, n_left_to_next,
2343 pi0, next0);
2344 }
Dave Barach75fc8542016-10-11 16:16:02 -04002345
Ed Warnickecb9cada2015-12-08 15:45:58 -07002346 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2347 }
2348
2349 /* Need to do trace after rewrites to pick up new packet data. */
2350 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002351 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002352
2353 return frame->n_vectors;
2354}
2355
Dave Barach132d51d2016-07-07 10:10:17 -04002356
Neale Rannsf06aea52016-11-29 06:51:37 -08002357/** @brief IPv4 rewrite node.
2358 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002359
2360 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2361 header checksum, fetch the ip adjacency, check the outbound mtu,
2362 apply the adjacency rewrite, and send pkts to the adjacency
2363 rewrite header's rewrite_next_index.
2364
2365 @param vm vlib_main_t corresponding to the current thread
2366 @param node vlib_node_runtime_t
2367 @param frame vlib_frame_t whose contents should be dispatched
2368
2369 @par Graph mechanics: buffer metadata, next index usage
2370
2371 @em Uses:
2372 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2373 - the rewrite adjacency index
2374 - <code>adj->lookup_next_index</code>
2375 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002376 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002377 - <code>adj->rewrite_header</code>
2378 - Rewrite string length, rewrite string, next_index
2379
2380 @em Sets:
2381 - <code>b->current_data, b->current_length</code>
2382 - Updated net of applying the rewrite string
2383
2384 <em>Next Indices:</em>
2385 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002386 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002387*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002388static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002389ip4_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002390 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002392 if (adj_are_counters_enabled ())
2393 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2394 else
2395 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002396}
2397
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002398static uword
2399ip4_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002400 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002401{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002402 if (adj_are_counters_enabled ())
2403 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2404 else
2405 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002406}
2407
Neale Ranns32e1c012016-11-22 17:07:28 +00002408static uword
2409ip4_rewrite_mcast (vlib_main_t * vm,
2410 vlib_node_runtime_t * node, vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002411{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002412 if (adj_are_counters_enabled ())
2413 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2414 else
2415 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002416}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002417
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002418static uword
2419ip4_mcast_midchain (vlib_main_t * vm,
2420 vlib_node_runtime_t * node, vlib_frame_t * frame)
2421{
2422 if (adj_are_counters_enabled ())
2423 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2424 else
2425 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2426}
2427
Neale Ranns32e1c012016-11-22 17:07:28 +00002428/* *INDENT-OFF* */
2429VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2430 .function = ip4_rewrite,
2431 .name = "ip4-rewrite",
2432 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002433
Neale Ranns32e1c012016-11-22 17:07:28 +00002434 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002435
Neale Ranns32e1c012016-11-22 17:07:28 +00002436 .n_next_nodes = 2,
2437 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002438 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002439 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2440 },
2441};
2442VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite)
2443
2444VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2445 .function = ip4_rewrite_mcast,
2446 .name = "ip4-rewrite-mcast",
2447 .vector_size = sizeof (u32),
2448
2449 .format_trace = format_ip4_rewrite_trace,
2450 .sibling_of = "ip4-rewrite",
2451};
2452VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
2453
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002454VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
2455 .function = ip4_mcast_midchain,
2456 .name = "ip4-mcast-midchain",
2457 .vector_size = sizeof (u32),
2458
2459 .format_trace = format_ip4_rewrite_trace,
2460 .sibling_of = "ip4-rewrite",
2461};
2462VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
2463
Neale Ranns32e1c012016-11-22 17:07:28 +00002464VLIB_REGISTER_NODE (ip4_midchain_node) = {
2465 .function = ip4_midchain,
2466 .name = "ip4-midchain",
2467 .vector_size = sizeof (u32),
2468 .format_trace = format_ip4_forward_next_trace,
2469 .sibling_of = "ip4-rewrite",
2470};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002471VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
Neale Ranns32e1c012016-11-22 17:07:28 +00002472/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002473
Dave Barachd7cb1b52016-12-09 09:52:16 -05002474int
2475ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2476{
2477 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002478 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002479 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002480
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002481 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482
Neale Ranns04a75e32017-03-23 06:46:01 -07002483 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002484 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2485 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002486
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002487 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002488
Dave Barachd7cb1b52016-12-09 09:52:16 -05002489 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002490}
Dave Barach75fc8542016-10-11 16:16:02 -04002491
Ed Warnickecb9cada2015-12-08 15:45:58 -07002492static clib_error_t *
2493test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002494 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002495{
Billy McFall309fe062016-10-14 07:37:33 -04002496 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002497 u32 table_id = 0;
2498 f64 count = 1;
2499 u32 n;
2500 int i;
2501 ip4_address_t ip4_base_address;
2502 u64 errors = 0;
2503
Dave Barachd7cb1b52016-12-09 09:52:16 -05002504 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2505 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002506 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002507 {
2508 /* Make sure the entry exists. */
2509 fib = ip4_fib_get (table_id);
2510 if ((fib) && (fib->index != table_id))
2511 return clib_error_return (0, "<fib-index> %d does not exist",
2512 table_id);
2513 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002514 else if (unformat (input, "count %f", &count))
2515 ;
2516
2517 else if (unformat (input, "%U",
2518 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002519 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002520 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002521 return clib_error_return (0, "unknown input `%U'",
2522 format_unformat_error, input);
2523 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002524
2525 n = count;
2526
2527 for (i = 0; i < n; i++)
2528 {
2529 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002530 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002531
Dave Barach75fc8542016-10-11 16:16:02 -04002532 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002533 clib_host_to_net_u32 (1 +
2534 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002535 }
2536
Dave Barach75fc8542016-10-11 16:16:02 -04002537 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002538 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2539 else
2540 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2541
2542 return 0;
2543}
2544
Billy McFall0683c9c2016-10-13 08:27:31 -04002545/*?
2546 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2547 * given FIB table to determine if there is a conflict with the
2548 * adjacency table. The fib-id can be determined by using the
2549 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2550 * of 0 is used.
2551 *
2552 * @todo This command uses fib-id, other commands use table-id (not
2553 * just a name, they are different indexes). Would like to change this
2554 * to table-id for consistency.
2555 *
2556 * @cliexpar
2557 * Example of how to run the test lookup command:
2558 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2559 * No errors in 2 lookups
2560 * @cliexend
2561?*/
2562/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002563VLIB_CLI_COMMAND (lookup_test_command, static) =
2564{
2565 .path = "test lookup",
2566 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2567 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002568};
Billy McFall0683c9c2016-10-13 08:27:31 -04002569/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002570
Dave Barachd7cb1b52016-12-09 09:52:16 -05002571int
2572vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002573{
Neale Ranns107e7d42017-04-11 09:55:19 -07002574 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002575
Neale Ranns107e7d42017-04-11 09:55:19 -07002576 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2577
2578 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002579 return VNET_API_ERROR_NO_SUCH_FIB;
2580
Neale Ranns227038a2017-04-21 01:07:59 -07002581 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2582 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002583
Ed Warnickecb9cada2015-12-08 15:45:58 -07002584 return 0;
2585}
Dave Barach75fc8542016-10-11 16:16:02 -04002586
Ed Warnickecb9cada2015-12-08 15:45:58 -07002587static clib_error_t *
2588set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002589 unformat_input_t * input,
2590 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002591{
2592 int matched = 0;
2593 u32 table_id = 0;
2594 u32 flow_hash_config = 0;
2595 int rv;
2596
Dave Barachd7cb1b52016-12-09 09:52:16 -05002597 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2598 {
2599 if (unformat (input, "table %d", &table_id))
2600 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002601#define _(a,v) \
2602 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002603 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002604#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002605 else
2606 break;
2607 }
Dave Barach75fc8542016-10-11 16:16:02 -04002608
Ed Warnickecb9cada2015-12-08 15:45:58 -07002609 if (matched == 0)
2610 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002611 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002612
Ed Warnickecb9cada2015-12-08 15:45:58 -07002613 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2614 switch (rv)
2615 {
2616 case 0:
2617 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002618
Ed Warnickecb9cada2015-12-08 15:45:58 -07002619 case VNET_API_ERROR_NO_SUCH_FIB:
2620 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002621
Ed Warnickecb9cada2015-12-08 15:45:58 -07002622 default:
2623 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2624 break;
2625 }
Dave Barach75fc8542016-10-11 16:16:02 -04002626
Ed Warnickecb9cada2015-12-08 15:45:58 -07002627 return 0;
2628}
Dave Barach75fc8542016-10-11 16:16:02 -04002629
Billy McFall0683c9c2016-10-13 08:27:31 -04002630/*?
2631 * Configure the set of IPv4 fields used by the flow hash.
2632 *
2633 * @cliexpar
2634 * Example of how to set the flow hash on a given table:
2635 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2636 * Example of display the configured flow hash:
2637 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002638 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2639 * 0.0.0.0/0
2640 * unicast-ip4-chain
2641 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2642 * [0] [@0]: dpo-drop ip6
2643 * 0.0.0.0/32
2644 * unicast-ip4-chain
2645 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2646 * [0] [@0]: dpo-drop ip6
2647 * 224.0.0.0/8
2648 * unicast-ip4-chain
2649 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2650 * [0] [@0]: dpo-drop ip6
2651 * 6.0.1.2/32
2652 * unicast-ip4-chain
2653 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2654 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2655 * 7.0.0.1/32
2656 * unicast-ip4-chain
2657 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2658 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2659 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2660 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2661 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2662 * 240.0.0.0/8
2663 * unicast-ip4-chain
2664 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2665 * [0] [@0]: dpo-drop ip6
2666 * 255.255.255.255/32
2667 * unicast-ip4-chain
2668 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2669 * [0] [@0]: dpo-drop ip6
2670 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2671 * 0.0.0.0/0
2672 * unicast-ip4-chain
2673 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2674 * [0] [@0]: dpo-drop ip6
2675 * 0.0.0.0/32
2676 * unicast-ip4-chain
2677 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2678 * [0] [@0]: dpo-drop ip6
2679 * 172.16.1.0/24
2680 * unicast-ip4-chain
2681 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2682 * [0] [@4]: ipv4-glean: af_packet0
2683 * 172.16.1.1/32
2684 * unicast-ip4-chain
2685 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2686 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2687 * 172.16.1.2/32
2688 * unicast-ip4-chain
2689 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2690 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2691 * 172.16.2.0/24
2692 * unicast-ip4-chain
2693 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2694 * [0] [@4]: ipv4-glean: af_packet1
2695 * 172.16.2.1/32
2696 * unicast-ip4-chain
2697 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2698 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2699 * 224.0.0.0/8
2700 * unicast-ip4-chain
2701 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2702 * [0] [@0]: dpo-drop ip6
2703 * 240.0.0.0/8
2704 * unicast-ip4-chain
2705 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2706 * [0] [@0]: dpo-drop ip6
2707 * 255.255.255.255/32
2708 * unicast-ip4-chain
2709 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2710 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002711 * @cliexend
2712?*/
2713/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002714VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2715{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002716 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002717 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002718 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002719 .function = set_ip_flow_hash_command_fn,
2720};
Billy McFall0683c9c2016-10-13 08:27:31 -04002721/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002722
Dave Barachd7cb1b52016-12-09 09:52:16 -05002723int
2724vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2725 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002727 vnet_main_t *vnm = vnet_get_main ();
2728 vnet_interface_main_t *im = &vnm->interface_main;
2729 ip4_main_t *ipm = &ip4_main;
2730 ip_lookup_main_t *lm = &ipm->lookup_main;
2731 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002732 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002733
2734 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2735 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2736
2737 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2738 return VNET_API_ERROR_NO_SUCH_ENTRY;
2739
2740 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002741 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002742
Neale Rannsdf089a82016-10-02 16:39:06 +01002743 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2744
2745 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002746 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002747 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002748 .fp_len = 32,
2749 .fp_proto = FIB_PROTOCOL_IP4,
2750 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002751 };
2752 u32 fib_index;
2753
Dave Barachd7cb1b52016-12-09 09:52:16 -05002754 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2755 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002756
2757
Dave Barachd7cb1b52016-12-09 09:52:16 -05002758 if (table_index != (u32) ~ 0)
2759 {
2760 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002761
Dave Barachd7cb1b52016-12-09 09:52:16 -05002762 dpo_set (&dpo,
2763 DPO_CLASSIFY,
2764 DPO_PROTO_IP4,
2765 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002766
Dave Barachd7cb1b52016-12-09 09:52:16 -05002767 fib_table_entry_special_dpo_add (fib_index,
2768 &pfx,
2769 FIB_SOURCE_CLASSIFY,
2770 FIB_ENTRY_FLAG_NONE, &dpo);
2771 dpo_reset (&dpo);
2772 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002773 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002774 {
2775 fib_table_entry_special_remove (fib_index,
2776 &pfx, FIB_SOURCE_CLASSIFY);
2777 }
2778 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002779
Ed Warnickecb9cada2015-12-08 15:45:58 -07002780 return 0;
2781}
2782
2783static clib_error_t *
2784set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002785 unformat_input_t * input,
2786 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002787{
2788 u32 table_index = ~0;
2789 int table_index_set = 0;
2790 u32 sw_if_index = ~0;
2791 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002792
Dave Barachd7cb1b52016-12-09 09:52:16 -05002793 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2794 {
2795 if (unformat (input, "table-index %d", &table_index))
2796 table_index_set = 1;
2797 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2798 vnet_get_main (), &sw_if_index))
2799 ;
2800 else
2801 break;
2802 }
Dave Barach75fc8542016-10-11 16:16:02 -04002803
Ed Warnickecb9cada2015-12-08 15:45:58 -07002804 if (table_index_set == 0)
2805 return clib_error_return (0, "classify table-index must be specified");
2806
2807 if (sw_if_index == ~0)
2808 return clib_error_return (0, "interface / subif must be specified");
2809
2810 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2811
2812 switch (rv)
2813 {
2814 case 0:
2815 break;
2816
2817 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2818 return clib_error_return (0, "No such interface");
2819
2820 case VNET_API_ERROR_NO_SUCH_ENTRY:
2821 return clib_error_return (0, "No such classifier table");
2822 }
2823 return 0;
2824}
2825
Billy McFall0683c9c2016-10-13 08:27:31 -04002826/*?
2827 * Assign a classification table to an interface. The classification
2828 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2829 * commands. Once the table is create, use this command to filter packets
2830 * on an interface.
2831 *
2832 * @cliexpar
2833 * Example of how to assign a classification table to an interface:
2834 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2835?*/
2836/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002837VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2838{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002839 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002840 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002841 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842 .function = set_ip_classify_command_fn,
2843};
Billy McFall0683c9c2016-10-13 08:27:31 -04002844/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002845
Neale Ranns1ec36522017-11-29 05:20:37 -08002846static clib_error_t *
2847ip4_config (vlib_main_t * vm, unformat_input_t * input)
2848{
2849 ip4_main_t *im = &ip4_main;
2850 uword heapsize = 0;
2851
2852 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2853 {
2854 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
2855 ;
2856 else
2857 return clib_error_return (0,
2858 "invalid heap-size parameter `%U'",
2859 format_unformat_error, input);
2860 }
2861
2862 im->mtrie_heap_size = heapsize;
2863
2864 return 0;
2865}
2866
2867VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
2868
Dave Barachd7cb1b52016-12-09 09:52:16 -05002869/*
2870 * fd.io coding-style-patch-verification: ON
2871 *
2872 * Local Variables:
2873 * eval: (c-set-style "gnu")
2874 * End:
2875 */