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:
Vincenzo Maffione 2020-11-22 09:20:08 +00:00
parent ecfd9756ce
commit 4bfe1a4fe2

View File

@ -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 = nm_open(g.ifname, NULL, flags, &base_nmd);
if (g.nmd == NULL) {
D("Unable to open %s: %s", g.ifname, strerror(errno));
g.nmd->reg.nr_ringid = 0;
}
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;