mirror of
https://github.com/rtbrick/bngblaster.git
synced 2024-05-06 15:54:57 +00:00
IO fixes/enhancements
This commit is contained in:
committed by
Christian Giese
parent
4d8de4fd34
commit
425f384efd
@@ -50,10 +50,8 @@ typedef struct io_handle_ {
|
||||
struct sockaddr_ll addr;
|
||||
|
||||
uint8_t *ring; /* ring buffer */
|
||||
uint16_t cursor; /* ring buffer cursor */
|
||||
uint16_t queued;
|
||||
bool polled;
|
||||
bool ctrl;
|
||||
unsigned int cursor; /* ring buffer cursor */
|
||||
unsigned int queued;
|
||||
|
||||
io_thread_s *thread;
|
||||
bbl_interface_s *interface;
|
||||
|
||||
@@ -20,16 +20,14 @@
|
||||
static void
|
||||
poll_kernel(io_handle_s *io, short events)
|
||||
{
|
||||
struct pollfd fds[1] = {0};
|
||||
fds[0].fd = io->fd;
|
||||
fds[0].events = events;
|
||||
fds[0].revents = 0;
|
||||
struct pollfd pollset;
|
||||
pollset.fd = io->fd;
|
||||
pollset.events = events;
|
||||
pollset.revents = 0;
|
||||
io->stats.polled++;
|
||||
if(poll(fds, 1, 0) == -1) {
|
||||
if(poll(&pollset, 1, 0) == -1) {
|
||||
LOG(IO, "Failed to poll interface %s",
|
||||
io->interface->name);
|
||||
} else {
|
||||
io->polled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,20 +130,14 @@ io_packet_mmap_tx_job(timer_s *timer)
|
||||
assert(io->thread == NULL);
|
||||
|
||||
frame_ptr = io->ring + (io->cursor * io->req.tp_frame_size);
|
||||
tphdr = (struct tpacket2_hdr *)frame_ptr;
|
||||
if(tphdr->tp_status != TP_STATUS_AVAILABLE) {
|
||||
if(io->polled) {
|
||||
/* We already polled kernel. */
|
||||
return;
|
||||
}
|
||||
/* If no buffer is available poll kernel. */
|
||||
poll_kernel(io, POLLOUT);
|
||||
tphdr = (struct tpacket2_hdr*)frame_ptr;
|
||||
if(!(tphdr->tp_status != TP_STATUS_AVAILABLE)) {
|
||||
/* If no buffer is available poll kernel */
|
||||
poll_kernel(io, POLLIN);
|
||||
io->stats.no_buffer++;
|
||||
} else {
|
||||
io->polled = false;
|
||||
|
||||
/* Get TX timestamp */
|
||||
clock_gettime(CLOCK_MONOTONIC, &io->timestamp);
|
||||
|
||||
while(tx_result != EMPTY) {
|
||||
/* Check if this slot available for writing. */
|
||||
if(tphdr->tp_status != TP_STATUS_AVAILABLE) {
|
||||
@@ -155,19 +147,18 @@ io_packet_mmap_tx_job(timer_s *timer)
|
||||
io->buf = frame_ptr + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);
|
||||
tx_result = bbl_tx(interface, io->buf, &io->buf_len);
|
||||
if(tx_result == PROTOCOL_SUCCESS) {
|
||||
io->queued++;
|
||||
tphdr->tp_len = io->buf_len;
|
||||
tphdr->tp_status = TP_STATUS_SEND_REQUEST;
|
||||
io->stats.packets++;
|
||||
io->stats.bytes += io->buf_len;
|
||||
/* Dump the packet into pcap file. */
|
||||
if(g_ctx->pcap.write_buf) {
|
||||
pcap = true;
|
||||
pcapng_push_packet_header(&io->timestamp, io->buf, io->buf_len,
|
||||
interface->pcap_index, PCAPNG_EPB_FLAGS_OUTBOUND);
|
||||
}
|
||||
/* Request send from kernel. */
|
||||
tphdr->tp_len = io->buf_len;
|
||||
tphdr->tp_status = TP_STATUS_SEND_REQUEST;
|
||||
io->queued++;
|
||||
io->stats.packets++;
|
||||
io->stats.bytes += io->buf_len;
|
||||
|
||||
/* Get next slot. */
|
||||
io->cursor = (io->cursor + 1) % io->req.tp_frame_nr;
|
||||
frame_ptr = io->ring + (io->cursor * io->req.tp_frame_size);
|
||||
@@ -181,7 +172,7 @@ io_packet_mmap_tx_job(timer_s *timer)
|
||||
|
||||
if(io->queued) {
|
||||
/* Notify kernel. */
|
||||
if(sendto(io->fd, NULL, 0, 0, NULL, 0) == -1) {
|
||||
if(sendto(io->fd, NULL, 0, 0, NULL, 0) < 0) {
|
||||
LOG(IO, "PACKET_MMAP sendto on interface %s failed with error %s (%d)\n",
|
||||
interface->name, strerror(errno), errno);
|
||||
io->stats.io_errors++;
|
||||
@@ -266,15 +257,10 @@ io_packet_mmap_thread_tx_job(timer_s *timer)
|
||||
frame_ptr = io->ring + (io->cursor * io->req.tp_frame_size);
|
||||
tphdr = (struct tpacket2_hdr *)frame_ptr;
|
||||
if(tphdr->tp_status != TP_STATUS_AVAILABLE) {
|
||||
if(io->polled) {
|
||||
/* We already polled kernel. */
|
||||
return;
|
||||
}
|
||||
/* If no buffer is available poll kernel. */
|
||||
poll_kernel(io, POLLOUT);
|
||||
io->stats.no_buffer++;
|
||||
} else {
|
||||
io->polled = false;
|
||||
|
||||
while((slot = bbl_txq_read_slot(txq))) {
|
||||
/* Check if this slot available for writing. */
|
||||
if(tphdr->tp_status != TP_STATUS_AVAILABLE) {
|
||||
@@ -283,14 +269,12 @@ io_packet_mmap_thread_tx_job(timer_s *timer)
|
||||
}
|
||||
io->buf = frame_ptr + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);
|
||||
io->buf_len = slot->packet_len;
|
||||
io->queued++;
|
||||
io->stats.packets++;
|
||||
io->stats.bytes += slot->packet_len;
|
||||
memcpy(io->buf, slot->packet, slot->packet_len);
|
||||
tphdr->tp_len = io->buf_len;
|
||||
tphdr->tp_status = TP_STATUS_SEND_REQUEST;
|
||||
/* Request send from kernel. */
|
||||
tphdr->tp_status = TP_STATUS_SEND_REQUEST;
|
||||
io->queued++;
|
||||
io->stats.packets++;
|
||||
io->stats.bytes += io->buf_len;
|
||||
/* Get next slot. */
|
||||
io->cursor = (io->cursor + 1) % io->req.tp_frame_nr;
|
||||
frame_ptr = io->ring + (io->cursor * io->req.tp_frame_size);
|
||||
@@ -301,7 +285,7 @@ io_packet_mmap_thread_tx_job(timer_s *timer)
|
||||
|
||||
if(io->queued) {
|
||||
/* Notify kernel. */
|
||||
if(sendto(io->fd, NULL, 0, 0, NULL, 0) == -1) {
|
||||
if(sendto(io->fd, NULL, 0, 0, NULL, 0) < 0) {
|
||||
LOG(IO, "PACKET_MMAP sendto on interface %s failed with error %s (%d)\n",
|
||||
interface->name, strerror(errno), errno);
|
||||
io->stats.io_errors++;
|
||||
@@ -327,28 +311,26 @@ io_packet_mmap_send(io_handle_s *io, uint8_t *buf, uint16_t len)
|
||||
frame_ptr = io->ring + (io->cursor * io->req.tp_frame_size);
|
||||
tphdr = (struct tpacket2_hdr *)frame_ptr;
|
||||
if(tphdr->tp_status != TP_STATUS_AVAILABLE) {
|
||||
if(!io->polled) {
|
||||
/* If no buffer is available poll kernel. */
|
||||
poll_kernel(io, POLLOUT);
|
||||
}
|
||||
/* If no buffer is available poll kernel. */
|
||||
poll_kernel(io, POLLOUT);
|
||||
io->stats.no_buffer++;
|
||||
return false;
|
||||
}
|
||||
io->polled = false;
|
||||
io->queued++;
|
||||
|
||||
tphdr_buf = frame_ptr + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);
|
||||
memcpy(tphdr_buf, buf, len);
|
||||
tphdr->tp_len = len;
|
||||
tphdr->tp_status = TP_STATUS_SEND_REQUEST;
|
||||
/* Request send from kernel. */
|
||||
tphdr->tp_status = TP_STATUS_SEND_REQUEST;
|
||||
io->queued++;
|
||||
io->stats.packets++;
|
||||
io->stats.bytes += len;
|
||||
/* Get next slot. */
|
||||
io->cursor = (io->cursor + 1) % io->req.tp_frame_nr;
|
||||
frame_ptr = io->ring + (io->cursor * io->req.tp_frame_size);
|
||||
tphdr = (struct tpacket2_hdr *)frame_ptr;
|
||||
if(tphdr->tp_status != TP_STATUS_AVAILABLE) {
|
||||
/* Notify kernel. */
|
||||
if(sendto(io->fd, NULL, 0, 0, NULL, 0) == -1) {
|
||||
if(sendto(io->fd, NULL, 0, 0, NULL, 0) < 0) {
|
||||
LOG(IO, "PACKET_MMAP sendto on interface %s failed with error %s (%d)\n",
|
||||
interface->name, strerror(errno), errno);
|
||||
io->stats.io_errors++;
|
||||
|
||||
@@ -118,6 +118,8 @@ io_raw_thread_rx_run_fn(io_thread_s *thread)
|
||||
|
||||
struct timespec sleep, rem;
|
||||
|
||||
assert(io->direction == IO_INGRESS);
|
||||
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 0;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ set_qdisc_bypass(io_handle_s *io) {
|
||||
/* Set fanout group. */
|
||||
static bool
|
||||
set_fanout(io_handle_s *io) {
|
||||
if(io->direction == IO_INGRESS && io->fanout_id) {
|
||||
if(io->fanout_id) {
|
||||
int fanout_arg = (io->fanout_id | (io->fanout_type << 16));
|
||||
if (setsockopt(io->fd, SOL_PACKET, PACKET_FANOUT, &fanout_arg, sizeof(fanout_arg)) == -1) {
|
||||
LOG(ERROR, "Failed to set fanout group for interface %s - %s (%d)\n",
|
||||
@@ -67,22 +67,21 @@ set_ring(io_handle_s *io, int slots) {
|
||||
* - tp_frame_nr must be exactly frames_per_block*tp_block_nr
|
||||
* Note that tp_block_size should be chosen to be a power of two
|
||||
* or there will be a waste of memory. */
|
||||
size_t ring_size = 0;
|
||||
unsigned int ring_size = 0;
|
||||
int flag = 0;
|
||||
|
||||
if(io->direction == IO_INGRESS) {
|
||||
flag = PACKET_RX_RING;
|
||||
} else {
|
||||
flag = PACKET_TX_RING;
|
||||
}
|
||||
io->req.tp_block_size = sysconf(_SC_PAGESIZE); /* 4096 */
|
||||
io->req.tp_frame_size =io->req.tp_block_size/2; /* 2048 */
|
||||
io->req.tp_block_nr = slots/2;
|
||||
io->req.tp_block_size = getpagesize(); /* 4096 */
|
||||
io->req.tp_frame_size = io->req.tp_block_size;
|
||||
io->req.tp_block_nr = slots;
|
||||
io->req.tp_frame_nr = slots;
|
||||
|
||||
ring_size = io->req.tp_block_nr * io->req.tp_block_size;
|
||||
|
||||
LOG(DEBUG, "Setup %lu byte packet_mmap ringbuffer (%d slots) for interface %s\n",
|
||||
LOG(DEBUG, "Setup %u byte packet_mmap ringbuffer (%d slots) for interface %s\n",
|
||||
ring_size, slots, io->interface->name);
|
||||
if (setsockopt(io->fd, SOL_PACKET, flag, &io->req, sizeof(struct tpacket_req)) == -1) {
|
||||
LOG(ERROR, "Allocating ringbuffer error for interface %s - %s (%d)\n",
|
||||
@@ -105,25 +104,23 @@ io_socket_open(io_handle_s *io) {
|
||||
assert(io->mode == IO_MODE_PACKET_MMAP || io->mode == IO_MODE_RAW);
|
||||
|
||||
int protocol = 0;
|
||||
int slots = config->io_slots_tx;
|
||||
|
||||
if(io->direction == IO_INGRESS) {
|
||||
protocol = htobe16(ETH_P_ALL);
|
||||
}
|
||||
|
||||
uint16_t slots = config->io_slots_tx;
|
||||
if(io->direction == IO_INGRESS) {
|
||||
slots = config->io_slots_rx;
|
||||
}
|
||||
|
||||
/* Open RAW socket for all ethertypes.
|
||||
* https://man7.org/linux/man-pages/man7/packet.7.html */
|
||||
io->fd = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK, protocol);
|
||||
io->fd = socket(AF_PACKET, SOCK_RAW|SOCK_NONBLOCK, protocol);
|
||||
if(io->fd == -1) {
|
||||
LOG(ERROR, "Failed to open socket for interface %s - %s (%d)\n",
|
||||
io->interface->name, strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
/* Limit socket to the given interface index. */
|
||||
io->addr.sll_family = PF_PACKET;
|
||||
io->addr.sll_family = AF_PACKET;
|
||||
io->addr.sll_ifindex = io->interface->ifindex;
|
||||
io->addr.sll_protocol = protocol;
|
||||
if (bind(io->fd, (struct sockaddr*)&io->addr, sizeof(io->addr)) == -1) {
|
||||
|
||||
Reference in New Issue
Block a user