#define BLOCK_NR 2
#define FRAME_NR (BLOCK_NR*(BLOCK_SIZE/FRAME_SIZE))
+#define MMSG_MAX 64
+
#define STRINGIFY(val) #val
#define TOSTRING(val) STRINGIFY(val)
#define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
char *devin = "can0";
char *devout = "can1";
enum { IN_READ, IN_RECVMMSG, IN_MMAP, IN_MMAPBUSY } in_method = IN_READ;
-enum { WRITE, OUT_MMAP } out_method = WRITE;
+enum { WRITE, OUT_MMAP, OUT_SENDMMSG } out_method = WRITE;
bool quiet = false;
int busy_poll_us = 0;
bool nonblocking = false;
struct in_ctx {
int s;
+ enum in2out (*in_fn)(struct in_ctx *ctx, struct can_frame *cf);
+ /* mmap */
void *ptr;
int hdrlen;
int current;
- enum in2out (*in_fn)(struct in_ctx *ctx, struct can_frame *cf);
+ /* mmsg */
+ int received;
+ struct mmsghdr msgs[MMSG_MAX];
+ struct iovec iovecs[MMSG_MAX];
+ char bufs[MMSG_MAX][sizeof(struct can_frame)];
};
struct out_ctx {
int s;
enum in2out from_in;
+ int (*out_fn)(struct out_ctx *ctx, struct can_frame *cf);
+ /* mmap */
void *ptr;
int hdrlen;
int current;
- int (*out_fn)(struct out_ctx *ctx, struct can_frame *cf);
+ /* mmsg */
+ int stored;
+ struct mmsghdr msgs[MMSG_MAX];
+ struct iovec iovecs[MMSG_MAX];
+ char bufs[MMSG_MAX][sizeof(struct can_frame)];
};
struct stats {
s = CHECK(socket(PF_CAN, SOCK_RAW, CAN_RAW));
+ int rcvbuf = 25000; /* Limit rcvbuf to not have so big queueing latencies */
+ CHECK(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)));
+
if (nonblocking) {
int flags = CHECK(fcntl(s, F_GETFL, 0));
CHECK(fcntl(s, F_SETFL, flags | O_NONBLOCK));
ctx->in_fn = in_read;
}
+enum in2out in_recvmmsg(struct in_ctx *ctx, struct can_frame *cf)
+{
+ int ret;
+
+ if (ctx->current >= ctx->received) {
+ ret = CHECK(recvmmsg(ctx->s, ctx->msgs, MMSG_MAX, MSG_WAITFORONE, NULL));
+ if (nonblocking && ret == -1 && errno == EAGAIN)
+ return NOP;
+ ctx->received = ret;
+ ctx->current = 0;
+ }
+
+ memcpy(cf, ctx->bufs[ctx->current], sizeof(struct can_frame));
+ ctx->current++;
+
+ return (ctx->current < ctx->received) ? STORE_ONLY : SEND;
+}
+
+void init_recvmmg(struct in_ctx *ctx)
+{
+ int i;
+
+ init_read(ctx);
+ ctx->in_fn = in_recvmmsg;
+ ctx->current = 0;
+ memset(ctx->msgs, 0, sizeof(ctx->msgs));
+ memset(ctx->iovecs, 0, sizeof(ctx->iovecs));
+ for (i = 0; i < MMSG_MAX; i++) {
+ ctx->iovecs[i].iov_base = ctx->bufs[i];
+ ctx->iovecs[i].iov_len = sizeof(struct can_frame);
+ ctx->msgs[i].msg_hdr.msg_iov = &ctx->iovecs[i];
+ ctx->msgs[i].msg_hdr.msg_iovlen = 1;
+ }
+}
+
enum in2out in_packet_rx(struct in_ctx *ctx, struct can_frame *cf)
{
volatile struct tpacket2_hdr *hdr = ctx->ptr + ctx->current*FRAME_SIZE;
ctx->out_fn = out_write;
}
+int out_sendmmsg(struct out_ctx *ctx, struct can_frame *cf)
+{
+ if (ctx->from_in == NOP)
+ return 0;
+
+ memcpy(ctx->bufs[ctx->current++], cf, sizeof(*cf));
+
+ if (ctx->from_in == SEND ||
+ ctx->current >= MMSG_MAX) {
+ int ret, i;
+ for (i = 0; i < ctx->current; i += ret)
+ ret = CHECK(sendmmsg(ctx->s, &ctx->msgs[i], ctx->current - i, 0));
+ ctx->current = 0;
+ }
+ return 0;
+}
+
+void init_sendmmsg(struct out_ctx *ctx)
+{
+ int i;
+
+ init_write(ctx);
+ ctx->out_fn = out_sendmmsg;
+ ctx->current = 0;
+ ctx->stored = 0;
+
+ memset(ctx->msgs, 0, sizeof(ctx->msgs));
+ memset(ctx->iovecs, 0, sizeof(ctx->iovecs));
+ for (i = 0; i < MMSG_MAX; i++) {
+ ctx->iovecs[i].iov_base = &ctx->bufs[i];
+ ctx->iovecs[i].iov_len = sizeof(struct can_frame);
+ ctx->msgs[i].msg_hdr.msg_iov = &ctx->iovecs[i];
+ ctx->msgs[i].msg_hdr.msg_iovlen = 1;
+ }
+}
+
int out_packet_tx(struct out_ctx *ctx, struct can_frame *cf)
{
volatile struct tpacket2_hdr *hdr = ctx->ptr + ctx->current*FRAME_SIZE;
case IN_READ:
init_read(in);
break;
+ case IN_RECVMMSG:
+ init_recvmmg(in);
+ break;
case IN_MMAP:
case IN_MMAPBUSY:
init_packet_rx(in);
memset(out, 0, sizeof(*out));
switch (out_method) {
case WRITE: init_write(out); break;
+ case OUT_SENDMMSG: init_sendmmsg(out); break;
case OUT_MMAP: init_packet_tx(out); break;
default:
fprintf(stderr, "Unknown \"out method\" %d\n", out_method);
in_method = IN_MMAP;
else if (strcmp(optarg, "mmapbusy") == 0)
in_method = IN_MMAPBUSY;
+ else if (strcmp(optarg, "mmsg") == 0)
+ in_method = IN_RECVMMSG;
else {
fprintf(stderr, "Unsuported RX method: %s\n", optarg);
exit(1);
out_method = WRITE;
else if (strcmp(optarg, "mmap") == 0)
out_method = OUT_MMAP;
+ else if (strcmp(optarg, "mmsg") == 0)
+ out_method = OUT_SENDMMSG;
else {
fprintf(stderr, "Unsuported TX method: %s\n", optarg);
exit(1);