]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/netmap/vale-ctl.c
MFC r339685
[FreeBSD/FreeBSD.git] / tools / tools / netmap / vale-ctl.c
1 /*
2  * Copyright (C) 2013-2014 Michio Honda. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *   1. Redistributions of source code must retain the above copyright
8  *      notice, this list of conditions and the following disclaimer.
9  *   2. Redistributions in binary form must reproduce the above copyright
10  *      notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 /* $FreeBSD$ */
27
28 #define NETMAP_WITH_LIBS
29 #include <net/netmap_user.h>
30 #include <net/netmap.h>
31
32 #include <errno.h>
33 #include <stdio.h>
34 #include <inttypes.h>   /* PRI* macros */
35 #include <string.h>     /* strcmp */
36 #include <fcntl.h>      /* open */
37 #include <unistd.h>     /* close */
38 #include <sys/ioctl.h>  /* ioctl */
39 #include <sys/param.h>
40 #include <sys/socket.h> /* apple needs sockaddr */
41 #include <net/if.h>     /* ifreq */
42 #include <libgen.h>     /* basename */
43 #include <stdlib.h>     /* atoi, free */
44
45 /* XXX cut and paste from pkt-gen.c because I'm not sure whether this
46  * program may include nm_util.h
47  */
48 void parse_nmr_config(const char* conf, struct nmreq *nmr)
49 {
50         char *w, *tok;
51         int i, v;
52
53         nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
54         nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
55         if (conf == NULL || ! *conf)
56                 return;
57         w = strdup(conf);
58         for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
59                 v = atoi(tok);
60                 switch (i) {
61                 case 0:
62                         nmr->nr_tx_slots = nmr->nr_rx_slots = v;
63                         break;
64                 case 1:
65                         nmr->nr_rx_slots = v;
66                         break;
67                 case 2:
68                         nmr->nr_tx_rings = nmr->nr_rx_rings = v;
69                         break;
70                 case 3:
71                         nmr->nr_rx_rings = v;
72                         break;
73                 default:
74                         D("ignored config: %s", tok);
75                         break;
76                 }
77         }
78         D("txr %d txd %d rxr %d rxd %d",
79                         nmr->nr_tx_rings, nmr->nr_tx_slots,
80                         nmr->nr_rx_rings, nmr->nr_rx_slots);
81         free(w);
82 }
83
84 static int
85 bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2)
86 {
87         struct nmreq nmr;
88         int error = 0;
89         int fd = open("/dev/netmap", O_RDWR);
90
91         if (fd == -1) {
92                 D("Unable to open /dev/netmap");
93                 return -1;
94         }
95
96         bzero(&nmr, sizeof(nmr));
97         nmr.nr_version = NETMAP_API;
98         if (name != NULL) /* might be NULL */
99                 strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)-1);
100         nmr.nr_cmd = nr_cmd;
101         parse_nmr_config(nmr_config, &nmr);
102         nmr.nr_arg2 = nr_arg2;
103
104         switch (nr_cmd) {
105         case NETMAP_BDG_DELIF:
106         case NETMAP_BDG_NEWIF:
107                 error = ioctl(fd, NIOCREGIF, &nmr);
108                 if (error == -1) {
109                         ND("Unable to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name);
110                         perror(name);
111                 } else {
112                         ND("Success to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name);
113                 }
114                 break;
115         case NETMAP_BDG_ATTACH:
116         case NETMAP_BDG_DETACH:
117                 nmr.nr_flags = NR_REG_ALL_NIC;
118                 if (nr_arg && nr_arg != NETMAP_BDG_HOST) {
119                         nmr.nr_flags = NR_REG_NIC_SW;
120                         nr_arg = 0;
121                 }
122                 nmr.nr_arg1 = nr_arg;
123                 error = ioctl(fd, NIOCREGIF, &nmr);
124                 if (error == -1) {
125                         ND("Unable to %s %s to the bridge", nr_cmd ==
126                             NETMAP_BDG_DETACH?"detach":"attach", name);
127                         perror(name);
128                 } else
129                         ND("Success to %s %s to the bridge", nr_cmd ==
130                             NETMAP_BDG_DETACH?"detach":"attach", name);
131                 break;
132
133         case NETMAP_BDG_LIST:
134                 if (strlen(nmr.nr_name)) { /* name to bridge/port info */
135                         error = ioctl(fd, NIOCGINFO, &nmr);
136                         if (error) {
137                                 ND("Unable to obtain info for %s", name);
138                                 perror(name);
139                         } else
140                                 D("%s at bridge:%d port:%d", name, nmr.nr_arg1,
141                                     nmr.nr_arg2);
142                         break;
143                 }
144
145                 /* scan all the bridges and ports */
146                 nmr.nr_arg1 = nmr.nr_arg2 = 0;
147                 for (; !ioctl(fd, NIOCGINFO, &nmr); nmr.nr_arg2++) {
148                         D("bridge:%d port:%d %s", nmr.nr_arg1, nmr.nr_arg2,
149                             nmr.nr_name);
150                         nmr.nr_name[0] = '\0';
151                 }
152
153                 break;
154
155         case NETMAP_BDG_POLLING_ON:
156         case NETMAP_BDG_POLLING_OFF:
157                 /* We reuse nmreq fields as follows:
158                  *   nr_tx_slots: 0 and non-zero indicate REG_ALL_NIC
159                  *                REG_ONE_NIC, respectively.
160                  *   nr_rx_slots: CPU core index. This also indicates the
161                  *                first queue in the case of REG_ONE_NIC
162                  *   nr_tx_rings: (REG_ONE_NIC only) indicates the
163                  *                number of CPU cores or the last queue
164                  */
165                 nmr.nr_flags |= nmr.nr_tx_slots ?
166                         NR_REG_ONE_NIC : NR_REG_ALL_NIC;
167                 nmr.nr_ringid = nmr.nr_rx_slots;
168                 /* number of cores/rings */
169                 if (nmr.nr_flags == NR_REG_ALL_NIC)
170                         nmr.nr_arg1 = 1;
171                 else
172                         nmr.nr_arg1 = nmr.nr_tx_rings;
173
174                 error = ioctl(fd, NIOCREGIF, &nmr);
175                 if (!error)
176                         D("polling on %s %s", nmr.nr_name,
177                                 nr_cmd == NETMAP_BDG_POLLING_ON ?
178                                 "started" : "stopped");
179                 else
180                         D("polling on %s %s (err %d)", nmr.nr_name,
181                                 nr_cmd == NETMAP_BDG_POLLING_ON ?
182                                 "couldn't start" : "couldn't stop", error);
183                 break;
184
185         default: /* GINFO */
186                 nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0;
187                 error = ioctl(fd, NIOCGINFO, &nmr);
188                 if (error) {
189                         ND("Unable to get if info for %s", name);
190                         perror(name);
191                 } else
192                         D("%s: %d queues.", name, nmr.nr_rx_rings);
193                 break;
194         }
195         close(fd);
196         return error;
197 }
198
199 static void
200 usage(int errcode)
201 {
202         fprintf(stderr,
203             "Usage:\n"
204             "vale-ctl arguments\n"
205             "\t-g interface     interface name to get info\n"
206             "\t-d interface     interface name to be detached\n"
207             "\t-a interface     interface name to be attached\n"
208             "\t-h interface     interface name to be attached with the host stack\n"
209             "\t-n interface     interface name to be created\n"
210             "\t-r interface     interface name to be deleted\n"
211             "\t-l list all or specified bridge's interfaces (default)\n"
212             "\t-C string ring/slot setting of an interface creating by -n\n"
213             "\t-p interface start polling. Additional -C x,y,z configures\n"
214             "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n"
215             "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n"
216             "\t\t z: (ONE_NIC only) num of total cores/rings\n"
217             "\t-P interface stop polling\n"
218             "\t-m memid to use when creating a new interface\n");
219         exit(errcode);
220 }
221
222 int
223 main(int argc, char *argv[])
224 {
225         int ch, nr_cmd = 0, nr_arg = 0;
226         char *name = NULL, *nmr_config = NULL;
227         int nr_arg2 = 0;
228
229         while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:")) != -1) {
230                 if (ch != 'C' && ch != 'm')
231                         name = optarg; /* default */
232                 switch (ch) {
233                 default:
234                         fprintf(stderr, "bad option %c %s", ch, optarg);
235                         usage(-1);
236                         break;
237                 case 'd':
238                         nr_cmd = NETMAP_BDG_DETACH;
239                         break;
240                 case 'a':
241                         nr_cmd = NETMAP_BDG_ATTACH;
242                         break;
243                 case 'h':
244                         nr_cmd = NETMAP_BDG_ATTACH;
245                         nr_arg = NETMAP_BDG_HOST;
246                         break;
247                 case 'n':
248                         nr_cmd = NETMAP_BDG_NEWIF;
249                         break;
250                 case 'r':
251                         nr_cmd = NETMAP_BDG_DELIF;
252                         break;
253                 case 'g':
254                         nr_cmd = 0;
255                         break;
256                 case 'l':
257                         nr_cmd = NETMAP_BDG_LIST;
258                         break;
259                 case 'C':
260                         nmr_config = strdup(optarg);
261                         break;
262                 case 'p':
263                         nr_cmd = NETMAP_BDG_POLLING_ON;
264                         break;
265                 case 'P':
266                         nr_cmd = NETMAP_BDG_POLLING_OFF;
267                         break;
268                 case 'm':
269                         nr_arg2 = atoi(optarg);
270                         break;
271                 }
272         }
273         if (optind != argc) {
274                 // fprintf(stderr, "optind %d argc %d\n", optind, argc);
275                 usage(-1);
276         }
277         if (argc == 1) {
278                 nr_cmd = NETMAP_BDG_LIST;
279                 name = NULL;
280         }
281         return bdg_ctl(name, nr_cmd, nr_arg, nmr_config, nr_arg2) ? 1 : 0;
282 }