X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_net%2Frte_ip.h;h=73ec398fc3995ab747246ce937ec4e421b2be9bd;hb=e32cb57973fc311b4b5f60ae5dac37d99e48c94d;hp=46f049716abcf248c5be95d18d17f75e512ca777;hpb=2b039d5f20a34016ecaf9b26f8f8b6c4a81bf4b6;p=dpdk.git diff --git a/lib/librte_net/rte_ip.h b/lib/librte_net/rte_ip.h index 46f049716a..73ec398fc3 100644 --- a/lib/librte_net/rte_ip.h +++ b/lib/librte_net/rte_ip.h @@ -80,7 +80,6 @@ #include #include -#include #include #include @@ -110,6 +109,17 @@ struct ipv4_hdr { (((c) & 0xff) << 8) | \ ((d) & 0xff)) +/** Maximal IPv4 packet length (including a header) */ +#define IPV4_MAX_PKT_LEN 65535 + +/** Internet header length mask for version_ihl field */ +#define IPV4_HDR_IHL_MASK (0x0f) +/** + * Internet header length field multiplier (IHL field specifies overall header + * length in number of 4-byte words) + */ +#define IPV4_IHL_MULTIPLIER (4) + /* Fragment Offset * Flags. */ #define IPV4_HDR_DF_SHIFT 14 #define IPV4_HDR_MF_SHIFT 13 @@ -142,22 +152,25 @@ struct ipv4_hdr { ((x) >= IPV4_MIN_MCAST && (x) <= IPV4_MAX_MCAST) /**< check if IPv4 address is multicast */ /** - * Process the non-complemented checksum of a buffer. + * @internal Calculate a sum of all words in the buffer. + * Helper routine for the rte_raw_cksum(). * * @param buf * Pointer to the buffer. * @param len * Length of the buffer. + * @param sum + * Initial value of the sum. * @return - * The non-complemented checksum. + * sum += Sum of all words in the buffer. */ -static inline uint16_t -rte_raw_cksum(const char *buf, size_t len) +static inline uint32_t +__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) { /* workaround gcc strict-aliasing warning */ uintptr_t ptr = (uintptr_t)buf; - const uint16_t *u16 = (const uint16_t *)ptr; - uint32_t sum = 0; + typedef uint16_t __attribute__((__may_alias__)) u16_p; + const u16_p *u16 = (const u16_p *)ptr; while (len >= (sizeof(*u16) * 4)) { sum += u16[0]; @@ -177,11 +190,116 @@ rte_raw_cksum(const char *buf, size_t len) if (len == 1) sum += *((const uint8_t *)u16); + return sum; +} + +/** + * @internal Reduce a sum to the non-complemented checksum. + * Helper routine for the rte_raw_cksum(). + * + * @param sum + * Value of the sum. + * @return + * The non-complemented checksum. + */ +static inline uint16_t +__rte_raw_cksum_reduce(uint32_t sum) +{ sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff); sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff); return (uint16_t)sum; } +/** + * Process the non-complemented checksum of a buffer. + * + * @param buf + * Pointer to the buffer. + * @param len + * Length of the buffer. + * @return + * The non-complemented checksum. + */ +static inline uint16_t +rte_raw_cksum(const void *buf, size_t len) +{ + uint32_t sum; + + sum = __rte_raw_cksum(buf, len, 0); + return __rte_raw_cksum_reduce(sum); +} + +/** + * Compute the raw (non complemented) checksum of a packet. + * + * @param m + * The pointer to the mbuf. + * @param off + * The offset in bytes to start the checksum. + * @param len + * The length in bytes of the data to checksum. + * @param cksum + * A pointer to the checksum, filled on success. + * @return + * 0 on success, -1 on error (bad length or offset). + */ +static inline int +rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len, + uint16_t *cksum) +{ + const struct rte_mbuf *seg; + const char *buf; + uint32_t sum, tmp; + uint32_t seglen, done; + + /* easy case: all data in the first segment */ + if (off + len <= rte_pktmbuf_data_len(m)) { + *cksum = rte_raw_cksum(rte_pktmbuf_mtod_offset(m, + const char *, off), len); + return 0; + } + + if (unlikely(off + len > rte_pktmbuf_pkt_len(m))) + return -1; /* invalid params, return a dummy value */ + + /* else browse the segment to find offset */ + seglen = 0; + for (seg = m; seg != NULL; seg = seg->next) { + seglen = rte_pktmbuf_data_len(seg); + if (off < seglen) + break; + off -= seglen; + } + seglen -= off; + buf = rte_pktmbuf_mtod_offset(seg, const char *, off); + if (seglen >= len) { + /* all in one segment */ + *cksum = rte_raw_cksum(buf, len); + return 0; + } + + /* hard case: process checksum of several segments */ + sum = 0; + done = 0; + for (;;) { + tmp = __rte_raw_cksum(buf, seglen, 0); + if (done & 1) + tmp = rte_bswap16(tmp); + sum += tmp; + done += seglen; + if (done == len) + break; + seg = seg->next; + buf = rte_pktmbuf_mtod(seg, const char *); + seglen = rte_pktmbuf_data_len(seg); + if (seglen > len - done) + seglen = len - done; + } + + *cksum = __rte_raw_cksum_reduce(sum); + return 0; +} + /** * Process the IPv4 checksum of an IPv4 header. * @@ -196,8 +314,8 @@ static inline uint16_t rte_ipv4_cksum(const struct ipv4_hdr *ipv4_hdr) { uint16_t cksum; - cksum = rte_raw_cksum((const char *)ipv4_hdr, sizeof(struct ipv4_hdr)); - return ((cksum == 0xffff) ? cksum : ~cksum); + cksum = rte_raw_cksum(ipv4_hdr, sizeof(struct ipv4_hdr)); + return (cksum == 0xffff) ? cksum : ~cksum; } /** @@ -240,7 +358,7 @@ rte_ipv4_phdr_cksum(const struct ipv4_hdr *ipv4_hdr, uint64_t ol_flags) (uint16_t)(rte_be_to_cpu_16(ipv4_hdr->total_length) - sizeof(struct ipv4_hdr))); } - return rte_raw_cksum((const char *)&psd_hdr, sizeof(psd_hdr)); + return rte_raw_cksum(&psd_hdr, sizeof(psd_hdr)); } /** @@ -307,15 +425,12 @@ struct ipv6_hdr { static inline uint16_t rte_ipv6_phdr_cksum(const struct ipv6_hdr *ipv6_hdr, uint64_t ol_flags) { - struct ipv6_psd_header { - uint8_t src_addr[16]; /* IP address of source host. */ - uint8_t dst_addr[16]; /* IP address of destination host. */ - uint32_t len; /* L4 length. */ - uint32_t proto; /* L4 protocol - top 3 bytes must be zero */ + uint32_t sum; + struct { + uint32_t len; /* L4 length. */ + uint32_t proto; /* L4 protocol - top 3 bytes must be zero */ } psd_hdr; - rte_memcpy(&psd_hdr.src_addr, ipv6_hdr->src_addr, - sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr)); psd_hdr.proto = (ipv6_hdr->proto << 24); if (ol_flags & PKT_TX_TCP_SEG) { psd_hdr.len = 0; @@ -323,7 +438,11 @@ rte_ipv6_phdr_cksum(const struct ipv6_hdr *ipv6_hdr, uint64_t ol_flags) psd_hdr.len = ipv6_hdr->payload_len; } - return rte_raw_cksum((const char *)&psd_hdr, sizeof(psd_hdr)); + sum = __rte_raw_cksum(ipv6_hdr->src_addr, + sizeof(ipv6_hdr->src_addr) + sizeof(ipv6_hdr->dst_addr), + 0); + sum = __rte_raw_cksum(&psd_hdr, sizeof(psd_hdr), sum); + return __rte_raw_cksum_reduce(sum); } /**