FD.io VPP  v21.06
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 
363 ip4_header_get_ttl (const ip4_header_t *ip4)
364 {
365  return (ip4->ttl);
366 }
367 
368 always_inline void
369 ip4_header_set_ttl (ip4_header_t *ip4, u8 ttl)
370 {
371  ip4->ttl = ttl;
372 }
373 
374 always_inline void
375 ip4_header_set_df (ip4_header_t * ip4)
376 {
378  clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
379 }
380 
381 always_inline void
382 ip4_header_clear_df (ip4_header_t * ip4)
383 {
385  ~clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
386 }
387 
389 ip4_header_get_df (const ip4_header_t * ip4)
390 {
391  return (! !(ip4->flags_and_fragment_offset &
392  clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT)));
393 }
394 
395 static inline uword
397 {
398  return ip4_header_checksum_inline (i, /* with_checksum */ 1) == 0;
399 }
400 
401 #define ip4_partial_header_checksum_x1(ip0,sum0) \
402 do { \
403  if (BITS (ip_csum_t) > 32) \
404  { \
405  sum0 = ip0->checksum_data_64[0]; \
406  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]); \
407  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]); \
408  } \
409  else \
410  { \
411  sum0 = ip0->checksum_data_32[0]; \
412  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]); \
413  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]); \
414  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]); \
415  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]); \
416  } \
417 } while (0)
418 
419 #define ip4_partial_header_checksum_x2(ip0,ip1,sum0,sum1) \
420 do { \
421  if (BITS (ip_csum_t) > 32) \
422  { \
423  sum0 = ip0->checksum_data_64[0]; \
424  sum1 = ip1->checksum_data_64[0]; \
425  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64[1]); \
426  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64[1]); \
427  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_64_32[0]); \
428  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_64_32[0]); \
429  } \
430  else \
431  { \
432  sum0 = ip0->checksum_data_32[0]; \
433  sum1 = ip1->checksum_data_32[0]; \
434  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[1]); \
435  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[1]); \
436  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[2]); \
437  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[2]); \
438  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[3]); \
439  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[3]); \
440  sum0 = ip_csum_with_carry (sum0, ip0->checksum_data_32[4]); \
441  sum1 = ip_csum_with_carry (sum1, ip1->checksum_data_32[4]); \
442  } \
443 } while (0)
444 
447 {
448  return (a->data[0] & 0xf0) == 0xe0;
449 }
450 
453 {
454  return (a->as_u32) == 0xffffffff;
455 }
456 
457 always_inline void
460 {
461  ASSERT ((u32) g < (1 << 28));
462  a->as_u32 = clib_host_to_net_u32 ((0xe << 28) + g);
463 }
464 
465 always_inline void
466 ip4_multicast_ethernet_address (u8 * ethernet_address,
467  const ip4_address_t * a)
468 {
469  const u8 *d = a->as_u8;
470 
471  ethernet_address[0] = 0x01;
472  ethernet_address[1] = 0x00;
473  ethernet_address[2] = 0x5e;
474  ethernet_address[3] = d[1] & 0x7f;
475  ethernet_address[4] = d[2];
476  ethernet_address[5] = d[3];
477 }
478 
479 always_inline void
480 ip4_tcp_reply_x1 (ip4_header_t * ip0, tcp_header_t * tcp0)
481 {
482  u32 src0, dst0;
483 
484  src0 = ip0->src_address.data_u32;
485  dst0 = ip0->dst_address.data_u32;
486  ip0->src_address.data_u32 = dst0;
487  ip0->dst_address.data_u32 = src0;
488 
489  src0 = tcp0->src;
490  dst0 = tcp0->dst;
491  tcp0->src = dst0;
492  tcp0->dst = src0;
493 }
494 
495 always_inline void
496 ip4_tcp_reply_x2 (ip4_header_t * ip0, ip4_header_t * ip1,
497  tcp_header_t * tcp0, tcp_header_t * tcp1)
498 {
499  u32 src0, dst0, src1, dst1;
500 
501  src0 = ip0->src_address.data_u32;
502  src1 = ip1->src_address.data_u32;
503  dst0 = ip0->dst_address.data_u32;
504  dst1 = ip1->dst_address.data_u32;
505  ip0->src_address.data_u32 = dst0;
506  ip1->src_address.data_u32 = dst1;
507  ip0->dst_address.data_u32 = src0;
508  ip1->dst_address.data_u32 = src1;
509 
510  src0 = tcp0->src;
511  src1 = tcp1->src;
512  dst0 = tcp0->dst;
513  dst1 = tcp1->dst;
514  tcp0->src = dst0;
515  tcp1->src = dst1;
516  tcp0->dst = src0;
517  tcp1->dst = src1;
518 }
519 
520 #endif /* included_ip4_packet_h */
521 
522 /*
523  * fd.io coding-style-patch-verification: ON
524  *
525  * Local Variables:
526  * eval: (c-set-style "gnu")
527  * End:
528  */
ip4_address_t ip4_addr
Definition: ip4_packet.h:63
static u8 ip4_header_get_ttl(const ip4_header_t *ip4)
Definition: ip4_packet.h:363
a
Definition: bitmap.h:544
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
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:245
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:130
static uword ip4_address_is_multicast(const ip4_address_t *a)
Definition: ip4_packet.h:446
struct _tcp_header tcp_header_t
vhost_vring_addr_t addr
Definition: vhost_user.h:130
static void ip4_header_clear_df(ip4_header_t *ip4)
Definition: ip4_packet.h:382
static void ip4_tcp_reply_x1(ip4_header_t *ip0, tcp_header_t *tcp0)
Definition: ip4_packet.h:480
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:92
static int ip4_is_fragment(const ip4_header_t *i)
Definition: ip4_packet.h:168
unsigned int u32
Definition: types.h:88
#define static_always_inline
Definition: clib.h:112
static uword ip4_header_checksum_is_valid(ip4_header_t *i)
Definition: ip4_packet.h:396
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:129
#define WARN_ON(x)
Definition: warnings.h:81
static void * ip4_next_header(ip4_header_t *i)
Definition: ip4_packet.h:196
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:375
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:124
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:496
#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:466
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
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
static void ip4_header_set_ttl(ip4_header_t *ip4, u8 ttl)
Definition: ip4_packet.h:369
u8 ttl
Definition: fib_types.api:26
#define WARN_OFF(x)
Definition: warnings.h:80
#define ASSERT(truth)
manual_print typedef address
Definition: ip_types.api:96
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:458
#define always_inline
Definition: rdma_mlx5dv.h:23
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_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
static u8 ip4_header_get_df(const ip4_header_t *ip4)
Definition: ip4_packet.h:389
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:295
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:452
vl_api_ip4_address_t dst
Definition: pnat.api:41
ip_multicast_group_t
Definition: ip_packet.h:81
#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:301
#define CLIB_PACKED(x)
Definition: clib.h:89