Skip to content

Instantly share code, notes, and snippets.

@upa
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save upa/d6ff72b0306945a0284f to your computer and use it in GitHub Desktop.
Save upa/d6ff72b0306945a0284f to your computer and use it in GitHub Desktop.
multiple source traffic generator using netmap
/*
* multiple source address traffic generator using netmap
*/
#include <stdio.h>
#define NETMAP_WITH_LIBS
#include <net/netmap_user.h>
#include <unistd.h>
#include <sys/poll.h>
#include <arpa/inet.h>
#include <sys/sysctl.h>
#include <ifaddrs.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#define BURST_MAX 1024
#define SRCIP_MAX 256
#define MACCOPY(s, d) \
do { \
d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; \
d[3] = s[3]; d[4] = s[4]; d[5] = s[5]; \
} while (0)
struct srcgen {
int raw_mode;
char * ifname;
int sip_num;
struct in_addr sips[SRCIP_MAX];
struct in_addr dip;
uint16_t csums[SRCIP_MAX];
u_int8_t smac[ETH_ALEN];
u_int8_t dmac[ETH_ALEN];
int pktlen;
int interval;
/* netmap related */
int fd;
char * mem;
struct netmap_if * nifp;
};
static uint16_t
checksum(const void * data, uint16_t len, uint32_t sum)
{
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 u_int16_t
wrapsum(u_int32_t sum)
{
sum = ~sum & 0xFFFF;
return (htons(sum));
}
struct ip *
build_packet (char * pkt, size_t len, struct srcgen * sg)
{
memset (pkt, 0, len);
/* build ether header */
struct ether_header * eth;
eth = (struct ether_header *) pkt;
MACCOPY (sg->smac, eth->ether_shost);
MACCOPY (sg->dmac, eth->ether_dhost);
eth->ether_type = htons (ETHERTYPE_IP);
/* build ip packet */
struct ip * ip;
ip = (struct ip *)(eth + 1);
ip->ip_v = IPVERSION;
ip->ip_hl = 5;
ip->ip_id = 0;
ip->ip_tos = 0;
ip->ip_ttl = 16;
ip->ip_len = htons (sg->pktlen - sizeof (*eth));
ip->ip_off = htons (IP_DF);
ip->ip_p = IPPROTO_UDP;
ip->ip_dst = sg->dip;
/* ip->ip_src is filled when transmitting */
ip->ip_sum = 0;
/* build udp packet */
struct udphdr * udp;
udp = (struct udphdr *)(ip + 1);
udp->source = htons (48558);
udp->dest = htons (48558);
udp->len = htons (sg->pktlen - (sizeof (*eth) + sizeof (*ip)));
udp->check = 0; /* no udp checksum */
return ip;
}
void
srcgen (struct srcgen * sg)
{
int idx;
u_int burst, cur;
char pkt[2048], * nm_pkt;
struct ip * ip;
struct netmap_ring * ring;
struct netmap_slot * slot;
ip = build_packet (pkt, sizeof (pkt), sg);
/* pre-culculate checksum */
for (idx = 0; idx < sg->sip_num; idx++) {
ip->ip_src = sg->sips[idx];
ip->ip_sum = 0;
sg->csums[idx] = wrapsum (checksum (ip, sizeof (*ip), 0));
}
idx = 0;
if (sg->raw_mode) {
int sock, ret;
struct sockaddr_ll ll;
sock = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
memset (&ll, 0, sizeof (ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = if_nametoindex(sg->ifname);
ll.sll_protocol = htons(ETH_P_ALL);
bind(sock, (struct sockaddr *)&ll, sizeof(ll));
while (1) {
/* set src ip address */
ip->ip_src = sg->sips[idx];
ip->ip_sum = sg->csums[idx];
idx = (idx + 1) % sg->sip_num;
ret = write (sock, pkt, sg->pktlen);
if (ret < 0) {
perror ("write");
}
if (sg->interval)
sleep (sg->interval);
}
}
ring = NETMAP_TXRING (sg->nifp, 0);
/* netmap mode */
while (1) {
cur = ring->cur;
burst = nm_ring_space (ring) < BURST_MAX ?
nm_ring_space (ring) : BURST_MAX;
while (burst-- > 0) {
/* set src ip address */
ip->ip_src = sg->sips[idx];
ip->ip_sum = sg->csums[idx];
idx = (idx + 1) % sg->sip_num;
/* xmit vai netmap ring */
slot = &ring->slot[cur];
nm_pkt = NETMAP_BUF (ring, slot->buf_idx);
nm_pkt_copy (pkt, nm_pkt, sg->pktlen);
slot->len = sg->pktlen;
cur = nm_ring_next (ring, cur);
if (sg->interval)
sleep (sg->interval);
}
ring->head = ring->cur = cur;
ioctl (sg->fd, NIOCTXSYNC, NULL);
}
return;
}
void
usage (void)
{
printf ("srcgen\n"
"\t" "-i : interface\n"
"\t" "-s : source ip address (multiple -s allowed)\n"
"\t" "-d : destination ip address\n"
"\t" "-S : source mac address\n"
"\t" "-D : destination mac address\n"
"\t" "-l : packet length (default 64)\n"
"\t" "-r : raw socket mode\n"
"\t" "-t : interval (sec)\n"
);
return;
}
int
main (int argc, char ** argv)
{
int fd, ret, mac[ETH_ALEN];
char ch;
struct nmreq nmr;
struct srcgen sg;
memset (&sg, 0, sizeof (struct srcgen));
/* parse arguments and setup default values */
while ((ch = getopt (argc, argv, "i:s:d:S:D:l:rt:")) != -1) {
switch (ch) {
case 'i' :
sg.ifname = optarg;
break;
case 's' :
ret = inet_pton (AF_INET, optarg,
&sg.sips[sg.sip_num++]);
if (ret < 1) {
D ("invalid source ip \"%s\"", optarg);
return -1;
}
break;
case 'd' :
ret = inet_pton (AF_INET, optarg, &sg.dip);
if (ret < 1) {
D ("invalid destination ip \"%s\"", optarg);
return -1;
}
break;
case 'S' :
sscanf (optarg, "%02x:%02x:%02x:%02x:%02x:%02x",
&mac[0], &mac[1], &mac[2],
&mac[3], &mac[4], &mac[5]);
MACCOPY (mac, sg.smac);
break;
case 'D' :
sscanf (optarg, "%02x:%02x:%02x:%02x:%02x:%02x",
&mac[0], &mac[1], &mac[2],
&mac[3], &mac[4], &mac[5]);
MACCOPY (mac, sg.dmac);
break;
case 'l' :
sg.pktlen = atoi (optarg);
break;
case 'r' :
sg.raw_mode = 1;
break;
case 't' :
sg.interval = atoi (optarg);
break;
default :
usage ();
return -1;
}
}
if (argc == 1) {
usage ();
return -1;
}
if (sg.ifname == NULL) {
D ("specify interface name");
return -1;
}
if (sg.pktlen == 0) {
sg.pktlen = 64;
}
if (sg.raw_mode) {
goto srcgen;
}
/* setup netmap */
fd = open ("/dev/netmap", O_RDWR);
if (fd < 0) {
D ("unable to open /dev/netmap");
return -1;
}
memset (&nmr, 0, sizeof (nmr));
strcpy (nmr.nr_name, sg.ifname);
nmr.nr_version = NETMAP_API;
nmr.nr_ringid = 0 | (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
nmr.nr_flags |= NR_REG_ALL_NIC;
if (ioctl (fd, NIOCREGIF, &nmr) < 0) {
D ("unable to register interface \"%s\"", sg.ifname);
return -1;
}
sg.mem = mmap (NULL, nmr.nr_memsize,
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (sg.mem == MAP_FAILED) {
D ("unable to mmap");
return -1;
}
sg.nifp = NETMAP_IF (sg.mem, nmr.nr_offset);
sg.fd = fd;
srcgen:
srcgen (&sg);
/* not reached */
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment