FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
ip4_packet.h
Go to the documentation of this file.
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  * ip4/packet.h: ip4 packet format
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_ip4_packet_h
41 #define included_ip4_packet_h
42 
43 #include <vnet/ip/ip_packet.h> /* for ip_csum_t */
44 #include <vnet/tcp/tcp_packet.h> /* for tcp_header_t */
45 #include <vppinfra/byte_order.h> /* for clib_net_to_host_u16 */
46 #include <vppinfra/warnings.h> /* for WARN_OFF/WARN_ON macro */
47 
48 /* IP4 address which can be accessed either as 4 bytes
49  or as a 32-bit number. */
50 typedef union
51 {
52  u8 data[4];
54  /* Aliases. */
55  u8 as_u8[4];
56  u16 as_u16[2];
59 
60 typedef struct
61 {
62  /* IP address must be first for ip_interface_address_get_address() to work */
66 
67 always_inline void
69  const ip4_address_t * address, u32 fib_index)
70 {
71  clib_memcpy_fast (&addr_fib->ip4_addr, address,
72  sizeof (addr_fib->ip4_addr));
73  addr_fib->fib_index = fib_index;
74 }
75 
76 /* (src,dst) pair of addresses as found in packet header. */
77 typedef struct
78 {
81 
82 typedef struct
83 {
86 
87 typedef union
88 {
89  struct
90  {
91  /* 4 bit packet length (in 32bit units) and version VVVVLLLL.
92  e.g. for packets w/ no options ip_version_and_header_length == 0x45. */
94 
95  /* Type of service. */
97 
98  /* Total layer 3 packet length including this header. */
100 
101  /* Fragmentation ID. */
103 
104  /* 3 bits of flags and 13 bits of fragment offset (in units
105  of 8 byte quantities). */
107 #define IP4_HEADER_FLAG_MORE_FRAGMENTS (1 << 13)
108 #define IP4_HEADER_FLAG_DONT_FRAGMENT (1 << 14)
109 #define IP4_HEADER_FLAG_CONGESTION (1 << 15)
110 
111  /* Time to live decremented by router at each hop. */
113 
114  /* Next level protocol packet. */
116 
117  /* Checksum. */
119 
120  /* Source and destination address. */
121  union
122  {
123  struct
124  {
126  };
128  };
129  };
130 
131  /* For checksumming we'll want to access IP header in word sized chunks. */
132  /* For 64 bit machines. */
133  /* *INDENT-OFF* */
134  CLIB_PACKED (struct {
135  u64 checksum_data_64[2];
136  u32 checksum_data_64_32[1];
137  });
138  /* *INDENT-ON* */
139 
140  /* For 32 bit machines. */
141  /* *INDENT-OFF* */
142  CLIB_PACKED (struct {
143  u32 checksum_data_32[5];
144  });
145  /* *INDENT-ON* */
146 } ip4_header_t;
147 
148 /* Value of ip_version_and_header_length for packets w/o options. */
149 #define IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS \
150  ((4 << 4) | (sizeof (ip4_header_t) / sizeof (u32)))
151 
152 #define IP4_ROUTER_ALERT_OPTION 20
153 
155 ip4_get_fragment_offset (const ip4_header_t * i)
156 {
157  return clib_net_to_host_u16 (i->flags_and_fragment_offset) & 0x1fff;
158 }
159 
161 ip4_get_fragment_more (const ip4_header_t * i)
162 {
163  return clib_net_to_host_u16 (i->flags_and_fragment_offset) &
165 }
166 
167 always_inline int
168 ip4_is_fragment (const ip4_header_t * i)
169 {
170  return (i->flags_and_fragment_offset &
171  clib_net_to_host_u16 (0x1fff | IP4_HEADER_FLAG_MORE_FRAGMENTS));
172 }
173 
174 always_inline int
175 ip4_is_first_fragment (const ip4_header_t * i)
176 {
177  return (i->flags_and_fragment_offset &
178  clib_net_to_host_u16 (0x1fff | IP4_HEADER_FLAG_MORE_FRAGMENTS)) ==
179  clib_net_to_host_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS);
180 }
181 
182 /* Fragment offset in bytes. */
183 always_inline int
184 ip4_get_fragment_offset_bytes (const ip4_header_t * i)
185 {
186  return 8 * ip4_get_fragment_offset (i);
187 }
188 
189 always_inline int
190 ip4_header_bytes (const ip4_header_t * i)
191 {
192  return sizeof (u32) * (i->ip_version_and_header_length & 0xf);
193 }
194 
195 always_inline void *
196 ip4_next_header (ip4_header_t * i)
197 {
198  return (void *) i + ip4_header_bytes (i);
199 }
200 
201 /* Turn off array bounds check due to ip4_header_t
202  option field operations. */
203 
204 /* *INDENT-OFF* */
205 WARN_OFF(array-bounds)
206 /* *INDENT-ON* */
207 
209 ip4_header_checksum_inline (ip4_header_t * i, int with_checksum)
210 {
211  int option_len = (i->ip_version_and_header_length & 0xf) - 5;
212  uword sum = 0;
213 #if uword_bits == 64
214  u32 *iphdr = (u32 *) i;
215 
216  sum += iphdr[0];
217  sum += iphdr[1];
218  sum += with_checksum ? iphdr[2] : *(u16 *) (iphdr + 2);
219  /* skip checksum */
220  sum += iphdr[3];
221  sum += iphdr[4];
222 
223  if (PREDICT_FALSE (option_len > 0))
224  switch (option_len)
225  {
226  case 10:
227  sum += iphdr[14];
228  case 9:
229  sum += iphdr[13];
230  case 8:
231  sum += iphdr[12];
232  case 7:
233  sum += iphdr[11];
234  case 6:
235  sum += iphdr[10];
236  case 5:
237  sum += iphdr[9];
238  case 4:
239  sum += iphdr[8];
240  case 3:
241  sum += iphdr[7];
242  case 2:
243  sum += iphdr[6];
244  case 1:
245  sum += iphdr[5];
246  default:
247  break;
248  }
249 
250  sum = ((u32) sum) + (sum >> 32);
251 #else
252  u16 *iphdr = (u16 *) i;
253 
254  sum += iphdr[0];
255  sum += iphdr[1];
256  sum += iphdr[2];
257  sum += iphdr[3];
258  sum += iphdr[4];
259  if (with_checksum)
260  sum += iphdr[5];
261  sum += iphdr[6];
262  sum += iphdr[7];
263  sum += iphdr[8];
264  sum += iphdr[9];
265 
266  if (PREDICT_FALSE (option_len > 0))
267  switch (option_len)
268  {
269  case 10:
270  sum += iphdr[28];
271  sum += iphdr[29];
272  case 9:
273  sum += iphdr[26];
274  sum += iphdr[27];
275  case 8:
276  sum += iphdr[24];
277  sum += iphdr[25];
278  case 7:
279  sum += iphdr[22];
280  sum += iphdr[23];
281  case 6:
282  sum += iphdr[20];
283  sum += iphdr[21];
284  case 5:
285  sum += iphdr[18];
286  sum += iphdr[19];
287  case 4:
288  sum += iphdr[16];
289  sum += iphdr[17];
290  case 3:
291  sum += iphdr[14];
292  sum += iphdr[15];
293  case 2:
294  sum += iphdr[12];
295  sum += iphdr[13];
296  case 1:
297  sum += iphdr[10];
298  sum += iphdr[11];
299  default:
300  break;
301  }
302 #endif
303 
304  sum = ((u16) sum) + (sum >> 16);
305  sum = ((u16) sum) + (sum >> 16);
306  return ~((u16) sum);
307 }
308 
309 /* *INDENT-OFF* */
310 WARN_ON(array-bounds)
311 /* *INDENT-ON* */
312 
314 ip4_header_checksum (ip4_header_t * i)
315 {
316  return ip4_header_checksum_inline (i, /* with_checksum */ 0);
317 }
318 
319 always_inline void
321 {
322  ip4->tos &= ~0xfc;
323  /* not masking the dscp value to save th instruction
324  * it shouldn't b necessary since the argument is an enum
325  * whose range is therefore constrained in the CP. in the
326  * DP it will have been taken from another packet, so again
327  * constrained in value */
328  ip4->tos |= dscp << IP_PACKET_TC_FIELD_DSCP_BIT_SHIFT;
329 }
330 
331 always_inline void
332 ip4_header_set_ecn (ip4_header_t * ip4, ip_ecn_t ecn)
333 {
335  ip4->tos |= ecn;
336 }
337 
338 always_inline void
340 {
341  ip_csum_t sum = ip4->checksum;
342  u8 old = ip4->tos;
343  u8 new = (old & ~IP_PACKET_TC_FIELD_ECN_MASK) | ecn;
344 
345  sum = ip_csum_update (sum, old, new, ip4_header_t, tos);
346  ip4->checksum = ip_csum_fold (sum);
347  ip4->tos = new;
348 }
349 
351 ip4_header_get_dscp (const ip4_header_t * ip4)
352 {
353  return (ip4->tos >> IP_PACKET_TC_FIELD_DSCP_BIT_SHIFT);
354 }
355 
357 ip4_header_get_ecn (const ip4_header_t * ip4)
358 {
359  return (ip4->tos & IP_PACKET_TC_FIELD_ECN_MASK);
360 }
361 
362 always_inline void
363 ip4_header_set_df (ip4_header_t * ip4)
364 {
366  clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
367 }
368 
369 always_inline void
370 ip4_header_clear_df (ip4_header_t * ip4)
371 {
373  ~clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
374 }
375 
377 ip4_header_get_df (const ip4_header_t * ip4)
378 {
379  return (! !(ip4->flags_and_fragment_offset &
380  clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT)));
381 }
382 
383 static inline uword
385 {
386  return ip4_header_checksum_inline (i, /* with_checksum */ 1) == 0;
387 }
388 
389 #define ip4_partial_header_checksum_x1(ip0,sum0) \
390 do { \
391  if (BITS (ip_csum_t) > 32) \
392  { \
393  sum0 = ip0->checksum_data_64[0]; \
394  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]); \
395  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]); \
396  } \
397  else \
398  { \
399  sum0 = ip0->checksum_data_32[0]; \
400  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]); \
401  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]); \
402  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]); \
403  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]); \
404  } \
405 } while (0)
406 
407 #define ip4_partial_header_checksum_x2(ip0,ip1,sum0,sum1) \
408 do { \
409  if (BITS (ip_csum_t) > 32) \
410  { \
411  sum0 = ip0->checksum_data_64[0]; \
412  sum1 = ip1->checksum_data_64[0]; \
413  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]); \
414  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64[1]); \
415  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]); \
416  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64_32[0]); \
417  } \
418  else \
419  { \
420  sum0 = ip0->checksum_data_32[0]; \
421  sum1 = ip1->checksum_data_32[0]; \
422  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]); \
423  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[1]); \
424  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]); \
425  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[2]); \
426  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]); \
427  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[3]); \
428  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]); \
429  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[4]); \
430  } \
431 } while (0)
432 
435 {
436  return (a->data[0] & 0xf0) == 0xe0;
437 }
438 
441 {
442  return (a->as_u32) == 0xffffffff;
443 }
444 
445 always_inline void
448 {
449  ASSERT ((u32) g < (1 << 28));
450  a->as_u32 = clib_host_to_net_u32 ((0xe << 28) + g);
451 }
452 
453 always_inline void
454 ip4_multicast_ethernet_address (u8 * ethernet_address,
455  const ip4_address_t * a)
456 {
457  const u8 *d = a->as_u8;
458 
459  ethernet_address[0] = 0x01;
460  ethernet_address[1] = 0x00;
461  ethernet_address[2] = 0x5e;
462  ethernet_address[3] = d[1] & 0x7f;
463  ethernet_address[4] = d[2];
464  ethernet_address[5] = d[3];
465 }
466 
467 always_inline void
468 ip4_tcp_reply_x1 (ip4_header_t * ip0, tcp_header_t * tcp0)
469 {
470  u32 src0, dst0;
471 
472  src0 = ip0->src_address.data_u32;
473  dst0 = ip0->dst_address.data_u32;
474  ip0->src_address.data_u32 = dst0;
475  ip0->dst_address.data_u32 = src0;
476 
477  src0 = tcp0->src;
478  dst0 = tcp0->dst;
479  tcp0->src = dst0;
480  tcp0->dst = src0;
481 }
482 
483 always_inline void
484 ip4_tcp_reply_x2 (ip4_header_t * ip0, ip4_header_t * ip1,
485  tcp_header_t * tcp0, tcp_header_t * tcp1)
486 {
487  u32 src0, dst0, src1, dst1;
488 
489  src0 = ip0->src_address.data_u32;
490  src1 = ip1->src_address.data_u32;
491  dst0 = ip0->dst_address.data_u32;
492  dst1 = ip1->dst_address.data_u32;
493  ip0->src_address.data_u32 = dst0;
494  ip1->src_address.data_u32 = dst1;
495  ip0->dst_address.data_u32 = src0;
496  ip1->dst_address.data_u32 = src1;
497 
498  src0 = tcp0->src;
499  src1 = tcp1->src;
500  dst0 = tcp0->dst;
501  dst1 = tcp1->dst;
502  tcp0->src = dst0;
503  tcp1->src = dst1;
504  tcp0->dst = src0;
505  tcp1->dst = src1;
506 }
507 
508 #endif /* included_ip4_packet_h */
509 
510 /*
511  * fd.io coding-style-patch-verification: ON
512  *
513  * Local Variables:
514  * eval: (c-set-style "gnu")
515  * End:
516  */
ip4_address_t ip4_addr
Definition: ip4_packet.h:63
a
Definition: bitmap.h:538
ip4_address_t src_address
Definition: ip4_packet.h:125
static ip_dscp_t ip4_header_get_dscp(const ip4_header_t *ip4)
Definition: ip4_packet.h:351
unsigned long u64
Definition: types.h:89
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
static void ip4_header_set_ecn_w_chksum(ip4_header_t *ip4, ip_ecn_t ecn)
Definition: ip4_packet.h:339
enum ip_ecn_t_ ip_ecn_t
uword ip_csum_t
Definition: ip_packet.h:244
static void ip4_header_set_dscp(ip4_header_t *ip4, ip_dscp_t dscp)
Definition: ip4_packet.h:320
u16 flags_and_fragment_offset
Definition: ip4_packet.h:106
#define IP_PACKET_TC_FIELD_ECN_MASK
Definition: ip_packet.h:128
static uword ip4_address_is_multicast(const ip4_address_t *a)
Definition: ip4_packet.h:434
struct _tcp_header tcp_header_t
vhost_vring_addr_t addr
Definition: vhost_user.h:111
static void ip4_header_clear_df(ip4_header_t *ip4)
Definition: ip4_packet.h:370
static void ip4_tcp_reply_x1(ip4_header_t *ip0, tcp_header_t *tcp0)
Definition: ip4_packet.h:468
unsigned char u8
Definition: types.h:56
static int ip4_get_fragment_offset_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:184
u8 data[128]
Definition: ipsec_types.api:89
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:168
#define static_always_inline
Definition: clib.h:108
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:384
static u16 ip4_get_fragment_more(const ip4_header_t *i)
Definition: ip4_packet.h:161
ip4_address_t dst_address
Definition: ip4_packet.h:125
#define IP_PACKET_TC_FIELD_DSCP_BIT_SHIFT
IP DSCP bit shift The ECN occupies the 2 least significant bits of the TC field.
Definition: ip_packet.h:127
#define WARN_ON(x)
Definition: warnings.h:81
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:196
unsigned int u32
Definition: types.h:88
vl_api_ip_dscp_t dscp
Definition: dhcp.api:163
static void ip4_header_set_ecn(ip4_header_t *ip4, ip_ecn_t ecn)
Definition: ip4_packet.h:332
static void ip4_header_set_df(ip4_header_t *ip4)
Definition: ip4_packet.h:363
unsigned short u16
Definition: types.h:57
ip4_address_pair_t address_pair
Definition: ip4_packet.h:127
#define PREDICT_FALSE(x)
Definition: clib.h:120
#define always_inline
Definition: ipsec.h:28
vl_api_ip4_address_t ip4
Definition: one.api:376
static void ip4_tcp_reply_x2(ip4_header_t *ip0, ip4_header_t *ip1, tcp_header_t *tcp0, tcp_header_t *tcp1)
Definition: ip4_packet.h:484
vl_api_address_t dst
Definition: gre.api:55
#define IP4_HEADER_FLAG_MORE_FRAGMENTS
Definition: ip4_packet.h:107
static void ip4_multicast_ethernet_address(u8 *ethernet_address, const ip4_address_t *a)
Definition: ip4_packet.h:454
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
static u16 ip4_get_fragment_offset(const ip4_header_t *i)
Definition: ip4_packet.h:155
ip4_address_t src
Definition: ip4_packet.h:79
#define WARN_OFF(x)
Definition: warnings.h:80
#define ASSERT(truth)
manual_print typedef address
Definition: ip_types.api:85
enum ip_dscp_t_ ip_dscp_t
ip_dscp_t tos
Definition: ip4_packet.h:96
static void ip4_multicast_address_set_for_group(ip4_address_t *a, ip_multicast_group_t g)
Definition: ip4_packet.h:446
static void ip4_addr_fib_init(ip4_address_fib_t *addr_fib, const ip4_address_t *address, u32 fib_index)
Definition: ip4_packet.h:68
static u8 ip4_header_get_df(const ip4_header_t *ip4)
Definition: ip4_packet.h:377
static int ip4_is_first_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:175
static_always_inline u16 ip4_header_checksum_inline(ip4_header_t *i, int with_checksum)
Definition: ip4_packet.h:209
u64 uword
Definition: types.h:112
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:294
static ip_ecn_t ip4_header_get_ecn(const ip4_header_t *ip4)
Definition: ip4_packet.h:357
ip4_address_t mask
Definition: ip4_packet.h:84
static uword ip4_address_is_global_broadcast(const ip4_address_t *a)
Definition: ip4_packet.h:440
ip_multicast_group_t
Definition: ip_packet.h:80
#define IP4_HEADER_FLAG_DONT_FRAGMENT
Definition: ip4_packet.h:108
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:190
u8 ip_version_and_header_length
Definition: ip4_packet.h:93
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:314
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
#define CLIB_PACKED(x)
Definition: clib.h:86