FD.io VPP  v18.07-rc0-415-g6c78436
Vector Packet Processing
ip4_input.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 #ifndef included_ip_input_h
41 #define included_ip_input_h
42 
43 #include <vnet/ip/ip.h>
44 #include <vnet/ethernet/ethernet.h>
45 
46 extern char *ip4_error_strings[];
47 
48 typedef enum
49 {
58 
59 always_inline void
61  vlib_node_runtime_t * error_node,
62  vlib_buffer_t ** p, ip4_header_t ** ip,
63  u16 * next, int verify_checksum)
64 {
65  u8 error0, error1, error2, error3;
66  u32 ip_len0, cur_len0;
67  u32 ip_len1, cur_len1;
68  u32 ip_len2, cur_len2;
69  u32 ip_len3, cur_len3;
70  i32 len_diff0, len_diff1, len_diff2, len_diff3;
71 
72  error0 = error1 = error2 = error3 = IP4_ERROR_NONE;
73 
74  /* Punt packets with options or wrong version. */
75  if (PREDICT_FALSE (ip[0]->ip_version_and_header_length != 0x45))
76  error0 = (ip[0]->ip_version_and_header_length & 0xf) != 5 ?
77  IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
78 
79  if (PREDICT_FALSE (ip[1]->ip_version_and_header_length != 0x45))
80  error1 = (ip[1]->ip_version_and_header_length & 0xf) != 5 ?
81  IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
82 
83  if (PREDICT_FALSE (ip[2]->ip_version_and_header_length != 0x45))
84  error2 = (ip[2]->ip_version_and_header_length & 0xf) != 5 ?
85  IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
86 
87  if (PREDICT_FALSE (ip[3]->ip_version_and_header_length != 0x45))
88  error3 = (ip[3]->ip_version_and_header_length & 0xf) != 5 ?
89  IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
90 
91  if (PREDICT_FALSE (ip[0]->ttl < 1))
92  error0 = IP4_ERROR_TIME_EXPIRED;
93  if (PREDICT_FALSE (ip[1]->ttl < 1))
94  error1 = IP4_ERROR_TIME_EXPIRED;
95  if (PREDICT_FALSE (ip[2]->ttl < 1))
96  error2 = IP4_ERROR_TIME_EXPIRED;
97  if (PREDICT_FALSE (ip[3]->ttl < 1))
98  error3 = IP4_ERROR_TIME_EXPIRED;
99 
100  /* Verify header checksum. */
101  if (verify_checksum)
102  {
103  ip_csum_t sum0, sum1, sum2, sum3;
104 
105  ip4_partial_header_checksum_x1 (ip[0], sum0);
106  ip4_partial_header_checksum_x1 (ip[1], sum1);
107  ip4_partial_header_checksum_x1 (ip[2], sum2);
108  ip4_partial_header_checksum_x1 (ip[3], sum3);
109 
110  error0 = 0xffff != ip_csum_fold (sum0) ?
111  IP4_ERROR_BAD_CHECKSUM : error0;
112  error1 = 0xffff != ip_csum_fold (sum1) ?
113  IP4_ERROR_BAD_CHECKSUM : error1;
114  error2 = 0xffff != ip_csum_fold (sum2) ?
115  IP4_ERROR_BAD_CHECKSUM : error2;
116  error3 = 0xffff != ip_csum_fold (sum3) ?
117  IP4_ERROR_BAD_CHECKSUM : error3;
118  }
119 
120  /* Drop fragmentation offset 1 packets. */
121  error0 = ip4_get_fragment_offset (ip[0]) == 1 ?
122  IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
123  error1 = ip4_get_fragment_offset (ip[1]) == 1 ?
124  IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
125  error2 = ip4_get_fragment_offset (ip[2]) == 1 ?
126  IP4_ERROR_FRAGMENT_OFFSET_ONE : error2;
127  error3 = ip4_get_fragment_offset (ip[3]) == 1 ?
128  IP4_ERROR_FRAGMENT_OFFSET_ONE : error3;
129 
130  /* Verify lengths. */
131  ip_len0 = clib_net_to_host_u16 (ip[0]->length);
132  ip_len1 = clib_net_to_host_u16 (ip[1]->length);
133  ip_len2 = clib_net_to_host_u16 (ip[2]->length);
134  ip_len3 = clib_net_to_host_u16 (ip[3]->length);
135 
136  /* IP length must be at least minimal IP header. */
137  error0 = ip_len0 < sizeof (ip[0][0]) ? IP4_ERROR_TOO_SHORT : error0;
138  error1 = ip_len1 < sizeof (ip[1][0]) ? IP4_ERROR_TOO_SHORT : error1;
139  error2 = ip_len2 < sizeof (ip[2][0]) ? IP4_ERROR_TOO_SHORT : error2;
140  error3 = ip_len3 < sizeof (ip[3][0]) ? IP4_ERROR_TOO_SHORT : error3;
141 
142  cur_len0 = vlib_buffer_length_in_chain (vm, p[0]);
143  cur_len1 = vlib_buffer_length_in_chain (vm, p[1]);
144  cur_len2 = vlib_buffer_length_in_chain (vm, p[2]);
145  cur_len3 = vlib_buffer_length_in_chain (vm, p[3]);
146 
147  len_diff0 = cur_len0 - ip_len0;
148  len_diff1 = cur_len1 - ip_len1;
149  len_diff2 = cur_len2 - ip_len2;
150  len_diff3 = cur_len3 - ip_len3;
151 
152  error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
153  error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
154  error2 = len_diff2 < 0 ? IP4_ERROR_BAD_LENGTH : error2;
155  error3 = len_diff3 < 0 ? IP4_ERROR_BAD_LENGTH : error3;
156 
157  if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
158  {
159  if (error0 == IP4_ERROR_TIME_EXPIRED)
160  {
161  icmp4_error_set_vnet_buffer (p[0], ICMP4_time_exceeded,
162  ICMP4_time_exceeded_ttl_exceeded_in_transit,
163  0);
164  next[0] = IP4_INPUT_NEXT_ICMP_ERROR;
165  }
166  else
167  next[0] = error0 != IP4_ERROR_OPTIONS ?
169  p[0]->error = error_node->errors[error0];
170  }
171  if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
172  {
173  if (error1 == IP4_ERROR_TIME_EXPIRED)
174  {
175  icmp4_error_set_vnet_buffer (p[1], ICMP4_time_exceeded,
176  ICMP4_time_exceeded_ttl_exceeded_in_transit,
177  0);
178  next[1] = IP4_INPUT_NEXT_ICMP_ERROR;
179  }
180  else
181  next[1] = error1 != IP4_ERROR_OPTIONS ?
183  p[1]->error = error_node->errors[error1];
184  }
185  if (PREDICT_FALSE (error2 != IP4_ERROR_NONE))
186  {
187  if (error2 == IP4_ERROR_TIME_EXPIRED)
188  {
189  icmp4_error_set_vnet_buffer (p[2], ICMP4_time_exceeded,
190  ICMP4_time_exceeded_ttl_exceeded_in_transit,
191  0);
192  next[2] = IP4_INPUT_NEXT_ICMP_ERROR;
193  }
194  else
195  next[2] = error2 != IP4_ERROR_OPTIONS ?
197  p[2]->error = error_node->errors[error2];
198  }
199  if (PREDICT_FALSE (error3 != IP4_ERROR_NONE))
200  {
201  if (error3 == IP4_ERROR_TIME_EXPIRED)
202  {
203  icmp4_error_set_vnet_buffer (p[3], ICMP4_time_exceeded,
204  ICMP4_time_exceeded_ttl_exceeded_in_transit,
205  0);
206  next[3] = IP4_INPUT_NEXT_ICMP_ERROR;
207  }
208  else
209  next[3] = error3 != IP4_ERROR_OPTIONS ?
211  p[3]->error = error_node->errors[error3];
212  }
213 }
214 
215 always_inline void
217  vlib_node_runtime_t * error_node,
218  vlib_buffer_t * p0, vlib_buffer_t * p1,
219  ip4_header_t * ip0, ip4_header_t * ip1,
220  u32 * next0, u32 * next1, int verify_checksum)
221 {
222  u8 error0, error1;
223  u32 ip_len0, cur_len0;
224  u32 ip_len1, cur_len1;
225  i32 len_diff0, len_diff1;
226 
227  error0 = error1 = IP4_ERROR_NONE;
228 
229  /* Punt packets with options or wrong version. */
230  if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45))
231  error0 = (ip0->ip_version_and_header_length & 0xf) != 5 ?
232  IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
233 
234  if (PREDICT_FALSE (ip1->ip_version_and_header_length != 0x45))
235  error1 = (ip1->ip_version_and_header_length & 0xf) != 5 ?
236  IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
237 
238  if (PREDICT_FALSE (ip0->ttl < 1))
239  error0 = IP4_ERROR_TIME_EXPIRED;
240  if (PREDICT_FALSE (ip1->ttl < 1))
241  error1 = IP4_ERROR_TIME_EXPIRED;
242 
243  /* Verify header checksum. */
244  if (verify_checksum)
245  {
246  ip_csum_t sum0, sum1;
247 
248  ip4_partial_header_checksum_x1 (ip0, sum0);
249  ip4_partial_header_checksum_x1 (ip1, sum1);
250 
251  error0 = 0xffff != ip_csum_fold (sum0) ?
252  IP4_ERROR_BAD_CHECKSUM : error0;
253  error1 = 0xffff != ip_csum_fold (sum1) ?
254  IP4_ERROR_BAD_CHECKSUM : error1;
255  }
256 
257  /* Drop fragmentation offset 1 packets. */
258  error0 = ip4_get_fragment_offset (ip0) == 1 ?
259  IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
260  error1 = ip4_get_fragment_offset (ip1) == 1 ?
261  IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
262 
263  /* Verify lengths. */
264  ip_len0 = clib_net_to_host_u16 (ip0->length);
265  ip_len1 = clib_net_to_host_u16 (ip1->length);
266 
267  /* IP length must be at least minimal IP header. */
268  error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
269  error1 = ip_len1 < sizeof (ip1[0]) ? IP4_ERROR_TOO_SHORT : error1;
270 
271  cur_len0 = vlib_buffer_length_in_chain (vm, p0);
272  cur_len1 = vlib_buffer_length_in_chain (vm, p1);
273 
274  len_diff0 = cur_len0 - ip_len0;
275  len_diff1 = cur_len1 - ip_len1;
276 
277  error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
278  error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
279 
280  if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
281  {
282  if (error0 == IP4_ERROR_TIME_EXPIRED)
283  {
284  icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
285  ICMP4_time_exceeded_ttl_exceeded_in_transit,
286  0);
287  *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
288  }
289  else
290  *next0 = error0 != IP4_ERROR_OPTIONS ?
292  p0->error = error_node->errors[error0];
293  }
294  if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
295  {
296  if (error1 == IP4_ERROR_TIME_EXPIRED)
297  {
298  icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
299  ICMP4_time_exceeded_ttl_exceeded_in_transit,
300  0);
301  *next1 = IP4_INPUT_NEXT_ICMP_ERROR;
302  }
303  else
304  *next1 = error1 != IP4_ERROR_OPTIONS ?
306  p1->error = error_node->errors[error1];
307  }
308 
309 }
310 
311 always_inline void
313  vlib_node_runtime_t * error_node,
314  vlib_buffer_t * p0,
315  ip4_header_t * ip0, u32 * next0, int verify_checksum)
316 {
317  u32 ip_len0, cur_len0;
318  i32 len_diff0;
319  u8 error0;
320 
321  error0 = IP4_ERROR_NONE;
322 
323  /* Punt packets with options or wrong version. */
324  if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45))
325  error0 = (ip0->ip_version_and_header_length & 0xf) != 5 ?
326  IP4_ERROR_OPTIONS : IP4_ERROR_VERSION;
327 
328  /* Verify header checksum. */
329  if (verify_checksum)
330  {
331  ip_csum_t sum0;
332 
333  ip4_partial_header_checksum_x1 (ip0, sum0);
334 
335  error0 = 0xffff != ip_csum_fold (sum0) ?
336  IP4_ERROR_BAD_CHECKSUM : error0;
337  }
338 
339  /* Drop fragmentation offset 1 packets. */
340  error0 = ip4_get_fragment_offset (ip0) == 1 ?
341  IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
342 
343  /* Verify lengths. */
344  ip_len0 = clib_net_to_host_u16 (ip0->length);
345 
346  /* IP length must be at least minimal IP header. */
347  error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
348 
349  cur_len0 = vlib_buffer_length_in_chain (vm, p0);
350 
351  len_diff0 = cur_len0 - ip_len0;
352 
353  error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
354 
355  if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
356  {
357  if (error0 == IP4_ERROR_TIME_EXPIRED)
358  {
359  icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
360  ICMP4_time_exceeded_ttl_exceeded_in_transit,
361  0);
362  *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
363  }
364  else
365  *next0 = error0 != IP4_ERROR_OPTIONS ?
367  p0->error = error_node->errors[error0];
368  }
369 
370 }
371 
372 /*
373  * fd.io coding-style-patch-verification: ON
374  *
375  * Local Variables:
376  * eval: (c-set-style "gnu")
377  * End:
378  */
379 
380 #endif
uword ip_csum_t
Definition: ip_packet.h:90
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:451
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:250
unsigned char u8
Definition: types.h:56
#define always_inline
Definition: clib.h:92
static int ip4_get_fragment_offset(ip4_header_t *i)
Definition: ip4_packet.h:197
static void ip4_input_check_x1(vlib_main_t *vm, vlib_node_runtime_t *error_node, vlib_buffer_t *p0, ip4_header_t *ip0, u32 *next0, int verify_checksum)
Definition: ip4_input.h:312
unsigned int u32
Definition: types.h:88
unsigned short u16
Definition: types.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:105
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:135
vlib_main_t * vm
Definition: buffer.c:294
void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.c:431
signed int i32
Definition: types.h:81
ip4_input_next_t
Definition: ip4_input.h:48
char * ip4_error_strings[]
Definition: ip4_input.c:309
static void ip4_input_check_x2(vlib_main_t *vm, vlib_node_runtime_t *error_node, vlib_buffer_t *p0, vlib_buffer_t *p1, ip4_header_t *ip0, ip4_header_t *ip1, u32 *next0, u32 *next1, int verify_checksum)
Definition: ip4_input.h:216
#define ip4_partial_header_checksum_x1(ip0, sum0)
Definition: ip4_packet.h:270
static void ip4_input_check_x4(vlib_main_t *vm, vlib_node_runtime_t *error_node, vlib_buffer_t **p, ip4_header_t **ip, u16 *next, int verify_checksum)
Definition: ip4_input.h:60
u8 ip_version_and_header_length
Definition: ip4_packet.h:137
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145