1 /*
2  * Copyright (c) 2008 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  * $DragonFly: src/tools/tools/netrate/pktgenctl/pktgenctl.c,v 1.3 2008/03/29 11:45:46 sephe Exp $
35  */
36 
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/stat.h>
40 #include <sys/socket.h>
41 
42 #include <arpa/inet.h>
43 #include <netinet/in.h>
44 #include <net/if.h>
45 #include <net/if_dl.h>
46 #include <net/ethernet.h>
47 
48 #include <err.h>
49 #include <fcntl.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 
55 #include "pktgen/pktgen.h"
56 
57 #define PKTGEN_DEVPATH	"/dev/pktg0"
58 
59 #define DEFAULT_SPORT	3001
60 #define DEFAULT_DPORT	3000
61 
62 #define INDST_MASK	0x1
63 #define INSRC_MASK	0x2
64 #define EADDR_MASK	0x4
65 #define IFACE_MASK	0x8
66 #define DATALEN_MASK	0x10
67 #define SPORT_MASK	0x20
68 #define DPORT_MASK	0x40
69 #define CPUID_MASK	0x80
70 #define DURATION_MASK	0x100
71 #define YIELD_MASK	0x200
72 
73 #define MASK_NEEDED	(INDST_MASK | INSRC_MASK | EADDR_MASK | IFACE_MASK)
74 
75 static void
76 usage(void)
77 {
78 	fprintf(stderr, "pktgenctl -d dst_inaddr[,ndst] -s src_inaddr[,nsrc] "
79 			"-e (gw_eaddr|dst_eaddr) -i iface "
80 			"[-p src_port[,nsport]] [-P dst_port[,ndport]] "
81 			"[-m data_len] [-c cpuid] [-l duration] [-y yield]\n");
82 	exit(1);
83 }
84 
85 static int
86 get_range(char *str)
87 {
88 	char *ptr;
89 
90 	ptr = strstr(str, ",");
91 	if (ptr == NULL) {
92 		return 0;
93 	} else {
94 		*ptr = '\0';
95 		return atoi(ptr + 1);
96 	}
97 }
98 
99 int
100 main(int argc, char *argv[])
101 {
102 	struct pktgen_conf conf;
103 	struct sockaddr *sa;
104 	struct sockaddr_in *dst_sin, *src_sin;
105 	struct sockaddr_dl sdl;
106 	char eaddr_str[32];
107 	uint32_t arg_mask = 0;
108 	int fd, c, n;
109 
110 	memset(&conf, 0, sizeof(conf));
111 
112 	conf.pc_cpuid = 0;
113 	conf.pc_duration = 10;
114 	conf.pc_datalen = 10;
115 
116 	sa = &conf.pc_dst_lladdr;
117 	sa->sa_family = AF_LINK;
118 	sa->sa_len = ETHER_ADDR_LEN;
119 
120 	dst_sin = &conf.pc_dst;
121 	dst_sin->sin_family = AF_INET;
122 	dst_sin->sin_port = htons(DEFAULT_DPORT);
123 
124 	src_sin = &conf.pc_src;
125 	src_sin->sin_family = AF_INET;
126 	src_sin->sin_port = htons(DEFAULT_SPORT);
127 
128 	while ((c = getopt(argc, argv, "d:s:e:i:p:P:m:c:l:y:")) != -1) {
129 		switch (c) {
130 		case 'd':
131 			conf.pc_ndaddr = get_range(optarg);
132 			n = inet_pton(AF_INET, optarg,
133 				      &dst_sin->sin_addr.s_addr);
134 			if (n == 0)
135 				errx(1, "-d: invalid inet address");
136 			else if (n < 0)
137 				err(1, "-d");
138 			arg_mask |= INDST_MASK;
139 			break;
140 
141 		case 's':
142 			conf.pc_nsaddr = get_range(optarg);
143 			n = inet_pton(AF_INET, optarg,
144 				      &src_sin->sin_addr.s_addr);
145 			if (n == 0)
146 				errx(1, "-s: invalid inet address");
147 			else if (n < 0)
148 				err(1, "-s");
149 			arg_mask |= INSRC_MASK;
150 			break;
151 
152 		case 'e':
153 			strcpy(eaddr_str, "if0.");
154 			strlcpy(&eaddr_str[strlen("if0.")], optarg,
155 				sizeof(eaddr_str) - strlen("if0."));
156 
157 			memset(&sdl, 0, sizeof(sdl));
158 			sdl.sdl_len = sizeof(sdl);
159 			link_addr(eaddr_str, &sdl);
160 			bcopy(LLADDR(&sdl), sa->sa_data, ETHER_ADDR_LEN);
161 			arg_mask |= EADDR_MASK;
162 			break;
163 
164 		case 'i':
165 			strlcpy(conf.pc_ifname, optarg, sizeof(conf.pc_ifname));
166 			arg_mask |= IFACE_MASK;
167 			break;
168 
169 		case 'p':
170 			conf.pc_nsport = get_range(optarg);
171 			src_sin->sin_port = htons(atoi(optarg));
172 			arg_mask |= SPORT_MASK;
173 			break;
174 
175 		case 'P':
176 			conf.pc_ndport = get_range(optarg);
177 			dst_sin->sin_port = htons(atoi(optarg));
178 			arg_mask |= DPORT_MASK;
179 			break;
180 
181 		case 'm':
182 			conf.pc_datalen = atoi(optarg);
183 			arg_mask |= DATALEN_MASK;
184 			break;
185 
186 		case 'c':
187 			conf.pc_cpuid = atoi(optarg);
188 			arg_mask |= CPUID_MASK;
189 			break;
190 
191 		case 'l':
192 			conf.pc_duration = atoi(optarg);
193 			arg_mask |= DURATION_MASK;
194 			break;
195 
196 		case 'y':
197 			conf.pc_yield = atoi(optarg);
198 			arg_mask |= YIELD_MASK;
199 			break;
200 		}
201 	}
202 
203 	if ((arg_mask & MASK_NEEDED) != MASK_NEEDED)
204 		usage();
205 
206 	fd = open(PKTGEN_DEVPATH, O_RDONLY);
207 	if (fd < 0)
208 		err(1, "open(" PKTGEN_DEVPATH ")");
209 
210 	if (ioctl(fd, PKTGENSCONF, &conf) < 0)
211 		err(1, "ioctl(PKTGENSCONF)");
212 
213 	if (ioctl(fd, PKTGENSTART) < 0)
214 		err(1, "ioctl(PKTGENSTART)");
215 
216 	close(fd);
217 	exit(0);
218 }
219