2 // Copyright (c) 2010-2017 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 #include "prox_cksum.h"
18 #include "prox_port_cfg.h"
19 #include <rte_byteorder.h>
22 /* compute IP 16 bit checksum */
23 inline void prox_ip_cksum_sw(struct ipv4_hdr *buf)
25 const uint16_t size = sizeof(struct ipv4_hdr);
29 uint32_t *pdwd = (uint32_t *)buf;
31 /* compute 16 bit checksum using hi and low parts of 32 bit integers */
32 for (nb_dwords = (size >> 2); nb_dwords > 0; --nb_dwords) {
33 cksum += (*pdwd >> 16);
34 cksum += (*pdwd & 0xFFFF);
38 /* deal with the odd byte length */
41 /* calculate mask for valid parts */
42 mask = 0xFFFFFFFF << ((size & 0x03) << 3);
43 /* clear unused bits */
46 cksum += (tail >> 16) + (tail & 0xFFFF);
49 cksum = (cksum >> 16) + (cksum & 0xFFFF);
50 cksum = (cksum >> 16) + (cksum & 0xFFFF);
52 buf->hdr_checksum = ~((uint16_t)cksum);
55 static inline uint16_t calc_pseudo_checksum(uint8_t ipproto, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
59 csum += (src_ip_addr >> 16) + (src_ip_addr & 0xFFFF);
60 csum += (dst_ip_addr >> 16) + (dst_ip_addr & 0xFFFF);
61 csum += rte_bswap16(ipproto) + rte_bswap16(len);
62 csum = (csum >> 16) + (csum & 0xFFFF);
66 static inline void prox_write_udp_pseudo_hdr(struct udp_hdr *udp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
68 /* Note that the csum is not complemented, while the pseaudo
69 header checksum is calculated as "... the 16-bit one's
70 complement of the one's complement sum of a pseudo header
71 of information ...", the psuedoheader forms as a basis for
72 the actual checksum calculated later either in software or
74 udp->dgram_cksum = calc_pseudo_checksum(IPPROTO_UDP, len, src_ip_addr, dst_ip_addr);
77 static inline void prox_write_tcp_pseudo_hdr(struct tcp_hdr *tcp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
79 tcp->cksum = calc_pseudo_checksum(IPPROTO_TCP, len, src_ip_addr, dst_ip_addr);
82 inline void prox_ip_udp_cksum(struct rte_mbuf *mbuf, struct ipv4_hdr *pip, uint16_t l2_len, uint16_t l3_len, int cksum_offload)
84 prox_ip_cksum(mbuf, pip, l2_len, l3_len, cksum_offload & DEV_TX_OFFLOAD_IPV4_CKSUM);
86 uint32_t l4_len = rte_bswap16(pip->total_length) - l3_len;
87 if (pip->next_proto_id == IPPROTO_UDP) {
88 struct udp_hdr *udp = (struct udp_hdr *)(((uint8_t*)pip) + l3_len);
90 if (cksum_offload & DEV_TX_OFFLOAD_UDP_CKSUM) {
91 mbuf->ol_flags |= PKT_TX_UDP_CKSUM;
92 prox_write_udp_pseudo_hdr(udp, l4_len, pip->src_addr, pip->dst_addr);
95 prox_udp_cksum_sw(udp, l4_len, pip->src_addr, pip->dst_addr);
96 } else if (pip->next_proto_id == IPPROTO_TCP) {
97 struct tcp_hdr *tcp = (struct tcp_hdr *)(((uint8_t*)pip) + l3_len);
99 if (cksum_offload & DEV_TX_OFFLOAD_TCP_CKSUM) {
100 prox_write_tcp_pseudo_hdr(tcp, l4_len, pip->src_addr, pip->dst_addr);
101 mbuf->ol_flags |= PKT_TX_UDP_CKSUM;
104 prox_tcp_cksum_sw(tcp, l4_len, pip->src_addr, pip->dst_addr);
108 static inline uint16_t checksum_byte_seq(uint16_t *buf, uint16_t len)
123 csum += *(uint8_t*)buf;
132 inline void prox_udp_cksum_sw(struct udp_hdr *udp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
134 prox_write_udp_pseudo_hdr(udp, len, src_ip_addr, dst_ip_addr);
135 uint16_t csum = checksum_byte_seq((uint16_t *)udp, len);
136 udp->dgram_cksum = csum;
139 inline void prox_tcp_cksum_sw(struct tcp_hdr *tcp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
141 prox_write_tcp_pseudo_hdr(tcp, len, src_ip_addr, dst_ip_addr);
143 uint16_t csum = checksum_byte_seq((uint16_t *)tcp, len);