summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/vnet/ip/ip4_packet.h104
1 files changed, 72 insertions, 32 deletions
diff --git a/src/vnet/ip/ip4_packet.h b/src/vnet/ip/ip4_packet.h
index 9d63baecf88..fee0c8cbcd7 100644
--- a/src/vnet/ip/ip4_packet.h
+++ b/src/vnet/ip/ip4_packet.h
@@ -200,61 +200,101 @@ ip4_next_header (ip4_header_t * i)
always_inline u16
ip4_header_checksum (ip4_header_t * i)
{
- u16 *iphdr = (u16 *) i;
- u32 sum = 0;
int option_len = (i->ip_version_and_header_length & 0xf) - 5;
+ uword sum = 0;
+#if uword_bits == 64
+ u32 *iphdr = (u32 *) i;
+
+ sum += iphdr[0];
+ sum += iphdr[1];
+ sum += *(u16 *) (iphdr + 2);
+ /* skip checksum */
+ sum += iphdr[3];
+ sum += iphdr[4];
+
+ if (PREDICT_FALSE (option_len > 0))
+ switch (option_len)
+ {
+ case 10:
+ sum += iphdr[14];
+ case 9:
+ sum += iphdr[13];
+ case 8:
+ sum += iphdr[12];
+ case 7:
+ sum += iphdr[11];
+ case 6:
+ sum += iphdr[10];
+ case 5:
+ sum += iphdr[9];
+ case 4:
+ sum += iphdr[8];
+ case 3:
+ sum += iphdr[7];
+ case 2:
+ sum += iphdr[6];
+ case 1:
+ sum += iphdr[5];
+ default:
+ break;
+ }
- sum += clib_net_to_host_u16 (iphdr[0]);
- sum += clib_net_to_host_u16 (iphdr[1]);
- sum += clib_net_to_host_u16 (iphdr[2]);
- sum += clib_net_to_host_u16 (iphdr[3]);
- sum += clib_net_to_host_u16 (iphdr[4]);
+ sum = ((u32) sum) + (sum >> 32);
+#else
+ u16 *iphdr = (u16 *) i;
- sum += clib_net_to_host_u16 (iphdr[6]);
- sum += clib_net_to_host_u16 (iphdr[7]);
- sum += clib_net_to_host_u16 (iphdr[8]);
- sum += clib_net_to_host_u16 (iphdr[9]);
+ sum += iphdr[0];
+ sum += iphdr[1];
+ sum += iphdr[2];
+ sum += iphdr[3];
+ sum += iphdr[4];
+ /* skip checksum */
+ sum += iphdr[6];
+ sum += iphdr[7];
+ sum += iphdr[8];
+ sum += iphdr[9];
if (PREDICT_FALSE (option_len > 0))
switch (option_len)
{
case 10:
- sum += clib_net_to_host_u16 (iphdr[28]);
- sum += clib_net_to_host_u16 (iphdr[29]);
+ sum += iphdr[28];
+ sum += iphdr[29];
case 9:
- sum += clib_net_to_host_u16 (iphdr[26]);
- sum += clib_net_to_host_u16 (iphdr[27]);
+ sum += iphdr[26];
+ sum += iphdr[27];
case 8:
- sum += clib_net_to_host_u16 (iphdr[24]);
- sum += clib_net_to_host_u16 (iphdr[25]);
+ sum += iphdr[24];
+ sum += iphdr[25];
case 7:
- sum += clib_net_to_host_u16 (iphdr[22]);
- sum += clib_net_to_host_u16 (iphdr[23]);
+ sum += iphdr[22];
+ sum += iphdr[23];
case 6:
- sum += clib_net_to_host_u16 (iphdr[20]);
- sum += clib_net_to_host_u16 (iphdr[21]);
+ sum += iphdr[20];
+ sum += iphdr[21];
case 5:
- sum += clib_net_to_host_u16 (iphdr[18]);
- sum += clib_net_to_host_u16 (iphdr[19]);
+ sum += iphdr[18];
+ sum += iphdr[19];
case 4:
- sum += clib_net_to_host_u16 (iphdr[16]);
- sum += clib_net_to_host_u16 (iphdr[17]);
+ sum += iphdr[16];
+ sum += iphdr[17];
case 3:
- sum += clib_net_to_host_u16 (iphdr[14]);
- sum += clib_net_to_host_u16 (iphdr[15]);
+ sum += iphdr[14];
+ sum += iphdr[15];
case 2:
- sum += clib_net_to_host_u16 (iphdr[12]);
- sum += clib_net_to_host_u16 (iphdr[13]);
+ sum += iphdr[12];
+ sum += iphdr[13];
case 1:
- sum += clib_net_to_host_u16 (iphdr[10]);
- sum += clib_net_to_host_u16 (iphdr[11]);
+ sum += iphdr[10];
+ sum += iphdr[11];
default:
break;
}
+#endif
sum = ((u16) sum) + (sum >> 16);
sum = ((u16) sum) + (sum >> 16);
- return clib_host_to_net_u16 (~((u16) sum));
+ return ~((u16) sum);
}
always_inline void