tools: netmap: pkt-gen: check packet length against interface MTU

Validate the value of the -l argument (packet length) against the MTU of the netmap port.
In case the netmap port does not refer to a physical interface (e.g. VALE port or pipe), then
the netmap buffer size is used as MTU.
This change also sets a better default value for the -M option, so that pkt-gen uses
the largest possible fragments in case of multi-slot packets.

Differential Revision:	https://reviews.freebsd.org/D18436
This commit is contained in:
Vincenzo Maffione 2018-12-08 12:52:09 +00:00
parent 1becbc64f8
commit 9e53f3bd67

View File

@ -195,7 +195,7 @@ struct virt_header {
uint8_t fields[VIRT_HDR_MAX]; uint8_t fields[VIRT_HDR_MAX];
}; };
#define MAX_BODYSIZE 16384 #define MAX_BODYSIZE 65536
struct pkt { struct pkt {
struct virt_header vh; struct virt_header vh;
@ -238,7 +238,6 @@ struct mac_range {
/* ifname can be netmap:foo-xxxx */ /* ifname can be netmap:foo-xxxx */
#define MAX_IFNAMELEN 64 /* our buffer for ifname */ #define MAX_IFNAMELEN 64 /* our buffer for ifname */
//#define MAX_PKTSIZE 1536
#define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */ #define MAX_PKTSIZE MAX_BODYSIZE /* XXX: + IP_HDR + ETH_HDR */
/* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */ /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
@ -263,7 +262,7 @@ struct glob_arg {
int forever; int forever;
uint64_t npackets; /* total packets to send */ uint64_t npackets; /* total packets to send */
int frags; /* fragments per packet */ int frags; /* fragments per packet */
u_int mtu; /* size of each fragment */ u_int frag_size; /* size of each fragment */
int nthreads; int nthreads;
int cpus; /* cpus used for running */ int cpus; /* cpus used for running */
int system_cpus; /* cpus on the system */ int system_cpus; /* cpus on the system */
@ -308,6 +307,11 @@ struct glob_arg {
}; };
enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP };
enum {
TD_TYPE_SENDER = 1,
TD_TYPE_RECEIVER,
TD_TYPE_OTHER,
};
/* /*
* Arguments for a new thread. The same structure is used by * Arguments for a new thread. The same structure is used by
@ -509,6 +513,42 @@ extract_mac_range(struct mac_range *r)
return 0; return 0;
} }
static int
get_if_mtu(const struct glob_arg *g)
{
char ifname[IFNAMSIZ];
struct ifreq ifreq;
int s, ret;
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';
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
D("socket() failed: %s", strerror(errno));
return s;
}
memset(&ifreq, 0, sizeof(ifreq));
strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
ret = ioctl(s, SIOCGIFMTU, &ifreq);
if (ret) {
D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
}
return ifreq.ifr_mtu;
}
/* This is a pipe or a VALE port, where the MTU is very large,
* so we use some practical limit. */
return 65536;
}
static struct targ *targs; static struct targ *targs;
static int global_nthreads; static int global_nthreads;
@ -1581,18 +1621,18 @@ sender_body(void *data)
#endif /* NO_PCAP */ #endif /* NO_PCAP */
} else { } else {
int tosend = 0; int tosend = 0;
u_int bufsz, mtu = targ->g->mtu; u_int bufsz, frag_size = targ->g->frag_size;
nifp = targ->nmd->nifp; nifp = targ->nmd->nifp;
txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring); txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
bufsz = txring->nr_buf_size; bufsz = txring->nr_buf_size;
if (bufsz < mtu) if (bufsz < frag_size)
mtu = bufsz; frag_size = bufsz;
targ->frag_size = targ->g->pkt_size / targ->frags; targ->frag_size = targ->g->pkt_size / targ->frags;
if (targ->frag_size > mtu) { if (targ->frag_size > frag_size) {
targ->frags = targ->g->pkt_size / mtu; targ->frags = targ->g->pkt_size / frag_size;
targ->frag_size = mtu; targ->frag_size = frag_size;
if (targ->g->pkt_size % mtu != 0) if (targ->g->pkt_size % frag_size != 0)
targ->frags++; targ->frags++;
} }
D("frags %u frag_size %u", targ->frags, targ->frag_size); D("frags %u frag_size %u", targ->frags, targ->frag_size);
@ -2441,12 +2481,6 @@ usage(int errcode)
exit(errcode); exit(errcode);
} }
enum {
TD_TYPE_SENDER = 1,
TD_TYPE_RECEIVER,
TD_TYPE_OTHER,
};
static void static void
start_threads(struct glob_arg *g) { start_threads(struct glob_arg *g) {
int i; int i;
@ -2779,8 +2813,8 @@ main(int arc, char **argv)
g.cpus = 1; /* default */ g.cpus = 1; /* default */
g.forever = 1; g.forever = 1;
g.tx_rate = 0; g.tx_rate = 0;
g.frags =1; g.frags = 1;
g.mtu = 1500; g.frag_size = (u_int)-1; /* use the netmap buffer size by default */
g.nmr_config = ""; g.nmr_config = "";
g.virt_header = 0; g.virt_header = 0;
g.wait_link = 2; /* wait 2 seconds for physical ports */ g.wait_link = 2; /* wait 2 seconds for physical ports */
@ -2824,7 +2858,7 @@ main(int arc, char **argv)
break; break;
case 'M': case 'M':
g.mtu = atoi(optarg); g.frag_size = atoi(optarg);
break; break;
case 'f': case 'f':
@ -3104,6 +3138,16 @@ main(int arc, char **argv)
// continue, fail later // continue, fail later
} }
if (g.td_type == TD_TYPE_SENDER) {
int mtu = get_if_mtu(&g);
if (mtu > 0 && g.pkt_size > mtu) {
D("pkt_size (%d) must be <= mtu (%d)",
g.pkt_size, mtu);
return -1;
}
}
if (verbose) { if (verbose) {
struct netmap_if *nifp = g.nmd->nifp; struct netmap_if *nifp = g.nmd->nifp;
struct nmreq *req = &g.nmd->req; struct nmreq *req = &g.nmd->req;