Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/net/bridgestp.c
39475 views
1
/* $NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $ */
2
3
/*-
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2000 Jason L. Wright ([email protected])
7
* Copyright (c) 2006 Andrew Thompson ([email protected])
8
* All rights reserved.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
* POSSIBILITY OF SUCH DAMAGE.
30
*
31
* OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason Exp
32
*/
33
34
/*
35
* Implementation of the spanning tree protocol as defined in
36
* ISO/IEC 802.1D-2004, June 9, 2004.
37
*/
38
39
#include <sys/param.h>
40
#include <sys/systm.h>
41
#include <sys/mbuf.h>
42
#include <sys/socket.h>
43
#include <sys/sockio.h>
44
#include <sys/kernel.h>
45
#include <sys/malloc.h>
46
#include <sys/callout.h>
47
#include <sys/module.h>
48
#include <sys/proc.h>
49
#include <sys/lock.h>
50
#include <sys/mutex.h>
51
#include <sys/taskqueue.h>
52
53
#include <net/if.h>
54
#include <net/if_var.h>
55
#include <net/if_private.h>
56
#include <net/if_dl.h>
57
#include <net/if_types.h>
58
#include <net/if_llc.h>
59
#include <net/if_media.h>
60
#include <net/if_bridgevar.h>
61
#include <net/vnet.h>
62
63
#include <netinet/in.h>
64
#include <netinet/in_systm.h>
65
#include <netinet/in_var.h>
66
#include <netinet/if_ether.h>
67
#include <net/bridgestp.h>
68
69
#ifdef BRIDGESTP_DEBUG
70
#define DPRINTF(fmt, arg...) printf("bstp: " fmt, ##arg)
71
#else
72
#define DPRINTF(fmt, arg...) (void)0
73
#endif
74
75
#define PV2ADDR(pv, eaddr) do { \
76
eaddr[0] = pv >> 40; \
77
eaddr[1] = pv >> 32; \
78
eaddr[2] = pv >> 24; \
79
eaddr[3] = pv >> 16; \
80
eaddr[4] = pv >> 8; \
81
eaddr[5] = pv >> 0; \
82
} while (0)
83
84
#define INFO_BETTER 1
85
#define INFO_SAME 0
86
#define INFO_WORSE -1
87
88
const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
89
90
LIST_HEAD(, bstp_state) bstp_list = LIST_HEAD_INITIALIZER(bstp_list);
91
static struct mtx bstp_list_mtx;
92
93
static void bstp_transmit(struct bstp_state *, struct bstp_port *);
94
static void bstp_transmit_bpdu(struct bstp_state *, struct bstp_port *);
95
static void bstp_transmit_tcn(struct bstp_state *, struct bstp_port *);
96
static void bstp_decode_bpdu(struct bstp_port *, struct bstp_cbpdu *,
97
struct bstp_config_unit *);
98
static void bstp_send_bpdu(struct bstp_state *, struct bstp_port *,
99
struct bstp_cbpdu *);
100
static int bstp_pdu_flags(struct bstp_port *);
101
static void bstp_received_stp(struct bstp_state *, struct bstp_port *,
102
struct mbuf **, struct bstp_tbpdu *);
103
static void bstp_received_rstp(struct bstp_state *, struct bstp_port *,
104
struct mbuf **, struct bstp_tbpdu *);
105
static void bstp_received_tcn(struct bstp_state *, struct bstp_port *,
106
struct bstp_tcn_unit *);
107
static void bstp_received_bpdu(struct bstp_state *, struct bstp_port *,
108
struct bstp_config_unit *);
109
static int bstp_pdu_rcvtype(struct bstp_port *, struct bstp_config_unit *);
110
static int bstp_pdu_bettersame(struct bstp_port *, int);
111
static int bstp_info_cmp(struct bstp_pri_vector *,
112
struct bstp_pri_vector *);
113
static int bstp_info_superior(struct bstp_pri_vector *,
114
struct bstp_pri_vector *);
115
static void bstp_assign_roles(struct bstp_state *);
116
static void bstp_update_roles(struct bstp_state *, struct bstp_port *);
117
static void bstp_update_state(struct bstp_state *, struct bstp_port *);
118
static void bstp_update_tc(struct bstp_port *);
119
static void bstp_update_info(struct bstp_port *);
120
static void bstp_set_other_tcprop(struct bstp_port *);
121
static void bstp_set_all_reroot(struct bstp_state *);
122
static void bstp_set_all_sync(struct bstp_state *);
123
static void bstp_set_port_state(struct bstp_port *, int);
124
static void bstp_set_port_role(struct bstp_port *, int);
125
static void bstp_set_port_proto(struct bstp_port *, int);
126
static void bstp_set_port_tc(struct bstp_port *, int);
127
static void bstp_set_timer_tc(struct bstp_port *);
128
static void bstp_set_timer_msgage(struct bstp_port *);
129
static int bstp_rerooted(struct bstp_state *, struct bstp_port *);
130
static uint32_t bstp_calc_path_cost(struct bstp_port *);
131
static void bstp_notify_state(void *, int);
132
static void bstp_notify_rtage(void *, int);
133
static void bstp_ifupdstatus(void *, int);
134
static void bstp_enable_port(struct bstp_state *, struct bstp_port *);
135
static void bstp_disable_port(struct bstp_state *, struct bstp_port *);
136
static void bstp_tick(void *);
137
static void bstp_timer_start(struct bstp_timer *, uint16_t);
138
static void bstp_timer_stop(struct bstp_timer *);
139
static void bstp_timer_latch(struct bstp_timer *);
140
static int bstp_timer_dectest(struct bstp_timer *);
141
static void bstp_hello_timer_expiry(struct bstp_state *,
142
struct bstp_port *);
143
static void bstp_message_age_expiry(struct bstp_state *,
144
struct bstp_port *);
145
static void bstp_migrate_delay_expiry(struct bstp_state *,
146
struct bstp_port *);
147
static void bstp_edge_delay_expiry(struct bstp_state *,
148
struct bstp_port *);
149
static int bstp_addr_cmp(const uint8_t *, const uint8_t *);
150
static int bstp_same_bridgeid(uint64_t, uint64_t);
151
static void bstp_reinit(struct bstp_state *);
152
153
static void
154
bstp_transmit(struct bstp_state *bs, struct bstp_port *bp)
155
{
156
NET_EPOCH_ASSERT();
157
158
if (bs->bs_running == 0)
159
return;
160
161
/*
162
* a PDU can only be sent if we have tx quota left and the
163
* hello timer is running.
164
*/
165
if (bp->bp_hello_timer.active == 0) {
166
/* Test if it needs to be reset */
167
bstp_hello_timer_expiry(bs, bp);
168
return;
169
}
170
if (bp->bp_txcount > bs->bs_txholdcount)
171
/* Ran out of karma */
172
return;
173
174
if (bp->bp_protover == BSTP_PROTO_RSTP) {
175
bstp_transmit_bpdu(bs, bp);
176
bp->bp_tc_ack = 0;
177
} else { /* STP */
178
switch (bp->bp_role) {
179
case BSTP_ROLE_DESIGNATED:
180
bstp_transmit_bpdu(bs, bp);
181
bp->bp_tc_ack = 0;
182
break;
183
184
case BSTP_ROLE_ROOT:
185
bstp_transmit_tcn(bs, bp);
186
break;
187
}
188
}
189
bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
190
bp->bp_flags &= ~BSTP_PORT_NEWINFO;
191
}
192
193
static void
194
bstp_transmit_bpdu(struct bstp_state *bs, struct bstp_port *bp)
195
{
196
struct bstp_cbpdu bpdu;
197
198
BSTP_LOCK_ASSERT(bs);
199
200
bpdu.cbu_rootpri = htons(bp->bp_desg_pv.pv_root_id >> 48);
201
PV2ADDR(bp->bp_desg_pv.pv_root_id, bpdu.cbu_rootaddr);
202
203
bpdu.cbu_rootpathcost = htonl(bp->bp_desg_pv.pv_cost);
204
205
bpdu.cbu_bridgepri = htons(bp->bp_desg_pv.pv_dbridge_id >> 48);
206
PV2ADDR(bp->bp_desg_pv.pv_dbridge_id, bpdu.cbu_bridgeaddr);
207
208
bpdu.cbu_portid = htons(bp->bp_port_id);
209
bpdu.cbu_messageage = htons(bp->bp_desg_msg_age);
210
bpdu.cbu_maxage = htons(bp->bp_desg_max_age);
211
bpdu.cbu_hellotime = htons(bp->bp_desg_htime);
212
bpdu.cbu_forwarddelay = htons(bp->bp_desg_fdelay);
213
214
bpdu.cbu_flags = bstp_pdu_flags(bp);
215
216
switch (bp->bp_protover) {
217
case BSTP_PROTO_STP:
218
bpdu.cbu_bpdutype = BSTP_MSGTYPE_CFG;
219
break;
220
221
case BSTP_PROTO_RSTP:
222
bpdu.cbu_bpdutype = BSTP_MSGTYPE_RSTP;
223
break;
224
}
225
226
bstp_send_bpdu(bs, bp, &bpdu);
227
}
228
229
static void
230
bstp_transmit_tcn(struct bstp_state *bs, struct bstp_port *bp)
231
{
232
struct bstp_tbpdu bpdu;
233
struct ifnet *ifp = bp->bp_ifp;
234
struct ether_header *eh;
235
struct mbuf *m;
236
237
KASSERT(bp == bs->bs_root_port, ("%s: bad root port\n", __func__));
238
239
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
240
return;
241
242
m = m_gethdr(M_NOWAIT, MT_DATA);
243
if (m == NULL)
244
return;
245
246
m->m_pkthdr.rcvif = ifp;
247
m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
248
m->m_len = m->m_pkthdr.len;
249
250
eh = mtod(m, struct ether_header *);
251
252
memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
253
memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
254
eh->ether_type = htons(sizeof(bpdu));
255
256
bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
257
bpdu.tbu_ctl = LLC_UI;
258
bpdu.tbu_protoid = 0;
259
bpdu.tbu_protover = 0;
260
bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
261
262
memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
263
264
bp->bp_txcount++;
265
ifp->if_transmit(ifp, m);
266
}
267
268
static void
269
bstp_decode_bpdu(struct bstp_port *bp, struct bstp_cbpdu *cpdu,
270
struct bstp_config_unit *cu)
271
{
272
int flags;
273
274
cu->cu_pv.pv_root_id =
275
(((uint64_t)ntohs(cpdu->cbu_rootpri)) << 48) |
276
(((uint64_t)cpdu->cbu_rootaddr[0]) << 40) |
277
(((uint64_t)cpdu->cbu_rootaddr[1]) << 32) |
278
(((uint64_t)cpdu->cbu_rootaddr[2]) << 24) |
279
(((uint64_t)cpdu->cbu_rootaddr[3]) << 16) |
280
(((uint64_t)cpdu->cbu_rootaddr[4]) << 8) |
281
(((uint64_t)cpdu->cbu_rootaddr[5]) << 0);
282
283
cu->cu_pv.pv_dbridge_id =
284
(((uint64_t)ntohs(cpdu->cbu_bridgepri)) << 48) |
285
(((uint64_t)cpdu->cbu_bridgeaddr[0]) << 40) |
286
(((uint64_t)cpdu->cbu_bridgeaddr[1]) << 32) |
287
(((uint64_t)cpdu->cbu_bridgeaddr[2]) << 24) |
288
(((uint64_t)cpdu->cbu_bridgeaddr[3]) << 16) |
289
(((uint64_t)cpdu->cbu_bridgeaddr[4]) << 8) |
290
(((uint64_t)cpdu->cbu_bridgeaddr[5]) << 0);
291
292
cu->cu_pv.pv_cost = ntohl(cpdu->cbu_rootpathcost);
293
cu->cu_message_age = ntohs(cpdu->cbu_messageage);
294
cu->cu_max_age = ntohs(cpdu->cbu_maxage);
295
cu->cu_hello_time = ntohs(cpdu->cbu_hellotime);
296
cu->cu_forward_delay = ntohs(cpdu->cbu_forwarddelay);
297
cu->cu_pv.pv_dport_id = ntohs(cpdu->cbu_portid);
298
cu->cu_pv.pv_port_id = bp->bp_port_id;
299
cu->cu_message_type = cpdu->cbu_bpdutype;
300
301
/* Strip off unused flags in STP mode */
302
flags = cpdu->cbu_flags;
303
switch (cpdu->cbu_protover) {
304
case BSTP_PROTO_STP:
305
flags &= BSTP_PDU_STPMASK;
306
/* A STP BPDU explicitly conveys a Designated Port */
307
cu->cu_role = BSTP_ROLE_DESIGNATED;
308
break;
309
310
case BSTP_PROTO_RSTP:
311
flags &= BSTP_PDU_RSTPMASK;
312
break;
313
}
314
315
cu->cu_topology_change_ack =
316
(flags & BSTP_PDU_F_TCA) ? 1 : 0;
317
cu->cu_proposal =
318
(flags & BSTP_PDU_F_P) ? 1 : 0;
319
cu->cu_agree =
320
(flags & BSTP_PDU_F_A) ? 1 : 0;
321
cu->cu_learning =
322
(flags & BSTP_PDU_F_L) ? 1 : 0;
323
cu->cu_forwarding =
324
(flags & BSTP_PDU_F_F) ? 1 : 0;
325
cu->cu_topology_change =
326
(flags & BSTP_PDU_F_TC) ? 1 : 0;
327
328
switch ((flags & BSTP_PDU_PRMASK) >> BSTP_PDU_PRSHIFT) {
329
case BSTP_PDU_F_ROOT:
330
cu->cu_role = BSTP_ROLE_ROOT;
331
break;
332
case BSTP_PDU_F_ALT:
333
cu->cu_role = BSTP_ROLE_ALTERNATE;
334
break;
335
case BSTP_PDU_F_DESG:
336
cu->cu_role = BSTP_ROLE_DESIGNATED;
337
break;
338
}
339
}
340
341
static void
342
bstp_send_bpdu(struct bstp_state *bs, struct bstp_port *bp,
343
struct bstp_cbpdu *bpdu)
344
{
345
struct ifnet *ifp;
346
struct mbuf *m;
347
struct ether_header *eh;
348
349
BSTP_LOCK_ASSERT(bs);
350
NET_EPOCH_ASSERT();
351
352
ifp = bp->bp_ifp;
353
354
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
355
return;
356
357
m = m_gethdr(M_NOWAIT, MT_DATA);
358
if (m == NULL)
359
return;
360
361
eh = mtod(m, struct ether_header *);
362
363
bpdu->cbu_ssap = bpdu->cbu_dsap = LLC_8021D_LSAP;
364
bpdu->cbu_ctl = LLC_UI;
365
bpdu->cbu_protoid = htons(BSTP_PROTO_ID);
366
367
memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
368
memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
369
370
switch (bpdu->cbu_bpdutype) {
371
case BSTP_MSGTYPE_CFG:
372
bpdu->cbu_protover = BSTP_PROTO_STP;
373
m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_STP_LEN;
374
eh->ether_type = htons(BSTP_BPDU_STP_LEN);
375
memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
376
BSTP_BPDU_STP_LEN);
377
break;
378
379
case BSTP_MSGTYPE_RSTP:
380
bpdu->cbu_protover = BSTP_PROTO_RSTP;
381
bpdu->cbu_versionlen = htons(0);
382
m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_RSTP_LEN;
383
eh->ether_type = htons(BSTP_BPDU_RSTP_LEN);
384
memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
385
BSTP_BPDU_RSTP_LEN);
386
break;
387
388
default:
389
panic("not implemented");
390
}
391
m->m_pkthdr.rcvif = ifp;
392
m->m_len = m->m_pkthdr.len;
393
394
bp->bp_txcount++;
395
ifp->if_transmit(ifp, m);
396
}
397
398
static int
399
bstp_pdu_flags(struct bstp_port *bp)
400
{
401
int flags = 0;
402
403
if (bp->bp_proposing && bp->bp_state != BSTP_IFSTATE_FORWARDING)
404
flags |= BSTP_PDU_F_P;
405
406
if (bp->bp_agree)
407
flags |= BSTP_PDU_F_A;
408
409
if (bp->bp_tc_timer.active)
410
flags |= BSTP_PDU_F_TC;
411
412
if (bp->bp_tc_ack)
413
flags |= BSTP_PDU_F_TCA;
414
415
switch (bp->bp_state) {
416
case BSTP_IFSTATE_LEARNING:
417
flags |= BSTP_PDU_F_L;
418
break;
419
420
case BSTP_IFSTATE_FORWARDING:
421
flags |= (BSTP_PDU_F_L | BSTP_PDU_F_F);
422
break;
423
}
424
425
switch (bp->bp_role) {
426
case BSTP_ROLE_ROOT:
427
flags |=
428
(BSTP_PDU_F_ROOT << BSTP_PDU_PRSHIFT);
429
break;
430
431
case BSTP_ROLE_ALTERNATE:
432
case BSTP_ROLE_BACKUP: /* fall through */
433
flags |=
434
(BSTP_PDU_F_ALT << BSTP_PDU_PRSHIFT);
435
break;
436
437
case BSTP_ROLE_DESIGNATED:
438
flags |=
439
(BSTP_PDU_F_DESG << BSTP_PDU_PRSHIFT);
440
break;
441
}
442
443
/* Strip off unused flags in either mode */
444
switch (bp->bp_protover) {
445
case BSTP_PROTO_STP:
446
flags &= BSTP_PDU_STPMASK;
447
break;
448
case BSTP_PROTO_RSTP:
449
flags &= BSTP_PDU_RSTPMASK;
450
break;
451
}
452
return (flags);
453
}
454
455
void
456
bstp_input(struct bstp_port *bp, struct ifnet *ifp, struct mbuf *m)
457
{
458
struct bstp_state *bs = bp->bp_bs;
459
struct ether_header *eh;
460
struct bstp_tbpdu tpdu;
461
uint16_t len;
462
463
if (bp->bp_active == 0) {
464
m_freem(m);
465
return;
466
}
467
468
BSTP_LOCK(bs);
469
470
eh = mtod(m, struct ether_header *);
471
472
len = ntohs(eh->ether_type);
473
if (len < sizeof(tpdu))
474
goto out;
475
476
m_adj(m, ETHER_HDR_LEN);
477
478
if (m->m_pkthdr.len > len)
479
m_adj(m, len - m->m_pkthdr.len);
480
if (m->m_len < sizeof(tpdu) &&
481
(m = m_pullup(m, sizeof(tpdu))) == NULL)
482
goto out;
483
484
memcpy(&tpdu, mtod(m, caddr_t), sizeof(tpdu));
485
486
/* basic packet checks */
487
if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
488
tpdu.tbu_ssap != LLC_8021D_LSAP ||
489
tpdu.tbu_ctl != LLC_UI)
490
goto out;
491
if (tpdu.tbu_protoid != BSTP_PROTO_ID)
492
goto out;
493
494
/*
495
* We can treat later versions of the PDU as the same as the maximum
496
* version we implement. All additional parameters/flags are ignored.
497
*/
498
if (tpdu.tbu_protover > BSTP_PROTO_MAX)
499
tpdu.tbu_protover = BSTP_PROTO_MAX;
500
501
if (tpdu.tbu_protover != bp->bp_protover) {
502
/*
503
* Wait for the migration delay timer to expire before changing
504
* protocol version to avoid flip-flops.
505
*/
506
if (bp->bp_flags & BSTP_PORT_CANMIGRATE)
507
bstp_set_port_proto(bp, tpdu.tbu_protover);
508
else
509
goto out;
510
}
511
512
/* Clear operedge upon receiving a PDU on the port */
513
bp->bp_operedge = 0;
514
bstp_timer_start(&bp->bp_edge_delay_timer,
515
BSTP_DEFAULT_MIGRATE_DELAY);
516
517
switch (tpdu.tbu_protover) {
518
case BSTP_PROTO_STP:
519
bstp_received_stp(bs, bp, &m, &tpdu);
520
break;
521
522
case BSTP_PROTO_RSTP:
523
bstp_received_rstp(bs, bp, &m, &tpdu);
524
break;
525
}
526
out:
527
BSTP_UNLOCK(bs);
528
if (m)
529
m_freem(m);
530
}
531
532
static void
533
bstp_received_stp(struct bstp_state *bs, struct bstp_port *bp,
534
struct mbuf **mp, struct bstp_tbpdu *tpdu)
535
{
536
struct bstp_cbpdu cpdu;
537
struct bstp_config_unit *cu = &bp->bp_msg_cu;
538
struct bstp_tcn_unit tu;
539
540
switch (tpdu->tbu_bpdutype) {
541
case BSTP_MSGTYPE_TCN:
542
tu.tu_message_type = tpdu->tbu_bpdutype;
543
bstp_received_tcn(bs, bp, &tu);
544
break;
545
case BSTP_MSGTYPE_CFG:
546
if ((*mp)->m_len < BSTP_BPDU_STP_LEN &&
547
(*mp = m_pullup(*mp, BSTP_BPDU_STP_LEN)) == NULL)
548
return;
549
memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_STP_LEN);
550
551
bstp_decode_bpdu(bp, &cpdu, cu);
552
bstp_received_bpdu(bs, bp, cu);
553
break;
554
}
555
}
556
557
static void
558
bstp_received_rstp(struct bstp_state *bs, struct bstp_port *bp,
559
struct mbuf **mp, struct bstp_tbpdu *tpdu)
560
{
561
struct bstp_cbpdu cpdu;
562
struct bstp_config_unit *cu = &bp->bp_msg_cu;
563
564
if (tpdu->tbu_bpdutype != BSTP_MSGTYPE_RSTP)
565
return;
566
567
if ((*mp)->m_len < BSTP_BPDU_RSTP_LEN &&
568
(*mp = m_pullup(*mp, BSTP_BPDU_RSTP_LEN)) == NULL)
569
return;
570
memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_RSTP_LEN);
571
572
bstp_decode_bpdu(bp, &cpdu, cu);
573
bstp_received_bpdu(bs, bp, cu);
574
}
575
576
static void
577
bstp_received_tcn(struct bstp_state *bs, struct bstp_port *bp,
578
struct bstp_tcn_unit *tcn)
579
{
580
bp->bp_rcvdtcn = 1;
581
bstp_update_tc(bp);
582
}
583
584
static void
585
bstp_received_bpdu(struct bstp_state *bs, struct bstp_port *bp,
586
struct bstp_config_unit *cu)
587
{
588
int type;
589
590
BSTP_LOCK_ASSERT(bs);
591
592
/* We need to have transitioned to INFO_MINE before proceeding */
593
switch (bp->bp_infois) {
594
case BSTP_INFO_DISABLED:
595
case BSTP_INFO_AGED:
596
return;
597
}
598
599
/* range checks */
600
if (cu->cu_message_age >= cu->cu_max_age) {
601
return;
602
}
603
if (cu->cu_max_age < BSTP_MIN_MAX_AGE ||
604
cu->cu_max_age > BSTP_MAX_MAX_AGE) {
605
return;
606
}
607
if (cu->cu_forward_delay < BSTP_MIN_FORWARD_DELAY ||
608
cu->cu_forward_delay > BSTP_MAX_FORWARD_DELAY) {
609
return;
610
}
611
if (cu->cu_hello_time < BSTP_MIN_HELLO_TIME ||
612
cu->cu_hello_time > BSTP_MAX_HELLO_TIME) {
613
return;
614
}
615
616
type = bstp_pdu_rcvtype(bp, cu);
617
618
switch (type) {
619
case BSTP_PDU_SUPERIOR:
620
bs->bs_allsynced = 0;
621
bp->bp_agreed = 0;
622
bp->bp_proposing = 0;
623
624
if (cu->cu_proposal && cu->cu_forwarding == 0)
625
bp->bp_proposed = 1;
626
if (cu->cu_topology_change)
627
bp->bp_rcvdtc = 1;
628
if (cu->cu_topology_change_ack)
629
bp->bp_rcvdtca = 1;
630
631
if (bp->bp_agree &&
632
!bstp_pdu_bettersame(bp, BSTP_INFO_RECEIVED))
633
bp->bp_agree = 0;
634
635
/* copy the received priority and timers to the port */
636
bp->bp_port_pv = cu->cu_pv;
637
bp->bp_port_msg_age = cu->cu_message_age;
638
bp->bp_port_max_age = cu->cu_max_age;
639
bp->bp_port_fdelay = cu->cu_forward_delay;
640
bp->bp_port_htime =
641
(cu->cu_hello_time > BSTP_MIN_HELLO_TIME ?
642
cu->cu_hello_time : BSTP_MIN_HELLO_TIME);
643
644
/* set expiry for the new info */
645
bstp_set_timer_msgage(bp);
646
647
bp->bp_infois = BSTP_INFO_RECEIVED;
648
bstp_assign_roles(bs);
649
break;
650
651
case BSTP_PDU_REPEATED:
652
if (cu->cu_proposal && cu->cu_forwarding == 0)
653
bp->bp_proposed = 1;
654
if (cu->cu_topology_change)
655
bp->bp_rcvdtc = 1;
656
if (cu->cu_topology_change_ack)
657
bp->bp_rcvdtca = 1;
658
659
/* rearm the age timer */
660
bstp_set_timer_msgage(bp);
661
break;
662
663
case BSTP_PDU_INFERIOR:
664
if (cu->cu_learning) {
665
bp->bp_agreed = 1;
666
bp->bp_proposing = 0;
667
}
668
break;
669
670
case BSTP_PDU_INFERIORALT:
671
/*
672
* only point to point links are allowed fast
673
* transitions to forwarding.
674
*/
675
if (cu->cu_agree && bp->bp_ptp_link) {
676
bp->bp_agreed = 1;
677
bp->bp_proposing = 0;
678
} else
679
bp->bp_agreed = 0;
680
681
if (cu->cu_topology_change)
682
bp->bp_rcvdtc = 1;
683
if (cu->cu_topology_change_ack)
684
bp->bp_rcvdtca = 1;
685
break;
686
687
case BSTP_PDU_OTHER:
688
return; /* do nothing */
689
}
690
/* update the state machines with the new data */
691
bstp_update_state(bs, bp);
692
}
693
694
static int
695
bstp_pdu_rcvtype(struct bstp_port *bp, struct bstp_config_unit *cu)
696
{
697
int type;
698
699
/* default return type */
700
type = BSTP_PDU_OTHER;
701
702
switch (cu->cu_role) {
703
case BSTP_ROLE_DESIGNATED:
704
if (bstp_info_superior(&bp->bp_port_pv, &cu->cu_pv))
705
/* bpdu priority is superior */
706
type = BSTP_PDU_SUPERIOR;
707
else if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) ==
708
INFO_SAME) {
709
if (bp->bp_port_msg_age != cu->cu_message_age ||
710
bp->bp_port_max_age != cu->cu_max_age ||
711
bp->bp_port_fdelay != cu->cu_forward_delay ||
712
bp->bp_port_htime != cu->cu_hello_time)
713
/* bpdu priority is equal and timers differ */
714
type = BSTP_PDU_SUPERIOR;
715
else
716
/* bpdu is equal */
717
type = BSTP_PDU_REPEATED;
718
} else
719
/* bpdu priority is worse */
720
type = BSTP_PDU_INFERIOR;
721
722
break;
723
724
case BSTP_ROLE_ROOT:
725
case BSTP_ROLE_ALTERNATE:
726
case BSTP_ROLE_BACKUP:
727
if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) <= INFO_SAME)
728
/*
729
* not a designated port and priority is the same or
730
* worse
731
*/
732
type = BSTP_PDU_INFERIORALT;
733
break;
734
}
735
736
return (type);
737
}
738
739
static int
740
bstp_pdu_bettersame(struct bstp_port *bp, int newinfo)
741
{
742
if (newinfo == BSTP_INFO_RECEIVED &&
743
bp->bp_infois == BSTP_INFO_RECEIVED &&
744
bstp_info_cmp(&bp->bp_port_pv, &bp->bp_msg_cu.cu_pv) >= INFO_SAME)
745
return (1);
746
747
if (newinfo == BSTP_INFO_MINE &&
748
bp->bp_infois == BSTP_INFO_MINE &&
749
bstp_info_cmp(&bp->bp_port_pv, &bp->bp_desg_pv) >= INFO_SAME)
750
return (1);
751
752
return (0);
753
}
754
755
static int
756
bstp_info_cmp(struct bstp_pri_vector *pv,
757
struct bstp_pri_vector *cpv)
758
{
759
if (cpv->pv_root_id < pv->pv_root_id)
760
return (INFO_BETTER);
761
if (cpv->pv_root_id > pv->pv_root_id)
762
return (INFO_WORSE);
763
764
if (cpv->pv_cost < pv->pv_cost)
765
return (INFO_BETTER);
766
if (cpv->pv_cost > pv->pv_cost)
767
return (INFO_WORSE);
768
769
if (cpv->pv_dbridge_id < pv->pv_dbridge_id)
770
return (INFO_BETTER);
771
if (cpv->pv_dbridge_id > pv->pv_dbridge_id)
772
return (INFO_WORSE);
773
774
if (cpv->pv_dport_id < pv->pv_dport_id)
775
return (INFO_BETTER);
776
if (cpv->pv_dport_id > pv->pv_dport_id)
777
return (INFO_WORSE);
778
779
return (INFO_SAME);
780
}
781
782
/*
783
* This message priority vector is superior to the port priority vector and
784
* will replace it if, and only if, the message priority vector is better than
785
* the port priority vector, or the message has been transmitted from the same
786
* designated bridge and designated port as the port priority vector.
787
*/
788
static int
789
bstp_info_superior(struct bstp_pri_vector *pv,
790
struct bstp_pri_vector *cpv)
791
{
792
if (bstp_info_cmp(pv, cpv) == INFO_BETTER ||
793
(bstp_same_bridgeid(pv->pv_dbridge_id, cpv->pv_dbridge_id) &&
794
(cpv->pv_dport_id & 0xfff) == (pv->pv_dport_id & 0xfff)))
795
return (1);
796
return (0);
797
}
798
799
static void
800
bstp_assign_roles(struct bstp_state *bs)
801
{
802
struct bstp_port *bp, *rbp = NULL;
803
struct bstp_pri_vector pv;
804
805
/* default to our priority vector */
806
bs->bs_root_pv = bs->bs_bridge_pv;
807
bs->bs_root_msg_age = 0;
808
bs->bs_root_max_age = bs->bs_bridge_max_age;
809
bs->bs_root_fdelay = bs->bs_bridge_fdelay;
810
bs->bs_root_htime = bs->bs_bridge_htime;
811
bs->bs_root_port = NULL;
812
813
/* check if any received info supersedes us */
814
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
815
if (bp->bp_infois != BSTP_INFO_RECEIVED)
816
continue;
817
818
pv = bp->bp_port_pv;
819
pv.pv_cost += bp->bp_path_cost;
820
821
/*
822
* The root priority vector is the best of the set comprising
823
* the bridge priority vector plus all root path priority
824
* vectors whose bridge address is not equal to us.
825
*/
826
if (bstp_same_bridgeid(pv.pv_dbridge_id,
827
bs->bs_bridge_pv.pv_dbridge_id) == 0 &&
828
bstp_info_cmp(&bs->bs_root_pv, &pv) == INFO_BETTER) {
829
/* the port vector replaces the root */
830
bs->bs_root_pv = pv;
831
bs->bs_root_msg_age = bp->bp_port_msg_age +
832
BSTP_MESSAGE_AGE_INCR;
833
bs->bs_root_max_age = bp->bp_port_max_age;
834
bs->bs_root_fdelay = bp->bp_port_fdelay;
835
bs->bs_root_htime = bp->bp_port_htime;
836
rbp = bp;
837
}
838
}
839
840
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
841
/* calculate the port designated vector */
842
bp->bp_desg_pv.pv_root_id = bs->bs_root_pv.pv_root_id;
843
bp->bp_desg_pv.pv_cost = bs->bs_root_pv.pv_cost;
844
bp->bp_desg_pv.pv_dbridge_id = bs->bs_bridge_pv.pv_dbridge_id;
845
bp->bp_desg_pv.pv_dport_id = bp->bp_port_id;
846
bp->bp_desg_pv.pv_port_id = bp->bp_port_id;
847
848
/* calculate designated times */
849
bp->bp_desg_msg_age = bs->bs_root_msg_age;
850
bp->bp_desg_max_age = bs->bs_root_max_age;
851
bp->bp_desg_fdelay = bs->bs_root_fdelay;
852
bp->bp_desg_htime = bs->bs_bridge_htime;
853
854
switch (bp->bp_infois) {
855
case BSTP_INFO_DISABLED:
856
bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
857
break;
858
859
case BSTP_INFO_AGED:
860
bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
861
bstp_update_info(bp);
862
break;
863
864
case BSTP_INFO_MINE:
865
bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
866
/* update the port info if stale */
867
if (bstp_info_cmp(&bp->bp_port_pv,
868
&bp->bp_desg_pv) != INFO_SAME ||
869
(rbp != NULL &&
870
(bp->bp_port_msg_age != rbp->bp_port_msg_age ||
871
bp->bp_port_max_age != rbp->bp_port_max_age ||
872
bp->bp_port_fdelay != rbp->bp_port_fdelay ||
873
bp->bp_port_htime != rbp->bp_port_htime)))
874
bstp_update_info(bp);
875
break;
876
877
case BSTP_INFO_RECEIVED:
878
if (bp == rbp) {
879
/*
880
* root priority is derived from this
881
* port, make it the root port.
882
*/
883
bstp_set_port_role(bp, BSTP_ROLE_ROOT);
884
bs->bs_root_port = bp;
885
} else if (bstp_info_cmp(&bp->bp_port_pv,
886
&bp->bp_desg_pv) == INFO_BETTER) {
887
/*
888
* the port priority is lower than the root
889
* port.
890
*/
891
bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
892
bstp_update_info(bp);
893
} else {
894
if (bstp_same_bridgeid(
895
bp->bp_port_pv.pv_dbridge_id,
896
bs->bs_bridge_pv.pv_dbridge_id)) {
897
/*
898
* the designated bridge refers to
899
* another port on this bridge.
900
*/
901
bstp_set_port_role(bp,
902
BSTP_ROLE_BACKUP);
903
} else {
904
/*
905
* the port is an inferior path to the
906
* root bridge.
907
*/
908
bstp_set_port_role(bp,
909
BSTP_ROLE_ALTERNATE);
910
}
911
}
912
break;
913
}
914
}
915
}
916
917
static void
918
bstp_update_state(struct bstp_state *bs, struct bstp_port *bp)
919
{
920
struct bstp_port *bp2;
921
int synced;
922
923
BSTP_LOCK_ASSERT(bs);
924
925
/* check if all the ports have syncronised again */
926
if (!bs->bs_allsynced) {
927
synced = 1;
928
LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
929
if (!(bp2->bp_synced ||
930
bp2->bp_role == BSTP_ROLE_ROOT)) {
931
synced = 0;
932
break;
933
}
934
}
935
bs->bs_allsynced = synced;
936
}
937
938
bstp_update_roles(bs, bp);
939
bstp_update_tc(bp);
940
}
941
942
static void
943
bstp_update_roles(struct bstp_state *bs, struct bstp_port *bp)
944
{
945
NET_EPOCH_ASSERT();
946
947
switch (bp->bp_role) {
948
case BSTP_ROLE_DISABLED:
949
/* Clear any flags if set */
950
if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
951
bp->bp_sync = 0;
952
bp->bp_synced = 1;
953
bp->bp_reroot = 0;
954
}
955
break;
956
957
case BSTP_ROLE_ALTERNATE:
958
case BSTP_ROLE_BACKUP:
959
if ((bs->bs_allsynced && !bp->bp_agree) ||
960
(bp->bp_proposed && bp->bp_agree)) {
961
bp->bp_proposed = 0;
962
bp->bp_agree = 1;
963
bp->bp_flags |= BSTP_PORT_NEWINFO;
964
DPRINTF("%s -> ALTERNATE_AGREED\n",
965
bp->bp_ifp->if_xname);
966
}
967
968
if (bp->bp_proposed && !bp->bp_agree) {
969
bstp_set_all_sync(bs);
970
bp->bp_proposed = 0;
971
DPRINTF("%s -> ALTERNATE_PROPOSED\n",
972
bp->bp_ifp->if_xname);
973
}
974
975
/* Clear any flags if set */
976
if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
977
bp->bp_sync = 0;
978
bp->bp_synced = 1;
979
bp->bp_reroot = 0;
980
DPRINTF("%s -> ALTERNATE_PORT\n", bp->bp_ifp->if_xname);
981
}
982
break;
983
984
case BSTP_ROLE_ROOT:
985
if (bp->bp_state != BSTP_IFSTATE_FORWARDING && !bp->bp_reroot) {
986
bstp_set_all_reroot(bs);
987
DPRINTF("%s -> ROOT_REROOT\n", bp->bp_ifp->if_xname);
988
}
989
990
if ((bs->bs_allsynced && !bp->bp_agree) ||
991
(bp->bp_proposed && bp->bp_agree)) {
992
bp->bp_proposed = 0;
993
bp->bp_sync = 0;
994
bp->bp_agree = 1;
995
bp->bp_flags |= BSTP_PORT_NEWINFO;
996
DPRINTF("%s -> ROOT_AGREED\n", bp->bp_ifp->if_xname);
997
}
998
999
if (bp->bp_proposed && !bp->bp_agree) {
1000
bstp_set_all_sync(bs);
1001
bp->bp_proposed = 0;
1002
DPRINTF("%s -> ROOT_PROPOSED\n", bp->bp_ifp->if_xname);
1003
}
1004
1005
if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1006
(bp->bp_forward_delay_timer.active == 0 ||
1007
(bstp_rerooted(bs, bp) &&
1008
bp->bp_recent_backup_timer.active == 0 &&
1009
bp->bp_protover == BSTP_PROTO_RSTP))) {
1010
switch (bp->bp_state) {
1011
case BSTP_IFSTATE_DISCARDING:
1012
bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1013
break;
1014
case BSTP_IFSTATE_LEARNING:
1015
bstp_set_port_state(bp,
1016
BSTP_IFSTATE_FORWARDING);
1017
break;
1018
}
1019
}
1020
1021
if (bp->bp_state == BSTP_IFSTATE_FORWARDING && bp->bp_reroot) {
1022
bp->bp_reroot = 0;
1023
DPRINTF("%s -> ROOT_REROOTED\n", bp->bp_ifp->if_xname);
1024
}
1025
break;
1026
1027
case BSTP_ROLE_DESIGNATED:
1028
if (bp->bp_recent_root_timer.active == 0 && bp->bp_reroot) {
1029
bp->bp_reroot = 0;
1030
DPRINTF("%s -> DESIGNATED_RETIRED\n",
1031
bp->bp_ifp->if_xname);
1032
}
1033
1034
if ((bp->bp_state == BSTP_IFSTATE_DISCARDING &&
1035
!bp->bp_synced) || (bp->bp_agreed && !bp->bp_synced) ||
1036
(bp->bp_operedge && !bp->bp_synced) ||
1037
(bp->bp_sync && bp->bp_synced)) {
1038
bstp_timer_stop(&bp->bp_recent_root_timer);
1039
bp->bp_synced = 1;
1040
bp->bp_sync = 0;
1041
DPRINTF("%s -> DESIGNATED_SYNCED\n",
1042
bp->bp_ifp->if_xname);
1043
}
1044
1045
if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1046
!bp->bp_agreed && !bp->bp_proposing &&
1047
!bp->bp_operedge) {
1048
bp->bp_proposing = 1;
1049
bp->bp_flags |= BSTP_PORT_NEWINFO;
1050
bstp_timer_start(&bp->bp_edge_delay_timer,
1051
(bp->bp_ptp_link ? BSTP_DEFAULT_MIGRATE_DELAY :
1052
bp->bp_desg_max_age));
1053
DPRINTF("%s -> DESIGNATED_PROPOSE\n",
1054
bp->bp_ifp->if_xname);
1055
}
1056
1057
if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1058
(bp->bp_forward_delay_timer.active == 0 || bp->bp_agreed ||
1059
bp->bp_operedge) &&
1060
(bp->bp_recent_root_timer.active == 0 || !bp->bp_reroot) &&
1061
!bp->bp_sync) {
1062
if (bp->bp_agreed)
1063
DPRINTF("%s -> AGREED\n", bp->bp_ifp->if_xname);
1064
/*
1065
* If agreed|operedge then go straight to forwarding,
1066
* otherwise follow discard -> learn -> forward.
1067
*/
1068
if (bp->bp_agreed || bp->bp_operedge ||
1069
bp->bp_state == BSTP_IFSTATE_LEARNING) {
1070
bstp_set_port_state(bp,
1071
BSTP_IFSTATE_FORWARDING);
1072
bp->bp_agreed = bp->bp_protover;
1073
} else if (bp->bp_state == BSTP_IFSTATE_DISCARDING)
1074
bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1075
}
1076
1077
if (((bp->bp_sync && !bp->bp_synced) ||
1078
(bp->bp_reroot && bp->bp_recent_root_timer.active) ||
1079
(bp->bp_flags & BSTP_PORT_DISPUTED)) && !bp->bp_operedge &&
1080
bp->bp_state != BSTP_IFSTATE_DISCARDING) {
1081
bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1082
bp->bp_flags &= ~BSTP_PORT_DISPUTED;
1083
bstp_timer_start(&bp->bp_forward_delay_timer,
1084
bp->bp_protover == BSTP_PROTO_RSTP ?
1085
bp->bp_desg_htime : bp->bp_desg_fdelay);
1086
DPRINTF("%s -> DESIGNATED_DISCARD\n",
1087
bp->bp_ifp->if_xname);
1088
}
1089
break;
1090
}
1091
1092
if (bp->bp_flags & BSTP_PORT_NEWINFO)
1093
bstp_transmit(bs, bp);
1094
}
1095
1096
static void
1097
bstp_update_tc(struct bstp_port *bp)
1098
{
1099
switch (bp->bp_tcstate) {
1100
case BSTP_TCSTATE_ACTIVE:
1101
if ((bp->bp_role != BSTP_ROLE_DESIGNATED &&
1102
bp->bp_role != BSTP_ROLE_ROOT) || bp->bp_operedge)
1103
bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1104
1105
if (bp->bp_rcvdtcn)
1106
bstp_set_port_tc(bp, BSTP_TCSTATE_TCN);
1107
if (bp->bp_rcvdtc)
1108
bstp_set_port_tc(bp, BSTP_TCSTATE_TC);
1109
1110
if (bp->bp_tc_prop && !bp->bp_operedge)
1111
bstp_set_port_tc(bp, BSTP_TCSTATE_PROPAG);
1112
1113
if (bp->bp_rcvdtca)
1114
bstp_set_port_tc(bp, BSTP_TCSTATE_ACK);
1115
break;
1116
1117
case BSTP_TCSTATE_INACTIVE:
1118
if ((bp->bp_state == BSTP_IFSTATE_LEARNING ||
1119
bp->bp_state == BSTP_IFSTATE_FORWARDING) &&
1120
bp->bp_fdbflush == 0)
1121
bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1122
break;
1123
1124
case BSTP_TCSTATE_LEARNING:
1125
if (bp->bp_rcvdtc || bp->bp_rcvdtcn || bp->bp_rcvdtca ||
1126
bp->bp_tc_prop)
1127
bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1128
else if (bp->bp_role != BSTP_ROLE_DESIGNATED &&
1129
bp->bp_role != BSTP_ROLE_ROOT &&
1130
bp->bp_state == BSTP_IFSTATE_DISCARDING)
1131
bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
1132
1133
if ((bp->bp_role == BSTP_ROLE_DESIGNATED ||
1134
bp->bp_role == BSTP_ROLE_ROOT) &&
1135
bp->bp_state == BSTP_IFSTATE_FORWARDING &&
1136
!bp->bp_operedge)
1137
bstp_set_port_tc(bp, BSTP_TCSTATE_DETECTED);
1138
break;
1139
1140
/* these are transient states and go straight back to ACTIVE */
1141
case BSTP_TCSTATE_DETECTED:
1142
case BSTP_TCSTATE_TCN:
1143
case BSTP_TCSTATE_TC:
1144
case BSTP_TCSTATE_PROPAG:
1145
case BSTP_TCSTATE_ACK:
1146
DPRINTF("Invalid TC state for %s\n",
1147
bp->bp_ifp->if_xname);
1148
break;
1149
}
1150
1151
}
1152
1153
static void
1154
bstp_update_info(struct bstp_port *bp)
1155
{
1156
struct bstp_state *bs = bp->bp_bs;
1157
1158
bp->bp_proposing = 0;
1159
bp->bp_proposed = 0;
1160
1161
if (bp->bp_agreed && !bstp_pdu_bettersame(bp, BSTP_INFO_MINE))
1162
bp->bp_agreed = 0;
1163
1164
if (bp->bp_synced && !bp->bp_agreed) {
1165
bp->bp_synced = 0;
1166
bs->bs_allsynced = 0;
1167
}
1168
1169
/* copy the designated pv to the port */
1170
bp->bp_port_pv = bp->bp_desg_pv;
1171
bp->bp_port_msg_age = bp->bp_desg_msg_age;
1172
bp->bp_port_max_age = bp->bp_desg_max_age;
1173
bp->bp_port_fdelay = bp->bp_desg_fdelay;
1174
bp->bp_port_htime = bp->bp_desg_htime;
1175
bp->bp_infois = BSTP_INFO_MINE;
1176
1177
/* Set transmit flag but do not immediately send */
1178
bp->bp_flags |= BSTP_PORT_NEWINFO;
1179
}
1180
1181
/* set tcprop on every port other than the caller */
1182
static void
1183
bstp_set_other_tcprop(struct bstp_port *bp)
1184
{
1185
struct bstp_state *bs = bp->bp_bs;
1186
struct bstp_port *bp2;
1187
1188
BSTP_LOCK_ASSERT(bs);
1189
1190
LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1191
if (bp2 == bp)
1192
continue;
1193
bp2->bp_tc_prop = 1;
1194
}
1195
}
1196
1197
static void
1198
bstp_set_all_reroot(struct bstp_state *bs)
1199
{
1200
struct bstp_port *bp;
1201
1202
BSTP_LOCK_ASSERT(bs);
1203
1204
LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1205
bp->bp_reroot = 1;
1206
}
1207
1208
static void
1209
bstp_set_all_sync(struct bstp_state *bs)
1210
{
1211
struct bstp_port *bp;
1212
1213
BSTP_LOCK_ASSERT(bs);
1214
1215
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1216
bp->bp_sync = 1;
1217
bp->bp_synced = 0; /* Not explicit in spec */
1218
}
1219
1220
bs->bs_allsynced = 0;
1221
}
1222
1223
static void
1224
bstp_set_port_state(struct bstp_port *bp, int state)
1225
{
1226
if (bp->bp_state == state)
1227
return;
1228
1229
bp->bp_state = state;
1230
1231
switch (bp->bp_state) {
1232
case BSTP_IFSTATE_DISCARDING:
1233
DPRINTF("state changed to DISCARDING on %s\n",
1234
bp->bp_ifp->if_xname);
1235
break;
1236
1237
case BSTP_IFSTATE_LEARNING:
1238
DPRINTF("state changed to LEARNING on %s\n",
1239
bp->bp_ifp->if_xname);
1240
1241
bstp_timer_start(&bp->bp_forward_delay_timer,
1242
bp->bp_protover == BSTP_PROTO_RSTP ?
1243
bp->bp_desg_htime : bp->bp_desg_fdelay);
1244
break;
1245
1246
case BSTP_IFSTATE_FORWARDING:
1247
DPRINTF("state changed to FORWARDING on %s\n",
1248
bp->bp_ifp->if_xname);
1249
1250
bstp_timer_stop(&bp->bp_forward_delay_timer);
1251
/* Record that we enabled forwarding */
1252
bp->bp_forward_transitions++;
1253
break;
1254
}
1255
1256
/* notify the parent bridge */
1257
taskqueue_enqueue(taskqueue_swi, &bp->bp_statetask);
1258
}
1259
1260
static void
1261
bstp_set_port_role(struct bstp_port *bp, int role)
1262
{
1263
struct bstp_state *bs = bp->bp_bs;
1264
1265
if (bp->bp_role == role)
1266
return;
1267
1268
/* perform pre-change tasks */
1269
switch (bp->bp_role) {
1270
case BSTP_ROLE_DISABLED:
1271
bstp_timer_start(&bp->bp_forward_delay_timer,
1272
bp->bp_desg_max_age);
1273
break;
1274
1275
case BSTP_ROLE_BACKUP:
1276
bstp_timer_start(&bp->bp_recent_backup_timer,
1277
bp->bp_desg_htime * 2);
1278
/* fall through */
1279
case BSTP_ROLE_ALTERNATE:
1280
bstp_timer_start(&bp->bp_forward_delay_timer,
1281
bp->bp_desg_fdelay);
1282
bp->bp_sync = 0;
1283
bp->bp_synced = 1;
1284
bp->bp_reroot = 0;
1285
break;
1286
1287
case BSTP_ROLE_ROOT:
1288
bstp_timer_start(&bp->bp_recent_root_timer,
1289
BSTP_DEFAULT_FORWARD_DELAY);
1290
break;
1291
}
1292
1293
bp->bp_role = role;
1294
/* clear values not carried between roles */
1295
bp->bp_proposing = 0;
1296
bs->bs_allsynced = 0;
1297
1298
/* initialise the new role */
1299
switch (bp->bp_role) {
1300
case BSTP_ROLE_DISABLED:
1301
case BSTP_ROLE_ALTERNATE:
1302
case BSTP_ROLE_BACKUP:
1303
DPRINTF("%s role -> ALT/BACK/DISABLED\n",
1304
bp->bp_ifp->if_xname);
1305
bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1306
bstp_timer_stop(&bp->bp_recent_root_timer);
1307
bstp_timer_latch(&bp->bp_forward_delay_timer);
1308
bp->bp_sync = 0;
1309
bp->bp_synced = 1;
1310
bp->bp_reroot = 0;
1311
break;
1312
1313
case BSTP_ROLE_ROOT:
1314
DPRINTF("%s role -> ROOT\n",
1315
bp->bp_ifp->if_xname);
1316
bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1317
bstp_timer_latch(&bp->bp_recent_root_timer);
1318
bp->bp_proposing = 0;
1319
break;
1320
1321
case BSTP_ROLE_DESIGNATED:
1322
DPRINTF("%s role -> DESIGNATED\n",
1323
bp->bp_ifp->if_xname);
1324
bstp_timer_start(&bp->bp_hello_timer,
1325
bp->bp_desg_htime);
1326
bp->bp_agree = 0;
1327
break;
1328
}
1329
1330
/* let the TC state know that the role changed */
1331
bstp_update_tc(bp);
1332
}
1333
1334
static void
1335
bstp_set_port_proto(struct bstp_port *bp, int proto)
1336
{
1337
struct bstp_state *bs = bp->bp_bs;
1338
1339
/* supported protocol versions */
1340
switch (proto) {
1341
case BSTP_PROTO_STP:
1342
/* we can downgrade protocols only */
1343
bstp_timer_stop(&bp->bp_migrate_delay_timer);
1344
/* clear unsupported features */
1345
bp->bp_operedge = 0;
1346
/* STP compat mode only uses 16 bits of the 32 */
1347
if (bp->bp_path_cost > 65535)
1348
bp->bp_path_cost = 65535;
1349
break;
1350
1351
case BSTP_PROTO_RSTP:
1352
bstp_timer_start(&bp->bp_migrate_delay_timer,
1353
bs->bs_migration_delay);
1354
break;
1355
1356
default:
1357
DPRINTF("Unsupported STP version %d\n", proto);
1358
return;
1359
}
1360
1361
bp->bp_protover = proto;
1362
bp->bp_flags &= ~BSTP_PORT_CANMIGRATE;
1363
}
1364
1365
static void
1366
bstp_set_port_tc(struct bstp_port *bp, int state)
1367
{
1368
struct bstp_state *bs = bp->bp_bs;
1369
1370
bp->bp_tcstate = state;
1371
1372
/* initialise the new state */
1373
switch (bp->bp_tcstate) {
1374
case BSTP_TCSTATE_ACTIVE:
1375
DPRINTF("%s -> TC_ACTIVE\n", bp->bp_ifp->if_xname);
1376
/* nothing to do */
1377
break;
1378
1379
case BSTP_TCSTATE_INACTIVE:
1380
bstp_timer_stop(&bp->bp_tc_timer);
1381
/* flush routes on the parent bridge */
1382
bp->bp_fdbflush = 1;
1383
taskqueue_enqueue(taskqueue_swi, &bp->bp_rtagetask);
1384
bp->bp_tc_ack = 0;
1385
DPRINTF("%s -> TC_INACTIVE\n", bp->bp_ifp->if_xname);
1386
break;
1387
1388
case BSTP_TCSTATE_LEARNING:
1389
bp->bp_rcvdtc = 0;
1390
bp->bp_rcvdtcn = 0;
1391
bp->bp_rcvdtca = 0;
1392
bp->bp_tc_prop = 0;
1393
DPRINTF("%s -> TC_LEARNING\n", bp->bp_ifp->if_xname);
1394
break;
1395
1396
case BSTP_TCSTATE_DETECTED:
1397
bstp_set_timer_tc(bp);
1398
bstp_set_other_tcprop(bp);
1399
/* send out notification */
1400
bp->bp_flags |= BSTP_PORT_NEWINFO;
1401
bstp_transmit(bs, bp);
1402
getmicrotime(&bs->bs_last_tc_time);
1403
DPRINTF("%s -> TC_DETECTED\n", bp->bp_ifp->if_xname);
1404
bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1405
break;
1406
1407
case BSTP_TCSTATE_TCN:
1408
bstp_set_timer_tc(bp);
1409
DPRINTF("%s -> TC_TCN\n", bp->bp_ifp->if_xname);
1410
/* fall through */
1411
case BSTP_TCSTATE_TC:
1412
bp->bp_rcvdtc = 0;
1413
bp->bp_rcvdtcn = 0;
1414
if (bp->bp_role == BSTP_ROLE_DESIGNATED)
1415
bp->bp_tc_ack = 1;
1416
1417
bstp_set_other_tcprop(bp);
1418
DPRINTF("%s -> TC_TC\n", bp->bp_ifp->if_xname);
1419
bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1420
break;
1421
1422
case BSTP_TCSTATE_PROPAG:
1423
/* flush routes on the parent bridge */
1424
bp->bp_fdbflush = 1;
1425
taskqueue_enqueue(taskqueue_swi, &bp->bp_rtagetask);
1426
bp->bp_tc_prop = 0;
1427
bstp_set_timer_tc(bp);
1428
DPRINTF("%s -> TC_PROPAG\n", bp->bp_ifp->if_xname);
1429
bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1430
break;
1431
1432
case BSTP_TCSTATE_ACK:
1433
bstp_timer_stop(&bp->bp_tc_timer);
1434
bp->bp_rcvdtca = 0;
1435
DPRINTF("%s -> TC_ACK\n", bp->bp_ifp->if_xname);
1436
bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1437
break;
1438
}
1439
}
1440
1441
static void
1442
bstp_set_timer_tc(struct bstp_port *bp)
1443
{
1444
struct bstp_state *bs = bp->bp_bs;
1445
1446
if (bp->bp_tc_timer.active)
1447
return;
1448
1449
switch (bp->bp_protover) {
1450
case BSTP_PROTO_RSTP:
1451
bstp_timer_start(&bp->bp_tc_timer,
1452
bp->bp_desg_htime + BSTP_TICK_VAL);
1453
bp->bp_flags |= BSTP_PORT_NEWINFO;
1454
break;
1455
1456
case BSTP_PROTO_STP:
1457
bstp_timer_start(&bp->bp_tc_timer,
1458
bs->bs_root_max_age + bs->bs_root_fdelay);
1459
break;
1460
}
1461
}
1462
1463
static void
1464
bstp_set_timer_msgage(struct bstp_port *bp)
1465
{
1466
if (bp->bp_port_msg_age + BSTP_MESSAGE_AGE_INCR <=
1467
bp->bp_port_max_age) {
1468
bstp_timer_start(&bp->bp_message_age_timer,
1469
bp->bp_port_htime * 3);
1470
} else
1471
/* expires immediately */
1472
bstp_timer_start(&bp->bp_message_age_timer, 0);
1473
}
1474
1475
static int
1476
bstp_rerooted(struct bstp_state *bs, struct bstp_port *bp)
1477
{
1478
struct bstp_port *bp2;
1479
int rr_set = 0;
1480
1481
LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1482
if (bp2 == bp)
1483
continue;
1484
if (bp2->bp_recent_root_timer.active) {
1485
rr_set = 1;
1486
break;
1487
}
1488
}
1489
return (!rr_set);
1490
}
1491
1492
int
1493
bstp_set_htime(struct bstp_state *bs, int t)
1494
{
1495
/* convert seconds to ticks */
1496
t *= BSTP_TICK_VAL;
1497
1498
/* value can only be changed in leagacy stp mode */
1499
if (bs->bs_protover != BSTP_PROTO_STP)
1500
return (EPERM);
1501
1502
if (t < BSTP_MIN_HELLO_TIME || t > BSTP_MAX_HELLO_TIME)
1503
return (EINVAL);
1504
1505
BSTP_LOCK(bs);
1506
bs->bs_bridge_htime = t;
1507
bstp_reinit(bs);
1508
BSTP_UNLOCK(bs);
1509
return (0);
1510
}
1511
1512
int
1513
bstp_set_fdelay(struct bstp_state *bs, int t)
1514
{
1515
/* convert seconds to ticks */
1516
t *= BSTP_TICK_VAL;
1517
1518
if (t < BSTP_MIN_FORWARD_DELAY || t > BSTP_MAX_FORWARD_DELAY)
1519
return (EINVAL);
1520
1521
BSTP_LOCK(bs);
1522
bs->bs_bridge_fdelay = t;
1523
bstp_reinit(bs);
1524
BSTP_UNLOCK(bs);
1525
return (0);
1526
}
1527
1528
int
1529
bstp_set_maxage(struct bstp_state *bs, int t)
1530
{
1531
/* convert seconds to ticks */
1532
t *= BSTP_TICK_VAL;
1533
1534
if (t < BSTP_MIN_MAX_AGE || t > BSTP_MAX_MAX_AGE)
1535
return (EINVAL);
1536
1537
BSTP_LOCK(bs);
1538
bs->bs_bridge_max_age = t;
1539
bstp_reinit(bs);
1540
BSTP_UNLOCK(bs);
1541
return (0);
1542
}
1543
1544
int
1545
bstp_set_holdcount(struct bstp_state *bs, int count)
1546
{
1547
struct bstp_port *bp;
1548
1549
if (count < BSTP_MIN_HOLD_COUNT ||
1550
count > BSTP_MAX_HOLD_COUNT)
1551
return (EINVAL);
1552
1553
BSTP_LOCK(bs);
1554
bs->bs_txholdcount = count;
1555
LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1556
bp->bp_txcount = 0;
1557
BSTP_UNLOCK(bs);
1558
return (0);
1559
}
1560
1561
int
1562
bstp_set_protocol(struct bstp_state *bs, int proto)
1563
{
1564
struct bstp_port *bp;
1565
1566
switch (proto) {
1567
/* Supported protocol versions */
1568
case BSTP_PROTO_STP:
1569
case BSTP_PROTO_RSTP:
1570
break;
1571
1572
default:
1573
return (EINVAL);
1574
}
1575
1576
BSTP_LOCK(bs);
1577
bs->bs_protover = proto;
1578
bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
1579
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1580
/* reinit state */
1581
bp->bp_infois = BSTP_INFO_DISABLED;
1582
bp->bp_txcount = 0;
1583
bstp_set_port_proto(bp, bs->bs_protover);
1584
bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
1585
bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
1586
bstp_timer_stop(&bp->bp_recent_backup_timer);
1587
}
1588
bstp_reinit(bs);
1589
BSTP_UNLOCK(bs);
1590
return (0);
1591
}
1592
1593
int
1594
bstp_set_priority(struct bstp_state *bs, int pri)
1595
{
1596
if (pri < 0 || pri > BSTP_MAX_PRIORITY)
1597
return (EINVAL);
1598
1599
/* Limit to steps of 4096 */
1600
pri -= pri % 4096;
1601
1602
BSTP_LOCK(bs);
1603
bs->bs_bridge_priority = pri;
1604
bstp_reinit(bs);
1605
BSTP_UNLOCK(bs);
1606
return (0);
1607
}
1608
1609
int
1610
bstp_set_port_priority(struct bstp_port *bp, int pri)
1611
{
1612
struct bstp_state *bs = bp->bp_bs;
1613
1614
if (pri < 0 || pri > BSTP_MAX_PORT_PRIORITY)
1615
return (EINVAL);
1616
1617
/* Limit to steps of 16 */
1618
pri -= pri % 16;
1619
1620
BSTP_LOCK(bs);
1621
bp->bp_priority = pri;
1622
bstp_reinit(bs);
1623
BSTP_UNLOCK(bs);
1624
return (0);
1625
}
1626
1627
int
1628
bstp_set_path_cost(struct bstp_port *bp, uint32_t path_cost)
1629
{
1630
struct bstp_state *bs = bp->bp_bs;
1631
1632
if (path_cost > BSTP_MAX_PATH_COST)
1633
return (EINVAL);
1634
1635
/* STP compat mode only uses 16 bits of the 32 */
1636
if (bp->bp_protover == BSTP_PROTO_STP && path_cost > 65535)
1637
path_cost = 65535;
1638
1639
BSTP_LOCK(bs);
1640
1641
if (path_cost == 0) { /* use auto */
1642
bp->bp_flags &= ~BSTP_PORT_ADMCOST;
1643
bp->bp_path_cost = bstp_calc_path_cost(bp);
1644
} else {
1645
bp->bp_path_cost = path_cost;
1646
bp->bp_flags |= BSTP_PORT_ADMCOST;
1647
}
1648
bstp_reinit(bs);
1649
BSTP_UNLOCK(bs);
1650
return (0);
1651
}
1652
1653
int
1654
bstp_set_edge(struct bstp_port *bp, int set)
1655
{
1656
struct bstp_state *bs = bp->bp_bs;
1657
1658
BSTP_LOCK(bs);
1659
if ((bp->bp_operedge = set) == 0)
1660
bp->bp_flags &= ~BSTP_PORT_ADMEDGE;
1661
else
1662
bp->bp_flags |= BSTP_PORT_ADMEDGE;
1663
BSTP_UNLOCK(bs);
1664
return (0);
1665
}
1666
1667
int
1668
bstp_set_autoedge(struct bstp_port *bp, int set)
1669
{
1670
struct bstp_state *bs = bp->bp_bs;
1671
1672
BSTP_LOCK(bs);
1673
if (set) {
1674
bp->bp_flags |= BSTP_PORT_AUTOEDGE;
1675
/* we may be able to transition straight to edge */
1676
if (bp->bp_edge_delay_timer.active == 0)
1677
bstp_edge_delay_expiry(bs, bp);
1678
} else
1679
bp->bp_flags &= ~BSTP_PORT_AUTOEDGE;
1680
BSTP_UNLOCK(bs);
1681
return (0);
1682
}
1683
1684
int
1685
bstp_set_ptp(struct bstp_port *bp, int set)
1686
{
1687
struct bstp_state *bs = bp->bp_bs;
1688
1689
BSTP_LOCK(bs);
1690
bp->bp_ptp_link = set;
1691
BSTP_UNLOCK(bs);
1692
return (0);
1693
}
1694
1695
int
1696
bstp_set_autoptp(struct bstp_port *bp, int set)
1697
{
1698
struct bstp_state *bs = bp->bp_bs;
1699
1700
BSTP_LOCK(bs);
1701
if (set) {
1702
bp->bp_flags |= BSTP_PORT_AUTOPTP;
1703
if (bp->bp_role != BSTP_ROLE_DISABLED)
1704
taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
1705
} else
1706
bp->bp_flags &= ~BSTP_PORT_AUTOPTP;
1707
BSTP_UNLOCK(bs);
1708
return (0);
1709
}
1710
1711
/*
1712
* Calculate the path cost according to the link speed.
1713
*/
1714
static uint32_t
1715
bstp_calc_path_cost(struct bstp_port *bp)
1716
{
1717
struct ifnet *ifp = bp->bp_ifp;
1718
uint32_t path_cost;
1719
1720
/* If the priority has been manually set then retain the value */
1721
if (bp->bp_flags & BSTP_PORT_ADMCOST)
1722
return bp->bp_path_cost;
1723
1724
if (ifp->if_link_state == LINK_STATE_DOWN) {
1725
/* Recalc when the link comes up again */
1726
bp->bp_flags |= BSTP_PORT_PNDCOST;
1727
return (BSTP_DEFAULT_PATH_COST);
1728
}
1729
1730
if (ifp->if_baudrate < 1000)
1731
return (BSTP_DEFAULT_PATH_COST);
1732
1733
/* formula from section 17.14, IEEE Std 802.1D-2004 */
1734
path_cost = 20000000000ULL / (ifp->if_baudrate / 1000);
1735
1736
if (path_cost > BSTP_MAX_PATH_COST)
1737
path_cost = BSTP_MAX_PATH_COST;
1738
1739
/* STP compat mode only uses 16 bits of the 32 */
1740
if (bp->bp_protover == BSTP_PROTO_STP && path_cost > 65535)
1741
path_cost = 65535;
1742
1743
return (path_cost);
1744
}
1745
1746
/*
1747
* Notify the bridge that a port state has changed, we need to do this from a
1748
* taskqueue to avoid a LOR.
1749
*/
1750
static void
1751
bstp_notify_state(void *arg, int pending)
1752
{
1753
struct bstp_port *bp = (struct bstp_port *)arg;
1754
struct bstp_state *bs = bp->bp_bs;
1755
1756
if (bp->bp_active == 1 && bs->bs_state_cb != NULL)
1757
(*bs->bs_state_cb)(bp->bp_ifp, bp->bp_state);
1758
}
1759
1760
/*
1761
* Flush the routes on the bridge port, we need to do this from a
1762
* taskqueue to avoid a LOR.
1763
*/
1764
static void
1765
bstp_notify_rtage(void *arg, int pending)
1766
{
1767
struct bstp_port *bp = (struct bstp_port *)arg;
1768
struct bstp_state *bs = bp->bp_bs;
1769
int age = 0;
1770
1771
BSTP_LOCK(bs);
1772
switch (bp->bp_protover) {
1773
case BSTP_PROTO_STP:
1774
/* convert to seconds */
1775
age = bp->bp_desg_fdelay / BSTP_TICK_VAL;
1776
break;
1777
1778
case BSTP_PROTO_RSTP:
1779
age = 0;
1780
break;
1781
}
1782
BSTP_UNLOCK(bs);
1783
1784
if (bp->bp_active == 1 && bs->bs_rtage_cb != NULL)
1785
(*bs->bs_rtage_cb)(bp->bp_ifp, age);
1786
1787
/* flush is complete */
1788
BSTP_LOCK(bs);
1789
bp->bp_fdbflush = 0;
1790
BSTP_UNLOCK(bs);
1791
}
1792
1793
void
1794
bstp_linkstate(struct bstp_port *bp)
1795
{
1796
struct bstp_state *bs = bp->bp_bs;
1797
1798
if (!bp->bp_active)
1799
return;
1800
1801
bstp_ifupdstatus(bp, 0);
1802
BSTP_LOCK(bs);
1803
bstp_update_state(bs, bp);
1804
BSTP_UNLOCK(bs);
1805
}
1806
1807
static void
1808
bstp_ifupdstatus(void *arg, int pending)
1809
{
1810
struct bstp_port *bp = (struct bstp_port *)arg;
1811
struct bstp_state *bs = bp->bp_bs;
1812
struct ifnet *ifp = bp->bp_ifp;
1813
struct ifmediareq ifmr;
1814
int error, changed;
1815
1816
if (!bp->bp_active)
1817
return;
1818
1819
bzero((char *)&ifmr, sizeof(ifmr));
1820
error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
1821
1822
BSTP_LOCK(bs);
1823
changed = 0;
1824
if ((error == 0) && (ifp->if_flags & IFF_UP)) {
1825
if (ifmr.ifm_status & IFM_ACTIVE) {
1826
/* A full-duplex link is assumed to be point to point */
1827
if (bp->bp_flags & BSTP_PORT_AUTOPTP) {
1828
int fdx;
1829
1830
fdx = ifmr.ifm_active & IFM_FDX ? 1 : 0;
1831
if (bp->bp_ptp_link ^ fdx) {
1832
bp->bp_ptp_link = fdx;
1833
changed = 1;
1834
}
1835
}
1836
1837
/* Calc the cost if the link was down previously */
1838
if (bp->bp_flags & BSTP_PORT_PNDCOST) {
1839
uint32_t cost;
1840
1841
cost = bstp_calc_path_cost(bp);
1842
if (bp->bp_path_cost != cost) {
1843
bp->bp_path_cost = cost;
1844
changed = 1;
1845
}
1846
bp->bp_flags &= ~BSTP_PORT_PNDCOST;
1847
}
1848
1849
if (bp->bp_role == BSTP_ROLE_DISABLED) {
1850
bstp_enable_port(bs, bp);
1851
changed = 1;
1852
}
1853
} else {
1854
if (bp->bp_role != BSTP_ROLE_DISABLED) {
1855
bstp_disable_port(bs, bp);
1856
changed = 1;
1857
if ((bp->bp_flags & BSTP_PORT_ADMEDGE) &&
1858
bp->bp_protover == BSTP_PROTO_RSTP)
1859
bp->bp_operedge = 1;
1860
}
1861
}
1862
} else if (bp->bp_infois != BSTP_INFO_DISABLED) {
1863
bstp_disable_port(bs, bp);
1864
changed = 1;
1865
}
1866
if (changed)
1867
bstp_assign_roles(bs);
1868
BSTP_UNLOCK(bs);
1869
}
1870
1871
static void
1872
bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp)
1873
{
1874
bp->bp_infois = BSTP_INFO_AGED;
1875
}
1876
1877
static void
1878
bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp)
1879
{
1880
bp->bp_infois = BSTP_INFO_DISABLED;
1881
}
1882
1883
static void
1884
bstp_tick(void *arg)
1885
{
1886
struct epoch_tracker et;
1887
struct bstp_state *bs = arg;
1888
struct bstp_port *bp;
1889
1890
BSTP_LOCK_ASSERT(bs);
1891
1892
if (bs->bs_running == 0)
1893
return;
1894
1895
NET_EPOCH_ENTER(et);
1896
CURVNET_SET(bs->bs_vnet);
1897
1898
/* poll link events on interfaces that do not support linkstate */
1899
if (bstp_timer_dectest(&bs->bs_link_timer)) {
1900
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1901
if (!(bp->bp_ifp->if_capabilities & IFCAP_LINKSTATE))
1902
taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
1903
}
1904
bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
1905
}
1906
1907
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1908
/* no events need to happen for these */
1909
bstp_timer_dectest(&bp->bp_tc_timer);
1910
bstp_timer_dectest(&bp->bp_recent_root_timer);
1911
bstp_timer_dectest(&bp->bp_forward_delay_timer);
1912
bstp_timer_dectest(&bp->bp_recent_backup_timer);
1913
1914
if (bstp_timer_dectest(&bp->bp_hello_timer))
1915
bstp_hello_timer_expiry(bs, bp);
1916
1917
if (bstp_timer_dectest(&bp->bp_message_age_timer))
1918
bstp_message_age_expiry(bs, bp);
1919
1920
if (bstp_timer_dectest(&bp->bp_migrate_delay_timer))
1921
bstp_migrate_delay_expiry(bs, bp);
1922
1923
if (bstp_timer_dectest(&bp->bp_edge_delay_timer))
1924
bstp_edge_delay_expiry(bs, bp);
1925
1926
/* update the various state machines for the port */
1927
bstp_update_state(bs, bp);
1928
1929
if (bp->bp_txcount > 0)
1930
bp->bp_txcount--;
1931
}
1932
1933
CURVNET_RESTORE();
1934
NET_EPOCH_EXIT(et);
1935
1936
callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
1937
}
1938
1939
static void
1940
bstp_timer_start(struct bstp_timer *t, uint16_t v)
1941
{
1942
t->value = v;
1943
t->active = 1;
1944
t->latched = 0;
1945
}
1946
1947
static void
1948
bstp_timer_stop(struct bstp_timer *t)
1949
{
1950
t->value = 0;
1951
t->active = 0;
1952
t->latched = 0;
1953
}
1954
1955
static void
1956
bstp_timer_latch(struct bstp_timer *t)
1957
{
1958
t->latched = 1;
1959
t->active = 1;
1960
}
1961
1962
static int
1963
bstp_timer_dectest(struct bstp_timer *t)
1964
{
1965
if (t->active == 0 || t->latched)
1966
return (0);
1967
t->value -= BSTP_TICK_VAL;
1968
if (t->value <= 0) {
1969
bstp_timer_stop(t);
1970
return (1);
1971
}
1972
return (0);
1973
}
1974
1975
static void
1976
bstp_hello_timer_expiry(struct bstp_state *bs, struct bstp_port *bp)
1977
{
1978
if ((bp->bp_flags & BSTP_PORT_NEWINFO) ||
1979
bp->bp_role == BSTP_ROLE_DESIGNATED ||
1980
(bp->bp_role == BSTP_ROLE_ROOT &&
1981
bp->bp_tc_timer.active == 1)) {
1982
bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
1983
bp->bp_flags |= BSTP_PORT_NEWINFO;
1984
bstp_transmit(bs, bp);
1985
}
1986
}
1987
1988
static void
1989
bstp_message_age_expiry(struct bstp_state *bs, struct bstp_port *bp)
1990
{
1991
if (bp->bp_infois == BSTP_INFO_RECEIVED) {
1992
bp->bp_infois = BSTP_INFO_AGED;
1993
bstp_assign_roles(bs);
1994
DPRINTF("aged info on %s\n", bp->bp_ifp->if_xname);
1995
}
1996
}
1997
1998
static void
1999
bstp_migrate_delay_expiry(struct bstp_state *bs, struct bstp_port *bp)
2000
{
2001
bp->bp_flags |= BSTP_PORT_CANMIGRATE;
2002
}
2003
2004
static void
2005
bstp_edge_delay_expiry(struct bstp_state *bs, struct bstp_port *bp)
2006
{
2007
if ((bp->bp_flags & BSTP_PORT_AUTOEDGE) &&
2008
bp->bp_protover == BSTP_PROTO_RSTP && bp->bp_proposing &&
2009
bp->bp_role == BSTP_ROLE_DESIGNATED) {
2010
bp->bp_operedge = 1;
2011
DPRINTF("%s -> edge port\n", bp->bp_ifp->if_xname);
2012
}
2013
}
2014
2015
static int
2016
bstp_addr_cmp(const uint8_t *a, const uint8_t *b)
2017
{
2018
int i, d;
2019
2020
for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
2021
d = ((int)a[i]) - ((int)b[i]);
2022
}
2023
2024
return (d);
2025
}
2026
2027
/*
2028
* compare the bridge address component of the bridgeid
2029
*/
2030
static int
2031
bstp_same_bridgeid(uint64_t id1, uint64_t id2)
2032
{
2033
u_char addr1[ETHER_ADDR_LEN];
2034
u_char addr2[ETHER_ADDR_LEN];
2035
2036
PV2ADDR(id1, addr1);
2037
PV2ADDR(id2, addr2);
2038
2039
if (bstp_addr_cmp(addr1, addr2) == 0)
2040
return (1);
2041
2042
return (0);
2043
}
2044
2045
void
2046
bstp_reinit(struct bstp_state *bs)
2047
{
2048
struct epoch_tracker et;
2049
struct bstp_port *bp;
2050
struct ifnet *ifp, *mif;
2051
u_char *e_addr;
2052
void *bridgeptr;
2053
static const u_char llzero[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */
2054
2055
BSTP_LOCK_ASSERT(bs);
2056
2057
if (LIST_EMPTY(&bs->bs_bplist))
2058
goto disablestp;
2059
2060
mif = NULL;
2061
bridgeptr = LIST_FIRST(&bs->bs_bplist)->bp_ifp->if_bridge;
2062
KASSERT(bridgeptr != NULL, ("Invalid bridge pointer"));
2063
KASSERT(bridge_same_p != NULL, ("if_bridge not loaded"));
2064
/*
2065
* Search through the Ethernet adapters and find the one with the
2066
* lowest value. Make sure the adapter which we take the MAC address
2067
* from is part of this bridge, so we can have more than one independent
2068
* bridges in the same STP domain.
2069
*/
2070
NET_EPOCH_ENTER(et);
2071
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2072
if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN)
2073
continue; /* Not Ethernet */
2074
2075
if (!bridge_same_p(ifp->if_bridge, bridgeptr))
2076
continue; /* Not part of our bridge */
2077
2078
if (bstp_addr_cmp(IF_LLADDR(ifp), llzero) == 0)
2079
continue; /* No mac address set */
2080
2081
if (mif == NULL) {
2082
mif = ifp;
2083
continue;
2084
}
2085
if (bstp_addr_cmp(IF_LLADDR(ifp), IF_LLADDR(mif)) < 0) {
2086
mif = ifp;
2087
continue;
2088
}
2089
}
2090
NET_EPOCH_EXIT(et);
2091
if (mif == NULL)
2092
goto disablestp;
2093
2094
e_addr = IF_LLADDR(mif);
2095
bs->bs_bridge_pv.pv_dbridge_id =
2096
(((uint64_t)bs->bs_bridge_priority) << 48) |
2097
(((uint64_t)e_addr[0]) << 40) |
2098
(((uint64_t)e_addr[1]) << 32) |
2099
(((uint64_t)e_addr[2]) << 24) |
2100
(((uint64_t)e_addr[3]) << 16) |
2101
(((uint64_t)e_addr[4]) << 8) |
2102
(((uint64_t)e_addr[5]));
2103
2104
bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id;
2105
bs->bs_bridge_pv.pv_cost = 0;
2106
bs->bs_bridge_pv.pv_dport_id = 0;
2107
bs->bs_bridge_pv.pv_port_id = 0;
2108
2109
if (bs->bs_running && callout_pending(&bs->bs_bstpcallout) == 0)
2110
callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
2111
2112
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2113
bp->bp_port_id = (bp->bp_priority << 8) |
2114
(bp->bp_ifp->if_index & 0xfff);
2115
taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
2116
}
2117
2118
bstp_assign_roles(bs);
2119
bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
2120
return;
2121
2122
disablestp:
2123
/* Set the bridge and root id (lower bits) to zero */
2124
bs->bs_bridge_pv.pv_dbridge_id =
2125
((uint64_t)bs->bs_bridge_priority) << 48;
2126
bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id;
2127
bs->bs_root_pv = bs->bs_bridge_pv;
2128
/* Disable any remaining ports, they will have no MAC address */
2129
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2130
bp->bp_infois = BSTP_INFO_DISABLED;
2131
bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2132
}
2133
callout_stop(&bs->bs_bstpcallout);
2134
}
2135
2136
static int
2137
bstp_modevent(module_t mod, int type, void *data)
2138
{
2139
switch (type) {
2140
case MOD_LOAD:
2141
mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF);
2142
break;
2143
case MOD_UNLOAD:
2144
mtx_destroy(&bstp_list_mtx);
2145
break;
2146
default:
2147
return (EOPNOTSUPP);
2148
}
2149
return (0);
2150
}
2151
2152
static moduledata_t bstp_mod = {
2153
"bridgestp",
2154
bstp_modevent,
2155
0
2156
};
2157
2158
DECLARE_MODULE(bridgestp, bstp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
2159
MODULE_VERSION(bridgestp, 1);
2160
2161
void
2162
bstp_attach(struct bstp_state *bs, struct bstp_cb_ops *cb)
2163
{
2164
BSTP_LOCK_INIT(bs);
2165
callout_init_mtx(&bs->bs_bstpcallout, &bs->bs_mtx, 0);
2166
LIST_INIT(&bs->bs_bplist);
2167
2168
bs->bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
2169
bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
2170
bs->bs_bridge_fdelay = BSTP_DEFAULT_FORWARD_DELAY;
2171
bs->bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
2172
bs->bs_hold_time = BSTP_DEFAULT_HOLD_TIME;
2173
bs->bs_migration_delay = BSTP_DEFAULT_MIGRATE_DELAY;
2174
bs->bs_txholdcount = BSTP_DEFAULT_HOLD_COUNT;
2175
bs->bs_protover = BSTP_PROTO_RSTP;
2176
bs->bs_state_cb = cb->bcb_state;
2177
bs->bs_rtage_cb = cb->bcb_rtage;
2178
bs->bs_vnet = curvnet;
2179
2180
getmicrotime(&bs->bs_last_tc_time);
2181
2182
mtx_lock(&bstp_list_mtx);
2183
LIST_INSERT_HEAD(&bstp_list, bs, bs_list);
2184
mtx_unlock(&bstp_list_mtx);
2185
}
2186
2187
void
2188
bstp_detach(struct bstp_state *bs)
2189
{
2190
KASSERT(LIST_EMPTY(&bs->bs_bplist), ("bstp still active"));
2191
2192
mtx_lock(&bstp_list_mtx);
2193
LIST_REMOVE(bs, bs_list);
2194
mtx_unlock(&bstp_list_mtx);
2195
callout_drain(&bs->bs_bstpcallout);
2196
BSTP_LOCK_DESTROY(bs);
2197
}
2198
2199
void
2200
bstp_init(struct bstp_state *bs)
2201
{
2202
BSTP_LOCK(bs);
2203
callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
2204
bs->bs_running = 1;
2205
bstp_reinit(bs);
2206
BSTP_UNLOCK(bs);
2207
}
2208
2209
void
2210
bstp_stop(struct bstp_state *bs)
2211
{
2212
struct bstp_port *bp;
2213
2214
BSTP_LOCK(bs);
2215
2216
LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
2217
bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
2218
2219
bs->bs_running = 0;
2220
callout_stop(&bs->bs_bstpcallout);
2221
BSTP_UNLOCK(bs);
2222
}
2223
2224
int
2225
bstp_create(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp)
2226
{
2227
bzero(bp, sizeof(struct bstp_port));
2228
2229
BSTP_LOCK(bs);
2230
bp->bp_ifp = ifp;
2231
bp->bp_bs = bs;
2232
bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY;
2233
TASK_INIT(&bp->bp_statetask, 0, bstp_notify_state, bp);
2234
TASK_INIT(&bp->bp_rtagetask, 0, bstp_notify_rtage, bp);
2235
TASK_INIT(&bp->bp_mediatask, 0, bstp_ifupdstatus, bp);
2236
2237
/* Init state */
2238
bp->bp_infois = BSTP_INFO_DISABLED;
2239
bp->bp_flags = BSTP_PORT_AUTOEDGE|BSTP_PORT_AUTOPTP;
2240
bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
2241
bstp_set_port_proto(bp, bs->bs_protover);
2242
bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2243
bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
2244
bp->bp_path_cost = bstp_calc_path_cost(bp);
2245
BSTP_UNLOCK(bs);
2246
return (0);
2247
}
2248
2249
int
2250
bstp_enable(struct bstp_port *bp)
2251
{
2252
struct bstp_state *bs = bp->bp_bs;
2253
struct ifnet *ifp = bp->bp_ifp;
2254
2255
KASSERT(bp->bp_active == 0, ("already a bstp member"));
2256
NET_EPOCH_ASSERT(); /* Because bstp_update_roles() causes traffic. */
2257
2258
switch (ifp->if_type) {
2259
case IFT_ETHER: /* These can do spanning tree. */
2260
case IFT_L2VLAN:
2261
break;
2262
default:
2263
/* Nothing else can. */
2264
return (EINVAL);
2265
}
2266
2267
BSTP_LOCK(bs);
2268
LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next);
2269
bp->bp_active = 1;
2270
bp->bp_flags |= BSTP_PORT_NEWINFO;
2271
bstp_reinit(bs);
2272
bstp_update_roles(bs, bp);
2273
BSTP_UNLOCK(bs);
2274
return (0);
2275
}
2276
2277
void
2278
bstp_disable(struct bstp_port *bp)
2279
{
2280
struct bstp_state *bs = bp->bp_bs;
2281
2282
KASSERT(bp->bp_active == 1, ("not a bstp member"));
2283
2284
BSTP_LOCK(bs);
2285
bstp_disable_port(bs, bp);
2286
LIST_REMOVE(bp, bp_next);
2287
bp->bp_active = 0;
2288
bstp_reinit(bs);
2289
BSTP_UNLOCK(bs);
2290
}
2291
2292
/*
2293
* The bstp_port structure is about to be freed by the parent bridge.
2294
*/
2295
void
2296
bstp_destroy(struct bstp_port *bp)
2297
{
2298
KASSERT(bp->bp_active == 0, ("port is still attached"));
2299
taskqueue_drain(taskqueue_swi, &bp->bp_statetask);
2300
taskqueue_drain(taskqueue_swi, &bp->bp_rtagetask);
2301
taskqueue_drain(taskqueue_swi, &bp->bp_mediatask);
2302
2303
if (bp->bp_bs->bs_root_port == bp)
2304
bstp_assign_roles(bp->bp_bs);
2305
}
2306
2307