- u16 save, csum;
- ip_csum_t sum;
-
- save = i->checksum;
- i->checksum = 0;
- sum = ip_incremental_checksum (0, i, ip4_header_bytes (i));
- csum = ~ip_csum_fold (sum);
-
- i->checksum = save;
-
- /* Make checksum agree for special case where either
- 0 or 0xffff would give same 1s complement sum. */
- if (csum == 0 && save == 0xffff)
- csum = save;
-
- return csum;
+ 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 = ((u32) sum) + (sum >> 32);
+#else
+ u16 *iphdr = (u16 *) i;
+
+ 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 += iphdr[28];
+ sum += iphdr[29];
+ case 9:
+ sum += iphdr[26];
+ sum += iphdr[27];
+ case 8:
+ sum += iphdr[24];
+ sum += iphdr[25];
+ case 7:
+ sum += iphdr[22];
+ sum += iphdr[23];
+ case 6:
+ sum += iphdr[20];
+ sum += iphdr[21];
+ case 5:
+ sum += iphdr[18];
+ sum += iphdr[19];
+ case 4:
+ sum += iphdr[16];
+ sum += iphdr[17];
+ case 3:
+ sum += iphdr[14];
+ sum += iphdr[15];
+ case 2:
+ sum += iphdr[12];
+ sum += iphdr[13];
+ case 1:
+ sum += iphdr[10];
+ sum += iphdr[11];
+ default:
+ break;
+ }
+#endif
+
+ sum = ((u16) sum) + (sum >> 16);
+ sum = ((u16) sum) + (sum >> 16);
+ return ~((u16) sum);