FD.io VPP  v20.01-48-g3e0dafb74
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 {
59 
61 check_ver_opt_csum (ip4_header_t * ip, u8 * error, int verify_checksum)
62 {
64  {
65  if ((ip->ip_version_and_header_length & 0xf) != 5)
66  {
67  *error = IP4_ERROR_OPTIONS;
68  if (verify_checksum && ip_csum (ip, ip4_header_bytes (ip)) != 0)
69  *error = IP4_ERROR_BAD_CHECKSUM;
70  }
71  else
72  *error = IP4_ERROR_VERSION;
73  }
74  else
75  if (PREDICT_FALSE (verify_checksum &&
76  ip_csum (ip, sizeof (ip4_header_t)) != 0))
77  *error = IP4_ERROR_BAD_CHECKSUM;
78 }
79 
80 always_inline void
82  vlib_node_runtime_t * error_node,
83  vlib_buffer_t ** p, ip4_header_t ** ip,
84  u16 * next, int verify_checksum)
85 {
86  u8 error0, error1, error2, error3;
87  u32 ip_len0, cur_len0;
88  u32 ip_len1, cur_len1;
89  u32 ip_len2, cur_len2;
90  u32 ip_len3, cur_len3;
91  i32 len_diff0, len_diff1, len_diff2, len_diff3;
92 
93  error0 = error1 = error2 = error3 = IP4_ERROR_NONE;
94 
95  check_ver_opt_csum (ip[0], &error0, verify_checksum);
96  check_ver_opt_csum (ip[1], &error1, verify_checksum);
97  check_ver_opt_csum (ip[2], &error2, verify_checksum);
98  check_ver_opt_csum (ip[3], &error3, verify_checksum);
99 
100  if (PREDICT_FALSE (ip[0]->ttl < 1))
101  error0 = IP4_ERROR_TIME_EXPIRED;
102  if (PREDICT_FALSE (ip[1]->ttl < 1))
103  error1 = IP4_ERROR_TIME_EXPIRED;
104  if (PREDICT_FALSE (ip[2]->ttl < 1))
105  error2 = IP4_ERROR_TIME_EXPIRED;
106  if (PREDICT_FALSE (ip[3]->ttl < 1))
107  error3 = IP4_ERROR_TIME_EXPIRED;
108 
109  /* Drop fragmentation offset 1 packets. */
110  error0 = ip4_get_fragment_offset (ip[0]) == 1 ?
111  IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
112  error1 = ip4_get_fragment_offset (ip[1]) == 1 ?
113  IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
114  error2 = ip4_get_fragment_offset (ip[2]) == 1 ?
115  IP4_ERROR_FRAGMENT_OFFSET_ONE : error2;
116  error3 = ip4_get_fragment_offset (ip[3]) == 1 ?
117  IP4_ERROR_FRAGMENT_OFFSET_ONE : error3;
118 
119  /* Verify lengths. */
120  ip_len0 = clib_net_to_host_u16 (ip[0]->length);
121  ip_len1 = clib_net_to_host_u16 (ip[1]->length);
122  ip_len2 = clib_net_to_host_u16 (ip[2]->length);
123  ip_len3 = clib_net_to_host_u16 (ip[3]->length);
124 
125  /* IP length must be at least minimal IP header. */
126  error0 = ip_len0 < sizeof (ip[0][0]) ? IP4_ERROR_TOO_SHORT : error0;
127  error1 = ip_len1 < sizeof (ip[1][0]) ? IP4_ERROR_TOO_SHORT : error1;
128  error2 = ip_len2 < sizeof (ip[2][0]) ? IP4_ERROR_TOO_SHORT : error2;
129  error3 = ip_len3 < sizeof (ip[3][0]) ? IP4_ERROR_TOO_SHORT : error3;
130 
131  cur_len0 = vlib_buffer_length_in_chain (vm, p[0]);
132  cur_len1 = vlib_buffer_length_in_chain (vm, p[1]);
133  cur_len2 = vlib_buffer_length_in_chain (vm, p[2]);
134  cur_len3 = vlib_buffer_length_in_chain (vm, p[3]);
135 
136  len_diff0 = cur_len0 - ip_len0;
137  len_diff1 = cur_len1 - ip_len1;
138  len_diff2 = cur_len2 - ip_len2;
139  len_diff3 = cur_len3 - ip_len3;
140 
141  error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
142  error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
143  error2 = len_diff2 < 0 ? IP4_ERROR_BAD_LENGTH : error2;
144  error3 = len_diff3 < 0 ? IP4_ERROR_BAD_LENGTH : error3;
145 
146  if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
147  {
148  if (error0 == IP4_ERROR_TIME_EXPIRED)
149  {
150  icmp4_error_set_vnet_buffer (p[0], ICMP4_time_exceeded,
151  ICMP4_time_exceeded_ttl_exceeded_in_transit,
152  0);
153  next[0] = IP4_INPUT_NEXT_ICMP_ERROR;
154  }
155  else
156  next[0] = error0 != IP4_ERROR_OPTIONS ?
158  p[0]->error = error_node->errors[error0];
159  }
160  if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
161  {
162  if (error1 == IP4_ERROR_TIME_EXPIRED)
163  {
164  icmp4_error_set_vnet_buffer (p[1], ICMP4_time_exceeded,
165  ICMP4_time_exceeded_ttl_exceeded_in_transit,
166  0);
167  next[1] = IP4_INPUT_NEXT_ICMP_ERROR;
168  }
169  else
170  next[1] = error1 != IP4_ERROR_OPTIONS ?
172  p[1]->error = error_node->errors[error1];
173  }
174  if (PREDICT_FALSE (error2 != IP4_ERROR_NONE))
175  {
176  if (error2 == IP4_ERROR_TIME_EXPIRED)
177  {
178  icmp4_error_set_vnet_buffer (p[2], ICMP4_time_exceeded,
179  ICMP4_time_exceeded_ttl_exceeded_in_transit,
180  0);
181  next[2] = IP4_INPUT_NEXT_ICMP_ERROR;
182  }
183  else
184  next[2] = error2 != IP4_ERROR_OPTIONS ?
186  p[2]->error = error_node->errors[error2];
187  }
188  if (PREDICT_FALSE (error3 != IP4_ERROR_NONE))
189  {
190  if (error3 == IP4_ERROR_TIME_EXPIRED)
191  {
192  icmp4_error_set_vnet_buffer (p[3], ICMP4_time_exceeded,
193  ICMP4_time_exceeded_ttl_exceeded_in_transit,
194  0);
195  next[3] = IP4_INPUT_NEXT_ICMP_ERROR;
196  }
197  else
198  next[3] = error3 != IP4_ERROR_OPTIONS ?
200  p[3]->error = error_node->errors[error3];
201  }
202 }
203 
204 always_inline void
206  vlib_node_runtime_t * error_node,
207  vlib_buffer_t * p0, vlib_buffer_t * p1,
208  ip4_header_t * ip0, ip4_header_t * ip1,
209  u32 * next0, u32 * next1, int verify_checksum)
210 {
211  u8 error0, error1;
212  u32 ip_len0, cur_len0;
213  u32 ip_len1, cur_len1;
214  i32 len_diff0, len_diff1;
215 
216  error0 = error1 = IP4_ERROR_NONE;
217 
218  check_ver_opt_csum (ip0, &error0, verify_checksum);
219  check_ver_opt_csum (ip1, &error1, verify_checksum);
220 
221  if (PREDICT_FALSE (ip0->ttl < 1))
222  error0 = IP4_ERROR_TIME_EXPIRED;
223  if (PREDICT_FALSE (ip1->ttl < 1))
224  error1 = IP4_ERROR_TIME_EXPIRED;
225 
226  /* Drop fragmentation offset 1 packets. */
227  error0 = ip4_get_fragment_offset (ip0) == 1 ?
228  IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
229  error1 = ip4_get_fragment_offset (ip1) == 1 ?
230  IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
231 
232  /* Verify lengths. */
233  ip_len0 = clib_net_to_host_u16 (ip0->length);
234  ip_len1 = clib_net_to_host_u16 (ip1->length);
235 
236  /* IP length must be at least minimal IP header. */
237  error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
238  error1 = ip_len1 < sizeof (ip1[0]) ? IP4_ERROR_TOO_SHORT : error1;
239 
240  cur_len0 = vlib_buffer_length_in_chain (vm, p0);
241  cur_len1 = vlib_buffer_length_in_chain (vm, p1);
242 
243  len_diff0 = cur_len0 - ip_len0;
244  len_diff1 = cur_len1 - ip_len1;
245 
246  error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
247  error1 = len_diff1 < 0 ? IP4_ERROR_BAD_LENGTH : error1;
248 
249  if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
250  {
251  if (error0 == IP4_ERROR_TIME_EXPIRED)
252  {
253  icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
254  ICMP4_time_exceeded_ttl_exceeded_in_transit,
255  0);
256  *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
257  }
258  else
259  *next0 = error0 != IP4_ERROR_OPTIONS ?
261  p0->error = error_node->errors[error0];
262  }
263  if (PREDICT_FALSE (error1 != IP4_ERROR_NONE))
264  {
265  if (error1 == IP4_ERROR_TIME_EXPIRED)
266  {
267  icmp4_error_set_vnet_buffer (p1, ICMP4_time_exceeded,
268  ICMP4_time_exceeded_ttl_exceeded_in_transit,
269  0);
270  *next1 = IP4_INPUT_NEXT_ICMP_ERROR;
271  }
272  else
273  *next1 = error1 != IP4_ERROR_OPTIONS ?
275  p1->error = error_node->errors[error1];
276  }
277 }
278 
279 always_inline void
281  vlib_node_runtime_t * error_node,
282  vlib_buffer_t * p0,
283  ip4_header_t * ip0, u32 * next0, int verify_checksum)
284 {
285  u32 ip_len0, cur_len0;
286  i32 len_diff0;
287  u8 error0;
288 
289  error0 = IP4_ERROR_NONE;
290 
291  check_ver_opt_csum (ip0, &error0, verify_checksum);
292 
293  if (PREDICT_FALSE (ip0->ttl < 1))
294  error0 = IP4_ERROR_TIME_EXPIRED;
295 
296  /* Drop fragmentation offset 1 packets. */
297  error0 = ip4_get_fragment_offset (ip0) == 1 ?
298  IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
299 
300  /* Verify lengths. */
301  ip_len0 = clib_net_to_host_u16 (ip0->length);
302 
303  /* IP length must be at least minimal IP header. */
304  error0 = ip_len0 < sizeof (ip0[0]) ? IP4_ERROR_TOO_SHORT : error0;
305 
306  cur_len0 = vlib_buffer_length_in_chain (vm, p0);
307 
308  len_diff0 = cur_len0 - ip_len0;
309 
310  error0 = len_diff0 < 0 ? IP4_ERROR_BAD_LENGTH : error0;
311 
312  if (PREDICT_FALSE (error0 != IP4_ERROR_NONE))
313  {
314  if (error0 == IP4_ERROR_TIME_EXPIRED)
315  {
316  icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
317  ICMP4_time_exceeded_ttl_exceeded_in_transit,
318  0);
319  *next0 = IP4_INPUT_NEXT_ICMP_ERROR;
320  }
321  else
322  *next0 = error0 != IP4_ERROR_OPTIONS ?
324  p0->error = error_node->errors[error0];
325  }
326 }
327 
328 /*
329  * fd.io coding-style-patch-verification: ON
330  *
331  * Local Variables:
332  * eval: (c-set-style "gnu")
333  * End:
334  */
335 
336 #endif
static_always_inline void check_ver_opt_csum(ip4_header_t *ip, u8 *error, int verify_checksum)
Definition: ip4_input.h:61
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
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:366
unsigned char u8
Definition: types.h:56
#define static_always_inline
Definition: clib.h:99
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:280
unsigned int u32
Definition: types.h:88
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
unsigned short u16
Definition: types.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define always_inline
Definition: ipsec.h:28
static_always_inline u16 ip_csum(void *data, u16 n_left)
Definition: ip_packet.h:153
vlib_main_t * vm
Definition: in2out_ed.c:1810
static u16 ip4_get_fragment_offset(const ip4_header_t *i)
Definition: ip4_packet.h:200
u8 ttl
Definition: fib_types.api:26
signed int i32
Definition: types.h:77
ip4_input_next_t
Definition: ip4_input.h:48
char * ip4_error_strings[]
Definition: ip4_input.c:377
vl_api_address_t ip
Definition: l2.api:490
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:205
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:81
VLIB buffer representation.
Definition: buffer.h:102
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:235
u8 ip_version_and_header_length
Definition: ip4_packet.h:138
static_always_inline void icmp4_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp4.h:51