ip4-input: fix prefetch data issue for tunnel decap cases
[vpp.git] / src / vnet / ip / ip4_input.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_input.c: IP v4 input node
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/ip/ip4_input.h>
41 #include <vnet/ethernet/ethernet.h>
42 #include <vnet/ppp/ppp.h>
43 #include <vnet/hdlc/hdlc.h>
44 #include <vnet/util/throttle.h>
45
46 typedef struct
47 {
48   u8 packet_data[64];
49 } ip4_input_trace_t;
50
51 static u8 *
52 format_ip4_input_trace (u8 * s, va_list * va)
53 {
54   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
55   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
56   ip4_input_trace_t *t = va_arg (*va, ip4_input_trace_t *);
57
58   s = format (s, "%U",
59               format_ip4_header, t->packet_data, sizeof (t->packet_data));
60
61   return s;
62 }
63
64 static_always_inline u32
65 ip4_input_set_next (u32 sw_if_index, vlib_buffer_t * b, int arc_enabled)
66 {
67   ip4_main_t *im = &ip4_main;
68   ip_lookup_main_t *lm = &im->lookup_main;
69   u32 next;
70   u8 arc;
71
72   ip4_header_t *ip = vlib_buffer_get_current (b);
73
74   if (PREDICT_FALSE (ip4_address_is_multicast (&ip->dst_address)))
75     {
76       next = IP4_INPUT_NEXT_LOOKUP_MULTICAST;
77       arc = lm->mcast_feature_arc_index;
78     }
79   else
80     {
81       next = IP4_INPUT_NEXT_LOOKUP;
82       arc = lm->ucast_feature_arc_index;
83     }
84
85   if (arc_enabled)
86     vnet_feature_arc_start (arc, sw_if_index, &next, b);
87
88   return next;
89 }
90
91 static_always_inline void
92 ip4_input_check_sw_if_index (vlib_main_t * vm,
93                              vlib_simple_counter_main_t * cm, u32 sw_if_index,
94                              u32 * last_sw_if_index, u32 * cnt,
95                              int *arc_enabled)
96 {
97   ip4_main_t *im = &ip4_main;
98   ip_lookup_main_t *lm = &im->lookup_main;
99   u32 thread_index;
100   if (*last_sw_if_index == sw_if_index)
101     {
102       (*cnt)++;
103       return;
104     }
105
106   thread_index = vm->thread_index;
107   if (*cnt)
108     vlib_increment_simple_counter (cm, thread_index, *last_sw_if_index, *cnt);
109   *cnt = 1;
110   *last_sw_if_index = sw_if_index;
111
112   if (vnet_have_features (lm->ucast_feature_arc_index, sw_if_index) ||
113       vnet_have_features (lm->mcast_feature_arc_index, sw_if_index))
114     *arc_enabled = 1;
115   else
116     *arc_enabled = 0;
117 }
118
119 /* Validate IP v4 packets and pass them either to forwarding code
120    or drop/punt exception packets. */
121 always_inline uword
122 ip4_input_inline (vlib_main_t * vm,
123                   vlib_node_runtime_t * node,
124                   vlib_frame_t * frame, int verify_checksum)
125 {
126   vnet_main_t *vnm = vnet_get_main ();
127   u32 n_left_from, *from;
128   u32 thread_index = vm->thread_index;
129   vlib_node_runtime_t *error_node =
130     vlib_node_get_runtime (vm, ip4_input_node.index);
131   vlib_simple_counter_main_t *cm;
132   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
133   ip4_header_t *ip[4];
134   u16 nexts[VLIB_FRAME_SIZE], *next;
135   u32 sw_if_index[4];
136   u32 last_sw_if_index = ~0;
137   u32 cnt = 0;
138   int arc_enabled = 0;
139
140   from = vlib_frame_vector_args (frame);
141   n_left_from = frame->n_vectors;
142
143   if (node->flags & VLIB_NODE_FLAG_TRACE)
144     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
145                                    /* stride */ 1,
146                                    sizeof (ip4_input_trace_t));
147
148   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
149                          VNET_INTERFACE_COUNTER_IP4);
150
151   vlib_get_buffers (vm, from, bufs, n_left_from);
152   b = bufs;
153   next = nexts;
154   while (n_left_from >= 4)
155     {
156       u32 x = 0;
157
158       /* Prefetch next iteration. */
159       if (n_left_from >= 12)
160         {
161           vlib_prefetch_buffer_header (b[8], LOAD);
162           vlib_prefetch_buffer_header (b[9], LOAD);
163           vlib_prefetch_buffer_header (b[10], LOAD);
164           vlib_prefetch_buffer_header (b[11], LOAD);
165
166           CLIB_PREFETCH (vlib_buffer_get_current (b[4]),
167                          sizeof (ip4_header_t), LOAD);
168           CLIB_PREFETCH (vlib_buffer_get_current (b[5]),
169                          sizeof (ip4_header_t), LOAD);
170           CLIB_PREFETCH (vlib_buffer_get_current (b[6]),
171                          sizeof (ip4_header_t), LOAD);
172           CLIB_PREFETCH (vlib_buffer_get_current (b[7]),
173                          sizeof (ip4_header_t), LOAD);
174         }
175
176       vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
177       vnet_buffer (b[1])->ip.adj_index[VLIB_RX] = ~0;
178       vnet_buffer (b[2])->ip.adj_index[VLIB_RX] = ~0;
179       vnet_buffer (b[3])->ip.adj_index[VLIB_RX] = ~0;
180
181       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
182       sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
183       sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
184       sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
185
186       x |= sw_if_index[0] ^ last_sw_if_index;
187       x |= sw_if_index[1] ^ last_sw_if_index;
188       x |= sw_if_index[2] ^ last_sw_if_index;
189       x |= sw_if_index[3] ^ last_sw_if_index;
190
191       if (PREDICT_TRUE (x == 0))
192         {
193           /* we deal with 4 more packets sharing the same sw_if_index
194              with the previous one, so we can optimize */
195           cnt += 4;
196           if (arc_enabled)
197             {
198               next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
199               next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
200               next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
201               next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
202             }
203           else
204             {
205               next[0] = ip4_input_set_next (sw_if_index[0], b[0], 0);
206               next[1] = ip4_input_set_next (sw_if_index[1], b[1], 0);
207               next[2] = ip4_input_set_next (sw_if_index[2], b[2], 0);
208               next[3] = ip4_input_set_next (sw_if_index[3], b[3], 0);
209             }
210         }
211       else
212         {
213           ip4_input_check_sw_if_index (vm, cm, sw_if_index[0],
214                                        &last_sw_if_index, &cnt, &arc_enabled);
215           ip4_input_check_sw_if_index (vm, cm, sw_if_index[1],
216                                        &last_sw_if_index, &cnt, &arc_enabled);
217           ip4_input_check_sw_if_index (vm, cm, sw_if_index[2],
218                                        &last_sw_if_index, &cnt, &arc_enabled);
219           ip4_input_check_sw_if_index (vm, cm, sw_if_index[3],
220                                        &last_sw_if_index, &cnt, &arc_enabled);
221
222           next[0] = ip4_input_set_next (sw_if_index[0], b[0], 1);
223           next[1] = ip4_input_set_next (sw_if_index[1], b[1], 1);
224           next[2] = ip4_input_set_next (sw_if_index[2], b[2], 1);
225           next[3] = ip4_input_set_next (sw_if_index[3], b[3], 1);
226         }
227
228       ip[0] = vlib_buffer_get_current (b[0]);
229       ip[1] = vlib_buffer_get_current (b[1]);
230       ip[2] = vlib_buffer_get_current (b[2]);
231       ip[3] = vlib_buffer_get_current (b[3]);
232
233       ip4_input_check_x4 (vm, error_node, b, ip, next, verify_checksum);
234
235       /* next */
236       b += 4;
237       next += 4;
238       n_left_from -= 4;
239     }
240   while (n_left_from)
241     {
242       u32 next0;
243       vnet_buffer (b[0])->ip.adj_index[VLIB_RX] = ~0;
244       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
245       ip4_input_check_sw_if_index (vm, cm, sw_if_index[0], &last_sw_if_index,
246                                    &cnt, &arc_enabled);
247       next0 = ip4_input_set_next (sw_if_index[0], b[0], arc_enabled);
248       ip[0] = vlib_buffer_get_current (b[0]);
249       ip4_input_check_x1 (vm, error_node, b[0], ip[0], &next0,
250                           verify_checksum);
251       next[0] = next0;
252
253       /* next */
254       b += 1;
255       next += 1;
256       n_left_from -= 1;
257     }
258
259   vlib_increment_simple_counter (cm, thread_index, last_sw_if_index, cnt);
260   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
261   return frame->n_vectors;
262 }
263
264 /** \brief IPv4 input node.
265     @node ip4-input
266
267     This is the IPv4 input node: validates ip4 header checksums,
268     verifies ip header lengths, discards pkts with expired TTLs,
269     and sends pkts to the set of ip feature nodes configured on
270     the rx interface.
271
272     @param vm vlib_main_t corresponding to the current thread
273     @param node vlib_node_runtime_t
274     @param frame vlib_frame_t whose contents should be dispatched
275
276     @par Graph mechanics: buffer metadata, next index usage
277
278     @em Uses:
279     - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
280       multicast status.
281     - <code>b->current_config_index</code> corresponding to each pkt's
282       rx sw_if_index.
283          - This sets the per-packet graph trajectory, ensuring that
284            each packet visits the per-interface features in order.
285
286     - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
287         - Indicates the @c sw_if_index value of the interface that the
288           packet was received on.
289
290     @em Sets:
291     - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
292         - The lookup result adjacency index.
293
294     <em>Next Indices:</em>
295     - Dispatches pkts to the (first) feature node:
296       <code> vnet_get_config_data (... &next0 ...); </code>
297       or @c error-drop
298 */
299 VLIB_NODE_FN (ip4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
300                                vlib_frame_t * frame)
301 {
302   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
303 }
304
305 VLIB_NODE_FN (ip4_input_no_checksum_node) (vlib_main_t * vm,
306                                            vlib_node_runtime_t * node,
307                                            vlib_frame_t * frame)
308 {
309   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
310 }
311
312 #ifndef CLIB_MARCH_VARIANT
313 char *ip4_error_strings[] = {
314 #define _(sym,string) string,
315   foreach_ip4_error
316 #undef _
317 };
318 #endif
319
320 /* *INDENT-OFF* */
321 VLIB_REGISTER_NODE (ip4_input_node) = {
322   .name = "ip4-input",
323   .vector_size = sizeof (u32),
324
325   .n_errors = IP4_N_ERROR,
326   .error_strings = ip4_error_strings,
327
328   .n_next_nodes = IP4_INPUT_N_NEXT,
329   .next_nodes = {
330     [IP4_INPUT_NEXT_DROP] = "error-drop",
331     [IP4_INPUT_NEXT_PUNT] = "error-punt",
332     [IP4_INPUT_NEXT_OPTIONS] = "ip4-options",
333     [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
334     [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup",
335     [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
336     [IP4_INPUT_NEXT_REASSEMBLY] = "ip4-reassembly",
337   },
338
339   .format_buffer = format_ip4_header,
340   .format_trace = format_ip4_input_trace,
341 };
342
343 VLIB_REGISTER_NODE (ip4_input_no_checksum_node) = {
344   .name = "ip4-input-no-checksum",
345   .vector_size = sizeof (u32),
346
347   .sibling_of = "ip4-input",
348   .format_buffer = format_ip4_header,
349   .format_trace = format_ip4_input_trace,
350 };
351 /* *INDENT-ON* */
352
353 static clib_error_t *
354 ip4_init (vlib_main_t * vm)
355 {
356   clib_error_t *error;
357
358   ethernet_register_input_type (vm, ETHERNET_TYPE_IP4, ip4_input_node.index);
359   ppp_register_input_protocol (vm, PPP_PROTOCOL_ip4, ip4_input_node.index);
360   hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip4, ip4_input_node.index);
361
362   {
363     extern vlib_node_registration_t ip4_input_no_checksum_node;
364     pg_node_t *pn;
365     pn = pg_get_node (ip4_input_node.index);
366     pn->unformat_edit = unformat_pg_ip4_header;
367     pn = pg_get_node (ip4_input_no_checksum_node.index);
368     pn->unformat_edit = unformat_pg_ip4_header;
369   }
370
371   if ((error = vlib_call_init_function (vm, ip4_cli_init)))
372     return error;
373
374   if ((error = vlib_call_init_function (vm, ip4_source_check_init)))
375     return error;
376
377   if ((error = vlib_call_init_function
378        (vm, ip4_source_and_port_range_check_init)))
379     return error;
380
381   /* Set flow hash to something non-zero. */
382   ip4_main.flow_hash_seed = 0xdeadbeef;
383
384   /* Default TTL for packets we generate. */
385   ip4_main.host_config.ttl = 64;
386
387   return error;
388 }
389
390 VLIB_INIT_FUNCTION (ip4_init);
391
392 static clib_error_t *
393 ip4_main_loop_enter (vlib_main_t * vm)
394 {
395   ip4_main_t *im = &ip4_main;
396   vlib_thread_main_t *tm = &vlib_thread_main;
397   u32 n_vlib_mains = tm->n_vlib_mains;
398
399   throttle_init (&im->arp_throttle, n_vlib_mains, 1e-3);
400
401   return (NULL);
402 }
403
404 VLIB_MAIN_LOOP_ENTER_FUNCTION (ip4_main_loop_enter);
405
406 /*
407  * fd.io coding-style-patch-verification: ON
408  *
409  * Local Variables:
410  * eval: (c-set-style "gnu")
411  * End:
412  */