kernel - Major bridging functionality completed
[dragonfly.git] / sbin / ifconfig / ifbridge.c
CommitLineData
ca74a0a2
SZ
1/*-
2 * Copyright 2001 Wasabi Systems, Inc.
3 * All rights reserved.
4 *
5 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
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 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project by
18 * Wasabi Systems, Inc.
19 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
20 * or promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * $FreeBSD: src/sbin/ifconfig/ifbridge.c,v 1.1.2.2 2005/12/28 04:12:58 thompsa Exp $
ca74a0a2
SZ
36 */
37
38#include <sys/param.h>
39#include <sys/ioctl.h>
40#include <sys/socket.h>
41#include <sys/sockio.h>
42
43#include <stdlib.h>
44#include <unistd.h>
45
46#include <net/ethernet.h>
47#include <net/if.h>
48#include <net/bridge/if_bridgevar.h>
49#include <net/route.h>
50
51#include <ctype.h>
52#include <stdio.h>
53#include <string.h>
54#include <stdlib.h>
55#include <unistd.h>
56#include <err.h>
57#include <errno.h>
58
59#include "ifconfig.h"
60
61static int
62get_val(const char *cp, u_long *valp)
63{
64 char *endptr;
65 u_long val;
66
67 errno = 0;
68 val = strtoul(cp, &endptr, 0);
69 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
70 return (-1);
71
72 *valp = val;
73 return (0);
74}
75
76static int
77do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
78{
79 struct ifdrv ifd;
80
81 memset(&ifd, 0, sizeof(ifd));
82
83 strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
84 ifd.ifd_cmd = op;
85 ifd.ifd_len = argsize;
86 ifd.ifd_data = arg;
87
88 return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
89}
90
91static void
92do_bridgeflag(int sock, const char *ifs, int flag, int set)
93{
94 struct ifbreq req;
95
96 strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
97
98 if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
99 err(1, "unable to get bridge flags");
100
101 if (set)
102 req.ifbr_ifsflags |= flag;
103 else
104 req.ifbr_ifsflags &= ~flag;
105
106 if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
107 err(1, "unable to set bridge flags");
108}
109
110static void
111bridge_interfaces(int s, const char *prefix)
112{
113 static const char *stpstates[] = {
114 "disabled",
115 "listening",
116 "learning",
117 "forwarding",
118 "blocking",
3677aae9 119 "blocking (link1)"
ca74a0a2
SZ
120 };
121 struct ifbifconf bifc;
122 struct ifbreq *req;
123 char *inbuf = NULL, *ninbuf;
124 char *p, *pad;
125 int i, len = 8192;
126
127 pad = strdup(prefix);
128 if (pad == NULL)
129 err(1, "strdup");
130 /* replace the prefix with whitespace */
131 for (p = pad; *p != '\0'; p++) {
132 if(isprint(*p))
133 *p = ' ';
134 }
135
136 for (;;) {
137 ninbuf = realloc(inbuf, len);
138 if (ninbuf == NULL)
139 err(1, "unable to allocate interface buffer");
140 bifc.ifbic_len = len;
141 bifc.ifbic_buf = inbuf = ninbuf;
142 if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
143 err(1, "unable to get interface list");
144 if ((bifc.ifbic_len + sizeof(*req)) < len)
145 break;
146 len *= 2;
147 }
148
149 for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
150 req = bifc.ifbic_req + i;
151 printf("%s%s ", prefix, req->ifbr_ifsname);
152 printb("flags", req->ifbr_ifsflags, IFBIFBITS);
153 printf("\n");
154
155 if (req->ifbr_ifsflags & IFBIF_STP) {
156 printf("%s", pad);
157 printf("port %u priority %u",
158 req->ifbr_portno, req->ifbr_priority);
159 printf(" path cost %u", req->ifbr_path_cost);
160 if (req->ifbr_state <
161 sizeof(stpstates) / sizeof(stpstates[0]))
162 printf(" %s", stpstates[req->ifbr_state]);
163 else
164 printf(" <unknown state %d>",
165 req->ifbr_state);
166 printf("\n");
3677aae9
MD
167 printf("%sdesignated root: %016jx\n",
168 pad, (intmax_t)req->ifbr_designated_root);
169 printf("%sdesignated bridge: %016jx\n",
170 pad, (intmax_t)req->ifbr_designated_bridge);
171 printf("%sdesignated cost: %u\n",
172 pad, req->ifbr_designated_cost);
173 printf("%sdesignated port: %u\n",
174 pad, req->ifbr_designated_port);
70d9a675
MD
175 if (verbose) {
176 printf("%speer root: %016jx\n",
177 pad, (intmax_t)req->ifbr_peer_root);
178 printf("%speer bridge: %016jx\n",
179 pad, (intmax_t)req->ifbr_peer_bridge);
180 printf("%speer cost: %u\n",
181 pad, req->ifbr_peer_cost);
182 printf("%speer port: %u\n",
183 pad, req->ifbr_peer_port);
184 }
ca74a0a2
SZ
185 }
186 }
187
188 free(inbuf);
189}
190
191static void
192bridge_addresses(int s, const char *prefix)
193{
194 struct ifbaconf ifbac;
195 struct ifbareq *ifba;
196 char *inbuf = NULL, *ninbuf;
197 int i, len = 8192;
198 struct ether_addr ea;
199
200 for (;;) {
201 ninbuf = realloc(inbuf, len);
202 if (ninbuf == NULL)
203 err(1, "unable to allocate address buffer");
204 ifbac.ifbac_len = len;
205 ifbac.ifbac_buf = inbuf = ninbuf;
206 if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
207 err(1, "unable to get address cache");
208 if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
209 break;
210 len *= 2;
211 }
212
213 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
214 ifba = ifbac.ifbac_req + i;
215 memcpy(ea.octet, ifba->ifba_dst,
216 sizeof(ea.octet));
217 printf("%s%s %s %lu ", prefix, ether_ntoa(&ea),
218 ifba->ifba_ifsname, ifba->ifba_expire);
219 printb("flags", ifba->ifba_flags, IFBAFBITS);
220 printf("\n");
221 }
222
223 free(inbuf);
224}
225
226static void
227bridge_status(int s)
228{
229 struct ifbrparam param;
230 u_int16_t pri;
231 u_int8_t ht, fd, ma;
232
233 if (do_cmd(s, BRDGGPRI, &param, sizeof(param), 0) < 0)
234 return;
235 pri = param.ifbrp_prio;
236
237 if (do_cmd(s, BRDGGHT, &param, sizeof(param), 0) < 0)
238 return;
239 ht = param.ifbrp_hellotime;
240
241 if (do_cmd(s, BRDGGFD, &param, sizeof(param), 0) < 0)
242 return;
243 fd = param.ifbrp_fwddelay;
244
245 if (do_cmd(s, BRDGGMA, &param, sizeof(param), 0) < 0)
246 return;
247 ma = param.ifbrp_maxage;
248
249 printf("\tpriority %u hellotime %u fwddelay %u maxage %u\n",
250 pri, ht, fd, ma);
251
252 bridge_interfaces(s, "\tmember: ");
253
254 return;
255
256}
257
258static void
259setbridge_add(const char *val, int d, int s, const struct afswtch *afp)
260{
261 struct ifbreq req;
262
263 memset(&req, 0, sizeof(req));
264 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
265 if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0)
266 err(1, "BRDGADD %s", val);
267}
268
269static void
270setbridge_delete(const char *val, int d, int s, const struct afswtch *afp)
271{
272 struct ifbreq req;
273
274 memset(&req, 0, sizeof(req));
275 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
276 if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0)
277 err(1, "BRDGDEL %s", val);
278}
279
280static void
281setbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
282{
283
284 do_bridgeflag(s, val, IFBIF_DISCOVER, 1);
285}
286
287static void
288unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
289{
290
291 do_bridgeflag(s, val, IFBIF_DISCOVER, 0);
292}
293
294static void
295setbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
296{
297
298 do_bridgeflag(s, val, IFBIF_LEARNING, 1);
299}
300
301static void
302unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
303{
304
305 do_bridgeflag(s, val, IFBIF_LEARNING, 0);
306}
307
ca74a0a2
SZ
308static void
309setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
310{
311 struct ifbreq req;
312
313 memset(&req, 0, sizeof(req));
314 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
315 if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0)
316 err(1, "BRDGADDS %s", val);
317}
318
319static void
320unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp)
321{
322 struct ifbreq req;
323
324 memset(&req, 0, sizeof(req));
325 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
326 if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0)
327 err(1, "BRDGDELS %s", val);
328}
ca74a0a2
SZ
329
330static void
331setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
332{
333
334 do_bridgeflag(s, val, IFBIF_STP, 1);
335}
336
337static void
338unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
339{
340
341 do_bridgeflag(s, val, IFBIF_STP, 0);
342}
343
344static void
345setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
346{
347 struct ifbreq req;
348
349 memset(&req, 0, sizeof(req));
350 req.ifbr_ifsflags = IFBF_FLUSHDYN;
351 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
352 err(1, "BRDGFLUSH");
353}
354
355static void
356setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp)
357{
358 struct ifbreq req;
359
360 memset(&req, 0, sizeof(req));
361 req.ifbr_ifsflags = IFBF_FLUSHALL;
362 if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
363 err(1, "BRDGFLUSH");
364}
365
366static void
367setbridge_static(const char *val, const char *mac, int s,
368 const struct afswtch *afp)
369{
370 struct ifbareq req;
371 struct ether_addr *ea;
372
373 memset(&req, 0, sizeof(req));
374 strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
375
376 ea = ether_aton(mac);
377 if (ea == NULL)
378 errx(1, "%s: invalid address: %s", val, mac);
379
380 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
381 req.ifba_flags = IFBAF_STATIC;
382
383 if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
384 err(1, "BRDGSADDR %s", val);
385}
386
387static void
388setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp)
389{
390 struct ifbareq req;
391 struct ether_addr *ea;
392
393 memset(&req, 0, sizeof(req));
394
395 ea = ether_aton(val);
396 if (ea == NULL)
397 errx(1, "invalid address: %s", val);
398
399 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
400
401 if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0)
402 err(1, "BRDGDADDR %s", val);
403}
404
405static void
406getbridge_addr(const char *val, int d, int s, const struct afswtch *afp)
407{
408 bridge_addresses(s, "");
409}
410
411static void
412setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp)
413{
414 struct ifbrparam param;
415 u_long val;
416
417 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
418 errx(1, "invalid value: %s", arg);
419
420 param.ifbrp_csize = val & 0xffffffff;
421
422 if (do_cmd(s, BRDGSCACHE, &param, sizeof(param), 1) < 0)
423 err(1, "BRDGSCACHE %s", arg);
424}
425
426static void
427setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp)
428{
429 struct ifbrparam param;
430 u_long val;
431
432 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
433 errx(1, "invalid value: %s", arg);
434
435 param.ifbrp_hellotime = val & 0xff;
436
437 if (do_cmd(s, BRDGSHT, &param, sizeof(param), 1) < 0)
438 err(1, "BRDGSHT %s", arg);
439}
440
441static void
442setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp)
443{
444 struct ifbrparam param;
445 u_long val;
446
447 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
448 errx(1, "invalid value: %s", arg);
449
450 param.ifbrp_fwddelay = val & 0xff;
451
452 if (do_cmd(s, BRDGSFD, &param, sizeof(param), 1) < 0)
453 err(1, "BRDGSFD %s", arg);
454}
455
456static void
457setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp)
458{
459 struct ifbrparam param;
460 u_long val;
461
462 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
463 errx(1, "invalid value: %s", arg);
464
465 param.ifbrp_maxage = val & 0xff;
466
467 if (do_cmd(s, BRDGSMA, &param, sizeof(param), 1) < 0)
468 err(1, "BRDGSMA %s", arg);
469}
470
471static void
472setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp)
473{
474 struct ifbrparam param;
475 u_long val;
476
477 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
478 errx(1, "invalid value: %s", arg);
479
480 param.ifbrp_prio = val & 0xffff;
481
482 if (do_cmd(s, BRDGSPRI, &param, sizeof(param), 1) < 0)
483 err(1, "BRDGSPRI %s", arg);
484}
485
486static void
487setbridge_ifpriority(const char *ifn, const char *pri, int s,
488 const struct afswtch *afp)
489{
490 struct ifbreq req;
491 u_long val;
492
493 memset(&req, 0, sizeof(req));
494
495 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
496 errx(1, "invalid value: %s", pri);
497
498 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
499 req.ifbr_priority = val & 0xff;
500
501 if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
502 err(1, "BRDGSIFPRIO %s", pri);
503}
504
505static void
506setbridge_ifpathcost(const char *ifn, const char *cost, int s,
507 const struct afswtch *afp)
508{
509 struct ifbreq req;
510 u_long val;
511
512 memset(&req, 0, sizeof(req));
513
514 if (get_val(cost, &val) < 0 || (val & ~0xff) != 0)
515 errx(1, "invalid value: %s", cost);
516
517 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
518 req.ifbr_path_cost = val & 0xffff;
519
520 if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
521 err(1, "BRDGSIFCOST %s", cost);
522}
523
524static void
525setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp)
526{
527 struct ifbrparam param;
528 u_long val;
529
530 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
531 errx(1, "invalid value: %s", arg);
532
533 param.ifbrp_ctime = val & 0xffffffff;
534
535 if (do_cmd(s, BRDGSTO, &param, sizeof(param), 1) < 0)
536 err(1, "BRDGSTO %s", arg);
537}
538
539static struct cmd bridge_cmds[] = {
540 DEF_CMD_ARG("addm", setbridge_add),
541 DEF_CMD_ARG("deletem", setbridge_delete),
542 DEF_CMD_ARG("discover", setbridge_discover),
543 DEF_CMD_ARG("-discover", unsetbridge_discover),
544 DEF_CMD_ARG("learn", setbridge_learn),
545 DEF_CMD_ARG("-learn", unsetbridge_learn),
ca74a0a2
SZ
546 DEF_CMD_ARG("span", setbridge_span),
547 DEF_CMD_ARG("-span", unsetbridge_span),
ca74a0a2
SZ
548 DEF_CMD_ARG("stp", setbridge_stp),
549 DEF_CMD_ARG("-stp", unsetbridge_stp),
550 DEF_CMD("flush", 0, setbridge_flush),
551 DEF_CMD("flushall", 0, setbridge_flushall),
552 DEF_CMD_ARG2("static", setbridge_static),
553 DEF_CMD_ARG("deladdr", setbridge_deladdr),
554 DEF_CMD("addr", 1, getbridge_addr),
555 DEF_CMD_ARG("maxaddr", setbridge_maxaddr),
556 DEF_CMD_ARG("hellotime", setbridge_hellotime),
557 DEF_CMD_ARG("fwddelay", setbridge_fwddelay),
558 DEF_CMD_ARG("maxage", setbridge_maxage),
559 DEF_CMD_ARG("priority", setbridge_priority),
560 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority),
561 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost),
562 DEF_CMD_ARG("timeout", setbridge_timeout),
563};
564static struct afswtch af_bridge = {
565 .af_name = "af_bridge",
566 .af_af = AF_UNSPEC,
567 .af_other_status = bridge_status,
568};
569
754d5cac 570static __constructor(100) void
ca74a0a2
SZ
571bridge_ctor(void)
572{
573#define N(a) (sizeof(a) / sizeof(a[0]))
574 int i;
575
576 for (i = 0; i < N(bridge_cmds); i++)
577 cmd_register(&bridge_cmds[i]);
578 af_register(&af_bridge);
579#undef N
580}