Coding standards cleanup for vnet/vnet/ip, VPP-255
[vpp.git] / vnet / 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/ip.h>
41 #include <vnet/ethernet/ethernet.h>
42 #include <vnet/ppp/ppp.h>
43 #include <vnet/hdlc/hdlc.h>
44
45 typedef struct
46 {
47   u8 packet_data[64];
48 } ip4_input_trace_t;
49
50 static u8 *
51 format_ip4_input_trace (u8 * s, va_list * va)
52 {
53   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
54   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
55   ip4_input_trace_t *t = va_arg (*va, ip4_input_trace_t *);
56
57   s = format (s, "%U",
58               format_ip4_header, t->packet_data, sizeof (t->packet_data));
59
60   return s;
61 }
62
63 typedef enum
64 {
65   IP4_INPUT_NEXT_DROP,
66   IP4_INPUT_NEXT_PUNT,
67   IP4_INPUT_NEXT_LOOKUP,
68   IP4_INPUT_NEXT_LOOKUP_MULTICAST,
69   IP4_INPUT_NEXT_ICMP_ERROR,
70   IP4_INPUT_N_NEXT,
71 } ip4_input_next_t;
72
73 /* Validate IP v4 packets and pass them either to forwarding code
74    or drop/punt exception packets. */
75 always_inline uword
76 ip4_input_inline (vlib_main_t * vm,
77                   vlib_node_runtime_t * node,
78                   vlib_frame_t * frame, int verify_checksum)
79 {
80   ip4_main_t *im = &ip4_main;
81   vnet_main_t *vnm = vnet_get_main ();
82   ip_lookup_main_t *lm = &im->lookup_main;
83   u32 n_left_from, *from, *to_next;
84   ip4_input_next_t next_index;
85   vlib_node_runtime_t *error_node =
86     vlib_node_get_runtime (vm, ip4_input_node.index);
87   vlib_simple_counter_main_t *cm;
88   u32 cpu_index = os_get_cpu_number ();
89
90   from = vlib_frame_vector_args (frame);
91   n_left_from = frame->n_vectors;
92   next_index = node->cached_next_index;
93
94   if (node->flags & VLIB_NODE_FLAG_TRACE)
95     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
96                                    /* stride */ 1,
97                                    sizeof (ip4_input_trace_t));
98
99   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
100                          VNET_INTERFACE_COUNTER_IP4);
101
102   while (n_left_from > 0)
103     {
104       u32 n_left_to_next;
105
106       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
107
108       while (n_left_from >= 4 && n_left_to_next >= 2)
109         {
110           vlib_buffer_t *p0, *p1;
111           ip4_header_t *ip0, *ip1;
112           u32 sw_if_index0, pi0, ip_len0, cur_len0, next0 = 0;
113           u32 sw_if_index1, pi1, ip_len1, cur_len1, next1 = 0;
114           i32 len_diff0, len_diff1;
115           u8 error0, error1, arc0, arc1;
116
117           /* Prefetch next iteration. */
118           {
119             vlib_buffer_t *p2, *p3;
120
121             p2 = vlib_get_buffer (vm, from[2]);
122             p3 = vlib_get_buffer (vm, from[3]);
123
124             vlib_prefetch_buffer_header (p2, LOAD);
125             vlib_prefetch_buffer_header (p3, LOAD);
126
127             CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
128             CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
129           }
130
131           to_next[0] = pi0 = from[0];
132           to_next[1] = pi1 = from[1];
133           from += 2;
134           to_next += 2;
135           n_left_from -= 2;
136           n_left_to_next -= 2;
137
138           p0 = vlib_get_buffer (vm, pi0);
139           p1 = vlib_get_buffer (vm, pi1);
140
141           ip0 = vlib_buffer_get_current (p0);
142           ip1 = vlib_buffer_get_current (p1);
143
144           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
145           sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX];
146
147           arc0 =
148             ip4_address_is_multicast (&ip0->dst_address) ?
149             lm->mcast_feature_arc_index : lm->ucast_feature_arc_index;
150           arc1 =
151             ip4_address_is_multicast (&ip1->dst_address) ?
152             lm->mcast_feature_arc_index : lm->ucast_feature_arc_index;
153
154           vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
155           vnet_buffer (p1)->ip.adj_index[VLIB_RX] = ~0;
156
157           vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
158           vnet_feature_arc_start (arc1, sw_if_index1, &next1, p1);
159
160           vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
161           vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1);
162
163           error0 = error1 = IP4_ERROR_NONE;
164
165           /* Punt packets with options. */
166           error0 =
167             (ip0->ip_version_and_header_length & 0xf) !=
168             5 ? IP4_ERROR_OPTIONS : error0;
169           error1 =
170             (ip1->ip_version_and_header_length & 0xf) !=
171             5 ? IP4_ERROR_OPTIONS : error1;
172
173           /* Version != 4?  Drop it. */
174           error0 =
175             (ip0->ip_version_and_header_length >> 4) !=
176             4 ? IP4_ERROR_VERSION : error0;
177           error1 =
178             (ip1->ip_version_and_header_length >> 4) !=
179             4 ? IP4_ERROR_VERSION : error1;
180
181           /* Verify header checksum. */
182           if (verify_checksum)
183             {
184               ip_csum_t sum0, sum1;
185
186               ip4_partial_header_checksum_x1 (ip0, sum0);
187               ip4_partial_header_checksum_x1 (ip1, sum1);
188
189               error0 =
190                 0xffff !=
191                 ip_csum_fold (sum0) ? IP4_ERROR_BAD_CHECKSUM : error0;
192               error1 =
193                 0xffff !=
194                 ip_csum_fold (sum1) ? IP4_ERROR_BAD_CHECKSUM : error1;
195             }
196
197           /* Drop fragmentation offset 1 packets. */
198           error0 =
199             ip4_get_fragment_offset (ip0) ==
200             1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
201           error1 =
202             ip4_get_fragment_offset (ip1) ==
203             1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
204
205           /* TTL < 1? Drop it. */
206           error0 = (ip0->ttl < 1
207                     && arc0 ==
208                     lm->ucast_feature_arc_index) ? IP4_ERROR_TIME_EXPIRED :
209             error0;
210           error1 = (ip1->ttl < 1
211                     && arc1 ==
212                     lm->ucast_feature_arc_index) ? IP4_ERROR_TIME_EXPIRED :
213             error1;
214
215           /* Verify lengths. */
216           ip_len0 = clib_net_to_host_u16 (ip0->length);
217           ip_len1 = clib_net_to_host_u16 (ip1->length);
218
219           /* IP length must be at least minimal IP header. */
220           error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
221           error1 = ip_len1 < sizeof (ip1[0]) ? IP4_ERROR_TOO_SHORT : error1;
222
223           cur_len0 = vlib_buffer_length_in_chain (vm, p0);
224           cur_len1 = vlib_buffer_length_in_chain (vm, p1);
225
226           len_diff0 = cur_len0 - ip_len0;
227           len_diff1 = cur_len1 - ip_len1;
228
229           error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
230           error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
231
232           p0->error = error_node->errors[error0];
233           p1->error = error_node->errors[error1];
234
235           if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
236             {
237               if (error0 == IP4_ERROR_TIME_EXPIRED)
238                 {
239                   icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
240                                                ICMP4_time_exceeded_ttl_exceeded_in_transit,
241                                                0);
242                   next0 = IP4_INPUT_NEXT_ICMP_ERROR;
243                 }
244               else
245                 next0 =
246                   error0 !=
247                   IP4_ERROR_OPTIONS ? IP4_INPUT_NEXT_DROP :
248                   IP4_INPUT_NEXT_PUNT;
249             }
250           if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
251             {
252               if (error1 == IP4_ERROR_TIME_EXPIRED)
253                 {
254                   icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
255                                                ICMP4_time_exceeded_ttl_exceeded_in_transit,
256                                                0);
257                   next1 = IP4_INPUT_NEXT_ICMP_ERROR;
258                 }
259               else
260                 next1 =
261                   error1 !=
262                   IP4_ERROR_OPTIONS ? IP4_INPUT_NEXT_DROP :
263                   IP4_INPUT_NEXT_PUNT;
264             }
265
266           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
267                                            to_next, n_left_to_next,
268                                            pi0, pi1, next0, next1);
269         }
270       while (n_left_from > 0 && n_left_to_next > 0)
271         {
272           vlib_buffer_t *p0;
273           ip4_header_t *ip0;
274           u32 sw_if_index0, pi0, ip_len0, cur_len0, next0 = 0;
275           i32 len_diff0;
276           u8 error0, arc0;
277
278           pi0 = from[0];
279           to_next[0] = pi0;
280           from += 1;
281           to_next += 1;
282           n_left_from -= 1;
283           n_left_to_next -= 1;
284
285           p0 = vlib_get_buffer (vm, pi0);
286           ip0 = vlib_buffer_get_current (p0);
287
288           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
289
290           arc0 =
291             ip4_address_is_multicast (&ip0->dst_address) ?
292             lm->mcast_feature_arc_index : lm->ucast_feature_arc_index;
293           vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0;
294           vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0);
295
296           vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
297
298           error0 = IP4_ERROR_NONE;
299
300           /* Punt packets with options. */
301           error0 =
302             (ip0->ip_version_and_header_length & 0xf) !=
303             5 ? IP4_ERROR_OPTIONS : error0;
304
305           /* Version != 4?  Drop it. */
306           error0 =
307             (ip0->ip_version_and_header_length >> 4) !=
308             4 ? IP4_ERROR_VERSION : error0;
309
310           /* Verify header checksum. */
311           if (verify_checksum)
312             {
313               ip_csum_t sum0;
314
315               ip4_partial_header_checksum_x1 (ip0, sum0);
316               error0 =
317                 0xffff !=
318                 ip_csum_fold (sum0) ? IP4_ERROR_BAD_CHECKSUM : error0;
319             }
320
321           /* Drop fragmentation offset 1 packets. */
322           error0 =
323             ip4_get_fragment_offset (ip0) ==
324             1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
325
326           /* TTL < 1? Drop it. */
327           error0 = (ip0->ttl < 1
328                     && arc0 ==
329                     lm->ucast_feature_arc_index) ? IP4_ERROR_TIME_EXPIRED :
330             error0;
331
332           /* Verify lengths. */
333           ip_len0 = clib_net_to_host_u16 (ip0->length);
334
335           /* IP length must be at least minimal IP header. */
336           error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
337
338           cur_len0 = vlib_buffer_length_in_chain (vm, p0);
339           len_diff0 = cur_len0 - ip_len0;
340           error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
341
342           p0->error = error_node->errors[error0];
343           if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
344             {
345               if (error0 == IP4_ERROR_TIME_EXPIRED)
346                 {
347                   icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
348                                                ICMP4_time_exceeded_ttl_exceeded_in_transit,
349                                                0);
350                   next0 = IP4_INPUT_NEXT_ICMP_ERROR;
351                 }
352               else
353                 next0 =
354                   error0 !=
355                   IP4_ERROR_OPTIONS ? IP4_INPUT_NEXT_DROP :
356                   IP4_INPUT_NEXT_PUNT;
357             }
358
359           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
360                                            to_next, n_left_to_next,
361                                            pi0, next0);
362         }
363
364       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
365     }
366
367   return frame->n_vectors;
368 }
369
370 /** \brief IPv4 input node.
371     @node ip4-input
372
373     This is the IPv4 input node: validates ip4 header checksums,
374     verifies ip header lengths, discards pkts with expired TTLs,
375     and sends pkts to the set of ip feature nodes configured on
376     the rx interface.
377
378     @param vm vlib_main_t corresponding to the current thread
379     @param node vlib_node_runtime_t
380     @param frame vlib_frame_t whose contents should be dispatched
381
382     @par Graph mechanics: buffer metadata, next index usage
383
384     @em Uses:
385     - vnet_feature_config_main_t cm corresponding to each pkt's dst address unicast /
386       multicast status.
387     - <code>b->current_config_index</code> corresponding to each pkt's
388       rx sw_if_index.
389          - This sets the per-packet graph trajectory, ensuring that
390            each packet visits the per-interface features in order.
391
392     - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
393         - Indicates the @c sw_if_index value of the interface that the
394           packet was received on.
395
396     @em Sets:
397     - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
398         - The lookup result adjacency index.
399
400     <em>Next Indices:</em>
401     - Dispatches pkts to the (first) feature node:
402       <code> vnet_get_config_data (... &next0 ...); </code>
403       or @c error-drop
404 */
405 static uword
406 ip4_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
407 {
408   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 1);
409 }
410
411 static uword
412 ip4_input_no_checksum (vlib_main_t * vm,
413                        vlib_node_runtime_t * node, vlib_frame_t * frame)
414 {
415   return ip4_input_inline (vm, node, frame, /* verify_checksum */ 0);
416 }
417
418 static char *ip4_error_strings[] = {
419 #define _(sym,string) string,
420   foreach_ip4_error
421 #undef _
422 };
423
424 /* *INDENT-OFF* */
425 VLIB_REGISTER_NODE (ip4_input_node) = {
426   .function = ip4_input,
427   .name = "ip4-input",
428   .vector_size = sizeof (u32),
429
430   .n_errors = IP4_N_ERROR,
431   .error_strings = ip4_error_strings,
432
433   .n_next_nodes = IP4_INPUT_N_NEXT,
434   .next_nodes = {
435     [IP4_INPUT_NEXT_DROP] = "error-drop",
436     [IP4_INPUT_NEXT_PUNT] = "error-punt",
437     [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
438     [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-lookup-multicast",
439     [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
440   },
441
442   .format_buffer = format_ip4_header,
443   .format_trace = format_ip4_input_trace,
444 };
445 /* *INDENT-ON* */
446
447 VLIB_NODE_FUNCTION_MULTIARCH (ip4_input_node, ip4_input);
448
449 /* *INDENT-OFF* */
450 VLIB_REGISTER_NODE (ip4_input_no_checksum_node,static) = {
451   .function = ip4_input_no_checksum,
452   .name = "ip4-input-no-checksum",
453   .vector_size = sizeof (u32),
454
455   .n_next_nodes = IP4_INPUT_N_NEXT,
456   .next_nodes = {
457     [IP4_INPUT_NEXT_DROP] = "error-drop",
458     [IP4_INPUT_NEXT_PUNT] = "error-punt",
459     [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup",
460     [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-lookup-multicast",
461     [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
462   },
463
464   .format_buffer = format_ip4_header,
465   .format_trace = format_ip4_input_trace,
466 };
467 /* *INDENT-ON* */
468
469 VLIB_NODE_FUNCTION_MULTIARCH (ip4_input_no_checksum_node,
470                               ip4_input_no_checksum);
471
472 static clib_error_t *
473 ip4_init (vlib_main_t * vm)
474 {
475   clib_error_t *error;
476
477   ethernet_register_input_type (vm, ETHERNET_TYPE_IP4, ip4_input_node.index);
478   ppp_register_input_protocol (vm, PPP_PROTOCOL_ip4, ip4_input_node.index);
479   hdlc_register_input_protocol (vm, HDLC_PROTOCOL_ip4, ip4_input_node.index);
480
481   {
482     pg_node_t *pn;
483     pn = pg_get_node (ip4_input_node.index);
484     pn->unformat_edit = unformat_pg_ip4_header;
485     pn = pg_get_node (ip4_input_no_checksum_node.index);
486     pn->unformat_edit = unformat_pg_ip4_header;
487   }
488
489   if ((error = vlib_call_init_function (vm, ip4_cli_init)))
490     return error;
491
492   if ((error = vlib_call_init_function (vm, ip4_source_check_init)))
493     return error;
494
495   if ((error = vlib_call_init_function
496        (vm, ip4_source_and_port_range_check_init)))
497     return error;
498
499   /* Set flow hash to something non-zero. */
500   ip4_main.flow_hash_seed = 0xdeadbeef;
501
502   /* Default TTL for packets we generate. */
503   ip4_main.host_config.ttl = 64;
504
505   return error;
506 }
507
508 VLIB_INIT_FUNCTION (ip4_init);
509
510 /*
511  * fd.io coding-style-patch-verification: ON
512  *
513  * Local Variables:
514  * eval: (c-set-style "gnu")
515  * End:
516  */