ip4: perf optimization in the ip4-input node
[vpp.git] / vnet / vnet / ip / ip4_forward.c
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/ethernet/ethernet.h>     /* for ethernet_header_t */
43 #include <vnet/ethernet/arp_packet.h>   /* for ethernet_arp_header_t */
44 #include <vnet/ppp/ppp.h>
45 #include <vnet/srp/srp.h>       /* for srp_hw_interface_class */
46 #include <vnet/api_errno.h>     /* for API error numbers */
47 #include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
48 #include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
49 #include <vnet/fib/fib_urpf_list.h>     /* for FIB uRPF check */
50 #include <vnet/fib/ip4_fib.h>
51 #include <vnet/dpo/load_balance.h>
52 #include <vnet/dpo/classify_dpo.h>
53
54 /**
55  * @file
56  * @brief IPv4 Forwarding.
57  *
58  * This file contains the source code for IPv4 forwarding.
59  */
60
61 void
62 ip4_forward_next_trace (vlib_main_t * vm,
63                         vlib_node_runtime_t * node,
64                         vlib_frame_t * frame,
65                         vlib_rx_or_tx_t which_adj_index);
66
67 always_inline uword
68 ip4_lookup_inline (vlib_main_t * vm,
69                    vlib_node_runtime_t * node,
70                    vlib_frame_t * frame,
71                    int lookup_for_responses_to_locally_received_packets)
72 {
73   ip4_main_t *im = &ip4_main;
74   vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
75   u32 n_left_from, n_left_to_next, *from, *to_next;
76   ip_lookup_next_t next;
77   u32 cpu_index = os_get_cpu_number ();
78
79   from = vlib_frame_vector_args (frame);
80   n_left_from = frame->n_vectors;
81   next = node->cached_next_index;
82
83   while (n_left_from > 0)
84     {
85       vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
86
87       while (n_left_from >= 8 && n_left_to_next >= 4)
88         {
89           vlib_buffer_t *p0, *p1, *p2, *p3;
90           ip4_header_t *ip0, *ip1, *ip2, *ip3;
91           __attribute__ ((unused)) tcp_header_t *tcp0, *tcp1, *tcp2, *tcp3;
92           ip_lookup_next_t next0, next1, next2, next3;
93           const load_balance_t *lb0, *lb1, *lb2, *lb3;
94           ip4_fib_mtrie_t *mtrie0, *mtrie1, *mtrie2, *mtrie3;
95           ip4_fib_mtrie_leaf_t leaf0, leaf1, leaf2, leaf3;
96           ip4_address_t *dst_addr0, *dst_addr1, *dst_addr2, *dst_addr3;
97           __attribute__ ((unused)) u32 pi0, fib_index0, lb_index0,
98             is_tcp_udp0;
99           __attribute__ ((unused)) u32 pi1, fib_index1, lb_index1,
100             is_tcp_udp1;
101           __attribute__ ((unused)) u32 pi2, fib_index2, lb_index2,
102             is_tcp_udp2;
103           __attribute__ ((unused)) u32 pi3, fib_index3, lb_index3,
104             is_tcp_udp3;
105           flow_hash_config_t flow_hash_config0, flow_hash_config1;
106           flow_hash_config_t flow_hash_config2, flow_hash_config3;
107           u32 hash_c0, hash_c1, hash_c2, hash_c3;
108           const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
109
110           /* Prefetch next iteration. */
111           {
112             vlib_buffer_t *p4, *p5, *p6, *p7;
113
114             p4 = vlib_get_buffer (vm, from[4]);
115             p5 = vlib_get_buffer (vm, from[5]);
116             p6 = vlib_get_buffer (vm, from[6]);
117             p7 = vlib_get_buffer (vm, from[7]);
118
119             vlib_prefetch_buffer_header (p4, LOAD);
120             vlib_prefetch_buffer_header (p5, LOAD);
121             vlib_prefetch_buffer_header (p6, LOAD);
122             vlib_prefetch_buffer_header (p7, LOAD);
123
124             CLIB_PREFETCH (p4->data, sizeof (ip0[0]), LOAD);
125             CLIB_PREFETCH (p5->data, sizeof (ip0[0]), LOAD);
126             CLIB_PREFETCH (p6->data, sizeof (ip0[0]), LOAD);
127             CLIB_PREFETCH (p7->data, sizeof (ip0[0]), LOAD);
128           }
129
130           pi0 = to_next[0] = from[0];
131           pi1 = to_next[1] = from[1];
132           pi2 = to_next[2] = from[2];
133           pi3 = to_next[3] = from[3];
134
135           from += 4;
136           to_next += 4;
137           n_left_to_next -= 4;
138           n_left_from -= 4;
139
140           p0 = vlib_get_buffer (vm, pi0);
141           p1 = vlib_get_buffer (vm, pi1);
142           p2 = vlib_get_buffer (vm, pi2);
143           p3 = vlib_get_buffer (vm, pi3);
144
145           ip0 = vlib_buffer_get_current (p0);
146           ip1 = vlib_buffer_get_current (p1);
147           ip2 = vlib_buffer_get_current (p2);
148           ip3 = vlib_buffer_get_current (p3);
149
150           dst_addr0 = &ip0->dst_address;
151           dst_addr1 = &ip1->dst_address;
152           dst_addr2 = &ip2->dst_address;
153           dst_addr3 = &ip3->dst_address;
154
155           fib_index0 =
156             vec_elt (im->fib_index_by_sw_if_index,
157                      vnet_buffer (p0)->sw_if_index[VLIB_RX]);
158           fib_index1 =
159             vec_elt (im->fib_index_by_sw_if_index,
160                      vnet_buffer (p1)->sw_if_index[VLIB_RX]);
161           fib_index2 =
162             vec_elt (im->fib_index_by_sw_if_index,
163                      vnet_buffer (p2)->sw_if_index[VLIB_RX]);
164           fib_index3 =
165             vec_elt (im->fib_index_by_sw_if_index,
166                      vnet_buffer (p3)->sw_if_index[VLIB_RX]);
167           fib_index0 =
168             (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
169              (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
170           fib_index1 =
171             (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
172              (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
173           fib_index2 =
174             (vnet_buffer (p2)->sw_if_index[VLIB_TX] ==
175              (u32) ~ 0) ? fib_index2 : vnet_buffer (p2)->sw_if_index[VLIB_TX];
176           fib_index3 =
177             (vnet_buffer (p3)->sw_if_index[VLIB_TX] ==
178              (u32) ~ 0) ? fib_index3 : vnet_buffer (p3)->sw_if_index[VLIB_TX];
179
180
181           if (!lookup_for_responses_to_locally_received_packets)
182             {
183               mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
184               mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
185               mtrie2 = &ip4_fib_get (fib_index2)->mtrie;
186               mtrie3 = &ip4_fib_get (fib_index3)->mtrie;
187
188               leaf0 = leaf1 = leaf2 = leaf3 = IP4_FIB_MTRIE_LEAF_ROOT;
189
190               leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
191               leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 0);
192               leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 0);
193               leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 0);
194             }
195
196           tcp0 = (void *) (ip0 + 1);
197           tcp1 = (void *) (ip1 + 1);
198           tcp2 = (void *) (ip2 + 1);
199           tcp3 = (void *) (ip3 + 1);
200
201           is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
202                          || ip0->protocol == IP_PROTOCOL_UDP);
203           is_tcp_udp1 = (ip1->protocol == IP_PROTOCOL_TCP
204                          || ip1->protocol == IP_PROTOCOL_UDP);
205           is_tcp_udp2 = (ip2->protocol == IP_PROTOCOL_TCP
206                          || ip2->protocol == IP_PROTOCOL_UDP);
207           is_tcp_udp3 = (ip1->protocol == IP_PROTOCOL_TCP
208                          || ip1->protocol == IP_PROTOCOL_UDP);
209
210           if (!lookup_for_responses_to_locally_received_packets)
211             {
212               leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
213               leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 1);
214               leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 1);
215               leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 1);
216             }
217
218           if (!lookup_for_responses_to_locally_received_packets)
219             {
220               leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
221               leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 2);
222               leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 2);
223               leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 2);
224             }
225
226           if (!lookup_for_responses_to_locally_received_packets)
227             {
228               leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
229               leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, dst_addr1, 3);
230               leaf2 = ip4_fib_mtrie_lookup_step (mtrie2, leaf2, dst_addr2, 3);
231               leaf3 = ip4_fib_mtrie_lookup_step (mtrie3, leaf3, dst_addr3, 3);
232             }
233
234           if (lookup_for_responses_to_locally_received_packets)
235             {
236               lb_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
237               lb_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_RX];
238               lb_index2 = vnet_buffer (p2)->ip.adj_index[VLIB_RX];
239               lb_index3 = vnet_buffer (p3)->ip.adj_index[VLIB_RX];
240             }
241           else
242             {
243               /* Handle default route. */
244               leaf0 =
245                 (leaf0 ==
246                  IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
247               leaf1 =
248                 (leaf1 ==
249                  IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
250               leaf2 =
251                 (leaf2 ==
252                  IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie2->default_leaf : leaf2);
253               leaf3 =
254                 (leaf3 ==
255                  IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie3->default_leaf : leaf3);
256               lb_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
257               lb_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
258               lb_index2 = ip4_fib_mtrie_leaf_get_adj_index (leaf2);
259               lb_index3 = ip4_fib_mtrie_leaf_get_adj_index (leaf3);
260             }
261
262           lb0 = load_balance_get (lb_index0);
263           lb1 = load_balance_get (lb_index1);
264           lb2 = load_balance_get (lb_index2);
265           lb3 = load_balance_get (lb_index3);
266
267           /* Use flow hash to compute multipath adjacency. */
268           hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
269           hash_c1 = vnet_buffer (p1)->ip.flow_hash = 0;
270           hash_c2 = vnet_buffer (p2)->ip.flow_hash = 0;
271           hash_c3 = vnet_buffer (p3)->ip.flow_hash = 0;
272           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
273             {
274               flow_hash_config0 = lb0->lb_hash_config;
275               hash_c0 = vnet_buffer (p0)->ip.flow_hash =
276                 ip4_compute_flow_hash (ip0, flow_hash_config0);
277             }
278           if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
279             {
280               flow_hash_config1 = lb1->lb_hash_config;
281               hash_c1 = vnet_buffer (p1)->ip.flow_hash =
282                 ip4_compute_flow_hash (ip1, flow_hash_config1);
283             }
284           if (PREDICT_FALSE (lb2->lb_n_buckets > 1))
285             {
286               flow_hash_config2 = lb2->lb_hash_config;
287               hash_c2 = vnet_buffer (p2)->ip.flow_hash =
288                 ip4_compute_flow_hash (ip2, flow_hash_config2);
289             }
290           if (PREDICT_FALSE (lb3->lb_n_buckets > 1))
291             {
292               flow_hash_config3 = lb3->lb_hash_config;
293               hash_c3 = vnet_buffer (p3)->ip.flow_hash =
294                 ip4_compute_flow_hash (ip3, flow_hash_config3);
295             }
296
297           ASSERT (lb0->lb_n_buckets > 0);
298           ASSERT (is_pow2 (lb0->lb_n_buckets));
299           ASSERT (lb1->lb_n_buckets > 0);
300           ASSERT (is_pow2 (lb1->lb_n_buckets));
301           ASSERT (lb2->lb_n_buckets > 0);
302           ASSERT (is_pow2 (lb2->lb_n_buckets));
303           ASSERT (lb3->lb_n_buckets > 0);
304           ASSERT (is_pow2 (lb3->lb_n_buckets));
305
306           dpo0 = load_balance_get_bucket_i (lb0,
307                                             (hash_c0 &
308                                              (lb0->lb_n_buckets_minus_1)));
309           dpo1 = load_balance_get_bucket_i (lb1,
310                                             (hash_c1 &
311                                              (lb1->lb_n_buckets_minus_1)));
312           dpo2 = load_balance_get_bucket_i (lb2,
313                                             (hash_c2 &
314                                              (lb2->lb_n_buckets_minus_1)));
315           dpo3 = load_balance_get_bucket_i (lb3,
316                                             (hash_c3 &
317                                              (lb3->lb_n_buckets_minus_1)));
318
319           next0 = dpo0->dpoi_next_node;
320           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
321           next1 = dpo1->dpoi_next_node;
322           vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
323           next2 = dpo2->dpoi_next_node;
324           vnet_buffer (p2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
325           next3 = dpo3->dpoi_next_node;
326           vnet_buffer (p3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
327
328           vlib_increment_combined_counter
329             (cm, cpu_index, lb_index0, 1,
330              vlib_buffer_length_in_chain (vm, p0)
331              + sizeof (ethernet_header_t));
332           vlib_increment_combined_counter
333             (cm, cpu_index, lb_index1, 1,
334              vlib_buffer_length_in_chain (vm, p1)
335              + sizeof (ethernet_header_t));
336           vlib_increment_combined_counter
337             (cm, cpu_index, lb_index2, 1,
338              vlib_buffer_length_in_chain (vm, p2)
339              + sizeof (ethernet_header_t));
340           vlib_increment_combined_counter
341             (cm, cpu_index, lb_index3, 1,
342              vlib_buffer_length_in_chain (vm, p3)
343              + sizeof (ethernet_header_t));
344
345           vlib_validate_buffer_enqueue_x4 (vm, node, next,
346                                            to_next, n_left_to_next,
347                                            pi0, pi1, pi2, pi3,
348                                            next0, next1, next2, next3);
349         }
350
351       while (n_left_from > 0 && n_left_to_next > 0)
352         {
353           vlib_buffer_t *p0;
354           ip4_header_t *ip0;
355           __attribute__ ((unused)) tcp_header_t *tcp0;
356           ip_lookup_next_t next0;
357           const load_balance_t *lb0;
358           ip4_fib_mtrie_t *mtrie0;
359           ip4_fib_mtrie_leaf_t leaf0;
360           ip4_address_t *dst_addr0;
361           __attribute__ ((unused)) u32 pi0, fib_index0, is_tcp_udp0, lbi0;
362           flow_hash_config_t flow_hash_config0;
363           const dpo_id_t *dpo0;
364           u32 hash_c0;
365
366           pi0 = from[0];
367           to_next[0] = pi0;
368
369           p0 = vlib_get_buffer (vm, pi0);
370
371           ip0 = vlib_buffer_get_current (p0);
372
373           dst_addr0 = &ip0->dst_address;
374
375           fib_index0 =
376             vec_elt (im->fib_index_by_sw_if_index,
377                      vnet_buffer (p0)->sw_if_index[VLIB_RX]);
378           fib_index0 =
379             (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
380              (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
381
382           if (!lookup_for_responses_to_locally_received_packets)
383             {
384               mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
385
386               leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
387
388               leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 0);
389             }
390
391           tcp0 = (void *) (ip0 + 1);
392
393           is_tcp_udp0 = (ip0->protocol == IP_PROTOCOL_TCP
394                          || ip0->protocol == IP_PROTOCOL_UDP);
395
396           if (!lookup_for_responses_to_locally_received_packets)
397             leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 1);
398
399           if (!lookup_for_responses_to_locally_received_packets)
400             leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 2);
401
402           if (!lookup_for_responses_to_locally_received_packets)
403             leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, dst_addr0, 3);
404
405           if (lookup_for_responses_to_locally_received_packets)
406             lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_RX];
407           else
408             {
409               /* Handle default route. */
410               leaf0 =
411                 (leaf0 ==
412                  IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
413               lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
414             }
415
416           lb0 = load_balance_get (lbi0);
417
418           /* Use flow hash to compute multipath adjacency. */
419           hash_c0 = vnet_buffer (p0)->ip.flow_hash = 0;
420           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
421             {
422               flow_hash_config0 = lb0->lb_hash_config;
423
424               hash_c0 = vnet_buffer (p0)->ip.flow_hash =
425                 ip4_compute_flow_hash (ip0, flow_hash_config0);
426             }
427
428           ASSERT (lb0->lb_n_buckets > 0);
429           ASSERT (is_pow2 (lb0->lb_n_buckets));
430
431           dpo0 = load_balance_get_bucket_i (lb0,
432                                             (hash_c0 &
433                                              (lb0->lb_n_buckets_minus_1)));
434
435           next0 = dpo0->dpoi_next_node;
436           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
437
438           vlib_increment_combined_counter
439             (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
440
441           from += 1;
442           to_next += 1;
443           n_left_to_next -= 1;
444           n_left_from -= 1;
445
446           if (PREDICT_FALSE (next0 != next))
447             {
448               n_left_to_next += 1;
449               vlib_put_next_frame (vm, node, next, n_left_to_next);
450               next = next0;
451               vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
452               to_next[0] = pi0;
453               to_next += 1;
454               n_left_to_next -= 1;
455             }
456         }
457
458       vlib_put_next_frame (vm, node, next, n_left_to_next);
459     }
460
461   if (node->flags & VLIB_NODE_FLAG_TRACE)
462     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
463
464   return frame->n_vectors;
465 }
466
467 /** @brief IPv4 lookup node.
468     @node ip4-lookup
469
470     This is the main IPv4 lookup dispatch node.
471
472     @param vm vlib_main_t corresponding to the current thread
473     @param node vlib_node_runtime_t
474     @param frame vlib_frame_t whose contents should be dispatched
475
476     @par Graph mechanics: buffer metadata, next index usage
477
478     @em Uses:
479     - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
480         - Indicates the @c sw_if_index value of the interface that the
481           packet was received on.
482     - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
483         - When the value is @c ~0 then the node performs a longest prefix
484           match (LPM) for the packet destination address in the FIB attached
485           to the receive interface.
486         - Otherwise perform LPM for the packet destination address in the
487           indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
488           value (0, 1, ...) and not a VRF id.
489
490     @em Sets:
491     - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
492         - The lookup result adjacency index.
493
494     <em>Next Index:</em>
495     - Dispatches the packet to the node index found in
496       ip_adjacency_t @c adj->lookup_next_index
497       (where @c adj is the lookup result adjacency).
498 */
499 static uword
500 ip4_lookup (vlib_main_t * vm,
501             vlib_node_runtime_t * node, vlib_frame_t * frame)
502 {
503   return ip4_lookup_inline (vm, node, frame,
504                             /* lookup_for_responses_to_locally_received_packets */
505                             0);
506
507 }
508
509 static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
510
511 VLIB_REGISTER_NODE (ip4_lookup_node) =
512 {
513 .function = ip4_lookup,.name = "ip4-lookup",.vector_size =
514     sizeof (u32),.format_trace = format_ip4_lookup_trace,.n_next_nodes =
515     IP_LOOKUP_N_NEXT,.next_nodes = IP4_LOOKUP_NEXT_NODES,};
516
517 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_node, ip4_lookup);
518
519 always_inline uword
520 ip4_load_balance (vlib_main_t * vm,
521                   vlib_node_runtime_t * node, vlib_frame_t * frame)
522 {
523   vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
524   u32 n_left_from, n_left_to_next, *from, *to_next;
525   ip_lookup_next_t next;
526   u32 cpu_index = os_get_cpu_number ();
527
528   from = vlib_frame_vector_args (frame);
529   n_left_from = frame->n_vectors;
530   next = node->cached_next_index;
531
532   if (node->flags & VLIB_NODE_FLAG_TRACE)
533     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
534
535   while (n_left_from > 0)
536     {
537       vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
538
539
540       while (n_left_from >= 4 && n_left_to_next >= 2)
541         {
542           ip_lookup_next_t next0, next1;
543           const load_balance_t *lb0, *lb1;
544           vlib_buffer_t *p0, *p1;
545           u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
546           const ip4_header_t *ip0, *ip1;
547           const dpo_id_t *dpo0, *dpo1;
548
549           /* Prefetch next iteration. */
550           {
551             vlib_buffer_t *p2, *p3;
552
553             p2 = vlib_get_buffer (vm, from[2]);
554             p3 = vlib_get_buffer (vm, from[3]);
555
556             vlib_prefetch_buffer_header (p2, STORE);
557             vlib_prefetch_buffer_header (p3, STORE);
558
559             CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
560             CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
561           }
562
563           pi0 = to_next[0] = from[0];
564           pi1 = to_next[1] = from[1];
565
566           from += 2;
567           n_left_from -= 2;
568           to_next += 2;
569           n_left_to_next -= 2;
570
571           p0 = vlib_get_buffer (vm, pi0);
572           p1 = vlib_get_buffer (vm, pi1);
573
574           ip0 = vlib_buffer_get_current (p0);
575           ip1 = vlib_buffer_get_current (p1);
576           lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
577           lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
578
579           lb0 = load_balance_get (lbi0);
580           lb1 = load_balance_get (lbi1);
581
582           /*
583            * this node is for via FIBs we can re-use the hash value from the
584            * to node if present.
585            * We don't want to use the same hash value at each level in the recursion
586            * graph as that would lead to polarisation
587            */
588           hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
589           hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
590
591           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
592             {
593               if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
594                 {
595                   hc0 = vnet_buffer (p0)->ip.flow_hash =
596                     vnet_buffer (p0)->ip.flow_hash >> 1;
597                 }
598               else
599                 {
600                   hc0 = vnet_buffer (p0)->ip.flow_hash =
601                     ip4_compute_flow_hash (ip0, hc0);
602                 }
603             }
604           if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
605             {
606               if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
607                 {
608                   hc1 = vnet_buffer (p1)->ip.flow_hash =
609                     vnet_buffer (p1)->ip.flow_hash >> 1;
610                 }
611               else
612                 {
613                   hc1 = vnet_buffer (p1)->ip.flow_hash =
614                     ip4_compute_flow_hash (ip1, hc1);
615                 }
616             }
617
618           dpo0 =
619             load_balance_get_bucket_i (lb0,
620                                        hc0 & (lb0->lb_n_buckets_minus_1));
621           dpo1 =
622             load_balance_get_bucket_i (lb1,
623                                        hc1 & (lb1->lb_n_buckets_minus_1));
624
625           next0 = dpo0->dpoi_next_node;
626           next1 = dpo1->dpoi_next_node;
627
628           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
629           vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
630
631           vlib_increment_combined_counter
632             (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
633           vlib_increment_combined_counter
634             (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
635
636           vlib_validate_buffer_enqueue_x2 (vm, node, next,
637                                            to_next, n_left_to_next,
638                                            pi0, pi1, next0, next1);
639         }
640
641       while (n_left_from > 0 && n_left_to_next > 0)
642         {
643           ip_lookup_next_t next0;
644           const load_balance_t *lb0;
645           vlib_buffer_t *p0;
646           u32 pi0, lbi0, hc0;
647           const ip4_header_t *ip0;
648           const dpo_id_t *dpo0;
649
650           pi0 = from[0];
651           to_next[0] = pi0;
652           from += 1;
653           to_next += 1;
654           n_left_to_next -= 1;
655           n_left_from -= 1;
656
657           p0 = vlib_get_buffer (vm, pi0);
658
659           ip0 = vlib_buffer_get_current (p0);
660           lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
661
662           lb0 = load_balance_get (lbi0);
663
664           hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
665           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
666             {
667               if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
668                 {
669                   hc0 = vnet_buffer (p0)->ip.flow_hash =
670                     vnet_buffer (p0)->ip.flow_hash >> 1;
671                 }
672               else
673                 {
674                   hc0 = vnet_buffer (p0)->ip.flow_hash =
675                     ip4_compute_flow_hash (ip0, hc0);
676                 }
677             }
678
679           dpo0 =
680             load_balance_get_bucket_i (lb0,
681                                        hc0 & (lb0->lb_n_buckets_minus_1));
682
683           next0 = dpo0->dpoi_next_node;
684           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
685
686           vlib_increment_combined_counter
687             (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
688
689           vlib_validate_buffer_enqueue_x1 (vm, node, next,
690                                            to_next, n_left_to_next,
691                                            pi0, next0);
692         }
693
694       vlib_put_next_frame (vm, node, next, n_left_to_next);
695     }
696
697   return frame->n_vectors;
698 }
699
700 VLIB_REGISTER_NODE (ip4_load_balance_node) =
701 {
702 .function = ip4_load_balance,.name = "ip4-load-balance",.vector_size =
703     sizeof (u32),.sibling_of = "ip4-lookup",.format_trace =
704     format_ip4_lookup_trace,};
705
706 VLIB_NODE_FUNCTION_MULTIARCH (ip4_load_balance_node, ip4_load_balance);
707
708 /* get first interface address */
709 ip4_address_t *
710 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
711                              ip_interface_address_t ** result_ia)
712 {
713   ip_lookup_main_t *lm = &im->lookup_main;
714   ip_interface_address_t *ia = 0;
715   ip4_address_t *result = 0;
716
717   foreach_ip_interface_address (lm, ia, sw_if_index,
718                                 1 /* honor unnumbered */ ,
719                                 (
720                                   {
721                                   ip4_address_t * a =
722                                   ip_interface_address_get_address (lm, ia);
723                                   result = a;
724                                   break;
725                                   }
726                                 ));
727   if (result_ia)
728     *result_ia = result ? ia : 0;
729   return result;
730 }
731
732 static void
733 ip4_add_interface_routes (u32 sw_if_index,
734                           ip4_main_t * im, u32 fib_index,
735                           ip_interface_address_t * a)
736 {
737   ip_lookup_main_t *lm = &im->lookup_main;
738   ip4_address_t *address = ip_interface_address_get_address (lm, a);
739   fib_prefix_t pfx = {
740     .fp_len = a->address_length,
741     .fp_proto = FIB_PROTOCOL_IP4,
742     .fp_addr.ip4 = *address,
743   };
744
745   a->neighbor_probe_adj_index = ~0;
746
747   if (pfx.fp_len < 32)
748     {
749       fib_node_index_t fei;
750
751       fei = fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), FIB_PROTOCOL_IP4, NULL,       /* No next-hop address */
752                                              sw_if_index, ~0,   // invalid FIB index
753                                              1, NULL,   // no out-label stack
754                                              FIB_ROUTE_PATH_FLAG_NONE);
755       a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
756     }
757
758   pfx.fp_len = 32;
759
760   if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
761     {
762       u32 classify_table_index =
763         lm->classify_table_index_by_sw_if_index[sw_if_index];
764       if (classify_table_index != (u32) ~ 0)
765         {
766           dpo_id_t dpo = DPO_INVALID;
767
768           dpo_set (&dpo,
769                    DPO_CLASSIFY,
770                    DPO_PROTO_IP4,
771                    classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
772
773           fib_table_entry_special_dpo_add (fib_index,
774                                            &pfx,
775                                            FIB_SOURCE_CLASSIFY,
776                                            FIB_ENTRY_FLAG_NONE, &dpo);
777           dpo_reset (&dpo);
778         }
779     }
780
781   fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), FIB_PROTOCOL_IP4, &pfx.fp_addr, sw_if_index, ~0,   // invalid FIB index
782                                    1, NULL,     // no out-label stack
783                                    FIB_ROUTE_PATH_FLAG_NONE);
784 }
785
786 static void
787 ip4_del_interface_routes (ip4_main_t * im,
788                           u32 fib_index,
789                           ip4_address_t * address, u32 address_length)
790 {
791   fib_prefix_t pfx = {
792     .fp_len = address_length,
793     .fp_proto = FIB_PROTOCOL_IP4,
794     .fp_addr.ip4 = *address,
795   };
796
797   if (pfx.fp_len < 32)
798     {
799       fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
800     }
801
802   pfx.fp_len = 32;
803   fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
804 }
805
806 void
807 ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
808 {
809   ip4_main_t *im = &ip4_main;
810
811   vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
812
813   /*
814    * enable/disable only on the 1<->0 transition
815    */
816   if (is_enable)
817     {
818       if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
819         return;
820     }
821   else
822     {
823       ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
824       if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
825         return;
826     }
827   vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
828                                !is_enable, 0, 0);
829
830   vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
831                                !is_enable, 0, 0);
832
833 }
834
835 static clib_error_t *
836 ip4_add_del_interface_address_internal (vlib_main_t * vm,
837                                         u32 sw_if_index,
838                                         ip4_address_t * address,
839                                         u32 address_length, u32 is_del)
840 {
841   vnet_main_t *vnm = vnet_get_main ();
842   ip4_main_t *im = &ip4_main;
843   ip_lookup_main_t *lm = &im->lookup_main;
844   clib_error_t *error = 0;
845   u32 if_address_index, elts_before;
846   ip4_address_fib_t ip4_af, *addr_fib = 0;
847
848   vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
849   ip4_addr_fib_init (&ip4_af, address,
850                      vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
851   vec_add1 (addr_fib, ip4_af);
852
853   /* FIXME-LATER
854    * there is no support for adj-fib handling in the presence of overlapping
855    * subnets on interfaces. Easy fix - disallow overlapping subnets, like
856    * most routers do.
857    */
858   if (!is_del)
859     {
860       /* When adding an address check that it does not conflict
861          with an existing address. */
862       ip_interface_address_t *ia;
863       foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
864                                     0 /* honor unnumbered */ ,
865                                     (
866                                       {
867                                       ip4_address_t * x =
868                                       ip_interface_address_get_address
869                                       (&im->lookup_main, ia);
870                                       if (ip4_destination_matches_route
871                                           (im, address, x, ia->address_length)
872                                           ||
873                                           ip4_destination_matches_route (im,
874                                                                          x,
875                                                                          address,
876                                                                          address_length))
877                                       return
878                                       clib_error_create
879                                       ("failed to add %U which conflicts with %U for interface %U",
880                                        format_ip4_address_and_length, address,
881                                        address_length,
882                                        format_ip4_address_and_length, x,
883                                        ia->address_length,
884                                        format_vnet_sw_if_index_name, vnm,
885                                        sw_if_index);}
886                                     ));
887     }
888
889   elts_before = pool_elts (lm->if_address_pool);
890
891   error = ip_interface_address_add_del
892     (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
893   if (error)
894     goto done;
895
896   ip4_sw_interface_enable_disable (sw_if_index, !is_del);
897
898   if (is_del)
899     ip4_del_interface_routes (im, ip4_af.fib_index, address, address_length);
900   else
901     ip4_add_interface_routes (sw_if_index,
902                               im, ip4_af.fib_index,
903                               pool_elt_at_index
904                               (lm->if_address_pool, if_address_index));
905
906   /* If pool did not grow/shrink: add duplicate address. */
907   if (elts_before != pool_elts (lm->if_address_pool))
908     {
909       ip4_add_del_interface_address_callback_t *cb;
910       vec_foreach (cb, im->add_del_interface_address_callbacks)
911         cb->function (im, cb->function_opaque, sw_if_index,
912                       address, address_length, if_address_index, is_del);
913     }
914
915 done:
916   vec_free (addr_fib);
917   return error;
918 }
919
920 clib_error_t *
921 ip4_add_del_interface_address (vlib_main_t * vm, u32 sw_if_index,
922                                ip4_address_t * address, u32 address_length,
923                                u32 is_del)
924 {
925   return ip4_add_del_interface_address_internal
926     (vm, sw_if_index, address, address_length, is_del);
927 }
928
929 /* Built-in ip4 unicast rx feature path definition */
930 /* *INDENT-OFF* */
931 VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
932 {
933   .arc_name = "ip4-unicast",
934   .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
935   .end_node = "ip4-lookup",
936   .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
937 };
938
939 VNET_FEATURE_INIT (ip4_flow_classify, static) =
940 {
941   .arc_name = "ip4-unicast",
942   .node_name = "ip4-flow-classify",
943   .runs_before = VNET_FEATURES ("ip4-inacl"),
944 };
945
946 VNET_FEATURE_INIT (ip4_inacl, static) =
947 {
948   .arc_name = "ip4-unicast",
949   .node_name = "ip4-inacl",
950   .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
951 };
952
953 VNET_FEATURE_INIT (ip4_source_check_1, static) =
954 {
955   .arc_name = "ip4-unicast",
956   .node_name = "ip4-source-check-via-rx",
957   .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
958 };
959
960 VNET_FEATURE_INIT (ip4_source_check_2, static) =
961 {
962   .arc_name = "ip4-unicast",
963   .node_name = "ip4-source-check-via-any",
964   .runs_before = VNET_FEATURES ("ip4-policer-classify"),
965 };
966
967 VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
968 {
969   .arc_name = "ip4-unicast",
970   .node_name = "ip4-source-and-port-range-check-rx",
971   .runs_before = VNET_FEATURES ("ip4-policer-classify"),
972 };
973
974 VNET_FEATURE_INIT (ip4_policer_classify, static) =
975 {
976   .arc_name = "ip4-unicast",
977   .node_name = "ip4-policer-classify",
978   .runs_before = VNET_FEATURES ("ipsec-input-ip4"),
979 };
980
981 VNET_FEATURE_INIT (ip4_ipsec, static) =
982 {
983   .arc_name = "ip4-unicast",
984   .node_name = "ipsec-input-ip4",
985   .runs_before = VNET_FEATURES ("vpath-input-ip4"),
986 };
987
988 VNET_FEATURE_INIT (ip4_vpath, static) =
989 {
990   .arc_name = "ip4-unicast",
991   .node_name = "vpath-input-ip4",
992   .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
993 };
994
995 VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
996 {
997   .arc_name = "ip4-unicast",
998   .node_name = "ip4-vxlan-bypass",
999   .runs_before = VNET_FEATURES ("ip4-lookup"),
1000 };
1001
1002 VNET_FEATURE_INIT (ip4_lookup, static) =
1003 {
1004   .arc_name = "ip4-unicast",
1005   .node_name = "ip4-lookup",
1006   .runs_before = VNET_FEATURES ("ip4-drop"),
1007 };
1008
1009 VNET_FEATURE_INIT (ip4_drop, static) =
1010 {
1011   .arc_name = "ip4-unicast",
1012   .node_name = "ip4-drop",
1013   .runs_before = 0,     /* not before any other features */
1014 };
1015
1016
1017 /* Built-in ip4 multicast rx feature path definition */
1018 VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
1019 {
1020   .arc_name = "ip4-multicast",
1021   .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
1022   .end_node = "ip4-lookup-multicast",
1023   .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
1024 };
1025
1026 VNET_FEATURE_INIT (ip4_vpath_mc, static) =
1027 {
1028   .arc_name = "ip4-multicast",
1029   .node_name = "vpath-input-ip4",
1030   .runs_before = VNET_FEATURES ("ip4-lookup-multicast"),
1031 };
1032
1033 VNET_FEATURE_INIT (ip4_lookup_mc, static) =
1034 {
1035   .arc_name = "ip4-multicast",
1036   .node_name = "ip4-lookup-multicast",
1037   .runs_before = VNET_FEATURES ("ip4-drop"),
1038 };
1039
1040 VNET_FEATURE_INIT (ip4_mc_drop, static) =
1041 {
1042   .arc_name = "ip4-multicast",
1043   .node_name = "ip4-drop",
1044   .runs_before = 0,     /* last feature */
1045 };
1046
1047 /* Source and port-range check ip4 tx feature path definition */
1048 VNET_FEATURE_ARC_INIT (ip4_output, static) =
1049 {
1050   .arc_name = "ip4-output",
1051   .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"),
1052   .end_node = "interface-output",
1053   .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1054 };
1055
1056 VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1057 {
1058   .arc_name = "ip4-output",
1059   .node_name = "ip4-source-and-port-range-check-tx",
1060   .runs_before = VNET_FEATURES ("ipsec-output-ip4"),
1061 };
1062
1063 VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1064 {
1065   .arc_name = "ip4-output",
1066   .node_name = "ipsec-output-ip4",
1067   .runs_before = VNET_FEATURES ("interface-output"),
1068 };
1069
1070 /* Built-in ip4 tx feature path definition */
1071 VNET_FEATURE_INIT (ip4_interface_output, static) =
1072 {
1073   .arc_name = "ip4-output",
1074   .node_name = "interface-output",
1075   .runs_before = 0,     /* not before any other features */
1076 };
1077 /* *INDENT-ON* */
1078
1079 static clib_error_t *
1080 ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1081 {
1082   ip4_main_t *im = &ip4_main;
1083
1084   /* Fill in lookup tables with default table (0). */
1085   vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
1086
1087   vnet_feature_enable_disable ("ip4-unicast", "ip4-drop", sw_if_index,
1088                                is_add, 0, 0);
1089
1090   vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", sw_if_index,
1091                                is_add, 0, 0);
1092
1093   return /* no error */ 0;
1094 }
1095
1096 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1097
1098 /* Global IP4 main. */
1099 ip4_main_t ip4_main;
1100
1101 clib_error_t *
1102 ip4_lookup_init (vlib_main_t * vm)
1103 {
1104   ip4_main_t *im = &ip4_main;
1105   clib_error_t *error;
1106   uword i;
1107
1108   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1109     return error;
1110
1111   for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1112     {
1113       u32 m;
1114
1115       if (i < 32)
1116         m = pow2_mask (i) << (32 - i);
1117       else
1118         m = ~0;
1119       im->fib_masks[i] = clib_host_to_net_u32 (m);
1120     }
1121
1122   ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1123
1124   /* Create FIB with index 0 and table id of 0. */
1125   fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0);
1126
1127   {
1128     pg_node_t *pn;
1129     pn = pg_get_node (ip4_lookup_node.index);
1130     pn->unformat_edit = unformat_pg_ip4_header;
1131   }
1132
1133   {
1134     ethernet_arp_header_t h;
1135
1136     memset (&h, 0, sizeof (h));
1137
1138     /* Set target ethernet address to all zeros. */
1139     memset (h.ip4_over_ethernet[1].ethernet, 0,
1140             sizeof (h.ip4_over_ethernet[1].ethernet));
1141
1142 #define _16(f,v) h.f = clib_host_to_net_u16 (v);
1143 #define _8(f,v) h.f = v;
1144     _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1145     _16 (l3_type, ETHERNET_TYPE_IP4);
1146     _8 (n_l2_address_bytes, 6);
1147     _8 (n_l3_address_bytes, 4);
1148     _16 (opcode, ETHERNET_ARP_OPCODE_request);
1149 #undef _16
1150 #undef _8
1151
1152     vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
1153                                /* data */ &h,
1154                                sizeof (h),
1155                                /* alloc chunk size */ 8,
1156                                "ip4 arp");
1157   }
1158
1159   return error;
1160 }
1161
1162 VLIB_INIT_FUNCTION (ip4_lookup_init);
1163
1164 typedef struct
1165 {
1166   /* Adjacency taken. */
1167   u32 dpo_index;
1168   u32 flow_hash;
1169   u32 fib_index;
1170
1171   /* Packet data, possibly *after* rewrite. */
1172   u8 packet_data[64 - 1 * sizeof (u32)];
1173 }
1174 ip4_forward_next_trace_t;
1175
1176 u8 *
1177 format_ip4_forward_next_trace (u8 * s, va_list * args)
1178 {
1179   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1180   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1181   ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1182   uword indent = format_get_indent (s);
1183   s = format (s, "%U%U",
1184               format_white_space, indent,
1185               format_ip4_header, t->packet_data, sizeof (t->packet_data));
1186   return s;
1187 }
1188
1189 static u8 *
1190 format_ip4_lookup_trace (u8 * s, va_list * args)
1191 {
1192   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1193   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1194   ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1195   uword indent = format_get_indent (s);
1196
1197   s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1198               t->fib_index, t->dpo_index, t->flow_hash);
1199   s = format (s, "\n%U%U",
1200               format_white_space, indent,
1201               format_ip4_header, t->packet_data, sizeof (t->packet_data));
1202   return s;
1203 }
1204
1205 static u8 *
1206 format_ip4_rewrite_trace (u8 * s, va_list * args)
1207 {
1208   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1209   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1210   ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
1211   vnet_main_t *vnm = vnet_get_main ();
1212   uword indent = format_get_indent (s);
1213
1214   s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
1215               t->fib_index, t->dpo_index, format_ip_adjacency,
1216               t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1217   s = format (s, "\n%U%U",
1218               format_white_space, indent,
1219               format_ip_adjacency_packet_data,
1220               vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data));
1221   return s;
1222 }
1223
1224 /* Common trace function for all ip4-forward next nodes. */
1225 void
1226 ip4_forward_next_trace (vlib_main_t * vm,
1227                         vlib_node_runtime_t * node,
1228                         vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1229 {
1230   u32 *from, n_left;
1231   ip4_main_t *im = &ip4_main;
1232
1233   n_left = frame->n_vectors;
1234   from = vlib_frame_vector_args (frame);
1235
1236   while (n_left >= 4)
1237     {
1238       u32 bi0, bi1;
1239       vlib_buffer_t *b0, *b1;
1240       ip4_forward_next_trace_t *t0, *t1;
1241
1242       /* Prefetch next iteration. */
1243       vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1244       vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1245
1246       bi0 = from[0];
1247       bi1 = from[1];
1248
1249       b0 = vlib_get_buffer (vm, bi0);
1250       b1 = vlib_get_buffer (vm, bi1);
1251
1252       if (b0->flags & VLIB_BUFFER_IS_TRACED)
1253         {
1254           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1255           t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1256           t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1257           t0->fib_index =
1258             (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1259              (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1260             vec_elt (im->fib_index_by_sw_if_index,
1261                      vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1262
1263           clib_memcpy (t0->packet_data,
1264                        vlib_buffer_get_current (b0),
1265                        sizeof (t0->packet_data));
1266         }
1267       if (b1->flags & VLIB_BUFFER_IS_TRACED)
1268         {
1269           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1270           t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1271           t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1272           t1->fib_index =
1273             (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1274              (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1275             vec_elt (im->fib_index_by_sw_if_index,
1276                      vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1277           clib_memcpy (t1->packet_data, vlib_buffer_get_current (b1),
1278                        sizeof (t1->packet_data));
1279         }
1280       from += 2;
1281       n_left -= 2;
1282     }
1283
1284   while (n_left >= 1)
1285     {
1286       u32 bi0;
1287       vlib_buffer_t *b0;
1288       ip4_forward_next_trace_t *t0;
1289
1290       bi0 = from[0];
1291
1292       b0 = vlib_get_buffer (vm, bi0);
1293
1294       if (b0->flags & VLIB_BUFFER_IS_TRACED)
1295         {
1296           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1297           t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1298           t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1299           t0->fib_index =
1300             (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1301              (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1302             vec_elt (im->fib_index_by_sw_if_index,
1303                      vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1304           clib_memcpy (t0->packet_data, vlib_buffer_get_current (b0),
1305                        sizeof (t0->packet_data));
1306         }
1307       from += 1;
1308       n_left -= 1;
1309     }
1310 }
1311
1312 static uword
1313 ip4_drop_or_punt (vlib_main_t * vm,
1314                   vlib_node_runtime_t * node,
1315                   vlib_frame_t * frame, ip4_error_t error_code)
1316 {
1317   u32 *buffers = vlib_frame_vector_args (frame);
1318   uword n_packets = frame->n_vectors;
1319
1320   vlib_error_drop_buffers (vm, node, buffers,
1321                            /* stride */ 1,
1322                            n_packets,
1323                            /* next */ 0,
1324                            ip4_input_node.index, error_code);
1325
1326   if (node->flags & VLIB_NODE_FLAG_TRACE)
1327     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1328
1329   return n_packets;
1330 }
1331
1332 static uword
1333 ip4_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1334 {
1335   return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_DROP);
1336 }
1337
1338 static uword
1339 ip4_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1340 {
1341   return ip4_drop_or_punt (vm, node, frame, IP4_ERROR_ADJACENCY_PUNT);
1342 }
1343
1344 VLIB_REGISTER_NODE (ip4_drop_node, static) =
1345 {
1346   .function = ip4_drop,.name = "ip4-drop",.vector_size =
1347     sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
1348     1,.next_nodes =
1349   {
1350   [0] = "error-drop",}
1351 ,};
1352
1353 VLIB_NODE_FUNCTION_MULTIARCH (ip4_drop_node, ip4_drop);
1354
1355 VLIB_REGISTER_NODE (ip4_punt_node, static) =
1356 {
1357   .function = ip4_punt,.name = "ip4-punt",.vector_size =
1358     sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
1359     1,.next_nodes =
1360   {
1361   [0] = "error-punt",}
1362 ,};
1363
1364 VLIB_NODE_FUNCTION_MULTIARCH (ip4_punt_node, ip4_punt);
1365
1366 /* Compute TCP/UDP/ICMP4 checksum in software. */
1367 u16
1368 ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1369                               ip4_header_t * ip0)
1370 {
1371   ip_csum_t sum0;
1372   u32 ip_header_length, payload_length_host_byte_order;
1373   u32 n_this_buffer, n_bytes_left;
1374   u16 sum16;
1375   void *data_this_buffer;
1376
1377   /* Initialize checksum with ip header. */
1378   ip_header_length = ip4_header_bytes (ip0);
1379   payload_length_host_byte_order =
1380     clib_net_to_host_u16 (ip0->length) - ip_header_length;
1381   sum0 =
1382     clib_host_to_net_u32 (payload_length_host_byte_order +
1383                           (ip0->protocol << 16));
1384
1385   if (BITS (uword) == 32)
1386     {
1387       sum0 =
1388         ip_csum_with_carry (sum0,
1389                             clib_mem_unaligned (&ip0->src_address, u32));
1390       sum0 =
1391         ip_csum_with_carry (sum0,
1392                             clib_mem_unaligned (&ip0->dst_address, u32));
1393     }
1394   else
1395     sum0 =
1396       ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
1397
1398   n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1399   data_this_buffer = (void *) ip0 + ip_header_length;
1400   if (n_this_buffer + ip_header_length > p0->current_length)
1401     n_this_buffer =
1402       p0->current_length >
1403       ip_header_length ? p0->current_length - ip_header_length : 0;
1404   while (1)
1405     {
1406       sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1407       n_bytes_left -= n_this_buffer;
1408       if (n_bytes_left == 0)
1409         break;
1410
1411       ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
1412       p0 = vlib_get_buffer (vm, p0->next_buffer);
1413       data_this_buffer = vlib_buffer_get_current (p0);
1414       n_this_buffer = p0->current_length;
1415     }
1416
1417   sum16 = ~ip_csum_fold (sum0);
1418
1419   return sum16;
1420 }
1421
1422 u32
1423 ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1424 {
1425   ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1426   udp_header_t *udp0;
1427   u16 sum16;
1428
1429   ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1430           || ip0->protocol == IP_PROTOCOL_UDP);
1431
1432   udp0 = (void *) (ip0 + 1);
1433   if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1434     {
1435       p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1436                     | IP_BUFFER_L4_CHECKSUM_CORRECT);
1437       return p0->flags;
1438     }
1439
1440   sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1441
1442   p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1443                 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1444
1445   return p0->flags;
1446 }
1447
1448 static uword
1449 ip4_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1450 {
1451   ip4_main_t *im = &ip4_main;
1452   ip_lookup_main_t *lm = &im->lookup_main;
1453   ip_local_next_t next_index;
1454   u32 *from, *to_next, n_left_from, n_left_to_next;
1455   vlib_node_runtime_t *error_node =
1456     vlib_node_get_runtime (vm, ip4_input_node.index);
1457
1458   from = vlib_frame_vector_args (frame);
1459   n_left_from = frame->n_vectors;
1460   next_index = node->cached_next_index;
1461
1462   if (node->flags & VLIB_NODE_FLAG_TRACE)
1463     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1464
1465   while (n_left_from > 0)
1466     {
1467       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1468
1469       while (n_left_from >= 4 && n_left_to_next >= 2)
1470         {
1471           vlib_buffer_t *p0, *p1;
1472           ip4_header_t *ip0, *ip1;
1473           udp_header_t *udp0, *udp1;
1474           ip4_fib_mtrie_t *mtrie0, *mtrie1;
1475           ip4_fib_mtrie_leaf_t leaf0, leaf1;
1476           const dpo_id_t *dpo0, *dpo1;
1477           const load_balance_t *lb0, *lb1;
1478           u32 pi0, ip_len0, udp_len0, flags0, next0, fib_index0, lbi0;
1479           u32 pi1, ip_len1, udp_len1, flags1, next1, fib_index1, lbi1;
1480           i32 len_diff0, len_diff1;
1481           u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1482           u8 error1, is_udp1, is_tcp_udp1, good_tcp_udp1, proto1;
1483           u8 enqueue_code;
1484
1485           pi0 = to_next[0] = from[0];
1486           pi1 = to_next[1] = from[1];
1487           from += 2;
1488           n_left_from -= 2;
1489           to_next += 2;
1490           n_left_to_next -= 2;
1491
1492           p0 = vlib_get_buffer (vm, pi0);
1493           p1 = vlib_get_buffer (vm, pi1);
1494
1495           ip0 = vlib_buffer_get_current (p0);
1496           ip1 = vlib_buffer_get_current (p1);
1497
1498           vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1499           vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
1500
1501           fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1502                                 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1503           fib_index1 = vec_elt (im->fib_index_by_sw_if_index,
1504                                 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
1505
1506           mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1507           mtrie1 = &ip4_fib_get (fib_index1)->mtrie;
1508
1509           leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
1510
1511           leaf0 =
1512             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1513           leaf1 =
1514             ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 0);
1515
1516           /* Treat IP frag packets as "experimental" protocol for now
1517              until support of IP frag reassembly is implemented */
1518           proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1519           proto1 = ip4_is_fragment (ip1) ? 0xfe : ip1->protocol;
1520           is_udp0 = proto0 == IP_PROTOCOL_UDP;
1521           is_udp1 = proto1 == IP_PROTOCOL_UDP;
1522           is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1523           is_tcp_udp1 = is_udp1 || proto1 == IP_PROTOCOL_TCP;
1524
1525           flags0 = p0->flags;
1526           flags1 = p1->flags;
1527
1528           good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1529           good_tcp_udp1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1530
1531           udp0 = ip4_next_header (ip0);
1532           udp1 = ip4_next_header (ip1);
1533
1534           /* Don't verify UDP checksum for packets with explicit zero checksum. */
1535           good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1536           good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1537
1538           leaf0 =
1539             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1540           leaf1 =
1541             ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 1);
1542
1543           /* Verify UDP length. */
1544           ip_len0 = clib_net_to_host_u16 (ip0->length);
1545           ip_len1 = clib_net_to_host_u16 (ip1->length);
1546           udp_len0 = clib_net_to_host_u16 (udp0->length);
1547           udp_len1 = clib_net_to_host_u16 (udp1->length);
1548
1549           len_diff0 = ip_len0 - udp_len0;
1550           len_diff1 = ip_len1 - udp_len1;
1551
1552           len_diff0 = is_udp0 ? len_diff0 : 0;
1553           len_diff1 = is_udp1 ? len_diff1 : 0;
1554
1555           if (PREDICT_FALSE (!(is_tcp_udp0 & is_tcp_udp1
1556                                & good_tcp_udp0 & good_tcp_udp1)))
1557             {
1558               if (is_tcp_udp0)
1559                 {
1560                   if (is_tcp_udp0
1561                       && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
1562                     flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1563                   good_tcp_udp0 =
1564                     (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1565                   good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1566                 }
1567               if (is_tcp_udp1)
1568                 {
1569                   if (is_tcp_udp1
1570                       && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
1571                     flags1 = ip4_tcp_udp_validate_checksum (vm, p1);
1572                   good_tcp_udp1 =
1573                     (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1574                   good_tcp_udp1 |= is_udp1 && udp1->checksum == 0;
1575                 }
1576             }
1577
1578           good_tcp_udp0 &= len_diff0 >= 0;
1579           good_tcp_udp1 &= len_diff1 >= 0;
1580
1581           leaf0 =
1582             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1583           leaf1 =
1584             ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 2);
1585
1586           error0 = error1 = IP4_ERROR_UNKNOWN_PROTOCOL;
1587
1588           error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1589           error1 = len_diff1 < 0 ? IP4_ERROR_UDP_LENGTH : error1;
1590
1591           ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1592           error0 = (is_tcp_udp0 && !good_tcp_udp0
1593                     ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1594           error1 = (is_tcp_udp1 && !good_tcp_udp1
1595                     ? IP4_ERROR_TCP_CHECKSUM + is_udp1 : error1);
1596
1597           leaf0 =
1598             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1599           leaf1 =
1600             ip4_fib_mtrie_lookup_step (mtrie1, leaf1, &ip1->src_address, 3);
1601           leaf0 =
1602             (leaf0 ==
1603              IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1604           leaf1 =
1605             (leaf1 ==
1606              IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1);
1607
1608           vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0 =
1609             ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1610           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1611
1612           vnet_buffer (p1)->ip.adj_index[VLIB_RX] = lbi1 =
1613             ip4_fib_mtrie_leaf_get_adj_index (leaf1);
1614           vnet_buffer (p1)->ip.adj_index[VLIB_TX] = lbi1;
1615
1616           lb0 = load_balance_get (lbi0);
1617           lb1 = load_balance_get (lbi1);
1618           dpo0 = load_balance_get_bucket_i (lb0, 0);
1619           dpo1 = load_balance_get_bucket_i (lb1, 0);
1620
1621           /*
1622            * Must have a route to source otherwise we drop the packet.
1623            * ip4 broadcasts are accepted, e.g. to make dhcp client work
1624            *
1625            * The checks are:
1626            *  - the source is a recieve => it's from us => bogus, do this
1627            *    first since it sets a different error code.
1628            *  - uRPF check for any route to source - accept if passes.
1629            *  - allow packets destined to the broadcast address from unknown sources
1630            */
1631           error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1632                      dpo0->dpoi_type == DPO_RECEIVE) ?
1633                     IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1634           error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1635                      !fib_urpf_check_size (lb0->lb_urpf) &&
1636                      ip0->dst_address.as_u32 != 0xFFFFFFFF)
1637                     ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1638           error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1639                      dpo1->dpoi_type == DPO_RECEIVE) ?
1640                     IP4_ERROR_SPOOFED_LOCAL_PACKETS : error1);
1641           error1 = ((error1 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1642                      !fib_urpf_check_size (lb1->lb_urpf) &&
1643                      ip1->dst_address.as_u32 != 0xFFFFFFFF)
1644                     ? IP4_ERROR_SRC_LOOKUP_MISS : error1);
1645
1646           next0 = lm->local_next_by_ip_protocol[proto0];
1647           next1 = lm->local_next_by_ip_protocol[proto1];
1648
1649           next0 =
1650             error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1651           next1 =
1652             error1 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
1653
1654           p0->error = error0 ? error_node->errors[error0] : 0;
1655           p1->error = error1 ? error_node->errors[error1] : 0;
1656
1657           enqueue_code = (next0 != next_index) + 2 * (next1 != next_index);
1658
1659           if (PREDICT_FALSE (enqueue_code != 0))
1660             {
1661               switch (enqueue_code)
1662                 {
1663                 case 1:
1664                   /* A B A */
1665                   to_next[-2] = pi1;
1666                   to_next -= 1;
1667                   n_left_to_next += 1;
1668                   vlib_set_next_frame_buffer (vm, node, next0, pi0);
1669                   break;
1670
1671                 case 2:
1672                   /* A A B */
1673                   to_next -= 1;
1674                   n_left_to_next += 1;
1675                   vlib_set_next_frame_buffer (vm, node, next1, pi1);
1676                   break;
1677
1678                 case 3:
1679                   /* A B B or A B C */
1680                   to_next -= 2;
1681                   n_left_to_next += 2;
1682                   vlib_set_next_frame_buffer (vm, node, next0, pi0);
1683                   vlib_set_next_frame_buffer (vm, node, next1, pi1);
1684                   if (next0 == next1)
1685                     {
1686                       vlib_put_next_frame (vm, node, next_index,
1687                                            n_left_to_next);
1688                       next_index = next1;
1689                       vlib_get_next_frame (vm, node, next_index, to_next,
1690                                            n_left_to_next);
1691                     }
1692                   break;
1693                 }
1694             }
1695         }
1696
1697       while (n_left_from > 0 && n_left_to_next > 0)
1698         {
1699           vlib_buffer_t *p0;
1700           ip4_header_t *ip0;
1701           udp_header_t *udp0;
1702           ip4_fib_mtrie_t *mtrie0;
1703           ip4_fib_mtrie_leaf_t leaf0;
1704           u32 pi0, next0, ip_len0, udp_len0, flags0, fib_index0, lbi0;
1705           i32 len_diff0;
1706           u8 error0, is_udp0, is_tcp_udp0, good_tcp_udp0, proto0;
1707           load_balance_t *lb0;
1708           const dpo_id_t *dpo0;
1709
1710           pi0 = to_next[0] = from[0];
1711           from += 1;
1712           n_left_from -= 1;
1713           to_next += 1;
1714           n_left_to_next -= 1;
1715
1716           p0 = vlib_get_buffer (vm, pi0);
1717
1718           ip0 = vlib_buffer_get_current (p0);
1719
1720           vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1721
1722           fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
1723                                 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1724
1725           mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
1726
1727           leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
1728
1729           leaf0 =
1730             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 0);
1731
1732           /* Treat IP frag packets as "experimental" protocol for now
1733              until support of IP frag reassembly is implemented */
1734           proto0 = ip4_is_fragment (ip0) ? 0xfe : ip0->protocol;
1735           is_udp0 = proto0 == IP_PROTOCOL_UDP;
1736           is_tcp_udp0 = is_udp0 || proto0 == IP_PROTOCOL_TCP;
1737
1738           flags0 = p0->flags;
1739
1740           good_tcp_udp0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1741
1742           udp0 = ip4_next_header (ip0);
1743
1744           /* Don't verify UDP checksum for packets with explicit zero checksum. */
1745           good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1746
1747           leaf0 =
1748             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 1);
1749
1750           /* Verify UDP length. */
1751           ip_len0 = clib_net_to_host_u16 (ip0->length);
1752           udp_len0 = clib_net_to_host_u16 (udp0->length);
1753
1754           len_diff0 = ip_len0 - udp_len0;
1755
1756           len_diff0 = is_udp0 ? len_diff0 : 0;
1757
1758           if (PREDICT_FALSE (!(is_tcp_udp0 & good_tcp_udp0)))
1759             {
1760               if (is_tcp_udp0)
1761                 {
1762                   if (is_tcp_udp0
1763                       && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED))
1764                     flags0 = ip4_tcp_udp_validate_checksum (vm, p0);
1765                   good_tcp_udp0 =
1766                     (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1767                   good_tcp_udp0 |= is_udp0 && udp0->checksum == 0;
1768                 }
1769             }
1770
1771           good_tcp_udp0 &= len_diff0 >= 0;
1772
1773           leaf0 =
1774             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1775
1776           error0 = IP4_ERROR_UNKNOWN_PROTOCOL;
1777
1778           error0 = len_diff0 < 0 ? IP4_ERROR_UDP_LENGTH : error0;
1779
1780           ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1781           error0 = (is_tcp_udp0 && !good_tcp_udp0
1782                     ? IP4_ERROR_TCP_CHECKSUM + is_udp0 : error0);
1783
1784           leaf0 =
1785             ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1786           leaf0 =
1787             (leaf0 ==
1788              IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
1789
1790           lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1791           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = lbi0;
1792
1793           lb0 = load_balance_get (lbi0);
1794           dpo0 = load_balance_get_bucket_i (lb0, 0);
1795
1796           vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
1797             vnet_buffer (p0)->ip.adj_index[VLIB_RX] = lbi0;
1798
1799           error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1800                      dpo0->dpoi_type == DPO_RECEIVE) ?
1801                     IP4_ERROR_SPOOFED_LOCAL_PACKETS : error0);
1802           error0 = ((error0 == IP4_ERROR_UNKNOWN_PROTOCOL &&
1803                      !fib_urpf_check_size (lb0->lb_urpf) &&
1804                      ip0->dst_address.as_u32 != 0xFFFFFFFF)
1805                     ? IP4_ERROR_SRC_LOOKUP_MISS : error0);
1806
1807           next0 = lm->local_next_by_ip_protocol[proto0];
1808
1809           next0 =
1810             error0 != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1811
1812           p0->error = error0 ? error_node->errors[error0] : 0;
1813
1814           if (PREDICT_FALSE (next0 != next_index))
1815             {
1816               n_left_to_next += 1;
1817               vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1818
1819               next_index = next0;
1820               vlib_get_next_frame (vm, node, next_index, to_next,
1821                                    n_left_to_next);
1822               to_next[0] = pi0;
1823               to_next += 1;
1824               n_left_to_next -= 1;
1825             }
1826         }
1827
1828       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1829     }
1830
1831   return frame->n_vectors;
1832 }
1833
1834 VLIB_REGISTER_NODE (ip4_local_node, static) =
1835 {
1836   .function = ip4_local,.name = "ip4-local",.vector_size =
1837     sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
1838     IP_LOCAL_N_NEXT,.next_nodes =
1839   {
1840   [IP_LOCAL_NEXT_DROP] = "error-drop",
1841       [IP_LOCAL_NEXT_PUNT] = "error-punt",
1842       [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
1843       [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",}
1844 ,};
1845
1846 VLIB_NODE_FUNCTION_MULTIARCH (ip4_local_node, ip4_local);
1847
1848 void
1849 ip4_register_protocol (u32 protocol, u32 node_index)
1850 {
1851   vlib_main_t *vm = vlib_get_main ();
1852   ip4_main_t *im = &ip4_main;
1853   ip_lookup_main_t *lm = &im->lookup_main;
1854
1855   ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1856   lm->local_next_by_ip_protocol[protocol] =
1857     vlib_node_add_next (vm, ip4_local_node.index, node_index);
1858 }
1859
1860 static clib_error_t *
1861 show_ip_local_command_fn (vlib_main_t * vm,
1862                           unformat_input_t * input, vlib_cli_command_t * cmd)
1863 {
1864   ip4_main_t *im = &ip4_main;
1865   ip_lookup_main_t *lm = &im->lookup_main;
1866   int i;
1867
1868   vlib_cli_output (vm, "Protocols handled by ip4_local");
1869   for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
1870     {
1871       if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
1872         vlib_cli_output (vm, "%d", i);
1873     }
1874   return 0;
1875 }
1876
1877
1878
1879 /*?
1880  * Display the set of protocols handled by the local IPv4 stack.
1881  *
1882  * @cliexpar
1883  * Example of how to display local protocol table:
1884  * @cliexstart{show ip local}
1885  * Protocols handled by ip4_local
1886  * 1
1887  * 17
1888  * 47
1889  * @cliexend
1890 ?*/
1891 /* *INDENT-OFF* */
1892 VLIB_CLI_COMMAND (show_ip_local, static) =
1893 {
1894   .path = "show ip local",
1895   .function = show_ip_local_command_fn,
1896   .short_help = "show ip local",
1897 };
1898 /* *INDENT-ON* */
1899
1900 always_inline uword
1901 ip4_arp_inline (vlib_main_t * vm,
1902                 vlib_node_runtime_t * node,
1903                 vlib_frame_t * frame, int is_glean)
1904 {
1905   vnet_main_t *vnm = vnet_get_main ();
1906   ip4_main_t *im = &ip4_main;
1907   ip_lookup_main_t *lm = &im->lookup_main;
1908   u32 *from, *to_next_drop;
1909   uword n_left_from, n_left_to_next_drop, next_index;
1910   static f64 time_last_seed_change = -1e100;
1911   static u32 hash_seeds[3];
1912   static uword hash_bitmap[256 / BITS (uword)];
1913   f64 time_now;
1914
1915   if (node->flags & VLIB_NODE_FLAG_TRACE)
1916     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1917
1918   time_now = vlib_time_now (vm);
1919   if (time_now - time_last_seed_change > 1e-3)
1920     {
1921       uword i;
1922       u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1923                                             sizeof (hash_seeds));
1924       for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1925         hash_seeds[i] = r[i];
1926
1927       /* Mark all hash keys as been no-seen before. */
1928       for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1929         hash_bitmap[i] = 0;
1930
1931       time_last_seed_change = time_now;
1932     }
1933
1934   from = vlib_frame_vector_args (frame);
1935   n_left_from = frame->n_vectors;
1936   next_index = node->cached_next_index;
1937   if (next_index == IP4_ARP_NEXT_DROP)
1938     next_index = IP4_ARP_N_NEXT;        /* point to first interface */
1939
1940   while (n_left_from > 0)
1941     {
1942       vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1943                            to_next_drop, n_left_to_next_drop);
1944
1945       while (n_left_from > 0 && n_left_to_next_drop > 0)
1946         {
1947           u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1948           ip_adjacency_t *adj0;
1949           vlib_buffer_t *p0;
1950           ip4_header_t *ip0;
1951           uword bm0;
1952
1953           pi0 = from[0];
1954
1955           p0 = vlib_get_buffer (vm, pi0);
1956
1957           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1958           adj0 = ip_get_adjacency (lm, adj_index0);
1959           ip0 = vlib_buffer_get_current (p0);
1960
1961           a0 = hash_seeds[0];
1962           b0 = hash_seeds[1];
1963           c0 = hash_seeds[2];
1964
1965           sw_if_index0 = adj0->rewrite_header.sw_if_index;
1966           vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1967
1968           if (is_glean)
1969             {
1970               /*
1971                * this is the Glean case, so we are ARPing for the
1972                * packet's destination
1973                */
1974               a0 ^= ip0->dst_address.data_u32;
1975             }
1976           else
1977             {
1978               a0 ^= adj0->sub_type.nbr.next_hop.ip4.data_u32;
1979             }
1980           b0 ^= sw_if_index0;
1981
1982           hash_v3_finalize32 (a0, b0, c0);
1983
1984           c0 &= BITS (hash_bitmap) - 1;
1985           c0 = c0 / BITS (uword);
1986           m0 = (uword) 1 << (c0 % BITS (uword));
1987
1988           bm0 = hash_bitmap[c0];
1989           drop0 = (bm0 & m0) != 0;
1990
1991           /* Mark it as seen. */
1992           hash_bitmap[c0] = bm0 | m0;
1993
1994           from += 1;
1995           n_left_from -= 1;
1996           to_next_drop[0] = pi0;
1997           to_next_drop += 1;
1998           n_left_to_next_drop -= 1;
1999
2000           p0->error =
2001             node->errors[drop0 ? IP4_ARP_ERROR_DROP :
2002                          IP4_ARP_ERROR_REQUEST_SENT];
2003
2004           /*
2005            * the adj has been updated to a rewrite but the node the DPO that got
2006            * us here hasn't - yet. no big deal. we'll drop while we wait.
2007            */
2008           if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
2009             continue;
2010
2011           if (drop0)
2012             continue;
2013
2014           /*
2015            * Can happen if the control-plane is programming tables
2016            * with traffic flowing; at least that's today's lame excuse.
2017            */
2018           if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN) ||
2019               (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
2020             {
2021               p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
2022             }
2023           else
2024             /* Send ARP request. */
2025             {
2026               u32 bi0 = 0;
2027               vlib_buffer_t *b0;
2028               ethernet_arp_header_t *h0;
2029               vnet_hw_interface_t *hw_if0;
2030
2031               h0 =
2032                 vlib_packet_template_get_packet (vm,
2033                                                  &im->ip4_arp_request_packet_template,
2034                                                  &bi0);
2035
2036               /* Add rewrite/encap string for ARP packet. */
2037               vnet_rewrite_one_header (adj0[0], h0,
2038                                        sizeof (ethernet_header_t));
2039
2040               hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2041
2042               /* Src ethernet address in ARP header. */
2043               clib_memcpy (h0->ip4_over_ethernet[0].ethernet,
2044                            hw_if0->hw_address,
2045                            sizeof (h0->ip4_over_ethernet[0].ethernet));
2046
2047               if (is_glean)
2048                 {
2049                   /* The interface's source address is stashed in the Glean Adj */
2050                   h0->ip4_over_ethernet[0].ip4 =
2051                     adj0->sub_type.glean.receive_addr.ip4;
2052
2053                   /* Copy in destination address we are requesting. This is the
2054                    * glean case, so it's the packet's destination.*/
2055                   h0->ip4_over_ethernet[1].ip4.data_u32 =
2056                     ip0->dst_address.data_u32;
2057                 }
2058               else
2059                 {
2060                   /* Src IP address in ARP header. */
2061                   if (ip4_src_address_for_packet (lm, sw_if_index0,
2062                                                   &h0->
2063                                                   ip4_over_ethernet[0].ip4))
2064                     {
2065                       /* No source address available */
2066                       p0->error =
2067                         node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2068                       vlib_buffer_free (vm, &bi0, 1);
2069                       continue;
2070                     }
2071
2072                   /* Copy in destination address we are requesting from the
2073                      incomplete adj */
2074                   h0->ip4_over_ethernet[1].ip4.data_u32 =
2075                     adj0->sub_type.nbr.next_hop.ip4.as_u32;
2076                 }
2077
2078               vlib_buffer_copy_trace_flag (vm, p0, bi0);
2079               b0 = vlib_get_buffer (vm, bi0);
2080               vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2081
2082               vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2083
2084               vlib_set_next_frame_buffer (vm, node,
2085                                           adj0->rewrite_header.next_index,
2086                                           bi0);
2087             }
2088         }
2089
2090       vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2091     }
2092
2093   return frame->n_vectors;
2094 }
2095
2096 static uword
2097 ip4_arp (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
2098 {
2099   return (ip4_arp_inline (vm, node, frame, 0));
2100 }
2101
2102 static uword
2103 ip4_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
2104 {
2105   return (ip4_arp_inline (vm, node, frame, 1));
2106 }
2107
2108 static char *ip4_arp_error_strings[] = {
2109   [IP4_ARP_ERROR_DROP] = "address overflow drops",
2110   [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2111   [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
2112   [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed",
2113   [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed",
2114   [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
2115 };
2116
2117 VLIB_REGISTER_NODE (ip4_arp_node) =
2118 {
2119   .function = ip4_arp,.name = "ip4-arp",.vector_size =
2120     sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2121     ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2122     ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2123   {
2124   [IP4_ARP_NEXT_DROP] = "error-drop",}
2125 ,};
2126
2127 VLIB_REGISTER_NODE (ip4_glean_node) =
2128 {
2129   .function = ip4_glean,.name = "ip4-glean",.vector_size =
2130     sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_errors =
2131     ARRAY_LEN (ip4_arp_error_strings),.error_strings =
2132     ip4_arp_error_strings,.n_next_nodes = IP4_ARP_N_NEXT,.next_nodes =
2133   {
2134   [IP4_ARP_NEXT_DROP] = "error-drop",}
2135 ,};
2136
2137 #define foreach_notrace_ip4_arp_error           \
2138 _(DROP)                                         \
2139 _(REQUEST_SENT)                                 \
2140 _(REPLICATE_DROP)                               \
2141 _(REPLICATE_FAIL)
2142
2143 clib_error_t *
2144 arp_notrace_init (vlib_main_t * vm)
2145 {
2146   vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
2147
2148   /* don't trace ARP request packets */
2149 #define _(a)                                    \
2150     vnet_pcap_drop_trace_filter_add_del         \
2151         (rt->errors[IP4_ARP_ERROR_##a],         \
2152          1 /* is_add */);
2153   foreach_notrace_ip4_arp_error;
2154 #undef _
2155   return 0;
2156 }
2157
2158 VLIB_INIT_FUNCTION (arp_notrace_init);
2159
2160
2161 /* Send an ARP request to see if given destination is reachable on given interface. */
2162 clib_error_t *
2163 ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index)
2164 {
2165   vnet_main_t *vnm = vnet_get_main ();
2166   ip4_main_t *im = &ip4_main;
2167   ethernet_arp_header_t *h;
2168   ip4_address_t *src;
2169   ip_interface_address_t *ia;
2170   ip_adjacency_t *adj;
2171   vnet_hw_interface_t *hi;
2172   vnet_sw_interface_t *si;
2173   vlib_buffer_t *b;
2174   u32 bi = 0;
2175
2176   si = vnet_get_sw_interface (vnm, sw_if_index);
2177
2178   if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2179     {
2180       return clib_error_return (0, "%U: interface %U down",
2181                                 format_ip4_address, dst,
2182                                 format_vnet_sw_if_index_name, vnm,
2183                                 sw_if_index);
2184     }
2185
2186   src =
2187     ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2188   if (!src)
2189     {
2190       vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
2191       return clib_error_return
2192         (0, "no matching interface address for destination %U (interface %U)",
2193          format_ip4_address, dst,
2194          format_vnet_sw_if_index_name, vnm, sw_if_index);
2195     }
2196
2197   adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
2198
2199   h =
2200     vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template,
2201                                      &bi);
2202
2203   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2204
2205   clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address,
2206                sizeof (h->ip4_over_ethernet[0].ethernet));
2207
2208   h->ip4_over_ethernet[0].ip4 = src[0];
2209   h->ip4_over_ethernet[1].ip4 = dst[0];
2210
2211   b = vlib_get_buffer (vm, bi);
2212   vnet_buffer (b)->sw_if_index[VLIB_RX] =
2213     vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
2214
2215   /* Add encapsulation string for software interface (e.g. ethernet header). */
2216   vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2217   vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2218
2219   {
2220     vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2221     u32 *to_next = vlib_frame_vector_args (f);
2222     to_next[0] = bi;
2223     f->n_vectors = 1;
2224     vlib_put_frame_to_node (vm, hi->output_node_index, f);
2225   }
2226
2227   return /* no error */ 0;
2228 }
2229
2230 typedef enum
2231 {
2232   IP4_REWRITE_NEXT_DROP,
2233   IP4_REWRITE_NEXT_ICMP_ERROR,
2234 } ip4_rewrite_next_t;
2235
2236 always_inline uword
2237 ip4_rewrite_inline (vlib_main_t * vm,
2238                     vlib_node_runtime_t * node,
2239                     vlib_frame_t * frame, int is_midchain)
2240 {
2241   ip_lookup_main_t *lm = &ip4_main.lookup_main;
2242   u32 *from = vlib_frame_vector_args (frame);
2243   u32 n_left_from, n_left_to_next, *to_next, next_index;
2244   vlib_node_runtime_t *error_node =
2245     vlib_node_get_runtime (vm, ip4_input_node.index);
2246
2247   n_left_from = frame->n_vectors;
2248   next_index = node->cached_next_index;
2249   u32 cpu_index = os_get_cpu_number ();
2250
2251   while (n_left_from > 0)
2252     {
2253       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2254
2255       while (n_left_from >= 4 && n_left_to_next >= 2)
2256         {
2257           ip_adjacency_t *adj0, *adj1;
2258           vlib_buffer_t *p0, *p1;
2259           ip4_header_t *ip0, *ip1;
2260           u32 pi0, rw_len0, next0, error0, checksum0, adj_index0;
2261           u32 pi1, rw_len1, next1, error1, checksum1, adj_index1;
2262           u32 tx_sw_if_index0, tx_sw_if_index1;
2263
2264           /* Prefetch next iteration. */
2265           {
2266             vlib_buffer_t *p2, *p3;
2267
2268             p2 = vlib_get_buffer (vm, from[2]);
2269             p3 = vlib_get_buffer (vm, from[3]);
2270
2271             vlib_prefetch_buffer_header (p2, STORE);
2272             vlib_prefetch_buffer_header (p3, STORE);
2273
2274             CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2275             CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2276           }
2277
2278           pi0 = to_next[0] = from[0];
2279           pi1 = to_next[1] = from[1];
2280
2281           from += 2;
2282           n_left_from -= 2;
2283           to_next += 2;
2284           n_left_to_next -= 2;
2285
2286           p0 = vlib_get_buffer (vm, pi0);
2287           p1 = vlib_get_buffer (vm, pi1);
2288
2289           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2290           adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
2291
2292           /* We should never rewrite a pkt using the MISS adjacency */
2293           ASSERT (adj_index0 && adj_index1);
2294
2295           ip0 = vlib_buffer_get_current (p0);
2296           ip1 = vlib_buffer_get_current (p1);
2297
2298           error0 = error1 = IP4_ERROR_NONE;
2299           next0 = next1 = IP4_REWRITE_NEXT_DROP;
2300
2301           /* Decrement TTL & update checksum.
2302              Works either endian, so no need for byte swap. */
2303           if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2304             {
2305               i32 ttl0 = ip0->ttl;
2306
2307               /* Input node should have reject packets with ttl 0. */
2308               ASSERT (ip0->ttl > 0);
2309
2310               checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2311               checksum0 += checksum0 >= 0xffff;
2312
2313               ip0->checksum = checksum0;
2314               ttl0 -= 1;
2315               ip0->ttl = ttl0;
2316
2317               /*
2318                * If the ttl drops below 1 when forwarding, generate
2319                * an ICMP response.
2320                */
2321               if (PREDICT_FALSE (ttl0 <= 0))
2322                 {
2323                   error0 = IP4_ERROR_TIME_EXPIRED;
2324                   vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2325                   icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2326                                                ICMP4_time_exceeded_ttl_exceeded_in_transit,
2327                                                0);
2328                   next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2329                 }
2330
2331               /* Verify checksum. */
2332               ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2333             }
2334           else
2335             {
2336               p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2337             }
2338           if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2339             {
2340               i32 ttl1 = ip1->ttl;
2341
2342               /* Input node should have reject packets with ttl 0. */
2343               ASSERT (ip1->ttl > 0);
2344
2345               checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
2346               checksum1 += checksum1 >= 0xffff;
2347
2348               ip1->checksum = checksum1;
2349               ttl1 -= 1;
2350               ip1->ttl = ttl1;
2351
2352               /*
2353                * If the ttl drops below 1 when forwarding, generate
2354                * an ICMP response.
2355                */
2356               if (PREDICT_FALSE (ttl1 <= 0))
2357                 {
2358                   error1 = IP4_ERROR_TIME_EXPIRED;
2359                   vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2360                   icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
2361                                                ICMP4_time_exceeded_ttl_exceeded_in_transit,
2362                                                0);
2363                   next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
2364                 }
2365
2366               /* Verify checksum. */
2367               ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2368               ASSERT (ip1->checksum == ip4_header_checksum (ip1));
2369             }
2370           else
2371             {
2372               p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2373             }
2374
2375           /* Rewrite packet header and updates lengths. */
2376           adj0 = ip_get_adjacency (lm, adj_index0);
2377           adj1 = ip_get_adjacency (lm, adj_index1);
2378
2379           /* Worth pipelining. No guarantee that adj0,1 are hot... */
2380           rw_len0 = adj0[0].rewrite_header.data_bytes;
2381           rw_len1 = adj1[0].rewrite_header.data_bytes;
2382           vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2383           vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
2384
2385           /* Check MTU of outgoing interface. */
2386           error0 =
2387             (vlib_buffer_length_in_chain (vm, p0) >
2388              adj0[0].
2389              rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2390              error0);
2391           error1 =
2392             (vlib_buffer_length_in_chain (vm, p1) >
2393              adj1[0].
2394              rewrite_header.max_l3_packet_bytes ? IP4_ERROR_MTU_EXCEEDED :
2395              error1);
2396
2397           /*
2398            * We've already accounted for an ethernet_header_t elsewhere
2399            */
2400           if (PREDICT_FALSE (rw_len0 > sizeof (ethernet_header_t)))
2401             vlib_increment_combined_counter
2402               (&adjacency_counters, cpu_index, adj_index0,
2403                /* packet increment */ 0,
2404                /* byte increment */ rw_len0 - sizeof (ethernet_header_t));
2405
2406           if (PREDICT_FALSE (rw_len1 > sizeof (ethernet_header_t)))
2407             vlib_increment_combined_counter
2408               (&adjacency_counters, cpu_index, adj_index1,
2409                /* packet increment */ 0,
2410                /* byte increment */ rw_len1 - sizeof (ethernet_header_t));
2411
2412           /* Don't adjust the buffer for ttl issue; icmp-error node wants
2413            * to see the IP headerr */
2414           if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2415             {
2416               next0 = adj0[0].rewrite_header.next_index;
2417               p0->current_data -= rw_len0;
2418               p0->current_length += rw_len0;
2419               tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2420               vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2421
2422               vnet_feature_arc_start (lm->output_feature_arc_index,
2423                                       tx_sw_if_index0, &next0, p0);
2424             }
2425           if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2426             {
2427               next1 = adj1[0].rewrite_header.next_index;
2428               p1->current_data -= rw_len1;
2429               p1->current_length += rw_len1;
2430
2431               tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2432               vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2433
2434               vnet_feature_arc_start (lm->output_feature_arc_index,
2435                                       tx_sw_if_index1, &next1, p1);
2436             }
2437
2438           /* Guess we are only writing on simple Ethernet header. */
2439           vnet_rewrite_two_headers (adj0[0], adj1[0],
2440                                     ip0, ip1, sizeof (ethernet_header_t));
2441
2442           if (is_midchain)
2443             {
2444               adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2445               adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2446             }
2447
2448           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2449                                            to_next, n_left_to_next,
2450                                            pi0, pi1, next0, next1);
2451         }
2452
2453       while (n_left_from > 0 && n_left_to_next > 0)
2454         {
2455           ip_adjacency_t *adj0;
2456           vlib_buffer_t *p0;
2457           ip4_header_t *ip0;
2458           u32 pi0, rw_len0, adj_index0, next0, error0, checksum0;
2459           u32 tx_sw_if_index0;
2460
2461           pi0 = to_next[0] = from[0];
2462
2463           p0 = vlib_get_buffer (vm, pi0);
2464
2465           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2466
2467           /* We should never rewrite a pkt using the MISS adjacency */
2468           ASSERT (adj_index0);
2469
2470           adj0 = ip_get_adjacency (lm, adj_index0);
2471
2472           ip0 = vlib_buffer_get_current (p0);
2473
2474           error0 = IP4_ERROR_NONE;
2475           next0 = IP4_REWRITE_NEXT_DROP;        /* drop on error */
2476
2477           /* Decrement TTL & update checksum. */
2478           if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2479             {
2480               i32 ttl0 = ip0->ttl;
2481
2482               checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
2483
2484               checksum0 += checksum0 >= 0xffff;
2485
2486               ip0->checksum = checksum0;
2487
2488               ASSERT (ip0->ttl > 0);
2489
2490               ttl0 -= 1;
2491
2492               ip0->ttl = ttl0;
2493
2494               ASSERT (ip0->checksum == ip4_header_checksum (ip0));
2495
2496               if (PREDICT_FALSE (ttl0 <= 0))
2497                 {
2498                   /*
2499                    * If the ttl drops below 1 when forwarding, generate
2500                    * an ICMP response.
2501                    */
2502                   error0 = IP4_ERROR_TIME_EXPIRED;
2503                   next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
2504                   vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2505                   icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
2506                                                ICMP4_time_exceeded_ttl_exceeded_in_transit,
2507                                                0);
2508                 }
2509             }
2510           else
2511             {
2512               p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2513             }
2514
2515           /* Guess we are only writing on simple Ethernet header. */
2516           vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2517
2518           /* Update packet buffer attributes/set output interface. */
2519           rw_len0 = adj0[0].rewrite_header.data_bytes;
2520           vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2521
2522           if (PREDICT_FALSE (rw_len0 > sizeof (ethernet_header_t)))
2523             vlib_increment_combined_counter
2524               (&adjacency_counters, cpu_index, adj_index0,
2525                /* packet increment */ 0,
2526                /* byte increment */ rw_len0 - sizeof (ethernet_header_t));
2527
2528           /* Check MTU of outgoing interface. */
2529           error0 = (vlib_buffer_length_in_chain (vm, p0)
2530                     > adj0[0].rewrite_header.max_l3_packet_bytes
2531                     ? IP4_ERROR_MTU_EXCEEDED : error0);
2532
2533           p0->error = error_node->errors[error0];
2534
2535           /* Don't adjust the buffer for ttl issue; icmp-error node wants
2536            * to see the IP headerr */
2537           if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2538             {
2539               p0->current_data -= rw_len0;
2540               p0->current_length += rw_len0;
2541               tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2542
2543               vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2544               next0 = adj0[0].rewrite_header.next_index;
2545
2546               if (is_midchain)
2547                 {
2548                   adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2549                 }
2550
2551               vnet_feature_arc_start (lm->output_feature_arc_index,
2552                                       tx_sw_if_index0, &next0, p0);
2553
2554             }
2555
2556           from += 1;
2557           n_left_from -= 1;
2558           to_next += 1;
2559           n_left_to_next -= 1;
2560
2561           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2562                                            to_next, n_left_to_next,
2563                                            pi0, next0);
2564         }
2565
2566       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2567     }
2568
2569   /* Need to do trace after rewrites to pick up new packet data. */
2570   if (node->flags & VLIB_NODE_FLAG_TRACE)
2571     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2572
2573   return frame->n_vectors;
2574 }
2575
2576
2577 /** @brief IPv4 rewrite node.
2578     @node ip4-rewrite
2579
2580     This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2581     header checksum, fetch the ip adjacency, check the outbound mtu,
2582     apply the adjacency rewrite, and send pkts to the adjacency
2583     rewrite header's rewrite_next_index.
2584
2585     @param vm vlib_main_t corresponding to the current thread
2586     @param node vlib_node_runtime_t
2587     @param frame vlib_frame_t whose contents should be dispatched
2588
2589     @par Graph mechanics: buffer metadata, next index usage
2590
2591     @em Uses:
2592     - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2593         - the rewrite adjacency index
2594     - <code>adj->lookup_next_index</code>
2595         - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
2596           the packet will be dropped.
2597     - <code>adj->rewrite_header</code>
2598         - Rewrite string length, rewrite string, next_index
2599
2600     @em Sets:
2601     - <code>b->current_data, b->current_length</code>
2602         - Updated net of applying the rewrite string
2603
2604     <em>Next Indices:</em>
2605     - <code> adj->rewrite_header.next_index </code>
2606       or @c error-drop
2607 */
2608 static uword
2609 ip4_rewrite (vlib_main_t * vm,
2610              vlib_node_runtime_t * node, vlib_frame_t * frame)
2611 {
2612   return ip4_rewrite_inline (vm, node, frame, 0);
2613 }
2614
2615 static uword
2616 ip4_midchain (vlib_main_t * vm,
2617               vlib_node_runtime_t * node, vlib_frame_t * frame)
2618 {
2619   return ip4_rewrite_inline (vm, node, frame, 1);
2620 }
2621
2622
2623 VLIB_REGISTER_NODE (ip4_rewrite_node) =
2624 {
2625   .function = ip4_rewrite,.name = "ip4-rewrite",.vector_size =
2626     sizeof (u32),.format_trace = format_ip4_rewrite_trace,.n_next_nodes =
2627     2,.next_nodes =
2628   {
2629   [IP4_REWRITE_NEXT_DROP] = "error-drop",
2630       [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",}
2631 ,};
2632
2633 VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_node, ip4_rewrite);
2634
2635 VLIB_REGISTER_NODE (ip4_midchain_node) =
2636 {
2637 .function = ip4_midchain,.name = "ip4-midchain",.vector_size =
2638     sizeof (u32),.format_trace = format_ip4_forward_next_trace,.sibling_of =
2639     "ip4-rewrite",};
2640
2641 VLIB_NODE_FUNCTION_MULTIARCH (ip4_midchain_node, ip4_midchain);
2642
2643 static clib_error_t *
2644 add_del_interface_table (vlib_main_t * vm,
2645                          unformat_input_t * input, vlib_cli_command_t * cmd)
2646 {
2647   vnet_main_t *vnm = vnet_get_main ();
2648   clib_error_t *error = 0;
2649   u32 sw_if_index, table_id;
2650
2651   sw_if_index = ~0;
2652
2653   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
2654     {
2655       error = clib_error_return (0, "unknown interface `%U'",
2656                                  format_unformat_error, input);
2657       goto done;
2658     }
2659
2660   if (unformat (input, "%d", &table_id))
2661     ;
2662   else
2663     {
2664       error = clib_error_return (0, "expected table id `%U'",
2665                                  format_unformat_error, input);
2666       goto done;
2667     }
2668
2669   {
2670     ip4_main_t *im = &ip4_main;
2671     u32 fib_index;
2672
2673     fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2674                                                    table_id);
2675
2676     //
2677     // FIXME-LATER
2678     //  changing an interface's table has consequences for any connecteds
2679     //  and adj-fibs already installed.
2680     //
2681     vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
2682     im->fib_index_by_sw_if_index[sw_if_index] = fib_index;
2683   }
2684
2685 done:
2686   return error;
2687 }
2688
2689 /*?
2690  * Place the indicated interface into the supplied IPv4 FIB table (also known
2691  * as a VRF). If the FIB table does not exist, this command creates it. To
2692  * display the current IPv4 FIB table, use the command '<em>show ip fib</em>'.
2693  * FIB table will only be displayed if a route has been added to the table, or
2694  * an IP Address is assigned to an interface in the table (which adds a route
2695  * automatically).
2696  *
2697  * @note IP addresses added after setting the interface IP table end up in
2698  * the indicated FIB table. If the IP address is added prior to adding the
2699  * interface to the FIB table, it will NOT be part of the FIB table. Predictable
2700  * but potentially counter-intuitive results occur if you provision interface
2701  * addresses in multiple FIBs. Upon RX, packets will be processed in the last
2702  * IP table ID provisioned. It might be marginally useful to evade source RPF
2703  * drops to put an interface address into multiple FIBs.
2704  *
2705  * @cliexpar
2706  * Example of how to add an interface to an IPv4 FIB table (where 2 is the table-id):
2707  * @cliexcmd{set interface ip table GigabitEthernet2/0/0 2}
2708  ?*/
2709 /* *INDENT-OFF* */
2710 VLIB_CLI_COMMAND (set_interface_ip_table_command, static) =
2711 {
2712   .path = "set interface ip table",
2713   .function = add_del_interface_table,
2714   .short_help = "set interface ip table <interface> <table-id>",
2715 };
2716 /* *INDENT-ON* */
2717
2718
2719 static uword
2720 ip4_lookup_multicast (vlib_main_t * vm,
2721                       vlib_node_runtime_t * node, vlib_frame_t * frame)
2722 {
2723   ip4_main_t *im = &ip4_main;
2724   vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
2725   u32 n_left_from, n_left_to_next, *from, *to_next;
2726   ip_lookup_next_t next;
2727   u32 cpu_index = os_get_cpu_number ();
2728
2729   from = vlib_frame_vector_args (frame);
2730   n_left_from = frame->n_vectors;
2731   next = node->cached_next_index;
2732
2733   while (n_left_from > 0)
2734     {
2735       vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
2736
2737       while (n_left_from >= 4 && n_left_to_next >= 2)
2738         {
2739           vlib_buffer_t *p0, *p1;
2740           u32 pi0, pi1, lb_index0, lb_index1, wrong_next;
2741           ip_lookup_next_t next0, next1;
2742           ip4_header_t *ip0, *ip1;
2743           u32 fib_index0, fib_index1;
2744           const dpo_id_t *dpo0, *dpo1;
2745           const load_balance_t *lb0, *lb1;
2746
2747           /* Prefetch next iteration. */
2748           {
2749             vlib_buffer_t *p2, *p3;
2750
2751             p2 = vlib_get_buffer (vm, from[2]);
2752             p3 = vlib_get_buffer (vm, from[3]);
2753
2754             vlib_prefetch_buffer_header (p2, LOAD);
2755             vlib_prefetch_buffer_header (p3, LOAD);
2756
2757             CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
2758             CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
2759           }
2760
2761           pi0 = to_next[0] = from[0];
2762           pi1 = to_next[1] = from[1];
2763
2764           p0 = vlib_get_buffer (vm, pi0);
2765           p1 = vlib_get_buffer (vm, pi1);
2766
2767           ip0 = vlib_buffer_get_current (p0);
2768           ip1 = vlib_buffer_get_current (p1);
2769
2770           fib_index0 =
2771             vec_elt (im->fib_index_by_sw_if_index,
2772                      vnet_buffer (p0)->sw_if_index[VLIB_RX]);
2773           fib_index1 =
2774             vec_elt (im->fib_index_by_sw_if_index,
2775                      vnet_buffer (p1)->sw_if_index[VLIB_RX]);
2776           fib_index0 =
2777             (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
2778              (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
2779           fib_index1 =
2780             (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
2781              (u32) ~ 0) ? fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
2782
2783           lb_index0 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0),
2784                                                &ip0->dst_address);
2785           lb_index1 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index1),
2786                                                &ip1->dst_address);
2787
2788           lb0 = load_balance_get (lb_index0);
2789           lb1 = load_balance_get (lb_index1);
2790
2791           ASSERT (lb0->lb_n_buckets > 0);
2792           ASSERT (is_pow2 (lb0->lb_n_buckets));
2793           ASSERT (lb1->lb_n_buckets > 0);
2794           ASSERT (is_pow2 (lb1->lb_n_buckets));
2795
2796           vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
2797             (ip0, lb0->lb_hash_config);
2798
2799           vnet_buffer (p1)->ip.flow_hash = ip4_compute_flow_hash
2800             (ip1, lb1->lb_hash_config);
2801
2802           dpo0 = load_balance_get_bucket_i (lb0,
2803                                             (vnet_buffer (p0)->ip.flow_hash &
2804                                              (lb0->lb_n_buckets_minus_1)));
2805           dpo1 = load_balance_get_bucket_i (lb1,
2806                                             (vnet_buffer (p1)->ip.flow_hash &
2807                                              (lb1->lb_n_buckets_minus_1)));
2808
2809           next0 = dpo0->dpoi_next_node;
2810           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
2811           next1 = dpo1->dpoi_next_node;
2812           vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
2813
2814           if (1)                /* $$$$$$ HACK FIXME */
2815             vlib_increment_combined_counter
2816               (cm, cpu_index, lb_index0, 1,
2817                vlib_buffer_length_in_chain (vm, p0));
2818           if (1)                /* $$$$$$ HACK FIXME */
2819             vlib_increment_combined_counter
2820               (cm, cpu_index, lb_index1, 1,
2821                vlib_buffer_length_in_chain (vm, p1));
2822
2823           from += 2;
2824           to_next += 2;
2825           n_left_to_next -= 2;
2826           n_left_from -= 2;
2827
2828           wrong_next = (next0 != next) + 2 * (next1 != next);
2829           if (PREDICT_FALSE (wrong_next != 0))
2830             {
2831               switch (wrong_next)
2832                 {
2833                 case 1:
2834                   /* A B A */
2835                   to_next[-2] = pi1;
2836                   to_next -= 1;
2837                   n_left_to_next += 1;
2838                   vlib_set_next_frame_buffer (vm, node, next0, pi0);
2839                   break;
2840
2841                 case 2:
2842                   /* A A B */
2843                   to_next -= 1;
2844                   n_left_to_next += 1;
2845                   vlib_set_next_frame_buffer (vm, node, next1, pi1);
2846                   break;
2847
2848                 case 3:
2849                   /* A B C */
2850                   to_next -= 2;
2851                   n_left_to_next += 2;
2852                   vlib_set_next_frame_buffer (vm, node, next0, pi0);
2853                   vlib_set_next_frame_buffer (vm, node, next1, pi1);
2854                   if (next0 == next1)
2855                     {
2856                       /* A B B */
2857                       vlib_put_next_frame (vm, node, next, n_left_to_next);
2858                       next = next1;
2859                       vlib_get_next_frame (vm, node, next, to_next,
2860                                            n_left_to_next);
2861                     }
2862                 }
2863             }
2864         }
2865
2866       while (n_left_from > 0 && n_left_to_next > 0)
2867         {
2868           vlib_buffer_t *p0;
2869           ip4_header_t *ip0;
2870           u32 pi0, lb_index0;
2871           ip_lookup_next_t next0;
2872           u32 fib_index0;
2873           const dpo_id_t *dpo0;
2874           const load_balance_t *lb0;
2875
2876           pi0 = from[0];
2877           to_next[0] = pi0;
2878
2879           p0 = vlib_get_buffer (vm, pi0);
2880
2881           ip0 = vlib_buffer_get_current (p0);
2882
2883           fib_index0 = vec_elt (im->fib_index_by_sw_if_index,
2884                                 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
2885           fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
2886             fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
2887
2888           lb_index0 = ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0),
2889                                                &ip0->dst_address);
2890
2891           lb0 = load_balance_get (lb_index0);
2892
2893           ASSERT (lb0->lb_n_buckets > 0);
2894           ASSERT (is_pow2 (lb0->lb_n_buckets));
2895
2896           vnet_buffer (p0)->ip.flow_hash = ip4_compute_flow_hash
2897             (ip0, lb0->lb_hash_config);
2898
2899           dpo0 = load_balance_get_bucket_i (lb0,
2900                                             (vnet_buffer (p0)->ip.flow_hash &
2901                                              (lb0->lb_n_buckets_minus_1)));
2902
2903           next0 = dpo0->dpoi_next_node;
2904           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
2905
2906           if (1)                /* $$$$$$ HACK FIXME */
2907             vlib_increment_combined_counter
2908               (cm, cpu_index, lb_index0, 1,
2909                vlib_buffer_length_in_chain (vm, p0));
2910
2911           from += 1;
2912           to_next += 1;
2913           n_left_to_next -= 1;
2914           n_left_from -= 1;
2915
2916           if (PREDICT_FALSE (next0 != next))
2917             {
2918               n_left_to_next += 1;
2919               vlib_put_next_frame (vm, node, next, n_left_to_next);
2920               next = next0;
2921               vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
2922               to_next[0] = pi0;
2923               to_next += 1;
2924               n_left_to_next -= 1;
2925             }
2926         }
2927
2928       vlib_put_next_frame (vm, node, next, n_left_to_next);
2929     }
2930
2931   if (node->flags & VLIB_NODE_FLAG_TRACE)
2932     ip4_forward_next_trace (vm, node, frame, VLIB_TX);
2933
2934   return frame->n_vectors;
2935 }
2936
2937 VLIB_REGISTER_NODE (ip4_lookup_multicast_node, static) =
2938 {
2939 .function = ip4_lookup_multicast,.name =
2940     "ip4-lookup-multicast",.vector_size = sizeof (u32),.sibling_of =
2941     "ip4-lookup",.format_trace = format_ip4_lookup_trace,.n_next_nodes = 0,};
2942
2943 VLIB_NODE_FUNCTION_MULTIARCH (ip4_lookup_multicast_node,
2944                               ip4_lookup_multicast);
2945
2946 VLIB_REGISTER_NODE (ip4_multicast_node, static) =
2947 {
2948   .function = ip4_drop,.name = "ip4-multicast",.vector_size =
2949     sizeof (u32),.format_trace = format_ip4_forward_next_trace,.n_next_nodes =
2950     1,.next_nodes =
2951   {
2952   [0] = "error-drop",}
2953 ,};
2954
2955 int
2956 ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2957 {
2958   ip4_fib_mtrie_t *mtrie0;
2959   ip4_fib_mtrie_leaf_t leaf0;
2960   u32 lbi0;
2961
2962   mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
2963
2964   leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
2965   leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 0);
2966   leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 1);
2967   leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2968   leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
2969
2970   /* Handle default route. */
2971   leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0);
2972
2973   lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
2974
2975   return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
2976 }
2977
2978 static clib_error_t *
2979 test_lookup_command_fn (vlib_main_t * vm,
2980                         unformat_input_t * input, vlib_cli_command_t * cmd)
2981 {
2982   ip4_fib_t *fib;
2983   u32 table_id = 0;
2984   f64 count = 1;
2985   u32 n;
2986   int i;
2987   ip4_address_t ip4_base_address;
2988   u64 errors = 0;
2989
2990   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2991     {
2992       if (unformat (input, "table %d", &table_id))
2993         {
2994           /* Make sure the entry exists. */
2995           fib = ip4_fib_get (table_id);
2996           if ((fib) && (fib->index != table_id))
2997             return clib_error_return (0, "<fib-index> %d does not exist",
2998                                       table_id);
2999         }
3000       else if (unformat (input, "count %f", &count))
3001         ;
3002
3003       else if (unformat (input, "%U",
3004                          unformat_ip4_address, &ip4_base_address))
3005         ;
3006       else
3007         return clib_error_return (0, "unknown input `%U'",
3008                                   format_unformat_error, input);
3009     }
3010
3011   n = count;
3012
3013   for (i = 0; i < n; i++)
3014     {
3015       if (!ip4_lookup_validate (&ip4_base_address, table_id))
3016         errors++;
3017
3018       ip4_base_address.as_u32 =
3019         clib_host_to_net_u32 (1 +
3020                               clib_net_to_host_u32 (ip4_base_address.as_u32));
3021     }
3022
3023   if (errors)
3024     vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
3025   else
3026     vlib_cli_output (vm, "No errors in %d lookups\n", n);
3027
3028   return 0;
3029 }
3030
3031 /*?
3032  * Perform a lookup of an IPv4 Address (or range of addresses) in the
3033  * given FIB table to determine if there is a conflict with the
3034  * adjacency table. The fib-id can be determined by using the
3035  * '<em>show ip fib</em>' command. If fib-id is not entered, default value
3036  * of 0 is used.
3037  *
3038  * @todo This command uses fib-id, other commands use table-id (not
3039  * just a name, they are different indexes). Would like to change this
3040  * to table-id for consistency.
3041  *
3042  * @cliexpar
3043  * Example of how to run the test lookup command:
3044  * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
3045  * No errors in 2 lookups
3046  * @cliexend
3047 ?*/
3048 /* *INDENT-OFF* */
3049 VLIB_CLI_COMMAND (lookup_test_command, static) =
3050 {
3051   .path = "test lookup",
3052   .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
3053   .function = test_lookup_command_fn,
3054 };
3055 /* *INDENT-ON* */
3056
3057 int
3058 vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
3059 {
3060   ip4_main_t *im4 = &ip4_main;
3061   ip4_fib_t *fib;
3062   uword *p = hash_get (im4->fib_index_by_table_id, table_id);
3063
3064   if (p == 0)
3065     return VNET_API_ERROR_NO_SUCH_FIB;
3066
3067   fib = ip4_fib_get (p[0]);
3068
3069   fib->flow_hash_config = flow_hash_config;
3070   return 0;
3071 }
3072
3073 static clib_error_t *
3074 set_ip_flow_hash_command_fn (vlib_main_t * vm,
3075                              unformat_input_t * input,
3076                              vlib_cli_command_t * cmd)
3077 {
3078   int matched = 0;
3079   u32 table_id = 0;
3080   u32 flow_hash_config = 0;
3081   int rv;
3082
3083   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3084     {
3085       if (unformat (input, "table %d", &table_id))
3086         matched = 1;
3087 #define _(a,v) \
3088     else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3089       foreach_flow_hash_bit
3090 #undef _
3091         else
3092         break;
3093     }
3094
3095   if (matched == 0)
3096     return clib_error_return (0, "unknown input `%U'",
3097                               format_unformat_error, input);
3098
3099   rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3100   switch (rv)
3101     {
3102     case 0:
3103       break;
3104
3105     case VNET_API_ERROR_NO_SUCH_FIB:
3106       return clib_error_return (0, "no such FIB table %d", table_id);
3107
3108     default:
3109       clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3110       break;
3111     }
3112
3113   return 0;
3114 }
3115
3116 /*?
3117  * Configure the set of IPv4 fields used by the flow hash.
3118  *
3119  * @cliexpar
3120  * Example of how to set the flow hash on a given table:
3121  * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3122  * Example of display the configured flow hash:
3123  * @cliexstart{show ip fib}
3124  * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3125  * 0.0.0.0/0
3126  *   unicast-ip4-chain
3127  *   [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3128  *     [0] [@0]: dpo-drop ip6
3129  * 0.0.0.0/32
3130  *   unicast-ip4-chain
3131  *   [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3132  *     [0] [@0]: dpo-drop ip6
3133  * 224.0.0.0/8
3134  *   unicast-ip4-chain
3135  *   [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3136  *     [0] [@0]: dpo-drop ip6
3137  * 6.0.1.2/32
3138  *   unicast-ip4-chain
3139  *   [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3140  *     [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3141  * 7.0.0.1/32
3142  *   unicast-ip4-chain
3143  *   [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3144  *     [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3145  *     [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3146  *     [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3147  *     [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3148  * 240.0.0.0/8
3149  *   unicast-ip4-chain
3150  *   [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3151  *     [0] [@0]: dpo-drop ip6
3152  * 255.255.255.255/32
3153  *   unicast-ip4-chain
3154  *   [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3155  *     [0] [@0]: dpo-drop ip6
3156  * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3157  * 0.0.0.0/0
3158  *   unicast-ip4-chain
3159  *   [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3160  *     [0] [@0]: dpo-drop ip6
3161  * 0.0.0.0/32
3162  *   unicast-ip4-chain
3163  *   [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3164  *     [0] [@0]: dpo-drop ip6
3165  * 172.16.1.0/24
3166  *   unicast-ip4-chain
3167  *   [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3168  *     [0] [@4]: ipv4-glean: af_packet0
3169  * 172.16.1.1/32
3170  *   unicast-ip4-chain
3171  *   [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3172  *     [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3173  * 172.16.1.2/32
3174  *   unicast-ip4-chain
3175  *   [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3176  *     [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3177  * 172.16.2.0/24
3178  *   unicast-ip4-chain
3179  *   [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3180  *     [0] [@4]: ipv4-glean: af_packet1
3181  * 172.16.2.1/32
3182  *   unicast-ip4-chain
3183  *   [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3184  *     [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3185  * 224.0.0.0/8
3186  *   unicast-ip4-chain
3187  *   [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3188  *     [0] [@0]: dpo-drop ip6
3189  * 240.0.0.0/8
3190  *   unicast-ip4-chain
3191  *   [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3192  *     [0] [@0]: dpo-drop ip6
3193  * 255.255.255.255/32
3194  *   unicast-ip4-chain
3195  *   [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3196  *     [0] [@0]: dpo-drop ip6
3197  * @cliexend
3198 ?*/
3199 /* *INDENT-OFF* */
3200 VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3201 {
3202   .path = "set ip flow-hash",
3203   .short_help =
3204   "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3205   .function = set_ip_flow_hash_command_fn,
3206 };
3207 /* *INDENT-ON* */
3208
3209 int
3210 vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3211                              u32 table_index)
3212 {
3213   vnet_main_t *vnm = vnet_get_main ();
3214   vnet_interface_main_t *im = &vnm->interface_main;
3215   ip4_main_t *ipm = &ip4_main;
3216   ip_lookup_main_t *lm = &ipm->lookup_main;
3217   vnet_classify_main_t *cm = &vnet_classify_main;
3218   ip4_address_t *if_addr;
3219
3220   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3221     return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3222
3223   if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3224     return VNET_API_ERROR_NO_SUCH_ENTRY;
3225
3226   vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3227   lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
3228
3229   if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3230
3231   if (NULL != if_addr)
3232     {
3233       fib_prefix_t pfx = {
3234         .fp_len = 32,
3235         .fp_proto = FIB_PROTOCOL_IP4,
3236         .fp_addr.ip4 = *if_addr,
3237       };
3238       u32 fib_index;
3239
3240       fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3241                                                        sw_if_index);
3242
3243
3244       if (table_index != (u32) ~ 0)
3245         {
3246           dpo_id_t dpo = DPO_INVALID;
3247
3248           dpo_set (&dpo,
3249                    DPO_CLASSIFY,
3250                    DPO_PROTO_IP4,
3251                    classify_dpo_create (DPO_PROTO_IP4, table_index));
3252
3253           fib_table_entry_special_dpo_add (fib_index,
3254                                            &pfx,
3255                                            FIB_SOURCE_CLASSIFY,
3256                                            FIB_ENTRY_FLAG_NONE, &dpo);
3257           dpo_reset (&dpo);
3258         }
3259       else
3260         {
3261           fib_table_entry_special_remove (fib_index,
3262                                           &pfx, FIB_SOURCE_CLASSIFY);
3263         }
3264     }
3265
3266   return 0;
3267 }
3268
3269 static clib_error_t *
3270 set_ip_classify_command_fn (vlib_main_t * vm,
3271                             unformat_input_t * input,
3272                             vlib_cli_command_t * cmd)
3273 {
3274   u32 table_index = ~0;
3275   int table_index_set = 0;
3276   u32 sw_if_index = ~0;
3277   int rv;
3278
3279   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3280     {
3281       if (unformat (input, "table-index %d", &table_index))
3282         table_index_set = 1;
3283       else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3284                          vnet_get_main (), &sw_if_index))
3285         ;
3286       else
3287         break;
3288     }
3289
3290   if (table_index_set == 0)
3291     return clib_error_return (0, "classify table-index must be specified");
3292
3293   if (sw_if_index == ~0)
3294     return clib_error_return (0, "interface / subif must be specified");
3295
3296   rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3297
3298   switch (rv)
3299     {
3300     case 0:
3301       break;
3302
3303     case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3304       return clib_error_return (0, "No such interface");
3305
3306     case VNET_API_ERROR_NO_SUCH_ENTRY:
3307       return clib_error_return (0, "No such classifier table");
3308     }
3309   return 0;
3310 }
3311
3312 /*?
3313  * Assign a classification table to an interface. The classification
3314  * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3315  * commands. Once the table is create, use this command to filter packets
3316  * on an interface.
3317  *
3318  * @cliexpar
3319  * Example of how to assign a classification table to an interface:
3320  * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3321 ?*/
3322 /* *INDENT-OFF* */
3323 VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3324 {
3325     .path = "set ip classify",
3326     .short_help =
3327     "set ip classify intfc <interface> table-index <classify-idx>",
3328     .function = set_ip_classify_command_fn,
3329 };
3330 /* *INDENT-ON* */
3331
3332 /*
3333  * fd.io coding-style-patch-verification: ON
3334  *
3335  * Local Variables:
3336  * eval: (c-set-style "gnu")
3337  * End:
3338  */