Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ifconfig/ifbridge.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-4-Clause
3
*
4
* Copyright 2001 Wasabi Systems, Inc.
5
* All rights reserved.
6
*
7
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
* 3. All advertising materials mentioning features or use of this software
18
* must display the following acknowledgement:
19
* This product includes software developed for the NetBSD Project by
20
* Wasabi Systems, Inc.
21
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
22
* or promote products derived from this software without specific prior
23
* written permission.
24
*
25
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
* POSSIBILITY OF SUCH DAMAGE.
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/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 <libifconfig.h>
60
61
#include "ifconfig.h"
62
63
static int parse_vlans(ifbvlan_set_t *set, const char *str);
64
static int get_val(const char *cp, u_long *valp);
65
static int get_vlan_id(const char *cp, ether_vlanid_t *valp);
66
67
static const char *stpstates[] = { STP_STATES };
68
static const char *stpproto[] = { STP_PROTOS };
69
static const char *stproles[] = { STP_ROLES };
70
71
static int
72
get_val(const char *cp, u_long *valp)
73
{
74
char *endptr;
75
u_long val;
76
77
errno = 0;
78
val = strtoul(cp, &endptr, 0);
79
if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
80
return (-1);
81
82
*valp = val;
83
return (0);
84
}
85
86
static int
87
get_vlan_id(const char *cp, ether_vlanid_t *valp)
88
{
89
u_long val;
90
91
if (get_val(cp, &val) == -1)
92
return (-1);
93
if (val < DOT1Q_VID_MIN || val > DOT1Q_VID_MAX)
94
return (-1);
95
96
*valp = (ether_vlanid_t)val;
97
return (0);
98
}
99
100
static int
101
do_cmd(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set)
102
{
103
struct ifdrv ifd = {};
104
105
strlcpy(ifd.ifd_name, ctx->ifname, sizeof(ifd.ifd_name));
106
ifd.ifd_cmd = op;
107
ifd.ifd_len = argsize;
108
ifd.ifd_data = arg;
109
110
return (ioctl_ctx(ctx, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
111
}
112
113
static void
114
do_bridgeflag(if_ctx *ctx, const char *ifs, int flag, int set)
115
{
116
struct ifbreq req;
117
118
strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
119
120
if (do_cmd(ctx, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
121
err(1, "unable to get bridge flags");
122
123
if (set)
124
req.ifbr_ifsflags |= flag;
125
else
126
req.ifbr_ifsflags &= ~flag;
127
128
if (do_cmd(ctx, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
129
err(1, "unable to set bridge flags");
130
}
131
132
static void
133
bridge_addresses(if_ctx *ctx, const char *prefix)
134
{
135
struct ifbaconf ifbac;
136
struct ifbareq *ifba;
137
char *inbuf = NULL, *ninbuf;
138
size_t len = 8192;
139
struct ether_addr ea;
140
141
for (;;) {
142
ninbuf = realloc(inbuf, len);
143
if (ninbuf == NULL)
144
err(1, "unable to allocate address buffer");
145
ifbac.ifbac_len = len;
146
ifbac.ifbac_buf = inbuf = ninbuf;
147
if (do_cmd(ctx, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
148
err(1, "unable to get address cache");
149
if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
150
break;
151
len *= 2;
152
}
153
154
for (unsigned long i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
155
ifba = ifbac.ifbac_req + i;
156
memcpy(ea.octet, ifba->ifba_dst,
157
sizeof(ea.octet));
158
printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
159
ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
160
printb("flags", ifba->ifba_flags, IFBAFBITS);
161
printf("\n");
162
}
163
164
free(inbuf);
165
}
166
167
static void
168
print_vlans(ifbvlan_set_t *vlans)
169
{
170
unsigned printed = 0;
171
172
for (unsigned vlan = DOT1Q_VID_MIN; vlan <= DOT1Q_VID_MAX;) {
173
unsigned last;
174
175
if (!BRVLAN_TEST(vlans, vlan)) {
176
++vlan;
177
continue;
178
}
179
180
last = vlan;
181
while (last < DOT1Q_VID_MAX && BRVLAN_TEST(vlans, last + 1))
182
++last;
183
184
if (printed == 0)
185
printf(" tagged ");
186
else
187
printf(",");
188
189
printf("%u", vlan);
190
if (last != vlan)
191
printf("-%u", last);
192
++printed;
193
vlan = last + 1;
194
}
195
}
196
197
static char const *
198
vlan_proto_name(uint16_t proto)
199
{
200
switch (proto) {
201
case 0:
202
return "none";
203
case ETHERTYPE_VLAN:
204
return "802.1q";
205
case ETHERTYPE_QINQ:
206
return "802.1ad";
207
default:
208
return "unknown";
209
}
210
}
211
212
static void
213
bridge_status(if_ctx *ctx)
214
{
215
struct ifconfig_bridge_status *bridge;
216
struct ifbropreq *params;
217
const char *pad, *prefix;
218
uint8_t lladdr[ETHER_ADDR_LEN];
219
uint16_t bprio;
220
221
if (ifconfig_bridge_get_bridge_status(lifh, ctx->ifname, &bridge) == -1)
222
return;
223
224
params = bridge->params;
225
226
PV2ID(params->ifbop_bridgeid, bprio, lladdr);
227
printf("\tid %s priority %u hellotime %u fwddelay %u\n",
228
ether_ntoa((struct ether_addr *)lladdr),
229
params->ifbop_priority,
230
params->ifbop_hellotime,
231
params->ifbop_fwddelay);
232
printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
233
params->ifbop_maxage,
234
params->ifbop_holdcount,
235
stpproto[params->ifbop_protocol],
236
bridge->cache_size,
237
bridge->cache_lifetime);
238
PV2ID(params->ifbop_designated_root, bprio, lladdr);
239
printf("\troot id %s priority %d ifcost %u port %u\n",
240
ether_ntoa((struct ether_addr *)lladdr),
241
bprio,
242
params->ifbop_root_path_cost,
243
params->ifbop_root_port & 0xfff);
244
245
printb("\tbridge flags", bridge->flags, IFBRFBITS);
246
if (bridge->defpvid)
247
printf(" defuntagged=%u", (unsigned) bridge->defpvid);
248
printf("\n");
249
250
prefix = "\tmember: ";
251
pad = "\t ";
252
for (size_t i = 0; i < bridge->members_count; ++i) {
253
struct ifbreq *member = &bridge->members[i];
254
255
printf("%s%s ", prefix, member->ifbr_ifsname);
256
printb("flags", member->ifbr_ifsflags, IFBIFBITS);
257
printf("\n%s", pad);
258
if (member->ifbr_addrmax != 0)
259
printf("ifmaxaddr %u ", member->ifbr_addrmax);
260
printf("port %u priority %u path cost %u",
261
member->ifbr_portno,
262
member->ifbr_priority,
263
member->ifbr_path_cost);
264
if (member->ifbr_ifsflags & IFBIF_STP) {
265
uint8_t proto = member->ifbr_proto;
266
uint8_t role = member->ifbr_role;
267
uint8_t state = member->ifbr_state;
268
269
if (proto < nitems(stpproto))
270
printf(" proto %s", stpproto[proto]);
271
else
272
printf(" <unknown proto %d>", proto);
273
printf("\n%s", pad);
274
if (role < nitems(stproles))
275
printf("role %s", stproles[role]);
276
else
277
printf("<unknown role %d>", role);
278
if (state < nitems(stpstates))
279
printf(" state %s", stpstates[state]);
280
else
281
printf(" <unknown state %d>", state);
282
}
283
if (member->ifbr_vlanproto != 0)
284
printf(" vlan protocol %s",
285
vlan_proto_name(member->ifbr_vlanproto));
286
if (member->ifbr_pvid != 0)
287
printf(" untagged %u", (unsigned)member->ifbr_pvid);
288
print_vlans(&bridge->member_vlans[i]);
289
printf("\n");
290
}
291
292
ifconfig_bridge_free_bridge_status(bridge);
293
}
294
295
static int
296
setbridge_add(if_ctx *ctx, int argc, const char *const *argv)
297
{
298
struct ifbreq req;
299
struct ifbif_vlan_req vlreq;
300
int oargc = argc;
301
302
memset(&req, 0, sizeof(req));
303
memset(&vlreq, 0, sizeof(vlreq));
304
305
if (argc < 1)
306
errx(1, "usage: addm <interface> [opts ...]");
307
308
strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname));
309
--argc; ++argv;
310
311
while (argc) {
312
if (strcmp(argv[0], "untagged") == 0) {
313
if (argc < 2)
314
errx(1, "usage: untagged <vlan id>");
315
316
if (get_vlan_id(argv[1], &req.ifbr_pvid) < 0)
317
errx(1, "invalid VLAN identifier: %s", argv[1]);
318
319
argc -= 2;
320
argv += 2;
321
} else if (strcmp(argv[0], "tagged") == 0) {
322
if (argc < 2)
323
errx(1, "usage: tagged <vlan set>");
324
325
vlreq.bv_op = BRDG_VLAN_OP_SET;
326
strlcpy(vlreq.bv_ifname, req.ifbr_ifsname,
327
sizeof(vlreq.bv_ifname));
328
if (parse_vlans(&vlreq.bv_set, argv[1]) != 0)
329
errx(1, "invalid vlan set: %s", argv[1]);
330
331
argc -= 2;
332
argv += 2;
333
} else {
334
break;
335
}
336
}
337
338
if (do_cmd(ctx, BRDGADD, &req, sizeof(req), 1) < 0)
339
err(1, "BRDGADD %s", req.ifbr_ifsname);
340
341
if (req.ifbr_pvid != 0 &&
342
do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
343
err(1, "BRDGSIFPVID %s %u", req.ifbr_ifsname,
344
(unsigned)req.ifbr_pvid);
345
346
if (vlreq.bv_op != 0 &&
347
do_cmd(ctx, BRDGSIFVLANSET, &vlreq, sizeof(vlreq), 1) < 0)
348
err(1, "BRDGSIFVLANSET %s", req.ifbr_ifsname);
349
350
return (oargc - argc);
351
}
352
353
static void
354
setbridge_delete(if_ctx *ctx, const char *val, int dummy __unused)
355
{
356
struct ifbreq req;
357
358
memset(&req, 0, sizeof(req));
359
strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
360
if (do_cmd(ctx, BRDGDEL, &req, sizeof(req), 1) < 0)
361
err(1, "BRDGDEL %s", val);
362
}
363
364
static void
365
setbridge_discover(if_ctx *ctx, const char *val, int dummy __unused)
366
{
367
368
do_bridgeflag(ctx, val, IFBIF_DISCOVER, 1);
369
}
370
371
static void
372
unsetbridge_discover(if_ctx *ctx, const char *val, int dummy __unused)
373
{
374
375
do_bridgeflag(ctx, val, IFBIF_DISCOVER, 0);
376
}
377
378
static void
379
setbridge_learn(if_ctx *ctx, const char *val, int dummy __unused)
380
{
381
382
do_bridgeflag(ctx, val, IFBIF_LEARNING, 1);
383
}
384
385
static void
386
unsetbridge_learn(if_ctx *ctx, const char *val, int dummy __unused)
387
{
388
389
do_bridgeflag(ctx, val, IFBIF_LEARNING, 0);
390
}
391
392
static void
393
setbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused)
394
{
395
396
do_bridgeflag(ctx, val, IFBIF_STICKY, 1);
397
}
398
399
static void
400
unsetbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused)
401
{
402
403
do_bridgeflag(ctx, val, IFBIF_STICKY, 0);
404
}
405
406
static void
407
setbridge_span(if_ctx *ctx, const char *val, int dummy __unused)
408
{
409
struct ifbreq req;
410
411
memset(&req, 0, sizeof(req));
412
strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
413
if (do_cmd(ctx, BRDGADDS, &req, sizeof(req), 1) < 0)
414
err(1, "BRDGADDS %s", val);
415
}
416
417
static void
418
unsetbridge_span(if_ctx *ctx, const char *val, int dummy __unused)
419
{
420
struct ifbreq req;
421
422
memset(&req, 0, sizeof(req));
423
strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
424
if (do_cmd(ctx, BRDGDELS, &req, sizeof(req), 1) < 0)
425
err(1, "BRDGDELS %s", val);
426
}
427
428
static void
429
setbridge_stp(if_ctx *ctx, const char *val, int dummy __unused)
430
{
431
432
do_bridgeflag(ctx, val, IFBIF_STP, 1);
433
}
434
435
static void
436
unsetbridge_stp(if_ctx *ctx, const char *val, int dummy __unused)
437
{
438
439
do_bridgeflag(ctx, val, IFBIF_STP, 0);
440
}
441
442
static void
443
setbridge_edge(if_ctx *ctx, const char *val, int dummy __unused)
444
{
445
do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 1);
446
}
447
448
static void
449
unsetbridge_edge(if_ctx *ctx, const char *val, int dummy __unused)
450
{
451
do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 0);
452
}
453
454
static void
455
setbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused)
456
{
457
do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 1);
458
}
459
460
static void
461
unsetbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused)
462
{
463
do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 0);
464
}
465
466
static void
467
setbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused)
468
{
469
do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 1);
470
}
471
472
static void
473
unsetbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused)
474
{
475
do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 0);
476
}
477
478
static void
479
setbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused)
480
{
481
do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 1);
482
}
483
484
static void
485
unsetbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused)
486
{
487
do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 0);
488
}
489
490
static void
491
setbridge_flush(if_ctx *ctx, const char *val __unused, int dummy __unused)
492
{
493
struct ifbreq req;
494
495
memset(&req, 0, sizeof(req));
496
req.ifbr_ifsflags = IFBF_FLUSHDYN;
497
if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0)
498
err(1, "BRDGFLUSH");
499
}
500
501
static void
502
setbridge_flushall(if_ctx *ctx, const char *val __unused, int dummy __unused)
503
{
504
struct ifbreq req;
505
506
memset(&req, 0, sizeof(req));
507
req.ifbr_ifsflags = IFBF_FLUSHALL;
508
if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0)
509
err(1, "BRDGFLUSH");
510
}
511
512
static int
513
setbridge_static(if_ctx *ctx, int argc, const char *const *argv)
514
{
515
struct ifbareq req;
516
struct ether_addr *ea;
517
int arg;
518
519
if (argc < 2)
520
errx(1, "usage: static <interface> <address> [vlan <id>]");
521
arg = 0;
522
523
memset(&req, 0, sizeof(req));
524
req.ifba_flags = IFBAF_STATIC;
525
526
strlcpy(req.ifba_ifsname, argv[arg], sizeof(req.ifba_ifsname));
527
++arg;
528
529
ea = ether_aton(argv[arg]);
530
if (ea == NULL)
531
errx(1, "invalid address: %s", argv[arg]);
532
memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
533
++arg;
534
535
req.ifba_vlan = 0;
536
if (argc > 2 && strcmp(argv[arg], "vlan") == 0) {
537
if (argc < 3)
538
errx(1, "usage: static <interface> <address> "
539
"[vlan <id>]");
540
++arg;
541
542
if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0)
543
errx(1, "invalid vlan id: %s", argv[arg]);
544
++arg;
545
}
546
547
if (do_cmd(ctx, BRDGSADDR, &req, sizeof(req), 1) < 0)
548
err(1, "BRDGSADDR");
549
return arg;
550
}
551
552
static int
553
setbridge_deladdr(if_ctx *ctx, int argc, const char *const *argv)
554
{
555
struct ifbareq req;
556
struct ether_addr *ea;
557
int arg;
558
559
if (argc < 1)
560
errx(1, "usage: deladdr <address> [vlan <id>]");
561
arg = 0;
562
563
memset(&req, 0, sizeof(req));
564
565
ea = ether_aton(argv[arg]);
566
if (ea == NULL)
567
errx(1, "invalid address: %s", argv[arg]);
568
memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
569
++arg;
570
571
req.ifba_vlan = 0;
572
if (argc >= 2 && strcmp(argv[arg], "vlan") == 0) {
573
if (argc < 3)
574
errx(1, "usage: deladdr <address> [vlan <id>]");
575
++arg;
576
577
if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0)
578
errx(1, "invalid vlan id: %s", argv[arg]);
579
++arg;
580
}
581
582
if (do_cmd(ctx, BRDGDADDR, &req, sizeof(req), 1) < 0)
583
err(1, "BRDGDADDR");
584
585
return arg;
586
}
587
588
static void
589
setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused)
590
{
591
bridge_addresses(ctx, "");
592
}
593
594
static void
595
setbridge_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused)
596
{
597
struct ifbrparam param;
598
u_long val;
599
600
if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
601
errx(1, "invalid value: %s", arg);
602
603
param.ifbrp_csize = val & 0xffffffff;
604
605
if (do_cmd(ctx, BRDGSCACHE, &param, sizeof(param), 1) < 0)
606
err(1, "BRDGSCACHE %s", arg);
607
}
608
609
static void
610
setbridge_hellotime(if_ctx *ctx, const char *arg, int dummy __unused)
611
{
612
struct ifbrparam param;
613
u_long val;
614
615
if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
616
errx(1, "invalid value: %s", arg);
617
618
param.ifbrp_hellotime = val & 0xff;
619
620
if (do_cmd(ctx, BRDGSHT, &param, sizeof(param), 1) < 0)
621
err(1, "BRDGSHT %s", arg);
622
}
623
624
static void
625
setbridge_fwddelay(if_ctx *ctx, const char *arg, int dummy __unused)
626
{
627
struct ifbrparam param;
628
u_long val;
629
630
if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
631
errx(1, "invalid value: %s", arg);
632
633
param.ifbrp_fwddelay = val & 0xff;
634
635
if (do_cmd(ctx, BRDGSFD, &param, sizeof(param), 1) < 0)
636
err(1, "BRDGSFD %s", arg);
637
}
638
639
static void
640
setbridge_maxage(if_ctx *ctx, const char *arg, int dummy __unused)
641
{
642
struct ifbrparam param;
643
u_long val;
644
645
if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
646
errx(1, "invalid value: %s", arg);
647
648
param.ifbrp_maxage = val & 0xff;
649
650
if (do_cmd(ctx, BRDGSMA, &param, sizeof(param), 1) < 0)
651
err(1, "BRDGSMA %s", arg);
652
}
653
654
static void
655
setbridge_priority(if_ctx *ctx, const char *arg, int dummy __unused)
656
{
657
struct ifbrparam param;
658
u_long val;
659
660
if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
661
errx(1, "invalid value: %s", arg);
662
663
param.ifbrp_prio = val & 0xffff;
664
665
if (do_cmd(ctx, BRDGSPRI, &param, sizeof(param), 1) < 0)
666
err(1, "BRDGSPRI %s", arg);
667
}
668
669
static void
670
setbridge_protocol(if_ctx *ctx, const char *arg, int dummy __unused)
671
{
672
struct ifbrparam param;
673
674
if (strcasecmp(arg, "stp") == 0) {
675
param.ifbrp_proto = 0;
676
} else if (strcasecmp(arg, "rstp") == 0) {
677
param.ifbrp_proto = 2;
678
} else {
679
errx(1, "unknown stp protocol");
680
}
681
682
if (do_cmd(ctx, BRDGSPROTO, &param, sizeof(param), 1) < 0)
683
err(1, "BRDGSPROTO %s", arg);
684
}
685
686
static void
687
setbridge_holdcount(if_ctx *ctx, const char *arg, int dummy __unused)
688
{
689
struct ifbrparam param;
690
u_long val;
691
692
if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
693
errx(1, "invalid value: %s", arg);
694
695
param.ifbrp_txhc = val & 0xff;
696
697
if (do_cmd(ctx, BRDGSTXHC, &param, sizeof(param), 1) < 0)
698
err(1, "BRDGSTXHC %s", arg);
699
}
700
701
static void
702
setbridge_ifpriority(if_ctx *ctx, const char *ifn, const char *pri)
703
{
704
struct ifbreq req;
705
u_long val;
706
707
memset(&req, 0, sizeof(req));
708
709
if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
710
errx(1, "invalid value: %s", pri);
711
712
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
713
req.ifbr_priority = val & 0xff;
714
715
if (do_cmd(ctx, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
716
err(1, "BRDGSIFPRIO %s", pri);
717
}
718
719
static void
720
setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost)
721
{
722
struct ifbreq req;
723
u_long val;
724
725
memset(&req, 0, sizeof(req));
726
727
if (get_val(cost, &val) < 0)
728
errx(1, "invalid value: %s", cost);
729
730
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
731
req.ifbr_path_cost = val;
732
733
if (do_cmd(ctx, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
734
err(1, "BRDGSIFCOST %s", cost);
735
}
736
737
static void
738
setbridge_ifuntagged(if_ctx *ctx, const char *ifn, const char *vlanid)
739
{
740
struct ifbreq req;
741
742
memset(&req, 0, sizeof(req));
743
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
744
745
if (get_vlan_id(vlanid, &req.ifbr_pvid) < 0)
746
errx(1, "invalid VLAN identifier: %s", vlanid);
747
748
if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
749
err(1, "BRDGSIFPVID %s", vlanid);
750
}
751
752
static void
753
unsetbridge_ifuntagged(if_ctx *ctx, const char *ifn, int dummy __unused)
754
{
755
struct ifbreq req;
756
757
memset(&req, 0, sizeof(req));
758
759
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
760
req.ifbr_pvid = 0;
761
762
if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
763
err(1, "BRDGSIFPVID");
764
}
765
766
static void
767
setbridge_ifmaxaddr(if_ctx *ctx, const char *ifn, const char *arg)
768
{
769
struct ifbreq req;
770
u_long val;
771
772
memset(&req, 0, sizeof(req));
773
774
if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
775
errx(1, "invalid value: %s", arg);
776
777
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
778
req.ifbr_addrmax = val & 0xffffffff;
779
780
if (do_cmd(ctx, BRDGSIFAMAX, &req, sizeof(req), 1) < 0)
781
err(1, "BRDGSIFAMAX %s", arg);
782
}
783
784
static void
785
setbridge_timeout(if_ctx *ctx, const char *arg, int dummy __unused)
786
{
787
struct ifbrparam param;
788
u_long val;
789
790
if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
791
errx(1, "invalid value: %s", arg);
792
793
param.ifbrp_ctime = val & 0xffffffff;
794
795
if (do_cmd(ctx, BRDGSTO, &param, sizeof(param), 1) < 0)
796
err(1, "BRDGSTO %s", arg);
797
}
798
799
static void
800
setbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
801
{
802
do_bridgeflag(ctx, val, IFBIF_PRIVATE, 1);
803
}
804
805
static void
806
unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
807
{
808
do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0);
809
}
810
811
static int
812
parse_vlans(ifbvlan_set_t *set, const char *str)
813
{
814
char *s, *token;
815
816
/* "none" means the empty vlan set */
817
if (strcmp(str, "none") == 0) {
818
__BIT_ZERO(BRVLAN_SETSIZE, set);
819
return (0);
820
}
821
822
/* "all" means all vlans, except for 0 and 4095 which are reserved */
823
if (strcmp(str, "all") == 0) {
824
__BIT_FILL(BRVLAN_SETSIZE, set);
825
BRVLAN_CLR(set, DOT1Q_VID_NULL);
826
BRVLAN_CLR(set, DOT1Q_VID_RSVD_IMPL);
827
return (0);
828
}
829
830
if ((s = strdup(str)) == NULL)
831
return (-1);
832
833
while ((token = strsep(&s, ",")) != NULL) {
834
unsigned long first, last;
835
char *p, *lastp;
836
837
if ((lastp = strchr(token, '-')) != NULL)
838
*lastp++ = '\0';
839
840
first = last = strtoul(token, &p, 10);
841
if (*p != '\0')
842
goto err;
843
if (first < DOT1Q_VID_MIN || first > DOT1Q_VID_MAX)
844
goto err;
845
846
if (lastp) {
847
last = strtoul(lastp, &p, 10);
848
if (*p != '\0')
849
goto err;
850
if (last < DOT1Q_VID_MIN || last > DOT1Q_VID_MAX ||
851
last < first)
852
goto err;
853
}
854
855
for (unsigned vlan = first; vlan <= last; ++vlan)
856
BRVLAN_SET(set, vlan);
857
}
858
859
free(s);
860
return (0);
861
862
err:
863
free(s);
864
return (-1);
865
}
866
867
static void
868
set_bridge_vlanset(if_ctx *ctx, const char *ifn, const char *vlans, int op)
869
{
870
struct ifbif_vlan_req req;
871
872
memset(&req, 0, sizeof(req));
873
874
if (parse_vlans(&req.bv_set, vlans) != 0)
875
errx(1, "invalid vlan set: %s", vlans);
876
877
strlcpy(req.bv_ifname, ifn, sizeof(req.bv_ifname));
878
req.bv_op = op;
879
880
if (do_cmd(ctx, BRDGSIFVLANSET, &req, sizeof(req), 1) < 0)
881
err(1, "BRDGSIFVLANSET %s", vlans);
882
}
883
884
static void
885
setbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans)
886
{
887
set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_SET);
888
}
889
890
static void
891
addbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans)
892
{
893
set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_ADD);
894
}
895
896
static void
897
delbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans)
898
{
899
set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL);
900
}
901
902
static void
903
setbridge_flags(if_ctx *ctx, const char *val __unused, int newflags)
904
{
905
struct ifbrparam req;
906
907
if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0)
908
err(1, "BRDGGFLAGS");
909
910
req.ifbrp_flags |= (uint32_t)newflags;
911
912
if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0)
913
err(1, "BRDGSFLAGS");
914
}
915
916
static void
917
unsetbridge_flags(if_ctx *ctx, const char *val __unused, int newflags)
918
{
919
struct ifbrparam req;
920
921
if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0)
922
err(1, "BRDGGFLAGS");
923
924
req.ifbrp_flags &= ~(uint32_t)newflags;
925
926
if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0)
927
err(1, "BRDGSFLAGS");
928
}
929
930
static void
931
setbridge_defuntagged(if_ctx *ctx, const char *arg, int dummy __unused)
932
{
933
struct ifbrparam req;
934
935
memset(&req, 0, sizeof(req));
936
if (get_vlan_id(arg, &req.ifbrp_defpvid) < 0)
937
errx(1, "invalid vlan id: %s", arg);
938
939
if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0)
940
err(1, "BRDGSDEFPVID");
941
}
942
943
static void
944
unsetbridge_defuntagged(if_ctx *ctx, const char *val __unused, int dummy __unused)
945
{
946
struct ifbrparam req;
947
948
memset(&req, 0, sizeof(req));
949
req.ifbrp_defpvid = 0;
950
951
if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0)
952
err(1, "BRDGSDEFPVID");
953
}
954
955
static void
956
setbridge_qinq(if_ctx *ctx, const char *val, int dummy __unused)
957
{
958
do_bridgeflag(ctx, val, IFBIF_QINQ, 1);
959
}
960
961
static void
962
unsetbridge_qinq(if_ctx *ctx, const char *val, int dummy __unused)
963
{
964
do_bridgeflag(ctx, val, IFBIF_QINQ, 0);
965
}
966
967
static void
968
setbridge_ifvlanproto(if_ctx *ctx, const char *ifname, const char *proto)
969
{
970
struct ifbreq req;
971
972
memset(&req, 0, sizeof(req));
973
strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
974
975
if (strcmp(proto, "802.1q") == 0)
976
req.ifbr_vlanproto = ETHERTYPE_VLAN;
977
else if (strcmp(proto, "802.1ad") == 0)
978
req.ifbr_vlanproto = ETHERTYPE_QINQ;
979
else
980
errx(1, "unrecognised VLAN protocol: %s", proto);
981
982
if (do_cmd(ctx, BRDGSIFVLANPROTO, &req, sizeof(req), 1) < 0)
983
err(1, "BRDGSIFVLANPROTO");
984
}
985
986
static struct cmd bridge_cmds[] = {
987
DEF_CMD_VARG("addm", setbridge_add),
988
DEF_CMD_ARG("deletem", setbridge_delete),
989
DEF_CMD_ARG("discover", setbridge_discover),
990
DEF_CMD_ARG("-discover", unsetbridge_discover),
991
DEF_CMD_ARG("learn", setbridge_learn),
992
DEF_CMD_ARG("-learn", unsetbridge_learn),
993
DEF_CMD_ARG("sticky", setbridge_sticky),
994
DEF_CMD_ARG("-sticky", unsetbridge_sticky),
995
DEF_CMD_ARG("span", setbridge_span),
996
DEF_CMD_ARG("-span", unsetbridge_span),
997
DEF_CMD_ARG("stp", setbridge_stp),
998
DEF_CMD_ARG("-stp", unsetbridge_stp),
999
DEF_CMD_ARG("edge", setbridge_edge),
1000
DEF_CMD_ARG("-edge", unsetbridge_edge),
1001
DEF_CMD_ARG("autoedge", setbridge_autoedge),
1002
DEF_CMD_ARG("-autoedge", unsetbridge_autoedge),
1003
DEF_CMD_ARG("ptp", setbridge_ptp),
1004
DEF_CMD_ARG("-ptp", unsetbridge_ptp),
1005
DEF_CMD_ARG("autoptp", setbridge_autoptp),
1006
DEF_CMD_ARG("-autoptp", unsetbridge_autoptp),
1007
DEF_CMD("flush", 0, setbridge_flush),
1008
DEF_CMD("flushall", 0, setbridge_flushall),
1009
DEF_CMD_VARG("static", setbridge_static),
1010
DEF_CMD_VARG("deladdr", setbridge_deladdr),
1011
DEF_CMD("addr", 1, setbridge_addr),
1012
DEF_CMD_ARG("maxaddr", setbridge_maxaddr),
1013
DEF_CMD_ARG("hellotime", setbridge_hellotime),
1014
DEF_CMD_ARG("fwddelay", setbridge_fwddelay),
1015
DEF_CMD_ARG("maxage", setbridge_maxage),
1016
DEF_CMD_ARG("priority", setbridge_priority),
1017
DEF_CMD_ARG("proto", setbridge_protocol),
1018
DEF_CMD_ARG("holdcnt", setbridge_holdcount),
1019
DEF_CMD_ARG2("ifpriority", setbridge_ifpriority),
1020
DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost),
1021
DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr),
1022
DEF_CMD_ARG2("ifuntagged", setbridge_ifuntagged),
1023
DEF_CMD_ARG("-ifuntagged", unsetbridge_ifuntagged),
1024
DEF_CMD_ARG2("iftagged", setbridge_iftagged),
1025
DEF_CMD_ARG2("+iftagged", addbridge_iftagged),
1026
DEF_CMD_ARG2("-iftagged", delbridge_iftagged),
1027
DEF_CMD_ARG2("ifvlanproto", setbridge_ifvlanproto),
1028
DEF_CMD_ARG("timeout", setbridge_timeout),
1029
DEF_CMD_ARG("private", setbridge_private),
1030
DEF_CMD_ARG("-private", unsetbridge_private),
1031
DEF_CMD("vlanfilter", (int32_t)IFBRF_VLANFILTER,
1032
setbridge_flags),
1033
DEF_CMD("-vlanfilter", (int32_t)IFBRF_VLANFILTER,
1034
unsetbridge_flags),
1035
DEF_CMD_ARG("defuntagged", setbridge_defuntagged),
1036
DEF_CMD("-defuntagged", 0, unsetbridge_defuntagged),
1037
DEF_CMD("defqinq", (int32_t)IFBRF_DEFQINQ,
1038
setbridge_flags),
1039
DEF_CMD("-defqinq", (int32_t)IFBRF_DEFQINQ,
1040
unsetbridge_flags),
1041
DEF_CMD_ARG("qinq", setbridge_qinq),
1042
DEF_CMD_ARG("-qinq", unsetbridge_qinq),
1043
};
1044
1045
static struct afswtch af_bridge = {
1046
.af_name = "af_bridge",
1047
.af_af = AF_UNSPEC,
1048
.af_other_status = bridge_status,
1049
};
1050
1051
static __constructor void
1052
bridge_ctor(void)
1053
{
1054
for (size_t i = 0; i < nitems(bridge_cmds); i++)
1055
cmd_register(&bridge_cmds[i]);
1056
af_register(&af_bridge);
1057
}
1058
1059