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