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