1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 1982, 1986, 1990, 1993 3 * The Regents of the University of California. 4 * Copyright(c) 2010-2014 Intel Corporation. 5 * Copyright(c) 2014 6WIND S.A. 6 * All rights reserved. 7 */ 8 9 #ifndef _RTE_CKSUM_H_ 10 #define _RTE_CKSUM_H_ 11 12 /** 13 * @file 14 * 15 * Protocol independent checksum utilities. 16 */ 17 18 #include <stdint.h> 19 20 #include <rte_byteorder.h> 21 #include <rte_common.h> 22 #include <rte_mbuf.h> 23 24 #ifdef __cplusplus 25 extern "C" { 26 #endif 27 28 29 /** 30 * @internal Calculate a sum of all words in the buffer. 31 * Helper routine for the rte_raw_cksum(). 32 * 33 * @param buf 34 * Pointer to the buffer. 35 * @param len 36 * Length of the buffer. 37 * @param sum 38 * Initial value of the sum. 39 * @return 40 * sum += Sum of all words in the buffer. 41 */ 42 static inline uint32_t 43 __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) 44 { 45 const void *end; 46 47 for (end = RTE_PTR_ADD(buf, RTE_ALIGN_FLOOR(len, sizeof(uint16_t))); 48 buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) { 49 uint16_t v; 50 51 memcpy(&v, buf, sizeof(uint16_t)); 52 sum += v; 53 } 54 55 /* if length is odd, keeping it byte order independent */ 56 if (unlikely(len % 2)) { 57 uint16_t left = 0; 58 59 memcpy(&left, end, 1); 60 sum += left; 61 } 62 63 return sum; 64 } 65 66 /** 67 * @internal Reduce a sum to the non-complemented checksum. 68 * Helper routine for the rte_raw_cksum(). 69 * 70 * @param sum 71 * Value of the sum. 72 * @return 73 * The non-complemented checksum. 74 */ 75 static inline uint16_t 76 __rte_raw_cksum_reduce(uint32_t sum) 77 { 78 sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff); 79 sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff); 80 return (uint16_t)sum; 81 } 82 83 /** 84 * Process the non-complemented checksum of a buffer. 85 * 86 * @param buf 87 * Pointer to the buffer. 88 * @param len 89 * Length of the buffer. 90 * @return 91 * The non-complemented checksum. 92 */ 93 static inline uint16_t 94 rte_raw_cksum(const void *buf, size_t len) 95 { 96 uint32_t sum; 97 98 sum = __rte_raw_cksum(buf, len, 0); 99 return __rte_raw_cksum_reduce(sum); 100 } 101 102 /** 103 * Compute the raw (non complemented) checksum of a packet. 104 * 105 * @param m 106 * The pointer to the mbuf. 107 * @param off 108 * The offset in bytes to start the checksum. 109 * @param len 110 * The length in bytes of the data to checksum. 111 * @param cksum 112 * A pointer to the checksum, filled on success. 113 * @return 114 * 0 on success, -1 on error (bad length or offset). 115 */ 116 static inline int 117 rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len, 118 uint16_t *cksum) 119 { 120 const struct rte_mbuf *seg; 121 const char *buf; 122 uint32_t sum, tmp; 123 uint32_t seglen, done; 124 125 /* easy case: all data in the first segment */ 126 if (off + len <= rte_pktmbuf_data_len(m)) { 127 *cksum = rte_raw_cksum(rte_pktmbuf_mtod_offset(m, 128 const char *, off), len); 129 return 0; 130 } 131 132 if (unlikely(off + len > rte_pktmbuf_pkt_len(m))) 133 return -1; /* invalid params, return a dummy value */ 134 135 /* else browse the segment to find offset */ 136 seglen = 0; 137 for (seg = m; seg != NULL; seg = seg->next) { 138 seglen = rte_pktmbuf_data_len(seg); 139 if (off < seglen) 140 break; 141 off -= seglen; 142 } 143 RTE_ASSERT(seg != NULL); 144 if (seg == NULL) 145 return -1; 146 seglen -= off; 147 buf = rte_pktmbuf_mtod_offset(seg, const char *, off); 148 if (seglen >= len) { 149 /* all in one segment */ 150 *cksum = rte_raw_cksum(buf, len); 151 return 0; 152 } 153 154 /* hard case: process checksum of several segments */ 155 sum = 0; 156 done = 0; 157 for (;;) { 158 tmp = __rte_raw_cksum(buf, seglen, 0); 159 if (done & 1) 160 tmp = rte_bswap16((uint16_t)tmp); 161 sum += tmp; 162 done += seglen; 163 if (done == len) 164 break; 165 seg = seg->next; 166 buf = rte_pktmbuf_mtod(seg, const char *); 167 seglen = rte_pktmbuf_data_len(seg); 168 if (seglen > len - done) 169 seglen = len - done; 170 } 171 172 *cksum = __rte_raw_cksum_reduce(sum); 173 return 0; 174 } 175 176 #ifdef __cplusplus 177 } 178 #endif 179 180 #endif /* _RTE_CKSUM_H_ */ 181