130a65c6cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
230a65c6cSOlivier Matz * Copyright 2021 6WIND S.A.
330a65c6cSOlivier Matz */
430a65c6cSOlivier Matz
530a65c6cSOlivier Matz #include <string.h>
630a65c6cSOlivier Matz #include <stdio.h>
730a65c6cSOlivier Matz #include <stdlib.h>
830a65c6cSOlivier Matz #include <stdint.h>
930a65c6cSOlivier Matz
1030a65c6cSOlivier Matz #include <rte_net.h>
1130a65c6cSOlivier Matz #include <rte_mbuf.h>
1230a65c6cSOlivier Matz #include <rte_ip.h>
1330a65c6cSOlivier Matz
1430a65c6cSOlivier Matz #include "test.h"
1530a65c6cSOlivier Matz
1630a65c6cSOlivier Matz #define MEMPOOL_CACHE_SIZE 0
1730a65c6cSOlivier Matz #define MBUF_DATA_SIZE 256
1830a65c6cSOlivier Matz #define NB_MBUF 128
1930a65c6cSOlivier Matz
2030a65c6cSOlivier Matz /*
2130a65c6cSOlivier Matz * Test L3/L4 checksum API.
2230a65c6cSOlivier Matz */
2330a65c6cSOlivier Matz
2430a65c6cSOlivier Matz #define GOTO_FAIL(str, ...) do { \
2530a65c6cSOlivier Matz printf("cksum test FAILED (l.%d): <" str ">\n", \
2630a65c6cSOlivier Matz __LINE__, ##__VA_ARGS__); \
2730a65c6cSOlivier Matz goto fail; \
2830a65c6cSOlivier Matz } while (0)
2930a65c6cSOlivier Matz
3030a65c6cSOlivier Matz /* generated in scapy with Ether()/IP()/TCP())) */
3130a65c6cSOlivier Matz static const char test_cksum_ipv4_tcp[] = {
3230a65c6cSOlivier Matz 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
3330a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
3430a65c6cSOlivier Matz 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
3530a65c6cSOlivier Matz 0x7c, 0xcd, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00,
3630a65c6cSOlivier Matz 0x00, 0x01, 0x00, 0x14, 0x00, 0x50, 0x00, 0x00,
3730a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,
3830a65c6cSOlivier Matz 0x20, 0x00, 0x91, 0x7c, 0x00, 0x00,
3930a65c6cSOlivier Matz
4030a65c6cSOlivier Matz };
4130a65c6cSOlivier Matz
4230a65c6cSOlivier Matz /* generated in scapy with Ether()/IPv6()/TCP()) */
4330a65c6cSOlivier Matz static const char test_cksum_ipv6_tcp[] = {
4430a65c6cSOlivier Matz 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
4530a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x60, 0x00,
4630a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x14, 0x06, 0x40, 0x00, 0x00,
4730a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4830a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
4930a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5030a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14,
5130a65c6cSOlivier Matz 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5230a65c6cSOlivier Matz 0x00, 0x00, 0x50, 0x02, 0x20, 0x00, 0x8f, 0x7d,
5330a65c6cSOlivier Matz 0x00, 0x00,
5430a65c6cSOlivier Matz };
5530a65c6cSOlivier Matz
5630a65c6cSOlivier Matz /* generated in scapy with Ether()/IP()/UDP()/Raw('x')) */
5730a65c6cSOlivier Matz static const char test_cksum_ipv4_udp[] = {
5830a65c6cSOlivier Matz 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
5930a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
6030a65c6cSOlivier Matz 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
6130a65c6cSOlivier Matz 0x7c, 0xcd, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00,
6230a65c6cSOlivier Matz 0x00, 0x01, 0x00, 0x35, 0x00, 0x35, 0x00, 0x09,
6330a65c6cSOlivier Matz 0x89, 0x6f, 0x78,
6430a65c6cSOlivier Matz };
6530a65c6cSOlivier Matz
6630a65c6cSOlivier Matz /* generated in scapy with Ether()/IPv6()/UDP()/Raw('x')) */
6730a65c6cSOlivier Matz static const char test_cksum_ipv6_udp[] = {
6830a65c6cSOlivier Matz 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
6930a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x86, 0xdd, 0x60, 0x00,
7030a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x09, 0x11, 0x40, 0x00, 0x00,
7130a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7230a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
7330a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7430a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x35,
7530a65c6cSOlivier Matz 0x00, 0x35, 0x00, 0x09, 0x87, 0x70, 0x78,
7630a65c6cSOlivier Matz };
7730a65c6cSOlivier Matz
7830a65c6cSOlivier Matz /* generated in scapy with Ether()/IP(options='\x00')/UDP()/Raw('x')) */
7930a65c6cSOlivier Matz static const char test_cksum_ipv4_opts_udp[] = {
8030a65c6cSOlivier Matz 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
8130a65c6cSOlivier Matz 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x46, 0x00,
8230a65c6cSOlivier Matz 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
8330a65c6cSOlivier Matz 0x7b, 0xc9, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00,
8430a65c6cSOlivier Matz 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35,
8530a65c6cSOlivier Matz 0x00, 0x35, 0x00, 0x09, 0x89, 0x6f, 0x78,
8630a65c6cSOlivier Matz };
8730a65c6cSOlivier Matz
8830a65c6cSOlivier Matz /* test l3/l4 checksum api */
8930a65c6cSOlivier Matz static int
test_l4_cksum(struct rte_mempool * pktmbuf_pool,const char * pktdata,size_t len)9030a65c6cSOlivier Matz test_l4_cksum(struct rte_mempool *pktmbuf_pool, const char *pktdata, size_t len)
9130a65c6cSOlivier Matz {
9230a65c6cSOlivier Matz struct rte_net_hdr_lens hdr_lens;
9330a65c6cSOlivier Matz struct rte_mbuf *m = NULL;
9430a65c6cSOlivier Matz uint32_t packet_type;
9530a65c6cSOlivier Matz uint16_t prev_cksum;
9630a65c6cSOlivier Matz void *l3_hdr;
9730a65c6cSOlivier Matz void *l4_hdr;
9830a65c6cSOlivier Matz uint32_t l3;
9930a65c6cSOlivier Matz uint32_t l4;
10030a65c6cSOlivier Matz char *data;
10130a65c6cSOlivier Matz
10230a65c6cSOlivier Matz m = rte_pktmbuf_alloc(pktmbuf_pool);
10330a65c6cSOlivier Matz if (m == NULL)
10430a65c6cSOlivier Matz GOTO_FAIL("Cannot allocate mbuf");
10530a65c6cSOlivier Matz
10630a65c6cSOlivier Matz data = rte_pktmbuf_append(m, len);
10730a65c6cSOlivier Matz if (data == NULL)
10830a65c6cSOlivier Matz GOTO_FAIL("Cannot append data");
10930a65c6cSOlivier Matz
11030a65c6cSOlivier Matz memcpy(data, pktdata, len);
11130a65c6cSOlivier Matz
11230a65c6cSOlivier Matz packet_type = rte_net_get_ptype(m, &hdr_lens, RTE_PTYPE_ALL_MASK);
11330a65c6cSOlivier Matz l3 = packet_type & RTE_PTYPE_L3_MASK;
11430a65c6cSOlivier Matz l4 = packet_type & RTE_PTYPE_L4_MASK;
11530a65c6cSOlivier Matz
11630a65c6cSOlivier Matz l3_hdr = rte_pktmbuf_mtod_offset(m, void *, hdr_lens.l2_len);
11730a65c6cSOlivier Matz l4_hdr = rte_pktmbuf_mtod_offset(m, void *,
11830a65c6cSOlivier Matz hdr_lens.l2_len + hdr_lens.l3_len);
11930a65c6cSOlivier Matz
12030a65c6cSOlivier Matz if (l3 == RTE_PTYPE_L3_IPV4 || l3 == RTE_PTYPE_L3_IPV4_EXT) {
12130a65c6cSOlivier Matz struct rte_ipv4_hdr *ip = l3_hdr;
12230a65c6cSOlivier Matz
12330a65c6cSOlivier Matz /* verify IPv4 checksum */
12430a65c6cSOlivier Matz if (rte_ipv4_cksum(l3_hdr) != 0)
12530a65c6cSOlivier Matz GOTO_FAIL("invalid IPv4 checksum verification");
12630a65c6cSOlivier Matz
12730a65c6cSOlivier Matz /* verify bad IPv4 checksum */
12830a65c6cSOlivier Matz ip->hdr_checksum++;
12930a65c6cSOlivier Matz if (rte_ipv4_cksum(l3_hdr) == 0)
13030a65c6cSOlivier Matz GOTO_FAIL("invalid IPv4 bad checksum verification");
13130a65c6cSOlivier Matz ip->hdr_checksum--;
13230a65c6cSOlivier Matz
13330a65c6cSOlivier Matz /* recalculate IPv4 checksum */
13430a65c6cSOlivier Matz prev_cksum = ip->hdr_checksum;
13530a65c6cSOlivier Matz ip->hdr_checksum = 0;
13630a65c6cSOlivier Matz ip->hdr_checksum = rte_ipv4_cksum(ip);
13730a65c6cSOlivier Matz if (ip->hdr_checksum != prev_cksum)
13830a65c6cSOlivier Matz GOTO_FAIL("invalid IPv4 checksum calculation");
13930a65c6cSOlivier Matz
14030a65c6cSOlivier Matz /* verify L4 checksum */
14130a65c6cSOlivier Matz if (rte_ipv4_udptcp_cksum_verify(l3_hdr, l4_hdr) != 0)
14230a65c6cSOlivier Matz GOTO_FAIL("invalid L4 checksum verification");
14330a65c6cSOlivier Matz
14430a65c6cSOlivier Matz if (l4 == RTE_PTYPE_L4_TCP) {
14530a65c6cSOlivier Matz struct rte_tcp_hdr *tcp = l4_hdr;
14630a65c6cSOlivier Matz
14730a65c6cSOlivier Matz /* verify bad TCP checksum */
14830a65c6cSOlivier Matz tcp->cksum++;
14930a65c6cSOlivier Matz if (rte_ipv4_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
15030a65c6cSOlivier Matz GOTO_FAIL("invalid bad TCP checksum verification");
15130a65c6cSOlivier Matz tcp->cksum--;
15230a65c6cSOlivier Matz
15330a65c6cSOlivier Matz /* recalculate TCP checksum */
15430a65c6cSOlivier Matz prev_cksum = tcp->cksum;
15530a65c6cSOlivier Matz tcp->cksum = 0;
15630a65c6cSOlivier Matz tcp->cksum = rte_ipv4_udptcp_cksum(l3_hdr, l4_hdr);
15730a65c6cSOlivier Matz if (tcp->cksum != prev_cksum)
15830a65c6cSOlivier Matz GOTO_FAIL("invalid TCP checksum calculation");
15930a65c6cSOlivier Matz
16030a65c6cSOlivier Matz } else if (l4 == RTE_PTYPE_L4_UDP) {
16130a65c6cSOlivier Matz struct rte_udp_hdr *udp = l4_hdr;
16230a65c6cSOlivier Matz
16330a65c6cSOlivier Matz /* verify bad UDP checksum */
16430a65c6cSOlivier Matz udp->dgram_cksum++;
16530a65c6cSOlivier Matz if (rte_ipv4_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
16630a65c6cSOlivier Matz GOTO_FAIL("invalid bad UDP checksum verification");
16730a65c6cSOlivier Matz udp->dgram_cksum--;
16830a65c6cSOlivier Matz
16930a65c6cSOlivier Matz /* recalculate UDP checksum */
17030a65c6cSOlivier Matz prev_cksum = udp->dgram_cksum;
17130a65c6cSOlivier Matz udp->dgram_cksum = 0;
17230a65c6cSOlivier Matz udp->dgram_cksum = rte_ipv4_udptcp_cksum(l3_hdr,
17330a65c6cSOlivier Matz l4_hdr);
17430a65c6cSOlivier Matz if (udp->dgram_cksum != prev_cksum)
17530a65c6cSOlivier Matz GOTO_FAIL("invalid TCP checksum calculation");
17630a65c6cSOlivier Matz }
17730a65c6cSOlivier Matz } else if (l3 == RTE_PTYPE_L3_IPV6 || l3 == RTE_PTYPE_L3_IPV6_EXT) {
17830a65c6cSOlivier Matz if (rte_ipv6_udptcp_cksum_verify(l3_hdr, l4_hdr) != 0)
17930a65c6cSOlivier Matz GOTO_FAIL("invalid L4 checksum verification");
18030a65c6cSOlivier Matz
18130a65c6cSOlivier Matz if (l4 == RTE_PTYPE_L4_TCP) {
18230a65c6cSOlivier Matz struct rte_tcp_hdr *tcp = l4_hdr;
18330a65c6cSOlivier Matz
18430a65c6cSOlivier Matz /* verify bad TCP checksum */
18530a65c6cSOlivier Matz tcp->cksum++;
18630a65c6cSOlivier Matz if (rte_ipv6_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
18730a65c6cSOlivier Matz GOTO_FAIL("invalid bad TCP checksum verification");
18830a65c6cSOlivier Matz tcp->cksum--;
18930a65c6cSOlivier Matz
19030a65c6cSOlivier Matz /* recalculate TCP checksum */
19130a65c6cSOlivier Matz prev_cksum = tcp->cksum;
19230a65c6cSOlivier Matz tcp->cksum = 0;
19330a65c6cSOlivier Matz tcp->cksum = rte_ipv6_udptcp_cksum(l3_hdr, l4_hdr);
19430a65c6cSOlivier Matz if (tcp->cksum != prev_cksum)
19530a65c6cSOlivier Matz GOTO_FAIL("invalid TCP checksum calculation");
19630a65c6cSOlivier Matz
19730a65c6cSOlivier Matz } else if (l4 == RTE_PTYPE_L4_UDP) {
19830a65c6cSOlivier Matz struct rte_udp_hdr *udp = l4_hdr;
19930a65c6cSOlivier Matz
20030a65c6cSOlivier Matz /* verify bad UDP checksum */
20130a65c6cSOlivier Matz udp->dgram_cksum++;
20230a65c6cSOlivier Matz if (rte_ipv6_udptcp_cksum_verify(l3_hdr, l4_hdr) == 0)
20330a65c6cSOlivier Matz GOTO_FAIL("invalid bad UDP checksum verification");
20430a65c6cSOlivier Matz udp->dgram_cksum--;
20530a65c6cSOlivier Matz
20630a65c6cSOlivier Matz /* recalculate UDP checksum */
20730a65c6cSOlivier Matz prev_cksum = udp->dgram_cksum;
20830a65c6cSOlivier Matz udp->dgram_cksum = 0;
20930a65c6cSOlivier Matz udp->dgram_cksum = rte_ipv6_udptcp_cksum(l3_hdr,
21030a65c6cSOlivier Matz l4_hdr);
21130a65c6cSOlivier Matz if (udp->dgram_cksum != prev_cksum)
21230a65c6cSOlivier Matz GOTO_FAIL("invalid TCP checksum calculation");
21330a65c6cSOlivier Matz }
21430a65c6cSOlivier Matz }
21530a65c6cSOlivier Matz
21630a65c6cSOlivier Matz rte_pktmbuf_free(m);
21730a65c6cSOlivier Matz
21830a65c6cSOlivier Matz return 0;
21930a65c6cSOlivier Matz
22030a65c6cSOlivier Matz fail:
22130a65c6cSOlivier Matz rte_pktmbuf_free(m);
22230a65c6cSOlivier Matz
22330a65c6cSOlivier Matz return -1;
22430a65c6cSOlivier Matz }
22530a65c6cSOlivier Matz
22630a65c6cSOlivier Matz static int
test_cksum(void)22730a65c6cSOlivier Matz test_cksum(void)
22830a65c6cSOlivier Matz {
22930a65c6cSOlivier Matz struct rte_mempool *pktmbuf_pool = NULL;
23030a65c6cSOlivier Matz
23130a65c6cSOlivier Matz /* create pktmbuf pool if it does not exist */
23230a65c6cSOlivier Matz pktmbuf_pool = rte_pktmbuf_pool_create("test_cksum_mbuf_pool",
23330a65c6cSOlivier Matz NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
23430a65c6cSOlivier Matz SOCKET_ID_ANY);
23530a65c6cSOlivier Matz
23630a65c6cSOlivier Matz if (pktmbuf_pool == NULL)
23730a65c6cSOlivier Matz GOTO_FAIL("cannot allocate mbuf pool");
23830a65c6cSOlivier Matz
23930a65c6cSOlivier Matz if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv4_tcp,
24030a65c6cSOlivier Matz sizeof(test_cksum_ipv4_tcp)) < 0)
24130a65c6cSOlivier Matz GOTO_FAIL("checksum error on ipv4_tcp");
24230a65c6cSOlivier Matz
24330a65c6cSOlivier Matz if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv6_tcp,
24430a65c6cSOlivier Matz sizeof(test_cksum_ipv6_tcp)) < 0)
24530a65c6cSOlivier Matz GOTO_FAIL("checksum error on ipv6_tcp");
24630a65c6cSOlivier Matz
24730a65c6cSOlivier Matz if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv4_udp,
24830a65c6cSOlivier Matz sizeof(test_cksum_ipv4_udp)) < 0)
24930a65c6cSOlivier Matz GOTO_FAIL("checksum error on ipv4_udp");
25030a65c6cSOlivier Matz
25130a65c6cSOlivier Matz if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv6_udp,
25230a65c6cSOlivier Matz sizeof(test_cksum_ipv6_udp)) < 0)
25330a65c6cSOlivier Matz GOTO_FAIL("checksum error on ipv6_udp");
25430a65c6cSOlivier Matz
25530a65c6cSOlivier Matz if (test_l4_cksum(pktmbuf_pool, test_cksum_ipv4_opts_udp,
25630a65c6cSOlivier Matz sizeof(test_cksum_ipv4_opts_udp)) < 0)
25730a65c6cSOlivier Matz GOTO_FAIL("checksum error on ipv4_opts_udp");
25830a65c6cSOlivier Matz
25930a65c6cSOlivier Matz rte_mempool_free(pktmbuf_pool);
26030a65c6cSOlivier Matz
26130a65c6cSOlivier Matz return 0;
26230a65c6cSOlivier Matz
26330a65c6cSOlivier Matz fail:
26430a65c6cSOlivier Matz rte_mempool_free(pktmbuf_pool);
26530a65c6cSOlivier Matz
26630a65c6cSOlivier Matz return -1;
26730a65c6cSOlivier Matz }
26830a65c6cSOlivier Matz #undef GOTO_FAIL
26930a65c6cSOlivier Matz
270*e0a8442cSBruce Richardson REGISTER_FAST_TEST(cksum_autotest, true, true, test_cksum);
271