1 /* Copyright 2005 Renzo Davoli VDE-2
2 * Licensed under the GPLv2
11 #include <sys/socket.h>
13 #include <netinet/in.h> /*ntoh conversion*/
17 #include <vdecommon.h>
32 /*********************** sending macro used by FSTP & Core ******************/
33 void inline ltonstring(unsigned long l
,unsigned char *s
) {
40 unsigned long inline nstringtol(unsigned char *s
) {
41 return (s
[0]<<24)+(s
[1]<<16)+(s
[2]<<8)+s
[3];
45 #define STP_AGREEMENT 0x40
46 #define STP_FORWARDING 0x20
47 #define STP_LEARNING 0x10
48 #define STP_PORTROLEMASK 0x0c
50 #define STP_PROPOSAL 0x02
54 #define DBGFSTPSTATUS (dl)
55 #define DBGFSTPROOT (dl+1)
56 #define DBGFSTPPLUS (dl+2)
57 #define DBGFSTPMINUS (dl+3)
58 static struct dbgcl dl
[]= {
59 {"fstp/status","fstp: status change",D_FSTP
|D_STATUS
},
60 {"fstp/root","fstp: rootswitch/port change",D_FSTP
|D_ROOT
},
61 {"fstp/+","fstp: port becomes active",D_FSTP
|D_PLUS
},
62 {"fstp/-","fstp: port becomes inactive",D_FSTP
|D_MINUS
},
64 static char *fstpdecodestatus
[]={
68 "learning+forwarding"};
69 #define port_set_status(P,V,S) \
70 ({DBGOUT(DBGFSTPSTATUS,"Port %04d VLAN %02x:%02x %s",\
71 (P),(V)>>8,(V)&0xff,fstpdecodestatus[(S)]);\
72 EVENTOUT(DBGFSTPSTATUS,(P),(V),(S));\
73 port_set_status(P,V,S);})
76 #define SWITCHID_LEN (ETH_ALEN+2)
77 #define FSTP_ACTIVE(VLAN,PORT) (ba_check(fsttab[(VLAN)]->rcvhist[0],(PORT)) || \
78 ba_check(fsttab[(VLAN)]->rcvhist[1],(PORT)))
80 static int rcvhistindex
;
82 unsigned char root
[SWITCHID_LEN
];
83 unsigned char rootcost
[4];
84 unsigned char dessw
[SWITCHID_LEN
];
85 unsigned char port
[2];
90 /* TC: topology change timers missing XXX */
91 unsigned int roottimestamp
;
99 #define BPDUADDR {0x01,0x80,0xc2,0x00,0x00,0x00}
100 unsigned char bpduaddrp
[]=BPDUADDR
;
101 #define SETFSTID(ID,MAC,PRIO) ({ \
102 char *id=(char *)(ID); \
105 memcpy(id,(MAC),ETH_ALEN); 0; })
106 static unsigned char myid
[SWITCHID_LEN
];
108 #define STDHELLOPERIOD 4
109 static struct vlst
*fsttab
[NUMOFVLAN
];
110 static int helloperiod
= STDHELLOPERIOD
;
111 static int maxage
= STDHELLOPERIOD
*10;
112 static int fst_timerno
;
114 /* packet prototype for untagged ports */
116 struct ethheader header
;
117 unsigned char llc
[3];
118 unsigned char stp_protocol
[2];
119 unsigned char stp_version
;
120 unsigned char stp_type
;
121 unsigned char stp_flags
;
122 unsigned char stp_root
[SWITCHID_LEN
];
123 unsigned char stp_rootcost
[4];
124 unsigned char stp_bridge
[SWITCHID_LEN
];
125 unsigned char stp_port
[2];
126 unsigned char stp_age
[2];
127 unsigned char stp_maxage
[2];
128 unsigned char stp_hello
[2];
129 unsigned char stp_fwddelay
[2];
130 unsigned char stp_v1len
;
131 } __attribute__((packed
));;
133 /* packet prototype for tagged ports */
135 struct ethheader header
;
136 unsigned char tag_vlan
[2];
137 unsigned char tag_proto
[2];
138 unsigned char llc
[3];
139 unsigned char stp_protocol
[2];
140 unsigned char stp_version
;
141 unsigned char stp_type
;
142 unsigned char stp_flags
;
143 unsigned char stp_root
[SWITCHID_LEN
];
144 unsigned char stp_rootcost
[4];
145 unsigned char stp_bridge
[SWITCHID_LEN
];
146 unsigned char stp_port
[2];
147 unsigned char stp_age
[2];
148 unsigned char stp_maxage
[2];
149 unsigned char stp_hello
[2];
150 unsigned char stp_fwddelay
[2];
151 unsigned char stp_v1len
;
152 } __attribute__((packed
));;
154 static struct fstbpdu outpacket
= {
155 .header
.dest
=BPDUADDR
,
156 .header
.proto
={0x00,0x27}, /* 802.3 packet length */
157 .llc
={0x42,0x42,0x3},
163 static struct fsttagbpdu outtagpacket
= {
164 .header
.dest
=BPDUADDR
,
165 .header
.proto
={0x81,0x00},
166 .tag_proto
={0x00,0x27},
167 .llc
={0x42,0x42,0x3},
177 * 2/3 PORT ROLE: 00 UNKNOWN 01 ALT/BACKUP 10 ROOT 11 DESIGNATED
178 * 4 LEARNING 5 FORWARDING
180 * 7 TOPOLOGY CHANGE ACK
183 #define STP_FLAGS(VLAN,PORT,AGR,TC,TCACK) \
185 (ba_check(fsttab[(VLAN)]->backup,port) != 0) << 1 | \
186 (ba_check(fsttab[(VLAN)]->backup,port) == 0) << 2 | \
187 (fsttab[vlan]->rootport != (PORT)) << 3 |\
188 port_get_status((PORT),(VLAN)) << 4 | \
192 int fstnewvlan(int vlan
)
194 /*printf("F new vlan %d\n",vlan);*/
195 register unsigned int port
;
196 int newvlan
=(fsttab
[vlan
] == NULL
);
198 ((fsttab
[vlan
]=malloc(sizeof(struct vlst
))) == NULL
||
199 (fsttab
[vlan
]->untag
= ba_alloc(numports
)) == NULL
||
200 (fsttab
[vlan
]->tagged
= ba_alloc(numports
)) == NULL
||
201 (fsttab
[vlan
]->edge
= ba_alloc(numports
)) == NULL
||
202 (fsttab
[vlan
]->rcvhist
[0] = ba_alloc(numports
)) == NULL
||
203 (fsttab
[vlan
]->rcvhist
[1] = ba_alloc(numports
)) == NULL
||
204 (fsttab
[vlan
]->backup
= ba_alloc(numports
)) == NULL
))
207 memcpy(fsttab
[vlan
]->root
,myid
,SWITCHID_LEN
);
208 memset(fsttab
[vlan
]->rootcost
,0,4);
209 memset(fsttab
[vlan
]->dessw
,0xff,SWITCHID_LEN
);
210 memset(fsttab
[vlan
]->port
,0,4);
211 fsttab
[vlan
]->rootport
=fsttab
[vlan
]->roottimestamp
=0;
213 fsttab
[vlan
]->bonusport
=fsttab
[vlan
]->bonuscost
=0;
214 fsttab
[vlan
]->tctime
=0;
216 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
218 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1],
219 fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
220 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5],
221 fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
222 EVENTOUT(DBGFSTPROOT
,0,vlan
,fsttab
[vlan
]->root
);
223 ba_FORALL(fsttab
[vlan
]->backup
,numports
, ({
224 ba_clr(fsttab
[vlan
]->backup
,port
);
225 port_set_status(port
,vlan
,FORWARDING
);
231 int fstremovevlan(int vlan
)
233 /*printf("F remove vlan %d\n",vlan);*/
234 if (fsttab
[vlan
] == NULL
)
237 struct vlst
*old
=fsttab
[vlan
];
243 free(old
->rcvhist
[0]);
244 free(old
->rcvhist
[1]);
250 void fstsetnumports (int val
)
253 /*printf("F numports %d\n",val);*/
254 for (i
=0;i
<NUMOFVLAN
;i
++) {
256 fsttab
[i
]->untag
=ba_realloc(fsttab
[i
]->untag
,numports
,val
);
257 if (fsttab
[i
]->untag
== NULL
) {
258 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/untag %s",strerror(errno
));
261 fsttab
[i
]->tagged
=ba_realloc(fsttab
[i
]->tagged
,numports
,val
);
262 if (fsttab
[i
]->tagged
== NULL
) {
263 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/tagged %s",strerror(errno
));
266 fsttab
[i
]->backup
=ba_realloc(fsttab
[i
]->backup
,numports
,val
);
267 if (fsttab
[i
]->backup
== NULL
) {
268 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/backup %s",strerror(errno
));
271 fsttab
[i
]->edge
=ba_realloc(fsttab
[i
]->edge
,numports
,val
);
272 if (fsttab
[i
]->edge
== NULL
) {
273 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/edge %s",strerror(errno
));
276 fsttab
[i
]->rcvhist
[0]=ba_realloc(fsttab
[i
]->rcvhist
[0],numports
,val
);
277 if (fsttab
[i
]->rcvhist
[0] == NULL
) {
278 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist0 %s",strerror(errno
));
281 fsttab
[i
]->rcvhist
[1]=ba_realloc(fsttab
[i
]->rcvhist
[1],numports
,val
);
282 if (fsttab
[i
]->rcvhist
[1] == NULL
) {
283 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist1 %s",strerror(errno
));
292 static void fst_hello_vlan(int vlan
,int now
)
296 /* timeout on the root port */
297 if (fsttab
[vlan
]->rootport
!= 0 && (now
- fsttab
[vlan
]->roottimestamp
) > 3*helloperiod
)
299 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
300 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
301 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
302 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
303 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
304 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
305 if (age
> 0xffff) age
=0xffff;
306 outpacket
.stp_age
[0] = outtagpacket
.stp_age
[0]=age
;
307 outpacket
.stp_age
[1] = outtagpacket
.stp_age
[1]=age
>>8;
308 outpacket
.stp_fwddelay
[0] = outtagpacket
.stp_fwddelay
[0]=0;
309 outpacket
.stp_fwddelay
[1] = outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
310 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
311 ({ if (!(ba_check(fsttab
[vlan
]->edge
,port
))) {
312 outpacket
.stp_port
[0]=0x80| (port
>>4);
313 outpacket
.stp_port
[1]=port
;
314 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
315 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
318 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
319 ({ if (!(ba_check(fsttab
[vlan
]->edge
,port
))) {
320 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
321 outtagpacket
.stp_port
[1]=port
;
322 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
323 outtagpacket
.tag_vlan
[1]=vlan
;
324 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
325 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
330 /* a port that is not handling control packets for a while cannot be
331 * a backup port. It means that the other end is not speaking FSTP anymore.
332 * It must be reverted to a designed forwarding port.
334 static void fst_updatebackup(int vlan
,int index
)
337 ba_FORALL(fsttab
[vlan
]->backup
,numports
, ({
338 if (!FSTP_ACTIVE(vlan
,port
)) {
339 ba_clr(fsttab
[vlan
]->backup
,port
);
340 port_set_status(port
,vlan
,FORWARDING
);
344 ba_FORALL(fsttab
[vlan
]->untag
,numports
,({
345 if (ba_check(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(ba_check(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
346 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
347 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
349 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,({
350 if (ba_check(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(ba_check(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
351 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
352 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
355 ba_zap(fsttab
[vlan
]->rcvhist
[index
],numports
);
358 static void fst_hello(void *arg
)
361 static int hellocounter
;
364 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fst_hello_vlan
,now
);
365 if ((hellocounter
& 0x3) == 0) {
366 rcvhistindex
=1-rcvhistindex
;
367 bac_FORALLFUN(validvlan
,NUMOFVLAN
, fst_updatebackup
,rcvhistindex
);
371 static void fst_sendbpdu(int vlan
,int port
,int agr
,int tc
,int tcack
)
375 if (!(pflag
& FSTP_TAG
)) return;
376 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
377 if (ba_check(fsttab
[vlan
]->untag
,port
)) {
378 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
379 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
380 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
381 if (age
> 0xffff) age
=0xffff;
382 outpacket
.stp_age
[0] = age
;
383 outpacket
.stp_age
[1] = age
>>8;
384 outpacket
.stp_fwddelay
[0] = 0;
385 outpacket
.stp_fwddelay
[1] = 0; /* XXX */
386 outpacket
.stp_port
[0]=0x80| (port
>>4);
387 outpacket
.stp_port
[1]=port
;
388 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
389 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
391 if (ba_check(fsttab
[vlan
]->tagged
,port
)) {
392 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
393 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
394 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
395 if (age
> 0xffff) age
=0xffff;
396 outtagpacket
.stp_age
[0]=age
;
397 outtagpacket
.stp_age
[1]=age
>>8;
398 outtagpacket
.stp_fwddelay
[0]=0;
399 outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
400 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
401 outtagpacket
.stp_port
[1]=port
;
402 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
403 outtagpacket
.tag_vlan
[1]=vlan
;
404 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
405 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
409 /* Topology change flood
410 * two main difference between this and 802.1d/w:
411 * - it flushes all the hash table for this vlan (including the "calling" port
412 * - do not send all the packet with TC but just this
414 static void topology_change(int vlan
, int genport
)
418 //if (now - fsttab[vlan]->tctime > 2*helloperiod) { /*limit age?*/
419 /*printf("TOPOLOGY CHANGE %d\n",vlan);*/
420 fsttab
[vlan
]->tctime
=now
;
421 hash_delete_vlan(vlan
);
422 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
423 ({ if(port
!= genport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
424 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
425 fst_sendbpdu(vlan
,port
,0,1,0); }
427 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
428 ({ if(port
!= genport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
429 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
430 fst_sendbpdu(vlan
,port
,0,1,0); }
435 /* heart of the fast protocol:
436 * 1- receive a proposal
437 * 2- stop all the designed ports
438 * 3- give back the acknowledge and put the new root in fwd*/
439 static void fastprotocol(int vlan
, int newrootport
)
442 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
443 ({ if(port
!= newrootport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
444 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
445 port_set_status(port
,vlan
,DISCARDING
);
446 ba_set(fsttab
[vlan
]->backup
,port
);
447 fst_sendbpdu(vlan
,port
,0,0,0); }
449 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
450 ({ if(port
!= newrootport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
451 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
452 port_set_status(port
,vlan
,DISCARDING
);
453 ba_set(fsttab
[vlan
]->backup
,port
);
454 fst_sendbpdu(vlan
,port
,0,0,0); }
456 ba_clr(fsttab
[vlan
]->backup
,newrootport
); /* forward ON */
457 port_set_status(newrootport
,vlan
,FORWARDING
);
458 fst_sendbpdu(vlan
,newrootport
,1,0,0);
461 /* handling of bpdu incoming packets */
462 void fst_in_bpdu(int port
, struct packet
*inpacket
, int len
, int vlan
, int tagged
)
465 /* XXX check the header for fake info? */
466 struct vlst
*v
=fsttab
[vlan
];
468 if (ba_check(fsttab
[vlan
]->edge
,port
))
471 if (!FSTP_ACTIVE(vlan
,port
)) {
472 DBGOUT(DBGFSTPPLUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
473 EVENTOUT(DBGFSTPPLUS
,port
,vlan
);
476 ba_set(fsttab
[vlan
]->rcvhist
[rcvhistindex
],port
);
479 p
=(struct fstbpdu
*)(((unsigned char *)inpacket
)+4);
482 p
=(struct fstbpdu
*)(inpacket
);
483 if (len
< 51 || v
==NULL
|| p
->stp_version
!= 2 || p
->stp_type
!= 2)
484 return; /* faulty packet */
485 /* this is a topology change packet */
486 if (p
->stp_flags
& STP_TC
)
487 topology_change(vlan
,port
);
488 ltonstring(nstringtol(p
->stp_rootcost
)+
489 (port_getcost(port
)-((port
==v
->bonusport
)?v
->bonuscost
:0)),
492 /* >0 means new root, == 0 root unchanged, <0 sender must change topology */
493 if ((val
=valroot
=memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
)) == 0)
494 if ((val
=memcmp(v
->rootcost
,p
->stp_rootcost
,4)) == 0)
495 if ((val
=memcmp(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
)) == 0)
496 val
=memcmp(v
->port
,p
->stp_port
,2);
497 /*printf("VAL = %d root=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
498 " recv=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n",val,
499 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
500 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
501 p->stp_root[0], p->stp_root[1], p->stp_root[2], p->stp_root[3],
502 p->stp_root[4], p->stp_root[5], p->stp_root[6], p->stp_root[7]);
503 printf("++ stp_bridge=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
504 " cost=%02x:%02x:%02x:%02x: port %02x:%02x \n",
505 p->stp_bridge[0], p->stp_bridge[1], p->stp_bridge[2], p->stp_bridge[3],
506 p->stp_bridge[4], p->stp_bridge[5], p->stp_bridge[6], p->stp_bridge[7],
507 p->stp_rootcost[0], p->stp_rootcost[1], p->stp_rootcost[2], p->stp_rootcost[3],
508 p->stp_port[0], p->stp_port[1]); */
509 if (val
== 0) { /* root unchanged / new root announce*/
510 v
->roottimestamp
=qtime();
511 } else { /* new root or new root info*/
512 if (val
> 0 || (port
== fsttab
[vlan
]->rootport
&& val
<0)) {
513 if (memcmp(v
->root
,outpacket
.header
.src
,8) <= 0)
515 /* printf("NEW ROOT\n");*/
516 memcpy(v
->root
,p
->stp_root
,SWITCHID_LEN
);
517 memcpy(v
->rootcost
,p
->stp_rootcost
,4);
518 memcpy(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
);
519 memcpy(v
->port
,p
->stp_port
,2);
521 v
->roottimestamp
=qtime();
522 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
523 port
,vlan
>>8,vlan
&0xff,
524 v
->root
[0], v
->root
[1], v
->root
[2], v
->root
[3],
525 v
->root
[4], v
->root
[5], v
->root
[6], v
->root
[7]);
526 EVENTOUT(DBGFSTPROOT
,port
,vlan
,v
->root
);
527 fastprotocol(vlan
,port
);
528 topology_change(vlan
,port
);
531 if (memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
) == 0) {
532 /* critical point: longer path to root */
533 /* root -> designated */
534 /* non-root -> blocking */
535 if ((p
->stp_flags
& STP_PORTROLEMASK
) == STP_ROOT
) {
536 if (ba_check(v
->backup
,port
)) {
537 /* backup -> designated transition */
538 //printf("backup -> designated port %d\n",port);
539 ba_clr(v
->backup
,port
); /* forward ON */
540 port_set_status(port
,vlan
,FORWARDING
);
541 topology_change(vlan
,port
);
544 if (!ba_check(v
->backup
,port
)) {
545 /* designated -> backup transition */
546 //printf("designated ->backup port %d\n",port);
547 ba_set(v
->backup
,port
); /* forward OFF */
548 port_set_status(port
,vlan
,DISCARDING
);
549 topology_change(vlan
,port
);
553 /*printf("THIS?\n");*/
554 fst_sendbpdu(vlan
,port
,0,0,0);
560 void fstaddport(int vlan
,int port
,int tagged
)
562 /*printf("F addport V %d - P %d - T%d\n",vlan,port,tagged);*/
565 ba_set(fsttab
[vlan
]->tagged
,port
);
566 ba_clr(fsttab
[vlan
]->untag
,port
);
568 ba_set(fsttab
[vlan
]->untag
,port
);
569 ba_clr(fsttab
[vlan
]->tagged
,port
);
571 ba_clr(fsttab
[vlan
]->backup
,port
);
572 ba_clr(fsttab
[vlan
]->edge
,port
);
573 ba_clr(fsttab
[vlan
]->rcvhist
[0],port
);
574 ba_clr(fsttab
[vlan
]->rcvhist
[1],port
);
575 fst_sendbpdu(vlan
,port
,0,0,0);
576 topology_change(vlan
,port
);
579 void fstdelport(int vlan
,int port
)
581 /*printf("F delport V %d - P %d\n",vlan,port);*/
582 if (FSTP_ACTIVE(vlan
,port
)) {
583 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
584 EVENTOUT(DBGFSTPMINUS
,port
,vlan
);
586 ba_clr(fsttab
[vlan
]->untag
,port
);
587 ba_clr(fsttab
[vlan
]->tagged
,port
);
588 ba_clr(fsttab
[vlan
]->backup
,port
);
589 ba_clr(fsttab
[vlan
]->edge
,port
);
590 if (port
== fsttab
[vlan
]->rootport
) {
593 topology_change(vlan
,port
);
596 static void fstinitpkt(void)
598 memcpy(outpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
599 memcpy(outtagpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
600 memcpy(outpacket
.header
.src
,switchmac
,ETH_ALEN
);
601 memcpy(outtagpacket
.header
.src
,switchmac
,ETH_ALEN
);
602 outpacket
.stp_hello
[0]=outtagpacket
.stp_hello
[0]=helloperiod
,
603 outpacket
.stp_hello
[1]=outtagpacket
.stp_hello
[1]=helloperiod
>>8,
604 outpacket
.stp_maxage
[0]=outtagpacket
.stp_maxage
[0]=maxage
,
605 outpacket
.stp_maxage
[1]=outtagpacket
.stp_maxage
[1]=maxage
>>8,
606 fst_timerno
=qtimer_add(helloperiod
,0,fst_hello
,NULL
);
609 static int fstpshowinfo(FILE *fd
)
611 printoutc(fd
,"MAC %02x:%02x:%02x:%02x:%02x:%02x Priority %d (0x%x)",
612 switchmac
[0], switchmac
[1], switchmac
[2], switchmac
[3], switchmac
[4], switchmac
[5],
614 printoutc(fd
,"FSTP=%s",(pflag
& FSTP_TAG
)?"true":"false");
618 static void fstnewvlan2(int vlan
, void *arg
)
623 void fstpshutdown(void)
625 if (pflag
& FSTP_TAG
)
627 qtimer_del(fst_timerno
);
628 fstflag(P_CLRFLAG
,FSTP_TAG
);
629 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
633 static int fstpsetonoff(FILE *fd
, int val
)
635 int oldval
=((pflag
& FSTP_TAG
) != 0);
636 if (portflag(P_GETFLAG
, HUB_TAG
)){
637 printoutc(fd
, "Can't use fstp in hub mode");
643 if (val
) { /* START FST */
645 fstflag(P_SETFLAG
,FSTP_TAG
);
646 } else { /* STOP FST */
647 qtimer_del(fst_timerno
);
648 fstflag(P_CLRFLAG
,FSTP_TAG
);
649 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
655 static char *decoderole(int vlan
, int port
)
657 if (!(ba_check(fsttab
[vlan
]->untag
,port
) || ba_check(fsttab
[vlan
]->untag
,port
)))
659 if (ba_check(fsttab
[vlan
]->edge
,port
))
661 if (fsttab
[vlan
]->rootport
== port
)
663 if (ba_check(fsttab
[vlan
]->backup
,port
))
664 return "Alternate/Backup";
668 static void fstprintactive(int vlan
,FILE *fd
)
671 printoutc(fd
,"FST DATA VLAN %04d %s %s",vlan
,
672 memcmp(myid
,fsttab
[vlan
]->root
,SWITCHID_LEN
)==0?"ROOTSWITCH":"",
673 ((pflag
& FSTP_TAG
)==0)?"FSTP IS DISABLED":"");
674 printoutc(fd
, " ++ root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
675 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
676 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
677 printoutc(fd
, " ++ designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
678 fsttab
[vlan
]->dessw
[0], fsttab
[vlan
]->dessw
[1], fsttab
[vlan
]->dessw
[2], fsttab
[vlan
]->dessw
[3],
679 fsttab
[vlan
]->dessw
[4], fsttab
[vlan
]->dessw
[5], fsttab
[vlan
]->dessw
[6], fsttab
[vlan
]->dessw
[7]);
680 printoutc(fd
, " ++ rootport %04d cost %d age %d bonusport %04d bonuscost %d",
681 fsttab
[vlan
]->rootport
,
682 nstringtol(fsttab
[vlan
]->rootcost
),
683 qtime()-fsttab
[vlan
]->roottimestamp
,fsttab
[vlan
]->bonusport
,fsttab
[vlan
]->bonuscost
);
684 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
685 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,0,port_getcost(i
),decoderole(vlan
,i
)),i
);
686 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
687 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,1,port_getcost(i
),decoderole(vlan
,i
)),i
);
690 static int fstprint(FILE *fd
,char *arg
)
695 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
696 if (bac_check(validvlan
,vlan
))
697 fstprintactive(vlan
,fd
);
703 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fstprintactive
,fd
);
707 static int fstsetbonus(char *arg
)
709 int vlan
, port
, cost
;
710 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&cost
) != 3)
712 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
714 if (!bac_check(validvlan
,vlan
))
716 fsttab
[vlan
]->bonusport
=port
;
717 fsttab
[vlan
]->bonuscost
=cost
;
721 static int fstsetedge(char *arg
)
724 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&val
) != 3)
726 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
728 if (!bac_check(validvlan
,vlan
))
731 ba_set(fsttab
[vlan
]->edge
,port
);
732 if (ba_check(fsttab
[vlan
]->untag
,port
) || ba_check(fsttab
[vlan
]->untag
,port
))
733 port_set_status(port
,vlan
,FORWARDING
);
735 ba_clr(fsttab
[vlan
]->edge
,port
);
736 ba_clr(fsttab
[vlan
]->backup
,port
);
741 static struct comlist cl
[]={
742 {"fstp","============","FAST SPANNING TREE MENU",NULL
,NOARG
},
743 {"fstp/showinfo","","show fstp info",fstpshowinfo
,NOARG
|WITHFILE
},
744 {"fstp/setfstp","0/1","Fast spanning tree protocol 1=ON 0=OFF",fstpsetonoff
,INTARG
|WITHFILE
},
745 {"fstp/setedge","VLAN PORT 1/0","Define an edge port for a vlan 1=Y 0=N",fstsetedge
,STRARG
},
746 {"fstp/bonus","VLAN PORT COST","set the port bonus for a vlan",fstsetbonus
,STRARG
},
747 {"fstp/print","[N]","print fst data for the defined vlan",fstprint
,STRARG
|WITHFILE
},
750 int fstflag(int op
,int f
)
754 case P_GETFLAG
: oldflag
= pflag
& f
; break;
755 case P_SETFLAG
: pflag
=f
; break;
756 case P_ADDFLAG
: pflag
|= f
; break;
757 case P_CLRFLAG
: pflag
&= ~f
; break;
762 void fst_init(int initnumports
)
764 numports
=initnumports
;
765 SETFSTID(myid
,switchmac
,priority
);
766 if (pflag
& FSTP_TAG
)