pktgenctl: Allow pktgen device to be specified
[dragonfly.git] / tools / tools / netrate / pktgenctl / pktgenctl.c
1 /*
2  * Copyright (c) 2012 The DragonFly Project.  All rights reserved.
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.
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
57 #define DEFAULT_PORT    3000
58
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
65
66 #define MASK_NEEDED     (INDST_MASK | INSRC_MASK | EADDR_MASK | IFACE_MASK)
67
68 static void
69 usage(void)
70 {
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 "
75             "[-m data_len] [-l duration] [-D dev]\n");
76         exit(1);
77 }
78
79 static int
80 get_port(char *str)
81 {
82         char *p;
83
84         p = strchr(str, ':');
85         if (p == NULL) {
86                 return DEFAULT_PORT;
87         } else {
88                 *p = '\0';
89                 ++p;
90                 return atoi(p);
91         }
92 }
93
94 int
95 main(int argc, char *argv[])
96 {
97         struct pktgen_conf conf;
98         struct sockaddr *sa;
99         struct sockaddr_in *src_sin, *dst_sin;
100         struct sockaddr_dl sdl;
101         char eaddr_str[32];
102         uint32_t arg_mask = 0;
103         int fd, c, n, ndst_alloc;
104         const char *dev;
105
106         dev = PKTGEN_DEVPATH;
107
108         memset(&conf, 0, sizeof(conf));
109
110         conf.pc_duration = 10;
111         conf.pc_datalen = 18;
112
113         sa = &conf.pc_dst_lladdr;
114         sa->sa_family = AF_LINK;
115         sa->sa_len = ETHER_ADDR_LEN;
116
117         src_sin = &conf.pc_src;
118         src_sin->sin_family = AF_INET;
119
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;
126         while ((c = getopt(argc, argv, "d:s:e:i:m:l:D:")) != -1) {
127                 switch (c) {
128                 case 'd':
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);
148                         if (n == 0)
149                                 errx(1, "-d: invalid inet address: %s", optarg);
150                         else if (n < 0)
151                                 err(1, "-d: %s", optarg);
152                         arg_mask |= INDST_MASK;
153                         break;
154
155                 case 's':
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);
159                         if (n == 0)
160                                 errx(1, "-s: invalid inet address: %s", optarg);
161                         else if (n < 0)
162                                 err(1, "-s: %s", optarg);
163                         arg_mask |= INSRC_MASK;
164                         break;
165
166                 case 'e':
167                         strcpy(eaddr_str, "if0.");
168                         strlcpy(&eaddr_str[strlen("if0.")], optarg,
169                             sizeof(eaddr_str) - strlen("if0."));
170
171                         memset(&sdl, 0, sizeof(sdl));
172                         sdl.sdl_len = sizeof(sdl);
173                         link_addr(eaddr_str, &sdl);
174                         bcopy(LLADDR(&sdl), sa->sa_data, ETHER_ADDR_LEN);
175                         arg_mask |= EADDR_MASK;
176                         break;
177
178                 case 'i':
179                         strlcpy(conf.pc_ifname, optarg, sizeof(conf.pc_ifname));
180                         arg_mask |= IFACE_MASK;
181                         break;
182
183                 case 'm':
184                         conf.pc_datalen = atoi(optarg);
185                         arg_mask |= DATALEN_MASK;
186                         break;
187
188                 case 'l':
189                         conf.pc_duration = atoi(optarg);
190                         arg_mask |= DURATION_MASK;
191                         break;
192
193                 case 'D':
194                         dev = optarg;
195                         break;
196
197                 default:
198                         usage();
199                 }
200         }
201
202         if ((arg_mask & MASK_NEEDED) != MASK_NEEDED)
203                 usage();
204
205         fd = open(dev, O_RDONLY);
206         if (fd < 0)
207                 err(1, "open(%s)", dev);
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 }