根据 http://man7.org/linux/man-pages/man7/packet.7.html,有一个新选项PACKET_QDISC_BYPASS 自 Linux 3.14 以来。 这有可能更快地发送和接收数据包。
看到一个示例代码:https://github.com/netoptimizer/network-testing/blob/master/src/raw_packet_send.c,但不幸的是它没有发送数据包的代码。
我添加了一些代码来发送数据包,但它在发送方面存在问题。
# ./raw_packet_send p6p1 64
Lame RAW/PF_PACKET socket TX test program
Enabled kernel qdisc bypass
error sendto : Invalid argument
不知道为什么。 这是代码(原始raw_packet_send.c与我的愚蠢代码(。 请让我知道如何使其工作或指出一些好的简单示例代码。 谢谢。
#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:%dn", __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 bypassn");
}
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("%sn", 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 programn");
int sock = pf_tx_socket(0);
set_sock_qdisc_bypass(sock, 1);
mybind(sock, intfName);
flood(sock);
return 0;
}
我认为您需要从PF_PACKET
更改为AF_PACKET
(尽管看起来PF_PACKET
是AF_PACKET
的别名(,但是使用PF_PACKET
时我没有任何成功。
这段代码对我有用:
// 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;
}
这是从setup_socket_mmap()
这里