]> git.ipfire.org Git - people/ms/rstp.git/blame - rstplib/stpm.c
Initial commit
[people/ms/rstp.git] / rstplib / stpm.c
CommitLineData
ad02a0eb
SH
1/************************************************************************
2 * RSTP library - Rapid Spanning Tree (802.1t, 802.1w)
3 * Copyright (C) 2001-2003 Optical Access
4 * Author: Alex Rozin
5 *
6 * This file is part of RSTP library.
7 *
8 * RSTP library is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by the
10 * Free Software Foundation; version 2.1
11 *
12 * RSTP library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with RSTP library; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 **********************************************************************/
22
23 /* STP machine instance : bridge per VLAN: 17.17 */
24
25#include "base.h"
26#include "stpm.h"
27#include "stp_to.h" /* for STP_OUT_flush_lt */
28
29/*static*/ STPM_T *bridges = NULL;
30
31/* We can flush learned fdb by port, so set this in stpm.c and topoch.c */
32/* This doesn't seem to solve the topology change problems. Don't use it yet */
33//#define STRONGLY_SPEC_802_1W
34
35static int
36_stp_stpm_init_machine (STATE_MACH_T* this)
37{
38 this->State = BEGIN;
39 (*(this->concreteEnterState)) (this);
40 return 0;
41}
42
43static int
44_stp_stpm_iterate_machines (STPM_T* this,
45 int (*iter_callb) (STATE_MACH_T*),
46 Bool exit_on_non_zero_ret)
47{
48 register STATE_MACH_T* stater;
49 register PORT_T* port;
50 int iret, mret = 0;
51
52 /* state machines per bridge */
53 for (stater = this->machines; stater; stater = stater->next) {
54 iret = (*iter_callb) (stater);
55 if (exit_on_non_zero_ret && iret)
56 return iret;
57 else
58 mret += iret;
59 }
60
61 /* state machines per port */
62 for (port = this->ports; port; port = port->next) {
63 for (stater = port->machines; stater; stater = stater->next) {
64 iret = (*iter_callb) (stater);
65 if (exit_on_non_zero_ret && iret)
66 return iret;
67 else
68 mret += iret;
69 }
70 }
71
72 return mret;
73}
74
75void
76_stp_stpm_init_data (STPM_T* this)
77{
78 STP_VECT_create (&this->rootPrio,
79 &this->BrId,
80 0,
81 &this->BrId,
82 0, 0);
83
84 this->BrTimes.MessageAge = 0;
85
86 STP_copy_times (&this->rootTimes, &this->BrTimes);
87}
88
89static unsigned char
90_check_topoch (STPM_T* this)
91{
92 register PORT_T* port;
93
94 for (port = this->ports; port; port = port->next) {
95 if (port->tcWhile) {
96 return 1;
97 }
98 }
99 return 0;
100}
101
102void
103STP_stpm_one_second (STPM_T* param)
104{
105 STPM_T* this = (STPM_T*) param;
106 register PORT_T* port;
107 register int iii;
108
109 if (STP_ENABLED != this->admin_state) return;
110
111 for (port = this->ports; port; port = port->next) {
112 for (iii = 0; iii < TIMERS_NUMBER; iii++) {
113 if (*(port->timers[iii]) > 0) {
114 (*port->timers[iii])--;
115 }
116 }
117 port->uptime++;
118 }
119
120 STP_stpm_update (this);
121 this->Topo_Change = _check_topoch (this);
122 if (this->Topo_Change) {
123 this->Topo_Change_Count++;
124 this->timeSince_Topo_Change = 0;
125 } else {
126 this->Topo_Change_Count = 0;
127 this->timeSince_Topo_Change++;
128 }
129}
130
131STPM_T*
132STP_stpm_create (int vlan_id, char* name)
133{
134 STPM_T* this;
135
136 STP_NEW_IN_LIST(this, STPM_T, bridges, "stp instance");
137
138 this->admin_state = STP_DISABLED;
139
140 this->vlan_id = vlan_id;
141 if (name) {
142 STP_STRDUP(this->name, name, "stp bridge name");
143 }
144
145 this->machines = NULL;
146 this->ports = NULL;
147
148 STP_STATE_MACH_IN_LIST(rolesel);
149
150#ifdef STP_DBG
151 /* this->rolesel->debug = 2; */
152#endif
153
154 return this;
155}
156
157int
158STP_stpm_enable (STPM_T* this, UID_STP_MODE_T admin_state)
159{
160 int rc = 0;
161
162 if (admin_state == this->admin_state) {
163 /* nothing to do :) */
164 return 0;
165 }
166
167 if (STP_ENABLED == admin_state) {
168 rc = STP_stpm_start (this);
169 this->admin_state = admin_state;
170 } else {
171 this->admin_state = admin_state;
172 STP_stpm_stop (this);
173 }
174
175 return rc;
176}
177
178void
179STP_stpm_delete (STPM_T* this)
180{
181 register STPM_T* tmp;
182 register STPM_T* prev;
183 register STATE_MACH_T* stater;
184 register PORT_T* port;
185 register void* pv;
186
187 STP_stpm_enable (this, STP_DISABLED);
188
189 for (stater = this->machines; stater; ) {
190 pv = (void*) stater->next;
191 STP_state_mach_delete (stater);
192 this->machines = stater = (STATE_MACH_T*) pv;
193 }
194
195 for (port = this->ports; port; ) {
196 pv = (void*) port->next;
197 STP_port_delete (port);
198 this->ports = port = (PORT_T*) pv;
199 }
200
201 prev = NULL;
202 for (tmp = bridges; tmp; tmp = tmp->next) {
203 if (tmp->vlan_id == this->vlan_id) {
204 if (prev) {
205 prev->next = this->next;
206 } else {
207 bridges = this->next;
208 }
209
210 if (this->name)
211 STP_FREE(this->name, "stp bridge name");
212 STP_FREE(this, "stp instance");
213 break;
214 }
215 prev = tmp;
216 }
217}
218
219int
220STP_stpm_start (STPM_T* this)
221{
222 register PORT_T* port;
223
224#ifdef ORIG
225 if (! this->ports) { /* there are not any ports :( */
226 return STP_There_Are_No_Ports;
227 }
228#endif
229
230 if (! STP_compute_bridge_id (this)) {/* can't compute bridge id ? :( */
231 return STP_Cannot_Compute_Bridge_Prio;
232 }
233
234 /* check, that the stpm has unique bridge Id */
235 if (0 != STP_stpm_check_bridge_priority (this)) {
236 /* there is an enabled bridge with same ID :( */
237 return STP_Invalid_Bridge_Priority;
238 }
239
240 _stp_stpm_init_data (this);
241
242 for (port = this->ports; port; port = port->next) {
243 STP_port_init (port, this, True);
244 }
245
246#ifndef STRONGLY_SPEC_802_1W
247 /* A. see comment near STRONGLY_SPEC_802_1W in topoch.c */
248 /* B. port=0 here means: delete for all ports */
249#ifdef STP_DBG
250 stp_trace("%s (all, start stpm)",
251 "clearFDB");
252#endif
253
254 STP_OUT_flush_lt (0, this->vlan_id, LT_FLASH_ONLY_THE_PORT, "start stpm");
255#endif
256
257 _stp_stpm_iterate_machines (this, _stp_stpm_init_machine, False);
258 STP_stpm_update (this);
259
260 return 0;
261}
262
263void
264STP_stpm_stop (STPM_T* this)
265{
266}
267
268int
269STP_stpm_update (STPM_T* this) /* returns number of loops */
270{
271 register Bool need_state_change;
272 register int number_of_loops = 0;
273
274 need_state_change = False;
275
276 for (;;) {/* loop until not need changes */
277 need_state_change = _stp_stpm_iterate_machines (this,
278 STP_check_condition,
279 True);
280 if (! need_state_change) return number_of_loops;
281
282 number_of_loops++;
283 /* here we know, that at least one stater must be
284 updated (it has changed state) */
285 number_of_loops += _stp_stpm_iterate_machines (this,
286 STP_change_state,
287 False);
288
289 }
290
291 return number_of_loops;
292}
293
294BRIDGE_ID *
295STP_compute_bridge_id (STPM_T* this)
296{
297 register PORT_T* port;
298 unsigned char old[6], new[6];
299 memset(&old, 0xff, sizeof(old));
300
301 for (port = this->ports; port; port = port->next) {
302 STP_OUT_get_port_mac (port->port_index, new);
303 if (memcmp(new, old, sizeof(old)) < 0)
304 memcpy(old, new, sizeof(old));
305 }
306
307 memcpy(this->BrId.addr, old, sizeof(old));
308
309 return &this->BrId;
310}
311
312STPM_T*
313STP_stpm_get_the_list (void)
314{
315 return bridges;
316}
317
318void
319STP_stpm_update_after_bridge_management (STPM_T* this)
320{
321 register PORT_T* port;
322
323 for (port = this->ports; port; port = port->next) {
324 port->reselect = True;
325 port->selected = False;
326 }
327}
328
329int
330STP_stpm_check_bridge_priority (STPM_T* this)
331{
332 register STPM_T* oth;
333
334 for (oth = bridges; oth; oth = oth->next) {
335 if (STP_ENABLED == oth->admin_state && oth != this &&
336 ! STP_VECT_compare_bridge_id (&this->BrId, &oth->BrId)) {
337 return STP_Invalid_Bridge_Priority;
338 }
339 }
340
341 return 0;
342}
343
344const char*
345STP_stpm_get_port_name_by_id (STPM_T* this, PORT_ID port_id)
346{
347 register PORT_T* port;
348
349 for (port = this->ports; port; port = port->next) {
350 if (port_id == port->port_id) {
351 return port->port_name;
352 }
353 }
354
355 return "Undef?";
356}
357
358
359
360
361