Sample code using PACKET_QDISC_BYPASS parameter on ethernet raw socket on linux

According to http://man7.org/linux/man-pages/man7/packet.7.html there is a new PACKET_QDISC_BYPASS option with Linux 3.14. It has the ability to send and receive packets much faster.

Highlighted the sample code: https://github.com/netoptimizer/network-testing/blob/master/src/raw_packet_send.c but unfortunately it has no code when sending packets.

I added some code to send packets but it had a problem with sendto.

# ./raw_packet_send p6p1 64
Lame RAW/PF_PACKET socket TX test program
Enabled kernel qdisc bypass
error sendto : Invalid argument

      

I do not know why. Here is the code (original raw_packet_send.c with my silly code). Please let me know how this might make it work or point to a good simple code example. Thank.

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>

//#include <stdio.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <sys/socket.h>
//#include <sys/mman.h>
//#include <linux/filter.h>
//#include <ctype.h>
//#include <fcntl.h>
//#include <unistd.h>
//#include <bits/wordsize.h>
//#include <net/ethernet.h>
//#include <netinet/ip.h>
//#include <arpa/inet.h>
//#include <stdint.h>
//#include <string.h>
//#include <assert.h>
//#include <net/if.h>
//#include <inttypes.h>
//#include <poll.h>
//#include <unistd.h>

#ifndef PACKET_QDISC_BYPASS
#define PACKET_QDISC_BYPASS 20
#endif

#include "common_socket.h"

char pkt[2000] = {0x00, 1,2,3,4,0, 0,1,2,3,4,1, 8, 0};;
int len = 96;
char intfName[100] = "em1";
/* Avail in kernel >= 3.14
 * in commit d346a3fae3 (packet: introduce PACKET_QDISC_BYPASS socket option)
 */
void set_sock_qdisc_bypass(int fd, int verbose)
{
    int ret, val = 1;

    ret = setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &val, sizeof(val));
    if (ret < 0) {
        printf("[DEBUG] %s(): err:%d errno:%d\n", __func__, ret, errno);
        if (errno == ENOPROTOOPT) {
            if (verbose)
                printf("No kernel support for PACKET_QDISC_BYPASS"
                       " (kernel < 3.14?)\n");
        } else {
            perror("Cannot set PACKET_QDISC_BYPASS");
        }
    } else
        if (verbose) printf("Enabled kernel qdisc bypass\n");
}

int pf_tx_socket(int ver)
{
        int ret, val = 1;

    /* Don't use proto htons(ETH_P_ALL) as we only want to transmit */
    int sock = socket(PF_PACKET, SOCK_RAW, 0);
    //int sock = socket(AF_INET,SOCK_PACKET,htons(3));
        if (sock == -1) {
                perror("Creation of RAW PF_SOCKET failed!\n");
                exit(1);
        }

        ret = Setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver));

        return sock;
}

void mybind(int sock, char *intf) {
    struct ifreq ifr;
    int rc;
    memset((char*)&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), intf);
    if ((rc = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0)
    {
        perror("Server-setsockopt() error for SO_BINDTODEVICE");
      printf("%s\n", strerror(errno));
       close(sock);
      exit(-1);
    }
}

int flood (int sock) {
    struct sockaddr intfAddrs;
    char cmd[100];
    int tmp;
    memset((char*)&intfAddrs, 0, sizeof (struct sockaddr));
    intfAddrs.sa_family = PF_PACKET;
    strcpy((char*)(intfAddrs.sa_data),  intfName);  
    sprintf(cmd, "ifconfig %s promisc", intfName);  system(cmd);
    while (1) {
        while (1) {
            tmp = sendto(sock, pkt, len, 0, &intfAddrs, sizeof(intfAddrs));
            if (tmp != len) {perror("error sendto "); exit(0); }
        }
    }
}

int main(int argc, char **argv)
{
    if (argc > 1) { strcpy(intfName, argv[1]); }
    if (argc > 2) { len = atoi(argv[2]); }
    printf("Lame RAW/PF_PACKET socket TX test program\n");

    int sock = pf_tx_socket(0);

    set_sock_qdisc_bypass(sock, 1);
    mybind(sock, intfName);
    flood(sock);

    return 0;
}

      

+3


source to share


1 answer


I think you need to change from PF_PACKET

to AF_PACKET

(although it looks like it PF_PACKET

is an alias AF_PACKET

), but PF_PACKET

I have no success using it.

This code works for me:



// Create a raw socket
sock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

if (sock_fd == -1) {
    perror("Can't create AF_PACKET socket");
    return EXIT_FAILURE;
}


// Check kernel version
static const int32_t sock_qdisc_bypass = 1;
int32_t sock_qdisc_ret = setsockopt(thd_opt->sock_fd, SOL_PACKET, PACKET_QDISC_BYPASS, &sock_qdisc_bypass, sizeof(sock_qdisc_bypass));

if (sock_qdisc_ret == -1) {
    perror("Can't enable QDISC bypass on socket");
    return EXIT_FAILURE;
}

      

This is from setup_socket_mmap()

here

0


source







All Articles