Commit 2ba307c4 authored by Joanne Hugé's avatar Joanne Hugé

Remove poll wake-up for signal emission and XPD

parent 3f5754b5
...@@ -63,156 +63,141 @@ static char ts_tracemark_buf[64]; ...@@ -63,156 +63,141 @@ static char ts_tracemark_buf[64];
// Sets the interface // Sets the interface
static int set_if(void) { static int set_if(void) {
struct ifreq ifreq; struct ifreq ifreq;
memset(&ifreq, 0, sizeof(ifreq)); memset(&ifreq, 0, sizeof(ifreq));
strncpy(ifreq.ifr_name, params->network_if, sizeof(ifreq.ifr_name) - 1); strncpy(ifreq.ifr_name, params->network_if, sizeof(ifreq.ifr_name) - 1);
if (ioctl(sock_fd, SIOCGIFINDEX, &ifreq)) if (ioctl(sock_fd, SIOCGIFINDEX, &ifreq))
error(EXIT_FAILURE, errno, "ioctl SIOCGIFINDEX failed\n"); error(EXIT_FAILURE, errno, "ioctl SIOCGIFINDEX failed\n");
return ifreq.ifr_ifindex; return ifreq.ifr_ifindex;
} }
void init_udp_recv(ingress_param_t *_params, ingress_stat_t *_stats, void init_udp_recv(ingress_param_t *_params, ingress_stat_t *_stats,
int _use_histogram, uint64_t *_kernel_latency_hist) { int _use_histogram, uint64_t *_kernel_latency_hist) {
int getaddrinfo_err; int getaddrinfo_err;
int set_if_err; int set_if_err;
struct addrinfo hints, *servinfo, *servinfo_it; struct addrinfo hints, *servinfo, *servinfo_it;
params = _params; params = _params;
stats = _stats; stats = _stats;
use_histogram = _use_histogram; use_histogram = _use_histogram;
kernel_latency_hist = _kernel_latency_hist; kernel_latency_hist = _kernel_latency_hist;
memset(&hints, 0, sizeof hints); memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
getaddrinfo_err = getaddrinfo(NULL, SERVER_PORT, &hints, &servinfo); getaddrinfo_err = getaddrinfo(NULL, SERVER_PORT, &hints, &servinfo);
if (getaddrinfo_err != 0) { if (getaddrinfo_err != 0) {
fprintf(stderr, "getaddrinfo: %s\n", fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(getaddrinfo_err));
gai_strerror(getaddrinfo_err)); exit(EXIT_FAILURE);
exit(EXIT_FAILURE); }
}
for (servinfo_it = servinfo; servinfo_it;
for (servinfo_it = servinfo; servinfo_it; servinfo_it = servinfo_it->ai_next) {
servinfo_it = servinfo_it->ai_next) { sock_fd = socket(servinfo->ai_family, servinfo->ai_socktype,
sock_fd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
servinfo->ai_protocol);
if (bind(sock_fd, servinfo_it->ai_addr, servinfo_it->ai_addrlen) == -1) {
if (bind(sock_fd, servinfo_it->ai_addr, close(sock_fd);
servinfo_it->ai_addrlen) == -1) { continue;
close(sock_fd); }
continue; break;
} }
break;
} freeaddrinfo(servinfo);
freeaddrinfo(servinfo); if (sock_fd == -1)
error(EXIT_FAILURE, errno, "Couldn't create receive socket");
if (sock_fd == -1)
error(EXIT_FAILURE, errno, "Couldn't create receive socket"); set_if_err = set_if();
if (set_if_err < 0) error(EXIT_FAILURE, errno, "Couldn't set interface\n");
set_if_err = set_if();
if (set_if_err < 0) if (setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, params->network_if,
error(EXIT_FAILURE, errno, "Couldn't set interface\n"); strlen(params->network_if)))
error(EXIT_FAILURE, errno, "setsockopt SO_BINDTODEVICE failed\n");
if (setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, params->network_if,
strlen(params->network_if))) if (params->use_timestamps) {
error(EXIT_FAILURE, errno, if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping_flags,
"setsockopt SO_BINDTODEVICE failed\n"); sizeof(so_timestamping_flags)))
error(EXIT_FAILURE, errno, "setsockopt SO_TIMESTAMPING failed\n");
if (params->use_timestamps) { }
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING,
&so_timestamping_flags,
sizeof(so_timestamping_flags)))
error(EXIT_FAILURE, errno,
"setsockopt SO_TIMESTAMPING failed\n");
}
} }
/* /*
* Receive UDP packet * Receive UDP packet
*/ */
void recv_udp_packet() { void recv_udp_packet() {
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
struct msghdr msg; // Message hardware, sent to the socket struct msghdr msg; // Message hardware, sent to the socket
struct iovec iov; // The iovec structures stores the RX buffer struct iovec iov; // The iovec structures stores the RX buffer
struct sockaddr_in sin; struct sockaddr_in sin;
struct { struct {
struct cmsghdr cm; struct cmsghdr cm;
char control[512]; char control[512];
} control; } control;
int recvmsgerr; int recvmsgerr;
struct timespec ts; struct timespec ts;
iov.iov_base = &rx_buffer; iov.iov_base = &rx_buffer;
iov.iov_len = MAX_BUFFER_SIZE - 1; iov.iov_len = MAX_BUFFER_SIZE - 1;
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
msg.msg_name = &sin; msg.msg_name = &sin;
msg.msg_namelen = sizeof(sin); msg.msg_namelen = sizeof(sin);
msg.msg_iov = &iov; msg.msg_iov = &iov;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
msg.msg_control = &control; msg.msg_control = &control;
msg.msg_controllen = sizeof(control); msg.msg_controllen = sizeof(control);
recvmsgerr = recvmsg(sock_fd, &msg, 0); recvmsgerr = recvmsg(sock_fd, &msg, 0);
if (recvmsgerr < 0) if (recvmsgerr < 0)
error(EXIT_FAILURE, errno, "recvmsg failed, ret value: %d\n", error(EXIT_FAILURE, errno, "recvmsg failed, ret value: %d\n", recvmsgerr);
recvmsgerr);
if (params->use_timestamps) {
if (params->use_timestamps) { clock_gettime(CLOCK_REALTIME, &ts);
clock_gettime(CLOCK_REALTIME, &ts); post_kernel_timestamp = ts_to_uint(ts);
post_kernel_timestamp = ts_to_uint(ts); }
}
if (params->use_timestamps) {
if (params->use_timestamps) { for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg = CMSG_NXTHDR(&msg, cmsg)) { cmsg->cmsg_type == SO_TIMESTAMPING) {
if (cmsg->cmsg_level == SOL_SOCKET && struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = if (params->enable_ts_tracemark) {
(struct timespec *)CMSG_DATA(cmsg); sprintf(ts_tracemark_buf, "%" PRIu64, ts_to_uint(*stamp));
tracemark(ts_tracemark_buf);
if(params->enable_ts_tracemark) { } else {
sprintf(ts_tracemark_buf, "%" PRIu64, ts_to_uint(*stamp)); uint64_t kernel_latency = post_kernel_timestamp - ts_to_uint(*stamp);
tracemark(ts_tracemark_buf); kernel_latency /= 1000u;
}
else { stats->min_kernel_latency =
_min_(kernel_latency, stats->min_kernel_latency);
uint64_t kernel_latency = stats->max_kernel_latency =
post_kernel_timestamp - ts_to_uint(*stamp); _max_(kernel_latency, stats->max_kernel_latency);
kernel_latency /= 1000u; stats->avg_kernel_latency =
(stats->max_kernel_latency * (stats->packets_received) +
stats->min_kernel_latency = _min_( kernel_latency) /
kernel_latency, stats->min_kernel_latency); (stats->packets_received + 1);
stats->max_kernel_latency = _max_(
kernel_latency, stats->max_kernel_latency); if (use_histogram) {
stats->avg_kernel_latency = if (kernel_latency > MAX_KERNEL_LATENCY)
(stats->max_kernel_latency * stats->high_kernel_latency++;
(stats->packets_received) + else
kernel_latency) / kernel_latency_hist[kernel_latency]++;
(stats->packets_received + 1); }
}
if (use_histogram) { }
if (kernel_latency > MAX_KERNEL_LATENCY) }
stats->high_kernel_latency++; }
else
kernel_latency_hist for (int i = 0; i < MAX_BUFFER_SIZE; i++) stats->data[i] = rx_buffer[i];
[kernel_latency]++;
}
}
}
}
}
for(int i = 0; i < MAX_BUFFER_SIZE; i++)
stats->data[i] = rx_buffer[i];
} }
#ifdef WITH_XDP #ifdef WITH_XDP
...@@ -222,215 +207,180 @@ static unsigned int ifindex; ...@@ -222,215 +207,180 @@ static unsigned int ifindex;
static struct xdpsock xdp_socket; static struct xdpsock xdp_socket;
static void open_xdp_socket(char *network_if) { static void open_xdp_socket(char *network_if) {
struct xsk_socket_config xsk_cfg; struct xsk_socket_config xsk_cfg;
uint32_t idx; uint32_t idx;
int ret, i; int ret, i;
/* Create XDP socket */ /* Create XDP socket */
xsk_cfg.rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS; xsk_cfg.rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
xsk_cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; xsk_cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
xsk_cfg.libbpf_flags = 0; xsk_cfg.libbpf_flags = 0;
xsk_cfg.xdp_flags = xdp_flags; xsk_cfg.xdp_flags = xdp_flags;
xsk_cfg.bind_flags = 0; xsk_cfg.bind_flags = 0;
ret = xsk_socket__create(&xdp_socket.xsk, network_if, 0, ret = xsk_socket__create(&xdp_socket.xsk, network_if, 0, xdp_socket.umem.umem,
xdp_socket.umem.umem, &xdp_socket.rx, &xdp_socket.rx, &xdp_socket.tx, &xsk_cfg);
&xdp_socket.tx, &xsk_cfg); if (ret) err("xsk_socket__create() failed");
if (ret) err("xsk_socket__create() failed");
/* Add some buffers */
/* Add some buffers */ ret = xsk_ring_prod__reserve(&xdp_socket.umem.fq,
ret = xsk_ring_prod__reserve(&xdp_socket.umem.fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS) err("xsk_ring_prod__reserve() failed");
err("xsk_ring_prod__reserve() failed");
for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++) *xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx++) = i * FRAME_SIZE;
*xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx++) =
i * FRAME_SIZE; xsk_ring_prod__submit(&xdp_socket.umem.fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
xsk_ring_prod__submit(&xdp_socket.umem.fq,
XSK_RING_PROD__DEFAULT_NUM_DESCS);
} }
/* /*
* Init XDP socket * Init XDP socket
*/ */
void init_xdp_recv(ingress_param_t * _params, ingress_stat_t *_stats) { void init_xdp_recv(ingress_param_t *_params, ingress_stat_t *_stats) {
int ret, prog_fd, xsks_map = 0; int ret, prog_fd, xsks_map = 0;
struct bpf_prog_load_attr prog_load_attr = { struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP, .prog_type = BPF_PROG_TYPE_XDP,
.file = "/home/oli/tsn-measures/packet-exchange/build/xdp_kern.o", .file = "/home/oli/tsn-measures/packet-exchange/build/xdp_kern.o",
}; };
struct xsk_umem_config cfg = { struct xsk_umem_config cfg = {
.fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
.frame_size = FRAME_SIZE, .frame_size = FRAME_SIZE,
.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM, .frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM,
.flags = 0, .flags = 0,
}; };
struct bpf_object *obj; struct bpf_object *obj;
struct bpf_map *map; struct bpf_map *map;
void *buffer = NULL; void *buffer = NULL;
params = _params; params = _params;
stats = _stats; stats = _stats;
ret = bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd); ret = bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd);
if (ret || prog_fd < 0) err("bpf_prog_load_xattr() failed"); if (ret || prog_fd < 0) err("bpf_prog_load_xattr() failed");
map = bpf_object__find_map_by_name(obj, "xsks_map"); map = bpf_object__find_map_by_name(obj, "xsks_map");
xsks_map = bpf_map__fd(map); xsks_map = bpf_map__fd(map);
if (xsks_map < 0) err("No xsks_map found!"); if (xsks_map < 0) err("No xsks_map found!");
ifindex = if_nametoindex(params->network_if); ifindex = if_nametoindex(params->network_if);
if (!ifindex) err_errno("if_nametoindex() failed"); if (!ifindex) err_errno("if_nametoindex() failed");
/* Use XDP _only_ in conjuction with driver assisted mode */ /* Use XDP _only_ in conjuction with driver assisted mode */
ret = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags); ret = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags);
if (ret) err("bpf_set_link_xdp_fd() failed"); if (ret) err("bpf_set_link_xdp_fd() failed");
/* Allocate user space memory for xdp frames */ /* Allocate user space memory for xdp frames */
ret = posix_memalign(&buffer, sysconf(_SC_PAGE_SIZE), ret =
NUM_FRAMES * FRAME_SIZE); posix_memalign(&buffer, sysconf(_SC_PAGE_SIZE), NUM_FRAMES * FRAME_SIZE);
if (ret) err_errno("posix_memalign() failed"); if (ret) err_errno("posix_memalign() failed");
ret = xsk_umem__create(&xdp_socket.umem.umem, buffer, ret = xsk_umem__create(&xdp_socket.umem.umem, buffer, NUM_FRAMES * FRAME_SIZE,
NUM_FRAMES * FRAME_SIZE, &xdp_socket.umem.fq, &xdp_socket.umem.fq, &xdp_socket.umem.cq, &cfg);
&xdp_socket.umem.cq, &cfg); if (ret) err("xsk_umem__create() failed");
if (ret) err("xsk_umem__create() failed"); xdp_socket.umem.buffer = buffer;
xdp_socket.umem.buffer = buffer;
/* Open and bind socket */
/* Open and bind socket */ open_xdp_socket(params->network_if);
open_xdp_socket(params->network_if);
} }
void setup_poll_fd(void) { void setup_poll_fd(void) {
fds[0].fd = xsk_socket__fd(xdp_socket.xsk); fds[0].fd = xsk_socket__fd(xdp_socket.xsk);
fds[0].events = POLLIN; fds[0].events = POLLIN;
} }
static int received; static int received;
static uint32_t idx_rx = 0, idx; static uint32_t idx_rx = 0, idx;
static void poll_wakeup(struct timespec ts, int margin) { static void parse_raw_packet(uint64_t addr, size_t len) {
int ret; char *packet;
struct timespec ts_prev, current; struct ethhdr *eth;
struct iphdr *ip;
ts_prev = ts; struct udphdr *udp;
substract_ns(&ts_prev, margin * 1000); size_t min_len = sizeof(*eth) + sizeof(*ip) + sizeof(*udp);
ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts_prev, NULL); if (len <= min_len) {
if (ret) { stats->xdp_data = NULL;
fprintf(stderr, "clock_nanosleep returned error: %d, aborting...\n", ret); return;
exit(EXIT_FAILURE);
} }
do { packet = xsk_umem__get_data(xdp_socket.umem.buffer, addr);
clock_gettime(CLOCK_REALTIME, &current);
} while(calcdiff_ns_signed(ts, current) > 1000);
}
static void parse_raw_packet(uint64_t addr, size_t len)
{
char *packet;
struct ethhdr *eth;
struct iphdr *ip;
struct udphdr *udp;
size_t min_len = sizeof(*eth) + sizeof(*ip) + sizeof(*udp);
if (len <= min_len) {
stats->xdp_data = NULL;
return;
}
packet = xsk_umem__get_data(xdp_socket.umem.buffer, addr);
eth = (struct ethhdr *)packet; eth = (struct ethhdr *)packet;
ip = (struct iphdr *)(packet + sizeof(*eth)); ip = (struct iphdr *)(packet + sizeof(*eth));
udp = (struct udphdr *)(packet + sizeof(*eth) + sizeof(*ip)); udp = (struct udphdr *)(packet + sizeof(*eth) + sizeof(*ip));
stats->xdp_data = packet + sizeof(*eth) + sizeof(*ip) + sizeof(*udp); stats->xdp_data = packet + sizeof(*eth) + sizeof(*ip) + sizeof(*udp);
} }
/* /*
* Receive XDP socket * Receive XDP socket
*/ */
int recv_xdp_packet(struct timespec next) { int recv_xdp_packet(struct timespec next) {
int ret; int ret;
uint64_t addr; uint64_t addr;
uint32_t len; uint32_t len;
struct timespec next_pre, current; struct timespec next_pre, current;
int k = 0; int k = 0;
if (params->xdp_polling_mode == 0) { ret = poll(fds, 1, -1);
ret = poll(fds, 1, -1);
if (ret != 1)
if (ret == 0) { error(EXIT_FAILURE, errno, "poll failed");
return -1;
} else if (ret < 0)
error(EXIT_FAILURE, errno, "poll failed");
received = xsk_ring_cons__peek(&xdp_socket.rx, 1, &idx_rx);
} else {
next_pre = next;
substract_ns(&next_pre, 120 * 1000);
ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next_pre, NULL);
if (ret) {
fprintf(stderr, "clock_nanosleep returned error: %d, aborting...\n", ret);
exit(EXIT_FAILURE);
}
do { received = xsk_ring_cons__peek(&xdp_socket.rx, 1, &idx_rx);
received = xsk_ring_cons__peek(&xdp_socket.rx, 1, &idx_rx);
} while(!received);
}
if (received != 1) if (received != 1)
error(EXIT_FAILURE, errno, "Received %d packets", received); error(EXIT_FAILURE, errno, "Received %d packets", received);
/* Get the packet */ /* Get the packet */
addr = xsk_ring_cons__rx_desc(&xdp_socket.rx, idx_rx)->addr; addr = xsk_ring_cons__rx_desc(&xdp_socket.rx, idx_rx)->addr;
len = xsk_ring_cons__rx_desc(&xdp_socket.rx, idx_rx)->len; len = xsk_ring_cons__rx_desc(&xdp_socket.rx, idx_rx)->len;
/* Parse it */ /* Parse it */
parse_raw_packet(xsk_umem__add_offset_to_addr(addr), len); parse_raw_packet(xsk_umem__add_offset_to_addr(addr), len);
return 0; return 0;
} }
void recv_xdp_cleanup(void) { void recv_xdp_cleanup(void) {
uint64_t addr; uint64_t addr;
int ret; int ret;
/* Cleanup */ /* Cleanup */
xsk_ring_cons__release(&xdp_socket.rx, received); xsk_ring_cons__release(&xdp_socket.rx, received);
/* Add that particular buffer back to the fill queue */ /* Add that particular buffer back to the fill queue */
if (xsk_prod_nb_free(&xdp_socket.umem.fq, received)) { if (xsk_prod_nb_free(&xdp_socket.umem.fq, received)) {
ret = ret = xsk_ring_prod__reserve(&xdp_socket.umem.fq, received, &idx);
xsk_ring_prod__reserve(&xdp_socket.umem.fq, received, &idx);
if (ret != received) err("xsk_ring_prod__reserve() failed"); if (ret != received) err("xsk_ring_prod__reserve() failed");
*xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx) = *xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx) =
xsk_umem__extract_addr(addr); xsk_umem__extract_addr(addr);
xsk_ring_prod__submit(&xdp_socket.umem.fq, received); xsk_ring_prod__submit(&xdp_socket.umem.fq, received);
} }
} }
void close_xdp_socket(void) { void close_xdp_socket(void) {
xsk_socket__delete(xdp_socket.xsk); xsk_socket__delete(xdp_socket.xsk);
xsk_umem__delete(xdp_socket.umem.umem); xsk_umem__delete(xdp_socket.umem.umem);
bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
} }
#else #else
void init_xdp_recv(ingress_param_t * _params, ingress_stat_t *_stats) { (void) _params; (void) _stats; } void init_xdp_recv(ingress_param_t *_params, ingress_stat_t *_stats) {
(void)_params;
(void)_stats;
}
void setup_poll_fd(void) {} void setup_poll_fd(void) {}
void close_xdp_socket(void) {} void close_xdp_socket(void) {}
int recv_xdp_packet(struct timespec next) { (void) next; return 0; } int recv_xdp_packet(struct timespec next) {
(void)next;
return 0;
}
void recv_xdp_cleanup(void) {} void recv_xdp_cleanup(void) {}
#endif #endif
...@@ -440,53 +390,50 @@ void recv_xdp_cleanup(void) {} ...@@ -440,53 +390,50 @@ void recv_xdp_cleanup(void) {}
* Code from scheduled_tx_tools * Code from scheduled_tx_tools
*/ */
static int process_socket_error_queue(void) { static int process_socket_error_queue(void) {
uint8_t msg_control[CMSG_SPACE(sizeof(struct sock_extended_err))]; uint8_t msg_control[CMSG_SPACE(sizeof(struct sock_extended_err))];
unsigned char err_buffer[256]; unsigned char err_buffer[256];
struct sock_extended_err *serr; struct sock_extended_err *serr;
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
__u64 tstamp = 0; __u64 tstamp = 0;
struct iovec iov = {.iov_base = err_buffer, struct iovec iov = {.iov_base = err_buffer, .iov_len = sizeof(err_buffer)};
.iov_len = sizeof(err_buffer)}; struct msghdr msg = {.msg_iov = &iov,
struct msghdr msg = {.msg_iov = &iov, .msg_iovlen = 1,
.msg_iovlen = 1, .msg_control = msg_control,
.msg_control = msg_control, .msg_controllen = sizeof(msg_control)};
.msg_controllen = sizeof(msg_control)};
if (recvmsg(sock_fd, &msg, MSG_ERRQUEUE) == -1) {
if (recvmsg(sock_fd, &msg, MSG_ERRQUEUE) == -1) { fprintf(stderr, "recvmsg failed");
fprintf(stderr, "recvmsg failed"); return -1;
return -1; }
}
cmsg = CMSG_FIRSTHDR(&msg);
cmsg = CMSG_FIRSTHDR(&msg); while (cmsg != NULL) {
while (cmsg != NULL) { serr = (void *)CMSG_DATA(cmsg);
serr = (void *)CMSG_DATA(cmsg); if (serr->ee_origin == SO_EE_ORIGIN_TXTIME) {
if (serr->ee_origin == SO_EE_ORIGIN_TXTIME) { tstamp = ((__u64)serr->ee_data << 32) + serr->ee_info;
tstamp = ((__u64)serr->ee_data << 32) + serr->ee_info;
switch (serr->ee_code) {
switch (serr->ee_code) { case SO_EE_CODE_TXTIME_INVALID_PARAM:
case SO_EE_CODE_TXTIME_INVALID_PARAM: fprintf(stderr,
fprintf( "packet with tstamp %llu dropped "
stderr, "due to invalid params\n",
"packet with tstamp %llu dropped " tstamp);
"due to invalid params\n", return 0;
tstamp); case SO_EE_CODE_TXTIME_MISSED:
return 0; fprintf(stderr,
case SO_EE_CODE_TXTIME_MISSED: "packet with tstamp %llu dropped "
fprintf( "due to missed deadline\n",
stderr, tstamp);
"packet with tstamp %llu dropped " return 0;
"due to missed deadline\n", default:
tstamp); return -1;
return 0; }
default: }
return -1;
} cmsg = CMSG_NXTHDR(&msg, cmsg);
} }
cmsg = CMSG_NXTHDR(&msg, cmsg); return 0;
}
return 0;
} }
#endif #endif
...@@ -8,7 +8,6 @@ typedef struct ingress_param { ...@@ -8,7 +8,6 @@ typedef struct ingress_param {
int use_timestamps; int use_timestamps;
int enable_ts_tracemark; int enable_ts_tracemark;
int xdp_polling_mode;
uint64_t interval; uint64_t interval;
size_t tx_buffer_len; size_t tx_buffer_len;
......
...@@ -48,9 +48,6 @@ typedef struct thread_param { ...@@ -48,9 +48,6 @@ typedef struct thread_param {
uint64_t start_ts; uint64_t start_ts;
int poll;
int poll_margin;
} thread_param_t; } thread_param_t;
typedef struct main_params { typedef struct main_params {
...@@ -93,7 +90,7 @@ static char ts_tracemark_buf[64]; ...@@ -93,7 +90,7 @@ static char ts_tracemark_buf[64];
static void help(char *argv[]) { static void help(char *argv[]) {
printf( printf(
"Usage: %s [-f IF -a CPU -p PRIO -i USEC -r USEC] [-b CLIENT_IP] [-d " "Usage: %s [-f IF -a CPU -p PRIO -i USEC -r USEC] [-b CLIENT_IP] [-d "
"BUF_LEN -cgtv] [-T LATENCY_THRESHOLD -G] [-x POLL_MODE -X]\n\n" "BUF_LEN -cgtv] [-T LATENCY_THRESHOLD -G] [-xX]\n\n"
" -h Show help\n" " -h Show help\n"
" -f IF Set the network interface to be used\n" " -f IF Set the network interface to be used\n"
" -a CPU Pin the real time thread to CPU\n" " -a CPU Pin the real time thread to CPU\n"
...@@ -103,13 +100,11 @@ static void help(char *argv[]) { ...@@ -103,13 +100,11 @@ static void help(char *argv[]) {
" -d BUF_LEN Set the length of tx buffer\n" " -d BUF_LEN Set the length of tx buffer\n"
" -c Receive timestamp and emit signal\n" " -c Receive timestamp and emit signal\n"
" -s NS Common start time reference\n" " -s NS Common start time reference\n"
" -P USEC Do polling to wakeup signal thread with specified margin\n"
" -C Receive timestamp and print difference with current time\n" " -C Receive timestamp and print difference with current time\n"
" -b CLIENT_IP Server side RTT\n" " -b CLIENT_IP Server side RTT\n"
" -g Print histograms to sdtout on exit\n" " -g Print histograms to sdtout on exit\n"
" -t Enable timestamps\n" " -t Enable timestamps\n"
" -x POLL_MODE Use AF_XDP sockets\n" " -x Use AF_XDP sockets\n"
" POLL_MODE: 0 for polling, 1 for combination of both\n"
" -X Trace during XDP packet reception\n" " -X Trace during XDP packet reception\n"
" -T THRESHOLD Enable tracing until THRESHOLD is reached\n" " -T THRESHOLD Enable tracing until THRESHOLD is reached\n"
" -M Send tracemark when packet is received\n" " -M Send tracemark when packet is received\n"
...@@ -119,30 +114,13 @@ static void help(char *argv[]) { ...@@ -119,30 +114,13 @@ static void help(char *argv[]) {
argv[0]); argv[0]);
} }
static void poll_wakeup(struct timespec ts, int margin) {
int ret;
struct timespec ts_prev, current;
ts_prev = ts;
substract_ns(&ts_prev, margin * 1000);
ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts_prev, NULL);
if (ret) {
fprintf(stderr, "clock_nanosleep returned error: %d, aborting...\n", ret);
exit(EXIT_FAILURE);
}
do {
clock_gettime(CLOCK_REALTIME, &current);
} while(calcdiff_ns_signed(ts, current) > 1000);
}
static void *emit_signal_thread(void *p) { static void *emit_signal_thread(void *p) {
(void)p; (void)p;
cpu_set_t mask; cpu_set_t mask;
struct timespec current; struct timespec current;
struct timespec previous_emit, previous_ts; struct timespec previous_emit, previous_ts;
int64_t emit_diff, ts_diff; int64_t emit_diff, ts_diff;
int ret;
// Set thread CPU affinity // Set thread CPU affinity
if (thread_params.affinity_cpu) { if (thread_params.affinity_cpu) {
...@@ -157,15 +135,18 @@ static void *emit_signal_thread(void *p) { ...@@ -157,15 +135,18 @@ static void *emit_signal_thread(void *p) {
for (int i = 0;;i++) { for (int i = 0;;i++) {
pthread_cond_wait(&emit_signal_ts_received, &emit_signal_mutex); pthread_cond_wait(&emit_signal_ts_received, &emit_signal_mutex);
clock_gettime(CLOCK_REALTIME, &current);
poll_wakeup(emit_signal_next, thread_params.poll_margin); ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &emit_signal_next, NULL);
if (ret) {
fprintf(stderr, "clock_nanosleep returned error: %d, aborting...\n", ret);
exit(EXIT_FAILURE);
}
toggle_gpio(); toggle_gpio();
clock_gettime(CLOCK_REALTIME, &current);
// Check if something went wrong // Check if something went wrong
if(i > 0) { if(i > 0) {
clock_gettime(CLOCK_REALTIME, &current);
emit_diff = calcdiff_ns_signed(current, previous_emit); emit_diff = calcdiff_ns_signed(current, previous_emit);
ts_diff = calcdiff_ns_signed(emit_signal_next, previous_ts); ts_diff = calcdiff_ns_signed(emit_signal_next, previous_ts);
if((emit_diff < ((int64_t)thread_params.interval) - ERROR_MARGIN_NS) || if((emit_diff < ((int64_t)thread_params.interval) - ERROR_MARGIN_NS) ||
...@@ -397,8 +378,6 @@ int main(int argc, char *argv[]) { ...@@ -397,8 +378,6 @@ int main(int argc, char *argv[]) {
thread_params.affinity_cpu = 0; thread_params.affinity_cpu = 0;
thread_params.enable_diff_ts = 0; thread_params.enable_diff_ts = 0;
thread_params.enable_receive_tracemark = 0; thread_params.enable_receive_tracemark = 0;
thread_params.poll = 0;
thread_params.poll_margin = 75;
thread_params.start_ts = 0; thread_params.start_ts = 0;
main_params.refresh_rate = 50000; main_params.refresh_rate = 50000;
main_params.verbose = 0; main_params.verbose = 0;
...@@ -557,7 +536,7 @@ static void process_options(int argc, char *argv[]) { ...@@ -557,7 +536,7 @@ static void process_options(int argc, char *argv[]) {
int network_if_specified = 0; int network_if_specified = 0;
for (;;) { for (;;) {
int c = getopt(argc, argv, "a:b:cCs:d:f:ghi:p:r:tvx:XT:GMSP:"); int c = getopt(argc, argv, "a:b:cCs:d:f:ghi:p:r:tvxXT:GMS");
if (c == -1) break; if (c == -1) break;
...@@ -613,7 +592,6 @@ static void process_options(int argc, char *argv[]) { ...@@ -613,7 +592,6 @@ static void process_options(int argc, char *argv[]) {
break; break;
case 'x': case 'x':
tsn_task = XDP_TASK; tsn_task = XDP_TASK;
ingress_params.xdp_polling_mode = atoi(optarg);
break; break;
case 'X': case 'X':
main_params.enable_xdp_tracing = 1; main_params.enable_xdp_tracing = 1;
...@@ -628,10 +606,6 @@ static void process_options(int argc, char *argv[]) { ...@@ -628,10 +606,6 @@ static void process_options(int argc, char *argv[]) {
case 'S': case 'S':
ingress_params.enable_ts_tracemark = 1; ingress_params.enable_ts_tracemark = 1;
break; break;
case 'P':
thread_params.poll = 1;
thread_params.poll_margin = atoi(optarg);
break;
} }
} }
......
...@@ -10,18 +10,14 @@ usage() { ...@@ -10,18 +10,14 @@ usage() {
cat << ENDUSAGE cat << ENDUSAGE
Usage: $0 [-h] [-I if] [SERVER] | TCPDUMP [TRACE_OPTS] Usage: $0 [-h] [-I if] [SERVER] | TCPDUMP [TRACE_OPTS]
-h Show help -h Show help
SERVER: -bct ((-x | -X) POLL) -g INTERVAL -a CPU SERVER: -bctX -g INTERVAL -a CPU
Options passed to the C server program (everything here is optional) Options passed to the C server program (everything here is optional)
-b Send back packets for round trip measurements -b Send back packets for round trip measurements
-c USEC Emit a signal on GPIO at the timestamp given in packet, specify interval -c USEC Emit a signal on GPIO at the timestamp given in packet, specify interval
(to be used with -c option in client program) (to be used with -c option in client program)
-O USEC Do polling to wakeup signal thread with specified margin
-C USEC Measure difference between current time and timestamp sent in tx data -C USEC Measure difference between current time and timestamp sent in tx data
-t Use SO_TIMESTAMPS to see how much time packet spent in kernel -t Use SO_TIMESTAMPS to see how much time packet spent in kernel
-x POLL Use XDP sockets, with a global libbpf installation -X Use XDP sockets, with libbpf located in \$HOME/libbpf folder
-X POLL Use XDP sockets, with libbpf located in \$HOME/libbpf folder
POLL: Polling mode used in server program, 0 to poll with poll function,
1 to do active polling
-s NS Specify a CLOCK_REALTIME timestamp at which client should start -s NS Specify a CLOCK_REALTIME timestamp at which client should start
(to be used with PTP) (interval needs to be specified with -j) (to be used with PTP) (interval needs to be specified with -j)
-j USEC Specify interval (used with -s) -j USEC Specify interval (used with -s)
...@@ -60,7 +56,7 @@ tracecmd_events="-e irq -e sched -e net -e napi" ...@@ -60,7 +56,7 @@ tracecmd_events="-e irq -e sched -e net -e napi"
tracecmd_opts="" tracecmd_opts=""
cpu=1 cpu=1
while getopts "j:a:b:c:C:htx:X:s:d:i:g:I:T:E:P:B:MSQO:" opt; do while getopts "j:a:b:c:C:htx:Xs:d:i:g:I:T:E:P:B:MSQ" opt; do
case "${opt}" in case "${opt}" in
h ) h )
usage usage
...@@ -78,9 +74,6 @@ while getopts "j:a:b:c:C:htx:X:s:d:i:g:I:T:E:P:B:MSQO:" opt; do ...@@ -78,9 +74,6 @@ while getopts "j:a:b:c:C:htx:X:s:d:i:g:I:T:E:P:B:MSQO:" opt; do
c ) c )
server_options+=" -c -i ${OPTARG}" server_options+=" -c -i ${OPTARG}"
;; ;;
O )
server_options+=" -P ${OPTARG} "
;;
C ) C )
server_options+=" -C -i ${OPTARG}" server_options+=" -C -i ${OPTARG}"
;; ;;
...@@ -107,7 +100,7 @@ while getopts "j:a:b:c:C:htx:X:s:d:i:g:I:T:E:P:B:MSQO:" opt; do ...@@ -107,7 +100,7 @@ while getopts "j:a:b:c:C:htx:X:s:d:i:g:I:T:E:P:B:MSQO:" opt; do
interface="${OPTARG}" interface="${OPTARG}"
;; ;;
X ) X )
server_options+=" -x ${OPTARG}" server_options+=" -x "
make_opts=" -e WITH_GIT_XDP=1" make_opts=" -e WITH_GIT_XDP=1"
;; ;;
s ) s )
......
...@@ -4,13 +4,12 @@ script_dir=$(dirname $(realpath $0)) ...@@ -4,13 +4,12 @@ script_dir=$(dirname $(realpath $0))
usage() { usage() {
cat << ENDUSAGE cat << ENDUSAGE
Usage: $0 [-h] [-i USEC -c USEC -t MSEC] [-T] BOARD1_HOSTNAME BOARD2_HOSTNAME Usage: $0 [-h] [-i USEC -c USEC -t MSEC] [-TX] BOARD1_HOSTNAME BOARD2_HOSTNAME
-h Show help -h Show help
-i USEC Specify which interval to use in client -i USEC Specify which interval to use in client
-c USEC Specify which offset to use for the timestamp in the packet -c USEC Specify which offset to use for the timestamp in the packet
-t MSEC Set the start timestamp offset -t MSEC Set the start timestamp offset
-P USEC Do polling to wakeup signal thread with specified margin -X Use XDP
-X POLL_MODE Use XDP with specified poll mode
-T Enable tracing on the boards -T Enable tracing on the boards
BOARD_HOSTNAME Uses /etc/hosts to find the IP address associated to the hostname BOARD_HOSTNAME Uses /etc/hosts to find the IP address associated to the hostname
ENDUSAGE ENDUSAGE
...@@ -23,7 +22,7 @@ interval=1000 ...@@ -23,7 +22,7 @@ interval=1000
server_opts="" server_opts=""
ts_offset=2000 ts_offset=2000
while getopts "hc:i:o:rt:TP:X:" opt; do while getopts "hc:i:o:rt:TX" opt; do
case "${opt}" in case "${opt}" in
h ) h )
usage usage
...@@ -40,11 +39,8 @@ while getopts "hc:i:o:rt:TP:X:" opt; do ...@@ -40,11 +39,8 @@ while getopts "hc:i:o:rt:TP:X:" opt; do
T ) T )
enable_tracing=1 enable_tracing=1
;; ;;
P )
server_opts+=" -P ${OPTARG} "
;;
X ) X )
server_opts+=" -X ${OPTARG} " server_opts+=" -X "
;; ;;
* ) * )
usage usage
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment