new features (mostly for testing netmap capabilities)

+ pkt-gen -f rx now remains active even when traffic stops
  Previous behaviour (exit after 1 second of silence) can be
  restored with the -W option

+ the -X option does a hexdump of the content of a packet (both tx and rx).
  This can be useful to check what goes in and out.

+ the -I option instructs the sender to use indirect buffers
  (not really useful other than to test the kernel module in the
  VALE switch)
This commit is contained in:
Luigi Rizzo 2013-06-05 17:37:59 +00:00
parent 85233a7d39
commit b303f675df
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=251426

View File

@ -38,6 +38,8 @@
#include "nm_util.h"
#include <ctype.h> // isprint()
const char *default_payload="netmap pkt-gen payload\n"
"http://info.iet.unipi.it/~luigi/netmap/ ";
@ -86,6 +88,8 @@ struct glob_arg {
#define OPT_COPY 4
#define OPT_MEMCPY 8
#define OPT_TS 16 /* add a timestamp */
#define OPT_INDIRECT 32 /* use indirect buffers, tx only */
#define OPT_DUMP 64 /* dump rx/tx traffic */
int dev_type;
pcap_t *p;
@ -346,6 +350,33 @@ wrapsum(u_int32_t sum)
return (htons(sum));
}
/* Check the payload of the packet for errors (use it for debug).
* Look for consecutive ascii representations of the size of the packet.
*/
static void
dump_payload(char *p, int len, struct netmap_ring *ring, int cur)
{
char buf[128];
int i, j, i0;
/* get the length in ASCII of the length of the packet. */
printf("ring %p cur %5d len %5d buf %p\n", ring, cur, len, p);
/* hexdump routine */
for (i = 0; i < len; ) {
memset(buf, sizeof(buf), ' ');
sprintf(buf, "%5d: ", i);
i0 = i;
for (j=0; j < 16 && i < len; i++, j++)
sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i]));
i = i0;
for (j=0; j < 16 && i < len; i++, j++)
sprintf(buf+7+j + 48, "%c",
isprint(p[i]) ? p[i] : '.');
printf("%s\n", buf);
}
}
/*
* Fill a packet with some payload.
* We create a UDP packet so the payload starts at
@ -357,6 +388,7 @@ wrapsum(u_int32_t sum)
#define uh_ulen len
#define uh_sum check
#endif /* linux */
static void
initialize_packet(struct targ *targ)
{
@ -365,11 +397,13 @@ initialize_packet(struct targ *targ)
struct ip *ip;
struct udphdr *udp;
uint16_t paylen = targ->g->pkt_size - sizeof(*eh) - sizeof(struct ip);
int i, l, l0 = strlen(default_payload);
const char *payload = targ->g->options & OPT_INDIRECT ?
"XXXXXXXXXXXXXXXXXXXXXX" : default_payload;
int i, l, l0 = strlen(payload);
for (i = 0; i < paylen;) {
l = min(l0, paylen - i);
bcopy(default_payload, pkt->body + i, l);
bcopy(payload, pkt->body + i, l);
i += l;
}
pkt->body[i-1] = '\0';
@ -415,34 +449,9 @@ initialize_packet(struct targ *targ)
bcopy(&targ->g->src_mac.start, eh->ether_shost, 6);
bcopy(&targ->g->dst_mac.start, eh->ether_dhost, 6);
eh->ether_type = htons(ETHERTYPE_IP);
// dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0);
}
/* Check the payload of the packet for errors (use it for debug).
* Look for consecutive ascii representations of the size of the packet.
*/
static void
check_payload(char *p, int psize)
{
char temp[64];
int n_read, size, sizelen;
/* get the length in ASCII of the length of the packet. */
sizelen = sprintf(temp, "%d", psize) + 1; // include a whitespace
/* dummy payload. */
p += 14; /* skip packet header. */
n_read = 14;
while (psize - n_read >= sizelen) {
sscanf(p, "%d", &size);
if (size != psize) {
D("Read %d instead of %d", size, psize);
break;
}
p += sizelen;
n_read += sizelen;
}
}
/*
@ -475,7 +484,13 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt,
struct netmap_slot *slot = &ring->slot[cur];
char *p = NETMAP_BUF(ring, slot->buf_idx);
if (options & OPT_COPY)
slot->flags = 0;
if (options & OPT_DUMP)
dump_payload(p, size, ring, cur);
if (options & OPT_INDIRECT) {
slot->flags |= NS_INDIRECT;
*((struct pkt **)(void *)p) = pkt;
} else if (options & OPT_COPY)
pkt_copy(pkt, p, size);
else if (options & OPT_MEMCPY)
memcpy(p, pkt, size);
@ -756,6 +771,7 @@ sender_body(void *data)
struct timespec tmptime, nexttime = { 0, 0}; // XXX silence compiler
int rate_limit = targ->g->tx_rate;
long long waited = 0;
D("start");
if (setaffinity(targ->thread, targ->affinity))
goto quit;
@ -882,7 +898,7 @@ receive_pcap(u_char *user, const struct pcap_pkthdr * h,
}
static int
receive_packets(struct netmap_ring *ring, u_int limit, int skip_payload)
receive_packets(struct netmap_ring *ring, u_int limit, int dump)
{
u_int cur, rx;
@ -893,8 +909,9 @@ receive_packets(struct netmap_ring *ring, u_int limit, int skip_payload)
struct netmap_slot *slot = &ring->slot[cur];
char *p = NETMAP_BUF(ring, slot->buf_idx);
if (!skip_payload)
check_payload(p, slot->len);
slot->flags = OPT_INDIRECT; // XXX
if (dump)
dump_payload(p, slot->len, ring, cur);
cur = NETMAP_RING_NEXT(ring, cur);
}
@ -946,6 +963,7 @@ receiver_body(void *data)
targ->count++;
}
} else {
int dump = targ->g->options & OPT_DUMP;
while (!targ->cancel) {
/* Once we started to receive packets, wait at most 1 seconds
before quitting. */
@ -962,8 +980,7 @@ receiver_body(void *data)
if (rxring->avail == 0)
continue;
m = receive_packets(rxring, targ->g->burst,
SKIP_PAYLOAD);
m = receive_packets(rxring, targ->g->burst, dump);
received += m;
}
targ->count = received;
@ -1324,10 +1341,11 @@ main(int arc, char **argv)
g.burst = 512; // default
g.nthreads = 1;
g.cpus = 1;
g.forever = 1;
g.tx_rate = 0;
while ( (ch = getopt(arc, argv,
"a:f:n:i:t:r:l:d:s:D:S:b:c:o:p:PT:w:WvR:")) != -1) {
"a:f:n:i:It:r:l:d:s:D:S:b:c:o:p:PT:w:WvR:X")) != -1) {
struct sf *fn;
switch(ch) {
@ -1367,6 +1385,10 @@ main(int arc, char **argv)
g.dev_type = DEV_NETMAP;
break;
case 'I':
g.options |= OPT_INDIRECT; /* XXX use indirect buffer */
break;
case 't': /* send, deprecated */
D("-t deprecated, please use -f tx -n %s", optarg);
g.td_body = sender_body;
@ -1399,8 +1421,8 @@ main(int arc, char **argv)
wait_link = atoi(optarg);
break;
case 'W':
g.forever = 1; /* do not exit rx even with no traffic */
case 'W': /* XXX changed default */
g.forever = 0; /* do not exit rx even with no traffic */
break;
case 'b': /* burst */
@ -1430,6 +1452,8 @@ main(int arc, char **argv)
case 'R':
g.tx_rate = atoi(optarg);
break;
case 'X':
g.options |= OPT_DUMP;
}
}
@ -1572,10 +1596,11 @@ main(int arc, char **argv)
}
if (g.options) {
D("special options:%s%s%s%s\n",
D("--- SPECIAL OPTIONS:%s%s%s%s%s\n",
g.options & OPT_PREFETCH ? " prefetch" : "",
g.options & OPT_ACCESS ? " access" : "",
g.options & OPT_MEMCPY ? " memcpy" : "",
g.options & OPT_INDIRECT ? " indirect" : "",
g.options & OPT_COPY ? " copy" : "");
}