linux/tools/testing/selftests/net/txring_overwrite.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Verify that consecutive sends over packet tx_ring are mirrored
   5 * with their original content intact.
   6 */
   7
   8#define _GNU_SOURCE
   9
  10#include <arpa/inet.h>
  11#include <assert.h>
  12#include <error.h>
  13#include <errno.h>
  14#include <fcntl.h>
  15#include <linux/filter.h>
  16#include <linux/if_packet.h>
  17#include <net/ethernet.h>
  18#include <net/if.h>
  19#include <netinet/in.h>
  20#include <netinet/ip.h>
  21#include <netinet/udp.h>
  22#include <poll.h>
  23#include <pthread.h>
  24#include <sched.h>
  25#include <sys/ioctl.h>
  26#include <sys/mman.h>
  27#include <sys/socket.h>
  28#include <sys/time.h>
  29#include <sys/types.h>
  30#include <sys/utsname.h>
  31#include <stdbool.h>
  32#include <stdint.h>
  33#include <stdio.h>
  34#include <stdlib.h>
  35#include <string.h>
  36#include <unistd.h>
  37
  38const int eth_off = TPACKET_HDRLEN - sizeof(struct sockaddr_ll);
  39const int cfg_frame_size = 1000;
  40
  41static void build_packet(void *buffer, size_t blen, char payload_char)
  42{
  43        struct udphdr *udph;
  44        struct ethhdr *eth;
  45        struct iphdr *iph;
  46        size_t off = 0;
  47
  48        memset(buffer, 0, blen);
  49
  50        eth = buffer;
  51        eth->h_proto = htons(ETH_P_IP);
  52
  53        off += sizeof(*eth);
  54        iph = buffer + off;
  55        iph->ttl        = 8;
  56        iph->ihl        = 5;
  57        iph->version    = 4;
  58        iph->saddr      = htonl(INADDR_LOOPBACK);
  59        iph->daddr      = htonl(INADDR_LOOPBACK + 1);
  60        iph->protocol   = IPPROTO_UDP;
  61        iph->tot_len    = htons(blen - off);
  62        iph->check      = 0;
  63
  64        off += sizeof(*iph);
  65        udph = buffer + off;
  66        udph->dest      = htons(8000);
  67        udph->source    = htons(8001);
  68        udph->len       = htons(blen - off);
  69        udph->check     = 0;
  70
  71        off += sizeof(*udph);
  72        memset(buffer + off, payload_char, blen - off);
  73}
  74
  75static int setup_rx(void)
  76{
  77        int fdr;
  78
  79        fdr = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
  80        if (fdr == -1)
  81                error(1, errno, "socket r");
  82
  83        return fdr;
  84}
  85
  86static int setup_tx(char **ring)
  87{
  88        struct sockaddr_ll laddr = {};
  89        struct tpacket_req req = {};
  90        int fdt;
  91
  92        fdt = socket(PF_PACKET, SOCK_RAW, 0);
  93        if (fdt == -1)
  94                error(1, errno, "socket t");
  95
  96        laddr.sll_family = AF_PACKET;
  97        laddr.sll_protocol = htons(0);
  98        laddr.sll_ifindex = if_nametoindex("lo");
  99        if (!laddr.sll_ifindex)
 100                error(1, errno, "if_nametoindex");
 101
 102        if (bind(fdt, (void *)&laddr, sizeof(laddr)))
 103                error(1, errno, "bind fdt");
 104
 105        req.tp_block_size = getpagesize();
 106        req.tp_block_nr   = 1;
 107        req.tp_frame_size = getpagesize();
 108        req.tp_frame_nr   = 1;
 109
 110        if (setsockopt(fdt, SOL_PACKET, PACKET_TX_RING,
 111                       (void *)&req, sizeof(req)))
 112                error(1, errno, "setsockopt ring");
 113
 114        *ring = mmap(0, req.tp_block_size * req.tp_block_nr,
 115                     PROT_READ | PROT_WRITE, MAP_SHARED, fdt, 0);
 116        if (*ring == MAP_FAILED)
 117                error(1, errno, "mmap");
 118
 119        return fdt;
 120}
 121
 122static void send_pkt(int fdt, void *slot, char payload_char)
 123{
 124        struct tpacket_hdr *header = slot;
 125        int ret;
 126
 127        while (header->tp_status != TP_STATUS_AVAILABLE)
 128                usleep(1000);
 129
 130        build_packet(slot + eth_off, cfg_frame_size, payload_char);
 131
 132        header->tp_len = cfg_frame_size;
 133        header->tp_status = TP_STATUS_SEND_REQUEST;
 134
 135        ret = sendto(fdt, NULL, 0, 0, NULL, 0);
 136        if (ret == -1)
 137                error(1, errno, "kick tx");
 138}
 139
 140static int read_verify_pkt(int fdr, char payload_char)
 141{
 142        char buf[100];
 143        int ret;
 144
 145        ret = read(fdr, buf, sizeof(buf));
 146        if (ret != sizeof(buf))
 147                error(1, errno, "read");
 148
 149        if (buf[60] != payload_char) {
 150                printf("wrong pattern: 0x%x != 0x%x\n", buf[60], payload_char);
 151                return 1;
 152        }
 153
 154        printf("read: %c (0x%x)\n", buf[60], buf[60]);
 155        return 0;
 156}
 157
 158int main(int argc, char **argv)
 159{
 160        const char payload_patterns[] = "ab";
 161        char *ring;
 162        int fdr, fdt, ret = 0;
 163
 164        fdr = setup_rx();
 165        fdt = setup_tx(&ring);
 166
 167        send_pkt(fdt, ring, payload_patterns[0]);
 168        send_pkt(fdt, ring, payload_patterns[1]);
 169
 170        ret |= read_verify_pkt(fdr, payload_patterns[0]);
 171        ret |= read_verify_pkt(fdr, payload_patterns[1]);
 172
 173        if (close(fdt))
 174                error(1, errno, "close t");
 175        if (close(fdr))
 176                error(1, errno, "close r");
 177
 178        return ret;
 179}
 180