socsvn commit: r337265 - soc2018/sduo/netmap_utils
sduo at FreeBSD.org
sduo at FreeBSD.org
Wed Jun 27 16:17:27 UTC 2018
Author: sduo
Date: Wed Jun 27 16:17:21 2018
New Revision: 337265
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=337265
Log:
functional.c can request netmap interface file descriptors from fd_server.
Added:
soc2018/sduo/netmap_utils/functional.c
Modified:
soc2018/sduo/netmap_utils/fd_server.c
soc2018/sduo/netmap_utils/fd_server.h
Modified: soc2018/sduo/netmap_utils/fd_server.c
==============================================================================
--- soc2018/sduo/netmap_utils/fd_server.c Wed Jun 27 15:52:47 2018 (r337264)
+++ soc2018/sduo/netmap_utils/fd_server.c Wed Jun 27 16:17:21 2018 (r337265)
@@ -1,5 +1,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <net/if.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -10,17 +12,22 @@
#include <sys/un.h>
#include <sys/wait.h>
#include <syslog.h>
-#include <unistd.h>
+
+#include <net/netmap.h>
+#define NETMAP_WITH_LIBS
+#include <net/netmap_user.h>
#include "fd_server.h"
struct nmd_entry {
+ char if_name[NETMAP_REQ_IFNAMSIZ];
struct nm_desc *nmd;
uint8_t is_in_use;
uint8_t is_open;
};
-#define SOCKET_NAME "/tmp/my_unix_socket"
+#define printf(format, ...) syslog(LOG_NOTICE, format, ##__VA_ARGS__)
+
#define MAX_OPEN_IF 128
struct nmd_entry entries[MAX_OPEN_IF];
int num_entries = 0;
@@ -29,13 +36,13 @@
print_request(struct fd_request *req)
{
- syslog(LOG_NOTICE, "d action: %s, if_name: %s\n",
+ printf("action: %s, if_name: '%s'\n",
req->action == FD_GET
- ? "FD_GET"
- : req->action == FD_RELEASE
- ? "FD_RELEASE"
- : req->action == FD_CLOSE ? "FD_CLOSE"
- : "FD_STOP",
+ ? "FD_GET"
+ : req->action == FD_RELEASE
+ ? "FD_RELEASE"
+ : req->action == FD_CLOSE ? "FD_CLOSE"
+ : "FD_STOP",
req->if_name);
}
@@ -44,32 +51,34 @@
{
int i;
+ // printf("searching %s\n", if_name);
for (i = 0; i < num_entries; ++i) {
struct nmd_entry *entry = &entries[i];
- struct nm_desc *nmd = entry->nmd;
+
+ // printf("i=%d, is_open=%d, is_in_use=%d, if_name=%s\n",
+ // i, entry->is_open, entry->is_in_use, entry->if_name);
if (entry->is_open == 0) {
continue;
}
- if (strcmp(nmd->req.nr_name, if_name) == 0) {
+ if (strncmp(entry->if_name, if_name, IFNAMSIZ) == 0) {
+ // printf("finished searching with a match\n");
return entry;
}
}
+ // printf("finished searching without a match\n");
return NULL;
}
struct nmd_entry *
-get_free_des(int *ret)
+get_free_des(void)
{
-
if (num_entries == MAX_OPEN_IF) {
- *ret = -1;
return NULL;
}
- *ret = 0;
return &entries[num_entries++];
}
@@ -77,12 +86,11 @@
get_fd(const char *if_name, struct fd_response *res)
{
struct nmd_entry *entry;
- int ret;
entry = search_des(if_name);
if (entry != NULL) {
if (entry->is_in_use == 1) {
- syslog(LOG_NOTICE, "if_name %s is in use\n", if_name);
+ printf("if_name %s is in use\n", if_name);
res->result = EBUSY;
return -1;
}
@@ -90,20 +98,21 @@
return entry->nmd->fd;
}
- entry = get_free_des(&ret);
- if (ret == -1) {
- syslog(LOG_NOTICE, "Out of memory\n");
+ entry = get_free_des();
+ if (entry == NULL) {
+ printf("Out of memory\n");
res->result = ENOMEM;
return -1;
}
entry->nmd = nm_open(if_name, NULL, 0, NULL);
if (entry->nmd == NULL) {
- syslog(LOG_NOTICE, "Failed to nm_open(%s) with error %d\n",
- if_name, errno);
+ printf("Failed to nm_open(%s) with error %d\n", if_name, errno);
res->result = errno;
return -1;
}
+ strncpy(entry->if_name, if_name, sizeof(entry->if_name));
+ entry->if_name[sizeof(entry->if_name) - 1] = '\0';
memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
entry->is_in_use = 1;
@@ -118,7 +127,7 @@
entry = search_des(if_name);
if (entry == NULL) {
- syslog(LOG_NOTICE, "if_name %s isn't open\n", if_name);
+ printf("if_name %s isn't open\n", if_name);
res->result = ENOENT;
return;
}
@@ -132,7 +141,7 @@
struct nmd_entry *entry;
int ret;
- if (if_name == NULL || strnlen(if_name, IFNAMSIZ) == 0) {
+ if (if_name == NULL || strnlen(if_name, NETMAP_REQ_IFNAMSIZ) == 0) {
res->result = EINVAL;
return;
}
@@ -140,14 +149,14 @@
entry = search_des(if_name);
if (entry == NULL) {
res->result = ENOENT;
- syslog(LOG_NOTICE, "if_name %s hasn't been opened\n", if_name);
+ printf("if_name %s hasn't been opened\n", if_name);
return;
}
- ret = nm_close(entry->nmd);
+ ret = nm_close(entry->nmd);
res->result = ret;
if (ret != 0) {
- syslog(LOG_NOTICE, "error while close interface %s\n", if_name);
+ printf("error while close interface %s\n", if_name);
return;
}
entry->is_in_use = 0;
@@ -164,10 +173,10 @@
struct cmsghdr *cmsg;
struct iovec iov[1];
struct msghdr msg;
+ int ret;
iov[0].iov_base = buf;
iov[0].iov_len = buf_size;
-
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
@@ -176,17 +185,18 @@
/* We need the ancillary data only when we're sending a file
* descriptor, and a file descriptor cannot be negative.
*/
- msg.msg_control = ancillary.buf;
- msg.msg_controllen = sizeof(ancillary.buf);
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ printf("sending a file descriptor\n");
+ msg.msg_control = ancillary.buf;
+ msg.msg_controllen = sizeof(ancillary.buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*(int *)CMSG_DATA(cmsg) = fd;
}
- return sendmsg(socket, &msg, 0);
+ ret = sendmsg(socket, &msg, 0);
+ return ret;
}
int
@@ -194,15 +204,14 @@
{
struct fd_response res;
struct fd_request req;
- int amount;
int fd = -1;
+ int amount;
+ int ret;
- memset(&res, 0, sizeof(res));
memset(&req, 0, sizeof(req));
-
amount = recv(socket, &req, sizeof(struct fd_request), 0);
if (amount == -1) {
- syslog(LOG_NOTICE, "error during recv()");
+ printf("error while receiving the request\n");
return -1;
}
@@ -219,14 +228,18 @@
close_fd(req.if_name, &res);
return 0;
case FD_STOP:
- syslog(LOG_NOTICE, "shutting down");
+ printf("shutting down\n");
exit(EXIT_SUCCESS);
break;
default:
res.result = EOPNOTSUPP;
}
- return send_fd(socket, fd, &res, sizeof(struct fd_response));
+ ret = send_fd(socket, fd, &res, sizeof(struct fd_response));
+ if (ret == -1) {
+ printf("error while sending the reponse\n");
+ }
+ return ret;
}
void
@@ -236,42 +249,48 @@
int socket_fd;
int ret;
+ printf("starting up.\n");
+ if (unlink(SOCKET_NAME) == -1 && errno != ENOENT) {
+ printf("error %d during unlink()", errno);
+ exit(EXIT_FAILURE);
+ }
socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (socket_fd == -1) {
- syslog(LOG_NOTICE, "error during socket()");
+ printf("error during socket()\n");
exit(EXIT_FAILURE);
}
- unlink(SOCKET_NAME);
memset(&name, 0, sizeof(struct sockaddr_un));
name.sun_family = AF_UNIX;
strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
ret = bind(socket_fd, (const struct sockaddr *)&name,
- sizeof(struct sockaddr_un));
+ sizeof(struct sockaddr_un));
if (ret == -1) {
- syslog(LOG_NOTICE, "error during bind()");
+ printf("error during bind()\n");
exit(EXIT_FAILURE);
}
ret = listen(socket_fd, 2);
if (ret == -1) {
- syslog(LOG_NOTICE, "error during listen()");
+ printf("error during listen()");
exit(EXIT_FAILURE);
}
+ printf("listening\n");
for (;;) {
int conn_fd;
int ret;
conn_fd = accept(socket_fd, NULL, NULL);
if (conn_fd == -1) {
- syslog(LOG_NOTICE,
- "error during accept(), shutting down");
+ printf("error during accept(), shutting down\n");
exit(EXIT_FAILURE);
}
- syslog(LOG_NOTICE, "handling a request");
ret = handle_request(conn_fd);
+ if (ret == -1) {
+ printf("error while handling a request\n");
+ }
(void)ret;
close(conn_fd);
}
@@ -291,7 +310,7 @@
exit(EXIT_SUCCESS);
}
- if (setsid() < 0) {
+ if (setsid() == -1) {
exit(EXIT_FAILURE);
}
@@ -307,10 +326,11 @@
}
umask(0);
+
if (chdir("/") == -1) {
- perror("chdir()");
exit(EXIT_FAILURE);
}
+
for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--) {
close(i);
}
@@ -321,7 +341,6 @@
int
main()
{
-
daemonize();
main_loop();
return 0;
Modified: soc2018/sduo/netmap_utils/fd_server.h
==============================================================================
--- soc2018/sduo/netmap_utils/fd_server.h Wed Jun 27 15:52:47 2018 (r337264)
+++ soc2018/sduo/netmap_utils/fd_server.h Wed Jun 27 16:17:21 2018 (r337265)
@@ -1,14 +1,7 @@
#ifndef FD_LIB_H
#define FD_LIB_H
-#include <errno.h>
-#include <net/if.h>
-#include <stdint.h>
-#include <sys/socket.h>
-
-#include <net/netmap.h>
-#define NETMAP_WITH_LIBS
-#include <net/netmap_user.h>
+#define SOCKET_NAME "/tmp/my_unix_socket"
struct fd_request {
#define FD_GET 1
@@ -16,7 +9,7 @@
#define FD_CLOSE 3
#define FD_STOP 4
uint8_t action;
- char if_name[IFNAMSIZ];
+ char if_name[NETMAP_REQ_IFNAMSIZ];
};
struct fd_response {
Added: soc2018/sduo/netmap_utils/functional.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ soc2018/sduo/netmap_utils/functional.c Wed Jun 27 16:17:21 2018 (r337265)
@@ -0,0 +1,1245 @@
+/*
+ * A tool for functional testing netmap transmission and reception.
+ *
+ * Copyright (C) 2018 Vincenzo Maffione. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/netmap.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#define NETMAP_WITH_LIBS
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <net/netmap_user.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include "fd_server.h"
+
+#define ETH_ADDR_LEN 6
+
+struct Event {
+ unsigned evtype;
+#define EVENT_TYPE_RX 0x1
+#define EVENT_TYPE_TX 0x2
+#define EVENT_TYPE_PAUSE 0x3
+ unsigned num; /* > 1 if repeated event */
+
+ /* Tx and Rx event. */
+ unsigned pkt_len;
+ char filler;
+
+ /* Pause event. */
+ unsigned long long usecs;
+};
+
+struct Global {
+ struct nm_desc nmd;
+ const char *ifname;
+ unsigned wait_link_secs; /* wait for link */
+ unsigned timeout_secs; /* transmit/receive timeout */
+ int ignore_if_not_matching; /* ignore certain received packets */
+ int success_if_no_receive; /* exit status 0 if we receive no packets */
+ int
+ sequential_fill; /* increment fill char for multi-packets
+ operations */
+ int request_from_fd_server;
+ int verbose;
+
+#define MAX_PKT_SIZE 65536
+ char pktm[MAX_PKT_SIZE]; /* packet model */
+ unsigned pktm_len; /* packet model length */
+ char pktr[MAX_PKT_SIZE]; /* packet received */
+ unsigned pktr_len; /* length of received packet */
+ unsigned max_frag_size; /* max bytes per netmap TX slot */
+
+ char src_mac[ETH_ADDR_LEN];
+ char dst_mac[ETH_ADDR_LEN];
+ uint32_t src_ip;
+ uint32_t dst_ip;
+ uint16_t src_port;
+ uint16_t dst_port;
+ char filler;
+
+#define MAX_EVENTS 64
+ unsigned num_events;
+ struct Event events[MAX_EVENTS];
+ unsigned num_loops;
+};
+
+void release_if_fd(struct Global *, const char *);
+
+void
+clean_exit(struct Global *g)
+{
+
+ release_if_fd(g, g->ifname);
+ exit(EXIT_FAILURE);
+}
+
+static void
+fill_packet_field(struct Global *g, unsigned offset, const char *content,
+ unsigned content_len)
+{
+ if (offset + content_len > sizeof(g->pktm)) {
+ printf("Packet layout overflow: %u + %u > %lu\n", offset,
+ content_len, sizeof(g->pktm));
+ clean_exit(g);
+ }
+
+ memcpy(g->pktm + offset, content, content_len);
+}
+
+static void
+fill_packet_8bit(struct Global *g, unsigned offset, uint8_t val)
+{
+ fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_16bit(struct Global *g, unsigned offset, uint16_t val)
+{
+ val = htons(val);
+ fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_32bit(struct Global *g, unsigned offset, uint32_t val)
+{
+ val = htonl(val);
+ fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+/* Compute the checksum of the given ip header. */
+static uint32_t
+checksum(const void *data, uint16_t len, uint32_t sum /* host endianness */)
+{
+ const uint8_t *addr = data;
+ uint32_t i;
+
+ /* Checksum all the pairs of bytes first... */
+ for (i = 0; i < (len & ~1U); i += 2) {
+ sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
+ if (sum > 0xFFFF) {
+ sum -= 0xFFFF;
+ }
+ }
+ /*
+ * If there's a single byte left over, checksum it, too.
+ * Network byte order is big-endian, so the remaining byte is
+ * the high byte.
+ */
+ if (i < len) {
+ sum += addr[i] << 8;
+ if (sum > 0xFFFF) {
+ sum -= 0xFFFF;
+ }
+ }
+ return sum;
+}
+
+static uint16_t
+wrapsum(uint32_t sum /* host endianness */)
+{
+ sum = ~sum & 0xFFFF;
+ return sum; /* host endianness */
+}
+
+static void
+build_packet(struct Global *g)
+{
+ unsigned ofs = 0;
+ unsigned ethofs;
+ unsigned ipofs;
+ unsigned udpofs;
+ unsigned pldofs;
+
+ memset(g->pktm, 0, sizeof(g->pktm));
+ if (g->verbose) {
+ printf("%s: starting at ofs %u\n", __func__, ofs);
+ }
+
+ ethofs = ofs;
+ (void)ethofs;
+ /* Ethernet destination and source MAC address plus ethertype. */
+ fill_packet_field(g, ofs, g->dst_mac, ETH_ADDR_LEN);
+ ofs += ETH_ADDR_LEN;
+ fill_packet_field(g, ofs, g->src_mac, ETH_ADDR_LEN);
+ ofs += ETH_ADDR_LEN;
+ fill_packet_16bit(g, ofs, ETHERTYPE_IP);
+ ofs += 2;
+ if (g->verbose) {
+ printf("%s: eth done, ofs %u\n", __func__, ofs);
+ }
+
+ ipofs = ofs;
+ /* First byte of IP header. */
+ fill_packet_8bit(g, ofs,
+ (IPVERSION << 4) | ((sizeof(struct iphdr)) >> 2));
+ ofs += 1;
+ /* Skip QoS byte. */
+ ofs += 1;
+ /* Total length. */
+ fill_packet_16bit(g, ofs, g->pktm_len - ipofs);
+ ofs += 2;
+ /* Skip identification field. */
+ ofs += 2;
+ /* Offset (and flags) field. */
+ fill_packet_16bit(g, ofs, IP_DF);
+ ofs += 2;
+ /* TTL. */
+ fill_packet_8bit(g, ofs, IPDEFTTL);
+ ofs += 1;
+ /* Protocol. */
+ fill_packet_8bit(g, ofs, IPPROTO_UDP);
+ ofs += 1;
+ /* Skip checksum for now. */
+ ofs += 2;
+ /* Source IP address. */
+ fill_packet_32bit(g, ofs, g->src_ip);
+ ofs += 4;
+ /* Dst IP address. */
+ fill_packet_32bit(g, ofs, g->dst_ip);
+ ofs += 4;
+ /* Now put the checksum. */
+ fill_packet_16bit(
+ g, ipofs + 10,
+ wrapsum(checksum(g->pktm + ipofs, sizeof(struct iphdr), 0)));
+ if (g->verbose) {
+ printf("%s: ip done, ofs %u\n", __func__, ofs);
+ }
+
+ udpofs = ofs;
+ /* UDP source port. */
+ fill_packet_16bit(g, ofs, g->src_port);
+ ofs += 2;
+ /* UDP source port. */
+ fill_packet_16bit(g, ofs, g->dst_port);
+ ofs += 2;
+ /* UDP length (UDP header + data). */
+ fill_packet_16bit(g, ofs, g->pktm_len - udpofs);
+ ofs += 2;
+ /* Skip the UDP checksum for now. */
+ ofs += 2;
+ if (g->verbose) {
+ printf("%s: udp done, ofs %u\n", __func__, ofs);
+ }
+
+ /* Fill UDP payload. */
+ pldofs = ofs;
+ for (; ofs < g->pktm_len; ofs++) {
+ fill_packet_8bit(g, ofs, g->filler);
+ }
+ if (g->verbose) {
+ printf("%s: payload done, ofs %u\n", __func__, ofs);
+ }
+
+ /* Put the UDP checksum now.
+ * Magic: taken from sbin/dhclient/packet.c */
+ fill_packet_16bit(
+ g, udpofs + 6,
+ wrapsum(checksum(
+ /* udp header */ g->pktm + udpofs,
+ sizeof(struct udphdr),
+ checksum(/* udp payload */ g->pktm + pldofs,
+ g->pktm_len - pldofs,
+ checksum(/* pseudo header */ g->pktm + ipofs +
+ 12,
+ 2 * sizeof(g->src_ip),
+ IPPROTO_UDP + (uint32_t)(g->pktm_len -
+ udpofs))))));
+}
+
+// static unsigned
+// tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
+// {
+// unsigned avail_per_slot = ring->nr_buf_size;
+
+// if (max_frag_size < avail_per_slot) {
+// avail_per_slot = max_frag_size;
+// }
+
+// return nm_ring_space(ring) * avail_per_slot;
+// }
+
+static int
+tx_flush(struct Global *g)
+{
+ struct nm_desc *nmd = &g->nmd;
+ unsigned elapsed_ms = 0;
+ unsigned wait_ms = 100;
+ int i;
+
+ for (;;) {
+ int pending = 0;
+ for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+ struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+ pending += nm_tx_pending(ring);
+ }
+
+ if (!pending) {
+ return 0;
+ }
+
+ if (elapsed_ms > g->timeout_secs * 1000) {
+ printf("%s: Timeout\n", __func__);
+ return -1;
+ }
+
+ usleep(wait_ms * 1000);
+ elapsed_ms += wait_ms;
+
+ ioctl(nmd->fd, NIOCTXSYNC, NULL);
+ }
+}
+
+uint64_t
+ring_avail_packets(struct netmap_ring *ring, unsigned pkt_len)
+{
+ uint64_t slot_per_packet;
+
+ slot_per_packet = ceil((double)pkt_len / (double)ring->nr_buf_size);
+ return nm_ring_space(ring) / slot_per_packet;
+}
+
+uint64_t
+adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
+{
+ uint64_t sends_available = 0;
+ unsigned int i;
+
+ for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+ struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+ sends_available += ring_avail_packets(ring, pkt_len);
+ }
+
+ return sends_available;
+}
+
+void
+put_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+ unsigned head = ring->head;
+ unsigned frags = 0;
+ unsigned ofs = 0;
+
+ for (;;) {
+ struct netmap_slot *slot = &ring->slot[head];
+ char *buf = NETMAP_BUF(ring, slot->buf_idx);
+ unsigned copysize = g->pktm_len - ofs;
+
+ if (copysize > ring->nr_buf_size) {
+ copysize = ring->nr_buf_size;
+ }
+ if (copysize > g->max_frag_size) {
+ copysize = g->max_frag_size;
+ }
+
+ memcpy(buf, g->pktm + ofs, copysize);
+ ofs += copysize;
+ slot->len = copysize;
+ slot->flags = NS_MOREFRAG;
+ head = nm_ring_next(ring, head);
+ frags++;
+ if (ofs >= g->pktm_len) {
+ /* Last fragment. */
+ assert(ofs == g->pktm_len);
+ slot->flags = NS_REPORT;
+ break;
+ }
+ }
+
+ ring->head = ring->cur = head;
+ printf("packet (%u bytes, %u frags) placed to TX\n", g->pktm_len,
+ frags);
+}
+
+char
+next_fill(char cur_fill)
+{
+ if (cur_fill == 'z')
+ return 'a';
+ if (cur_fill == 'Z')
+ return 'A';
+ return ++cur_fill;
+}
+
+/* Transmit packets_num packets using any combination of TX rings. */
+static int
+tx(struct Global *g, unsigned packets_num)
+{
+ struct nm_desc *nmd = &g->nmd;
+ unsigned elapsed_ms = 0;
+ unsigned wait_ms = 100;
+ unsigned int i;
+
+ /* We cycle here until either we timeout or we find enough space. */
+ for (;;) {
+ if (adapter_avail_sends(nmd, g->pktm_len) >= packets_num) {
+ break;
+ }
+
+ if (elapsed_ms > g->timeout_secs * 1000) {
+ printf("%s: Timeout\n", __func__);
+ return -1;
+ }
+
+ /* Retry after a short while. */
+ usleep(wait_ms * 1000);
+ elapsed_ms += wait_ms;
+ ioctl(nmd->fd, NIOCTXSYNC, NULL);
+ }
+
+ /* Once we have enough space, we start filling slots. We might use
+ * multiple rings.
+ */
+ for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+ struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+ uint64_t ring_sends_num;
+
+ for (ring_sends_num = ring_avail_packets(ring, g->pktm_len);
+ ring_sends_num > 0 && packets_num > 0;
+ --ring_sends_num, --packets_num) {
+ put_one_packet(g, ring);
+
+ if (g->sequential_fill == 1) {
+ g->filler = next_fill(g->filler);
+ build_packet(g);
+ }
+ }
+
+ if (packets_num == 0) {
+ break;
+ }
+ }
+
+ assert(packets_num == 0);
+ /* Once we're done we sync, sending all packets at once. */
+ ioctl(nmd->fd, NIOCTXSYNC, NULL);
+ return 0;
+}
+
+/* If -I option is specified, we want to ignore frames that don't match
+ * our expected ethernet header.
+ * This function currently assumes that Ethernet header starts from
+ * the beginning of the packet buffers. */
+static int
+ignore_received_frame(struct Global *g)
+{
+ if (!g->ignore_if_not_matching) {
+ return 0; /* don't ignore */
+ }
+
+ if (g->pktr_len < 14 || memcmp(g->pktm, g->pktr, 14) != 0) {
+ return 1; /* ignore */
+ }
+
+ return 0; /* don't ignore */
+}
+
+uint64_t
+adapter_avail_receives(struct nm_desc *nmd, unsigned pkt_len)
+{
+ uint64_t receives_available = 0;
+ unsigned int i;
+
+ for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+ struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+
+ receives_available += ring_avail_packets(ring, pkt_len);
+ }
+
+ return receives_available;
+}
+
+static int
+rx_check(struct Global *g)
+{
+ unsigned i;
+
+ if (g->pktr_len != g->pktm_len) {
+ printf("Received packet length (%u) different from "
+ "expected (%u bytes)\n",
+ g->pktr_len, g->pktm_len);
+ return -1;
+ }
+
+ for (i = 0; i < g->pktr_len; i++) {
+ if (g->pktr[i] != g->pktm[i]) {
+ printf("Received packet differs from model at "
+ "offset %u (0x%02x!=0x%02x)\n",
+ i, g->pktr[i], (uint8_t)g->pktm[i]);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+read_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+ unsigned head = ring->head;
+ int frags = 0;
+
+ g->pktr_len = 0;
+ for (;;) {
+ struct netmap_slot *slot = &ring->slot[head];
+ char *buf = NETMAP_BUF(ring, slot->buf_idx);
+
+ if (g->pktr_len + slot->len > sizeof(g->pktr)) {
+ /* Sanity check. */
+ printf("Error: received packet too "
+ "large "
+ "(>= %u bytes) ",
+ g->pktr_len + slot->len);
+ clean_exit(g);
+ }
+
+ memcpy(g->pktr + g->pktr_len, buf, slot->len);
+ g->pktr_len += slot->len;
+ head = nm_ring_next(ring, head);
+ frags++;
+ if (!(slot->flags & NS_MOREFRAG)) {
+ break;
+ }
+
+ if (head == ring->tail) {
+ printf("warning: truncated packet "
+ "(len=%u)\n",
+ g->pktr_len);
+ frags = -1;
+ break;
+ }
+ }
+
+ ring->head = ring->cur = head;
+ printf("packet (%u bytes, %d frags) received "
+ "from RX\n",
+ g->pktr_len, frags);
+ return frags;
+}
+
+/* Receive packets_num packets from any combination of RX rings. */
+static int
+rx(struct Global *g, unsigned packets_num)
+{
+ struct nm_desc *nmd = &g->nmd;
+ unsigned elapsed_ms = 0;
+ unsigned wait_ms = 100;
+ unsigned int i;
+
+ /* We cycle here until either we timeout or we find enough space. */
+ for (;;) {
+ again:
+ if (adapter_avail_receives(nmd, g->pktm_len) >= packets_num) {
+ break;
+ }
+
+ if (elapsed_ms > g->timeout_secs * 1000) {
+ printf("%s: Timeout\n", __func__);
+ /* -n flag */
+ return g->success_if_no_receive == 1 ? 0 : -1;
+ }
+
+ /* Retry after a short while. */
+ usleep(wait_ms * 1000);
+ elapsed_ms += wait_ms;
+ ioctl(nmd->fd, NIOCRXSYNC, NULL);
+ }
+
+ /* Once we have enough space, we start reading packets. We might use
+ * multiple rings.
+ */
+ for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+ struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+ uint64_t ring_receives_num;
+
+ for (ring_receives_num = ring_avail_packets(ring, g->pktm_len);
+ ring_receives_num > 0 && packets_num > 0;
+ --ring_receives_num, --packets_num) {
+ int frags = 0;
+
+ frags = read_one_packet(g, ring);
+ if (frags == -1) {
+ break; /* Truncated packet, skip this ring. */
+ }
+
+ if (ignore_received_frame(g)) {
+ if (g->verbose) {
+ printf("(ignoring packet with %u bytes "
+ "and "
+ "%d frags received from RX ring "
+ "#%d)\n",
+ g->pktr_len, frags, i);
+ }
+ elapsed_ms = 0;
+ /* We can go back there, because we're
+ * decrementing packets_num each time, therefore
+ * the we will wait only for the remaining
+ * packets.
+ */
+ goto again;
+ }
+
+ /* As soon as we find a packet wich doesn't match our
+ * packet model we exit with status EXIT_FAILURE.
+ */
+ if (rx_check(g)) {
+ clean_exit(g);
+ }
+
+ if (g->sequential_fill == 1) {
+ g->filler = next_fill(g->filler);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-soc-all
mailing list