netmap: pkt-gen: switch to libnetmap
Use the newer libnetmap (included in base) rather than the older nm_open()/nm_close() defined in netmap_user.h
This commit is contained in:
parent
ecfd9756ce
commit
4bfe1a4fe2
@ -38,35 +38,39 @@
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for CPU_SET() */
|
||||
#include <stdio.h>
|
||||
#define NETMAP_WITH_LIBS
|
||||
#include <net/netmap_user.h>
|
||||
|
||||
#include <ctype.h> // isprint()
|
||||
#include <unistd.h> // sysconf()
|
||||
#include <sys/poll.h>
|
||||
#include <arpa/inet.h> /* ntohs */
|
||||
#ifndef _WIN32
|
||||
#include <sys/sysctl.h> /* sysctl */
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <ctype.h> // isprint()
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h> /* getifaddrs */
|
||||
#include <libnetmap.h>
|
||||
#include <math.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/udp.h>
|
||||
#ifndef NO_PCAP
|
||||
#include <pcap/pcap.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/stat.h>
|
||||
#if !defined(_WIN32) && !defined(linux)
|
||||
#include <sys/sysctl.h> /* sysctl */
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h> // sysconf()
|
||||
#ifdef linux
|
||||
#define IPV6_VERSION 0x60
|
||||
#define IPV6_DEFHLIM 64
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#ifndef NO_PCAP
|
||||
#include <pcap/pcap.h>
|
||||
#endif
|
||||
|
||||
#include "ctrs.h"
|
||||
|
||||
@ -236,7 +240,8 @@ struct mac_range {
|
||||
};
|
||||
|
||||
/* ifname can be netmap:foo-xxxx */
|
||||
#define MAX_IFNAMELEN 64 /* our buffer for ifname */
|
||||
#define MAX_IFNAMELEN 512 /* our buffer for ifname */
|
||||
//#define MAX_PKTSIZE 1536
|
||||
#define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */
|
||||
|
||||
/* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
|
||||
@ -288,7 +293,8 @@ struct glob_arg {
|
||||
|
||||
int affinity;
|
||||
int main_fd;
|
||||
struct nm_desc *nmd;
|
||||
struct nmport_d *nmd;
|
||||
uint32_t orig_mode;
|
||||
int report_interval; /* milliseconds between prints */
|
||||
void *(*td_body)(void *);
|
||||
int td_type;
|
||||
@ -322,7 +328,7 @@ struct targ {
|
||||
int completed;
|
||||
int cancel;
|
||||
int fd;
|
||||
struct nm_desc *nmd;
|
||||
struct nmport_d *nmd;
|
||||
/* these ought to be volatile, but they are
|
||||
* only sampled and errors should not accumulate
|
||||
*/
|
||||
@ -515,16 +521,20 @@ extract_mac_range(struct mac_range *r)
|
||||
static int
|
||||
get_if_mtu(const struct glob_arg *g)
|
||||
{
|
||||
char ifname[IFNAMSIZ];
|
||||
struct ifreq ifreq;
|
||||
int s, ret;
|
||||
const char *ifname = g->nmd->hdr.nr_name;
|
||||
size_t len;
|
||||
|
||||
if (!strncmp(g->ifname, "netmap:", 7) && !strchr(g->ifname, '{')
|
||||
&& !strchr(g->ifname, '}')) {
|
||||
/* Parse the interface name and ask the kernel for the
|
||||
* MTU value. */
|
||||
strncpy(ifname, g->ifname+7, IFNAMSIZ-1);
|
||||
ifname[strcspn(ifname, "-*^{}/@")] = '\0';
|
||||
if (!strncmp(g->ifname, "netmap:", 7) && !strchr(ifname, '{')
|
||||
&& !strchr(ifname, '}')) {
|
||||
|
||||
len = strlen(ifname);
|
||||
|
||||
if (len > IFNAMSIZ) {
|
||||
D("'%s' too long, cannot ask for MTU", ifname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
@ -533,13 +543,15 @@ get_if_mtu(const struct glob_arg *g)
|
||||
}
|
||||
|
||||
memset(&ifreq, 0, sizeof(ifreq));
|
||||
strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
|
||||
memcpy(ifreq.ifr_name, ifname, len);
|
||||
|
||||
ret = ioctl(s, SIOCGIFMTU, &ifreq);
|
||||
if (ret) {
|
||||
D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
return ifreq.ifr_mtu;
|
||||
}
|
||||
|
||||
@ -620,7 +632,7 @@ system_ncpus(void)
|
||||
* and #rx-rings.
|
||||
*/
|
||||
static int
|
||||
parse_nmr_config(const char* conf, struct nmreq *nmr)
|
||||
parse_nmr_config(const char* conf, struct nmreq_register *nmr)
|
||||
{
|
||||
char *w, *tok;
|
||||
int i, v;
|
||||
@ -654,9 +666,7 @@ parse_nmr_config(const char* conf, struct nmreq *nmr)
|
||||
nmr->nr_tx_rings, nmr->nr_tx_slots,
|
||||
nmr->nr_rx_rings, nmr->nr_rx_slots);
|
||||
free(w);
|
||||
return (nmr->nr_tx_rings || nmr->nr_tx_slots ||
|
||||
nmr->nr_rx_rings || nmr->nr_rx_slots) ?
|
||||
NM_OPEN_RING_CFG : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1108,20 +1118,22 @@ initialize_packet(struct targ *targ)
|
||||
static void
|
||||
get_vnet_hdr_len(struct glob_arg *g)
|
||||
{
|
||||
struct nmreq req;
|
||||
struct nmreq_header hdr;
|
||||
struct nmreq_port_hdr ph;
|
||||
int err;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
|
||||
req.nr_version = NETMAP_API;
|
||||
req.nr_cmd = NETMAP_VNET_HDR_GET;
|
||||
err = ioctl(g->main_fd, NIOCREGIF, &req);
|
||||
hdr = g->nmd->hdr; /* copy name and version */
|
||||
hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
|
||||
hdr.nr_options = 0;
|
||||
memset(&ph, 0, sizeof(ph));
|
||||
hdr.nr_body = (uintptr_t)&ph;
|
||||
err = ioctl(g->main_fd, NIOCCTRL, &hdr);
|
||||
if (err) {
|
||||
D("Unable to get virtio-net header length");
|
||||
return;
|
||||
}
|
||||
|
||||
g->virt_header = req.nr_arg1;
|
||||
g->virt_header = ph.nr_hdr_len;
|
||||
if (g->virt_header) {
|
||||
D("Port requires virtio-net header, length = %d",
|
||||
g->virt_header);
|
||||
@ -1132,17 +1144,18 @@ static void
|
||||
set_vnet_hdr_len(struct glob_arg *g)
|
||||
{
|
||||
int err, l = g->virt_header;
|
||||
struct nmreq req;
|
||||
struct nmreq_header hdr;
|
||||
struct nmreq_port_hdr ph;
|
||||
|
||||
if (l == 0)
|
||||
return;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
|
||||
req.nr_version = NETMAP_API;
|
||||
req.nr_cmd = NETMAP_BDG_VNET_HDR;
|
||||
req.nr_arg1 = l;
|
||||
err = ioctl(g->main_fd, NIOCREGIF, &req);
|
||||
hdr = g->nmd->hdr; /* copy name and version */
|
||||
hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
|
||||
hdr.nr_options = 0;
|
||||
memset(&ph, 0, sizeof(ph));
|
||||
hdr.nr_body = (uintptr_t)&ph;
|
||||
err = ioctl(g->main_fd, NIOCCTRL, &hdr);
|
||||
if (err) {
|
||||
D("Unable to set virtio-net header length %d", l);
|
||||
}
|
||||
@ -2480,7 +2493,7 @@ usage(int errcode)
|
||||
exit(errcode);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
start_threads(struct glob_arg *g) {
|
||||
int i;
|
||||
|
||||
@ -2500,31 +2513,43 @@ start_threads(struct glob_arg *g) {
|
||||
memcpy(t->seed, &seed, sizeof(t->seed));
|
||||
|
||||
if (g->dev_type == DEV_NETMAP) {
|
||||
struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */
|
||||
uint64_t nmd_flags = 0;
|
||||
nmd.self = &nmd;
|
||||
int m = -1;
|
||||
|
||||
/*
|
||||
* if the user wants both HW and SW rings, we need to
|
||||
* know when to switch from NR_REG_ONE_NIC to NR_REG_ONE_SW
|
||||
*/
|
||||
if (g->orig_mode == NR_REG_NIC_SW) {
|
||||
m = (g->td_type == TD_TYPE_RECEIVER ?
|
||||
g->nmd->reg.nr_rx_rings :
|
||||
g->nmd->reg.nr_tx_rings);
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
int j;
|
||||
/* the first thread uses the fd opened by the main
|
||||
* thread, the other threads re-open /dev/netmap
|
||||
*/
|
||||
if (g->nthreads > 1) {
|
||||
nmd.req.nr_flags =
|
||||
g->nmd->req.nr_flags & ~NR_REG_MASK;
|
||||
nmd.req.nr_flags |= NR_REG_ONE_NIC;
|
||||
nmd.req.nr_ringid = i;
|
||||
t->nmd = nmport_clone(g->nmd);
|
||||
if (t->nmd == NULL)
|
||||
return -1;
|
||||
|
||||
j = i;
|
||||
if (m > 0 && j >= m) {
|
||||
/* switch to the software rings */
|
||||
t->nmd->reg.nr_mode = NR_REG_ONE_SW;
|
||||
j -= m;
|
||||
}
|
||||
t->nmd->reg.nr_ringid = j & NETMAP_RING_MASK;
|
||||
/* Only touch one of the rings (rx is already ok) */
|
||||
if (g->td_type == TD_TYPE_RECEIVER)
|
||||
nmd_flags |= NETMAP_NO_TX_POLL;
|
||||
t->nmd->reg.nr_flags |= NETMAP_NO_TX_POLL;
|
||||
|
||||
/* register interface. Override ifname and ringid etc. */
|
||||
t->nmd = nm_open(t->g->ifname, NULL, nmd_flags |
|
||||
NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd);
|
||||
if (t->nmd == NULL) {
|
||||
D("Unable to open %s: %s",
|
||||
t->g->ifname, strerror(errno));
|
||||
continue;
|
||||
if (nmport_open_desc(t->nmd) < 0) {
|
||||
nmport_undo_prepare(t->nmd);
|
||||
t->nmd = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
t->nmd = g->nmd;
|
||||
@ -2556,6 +2581,7 @@ start_threads(struct glob_arg *g) {
|
||||
t->used = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2655,7 +2681,7 @@ main_thread(struct glob_arg *g)
|
||||
if (targs[i].used)
|
||||
pthread_join(targs[i].thread, NULL); /* blocking */
|
||||
if (g->dev_type == DEV_NETMAP) {
|
||||
nm_close(targs[i].nmd);
|
||||
nmport_close(targs[i].nmd);
|
||||
targs[i].nmd = NULL;
|
||||
} else {
|
||||
close(targs[i].fd);
|
||||
@ -3078,20 +3104,13 @@ main(int arc, char **argv)
|
||||
} else if (g.dummy_send) { /* but DEV_NETMAP */
|
||||
D("using a dummy send routine");
|
||||
} else {
|
||||
struct nm_desc base_nmd;
|
||||
char errmsg[MAXERRMSG];
|
||||
u_int flags;
|
||||
|
||||
bzero(&base_nmd, sizeof(base_nmd));
|
||||
|
||||
parse_nmr_config(g.nmr_config, &base_nmd.req);
|
||||
|
||||
base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR;
|
||||
|
||||
if (nm_parse(g.ifname, &base_nmd, errmsg) < 0) {
|
||||
D("Invalid name '%s': %s", g.ifname, errmsg);
|
||||
g.nmd = nmport_prepare(g.ifname);
|
||||
if (g.nmd == NULL)
|
||||
goto out;
|
||||
}
|
||||
|
||||
parse_nmr_config(g.nmr_config, &g.nmd->reg);
|
||||
|
||||
g.nmd->reg.nr_flags |= NR_ACCEPT_VNET_HDR;
|
||||
|
||||
/*
|
||||
* Open the netmap device using nm_open().
|
||||
@ -3100,20 +3119,25 @@ main(int arc, char **argv)
|
||||
* which in turn may take some time for the PHY to
|
||||
* reconfigure. We do the open here to have time to reset.
|
||||
*/
|
||||
flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
|
||||
NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
|
||||
g.orig_mode = g.nmd->reg.nr_mode;
|
||||
if (g.nthreads > 1) {
|
||||
base_nmd.req.nr_flags &= ~NR_REG_MASK;
|
||||
base_nmd.req.nr_flags |= NR_REG_ONE_NIC;
|
||||
base_nmd.req.nr_ringid = 0;
|
||||
switch (g.orig_mode) {
|
||||
case NR_REG_ALL_NIC:
|
||||
case NR_REG_NIC_SW:
|
||||
g.nmd->reg.nr_mode = NR_REG_ONE_NIC;
|
||||
break;
|
||||
case NR_REG_SW:
|
||||
g.nmd->reg.nr_mode = NR_REG_ONE_SW;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
g.nmd->reg.nr_ringid = 0;
|
||||
}
|
||||
g.nmd = nm_open(g.ifname, NULL, flags, &base_nmd);
|
||||
if (g.nmd == NULL) {
|
||||
D("Unable to open %s: %s", g.ifname, strerror(errno));
|
||||
if (nmport_open_desc(g.nmd) < 0)
|
||||
goto out;
|
||||
}
|
||||
g.main_fd = g.nmd->fd;
|
||||
D("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
|
||||
ND("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
|
||||
g.nmd->mem);
|
||||
|
||||
if (g.virt_header) {
|
||||
@ -3128,9 +3152,9 @@ main(int arc, char **argv)
|
||||
|
||||
/* get num of queues in tx or rx */
|
||||
if (g.td_type == TD_TYPE_SENDER)
|
||||
devqueues = g.nmd->req.nr_tx_rings;
|
||||
devqueues = g.nmd->reg.nr_tx_rings + g.nmd->reg.nr_host_tx_rings;
|
||||
else
|
||||
devqueues = g.nmd->req.nr_rx_rings;
|
||||
devqueues = g.nmd->reg.nr_rx_rings + g.nmd->reg.nr_host_rx_rings;
|
||||
|
||||
/* validate provided nthreads. */
|
||||
if (g.nthreads < 1 || g.nthreads > devqueues) {
|
||||
@ -3150,17 +3174,17 @@ main(int arc, char **argv)
|
||||
|
||||
if (verbose) {
|
||||
struct netmap_if *nifp = g.nmd->nifp;
|
||||
struct nmreq *req = &g.nmd->req;
|
||||
struct nmreq_register *req = &g.nmd->reg;
|
||||
|
||||
D("nifp at offset %d, %d tx %d rx region %d",
|
||||
D("nifp at offset %"PRIu64", %d tx %d rx region %d",
|
||||
req->nr_offset, req->nr_tx_rings, req->nr_rx_rings,
|
||||
req->nr_arg2);
|
||||
for (i = 0; i <= req->nr_tx_rings; i++) {
|
||||
req->nr_mem_id);
|
||||
for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) {
|
||||
struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
|
||||
D(" TX%d at 0x%p slots %d", i,
|
||||
(void *)((char *)ring - (char *)nifp), ring->num_slots);
|
||||
}
|
||||
for (i = 0; i <= req->nr_rx_rings; i++) {
|
||||
for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) {
|
||||
struct netmap_ring *ring = NETMAP_RXRING(nifp, i);
|
||||
D(" RX%d at 0x%p slots %d", i,
|
||||
(void *)((char *)ring - (char *)nifp), ring->num_slots);
|
||||
@ -3230,7 +3254,8 @@ out:
|
||||
if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) {
|
||||
D("failed to block SIGINT: %s", strerror(errno));
|
||||
}
|
||||
start_threads(&g);
|
||||
if (start_threads(&g) < 0)
|
||||
return 1;
|
||||
/* Install the handler and re-enable SIGINT for the main thread */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = sigint_h;
|
||||
|
Loading…
x
Reference in New Issue
Block a user