Add a test case and sample code for (TPACKET_V3, PACKET_TX_RING)

Signed-off-by: Sowmini Varadhan <sowmini.varad...@oracle.com>
---
v2: Added test case.

 tools/testing/selftests/net/psock_tpacket.c |  110 ++++++++++++++++++++++++++-
 1 files changed, 109 insertions(+), 1 deletions(-)

diff --git a/tools/testing/selftests/net/psock_tpacket.c 
b/tools/testing/selftests/net/psock_tpacket.c
index 24adf70..f2012dc 100644
--- a/tools/testing/selftests/net/psock_tpacket.c
+++ b/tools/testing/selftests/net/psock_tpacket.c
@@ -311,6 +311,17 @@ static inline void __v2_tx_user_ready(struct tpacket2_hdr 
*hdr)
        __sync_synchronize();
 }
 
+static inline int __v3_tx_kernel_ready(struct tpacket3_hdr *hdr)
+{
+       return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING));
+}
+
+static inline void __v3_tx_user_ready(struct tpacket3_hdr *hdr)
+{
+       hdr->tp_status = TP_STATUS_SEND_REQUEST;
+       __sync_synchronize();
+}
+
 static inline int __v1_v2_tx_kernel_ready(void *base, int version)
 {
        switch (version) {
@@ -578,12 +589,108 @@ static void walk_v3_rx(int sock, struct ring *ring)
        fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1);
 }
 
+static inline void *
+get_v3_frame(struct ring *ring, int n)
+{
+       uint8_t *f0 = ring->rd[0].iov_base;
+
+       return f0 + (n * ring->req3.tp_frame_size);
+}
+
+static void walk_v3_tx(int sock, struct ring *ring)
+{
+       struct pollfd pfd;
+       int rcv_sock, ret;
+       size_t packet_len;
+       char packet[1024];
+       unsigned int frame_num = 0, got = 0;
+       struct sockaddr_ll ll = {
+               .sll_family = PF_PACKET,
+               .sll_halen = ETH_ALEN,
+       };
+
+       bug_on(ring->type != PACKET_TX_RING);
+       bug_on(ring->req3.tp_frame_nr < NUM_PACKETS);
+
+       rcv_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       if (rcv_sock == -1) {
+               perror("socket");
+               exit(1);
+       }
+
+       pair_udp_setfilter(rcv_sock);
+
+       ll.sll_ifindex = if_nametoindex("lo");
+       ret = bind(rcv_sock, (struct sockaddr *) &ll, sizeof(ll));
+       if (ret == -1) {
+               perror("bind");
+               exit(1);
+       }
+
+       memset(&pfd, 0, sizeof(pfd));
+       pfd.fd = sock;
+       pfd.events = POLLOUT | POLLERR;
+       pfd.revents = 0;
+
+       total_packets = NUM_PACKETS;
+       create_payload(packet, &packet_len);
+
+       while (total_packets > 0) {
+               struct tpacket3_hdr *tx = get_v3_frame(ring, frame_num);
+
+               while (__v3_tx_kernel_ready(tx) && total_packets > 0) {
+                       tx->tp_snaplen = packet_len;
+                       tx->tp_len = packet_len;
+                       memcpy((uint8_t *) tx + TPACKET3_HDRLEN -
+                              sizeof(struct sockaddr_ll), packet, packet_len);
+                       total_bytes += tx->tp_snaplen;
+
+                       status_bar_update();
+                       total_packets--;
+
+                       __v3_tx_user_ready(tx);
+
+                       frame_num = (frame_num + 1) % ring->req3.tp_frame_nr;
+               }
+
+               poll(&pfd, 1, 1);
+       }
+
+       bug_on(total_packets != 0);
+
+       ret = sendto(sock, NULL, 0, 0, NULL, 0);
+       if (ret == -1) {
+               perror("sendto");
+               exit(1);
+       }
+
+       while ((ret = recvfrom(rcv_sock, packet, sizeof(packet),
+                              0, NULL, NULL)) > 0 &&
+              total_packets < NUM_PACKETS) {
+               got += ret;
+               test_payload(packet, ret);
+
+               status_bar_update();
+               total_packets++;
+       }
+
+       close(rcv_sock);
+
+       if (total_packets != NUM_PACKETS) {
+               fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n",
+                       ring->version, total_packets, NUM_PACKETS);
+               exit(1);
+       }
+
+       fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, got);
+}
+
 static void walk_v3(int sock, struct ring *ring)
 {
        if (ring->type == PACKET_RX_RING)
                walk_v3_rx(sock, ring);
        else
-               bug_on(1);
+               walk_v3_tx(sock, ring);
 }
 
 static void __v1_v2_fill(struct ring *ring, unsigned int blocks)
@@ -796,6 +903,7 @@ int main(void)
        ret |= test_tpacket(TPACKET_V2, PACKET_TX_RING);
 
        ret |= test_tpacket(TPACKET_V3, PACKET_RX_RING);
+       ret |= test_tpacket(TPACKET_V3, PACKET_TX_RING);
 
        if (ret)
                return 1;
-- 
1.7.1

Reply via email to