c++ - PACKET_TX_RING only sending out first packet, then not doing anything anymore -
i have following code:
#ifndef rawsocket_h #define rawsocket_h #include <stdio.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdint.h> #include <unistd.h> #include <assert.h> #include <errno.h> #include <fcntl.h> #include <poll.h> #include <arpa/inet.h> #include <netinet/if_ether.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/stat.h> #include <linux/if.h> #include <linux/if_packet.h> #include "ippacket.h" #define conf_ring_frames 128 /// initialize packet socket ring buffer // @param ringtype 1 of packet_rx_ring or packet_tx_ring static inline char * init_packetsock_ring(int fd, int ringtype) { tpacket_req tp; char *ring; // tell kernel export data through mmap()ped ring tp.tp_block_size = 1024 * 8; tp.tp_block_nr = 1024; tp.tp_frame_size = 1024 * 8; tp.tp_frame_nr = 1024; setsockopt(fd, sol_packet, ringtype, (void*) &tp, sizeof(tp)); int val = tpacket_v1; setsockopt(fd, sol_packet, packet_version, &val, sizeof(val)); // open ring ring = (char*)mmap(0, tp.tp_block_size * tp.tp_block_nr, prot_read | prot_write, map_shared, fd, 0); if (!ring) return null; return ring; } /// transmit packet using packet ring // note: high rate processing try batch system calls, // writing multiple packets ring before calling send() // // @param pkt packet network layer (e.g., ip) // @return 0 on success, -1 on failure static inline int process_tx(int fd, char *ring, const char *pkt, int pktlen, sockaddr_ll *txring_daddr) { static int ring_offset = 0; struct tpacket_hdr *header; struct pollfd pollset; char *off; int ret; // fetch frame // in packet_rx_ring case, define frames page long, // including header. explains use of getpagesize(). header = (tpacket_hdr*)(void *) ring + (ring_offset * 1024); while (header->tp_status != tp_status_available) { // if none available: wait on more data pollset.fd = fd; pollset.events = pollout; pollset.revents = 0; ret = poll(&pollset, 1, 1000 /* don't hang */); if (ret < 0) { if (errno != eintr) { perror("poll"); return -1; } return 0; } ring_offset++; if(ring_offset >= 1024 * 8) ring_offset = 0; header = (tpacket_hdr*)(void *) ring + (ring_offset * 1024); } // fill data off = (char*)(((char*) header) + (tpacket_hdrlen - sizeof(struct sockaddr_ll))); memcpy(off, pkt, pktlen); // fill header header->tp_len = pktlen; header->tp_status = tp_status_send_request; // increase consumer ring pointer /*ring_offset++; if(ring_offset >= 1024 * 8) ring_offset = 0;*/ // notify kernel if (sendto(fd, null, 0, 0, (sockaddr*)txring_daddr, sizeof(sockaddr_ll)) < 0) { perror("sendto"); return -1; } return 0; } class rawsocket { public: inline rawsocket() { } inline void initialize() { sockfd = socket(pf_packet, sock_raw, htons(eth_p_ip)); ring = init_packetsock_ring(sockfd, packet_tx_ring); ifreq ifr; memset (&ifr, 0, sizeof (ifr)); strncpy((char *) ifr.ifr_name, "eth0", ifnamsiz); ioctl(sockfd, siocgifindex, &ifr); int index = ifr.ifr_ifindex; ioctl(sockfd, siocgifhwaddr, &ifr); sll = new sockaddr_ll(); sll->sll_family = af_packet; sll->sll_ifindex = index; sll->sll_protocol = htons(eth_p_ip); sll->sll_halen = htons(6); memcpy(ippacket::our_mac, ifr.ifr_hwaddr.sa_data, eth_alen); memcpy(sll->sll_addr, ifr.ifr_hwaddr.sa_data, eth_alen); /*struct packet_mreq mr; memset (&mr, 0, sizeof (mr)); mr.mr_ifindex = ifr.ifr_ifindex; mr.mr_type = packet_mr_promisc; setsockopt(sockfd, sol_packet,packet_add_membership, &mr, sizeof (mr));*/ //setsockopt(sockfd, ipproto_ip, ip_hdrincl, &optval, sizeof(int)); } inline ~rawsocket() { close(sockfd); } inline void send(const ippacket* ip) const { process_tx(sockfd, ring, ip->packet_ptr, ip->tot_len, sll); printf("tx\n"); } protected: char *ring; int sockfd; sockaddr_ll *sll; }; #endif // rawsocket_h
ip->packet_ptr being pointer packet containing ethhdr , iphdr , on. packets being correcly sent via "normal" pf_packet sockets. tried using tx ring feature. however, first packet ever gets sent (and gets sent 100% correctly). nothing else seems happen on network layer (tcpdump -vvv -e shows no network traffic @ occuring!) however, sendto() calls processed correctly.
i didnt test functionality myself, think have error in configuring struct tpacket_req
fields. _nr fields quite large. see example code (linked wiki ):
/* setup fd mmap() ring buffer */ req.tp_block_size=4096; req.tp_frame_size=1024; req.tp_block_nr=64; req.tp_frame_nr=4*64; if ( (setsockopt(fd, sol_packet, packet_rx_ring, (char *)&req, sizeof(req))) != 0 ) { perror("setsockopt()"); close(fd); return 1; }; /* mmap() sucker */ map=mmap(null, req.tp_block_size * req.tp_block_nr, prot_read|prot_write|prot_exec, map_shared, fd, 0);
Comments
Post a Comment