1 /* Copyright 2005 Renzo Davoli VDE-2
2 * Licensed under the GPLv2
12 #include <sys/socket.h>
15 #include <netinet/in.h> /*ntoh conversion*/
30 /*********************** sending macro used by FSTP & Core ******************/
33 #define STP_AGREEMENT 0x40
34 #define STP_FORWARDING 0x20
35 #define STP_LEARNING 0x10
36 #define STP_PORTROLEMASK 0x0c
38 #define STP_PROPOSAL 0x02
42 #define DBGFSTPSTATUS (dl)
43 #define DBGFSTPROOT (dl+1)
44 #define DBGFSTPPLUS (dl+2)
45 #define DBGFSTPMINUS (dl+3)
46 static struct dbgcl dl
[]= {
47 {"fstp/status","fstp: status change",D_FSTP
|D_STATUS
},
48 {"fstp/root","fstp: rootswitch/port change",D_FSTP
|D_ROOT
},
49 {"fstp/+","fstp: port becomes active",D_FSTP
|D_PLUS
},
50 {"fstp/-","fstp: port becomes inactive",D_FSTP
|D_MINUS
},
52 static char *fstpdecodestatus
[]={
56 "learning+forwarding"};
57 #define port_set_status(P,V,S) \
58 ({DBGOUT(DBGFSTPSTATUS,"Port %04d VLAN %02x:%02x %s",\
59 (P),(V)>>8,(V)&0xff,fstpdecodestatus[(S)]);\
60 EVENTOUT(DBGFSTPSTATUS,(P),(V),(S));\
61 port_set_status(P,V,S);})
64 #define SWITCHID_LEN (ETH_ALEN+2)
65 #define FSTP_ACTIVE(VLAN,PORT) (BA_CHECK(fsttab[(VLAN)]->rcvhist[0],(PORT)) || \
66 BA_CHECK(fsttab[(VLAN)]->rcvhist[1],(PORT)))
68 static int rcvhistindex
;
70 unsigned char root
[SWITCHID_LEN
];
72 unsigned char dessw
[SWITCHID_LEN
];
78 /* TC: topology change timers missing XXX */
79 unsigned int roottimestamp
;
87 #define BPDUADDR {0x01,0x80,0xc2,0x00,0x00,0x00}
88 unsigned char bpduaddrp
[]=BPDUADDR
;
89 #define SETFSTID(ID,MAC,PRIO) ({ \
90 char *id=(char *)(ID); \
93 memcpy(id,(MAC),ETH_ALEN); 0; })
94 static unsigned char myid
[SWITCHID_LEN
];
96 #define STDHELLOPERIOD 4
97 static struct vlst
*fsttab
[NUMOFVLAN
];
98 static int helloperiod
= STDHELLOPERIOD
;
99 static int maxage
= STDHELLOPERIOD
*10;
100 static int fst_timerno
;
102 /* packet prototype for untagged ports */
104 struct ethheader header
;
105 unsigned char llc
[3];
106 unsigned char stp_protocol
[2];
107 unsigned char stp_version
;
108 unsigned char stp_type
;
109 unsigned char stp_flags
;
110 unsigned char stp_root
[SWITCHID_LEN
];
111 unsigned char stp_rootcost
[4];
112 unsigned char stp_bridge
[SWITCHID_LEN
];
113 unsigned char stp_port
[2];
114 unsigned char stp_age
[2];
115 unsigned char stp_maxage
[2];
116 unsigned char stp_hello
[2];
117 unsigned char stp_fwddelay
[2];
118 unsigned char stp_v1len
;
121 /* packet prototype for tagged ports */
123 struct ethheader header
;
124 unsigned char tag_vlan
[2];
125 unsigned char tag_proto
[2];
126 unsigned char llc
[3];
127 unsigned char stp_protocol
[2];
128 unsigned char stp_version
;
129 unsigned char stp_type
;
130 unsigned char stp_flags
;
131 unsigned char stp_root
[SWITCHID_LEN
];
132 unsigned char stp_rootcost
[4];
133 unsigned char stp_bridge
[SWITCHID_LEN
];
134 unsigned char stp_port
[2];
135 unsigned char stp_age
[2];
136 unsigned char stp_maxage
[2];
137 unsigned char stp_hello
[2];
138 unsigned char stp_fwddelay
[2];
139 unsigned char stp_v1len
;
142 static struct fstbpdu outpacket
= {
143 .header
.dest
=BPDUADDR
,
144 .header
.proto
={0x00,0x39}, /* 802.3 packet length */
145 .llc
={0x42,0x42,0x3},
151 static struct fsttagbpdu outtagpacket
= {
152 .header
.dest
=BPDUADDR
,
153 .header
.proto
={0x81,0x00},
154 .tag_proto
={0x00,0x39},
155 .llc
={0x42,0x42,0x3},
165 * 2/3 PORT ROLE: 00 UNKNOWN 01 ALT/BACKUP 10 ROOT 11 DESIGNATED
166 * 4 LEARNING 5 FORWARDING
168 * 7 TOPOLOGY CHANGE ACK
171 #define STP_FLAGS(VLAN,PORT,AGR,TC,TCACK) \
173 (BA_CHECK(fsttab[(VLAN)]->backup,port) != 0) << 1 | \
174 (BA_CHECK(fsttab[(VLAN)]->backup,port) == 0) << 2 | \
175 (fsttab[vlan]->rootport != (PORT)) << 3 |\
176 port_get_status((PORT),(VLAN)) << 4 | \
180 int fstnewvlan(int vlan
)
182 /*printf("F new vlan %d\n",vlan);*/
183 register unsigned int port
;
184 int newvlan
=(fsttab
[vlan
] == NULL
);
186 ((fsttab
[vlan
]=malloc(sizeof(struct vlst
))) == NULL
||
187 (fsttab
[vlan
]->untag
= BA_ALLOC(numports
)) == NULL
||
188 (fsttab
[vlan
]->tagged
= BA_ALLOC(numports
)) == NULL
||
189 (fsttab
[vlan
]->edge
= BA_ALLOC(numports
)) == NULL
||
190 (fsttab
[vlan
]->rcvhist
[0] = BA_ALLOC(numports
)) == NULL
||
191 (fsttab
[vlan
]->rcvhist
[1] = BA_ALLOC(numports
)) == NULL
||
192 (fsttab
[vlan
]->backup
= BA_ALLOC(numports
)) == NULL
))
195 memcpy(fsttab
[vlan
]->root
,myid
,SWITCHID_LEN
);
196 memset(fsttab
[vlan
]->rootcost
,0,4);
197 memset(fsttab
[vlan
]->dessw
,0xff,SWITCHID_LEN
);
198 memset(fsttab
[vlan
]->port
,0,4);
199 fsttab
[vlan
]->rootport
=fsttab
[vlan
]->roottimestamp
=0;
201 fsttab
[vlan
]->bonusport
=fsttab
[vlan
]->bonuscost
=0;
202 fsttab
[vlan
]->tctime
=0;
204 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
206 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1],
207 fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
208 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5],
209 fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
210 EVENTOUT(DBGFSTPROOT
,0,vlan
,fsttab
[vlan
]->root
);
211 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
212 BA_CLR(fsttab
[vlan
]->backup
,port
);
213 port_set_status(port
,vlan
,FORWARDING
);
219 int fstremovevlan(int vlan
)
221 /*printf("F remove vlan %d\n",vlan);*/
222 if (fsttab
[vlan
] == NULL
)
225 struct vlst
*old
=fsttab
[vlan
];
231 free(old
->rcvhist
[0]);
232 free(old
->rcvhist
[1]);
238 void fstsetnumports (int val
)
241 /*printf("F numports %d\n",val);*/
242 for (i
=0;i
<NUMOFVLAN
;i
++) {
244 fsttab
[i
]->untag
=BA_REALLOC(fsttab
[i
]->untag
,numports
,val
);
245 if (fsttab
[i
]->untag
== NULL
) {
246 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/untag %s",strerror(errno
));
249 fsttab
[i
]->tagged
=BA_REALLOC(fsttab
[i
]->tagged
,numports
,val
);
250 if (fsttab
[i
]->tagged
== NULL
) {
251 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/tagged %s",strerror(errno
));
254 fsttab
[i
]->backup
=BA_REALLOC(fsttab
[i
]->backup
,numports
,val
);
255 if (fsttab
[i
]->backup
== NULL
) {
256 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/backup %s",strerror(errno
));
259 fsttab
[i
]->edge
=BA_REALLOC(fsttab
[i
]->edge
,numports
,val
);
260 if (fsttab
[i
]->edge
== NULL
) {
261 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/edge %s",strerror(errno
));
264 fsttab
[i
]->rcvhist
[0]=BA_REALLOC(fsttab
[i
]->rcvhist
[0],numports
,val
);
265 if (fsttab
[i
]->rcvhist
[0] == NULL
) {
266 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist0 %s",strerror(errno
));
269 fsttab
[i
]->rcvhist
[1]=BA_REALLOC(fsttab
[i
]->rcvhist
[1],numports
,val
);
270 if (fsttab
[i
]->rcvhist
[1] == NULL
) {
271 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist1 %s",strerror(errno
));
280 static void fst_hello_vlan(int vlan
,int now
)
284 /* timeout on the root port */
285 if (fsttab
[vlan
]->rootport
!= 0 && (now
- fsttab
[vlan
]->roottimestamp
) > 3*helloperiod
)
287 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
288 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
289 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
290 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
291 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
292 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
293 if (age
> 0xffff) age
=0xffff;
294 outpacket
.stp_age
[0] = outtagpacket
.stp_age
[0]=age
;
295 outpacket
.stp_age
[1] = outtagpacket
.stp_age
[1]=age
>>8;
296 outpacket
.stp_fwddelay
[0] = outtagpacket
.stp_fwddelay
[0]=0;
297 outpacket
.stp_fwddelay
[1] = outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
298 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
299 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
300 outpacket
.stp_port
[0]=0x80| (port
>>4);
301 outpacket
.stp_port
[1]=port
;
302 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
303 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
306 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
307 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
308 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
309 outtagpacket
.stp_port
[1]=port
;
310 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
311 outtagpacket
.tag_vlan
[1]=vlan
;
312 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
313 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
318 /* a port that is not handling control packets for a while cannot be
319 * a backup port. It means that the other end is not speaking FSTP anymore.
320 * It must be reverted to a designed forwarding port.
322 static void fst_updatebackup(int vlan
,int index
)
325 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
326 if (!FSTP_ACTIVE(vlan
,port
)) {
327 BA_CLR(fsttab
[vlan
]->backup
,port
);
328 port_set_status(port
,vlan
,FORWARDING
);
332 BA_FORALL(fsttab
[vlan
]->untag
,numports
,({
333 if (BA_CHECK(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(BA_CHECK(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
334 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
335 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
337 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,({
338 if (BA_CHECK(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(BA_CHECK(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
339 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
340 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
343 BA_ZAP(fsttab
[vlan
]->rcvhist
[index
],numports
);
346 static void fst_hello(void *arg
)
349 static int hellocounter
;
352 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fst_hello_vlan
,now
);
353 if ((hellocounter
& 0x3) == 0) {
354 rcvhistindex
=1-rcvhistindex
;
355 BAC_FORALLFUN(validvlan
,NUMOFVLAN
, fst_updatebackup
,rcvhistindex
);
359 static void fst_sendbpdu(int vlan
,int port
,int agr
,int tc
,int tcack
)
363 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
364 if (BA_CHECK(fsttab
[vlan
]->untag
,port
)) {
365 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
366 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
367 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
368 if (age
> 0xffff) age
=0xffff;
369 outpacket
.stp_age
[0] = age
;
370 outpacket
.stp_age
[1] = age
>>8;
371 outpacket
.stp_fwddelay
[0] = 0;
372 outpacket
.stp_fwddelay
[1] = 0; /* XXX */
373 outpacket
.stp_port
[0]=0x80| (port
>>4);
374 outpacket
.stp_port
[1]=port
;
375 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
376 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
378 if (BA_CHECK(fsttab
[vlan
]->tagged
,port
)) {
379 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
380 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
381 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
382 if (age
> 0xffff) age
=0xffff;
383 outtagpacket
.stp_age
[0]=age
;
384 outtagpacket
.stp_age
[1]=age
>>8;
385 outtagpacket
.stp_fwddelay
[0]=0;
386 outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
387 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
388 outtagpacket
.stp_port
[1]=port
;
389 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
390 outtagpacket
.tag_vlan
[1]=vlan
;
391 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
392 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
396 /* Topology change flood
397 * two main difference between this and 802.1d/w:
398 * - it flushes all the hash table for this vlan (including the "calling" port
399 * - do not send all the packet with TC but just this
401 static void topology_change(int vlan
, int genport
)
405 //if (now - fsttab[vlan]->tctime > 2*helloperiod) { /*limit age?*/
406 /*printf("TOPOLOGY CHANGE %d\n",vlan);*/
407 fsttab
[vlan
]->tctime
=now
;
408 hash_delete_vlan(vlan
);
409 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
410 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
411 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
412 fst_sendbpdu(vlan
,port
,0,1,0); }
414 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
415 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
416 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
417 fst_sendbpdu(vlan
,port
,0,1,0); }
422 /* heart of the fast protocol:
423 * 1- receive a proposal
424 * 2- stop all the designed ports
425 * 3- give back the acknowledge and put the new root in fwd*/
426 static void fastprotocol(int vlan
, int newrootport
)
429 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
430 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
431 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
432 port_set_status(port
,vlan
,DISCARDING
);
433 BA_SET(fsttab
[vlan
]->backup
,port
);
434 fst_sendbpdu(vlan
,port
,0,0,0); }
436 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
437 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
438 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
439 port_set_status(port
,vlan
,DISCARDING
);
440 BA_SET(fsttab
[vlan
]->backup
,port
);
441 fst_sendbpdu(vlan
,port
,0,0,0); }
443 BA_CLR(fsttab
[vlan
]->backup
,newrootport
); /* forward ON */
444 port_set_status(newrootport
,vlan
,FORWARDING
);
445 fst_sendbpdu(vlan
,newrootport
,1,0,0);
448 /* handling of bpdu incoming packets */
449 void fst_in_bpdu(int port
, struct packet
*inpacket
, int len
, int vlan
, int tagged
)
452 /* XXX check the header for fake info? */
453 struct vlst
*v
=fsttab
[vlan
];
455 if (!(pflag
& FSTP_TAG
) || (BA_CHECK(fsttab
[vlan
]->edge
,port
)))
456 return; /*FST IS TURNED OFF or EDGE*/
458 if (!FSTP_ACTIVE(vlan
,port
)) {
459 DBGOUT(DBGFSTPPLUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
460 EVENTOUT(DBGFSTPPLUS
,port
,vlan
);
463 BA_SET(fsttab
[vlan
]->rcvhist
[rcvhistindex
],port
);
466 p
=(struct fstbpdu
*)(((unsigned char *)inpacket
)+4);
469 p
=(struct fstbpdu
*)(inpacket
);
470 if (len
< 51 || v
==NULL
|| p
->stp_version
!= 2 || p
->stp_type
!= 2)
471 return; /* faulty packet */
472 /* this is a topology change packet */
473 if (p
->stp_flags
& STP_TC
)
474 topology_change(vlan
,port
);
475 *((u_int32_t
*)(p
->stp_rootcost
))=
476 htonl(ntohl(*((u_int32_t
*)(p
->stp_rootcost
)))+
477 (port_getcost(port
)-((port
==v
->bonusport
)?v
->bonuscost
:0)));
479 /* >0 means new root, == 0 root unchanged, <0 sender must change topology */
480 if ((val
=valroot
=memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
)) == 0)
481 if ((val
=memcmp(v
->rootcost
,p
->stp_rootcost
,4)) == 0)
482 if ((val
=memcmp(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
)) == 0)
483 val
=memcmp(v
->port
,p
->stp_port
,2);
484 /*printf("VAL = %d root=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
485 " recv=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n",val,
486 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
487 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
488 p->stp_root[0], p->stp_root[1], p->stp_root[2], p->stp_root[3],
489 p->stp_root[4], p->stp_root[5], p->stp_root[6], p->stp_root[7]);
490 printf("++ stp_bridge=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
491 " cost=%02x:%02x:%02x:%02x: port %02x:%02x \n",
492 p->stp_bridge[0], p->stp_bridge[1], p->stp_bridge[2], p->stp_bridge[3],
493 p->stp_bridge[4], p->stp_bridge[5], p->stp_bridge[6], p->stp_bridge[7],
494 p->stp_rootcost[0], p->stp_rootcost[1], p->stp_rootcost[2], p->stp_rootcost[3],
495 p->stp_port[0], p->stp_port[1]); */
496 if (val
== 0) { /* root unchanged / new root announce*/
497 v
->roottimestamp
=qtime();
498 } else { /* new root or new root info*/
499 if (val
> 0 || (port
== fsttab
[vlan
]->rootport
&& val
<0)) {
500 if (memcmp(v
->root
,outpacket
.header
.src
,8) <= 0)
502 /* printf("NEW ROOT\n");*/
503 memcpy(v
->root
,p
->stp_root
,SWITCHID_LEN
);
504 memcpy(v
->rootcost
,p
->stp_rootcost
,4);
505 memcpy(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
);
506 memcpy(v
->port
,p
->stp_port
,2);
508 v
->roottimestamp
=qtime();
509 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
510 port
,vlan
>>8,vlan
&0xff,
511 v
->root
[0], v
->root
[1], v
->root
[2], v
->root
[3],
512 v
->root
[4], v
->root
[5], v
->root
[6], v
->root
[7]);
513 EVENTOUT(DBGFSTPROOT
,port
,vlan
,v
->root
);
514 fastprotocol(vlan
,port
);
515 topology_change(vlan
,port
);
518 if (memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
) == 0) {
519 /* critical point: longer path to root */
520 /* root -> designated */
521 /* non-root -> blocking */
522 if ((p
->stp_flags
& STP_PORTROLEMASK
) == STP_ROOT
) {
523 if (BA_CHECK(v
->backup
,port
)) {
524 /* backup -> designated transition */
525 //printf("backup -> designated port %d\n",port);
526 BA_CLR(v
->backup
,port
); /* forward ON */
527 port_set_status(port
,vlan
,FORWARDING
);
528 topology_change(vlan
,port
);
531 if (!BA_CHECK(v
->backup
,port
)) {
532 /* designated -> backup transition */
533 //printf("designated ->backup port %d\n",port);
534 BA_SET(v
->backup
,port
); /* forward OFF */
535 port_set_status(port
,vlan
,DISCARDING
);
536 topology_change(vlan
,port
);
540 /*printf("THIS?\n");*/
541 fst_sendbpdu(vlan
,port
,0,0,0);
547 void fstaddport(int vlan
,int port
,int tagged
)
549 /*printf("F addport V %d - P %d - T%d\n",vlan,port,tagged);*/
551 BA_SET(fsttab
[vlan
]->tagged
,port
);
552 BA_CLR(fsttab
[vlan
]->untag
,port
);
554 BA_SET(fsttab
[vlan
]->untag
,port
);
555 BA_CLR(fsttab
[vlan
]->tagged
,port
);
557 BA_CLR(fsttab
[vlan
]->backup
,port
);
558 BA_CLR(fsttab
[vlan
]->edge
,port
);
559 BA_CLR(fsttab
[vlan
]->rcvhist
[0],port
);
560 BA_CLR(fsttab
[vlan
]->rcvhist
[1],port
);
561 fst_sendbpdu(vlan
,port
,0,0,0);
562 topology_change(vlan
,port
);
565 void fstdelport(int vlan
,int port
)
567 /*printf("F delport V %d - P %d\n",vlan,port);*/
568 if (FSTP_ACTIVE(vlan
,port
)) {
569 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
570 EVENTOUT(DBGFSTPMINUS
,port
,vlan
);
572 BA_CLR(fsttab
[vlan
]->untag
,port
);
573 BA_CLR(fsttab
[vlan
]->tagged
,port
);
574 BA_CLR(fsttab
[vlan
]->backup
,port
);
575 BA_CLR(fsttab
[vlan
]->edge
,port
);
576 if (port
== fsttab
[vlan
]->rootport
) {
579 topology_change(vlan
,port
);
582 static void fstinitpkt(void)
584 memcpy(outpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
585 memcpy(outtagpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
586 memcpy(outpacket
.header
.src
,switchmac
,ETH_ALEN
);
587 memcpy(outtagpacket
.header
.src
,switchmac
,ETH_ALEN
);
588 outpacket
.stp_hello
[0]=outtagpacket
.stp_hello
[0]=helloperiod
,
589 outpacket
.stp_hello
[1]=outtagpacket
.stp_hello
[1]=helloperiod
>>8,
590 outpacket
.stp_maxage
[0]=outtagpacket
.stp_maxage
[0]=maxage
,
591 outpacket
.stp_maxage
[1]=outtagpacket
.stp_maxage
[1]=maxage
>>8,
592 fst_timerno
=qtimer_add(helloperiod
,0,fst_hello
,NULL
);
595 static int fstpshowinfo(FILE *fd
)
597 printoutc(fd
,"MAC %02x:%02x:%02x:%02x:%02x:%02x Priority %d (0x%x)",
598 switchmac
[0], switchmac
[1], switchmac
[2], switchmac
[3], switchmac
[4], switchmac
[5],
600 printoutc(fd
,"FSTP=%s",(pflag
& FSTP_TAG
)?"true":"false");
604 static void fstnewvlan2(int vlan
, void *arg
)
609 static int fstpsetonoff(int val
)
611 int oldval
=((pflag
& FSTP_TAG
) != 0);
615 if (val
) { /* START FST */
617 fstflag(P_SETFLAG
,FSTP_TAG
);
618 } else { /* STOP FST */
619 qtimer_del(fst_timerno
);
620 fstflag(P_CLRFLAG
,FSTP_TAG
);
621 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
627 static char *decoderole(int vlan
, int port
)
629 if (!(BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
)))
631 if (BA_CHECK(fsttab
[vlan
]->edge
,port
))
633 if (fsttab
[vlan
]->rootport
== port
)
635 if (BA_CHECK(fsttab
[vlan
]->backup
,port
))
636 return "Alternate/Backup";
640 static void fstprintactive(int vlan
,FILE *fd
)
643 printoutc(fd
,"FST DATA VLAN %04d %s %s",vlan
,
644 memcmp(myid
,fsttab
[vlan
]->root
,SWITCHID_LEN
)==0?"ROOTSWITCH":"",
645 ((pflag
& FSTP_TAG
)==0)?"FSTP IS DISABLED":"");
646 printoutc(fd
, " ++ root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
647 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
648 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
649 printoutc(fd
, " ++ designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
650 fsttab
[vlan
]->dessw
[0], fsttab
[vlan
]->dessw
[1], fsttab
[vlan
]->dessw
[2], fsttab
[vlan
]->dessw
[3],
651 fsttab
[vlan
]->dessw
[4], fsttab
[vlan
]->dessw
[5], fsttab
[vlan
]->dessw
[6], fsttab
[vlan
]->dessw
[7]);
652 printoutc(fd
, " ++ rootport %04d cost %d age %d bonusport %04d bonuscost %d",
653 fsttab
[vlan
]->rootport
,
654 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
655 qtime()-fsttab
[vlan
]->roottimestamp
,fsttab
[vlan
]->bonusport
,fsttab
[vlan
]->bonuscost
);
656 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
657 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,0,port_getcost(i
),decoderole(vlan
,i
)),i
);
658 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
659 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,1,port_getcost(i
),decoderole(vlan
,i
)),i
);
662 static int fstprint(FILE *fd
,char *arg
)
667 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
668 if (BAC_CHECK(validvlan
,vlan
))
669 fstprintactive(vlan
,fd
);
675 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstprintactive
,fd
);
679 static int fstsetbonus(char *arg
)
681 int vlan
, port
, cost
;
682 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&cost
) != 3)
684 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
686 if (!BAC_CHECK(validvlan
,vlan
))
688 fsttab
[vlan
]->bonusport
=port
;
689 fsttab
[vlan
]->bonuscost
=cost
;
693 static int fstsetedge(char *arg
)
696 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&val
) != 3)
698 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
700 if (!BAC_CHECK(validvlan
,vlan
))
703 BA_SET(fsttab
[vlan
]->edge
,port
);
704 if (BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
))
705 port_set_status(port
,vlan
,FORWARDING
);
707 BA_CLR(fsttab
[vlan
]->edge
,port
);
708 BA_CLR(fsttab
[vlan
]->backup
,port
);
713 static struct comlist cl
[]={
714 {"fstp","============","FAST SPANNING TREE MENU",NULL
,NOARG
},
715 {"fstp/showinfo","","show fstp info",fstpshowinfo
,NOARG
|WITHFILE
},
716 {"fstp/setfstp","0/1","Fast spanning tree protocol 1=ON 0=OFF",fstpsetonoff
,INTARG
},
717 {"fstp/setedge","VLAN PORT 1/0","Define an edge port for a vlan 1=Y 0=N",fstsetedge
,STRARG
},
718 {"fstp/bonus","VLAN PORT COST","set the port bonus for a vlan",fstsetbonus
,STRARG
},
719 {"fstp/print","[N]","print fst data for the defined vlan",fstprint
,STRARG
|WITHFILE
},
722 int fstflag(int op
,int f
)
726 case P_SETFLAG
: pflag
=f
; break;
727 case P_ADDFLAG
: pflag
|= f
; break;
728 case P_CLRFLAG
: pflag
&= ~f
; break;
733 void fst_init(int initnumports
)
735 numports
=initnumports
;
736 SETFSTID(myid
,switchmac
,priority
);
737 if (pflag
& FSTP_TAG
)