]>
Commit | Line | Data |
---|---|---|
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 | ||
35 | static int | |
36 | _stp_stpm_init_machine (STATE_MACH_T* this) | |
37 | { | |
38 | this->State = BEGIN; | |
39 | (*(this->concreteEnterState)) (this); | |
40 | return 0; | |
41 | } | |
42 | ||
43 | static 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 | ||
75 | void | |
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 | ||
89 | static 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 | ||
102 | void | |
103 | STP_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 | ||
131 | STPM_T* | |
132 | STP_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 | ||
157 | int | |
158 | STP_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 | ||
178 | void | |
179 | STP_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 | ||
219 | int | |
220 | STP_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 | ||
263 | void | |
264 | STP_stpm_stop (STPM_T* this) | |
265 | { | |
266 | } | |
267 | ||
268 | int | |
269 | STP_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 | ||
294 | BRIDGE_ID * | |
295 | STP_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 | ||
312 | STPM_T* | |
313 | STP_stpm_get_the_list (void) | |
314 | { | |
315 | return bridges; | |
316 | } | |
317 | ||
318 | void | |
319 | STP_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 | ||
329 | int | |
330 | STP_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 | ||
344 | const char* | |
345 | STP_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 |