pktgenctl: Allow pktgen device to be specified
[dragonfly.git] / tools / tools / netrate / pktgenctl / pktgenctl.c
CommitLineData
4fa8e46e 1/*
391741ec 2 * Copyright (c) 2012 The DragonFly Project. All rights reserved.
4fa8e46e
SZ
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
4fa8e46e
SZ
33 */
34
35#include <sys/types.h>
36#include <sys/ioctl.h>
37#include <sys/stat.h>
38#include <sys/socket.h>
39
40#include <arpa/inet.h>
41#include <netinet/in.h>
42#include <net/if.h>
43#include <net/if_dl.h>
44#include <net/ethernet.h>
45
46#include <err.h>
47#include <fcntl.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52
53#include "pktgen/pktgen.h"
54
55#define PKTGEN_DEVPATH "/dev/pktg0"
56
391741ec 57#define DEFAULT_PORT 3000
4fa8e46e 58
391741ec
SZ
59#define INDST_MASK 0x0001
60#define INSRC_MASK 0x0002
61#define EADDR_MASK 0x0004
62#define IFACE_MASK 0x0008
63#define DATALEN_MASK 0x0010
64#define DURATION_MASK 0x0020
4fa8e46e
SZ
65
66#define MASK_NEEDED (INDST_MASK | INSRC_MASK | EADDR_MASK | IFACE_MASK)
67
68static void
69usage(void)
70{
391741ec
SZ
71 fprintf(stderr, "pktgenctl "
72 "-d dst_inaddr[:dst_port] [-d dst_inaddr[:dst_port] ...] "
73 "-s src_inaddr[:src_port] "
74 "-e (gw_eaddr|dst_eaddr) -i iface "
52be0b30 75 "[-m data_len] [-l duration] [-D dev]\n");
4fa8e46e
SZ
76 exit(1);
77}
78
c95ebcd6 79static int
391741ec 80get_port(char *str)
c95ebcd6 81{
391741ec 82 char *p;
c95ebcd6 83
391741ec
SZ
84 p = strchr(str, ':');
85 if (p == NULL) {
86 return DEFAULT_PORT;
c95ebcd6 87 } else {
391741ec
SZ
88 *p = '\0';
89 ++p;
90 return atoi(p);
c95ebcd6
SZ
91 }
92}
93
4fa8e46e
SZ
94int
95main(int argc, char *argv[])
96{
97 struct pktgen_conf conf;
98 struct sockaddr *sa;
391741ec 99 struct sockaddr_in *src_sin, *dst_sin;
4fa8e46e
SZ
100 struct sockaddr_dl sdl;
101 char eaddr_str[32];
102 uint32_t arg_mask = 0;
391741ec 103 int fd, c, n, ndst_alloc;
52be0b30
SZ
104 const char *dev;
105
106 dev = PKTGEN_DEVPATH;
4fa8e46e
SZ
107
108 memset(&conf, 0, sizeof(conf));
109
4fa8e46e 110 conf.pc_duration = 10;
391741ec 111 conf.pc_datalen = 18;
4fa8e46e
SZ
112
113 sa = &conf.pc_dst_lladdr;
114 sa->sa_family = AF_LINK;
115 sa->sa_len = ETHER_ADDR_LEN;
116
4fa8e46e
SZ
117 src_sin = &conf.pc_src;
118 src_sin->sin_family = AF_INET;
4fa8e46e 119
391741ec
SZ
120 ndst_alloc = 1;
121 conf.pc_dst = calloc(ndst_alloc, sizeof(struct sockaddr_in));
122 if (conf.pc_dst == NULL)
123 err(1, "calloc(%d dst)", ndst_alloc);
124
125 conf.pc_ndst = 0;
52be0b30 126 while ((c = getopt(argc, argv, "d:s:e:i:m:l:D:")) != -1) {
4fa8e46e
SZ
127 switch (c) {
128 case 'd':
391741ec
SZ
129 if (conf.pc_ndst >= ndst_alloc) {
130 void *old = conf.pc_dst;
131 int old_ndst_alloc = ndst_alloc;
132
133 ndst_alloc *= 2;
134 conf.pc_dst = calloc(ndst_alloc,
135 sizeof(struct sockaddr_in));
136 if (conf.pc_dst == NULL)
137 err(1, "calloc(%d dst)", ndst_alloc);
138 memcpy(conf.pc_dst, old,
139 old_ndst_alloc * sizeof(struct sockaddr_in));
140 free(old);
141 }
142 dst_sin = &conf.pc_dst[conf.pc_ndst++];
143
144 dst_sin->sin_family = AF_INET;
145 dst_sin->sin_port = get_port(optarg);
146 dst_sin->sin_port = htons(dst_sin->sin_port);
147 n = inet_pton(AF_INET, optarg, &dst_sin->sin_addr);
4fa8e46e 148 if (n == 0)
391741ec 149 errx(1, "-d: invalid inet address: %s", optarg);
4fa8e46e 150 else if (n < 0)
391741ec 151 err(1, "-d: %s", optarg);
4fa8e46e
SZ
152 arg_mask |= INDST_MASK;
153 break;
154
155 case 's':
391741ec
SZ
156 src_sin->sin_port = get_port(optarg);
157 src_sin->sin_port = htons(src_sin->sin_port);
158 n = inet_pton(AF_INET, optarg, &src_sin->sin_addr);
4fa8e46e 159 if (n == 0)
391741ec 160 errx(1, "-s: invalid inet address: %s", optarg);
4fa8e46e 161 else if (n < 0)
391741ec 162 err(1, "-s: %s", optarg);
4fa8e46e
SZ
163 arg_mask |= INSRC_MASK;
164 break;
165
166 case 'e':
167 strcpy(eaddr_str, "if0.");
168 strlcpy(&eaddr_str[strlen("if0.")], optarg,
391741ec 169 sizeof(eaddr_str) - strlen("if0."));
4fa8e46e
SZ
170
171 memset(&sdl, 0, sizeof(sdl));
172 sdl.sdl_len = sizeof(sdl);
3618da85 173 link_addr(eaddr_str, &sdl);
4fa8e46e
SZ
174 bcopy(LLADDR(&sdl), sa->sa_data, ETHER_ADDR_LEN);
175 arg_mask |= EADDR_MASK;
4fa8e46e
SZ
176 break;
177
178 case 'i':
179 strlcpy(conf.pc_ifname, optarg, sizeof(conf.pc_ifname));
180 arg_mask |= IFACE_MASK;
181 break;
182
4fa8e46e
SZ
183 case 'm':
184 conf.pc_datalen = atoi(optarg);
185 arg_mask |= DATALEN_MASK;
186 break;
187
4fa8e46e
SZ
188 case 'l':
189 conf.pc_duration = atoi(optarg);
190 arg_mask |= DURATION_MASK;
191 break;
192
52be0b30
SZ
193 case 'D':
194 dev = optarg;
195 break;
196
391741ec
SZ
197 default:
198 usage();
4fa8e46e
SZ
199 }
200 }
201
202 if ((arg_mask & MASK_NEEDED) != MASK_NEEDED)
203 usage();
204
52be0b30 205 fd = open(dev, O_RDONLY);
4fa8e46e 206 if (fd < 0)
52be0b30 207 err(1, "open(%s)", dev);
4fa8e46e
SZ
208
209 if (ioctl(fd, PKTGENSCONF, &conf) < 0)
210 err(1, "ioctl(PKTGENSCONF)");
211
212 if (ioctl(fd, PKTGENSTART) < 0)
213 err(1, "ioctl(PKTGENSTART)");
214
215 close(fd);
216 exit(0);
217}