a8891c1bbd0f7a584417afdd06664d423ff6e7cc
[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]\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
105         memset(&conf, 0, sizeof(conf));
106
107         conf.pc_duration = 10;
108         conf.pc_datalen = 18;
109
110         sa = &conf.pc_dst_lladdr;
111         sa->sa_family = AF_LINK;
112         sa->sa_len = ETHER_ADDR_LEN;
113
114         src_sin = &conf.pc_src;
115         src_sin->sin_family = AF_INET;
116
117         ndst_alloc = 1;
118         conf.pc_dst = calloc(ndst_alloc, sizeof(struct sockaddr_in));
119         if (conf.pc_dst == NULL)
120                 err(1, "calloc(%d dst)", ndst_alloc);
121
122         conf.pc_ndst = 0;
123         while ((c = getopt(argc, argv, "d:s:e:i:m:l:")) != -1) {
124                 switch (c) {
125                 case 'd':
126                         if (conf.pc_ndst >= ndst_alloc) {
127                                 void *old = conf.pc_dst;
128                                 int old_ndst_alloc = ndst_alloc;
129
130                                 ndst_alloc *= 2;
131                                 conf.pc_dst = calloc(ndst_alloc,
132                                     sizeof(struct sockaddr_in));
133                                 if (conf.pc_dst == NULL)
134                                         err(1, "calloc(%d dst)", ndst_alloc);
135                                 memcpy(conf.pc_dst, old,
136                                 old_ndst_alloc * sizeof(struct sockaddr_in));
137                                 free(old);
138                         }
139                         dst_sin = &conf.pc_dst[conf.pc_ndst++];
140
141                         dst_sin->sin_family = AF_INET;
142                         dst_sin->sin_port = get_port(optarg);
143                         dst_sin->sin_port = htons(dst_sin->sin_port);
144                         n = inet_pton(AF_INET, optarg, &dst_sin->sin_addr);
145                         if (n == 0)
146                                 errx(1, "-d: invalid inet address: %s", optarg);
147                         else if (n < 0)
148                                 err(1, "-d: %s", optarg);
149                         arg_mask |= INDST_MASK;
150                         break;
151
152                 case 's':
153                         src_sin->sin_port = get_port(optarg);
154                         src_sin->sin_port = htons(src_sin->sin_port);
155                         n = inet_pton(AF_INET, optarg, &src_sin->sin_addr);
156                         if (n == 0)
157                                 errx(1, "-s: invalid inet address: %s", optarg);
158                         else if (n < 0)
159                                 err(1, "-s: %s", optarg);
160                         arg_mask |= INSRC_MASK;
161                         break;
162
163                 case 'e':
164                         strcpy(eaddr_str, "if0.");
165                         strlcpy(&eaddr_str[strlen("if0.")], optarg,
166                             sizeof(eaddr_str) - strlen("if0."));
167
168                         memset(&sdl, 0, sizeof(sdl));
169                         sdl.sdl_len = sizeof(sdl);
170                         link_addr(eaddr_str, &sdl);
171                         bcopy(LLADDR(&sdl), sa->sa_data, ETHER_ADDR_LEN);
172                         arg_mask |= EADDR_MASK;
173                         break;
174
175                 case 'i':
176                         strlcpy(conf.pc_ifname, optarg, sizeof(conf.pc_ifname));
177                         arg_mask |= IFACE_MASK;
178                         break;
179
180                 case 'm':
181                         conf.pc_datalen = atoi(optarg);
182                         arg_mask |= DATALEN_MASK;
183                         break;
184
185                 case 'l':
186                         conf.pc_duration = atoi(optarg);
187                         arg_mask |= DURATION_MASK;
188                         break;
189
190                 default:
191                         usage();
192                 }
193         }
194
195         if ((arg_mask & MASK_NEEDED) != MASK_NEEDED)
196                 usage();
197
198         fd = open(PKTGEN_DEVPATH, O_RDONLY);
199         if (fd < 0)
200                 err(1, "open(" PKTGEN_DEVPATH ")");
201
202         if (ioctl(fd, PKTGENSCONF, &conf) < 0)
203                 err(1, "ioctl(PKTGENSCONF)");
204
205         if (ioctl(fd, PKTGENSTART) < 0)
206                 err(1, "ioctl(PKTGENSTART)");
207
208         close(fd);
209         exit(0);
210 }