Support for DPDK 18.05 and DPDK 18.08
[samplevnf.git] / VNFs / DPPD-PROX / prox_cksum.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
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
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 */
16
17 #include "prox_cksum.h"
18 #include "prox_port_cfg.h"
19 #include <rte_byteorder.h>
20 #include "log.h"
21
22 /* compute IP 16 bit checksum */
23 void prox_ip_cksum_sw(struct ipv4_hdr *buf)
24 {
25         const uint16_t size = sizeof(struct ipv4_hdr);
26         uint32_t cksum = 0;
27         uint32_t nb_dwords;
28         uint32_t tail, mask;
29         uint32_t *pdwd = (uint32_t *)buf;
30
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);
35                 ++pdwd;
36         }
37
38         /* deal with the odd byte length */
39         if (size & 0x03) {
40                 tail = *pdwd;
41                 /* calculate mask for valid parts */
42                 mask = 0xFFFFFFFF << ((size & 0x03) << 3);
43                 /* clear unused bits */
44                 tail &= ~mask;
45
46                 cksum += (tail >> 16) + (tail & 0xFFFF);
47         }
48
49         cksum = (cksum >> 16) + (cksum & 0xFFFF);
50         cksum = (cksum >> 16) + (cksum & 0xFFFF);
51
52         buf->hdr_checksum = ~((uint16_t)cksum);
53 }
54
55 static uint16_t calc_pseudo_checksum(uint8_t ipproto, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
56 {
57         uint32_t csum = 0;
58
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);
63         return csum;
64 }
65
66 static void prox_write_udp_pseudo_hdr(struct udp_hdr *udp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
67 {
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
73            hardware. */
74         udp->dgram_cksum = calc_pseudo_checksum(IPPROTO_UDP, len, src_ip_addr, dst_ip_addr);
75 }
76
77 static void prox_write_tcp_pseudo_hdr(struct tcp_hdr *tcp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
78 {
79         tcp->cksum = calc_pseudo_checksum(IPPROTO_TCP, len, src_ip_addr, dst_ip_addr);
80 }
81
82 void prox_ip_udp_cksum(struct rte_mbuf *mbuf, struct ipv4_hdr *pip, uint16_t l2_len, uint16_t l3_len, int cksum_offload)
83 {
84         prox_ip_cksum(mbuf, pip, l2_len, l3_len, cksum_offload & DEV_TX_OFFLOAD_IPV4_CKSUM);
85
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);
89 #ifndef SOFT_CRC
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);
93                 } else
94 #endif
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);
98 #ifndef SOFT_CRC
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;
102                 } else
103 #endif
104                 prox_tcp_cksum_sw(tcp, l4_len, pip->src_addr, pip->dst_addr);
105         }
106 }
107
108 static uint16_t checksum_byte_seq(uint16_t *buf, uint16_t len)
109 {
110         uint32_t csum = 0;
111
112         while (len > 1) {
113                 csum += *buf;
114                 while (csum >> 16) {
115                         csum &= 0xffff;
116                         csum +=1;
117                 }
118                 buf++;
119                 len -= 2;
120         }
121
122         if (len) {
123                 csum += *(uint8_t*)buf;
124                 while (csum >> 16) {
125                         csum &= 0xffff;
126                         csum +=1;
127                 }
128         }
129         return ~csum;
130 }
131
132 void prox_udp_cksum_sw(struct udp_hdr *udp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
133 {
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;
137 }
138
139 void prox_tcp_cksum_sw(struct tcp_hdr *tcp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr)
140 {
141         prox_write_tcp_pseudo_hdr(tcp, len, src_ip_addr, dst_ip_addr);
142
143         uint16_t csum = checksum_byte_seq((uint16_t *)tcp, len);
144         tcp->cksum = csum;
145 }