Line data Source code
1 : /*
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>
42 : #include <vnet/ip/ip_frag.h>
43 : #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
44 : #include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
45 : #include <vnet/ppp/ppp.h>
46 : #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
47 : #include <vnet/api_errno.h> /* for API error numbers */
48 : #include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
49 : #include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
50 : #include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
51 : #include <vnet/fib/ip4_fib.h>
52 : #include <vnet/mfib/ip4_mfib.h>
53 : #include <vnet/dpo/load_balance.h>
54 : #include <vnet/dpo/load_balance_map.h>
55 : #include <vnet/dpo/receive_dpo.h>
56 : #include <vnet/dpo/classify_dpo.h>
57 : #include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
58 : #include <vnet/adj/adj_dp.h>
59 : #include <vnet/pg/pg.h>
60 :
61 : #include <vnet/ip/ip4_forward.h>
62 : #include <vnet/interface_output.h>
63 : #include <vnet/classify/vnet_classify.h>
64 : #include <vnet/ip/reass/ip4_full_reass.h>
65 :
66 : /** @brief IPv4 lookup node.
67 : @node ip4-lookup
68 :
69 : This is the main IPv4 lookup dispatch node.
70 :
71 : @param vm vlib_main_t corresponding to the current thread
72 : @param node vlib_node_runtime_t
73 : @param frame vlib_frame_t whose contents should be dispatched
74 :
75 : @par Graph mechanics: buffer metadata, next index usage
76 :
77 : @em Uses:
78 : - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
79 : - Indicates the @c sw_if_index value of the interface that the
80 : packet was received on.
81 : - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
82 : - When the value is @c ~0 then the node performs a longest prefix
83 : match (LPM) for the packet destination address in the FIB attached
84 : to the receive interface.
85 : - Otherwise perform LPM for the packet destination address in the
86 : indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
87 : value (0, 1, ...) and not a VRF id.
88 :
89 : @em Sets:
90 : - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
91 : - The lookup result adjacency index.
92 :
93 : <em>Next Index:</em>
94 : - Dispatches the packet to the node index found in
95 : ip_adjacency_t @c adj->lookup_next_index
96 : (where @c adj is the lookup result adjacency).
97 : */
98 281900 : VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
99 : vlib_frame_t * frame)
100 : {
101 279664 : return ip4_lookup_inline (vm, node, frame);
102 : }
103 :
104 : static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
105 :
106 : /* *INDENT-OFF* */
107 178120 : VLIB_REGISTER_NODE (ip4_lookup_node) =
108 : {
109 : .name = "ip4-lookup",
110 : .vector_size = sizeof (u32),
111 : .format_trace = format_ip4_lookup_trace,
112 : .n_next_nodes = IP_LOOKUP_N_NEXT,
113 : .next_nodes = IP4_LOOKUP_NEXT_NODES,
114 : };
115 : /* *INDENT-ON* */
116 :
117 7427 : VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
118 : vlib_node_runtime_t * node,
119 : vlib_frame_t * frame)
120 : {
121 5191 : vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
122 : u32 n_left, *from;
123 5191 : u32 thread_index = vm->thread_index;
124 5191 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
125 : u16 nexts[VLIB_FRAME_SIZE], *next;
126 :
127 5191 : from = vlib_frame_vector_args (frame);
128 5191 : n_left = frame->n_vectors;
129 5191 : next = nexts;
130 :
131 5191 : vlib_get_buffers (vm, from, bufs, n_left);
132 :
133 99482 : while (n_left >= 4)
134 : {
135 : const load_balance_t *lb0, *lb1;
136 : const ip4_header_t *ip0, *ip1;
137 : u32 lbi0, hc0, lbi1, hc1;
138 : const dpo_id_t *dpo0, *dpo1;
139 :
140 : /* Prefetch next iteration. */
141 : {
142 94291 : vlib_prefetch_buffer_header (b[2], LOAD);
143 94291 : vlib_prefetch_buffer_header (b[3], LOAD);
144 :
145 94293 : CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
146 94293 : CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
147 : }
148 :
149 94293 : ip0 = vlib_buffer_get_current (b[0]);
150 94297 : ip1 = vlib_buffer_get_current (b[1]);
151 94297 : lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
152 94297 : lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
153 :
154 94297 : lb0 = load_balance_get (lbi0);
155 94291 : lb1 = load_balance_get (lbi1);
156 :
157 : /*
158 : * this node is for via FIBs we can re-use the hash value from the
159 : * to node if present.
160 : * We don't want to use the same hash value at each level in the recursion
161 : * graph as that would lead to polarisation
162 : */
163 94291 : hc0 = hc1 = 0;
164 :
165 94291 : if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
166 : {
167 870 : if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
168 : {
169 584 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
170 584 : vnet_buffer (b[0])->ip.flow_hash >> 1;
171 : }
172 : else
173 : {
174 286 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
175 286 : ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
176 : }
177 870 : dpo0 = load_balance_get_fwd_bucket
178 870 : (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
179 : }
180 : else
181 : {
182 93421 : dpo0 = load_balance_get_bucket_i (lb0, 0);
183 : }
184 94291 : if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
185 : {
186 855 : if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
187 : {
188 569 : hc1 = vnet_buffer (b[1])->ip.flow_hash =
189 569 : vnet_buffer (b[1])->ip.flow_hash >> 1;
190 : }
191 : else
192 : {
193 286 : hc1 = vnet_buffer (b[1])->ip.flow_hash =
194 286 : ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
195 : }
196 855 : dpo1 = load_balance_get_fwd_bucket
197 855 : (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
198 : }
199 : else
200 : {
201 93436 : dpo1 = load_balance_get_bucket_i (lb1, 0);
202 : }
203 :
204 94291 : next[0] = dpo0->dpoi_next_node;
205 94291 : next[1] = dpo1->dpoi_next_node;
206 :
207 94291 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
208 94291 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
209 :
210 94291 : vlib_increment_combined_counter
211 : (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
212 94291 : vlib_increment_combined_counter
213 94291 : (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
214 :
215 94291 : b += 2;
216 94291 : next += 2;
217 94291 : n_left -= 2;
218 : }
219 :
220 16508 : while (n_left > 0)
221 : {
222 : const load_balance_t *lb0;
223 : const ip4_header_t *ip0;
224 : const dpo_id_t *dpo0;
225 : u32 lbi0, hc0;
226 :
227 11317 : ip0 = vlib_buffer_get_current (b[0]);
228 11317 : lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
229 :
230 11317 : lb0 = load_balance_get (lbi0);
231 :
232 11317 : hc0 = 0;
233 11317 : if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
234 : {
235 22 : if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
236 : {
237 13 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
238 13 : vnet_buffer (b[0])->ip.flow_hash >> 1;
239 : }
240 : else
241 : {
242 9 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
243 9 : ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
244 : }
245 22 : dpo0 = load_balance_get_fwd_bucket
246 22 : (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
247 : }
248 : else
249 : {
250 11295 : dpo0 = load_balance_get_bucket_i (lb0, 0);
251 : }
252 :
253 11317 : next[0] = dpo0->dpoi_next_node;
254 11317 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
255 :
256 11317 : vlib_increment_combined_counter
257 : (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
258 :
259 11317 : b += 1;
260 11317 : next += 1;
261 11317 : n_left -= 1;
262 : }
263 :
264 5191 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
265 5191 : if (node->flags & VLIB_NODE_FLAG_TRACE)
266 4158 : ip4_forward_next_trace (vm, node, frame, VLIB_TX);
267 :
268 5191 : return frame->n_vectors;
269 : }
270 :
271 : /* *INDENT-OFF* */
272 178120 : VLIB_REGISTER_NODE (ip4_load_balance_node) =
273 : {
274 : .name = "ip4-load-balance",
275 : .vector_size = sizeof (u32),
276 : .sibling_of = "ip4-lookup",
277 : .format_trace = format_ip4_lookup_trace,
278 : };
279 : /* *INDENT-ON* */
280 :
281 : #ifndef CLIB_MARCH_VARIANT
282 : /* get first interface address */
283 : ip4_address_t *
284 52 : ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
285 : ip_interface_address_t ** result_ia)
286 : {
287 52 : ip_lookup_main_t *lm = &im->lookup_main;
288 52 : ip_interface_address_t *ia = 0;
289 52 : ip4_address_t *result = 0;
290 :
291 : /* *INDENT-OFF* */
292 52 : foreach_ip_interface_address
293 : (lm, ia, sw_if_index,
294 : 1 /* honor unnumbered */ ,
295 : ({
296 : ip4_address_t * a =
297 : ip_interface_address_get_address (lm, ia);
298 : result = a;
299 : break;
300 : }));
301 : /* *INDENT-OFF* */
302 52 : if (result_ia)
303 0 : *result_ia = result ? ia : 0;
304 52 : return result;
305 : }
306 : #endif
307 :
308 : static void
309 2438 : ip4_add_subnet_bcast_route (u32 fib_index,
310 : fib_prefix_t *pfx,
311 : u32 sw_if_index)
312 : {
313 : vnet_sw_interface_flags_t iflags;
314 :
315 2438 : iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
316 :
317 2438 : fib_table_entry_special_remove(fib_index,
318 : pfx,
319 : FIB_SOURCE_INTERFACE);
320 :
321 2438 : if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
322 : {
323 2 : fib_table_entry_update_one_path (fib_index, pfx,
324 : FIB_SOURCE_INTERFACE,
325 : FIB_ENTRY_FLAG_NONE,
326 : DPO_PROTO_IP4,
327 : /* No next-hop address */
328 : &ADJ_BCAST_ADDR,
329 : sw_if_index,
330 : // invalid FIB index
331 : ~0,
332 : 1,
333 : // no out-label stack
334 : NULL,
335 : FIB_ROUTE_PATH_FLAG_NONE);
336 : }
337 : else
338 : {
339 2436 : fib_table_entry_special_add(fib_index,
340 : pfx,
341 : FIB_SOURCE_INTERFACE,
342 : (FIB_ENTRY_FLAG_DROP |
343 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
344 : }
345 2438 : }
346 :
347 : static void
348 2503 : ip4_add_interface_prefix_routes (ip4_main_t *im,
349 : u32 sw_if_index,
350 : u32 fib_index,
351 : ip_interface_address_t * a)
352 : {
353 2503 : ip_lookup_main_t *lm = &im->lookup_main;
354 : ip_interface_prefix_t *if_prefix;
355 2503 : ip4_address_t *address = ip_interface_address_get_address (lm, a);
356 :
357 2503 : ip_interface_prefix_key_t key = {
358 : .prefix = {
359 2503 : .fp_len = a->address_length,
360 : .fp_proto = FIB_PROTOCOL_IP4,
361 2503 : .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
362 : },
363 : .sw_if_index = sw_if_index,
364 : };
365 :
366 2503 : fib_prefix_t pfx_special = {
367 : .fp_proto = FIB_PROTOCOL_IP4,
368 : };
369 :
370 : /* If prefix already set on interface, just increment ref count & return */
371 2503 : if_prefix = ip_get_interface_prefix (lm, &key);
372 2503 : if (if_prefix)
373 : {
374 13 : if_prefix->ref_count += 1;
375 13 : return;
376 : }
377 :
378 : /* New prefix - allocate a pool entry, initialize it, add to the hash */
379 2490 : pool_get (lm->if_prefix_pool, if_prefix);
380 2490 : if_prefix->ref_count = 1;
381 2490 : if_prefix->src_ia_index = a - lm->if_address_pool;
382 2490 : clib_memcpy (&if_prefix->key, &key, sizeof (key));
383 2490 : mhash_set (&lm->prefix_to_if_prefix_index, &key,
384 2490 : if_prefix - lm->if_prefix_pool, 0 /* old value */);
385 :
386 2490 : pfx_special.fp_len = a->address_length;
387 2490 : pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
388 :
389 : /* set the glean route for the prefix */
390 2490 : fib_table_entry_update_one_path (fib_index, &pfx_special,
391 : FIB_SOURCE_INTERFACE,
392 : (FIB_ENTRY_FLAG_CONNECTED |
393 : FIB_ENTRY_FLAG_ATTACHED),
394 : DPO_PROTO_IP4,
395 : /* No next-hop address */
396 : NULL,
397 : sw_if_index,
398 : /* invalid FIB index */
399 : ~0,
400 : 1,
401 : /* no out-label stack */
402 : NULL,
403 : FIB_ROUTE_PATH_FLAG_NONE);
404 :
405 : /* length <= 30 - add glean, drop first address, maybe drop bcast address */
406 2490 : if (a->address_length <= 30)
407 : {
408 : /* set a drop route for the base address of the prefix */
409 2436 : pfx_special.fp_len = 32;
410 2436 : pfx_special.fp_addr.ip4.as_u32 =
411 2436 : address->as_u32 & im->fib_masks[a->address_length];
412 :
413 2436 : if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
414 2434 : fib_table_entry_special_add (fib_index, &pfx_special,
415 : FIB_SOURCE_INTERFACE,
416 : (FIB_ENTRY_FLAG_DROP |
417 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
418 :
419 : /* set a route for the broadcast address of the prefix */
420 2436 : pfx_special.fp_len = 32;
421 2436 : pfx_special.fp_addr.ip4.as_u32 =
422 2436 : address->as_u32 | ~im->fib_masks[a->address_length];
423 2436 : if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
424 2436 : ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
425 :
426 :
427 : }
428 : /* length == 31 - add an attached route for the other address */
429 54 : else if (a->address_length == 31)
430 : {
431 1 : pfx_special.fp_len = 32;
432 1 : pfx_special.fp_addr.ip4.as_u32 =
433 1 : address->as_u32 ^ clib_host_to_net_u32(1);
434 :
435 1 : fib_table_entry_update_one_path (fib_index, &pfx_special,
436 : FIB_SOURCE_INTERFACE,
437 : (FIB_ENTRY_FLAG_ATTACHED),
438 : DPO_PROTO_IP4,
439 : &pfx_special.fp_addr,
440 : sw_if_index,
441 : /* invalid FIB index */
442 : ~0,
443 : 1,
444 : NULL,
445 : FIB_ROUTE_PATH_FLAG_NONE);
446 : }
447 : }
448 :
449 : static void
450 2503 : ip4_add_interface_routes (u32 sw_if_index,
451 : ip4_main_t * im, u32 fib_index,
452 : ip_interface_address_t * a)
453 : {
454 2503 : ip_lookup_main_t *lm = &im->lookup_main;
455 2503 : ip4_address_t *address = ip_interface_address_get_address (lm, a);
456 2503 : fib_prefix_t pfx = {
457 : .fp_len = 32,
458 : .fp_proto = FIB_PROTOCOL_IP4,
459 : .fp_addr.ip4 = *address,
460 : };
461 :
462 : /* set special routes for the prefix if needed */
463 2503 : ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
464 :
465 2503 : if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
466 : {
467 0 : u32 classify_table_index =
468 0 : lm->classify_table_index_by_sw_if_index[sw_if_index];
469 0 : if (classify_table_index != (u32) ~ 0)
470 : {
471 0 : dpo_id_t dpo = DPO_INVALID;
472 :
473 0 : dpo_set (&dpo,
474 : DPO_CLASSIFY,
475 : DPO_PROTO_IP4,
476 : classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
477 :
478 0 : fib_table_entry_special_dpo_add (fib_index,
479 : &pfx,
480 : FIB_SOURCE_CLASSIFY,
481 : FIB_ENTRY_FLAG_NONE, &dpo);
482 0 : dpo_reset (&dpo);
483 : }
484 : }
485 :
486 2503 : fib_table_entry_update_one_path (fib_index, &pfx,
487 : FIB_SOURCE_INTERFACE,
488 : (FIB_ENTRY_FLAG_CONNECTED |
489 : FIB_ENTRY_FLAG_LOCAL),
490 : DPO_PROTO_IP4,
491 : &pfx.fp_addr,
492 : sw_if_index,
493 : // invalid FIB index
494 : ~0,
495 : 1, NULL,
496 : FIB_ROUTE_PATH_FLAG_NONE);
497 2503 : }
498 :
499 : static void
500 2256 : ip4_del_interface_prefix_routes (ip4_main_t * im,
501 : u32 sw_if_index,
502 : u32 fib_index,
503 : ip4_address_t * address,
504 : u32 address_length)
505 : {
506 2256 : ip_lookup_main_t *lm = &im->lookup_main;
507 : ip_interface_prefix_t *if_prefix;
508 :
509 2256 : ip_interface_prefix_key_t key = {
510 : .prefix = {
511 : .fp_len = address_length,
512 : .fp_proto = FIB_PROTOCOL_IP4,
513 2256 : .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
514 : },
515 : .sw_if_index = sw_if_index,
516 : };
517 :
518 2256 : fib_prefix_t pfx_special = {
519 : .fp_len = 32,
520 : .fp_proto = FIB_PROTOCOL_IP4,
521 : };
522 :
523 2256 : if_prefix = ip_get_interface_prefix (lm, &key);
524 2256 : if (!if_prefix)
525 : {
526 0 : clib_warning ("Prefix not found while deleting %U",
527 : format_ip4_address_and_length, address, address_length);
528 13 : return;
529 : }
530 :
531 2256 : if_prefix->ref_count -= 1;
532 :
533 : /*
534 : * Routes need to be adjusted if deleting last intf addr in prefix
535 : *
536 : * We're done now otherwise
537 : */
538 2256 : if (if_prefix->ref_count > 0)
539 13 : return;
540 :
541 : /* length <= 30, delete glean route, first address, last address */
542 2243 : if (address_length <= 30)
543 : {
544 : /* Less work to do in FIB if we remove the covered /32s first */
545 :
546 : /* first address in prefix */
547 2190 : pfx_special.fp_addr.ip4.as_u32 =
548 2190 : address->as_u32 & im->fib_masks[address_length];
549 2190 : pfx_special.fp_len = 32;
550 :
551 2190 : if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
552 2188 : fib_table_entry_special_remove (fib_index,
553 : &pfx_special,
554 : FIB_SOURCE_INTERFACE);
555 :
556 : /* prefix broadcast address */
557 2190 : pfx_special.fp_addr.ip4.as_u32 =
558 2190 : address->as_u32 | ~im->fib_masks[address_length];
559 2190 : pfx_special.fp_len = 32;
560 :
561 2190 : if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
562 2190 : fib_table_entry_special_remove (fib_index,
563 : &pfx_special,
564 : FIB_SOURCE_INTERFACE);
565 : }
566 53 : else if (address_length == 31)
567 : {
568 : /* length == 31, delete attached route for the other address */
569 1 : pfx_special.fp_addr.ip4.as_u32 =
570 1 : address->as_u32 ^ clib_host_to_net_u32(1);
571 :
572 1 : fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
573 : }
574 :
575 : /* remove glean route for prefix */
576 2243 : pfx_special.fp_addr.ip4 = *address;
577 2243 : pfx_special.fp_len = address_length;
578 2243 : fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
579 :
580 2243 : mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
581 2243 : pool_put (lm->if_prefix_pool, if_prefix);
582 : }
583 :
584 : static void
585 2256 : ip4_del_interface_routes (u32 sw_if_index,
586 : ip4_main_t * im,
587 : u32 fib_index,
588 : ip4_address_t * address, u32 address_length)
589 : {
590 2256 : fib_prefix_t pfx = {
591 : .fp_len = 32,
592 : .fp_proto = FIB_PROTOCOL_IP4,
593 : .fp_addr.ip4 = *address,
594 : };
595 :
596 2256 : fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
597 :
598 2256 : ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
599 : address, address_length);
600 2256 : }
601 :
602 : #ifndef CLIB_MARCH_VARIANT
603 : void
604 4750 : ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
605 : {
606 4750 : ip4_main_t *im = &ip4_main;
607 4750 : vnet_main_t *vnm = vnet_get_main ();
608 4750 : vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
609 :
610 6629 : vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
611 :
612 : /*
613 : * enable/disable only on the 1<->0 transition
614 : */
615 4750 : if (is_enable)
616 : {
617 2505 : if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
618 42 : return;
619 : }
620 : else
621 : {
622 2245 : ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
623 2245 : if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
624 37 : return;
625 : }
626 4671 : vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
627 : !is_enable, 0, 0);
628 :
629 :
630 4671 : vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
631 : sw_if_index, !is_enable, 0, 0);
632 :
633 4671 : if (is_enable)
634 2463 : hi->l3_if_count++;
635 2208 : else if (hi->l3_if_count)
636 2208 : hi->l3_if_count--;
637 :
638 : {
639 : ip4_enable_disable_interface_callback_t *cb;
640 9342 : vec_foreach (cb, im->enable_disable_interface_callbacks)
641 4671 : cb->function (im, cb->function_opaque, sw_if_index, is_enable);
642 : }
643 : }
644 :
645 : static clib_error_t *
646 4706 : ip4_add_del_interface_address_internal (vlib_main_t * vm,
647 : u32 sw_if_index,
648 : ip4_address_t * address,
649 : u32 address_length, u32 is_del)
650 : {
651 4706 : vnet_main_t *vnm = vnet_get_main ();
652 4706 : ip4_main_t *im = &ip4_main;
653 4706 : ip_lookup_main_t *lm = &im->lookup_main;
654 4706 : clib_error_t *error = 0;
655 : u32 if_address_index;
656 4706 : ip4_address_fib_t ip4_af, *addr_fib = 0;
657 :
658 4706 : error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
659 4706 : if (error)
660 : {
661 0 : vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
662 0 : return error;
663 : }
664 :
665 4706 : ip4_addr_fib_init (&ip4_af, address,
666 4706 : vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
667 4706 : vec_add1 (addr_fib, ip4_af);
668 :
669 : /*
670 : * there is no support for adj-fib handling in the presence of overlapping
671 : * subnets on interfaces. Easy fix - disallow overlapping subnets, like
672 : * most routers do.
673 : */
674 : /* *INDENT-OFF* */
675 4706 : if (!is_del)
676 : {
677 : /* When adding an address check that it does not conflict
678 : with an existing address on any interface in this table. */
679 : ip_interface_address_t *ia;
680 : vnet_sw_interface_t *sif;
681 :
682 15711 : pool_foreach (sif, vnm->interface_main.sw_interfaces)
683 : {
684 13229 : if (im->fib_index_by_sw_if_index[sw_if_index] ==
685 13229 : im->fib_index_by_sw_if_index[sif->sw_if_index])
686 : {
687 15189 : foreach_ip_interface_address
688 : (&im->lookup_main, ia, sif->sw_if_index,
689 : 0 /* honor unnumbered */ ,
690 : ({
691 : ip4_address_t * x =
692 : ip_interface_address_get_address
693 : (&im->lookup_main, ia);
694 :
695 : if (ip4_destination_matches_route
696 : (im, address, x, ia->address_length) ||
697 : ip4_destination_matches_route (im,
698 : x,
699 : address,
700 : address_length))
701 : {
702 : /* an intf may have >1 addr from the same prefix */
703 : if ((sw_if_index == sif->sw_if_index) &&
704 : (ia->address_length == address_length) &&
705 : (x->as_u32 != address->as_u32))
706 : continue;
707 :
708 : if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
709 : /* if the address we're comparing against is stale
710 : * then the CP has not added this one back yet, maybe
711 : * it never will, so we have to assume it won't and
712 : * ignore it. if it does add it back, then it will fail
713 : * because this one is now present */
714 : continue;
715 :
716 : /* error if the length or intf was different */
717 : vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
718 :
719 : error = clib_error_create
720 : ("failed to add %U on %U which conflicts with %U for interface %U",
721 : format_ip4_address_and_length, address,
722 : address_length,
723 : format_vnet_sw_if_index_name, vnm,
724 : sw_if_index,
725 : format_ip4_address_and_length, x,
726 : ia->address_length,
727 : format_vnet_sw_if_index_name, vnm,
728 : sif->sw_if_index);
729 : goto done;
730 : }
731 : }));
732 : }
733 : }
734 : }
735 : /* *INDENT-ON* */
736 :
737 4706 : if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
738 :
739 4706 : if (is_del)
740 : {
741 2224 : if (~0 == if_address_index)
742 : {
743 0 : vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
744 0 : error = clib_error_create ("%U not found for interface %U",
745 : lm->format_address_and_length,
746 : addr_fib, address_length,
747 : format_vnet_sw_if_index_name, vnm,
748 : sw_if_index);
749 0 : goto done;
750 : }
751 :
752 2224 : error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
753 : address_length, sw_if_index);
754 2224 : if (error)
755 1 : goto done;
756 : }
757 : else
758 : {
759 2482 : if (~0 != if_address_index)
760 : {
761 : ip_interface_address_t *ia;
762 :
763 9 : ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
764 :
765 9 : if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
766 : {
767 9 : if (ia->sw_if_index == sw_if_index)
768 : {
769 : /* re-adding an address during the replace action.
770 : * consdier this the update. clear the flag and
771 : * we're done */
772 6 : ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
773 6 : goto done;
774 : }
775 : else
776 : {
777 : /* The prefix is moving from one interface to another.
778 : * delete the stale and add the new */
779 3 : ip4_add_del_interface_address_internal (vm,
780 : ia->sw_if_index,
781 : address,
782 : address_length, 1);
783 3 : ia = NULL;
784 3 : error = ip_interface_address_add (lm, sw_if_index,
785 : addr_fib, address_length,
786 : &if_address_index);
787 : }
788 : }
789 : else
790 : {
791 0 : vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
792 0 : error = clib_error_create
793 : ("Prefix %U already found on interface %U",
794 : lm->format_address_and_length, addr_fib, address_length,
795 : format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
796 : }
797 : }
798 : else
799 2473 : error = ip_interface_address_add (lm, sw_if_index,
800 : addr_fib, address_length,
801 : &if_address_index);
802 : }
803 :
804 4699 : if (error)
805 0 : goto done;
806 :
807 4699 : ip4_sw_interface_enable_disable (sw_if_index, !is_del);
808 4699 : ip4_mfib_interface_enable_disable (sw_if_index, !is_del);
809 :
810 : /* intf addr routes are added/deleted on admin up/down */
811 4699 : if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
812 : {
813 3474 : if (is_del)
814 1110 : ip4_del_interface_routes (sw_if_index,
815 : im, ip4_af.fib_index, address,
816 : address_length);
817 : else
818 2364 : ip4_add_interface_routes (sw_if_index,
819 : im, ip4_af.fib_index,
820 2364 : pool_elt_at_index
821 : (lm->if_address_pool, if_address_index));
822 : }
823 :
824 : ip4_add_del_interface_address_callback_t *cb;
825 47006 : vec_foreach (cb, im->add_del_interface_address_callbacks)
826 42307 : cb->function (im, cb->function_opaque, sw_if_index,
827 : address, address_length, if_address_index, is_del);
828 :
829 4699 : done:
830 4706 : vec_free (addr_fib);
831 4706 : return error;
832 : }
833 :
834 : clib_error_t *
835 4703 : ip4_add_del_interface_address (vlib_main_t * vm,
836 : u32 sw_if_index,
837 : ip4_address_t * address,
838 : u32 address_length, u32 is_del)
839 : {
840 4703 : return ip4_add_del_interface_address_internal
841 : (vm, sw_if_index, address, address_length, is_del);
842 : }
843 :
844 : void
845 3 : ip4_directed_broadcast (u32 sw_if_index, u8 enable)
846 : {
847 : ip_interface_address_t *ia;
848 : ip4_main_t *im;
849 :
850 3 : im = &ip4_main;
851 :
852 : /*
853 : * when directed broadcast is enabled, the subnet braodcast route will forward
854 : * packets using an adjacency with a broadcast MAC. otherwise it drops
855 : */
856 : /* *INDENT-OFF* */
857 5 : foreach_ip_interface_address(&im->lookup_main, ia,
858 : sw_if_index, 0,
859 : ({
860 : if (ia->address_length <= 30)
861 : {
862 : ip4_address_t *ipa;
863 :
864 : ipa = ip_interface_address_get_address (&im->lookup_main, ia);
865 :
866 : fib_prefix_t pfx = {
867 : .fp_len = 32,
868 : .fp_proto = FIB_PROTOCOL_IP4,
869 : .fp_addr = {
870 : .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
871 : },
872 : };
873 :
874 : ip4_add_subnet_bcast_route
875 : (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
876 : sw_if_index),
877 : &pfx, sw_if_index);
878 : }
879 : }));
880 : /* *INDENT-ON* */
881 3 : }
882 : #endif
883 :
884 : static clib_error_t *
885 13268 : ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
886 : {
887 13268 : ip4_main_t *im = &ip4_main;
888 : ip_interface_address_t *ia;
889 : ip4_address_t *a;
890 : u32 is_admin_up, fib_index;
891 :
892 13268 : vec_validate_init_empty (im->
893 : lookup_main.if_address_pool_index_by_sw_if_index,
894 : sw_if_index, ~0);
895 :
896 13268 : is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
897 :
898 13268 : fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
899 :
900 : /* *INDENT-OFF* */
901 14553 : foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
902 : 0 /* honor unnumbered */,
903 : ({
904 : a = ip_interface_address_get_address (&im->lookup_main, ia);
905 : if (is_admin_up)
906 : ip4_add_interface_routes (sw_if_index,
907 : im, fib_index,
908 : ia);
909 : else
910 : ip4_del_interface_routes (sw_if_index,
911 : im, fib_index,
912 : a, ia->address_length);
913 : }));
914 : /* *INDENT-ON* */
915 :
916 13268 : return 0;
917 : }
918 :
919 2801 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
920 :
921 : /* Built-in ip4 unicast rx feature path definition */
922 : /* *INDENT-OFF* */
923 1119 : VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
924 : {
925 : .arc_name = "ip4-unicast",
926 : .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
927 : .last_in_arc = "ip4-lookup",
928 : .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
929 : };
930 :
931 70583 : VNET_FEATURE_INIT (ip4_flow_classify, static) =
932 : {
933 : .arc_name = "ip4-unicast",
934 : .node_name = "ip4-flow-classify",
935 : .runs_before = VNET_FEATURES ("ip4-inacl"),
936 : };
937 :
938 70583 : VNET_FEATURE_INIT (ip4_inacl, static) =
939 : {
940 : .arc_name = "ip4-unicast",
941 : .node_name = "ip4-inacl",
942 : .runs_before = VNET_FEATURES ("ip4-policer-classify"),
943 : };
944 :
945 70583 : VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
946 : {
947 : .arc_name = "ip4-unicast",
948 : .node_name = "ip4-source-and-port-range-check-rx",
949 : .runs_before = VNET_FEATURES ("ip4-policer-classify"),
950 : };
951 :
952 70583 : VNET_FEATURE_INIT (ip4_policer_classify, static) =
953 : {
954 : .arc_name = "ip4-unicast",
955 : .node_name = "ip4-policer-classify",
956 : .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
957 : };
958 :
959 70583 : VNET_FEATURE_INIT (ip4_ipsec, static) =
960 : {
961 : .arc_name = "ip4-unicast",
962 : .node_name = "ipsec4-input-feature",
963 : .runs_before = VNET_FEATURES ("vpath-input-ip4"),
964 : };
965 :
966 70583 : VNET_FEATURE_INIT (ip4_vpath, static) =
967 : {
968 : .arc_name = "ip4-unicast",
969 : .node_name = "vpath-input-ip4",
970 : .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
971 : };
972 :
973 70583 : VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
974 : {
975 : .arc_name = "ip4-unicast",
976 : .node_name = "ip4-vxlan-bypass",
977 : .runs_before = VNET_FEATURES ("ip4-lookup"),
978 : };
979 :
980 70583 : VNET_FEATURE_INIT (ip4_not_enabled, static) =
981 : {
982 : .arc_name = "ip4-unicast",
983 : .node_name = "ip4-not-enabled",
984 : .runs_before = VNET_FEATURES ("ip4-lookup"),
985 : };
986 :
987 70583 : VNET_FEATURE_INIT (ip4_lookup, static) =
988 : {
989 : .arc_name = "ip4-unicast",
990 : .node_name = "ip4-lookup",
991 : .runs_before = 0, /* not before any other features */
992 : };
993 :
994 : /* Built-in ip4 multicast rx feature path definition */
995 1119 : VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
996 : {
997 : .arc_name = "ip4-multicast",
998 : .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
999 : .last_in_arc = "ip4-mfib-forward-lookup",
1000 : .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1001 : };
1002 :
1003 70583 : VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1004 : {
1005 : .arc_name = "ip4-multicast",
1006 : .node_name = "vpath-input-ip4",
1007 : .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1008 : };
1009 :
1010 70583 : VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
1011 : {
1012 : .arc_name = "ip4-multicast",
1013 : .node_name = "ip4-not-enabled",
1014 : .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1015 : };
1016 :
1017 70583 : VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1018 : {
1019 : .arc_name = "ip4-multicast",
1020 : .node_name = "ip4-mfib-forward-lookup",
1021 : .runs_before = 0, /* last feature */
1022 : };
1023 :
1024 : /* Source and port-range check ip4 tx feature path definition */
1025 1119 : VNET_FEATURE_ARC_INIT (ip4_output, static) =
1026 : {
1027 : .arc_name = "ip4-output",
1028 : .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
1029 : .last_in_arc = "interface-output",
1030 : .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1031 : };
1032 :
1033 70583 : VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1034 : {
1035 : .arc_name = "ip4-output",
1036 : .node_name = "ip4-source-and-port-range-check-tx",
1037 : .runs_before = VNET_FEATURES ("ip4-outacl"),
1038 : };
1039 :
1040 70583 : VNET_FEATURE_INIT (ip4_outacl, static) =
1041 : {
1042 : .arc_name = "ip4-output",
1043 : .node_name = "ip4-outacl",
1044 : .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
1045 : };
1046 :
1047 70583 : VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1048 : {
1049 : .arc_name = "ip4-output",
1050 : .node_name = "ipsec4-output-feature",
1051 : .runs_before = VNET_FEATURES ("interface-output"),
1052 : };
1053 :
1054 : /* Built-in ip4 tx feature path definition */
1055 70583 : VNET_FEATURE_INIT (ip4_interface_output, static) =
1056 : {
1057 : .arc_name = "ip4-output",
1058 : .node_name = "interface-output",
1059 : .runs_before = 0, /* not before any other features */
1060 : };
1061 : /* *INDENT-ON* */
1062 :
1063 : static clib_error_t *
1064 11597 : ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1065 : {
1066 11597 : ip4_main_t *im = &ip4_main;
1067 :
1068 15494 : vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
1069 15494 : vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
1070 :
1071 11597 : if (is_add)
1072 : {
1073 : /* Fill in lookup tables with default table (0). */
1074 7418 : im->fib_index_by_sw_if_index[sw_if_index] = 0;
1075 7418 : im->mfib_index_by_sw_if_index[sw_if_index] = 0;
1076 : }
1077 : else
1078 : {
1079 4179 : ip4_main_t *im4 = &ip4_main;
1080 4179 : ip_lookup_main_t *lm4 = &im4->lookup_main;
1081 4179 : ip_interface_address_t *ia = 0;
1082 : ip4_address_t *address;
1083 4179 : vlib_main_t *vm = vlib_get_main ();
1084 :
1085 4179 : vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
1086 : /* *INDENT-OFF* */
1087 4179 : foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
1088 : ({
1089 : address = ip_interface_address_get_address (lm4, ia);
1090 : ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1091 : }));
1092 : /* *INDENT-ON* */
1093 4179 : ip4_mfib_interface_enable_disable (sw_if_index, 0);
1094 :
1095 4179 : if (0 != im4->fib_index_by_sw_if_index[sw_if_index])
1096 84 : fib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1097 4179 : if (0 != im4->mfib_index_by_sw_if_index[sw_if_index])
1098 84 : mfib_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0);
1099 :
1100 : /* Erase the lookup tables just in case */
1101 4179 : im4->fib_index_by_sw_if_index[sw_if_index] = ~0;
1102 4179 : im4->mfib_index_by_sw_if_index[sw_if_index] = ~0;
1103 : }
1104 :
1105 11597 : vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
1106 : is_add, 0, 0);
1107 :
1108 11597 : vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1109 : sw_if_index, is_add, 0, 0);
1110 :
1111 11597 : return /* no error */ 0;
1112 : }
1113 :
1114 3363 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1115 :
1116 : /* Global IP4 main. */
1117 : #ifndef CLIB_MARCH_VARIANT
1118 : ip4_main_t ip4_main;
1119 : #endif /* CLIB_MARCH_VARIANT */
1120 :
1121 : static clib_error_t *
1122 559 : ip4_lookup_init (vlib_main_t * vm)
1123 : {
1124 559 : ip4_main_t *im = &ip4_main;
1125 : clib_error_t *error;
1126 : uword i;
1127 :
1128 559 : if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1129 0 : return error;
1130 559 : if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1131 0 : return (error);
1132 559 : if ((error = vlib_call_init_function (vm, fib_module_init)))
1133 0 : return error;
1134 559 : if ((error = vlib_call_init_function (vm, mfib_module_init)))
1135 0 : return error;
1136 :
1137 19006 : for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1138 : {
1139 : u32 m;
1140 :
1141 18447 : if (i < 32)
1142 17888 : m = pow2_mask (i) << (32 - i);
1143 : else
1144 559 : m = ~0;
1145 18447 : im->fib_masks[i] = clib_host_to_net_u32 (m);
1146 : }
1147 :
1148 559 : ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1149 :
1150 : /* Create FIB with index 0 and table id of 0. */
1151 559 : fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1152 : FIB_SOURCE_DEFAULT_ROUTE);
1153 559 : mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1154 : MFIB_SOURCE_DEFAULT_ROUTE);
1155 :
1156 : {
1157 : pg_node_t *pn;
1158 559 : pn = pg_get_node (ip4_lookup_node.index);
1159 559 : pn->unformat_edit = unformat_pg_ip4_header;
1160 : }
1161 :
1162 : {
1163 : ethernet_arp_header_t h;
1164 :
1165 559 : clib_memset (&h, 0, sizeof (h));
1166 :
1167 : #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1168 : #define _8(f,v) h.f = v;
1169 559 : _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1170 559 : _16 (l3_type, ETHERNET_TYPE_IP4);
1171 559 : _8 (n_l2_address_bytes, 6);
1172 559 : _8 (n_l3_address_bytes, 4);
1173 559 : _16 (opcode, ETHERNET_ARP_OPCODE_request);
1174 : #undef _16
1175 : #undef _8
1176 :
1177 559 : vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
1178 : /* data */ &h,
1179 : sizeof (h),
1180 : /* alloc chunk size */ 8,
1181 : "ip4 arp");
1182 : }
1183 :
1184 559 : return error;
1185 : }
1186 :
1187 12879 : VLIB_INIT_FUNCTION (ip4_lookup_init);
1188 :
1189 : typedef struct
1190 : {
1191 : /* Adjacency taken. */
1192 : u32 dpo_index;
1193 : u32 flow_hash;
1194 : u32 fib_index;
1195 :
1196 : /* Packet data, possibly *after* rewrite. */
1197 : u8 packet_data[64 - 1 * sizeof (u32)];
1198 : }
1199 : ip4_forward_next_trace_t;
1200 :
1201 : #ifndef CLIB_MARCH_VARIANT
1202 : u8 *
1203 112852 : format_ip4_forward_next_trace (u8 * s, va_list * args)
1204 : {
1205 112852 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1206 112852 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1207 112852 : ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1208 112852 : u32 indent = format_get_indent (s);
1209 112852 : s = format (s, "%U%U",
1210 : format_white_space, indent,
1211 112852 : format_ip4_header, t->packet_data, sizeof (t->packet_data));
1212 112852 : return s;
1213 : }
1214 : #endif
1215 :
1216 : static u8 *
1217 319400 : format_ip4_lookup_trace (u8 * s, va_list * args)
1218 : {
1219 319400 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1220 319400 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1221 319400 : ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1222 319400 : u32 indent = format_get_indent (s);
1223 :
1224 319400 : s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1225 : t->fib_index, t->dpo_index, t->flow_hash);
1226 319400 : s = format (s, "\n%U%U",
1227 : format_white_space, indent,
1228 319400 : format_ip4_header, t->packet_data, sizeof (t->packet_data));
1229 319400 : return s;
1230 : }
1231 :
1232 : static u8 *
1233 205229 : format_ip4_rewrite_trace (u8 * s, va_list * args)
1234 : {
1235 205229 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1236 205229 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1237 205229 : ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1238 205229 : u32 indent = format_get_indent (s);
1239 :
1240 205229 : s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
1241 : t->fib_index, t->dpo_index, format_ip_adjacency,
1242 : t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1243 205229 : s = format (s, "\n%U%U",
1244 : format_white_space, indent,
1245 : format_ip_adjacency_packet_data,
1246 205229 : t->packet_data, sizeof (t->packet_data));
1247 205229 : return s;
1248 : }
1249 :
1250 : #ifndef CLIB_MARCH_VARIANT
1251 : /* Common trace function for all ip4-forward next nodes. */
1252 : void
1253 23856 : ip4_forward_next_trace (vlib_main_t * vm,
1254 : vlib_node_runtime_t * node,
1255 : vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1256 : {
1257 : u32 *from, n_left;
1258 23856 : ip4_main_t *im = &ip4_main;
1259 :
1260 23856 : n_left = frame->n_vectors;
1261 23856 : from = vlib_frame_vector_args (frame);
1262 :
1263 462184 : while (n_left >= 4)
1264 : {
1265 : u32 bi0, bi1;
1266 : vlib_buffer_t *b0, *b1;
1267 : ip4_forward_next_trace_t *t0, *t1;
1268 :
1269 : /* Prefetch next iteration. */
1270 438331 : vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1271 438330 : vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1272 :
1273 438328 : bi0 = from[0];
1274 438328 : bi1 = from[1];
1275 :
1276 438328 : b0 = vlib_get_buffer (vm, bi0);
1277 438327 : b1 = vlib_get_buffer (vm, bi1);
1278 :
1279 438329 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
1280 : {
1281 437021 : t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1282 437018 : t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1283 437018 : t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1284 437018 : t0->fib_index =
1285 437018 : (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1286 437018 : (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1287 268077 : vec_elt (im->fib_index_by_sw_if_index,
1288 : vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1289 :
1290 437018 : clib_memcpy_fast (t0->packet_data,
1291 437018 : vlib_buffer_get_current (b0),
1292 : sizeof (t0->packet_data));
1293 : }
1294 438325 : if (b1->flags & VLIB_BUFFER_IS_TRACED)
1295 : {
1296 437019 : t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1297 437016 : t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1298 437016 : t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1299 437016 : t1->fib_index =
1300 437016 : (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1301 437016 : (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1302 268012 : vec_elt (im->fib_index_by_sw_if_index,
1303 : vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1304 437016 : clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1305 : sizeof (t1->packet_data));
1306 : }
1307 438328 : from += 2;
1308 438328 : n_left -= 2;
1309 : }
1310 :
1311 73536 : while (n_left >= 1)
1312 : {
1313 : u32 bi0;
1314 : vlib_buffer_t *b0;
1315 : ip4_forward_next_trace_t *t0;
1316 :
1317 49683 : bi0 = from[0];
1318 :
1319 49683 : b0 = vlib_get_buffer (vm, bi0);
1320 :
1321 49682 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
1322 : {
1323 49545 : t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1324 49546 : t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1325 49546 : t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1326 49546 : t0->fib_index =
1327 49546 : (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1328 49546 : (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1329 32164 : vec_elt (im->fib_index_by_sw_if_index,
1330 : vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1331 49546 : clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1332 : sizeof (t0->packet_data));
1333 : }
1334 49683 : from += 1;
1335 49683 : n_left -= 1;
1336 : }
1337 23853 : }
1338 :
1339 : /* Compute TCP/UDP/ICMP4 checksum in software. */
1340 : u16
1341 14445100 : ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1342 : ip4_header_t * ip0)
1343 : {
1344 : ip_csum_t sum0;
1345 : u32 ip_header_length, payload_length_host_byte_order;
1346 :
1347 : /* Initialize checksum with ip header. */
1348 14445100 : ip_header_length = ip4_header_bytes (ip0);
1349 14445100 : payload_length_host_byte_order =
1350 14445100 : clib_net_to_host_u16 (ip0->length) - ip_header_length;
1351 14445100 : sum0 =
1352 14445100 : clib_host_to_net_u32 (payload_length_host_byte_order +
1353 14445100 : (ip0->protocol << 16));
1354 :
1355 : if (BITS (uword) == 32)
1356 : {
1357 : sum0 =
1358 : ip_csum_with_carry (sum0,
1359 : clib_mem_unaligned (&ip0->src_address, u32));
1360 : sum0 =
1361 : ip_csum_with_carry (sum0,
1362 : clib_mem_unaligned (&ip0->dst_address, u32));
1363 : }
1364 : else
1365 : sum0 =
1366 14445100 : ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1367 :
1368 14445100 : return ip_calculate_l4_checksum (vm, p0, sum0,
1369 : payload_length_host_byte_order, (u8 *) ip0,
1370 : ip_header_length, NULL);
1371 : }
1372 :
1373 : u32
1374 14014100 : ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1375 : {
1376 14014100 : ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1377 : udp_header_t *udp0;
1378 : u16 sum16;
1379 :
1380 14014100 : ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1381 : || ip0->protocol == IP_PROTOCOL_UDP);
1382 :
1383 14014100 : udp0 = (void *) (ip0 + 1);
1384 14014100 : if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1385 : {
1386 774 : p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1387 : | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1388 774 : return p0->flags;
1389 : }
1390 :
1391 14013300 : sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1392 :
1393 28026600 : p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1394 14013300 : | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1395 :
1396 14013300 : return p0->flags;
1397 : }
1398 : #endif
1399 :
1400 : /* *INDENT-OFF* */
1401 1119 : VNET_FEATURE_ARC_INIT (ip4_local) = {
1402 : .arc_name = "ip4-local",
1403 : .start_nodes = VNET_FEATURES ("ip4-local", "ip4-receive"),
1404 : .last_in_arc = "ip4-local-end-of-arc",
1405 : };
1406 : /* *INDENT-ON* */
1407 :
1408 : static inline void
1409 10649 : ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1410 : ip4_header_t * ip, u8 is_udp, u8 * error,
1411 : u8 * good_tcp_udp)
1412 : {
1413 : u32 flags0;
1414 10649 : flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1415 10649 : *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1416 10649 : if (is_udp)
1417 : {
1418 : udp_header_t *udp;
1419 : u32 ip_len, udp_len;
1420 : i32 len_diff;
1421 10558 : udp = ip4_next_header (ip);
1422 : /* Verify UDP length. */
1423 10558 : ip_len = clib_net_to_host_u16 (ip->length);
1424 10558 : udp_len = clib_net_to_host_u16 (udp->length);
1425 :
1426 10558 : len_diff = ip_len - udp_len;
1427 10558 : *good_tcp_udp &= len_diff >= 0;
1428 10558 : *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1429 : }
1430 10649 : }
1431 :
1432 : #define ip4_local_csum_is_offloaded(_b) \
1433 : ((_b->flags & VNET_BUFFER_F_OFFLOAD) && \
1434 : (vnet_buffer (_b)->oflags & \
1435 : (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM | VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)))
1436 :
1437 : #define ip4_local_need_csum_check(is_tcp_udp, _b) \
1438 : (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1439 : || ip4_local_csum_is_offloaded (_b)))
1440 :
1441 : #define ip4_local_csum_is_valid(_b) \
1442 : (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1443 : || (ip4_local_csum_is_offloaded (_b))) != 0
1444 :
1445 : static inline void
1446 138782 : ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1447 : ip4_header_t * ih, u8 * error)
1448 : {
1449 : u8 is_udp, is_tcp_udp, good_tcp_udp;
1450 :
1451 138782 : is_udp = ih->protocol == IP_PROTOCOL_UDP;
1452 138782 : is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1453 :
1454 138782 : if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1455 1143 : ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1456 : else
1457 137639 : good_tcp_udp = ip4_local_csum_is_valid (b);
1458 :
1459 : ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1460 138782 : *error = (is_tcp_udp && !good_tcp_udp
1461 : ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1462 138782 : }
1463 :
1464 : static inline void
1465 547344 : ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1466 : ip4_header_t ** ih, u8 * error)
1467 : {
1468 : u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1469 :
1470 547344 : is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1471 547344 : is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1472 :
1473 547344 : is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1474 547344 : is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1475 :
1476 547344 : good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1477 547344 : good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1478 :
1479 547344 : if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1480 : || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1481 : {
1482 4753 : if (is_tcp_udp[0] && !ip4_local_csum_is_offloaded (b[0]))
1483 4753 : ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1484 : &good_tcp_udp[0]);
1485 4753 : if (is_tcp_udp[1] && !ip4_local_csum_is_offloaded (b[1]))
1486 4753 : ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1487 : &good_tcp_udp[1]);
1488 : }
1489 :
1490 547344 : error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1491 0 : IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1492 547344 : error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1493 0 : IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1494 547344 : }
1495 :
1496 : static inline void
1497 1233930 : ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1498 : vlib_buffer_t * b, u16 * next, u8 error,
1499 : u8 head_of_feature_arc)
1500 : {
1501 1233930 : u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1502 : u32 next_index;
1503 :
1504 1233930 : *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1505 1233930 : b->error = error ? error_node->errors[error] : 0;
1506 1233930 : if (head_of_feature_arc)
1507 : {
1508 1233930 : next_index = *next;
1509 1233930 : if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1510 : {
1511 1233080 : vnet_feature_arc_start (
1512 1233080 : arc_index, vnet_buffer (b)->ip.rx_sw_if_index, &next_index, b);
1513 1233080 : *next = next_index;
1514 : }
1515 : }
1516 1233930 : }
1517 :
1518 : typedef struct
1519 : {
1520 : /* The src and fib-index together determine if packet n is the same as n-1 */
1521 : ip4_address_t src;
1522 : u32 fib_index;
1523 : u32 lbi;
1524 : u8 error;
1525 : u8 first;
1526 : } ip4_local_last_check_t;
1527 :
1528 : static inline void
1529 138782 : ip4_local_check_src (vlib_buffer_t *b, ip4_header_t *ip0,
1530 : ip4_local_last_check_t *last_check, u8 *error0,
1531 : int is_receive_dpo)
1532 : {
1533 : const dpo_id_t *dpo0;
1534 : load_balance_t *lb0;
1535 : u32 lbi0;
1536 :
1537 138782 : vnet_buffer (b)->ip.fib_index =
1538 138782 : vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1539 138782 : vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1540 :
1541 138782 : vnet_buffer (b)->ip.rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
1542 138782 : if (is_receive_dpo)
1543 : {
1544 : receive_dpo_t *rd;
1545 138758 : rd = receive_dpo_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
1546 138758 : if (rd->rd_sw_if_index != ~0)
1547 138736 : vnet_buffer (b)->ip.rx_sw_if_index = rd->rd_sw_if_index;
1548 : }
1549 :
1550 : /*
1551 : * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1552 : * adjacency for the destination address (the local interface address).
1553 : * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1554 : * adjacency for the source address (the remote sender's address)
1555 : */
1556 138782 : if (PREDICT_TRUE ((last_check->src.as_u32 != ip0->src_address.as_u32)) ||
1557 110358 : (last_check->fib_index != vnet_buffer (b)->ip.fib_index) ||
1558 110339 : last_check->first)
1559 : {
1560 28446 : lbi0 = ip4_fib_forwarding_lookup (vnet_buffer (b)->ip.fib_index,
1561 28446 : &ip0->src_address);
1562 :
1563 28446 : vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1564 28446 : vnet_buffer (b)->ip.adj_index[VLIB_TX];
1565 28446 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
1566 :
1567 28446 : lb0 = load_balance_get (lbi0);
1568 28446 : dpo0 = load_balance_get_bucket_i (lb0, 0);
1569 :
1570 : /*
1571 : * Must have a route to source otherwise we drop the packet.
1572 : * ip4 broadcasts are accepted, e.g. to make dhcp client work
1573 : *
1574 : * The checks are:
1575 : * - the source is a recieve => it's from us => bogus, do this
1576 : * first since it sets a different error code.
1577 : * - uRPF check for any route to source - accept if passes.
1578 : * - allow packets destined to the broadcast address from unknown sources
1579 : */
1580 :
1581 56892 : *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1582 28446 : && dpo0->dpoi_type == DPO_RECEIVE) ?
1583 : IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1584 56892 : *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1585 28446 : && !fib_urpf_check_size (lb0->lb_urpf)
1586 26 : && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1587 : IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1588 :
1589 28446 : last_check->src.as_u32 = ip0->src_address.as_u32;
1590 28446 : last_check->lbi = lbi0;
1591 28446 : last_check->error = *error0;
1592 28446 : last_check->first = 0;
1593 28446 : last_check->fib_index = vnet_buffer (b)->ip.fib_index;
1594 : }
1595 : else
1596 : {
1597 110336 : vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1598 110336 : vnet_buffer (b)->ip.adj_index[VLIB_TX];
1599 110336 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
1600 110336 : *error0 = last_check->error;
1601 : }
1602 138782 : }
1603 :
1604 : static inline void
1605 547344 : ip4_local_check_src_x2 (vlib_buffer_t **b, ip4_header_t **ip,
1606 : ip4_local_last_check_t *last_check, u8 *error,
1607 : int is_receive_dpo)
1608 : {
1609 : const dpo_id_t *dpo[2];
1610 : load_balance_t *lb[2];
1611 : u32 not_last_hit;
1612 : u32 lbi[2];
1613 :
1614 547344 : not_last_hit = last_check->first;
1615 547344 : not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1616 547344 : not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1617 :
1618 547344 : vnet_buffer (b[0])->ip.fib_index =
1619 547344 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1620 547344 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1621 69871 : vnet_buffer (b[0])->ip.fib_index;
1622 :
1623 547344 : vnet_buffer (b[1])->ip.fib_index =
1624 547344 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1625 547344 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1626 69871 : vnet_buffer (b[1])->ip.fib_index;
1627 :
1628 547344 : not_last_hit |= vnet_buffer (b[0])->ip.fib_index ^ last_check->fib_index;
1629 547344 : not_last_hit |= vnet_buffer (b[1])->ip.fib_index ^ last_check->fib_index;
1630 :
1631 547344 : vnet_buffer (b[0])->ip.rx_sw_if_index =
1632 547344 : vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1633 547344 : vnet_buffer (b[1])->ip.rx_sw_if_index =
1634 547344 : vnet_buffer (b[1])->sw_if_index[VLIB_RX];
1635 547344 : if (is_receive_dpo)
1636 : {
1637 : const receive_dpo_t *rd0, *rd1;
1638 547344 : rd0 = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1639 547344 : rd1 = receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1640 547344 : if (rd0->rd_sw_if_index != ~0)
1641 547312 : vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1642 547344 : if (rd1->rd_sw_if_index != ~0)
1643 547312 : vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1644 : }
1645 :
1646 : /*
1647 : * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1648 : * adjacency for the destination address (the local interface address).
1649 : * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1650 : * adjacency for the source address (the remote sender's address)
1651 : */
1652 547344 : if (PREDICT_TRUE (not_last_hit))
1653 : {
1654 28607 : ip4_fib_forwarding_lookup_x2 (
1655 28607 : vnet_buffer (b[0])->ip.fib_index, vnet_buffer (b[1])->ip.fib_index,
1656 28607 : &ip[0]->src_address, &ip[1]->src_address, &lbi[0], &lbi[1]);
1657 :
1658 28607 : vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1659 28607 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1660 28607 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
1661 :
1662 28607 : vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1663 28607 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1664 28607 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
1665 :
1666 28607 : lb[0] = load_balance_get (lbi[0]);
1667 28607 : lb[1] = load_balance_get (lbi[1]);
1668 :
1669 28607 : dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1670 28607 : dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1671 :
1672 57214 : error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1673 28607 : dpo[0]->dpoi_type == DPO_RECEIVE) ?
1674 : IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1675 57227 : error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1676 28606 : !fib_urpf_check_size (lb[0]->lb_urpf) &&
1677 14 : ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1678 : ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1679 :
1680 57214 : error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1681 28607 : dpo[1]->dpoi_type == DPO_RECEIVE) ?
1682 : IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1683 57227 : error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1684 28606 : !fib_urpf_check_size (lb[1]->lb_urpf) &&
1685 14 : ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1686 : ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1687 :
1688 28607 : last_check->src.as_u32 = ip[1]->src_address.as_u32;
1689 28607 : last_check->lbi = lbi[1];
1690 28607 : last_check->error = error[1];
1691 28607 : last_check->first = 0;
1692 28607 : last_check->fib_index = vnet_buffer (b[1])->ip.fib_index;
1693 : }
1694 : else
1695 : {
1696 518737 : vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1697 518737 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
1698 518737 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
1699 :
1700 518737 : vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1701 518737 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
1702 518737 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
1703 :
1704 518737 : error[0] = last_check->error;
1705 518737 : error[1] = last_check->error;
1706 : }
1707 547344 : }
1708 :
1709 : enum ip_local_packet_type_e
1710 : {
1711 : IP_LOCAL_PACKET_TYPE_L4,
1712 : IP_LOCAL_PACKET_TYPE_NAT,
1713 : IP_LOCAL_PACKET_TYPE_FRAG,
1714 : };
1715 :
1716 : /**
1717 : * Determine packet type and next node.
1718 : *
1719 : * The expectation is that all packets that are not L4 will skip
1720 : * checksums and source checks.
1721 : */
1722 : always_inline u8
1723 1233930 : ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1724 : {
1725 1233930 : ip_lookup_main_t *lm = &ip4_main.lookup_main;
1726 :
1727 1233930 : if (PREDICT_FALSE (ip4_is_fragment (ip)))
1728 : {
1729 432 : *next = IP_LOCAL_NEXT_REASSEMBLY;
1730 432 : return IP_LOCAL_PACKET_TYPE_FRAG;
1731 : }
1732 1233500 : if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1733 : {
1734 25 : *next = lm->local_next_by_ip_protocol[ip->protocol];
1735 25 : return IP_LOCAL_PACKET_TYPE_NAT;
1736 : }
1737 :
1738 1233470 : *next = lm->local_next_by_ip_protocol[ip->protocol];
1739 1233470 : return IP_LOCAL_PACKET_TYPE_L4;
1740 : }
1741 :
1742 : static inline uword
1743 45993 : ip4_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1744 : vlib_frame_t *frame, int head_of_feature_arc,
1745 : int is_receive_dpo)
1746 : {
1747 : u32 *from, n_left_from;
1748 : vlib_node_runtime_t *error_node =
1749 45993 : vlib_node_get_runtime (vm, ip4_local_node.index);
1750 : u16 nexts[VLIB_FRAME_SIZE], *next;
1751 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1752 : ip4_header_t *ip[2];
1753 : u8 error[2], pt[2];
1754 :
1755 45993 : ip4_local_last_check_t last_check = {
1756 : /*
1757 : * 0.0.0.0 can appear as the source address of an IP packet,
1758 : * as can any other address, hence the need to use the 'first'
1759 : * member to make sure the .lbi is initialised for the first
1760 : * packet.
1761 : */
1762 : .src = { .as_u32 = 0 },
1763 : .lbi = ~0,
1764 : .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1765 : .first = 1,
1766 : .fib_index = 0,
1767 : };
1768 :
1769 45993 : from = vlib_frame_vector_args (frame);
1770 45993 : n_left_from = frame->n_vectors;
1771 :
1772 45993 : if (node->flags & VLIB_NODE_FLAG_TRACE)
1773 4304 : ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1774 :
1775 45993 : vlib_get_buffers (vm, from, bufs, n_left_from);
1776 45993 : b = bufs;
1777 45993 : next = nexts;
1778 :
1779 593543 : while (n_left_from >= 6)
1780 : {
1781 547550 : u8 not_batch = 0;
1782 :
1783 : /* Prefetch next iteration. */
1784 : {
1785 547550 : vlib_prefetch_buffer_header (b[4], LOAD);
1786 547550 : vlib_prefetch_buffer_header (b[5], LOAD);
1787 :
1788 547550 : clib_prefetch_load (b[4]->data);
1789 547550 : clib_prefetch_load (b[5]->data);
1790 : }
1791 :
1792 547550 : error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1793 :
1794 547550 : ip[0] = vlib_buffer_get_current (b[0]);
1795 547550 : ip[1] = vlib_buffer_get_current (b[1]);
1796 :
1797 547550 : vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1798 547550 : vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1799 :
1800 547550 : pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1801 547550 : pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
1802 :
1803 547550 : not_batch = pt[0] ^ pt[1];
1804 :
1805 547550 : if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
1806 206 : goto skip_checks;
1807 :
1808 547344 : if (PREDICT_TRUE (not_batch == 0))
1809 : {
1810 547344 : ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1811 547344 : ip4_local_check_src_x2 (b, ip, &last_check, error, is_receive_dpo);
1812 : }
1813 : else
1814 : {
1815 0 : if (!pt[0])
1816 : {
1817 0 : ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1818 0 : ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1819 : is_receive_dpo);
1820 : }
1821 0 : if (!pt[1])
1822 : {
1823 0 : ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1824 0 : ip4_local_check_src (b[1], ip[1], &last_check, &error[1],
1825 : is_receive_dpo);
1826 : }
1827 : }
1828 :
1829 0 : skip_checks:
1830 :
1831 547550 : ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1832 : head_of_feature_arc);
1833 547550 : ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1834 : head_of_feature_arc);
1835 :
1836 547550 : b += 2;
1837 547550 : next += 2;
1838 547550 : n_left_from -= 2;
1839 : }
1840 :
1841 184820 : while (n_left_from > 0)
1842 : {
1843 138827 : error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1844 :
1845 138827 : ip[0] = vlib_buffer_get_current (b[0]);
1846 138827 : vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1847 138827 : pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1848 :
1849 138827 : if (head_of_feature_arc == 0 || pt[0])
1850 45 : goto skip_check;
1851 :
1852 138782 : ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1853 138782 : ip4_local_check_src (b[0], ip[0], &last_check, &error[0],
1854 : is_receive_dpo);
1855 :
1856 138827 : skip_check:
1857 :
1858 138827 : ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1859 : head_of_feature_arc);
1860 :
1861 138827 : b += 1;
1862 138827 : next += 1;
1863 138827 : n_left_from -= 1;
1864 : }
1865 :
1866 45993 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1867 45993 : return frame->n_vectors;
1868 : }
1869 :
1870 2258 : VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1871 : vlib_frame_t * frame)
1872 : {
1873 22 : return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1874 : 0 /* is_receive_dpo */);
1875 : }
1876 :
1877 178120 : VLIB_REGISTER_NODE (ip4_local_node) =
1878 : {
1879 : .name = "ip4-local",
1880 : .vector_size = sizeof (u32),
1881 : .format_trace = format_ip4_forward_next_trace,
1882 : .n_errors = IP4_N_ERROR,
1883 : .error_counters = ip4_error_counters,
1884 : .n_next_nodes = IP_LOCAL_N_NEXT,
1885 : .next_nodes =
1886 : {
1887 : [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1888 : [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
1889 : [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1890 : [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
1891 : [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly",
1892 : },
1893 : };
1894 :
1895 48206 : VLIB_NODE_FN (ip4_receive_local_node)
1896 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1897 : {
1898 45970 : return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */,
1899 : 1 /* is_receive_dpo */);
1900 : }
1901 :
1902 178120 : VLIB_REGISTER_NODE (ip4_receive_local_node) = {
1903 : .name = "ip4-receive",
1904 : .vector_size = sizeof (u32),
1905 : .format_trace = format_ip4_forward_next_trace,
1906 : .sibling_of = "ip4-local"
1907 : };
1908 :
1909 2237 : VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1910 : vlib_node_runtime_t * node,
1911 : vlib_frame_t * frame)
1912 : {
1913 1 : return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */,
1914 : 0 /* is_receive_dpo */);
1915 : }
1916 :
1917 178120 : VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
1918 : .name = "ip4-local-end-of-arc",
1919 : .vector_size = sizeof (u32),
1920 :
1921 : .format_trace = format_ip4_forward_next_trace,
1922 : .sibling_of = "ip4-local",
1923 : };
1924 :
1925 70583 : VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1926 : .arc_name = "ip4-local",
1927 : .node_name = "ip4-local-end-of-arc",
1928 : .runs_before = 0, /* not before any other features */
1929 : };
1930 :
1931 : #ifndef CLIB_MARCH_VARIANT
1932 : void
1933 2002 : ip4_register_protocol (u32 protocol, u32 node_index)
1934 : {
1935 2002 : vlib_main_t *vm = vlib_get_main ();
1936 2002 : ip4_main_t *im = &ip4_main;
1937 2002 : ip_lookup_main_t *lm = &im->lookup_main;
1938 :
1939 2002 : ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1940 2002 : lm->local_next_by_ip_protocol[protocol] =
1941 2002 : vlib_node_add_next (vm, ip4_local_node.index, node_index);
1942 2002 : }
1943 :
1944 : void
1945 101 : ip4_unregister_protocol (u32 protocol)
1946 : {
1947 101 : ip4_main_t *im = &ip4_main;
1948 101 : ip_lookup_main_t *lm = &im->lookup_main;
1949 :
1950 101 : ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1951 101 : lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1952 101 : }
1953 : #endif
1954 :
1955 : static clib_error_t *
1956 0 : show_ip_local_command_fn (vlib_main_t * vm,
1957 : unformat_input_t * input, vlib_cli_command_t * cmd)
1958 : {
1959 0 : ip4_main_t *im = &ip4_main;
1960 0 : ip_lookup_main_t *lm = &im->lookup_main;
1961 : int i;
1962 :
1963 0 : vlib_cli_output (vm, "Protocols handled by ip4_local");
1964 0 : for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1965 : {
1966 0 : if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1967 : {
1968 0 : u32 node_index = vlib_get_node (vm,
1969 0 : ip4_local_node.index)->
1970 0 : next_nodes[lm->local_next_by_ip_protocol[i]];
1971 0 : vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1972 : format_vlib_node_name, vm, node_index);
1973 : }
1974 : }
1975 0 : return 0;
1976 : }
1977 :
1978 :
1979 :
1980 : /*?
1981 : * Display the set of protocols handled by the local IPv4 stack.
1982 : *
1983 : * @cliexpar
1984 : * Example of how to display local protocol table:
1985 : * @cliexstart{show ip local}
1986 : * Protocols handled by ip4_local
1987 : * 1
1988 : * 17
1989 : * 47
1990 : * @cliexend
1991 : ?*/
1992 : /* *INDENT-OFF* */
1993 272887 : VLIB_CLI_COMMAND (show_ip_local, static) =
1994 : {
1995 : .path = "show ip local",
1996 : .function = show_ip_local_command_fn,
1997 : .short_help = "show ip local",
1998 : };
1999 : /* *INDENT-ON* */
2000 :
2001 : typedef enum
2002 : {
2003 : IP4_REWRITE_NEXT_DROP,
2004 : IP4_REWRITE_NEXT_ICMP_ERROR,
2005 : IP4_REWRITE_NEXT_FRAGMENT,
2006 : IP4_REWRITE_N_NEXT /* Last */
2007 : } ip4_rewrite_next_t;
2008 :
2009 : /**
2010 : * This bits of an IPv4 address to mask to construct a multicast
2011 : * MAC address
2012 : */
2013 : #if CLIB_ARCH_IS_BIG_ENDIAN
2014 : #define IP4_MCAST_ADDR_MASK 0x007fffff
2015 : #else
2016 : #define IP4_MCAST_ADDR_MASK 0xffff7f00
2017 : #endif
2018 :
2019 : always_inline void
2020 8999180 : ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
2021 : u16 adj_packet_bytes, bool df, u16 * next,
2022 : u8 is_midchain, u32 * error)
2023 : {
2024 8999180 : if (packet_len > adj_packet_bytes)
2025 : {
2026 409 : *error = IP4_ERROR_MTU_EXCEEDED;
2027 409 : if (df)
2028 : {
2029 79 : icmp4_error_set_vnet_buffer
2030 : (b, ICMP4_destination_unreachable,
2031 : ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2032 : adj_packet_bytes);
2033 79 : *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2034 : }
2035 : else
2036 : {
2037 : /* IP fragmentation */
2038 330 : ip_frag_set_vnet_buffer (b, adj_packet_bytes,
2039 : (is_midchain ?
2040 : IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
2041 : IP_FRAG_NEXT_IP_REWRITE), 0);
2042 330 : *next = IP4_REWRITE_NEXT_FRAGMENT;
2043 : }
2044 : }
2045 8999180 : }
2046 :
2047 : /* increment TTL & update checksum.
2048 : Works either endian, so no need for byte swap. */
2049 : static_always_inline void
2050 409 : ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
2051 : {
2052 : i32 ttl;
2053 : u32 checksum;
2054 409 : if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2055 0 : return;
2056 :
2057 409 : ttl = ip->ttl;
2058 :
2059 409 : checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
2060 409 : checksum += checksum >= 0xffff;
2061 :
2062 409 : ip->checksum = checksum;
2063 409 : ttl += 1;
2064 409 : ip->ttl = ttl;
2065 :
2066 409 : ASSERT (ip4_header_checksum_is_valid (ip) ||
2067 : (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2068 : (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2069 : }
2070 :
2071 : /* Decrement TTL & update checksum.
2072 : Works either endian, so no need for byte swap. */
2073 : static_always_inline void
2074 8999180 : ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2075 : u32 * error)
2076 : {
2077 : i32 ttl;
2078 : u32 checksum;
2079 8999180 : if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2080 159199 : return;
2081 :
2082 8839980 : ttl = ip->ttl;
2083 :
2084 : /* Input node should have reject packets with ttl 0. */
2085 8839980 : ASSERT (ip->ttl > 0);
2086 :
2087 8839980 : checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2088 8839980 : checksum += checksum >= 0xffff;
2089 :
2090 8839980 : ip->checksum = checksum;
2091 8839980 : ttl -= 1;
2092 8839980 : ip->ttl = ttl;
2093 :
2094 : /*
2095 : * If the ttl drops below 1 when forwarding, generate
2096 : * an ICMP response.
2097 : */
2098 8839980 : if (PREDICT_FALSE (ttl <= 0))
2099 : {
2100 197 : *error = IP4_ERROR_TIME_EXPIRED;
2101 197 : vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2102 197 : icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2103 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
2104 : 0);
2105 197 : *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2106 : }
2107 :
2108 : /* Verify checksum. */
2109 8839980 : ASSERT (ip4_header_checksum_is_valid (ip) ||
2110 : (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ||
2111 : (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM));
2112 : }
2113 :
2114 : always_inline uword
2115 239028 : ip4_rewrite_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
2116 : vlib_frame_t *frame, int do_counters, int is_midchain,
2117 : int is_mcast)
2118 : {
2119 239028 : ip_lookup_main_t *lm = &ip4_main.lookup_main;
2120 239028 : u32 *from = vlib_frame_vector_args (frame);
2121 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2122 : u16 nexts[VLIB_FRAME_SIZE], *next;
2123 : u32 n_left_from;
2124 : vlib_node_runtime_t *error_node =
2125 239028 : vlib_node_get_runtime (vm, ip4_input_node.index);
2126 :
2127 239028 : n_left_from = frame->n_vectors;
2128 239028 : u32 thread_index = vm->thread_index;
2129 :
2130 239028 : vlib_get_buffers (vm, from, bufs, n_left_from);
2131 239028 : clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2132 :
2133 : #if (CLIB_N_PREFETCHES >= 8)
2134 239028 : if (n_left_from >= 6)
2135 : {
2136 : int i;
2137 727550 : for (i = 2; i < 6; i++)
2138 582040 : vlib_prefetch_buffer_header (bufs[i], LOAD);
2139 : }
2140 :
2141 239028 : next = nexts;
2142 239028 : b = bufs;
2143 4188890 : while (n_left_from >= 8)
2144 : {
2145 : const ip_adjacency_t *adj0, *adj1;
2146 : ip4_header_t *ip0, *ip1;
2147 : u32 rw_len0, error0, adj_index0;
2148 : u32 rw_len1, error1, adj_index1;
2149 : u32 tx_sw_if_index0, tx_sw_if_index1;
2150 : u8 *p;
2151 :
2152 3949860 : if (is_midchain)
2153 : {
2154 14939 : vlib_prefetch_buffer_header (b[6], LOAD);
2155 14939 : vlib_prefetch_buffer_header (b[7], LOAD);
2156 : }
2157 :
2158 3949860 : adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2159 3949860 : adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2160 :
2161 : /*
2162 : * pre-fetch the per-adjacency counters
2163 : */
2164 3949860 : if (do_counters)
2165 : {
2166 90 : vlib_prefetch_combined_counter (&adjacency_counters,
2167 : thread_index, adj_index0);
2168 90 : vlib_prefetch_combined_counter (&adjacency_counters,
2169 : thread_index, adj_index1);
2170 : }
2171 :
2172 3949860 : ip0 = vlib_buffer_get_current (b[0]);
2173 3949860 : ip1 = vlib_buffer_get_current (b[1]);
2174 :
2175 3949860 : error0 = error1 = IP4_ERROR_NONE;
2176 :
2177 3949860 : ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2178 3949860 : ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2179 :
2180 : /* Rewrite packet header and updates lengths. */
2181 3949860 : adj0 = adj_get (adj_index0);
2182 3949860 : adj1 = adj_get (adj_index1);
2183 :
2184 : /* Worth pipelining. No guarantee that adj0,1 are hot... */
2185 3949860 : rw_len0 = adj0[0].rewrite_header.data_bytes;
2186 3949860 : rw_len1 = adj1[0].rewrite_header.data_bytes;
2187 3949860 : vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2188 3949860 : vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2189 :
2190 3949860 : p = vlib_buffer_get_current (b[2]);
2191 3949860 : clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2192 3949860 : clib_prefetch_load (p);
2193 :
2194 3949860 : p = vlib_buffer_get_current (b[3]);
2195 3949860 : clib_prefetch_store (p - CLIB_CACHE_LINE_BYTES);
2196 3949860 : clib_prefetch_load (p);
2197 :
2198 : /* Check MTU of outgoing interface. */
2199 3949860 : u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2200 3949860 : u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2201 :
2202 3949860 : if (b[0]->flags & VNET_BUFFER_F_GSO)
2203 26862 : ip0_len = gso_mtu_sz (b[0]);
2204 3949860 : if (b[1]->flags & VNET_BUFFER_F_GSO)
2205 33603 : ip1_len = gso_mtu_sz (b[1]);
2206 :
2207 7899730 : ip4_mtu_check (b[0], ip0_len,
2208 3949860 : adj0[0].rewrite_header.max_l3_packet_bytes,
2209 3949860 : ip0->flags_and_fragment_offset &
2210 3949860 : clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2211 : next + 0, is_midchain, &error0);
2212 7899730 : ip4_mtu_check (b[1], ip1_len,
2213 3949860 : adj1[0].rewrite_header.max_l3_packet_bytes,
2214 3949860 : ip1->flags_and_fragment_offset &
2215 3949860 : clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2216 : next + 1, is_midchain, &error1);
2217 :
2218 3949860 : if (is_mcast)
2219 : {
2220 2716 : error0 = ((adj0[0].rewrite_header.sw_if_index ==
2221 1358 : vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2222 1358 : IP4_ERROR_SAME_INTERFACE : error0);
2223 1358 : error1 = ((adj1[0].rewrite_header.sw_if_index ==
2224 1358 : vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2225 1358 : IP4_ERROR_SAME_INTERFACE : error1);
2226 : }
2227 :
2228 : /* Don't adjust the buffer for ttl issue; icmp-error node wants
2229 : * to see the IP header */
2230 3949860 : if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2231 : {
2232 3949530 : u32 next_index = adj0[0].rewrite_header.next_index;
2233 3949530 : vlib_buffer_advance (b[0], -(word) rw_len0);
2234 :
2235 3949530 : tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2236 3949530 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2237 :
2238 3949530 : if (PREDICT_FALSE
2239 : (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2240 746219 : vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2241 : tx_sw_if_index0,
2242 : &next_index, b[0],
2243 : adj0->ia_cfg_index);
2244 :
2245 3949530 : next[0] = next_index;
2246 3949530 : if (is_midchain)
2247 14810 : vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2248 : 0 /* is_ip6 */ );
2249 : }
2250 : else
2251 : {
2252 333 : b[0]->error = error_node->errors[error0];
2253 333 : if (error0 == IP4_ERROR_MTU_EXCEEDED)
2254 161 : ip4_ttl_inc (b[0], ip0);
2255 : }
2256 3949860 : if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2257 : {
2258 3949620 : u32 next_index = adj1[0].rewrite_header.next_index;
2259 3949620 : vlib_buffer_advance (b[1], -(word) rw_len1);
2260 :
2261 3949620 : tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2262 3949620 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2263 :
2264 3949620 : if (PREDICT_FALSE
2265 : (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2266 735272 : vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2267 : tx_sw_if_index1,
2268 735272 : &next_index, b[1],
2269 : adj1->ia_cfg_index);
2270 3949620 : next[1] = next_index;
2271 3949620 : if (is_midchain)
2272 14810 : vnet_calc_checksums_inline (vm, b[1], 1 /* is_ip4 */ ,
2273 : 0 /* is_ip6 */ );
2274 : }
2275 : else
2276 : {
2277 244 : b[1]->error = error_node->errors[error1];
2278 244 : if (error1 == IP4_ERROR_MTU_EXCEEDED)
2279 161 : ip4_ttl_inc (b[1], ip1);
2280 : }
2281 :
2282 3949860 : if (is_midchain)
2283 : /* Guess we are only writing on ipv4 header. */
2284 14939 : vnet_rewrite_two_headers (adj0[0], adj1[0],
2285 : ip0, ip1, sizeof (ip4_header_t));
2286 : else
2287 : /* Guess we are only writing on simple Ethernet header. */
2288 3934920 : vnet_rewrite_two_headers (adj0[0], adj1[0],
2289 : ip0, ip1, sizeof (ethernet_header_t));
2290 :
2291 3949860 : if (do_counters)
2292 : {
2293 90 : if (error0 == IP4_ERROR_NONE)
2294 90 : vlib_increment_combined_counter
2295 : (&adjacency_counters,
2296 : thread_index,
2297 : adj_index0, 1,
2298 90 : vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2299 :
2300 90 : if (error1 == IP4_ERROR_NONE)
2301 90 : vlib_increment_combined_counter
2302 : (&adjacency_counters,
2303 : thread_index,
2304 : adj_index1, 1,
2305 90 : vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2306 : }
2307 :
2308 3949860 : if (is_midchain)
2309 : {
2310 14939 : if (error0 == IP4_ERROR_NONE)
2311 14810 : adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2312 14939 : if (error1 == IP4_ERROR_NONE)
2313 14810 : adj_midchain_fixup (vm, adj1, b[1], VNET_LINK_IP4);
2314 : }
2315 :
2316 3949860 : if (is_mcast)
2317 : {
2318 : /* copy bytes from the IP address into the MAC rewrite */
2319 1358 : if (error0 == IP4_ERROR_NONE)
2320 1269 : vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2321 1269 : adj0->rewrite_header.dst_mcast_offset,
2322 : &ip0->dst_address.as_u32, (u8 *) ip0);
2323 1358 : if (error1 == IP4_ERROR_NONE)
2324 1358 : vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2325 1358 : adj1->rewrite_header.dst_mcast_offset,
2326 : &ip1->dst_address.as_u32, (u8 *) ip1);
2327 : }
2328 :
2329 3949860 : next += 2;
2330 3949860 : b += 2;
2331 3949860 : n_left_from -= 2;
2332 : }
2333 : #elif (CLIB_N_PREFETCHES >= 4)
2334 : next = nexts;
2335 : b = bufs;
2336 : while (n_left_from >= 1)
2337 : {
2338 : ip_adjacency_t *adj0;
2339 : ip4_header_t *ip0;
2340 : u32 rw_len0, error0, adj_index0;
2341 : u32 tx_sw_if_index0;
2342 : u8 *p;
2343 :
2344 : /* Prefetch next iteration */
2345 : if (PREDICT_TRUE (n_left_from >= 4))
2346 : {
2347 : ip_adjacency_t *adj2;
2348 : u32 adj_index2;
2349 :
2350 : vlib_prefetch_buffer_header (b[3], LOAD);
2351 : vlib_prefetch_buffer_data (b[2], LOAD);
2352 :
2353 : /* Prefetch adj->rewrite_header */
2354 : adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2355 : adj2 = adj_get (adj_index2);
2356 : p = (u8 *) adj2;
2357 : CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2358 : LOAD);
2359 : }
2360 :
2361 : adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2362 :
2363 : /*
2364 : * Prefetch the per-adjacency counters
2365 : */
2366 : if (do_counters)
2367 : {
2368 : vlib_prefetch_combined_counter (&adjacency_counters,
2369 : thread_index, adj_index0);
2370 : }
2371 :
2372 : ip0 = vlib_buffer_get_current (b[0]);
2373 :
2374 : error0 = IP4_ERROR_NONE;
2375 :
2376 : ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2377 :
2378 : /* Rewrite packet header and updates lengths. */
2379 : adj0 = adj_get (adj_index0);
2380 :
2381 : /* Rewrite header was prefetched. */
2382 : rw_len0 = adj0[0].rewrite_header.data_bytes;
2383 : vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2384 :
2385 : /* Check MTU of outgoing interface. */
2386 : u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2387 :
2388 : if (b[0]->flags & VNET_BUFFER_F_GSO)
2389 : ip0_len = gso_mtu_sz (b[0]);
2390 :
2391 : ip4_mtu_check (b[0], ip0_len,
2392 : adj0[0].rewrite_header.max_l3_packet_bytes,
2393 : ip0->flags_and_fragment_offset &
2394 : clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2395 : next + 0, is_midchain, &error0);
2396 :
2397 : if (is_mcast)
2398 : {
2399 : error0 = ((adj0[0].rewrite_header.sw_if_index ==
2400 : vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2401 : IP4_ERROR_SAME_INTERFACE : error0);
2402 : }
2403 :
2404 : /* Don't adjust the buffer for ttl issue; icmp-error node wants
2405 : * to see the IP header */
2406 : if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2407 : {
2408 : u32 next_index = adj0[0].rewrite_header.next_index;
2409 : vlib_buffer_advance (b[0], -(word) rw_len0);
2410 : tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2411 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2412 :
2413 : if (PREDICT_FALSE
2414 : (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2415 : vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2416 : tx_sw_if_index0,
2417 : &next_index, b[0],
2418 : adj0->ia_cfg_index);
2419 : next[0] = next_index;
2420 :
2421 : if (is_midchain)
2422 : {
2423 : vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2424 : 0 /* is_ip6 */ );
2425 :
2426 : /* Guess we are only writing on ipv4 header. */
2427 : vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2428 : }
2429 : else
2430 : /* Guess we are only writing on simple Ethernet header. */
2431 : vnet_rewrite_one_header (adj0[0], ip0,
2432 : sizeof (ethernet_header_t));
2433 :
2434 : /*
2435 : * Bump the per-adjacency counters
2436 : */
2437 : if (do_counters)
2438 : vlib_increment_combined_counter
2439 : (&adjacency_counters,
2440 : thread_index,
2441 : adj_index0, 1, vlib_buffer_length_in_chain (vm,
2442 : b[0]) + rw_len0);
2443 :
2444 : if (is_midchain)
2445 : adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2446 :
2447 : if (is_mcast)
2448 : /* copy bytes from the IP address into the MAC rewrite */
2449 : vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2450 : adj0->rewrite_header.dst_mcast_offset,
2451 : &ip0->dst_address.as_u32, (u8 *) ip0);
2452 : }
2453 : else
2454 : {
2455 : b[0]->error = error_node->errors[error0];
2456 : if (error0 == IP4_ERROR_MTU_EXCEEDED)
2457 : ip4_ttl_inc (b[0], ip0);
2458 : }
2459 :
2460 : next += 1;
2461 : b += 1;
2462 : n_left_from -= 1;
2463 : }
2464 : #endif
2465 :
2466 1338490 : while (n_left_from > 0)
2467 : {
2468 : ip_adjacency_t *adj0;
2469 : ip4_header_t *ip0;
2470 : u32 rw_len0, adj_index0, error0;
2471 : u32 tx_sw_if_index0;
2472 :
2473 1099460 : adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2474 :
2475 1099460 : adj0 = adj_get (adj_index0);
2476 :
2477 1099460 : if (do_counters)
2478 191 : vlib_prefetch_combined_counter (&adjacency_counters,
2479 : thread_index, adj_index0);
2480 :
2481 1099460 : ip0 = vlib_buffer_get_current (b[0]);
2482 :
2483 1099460 : error0 = IP4_ERROR_NONE;
2484 :
2485 1099460 : ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2486 :
2487 :
2488 : /* Update packet buffer attributes/set output interface. */
2489 1099460 : rw_len0 = adj0[0].rewrite_header.data_bytes;
2490 1099460 : vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2491 :
2492 : /* Check MTU of outgoing interface. */
2493 1099460 : u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2494 1099460 : if (b[0]->flags & VNET_BUFFER_F_GSO)
2495 159117 : ip0_len = gso_mtu_sz (b[0]);
2496 :
2497 2198920 : ip4_mtu_check (b[0], ip0_len,
2498 1099460 : adj0[0].rewrite_header.max_l3_packet_bytes,
2499 1099460 : ip0->flags_and_fragment_offset &
2500 1099460 : clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2501 : next + 0, is_midchain, &error0);
2502 :
2503 1099460 : if (is_mcast)
2504 : {
2505 230 : error0 = ((adj0[0].rewrite_header.sw_if_index ==
2506 230 : vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2507 230 : IP4_ERROR_SAME_INTERFACE : error0);
2508 : }
2509 :
2510 : /* Don't adjust the buffer for ttl issue; icmp-error node wants
2511 : * to see the IP header */
2512 1099460 : if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2513 : {
2514 1099340 : u32 next_index = adj0[0].rewrite_header.next_index;
2515 1099340 : vlib_buffer_advance (b[0], -(word) rw_len0);
2516 1099340 : tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2517 1099340 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2518 :
2519 1099340 : if (PREDICT_FALSE
2520 : (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2521 472530 : vnet_feature_arc_start_w_cfg_index (lm->output_feature_arc_index,
2522 : tx_sw_if_index0,
2523 : &next_index, b[0],
2524 : adj0->ia_cfg_index);
2525 1099340 : next[0] = next_index;
2526 :
2527 1099340 : if (is_midchain)
2528 : {
2529 : /* this acts on the packet that is about to be encapped */
2530 2027 : vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
2531 : 0 /* is_ip6 */ );
2532 :
2533 : /* Guess we are only writing on ipv4 header. */
2534 2027 : vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip4_header_t));
2535 : }
2536 : else
2537 : /* Guess we are only writing on simple Ethernet header. */
2538 1097310 : vnet_rewrite_one_header (adj0[0], ip0,
2539 : sizeof (ethernet_header_t));
2540 :
2541 1099340 : if (do_counters)
2542 143 : vlib_increment_combined_counter
2543 : (&adjacency_counters,
2544 : thread_index, adj_index0, 1,
2545 143 : vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2546 :
2547 1099340 : if (is_midchain)
2548 2027 : adj_midchain_fixup (vm, adj0, b[0], VNET_LINK_IP4);
2549 :
2550 1099340 : if (is_mcast)
2551 : /* copy bytes from the IP address into the MAC rewrite */
2552 228 : vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2553 228 : adj0->rewrite_header.dst_mcast_offset,
2554 : &ip0->dst_address.as_u32, (u8 *) ip0);
2555 : }
2556 : else
2557 : {
2558 120 : b[0]->error = error_node->errors[error0];
2559 : /* undo the TTL decrement - we'll be back to do it again */
2560 120 : if (error0 == IP4_ERROR_MTU_EXCEEDED)
2561 87 : ip4_ttl_inc (b[0], ip0);
2562 : }
2563 :
2564 1099460 : next += 1;
2565 1099460 : b += 1;
2566 1099460 : n_left_from -= 1;
2567 : }
2568 :
2569 :
2570 : /* Need to do trace after rewrites to pick up new packet data. */
2571 239028 : if (node->flags & VLIB_NODE_FLAG_TRACE)
2572 6914 : ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2573 :
2574 239028 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
2575 239028 : return frame->n_vectors;
2576 : }
2577 :
2578 : /** @brief IPv4 rewrite node.
2579 : @node ip4-rewrite
2580 :
2581 : This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2582 : header checksum, fetch the ip adjacency, check the outbound mtu,
2583 : apply the adjacency rewrite, and send pkts to the adjacency
2584 : rewrite header's rewrite_next_index.
2585 :
2586 : @param vm vlib_main_t corresponding to the current thread
2587 : @param node vlib_node_runtime_t
2588 : @param frame vlib_frame_t whose contents should be dispatched
2589 :
2590 : @par Graph mechanics: buffer metadata, next index usage
2591 :
2592 : @em Uses:
2593 : - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2594 : - the rewrite adjacency index
2595 : - <code>adj->lookup_next_index</code>
2596 : - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2597 : the packet will be dropped.
2598 : - <code>adj->rewrite_header</code>
2599 : - Rewrite string length, rewrite string, next_index
2600 :
2601 : @em Sets:
2602 : - <code>b->current_data, b->current_length</code>
2603 : - Updated net of applying the rewrite string
2604 :
2605 : <em>Next Indices:</em>
2606 : - <code> adj->rewrite_header.next_index </code>
2607 : or @c ip4-drop
2608 : */
2609 :
2610 240776 : VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2611 : vlib_frame_t * frame)
2612 : {
2613 238540 : if (adj_are_counters_enabled ())
2614 102 : return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2615 : else
2616 238438 : return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2617 : }
2618 :
2619 2236 : VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2620 : vlib_node_runtime_t * node,
2621 : vlib_frame_t * frame)
2622 : {
2623 0 : if (adj_are_counters_enabled ())
2624 0 : return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2625 : else
2626 0 : return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2627 : }
2628 :
2629 2627 : VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2630 : vlib_node_runtime_t * node,
2631 : vlib_frame_t * frame)
2632 : {
2633 391 : if (adj_are_counters_enabled ())
2634 0 : return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2635 : else
2636 391 : return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
2637 : }
2638 :
2639 2333 : VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2640 : vlib_node_runtime_t * node,
2641 : vlib_frame_t * frame)
2642 : {
2643 97 : if (adj_are_counters_enabled ())
2644 0 : return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2645 : else
2646 97 : return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
2647 : }
2648 :
2649 2236 : VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2650 : vlib_node_runtime_t * node,
2651 : vlib_frame_t * frame)
2652 : {
2653 0 : if (adj_are_counters_enabled ())
2654 0 : return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2655 : else
2656 0 : return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2657 : }
2658 :
2659 : /* *INDENT-OFF* */
2660 178120 : VLIB_REGISTER_NODE (ip4_rewrite_node) = {
2661 : .name = "ip4-rewrite",
2662 : .vector_size = sizeof (u32),
2663 :
2664 : .format_trace = format_ip4_rewrite_trace,
2665 :
2666 : .n_next_nodes = IP4_REWRITE_N_NEXT,
2667 : .next_nodes = {
2668 : [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
2669 : [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
2670 : [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
2671 : },
2672 : };
2673 :
2674 178120 : VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
2675 : .name = "ip4-rewrite-bcast",
2676 : .vector_size = sizeof (u32),
2677 :
2678 : .format_trace = format_ip4_rewrite_trace,
2679 : .sibling_of = "ip4-rewrite",
2680 : };
2681 :
2682 178120 : VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
2683 : .name = "ip4-rewrite-mcast",
2684 : .vector_size = sizeof (u32),
2685 :
2686 : .format_trace = format_ip4_rewrite_trace,
2687 : .sibling_of = "ip4-rewrite",
2688 : };
2689 :
2690 178120 : VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
2691 : .name = "ip4-mcast-midchain",
2692 : .vector_size = sizeof (u32),
2693 :
2694 : .format_trace = format_ip4_rewrite_trace,
2695 : .sibling_of = "ip4-rewrite",
2696 : };
2697 :
2698 178120 : VLIB_REGISTER_NODE (ip4_midchain_node) = {
2699 : .name = "ip4-midchain",
2700 : .vector_size = sizeof (u32),
2701 : .format_trace = format_ip4_rewrite_trace,
2702 : .sibling_of = "ip4-rewrite",
2703 : };
2704 : /* *INDENT-ON */
2705 :
2706 : static clib_error_t *
2707 0 : set_ip_flow_hash_command_fn (vlib_main_t * vm,
2708 : unformat_input_t * input,
2709 : vlib_cli_command_t * cmd)
2710 : {
2711 0 : int matched = 0;
2712 0 : u32 table_id = 0;
2713 0 : u32 flow_hash_config = 0;
2714 : int rv;
2715 :
2716 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2717 : {
2718 0 : if (unformat (input, "table %d", &table_id))
2719 0 : matched = 1;
2720 : #define _(a, b, v) \
2721 : else if (unformat (input, #a)) \
2722 : { \
2723 : flow_hash_config |= v; \
2724 : matched = 1; \
2725 : }
2726 0 : foreach_flow_hash_bit
2727 : #undef _
2728 : else
2729 0 : break;
2730 : }
2731 :
2732 0 : if (matched == 0)
2733 0 : return clib_error_return (0, "unknown input `%U'",
2734 : format_unformat_error, input);
2735 :
2736 0 : rv = ip_flow_hash_set (AF_IP4, table_id, flow_hash_config);
2737 0 : switch (rv)
2738 : {
2739 0 : case 0:
2740 0 : break;
2741 :
2742 0 : case VNET_API_ERROR_NO_SUCH_FIB:
2743 0 : return clib_error_return (0, "no such FIB table %d", table_id);
2744 :
2745 0 : default:
2746 0 : clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2747 0 : break;
2748 : }
2749 :
2750 0 : return 0;
2751 : }
2752 :
2753 : /*?
2754 : * Configure the set of IPv4 fields used by the flow hash.
2755 : *
2756 : * @cliexpar
2757 : * Example of how to set the flow hash on a given table:
2758 : * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2759 : * Example of display the configured flow hash:
2760 : * @cliexstart{show ip fib}
2761 : * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2762 : * 0.0.0.0/0
2763 : * unicast-ip4-chain
2764 : * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2765 : * [0] [@0]: dpo-drop ip6
2766 : * 0.0.0.0/32
2767 : * unicast-ip4-chain
2768 : * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2769 : * [0] [@0]: dpo-drop ip6
2770 : * 224.0.0.0/8
2771 : * unicast-ip4-chain
2772 : * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2773 : * [0] [@0]: dpo-drop ip6
2774 : * 6.0.1.2/32
2775 : * unicast-ip4-chain
2776 : * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2777 : * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2778 : * 7.0.0.1/32
2779 : * unicast-ip4-chain
2780 : * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2781 : * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2782 : * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2783 : * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2784 : * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2785 : * 240.0.0.0/8
2786 : * unicast-ip4-chain
2787 : * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2788 : * [0] [@0]: dpo-drop ip6
2789 : * 255.255.255.255/32
2790 : * unicast-ip4-chain
2791 : * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2792 : * [0] [@0]: dpo-drop ip6
2793 : * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2794 : * 0.0.0.0/0
2795 : * unicast-ip4-chain
2796 : * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2797 : * [0] [@0]: dpo-drop ip6
2798 : * 0.0.0.0/32
2799 : * unicast-ip4-chain
2800 : * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2801 : * [0] [@0]: dpo-drop ip6
2802 : * 172.16.1.0/24
2803 : * unicast-ip4-chain
2804 : * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2805 : * [0] [@4]: ipv4-glean: af_packet0
2806 : * 172.16.1.1/32
2807 : * unicast-ip4-chain
2808 : * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2809 : * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2810 : * 172.16.1.2/32
2811 : * unicast-ip4-chain
2812 : * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2813 : * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2814 : * 172.16.2.0/24
2815 : * unicast-ip4-chain
2816 : * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2817 : * [0] [@4]: ipv4-glean: af_packet1
2818 : * 172.16.2.1/32
2819 : * unicast-ip4-chain
2820 : * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2821 : * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2822 : * 224.0.0.0/8
2823 : * unicast-ip4-chain
2824 : * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2825 : * [0] [@0]: dpo-drop ip6
2826 : * 240.0.0.0/8
2827 : * unicast-ip4-chain
2828 : * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2829 : * [0] [@0]: dpo-drop ip6
2830 : * 255.255.255.255/32
2831 : * unicast-ip4-chain
2832 : * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2833 : * [0] [@0]: dpo-drop ip6
2834 : * @cliexend
2835 : ?*/
2836 : /* *INDENT-OFF* */
2837 272887 : VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) = {
2838 : .path = "set ip flow-hash",
2839 : .short_help = "set ip flow-hash table <table-id> [src] [dst] [sport] "
2840 : "[dport] [proto] [reverse] [gtpv1teid]",
2841 : .function = set_ip_flow_hash_command_fn,
2842 : };
2843 : /* *INDENT-ON* */
2844 :
2845 : #ifndef CLIB_MARCH_VARIANT
2846 : int
2847 0 : vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2848 : u32 table_index)
2849 : {
2850 0 : vnet_main_t *vnm = vnet_get_main ();
2851 0 : vnet_interface_main_t *im = &vnm->interface_main;
2852 0 : ip4_main_t *ipm = &ip4_main;
2853 0 : ip_lookup_main_t *lm = &ipm->lookup_main;
2854 0 : vnet_classify_main_t *cm = &vnet_classify_main;
2855 : ip4_address_t *if_addr;
2856 :
2857 0 : if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2858 0 : return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2859 :
2860 0 : if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2861 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
2862 :
2863 0 : vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2864 0 : lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2865 :
2866 0 : if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2867 :
2868 0 : if (NULL != if_addr)
2869 : {
2870 0 : fib_prefix_t pfx = {
2871 : .fp_len = 32,
2872 : .fp_proto = FIB_PROTOCOL_IP4,
2873 : .fp_addr.ip4 = *if_addr,
2874 : };
2875 : u32 fib_index;
2876 :
2877 0 : fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2878 : sw_if_index);
2879 :
2880 :
2881 0 : if (table_index != (u32) ~ 0)
2882 : {
2883 0 : dpo_id_t dpo = DPO_INVALID;
2884 :
2885 0 : dpo_set (&dpo,
2886 : DPO_CLASSIFY,
2887 : DPO_PROTO_IP4,
2888 : classify_dpo_create (DPO_PROTO_IP4, table_index));
2889 :
2890 0 : fib_table_entry_special_dpo_add (fib_index,
2891 : &pfx,
2892 : FIB_SOURCE_CLASSIFY,
2893 : FIB_ENTRY_FLAG_NONE, &dpo);
2894 0 : dpo_reset (&dpo);
2895 : }
2896 : else
2897 : {
2898 0 : fib_table_entry_special_remove (fib_index,
2899 : &pfx, FIB_SOURCE_CLASSIFY);
2900 : }
2901 : }
2902 :
2903 0 : return 0;
2904 : }
2905 : #endif
2906 :
2907 : static clib_error_t *
2908 0 : set_ip_classify_command_fn (vlib_main_t * vm,
2909 : unformat_input_t * input,
2910 : vlib_cli_command_t * cmd)
2911 : {
2912 0 : u32 table_index = ~0;
2913 0 : int table_index_set = 0;
2914 0 : u32 sw_if_index = ~0;
2915 : int rv;
2916 :
2917 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2918 : {
2919 0 : if (unformat (input, "table-index %d", &table_index))
2920 0 : table_index_set = 1;
2921 0 : else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2922 : vnet_get_main (), &sw_if_index))
2923 : ;
2924 : else
2925 0 : break;
2926 : }
2927 :
2928 0 : if (table_index_set == 0)
2929 0 : return clib_error_return (0, "classify table-index must be specified");
2930 :
2931 0 : if (sw_if_index == ~0)
2932 0 : return clib_error_return (0, "interface / subif must be specified");
2933 :
2934 0 : rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2935 :
2936 0 : switch (rv)
2937 : {
2938 0 : case 0:
2939 0 : break;
2940 :
2941 0 : case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2942 0 : return clib_error_return (0, "No such interface");
2943 :
2944 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
2945 0 : return clib_error_return (0, "No such classifier table");
2946 : }
2947 0 : return 0;
2948 : }
2949 :
2950 : /*?
2951 : * Assign a classification table to an interface. The classification
2952 : * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2953 : * commands. Once the table is create, use this command to filter packets
2954 : * on an interface.
2955 : *
2956 : * @cliexpar
2957 : * Example of how to assign a classification table to an interface:
2958 : * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2959 : ?*/
2960 : /* *INDENT-OFF* */
2961 272887 : VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2962 : {
2963 : .path = "set ip classify",
2964 : .short_help =
2965 : "set ip classify intfc <interface> table-index <classify-idx>",
2966 : .function = set_ip_classify_command_fn,
2967 : };
2968 : /* *INDENT-ON* */
2969 :
2970 : /*
2971 : * fd.io coding-style-patch-verification: ON
2972 : *
2973 : * Local Variables:
2974 : * eval: (c-set-style "gnu")
2975 : * End:
2976 : */
|