1 /* Copyright 2005 Renzo Davoli VDE-2
2 * Licensed under the GPLv2
12 #include <sys/socket.h>
14 #include <netinet/in.h> /*ntoh conversion*/
29 /*********************** sending macro used by FSTP & Core ******************/
32 #define STP_AGREEMENT 0x40
33 #define STP_FORWARDING 0x20
34 #define STP_LEARNING 0x10
35 #define STP_PORTROLEMASK 0x0c
37 #define STP_PROPOSAL 0x02
41 #define DBGFSTPSTATUS (dl)
42 #define DBGFSTPROOT (dl+1)
43 #define DBGFSTPPLUS (dl+2)
44 #define DBGFSTPMINUS (dl+3)
45 static struct dbgcl dl
[]= {
46 {"fstp/status","fstp: status change",D_FSTP
|D_STATUS
},
47 {"fstp/root","fstp: rootswitch/port change",D_FSTP
|D_ROOT
},
48 {"fstp/+","fstp: port becomes active",D_FSTP
|D_PLUS
},
49 {"fstp/-","fstp: port becomes inactive",D_FSTP
|D_MINUS
},
51 static char *fstpdecodestatus
[]={
55 "learning+forwarding"};
56 #define port_set_status(P,V,S) \
57 ({DBGOUT(DBGFSTPSTATUS,"Port %04d VLAN %02x:%02x %s",\
58 (P),(V)>>8,(V)&0xff,fstpdecodestatus[(S)]);\
59 EVENTOUT(DBGFSTPSTATUS,(P),(V),(S));\
60 port_set_status(P,V,S);})
63 #define SWITCHID_LEN (ETH_ALEN+2)
64 #define FSTP_ACTIVE(VLAN,PORT) (BA_CHECK(fsttab[(VLAN)]->rcvhist[0],(PORT)) || \
65 BA_CHECK(fsttab[(VLAN)]->rcvhist[1],(PORT)))
67 static int rcvhistindex
;
69 unsigned char root
[SWITCHID_LEN
];
71 unsigned char dessw
[SWITCHID_LEN
];
77 /* TC: topology change timers missing XXX */
78 unsigned int roottimestamp
;
86 #define BPDUADDR {0x01,0x80,0xc2,0x00,0x00,0x00}
87 unsigned char bpduaddrp
[]=BPDUADDR
;
88 #define SETFSTID(ID,MAC,PRIO) ({ \
89 char *id=(char *)(ID); \
92 memcpy(id,(MAC),ETH_ALEN); 0; })
93 static unsigned char myid
[SWITCHID_LEN
];
95 #define STDHELLOPERIOD 4
96 static struct vlst
*fsttab
[NUMOFVLAN
];
97 static int helloperiod
= STDHELLOPERIOD
;
98 static int maxage
= STDHELLOPERIOD
*10;
99 static int fst_timerno
;
101 /* packet prototype for untagged ports */
103 struct ethheader header
;
104 unsigned char llc
[3];
105 unsigned char stp_protocol
[2];
106 unsigned char stp_version
;
107 unsigned char stp_type
;
108 unsigned char stp_flags
;
109 unsigned char stp_root
[SWITCHID_LEN
];
110 unsigned char stp_rootcost
[4];
111 unsigned char stp_bridge
[SWITCHID_LEN
];
112 unsigned char stp_port
[2];
113 unsigned char stp_age
[2];
114 unsigned char stp_maxage
[2];
115 unsigned char stp_hello
[2];
116 unsigned char stp_fwddelay
[2];
117 unsigned char stp_v1len
;
120 /* packet prototype for tagged ports */
122 struct ethheader header
;
123 unsigned char tag_vlan
[2];
124 unsigned char tag_proto
[2];
125 unsigned char llc
[3];
126 unsigned char stp_protocol
[2];
127 unsigned char stp_version
;
128 unsigned char stp_type
;
129 unsigned char stp_flags
;
130 unsigned char stp_root
[SWITCHID_LEN
];
131 unsigned char stp_rootcost
[4];
132 unsigned char stp_bridge
[SWITCHID_LEN
];
133 unsigned char stp_port
[2];
134 unsigned char stp_age
[2];
135 unsigned char stp_maxage
[2];
136 unsigned char stp_hello
[2];
137 unsigned char stp_fwddelay
[2];
138 unsigned char stp_v1len
;
141 static struct fstbpdu outpacket
= {
142 .header
.dest
=BPDUADDR
,
143 .header
.proto
={0x00,0x39}, /* 802.3 packet length */
144 .llc
={0x42,0x42,0x3},
150 static struct fsttagbpdu outtagpacket
= {
151 .header
.dest
=BPDUADDR
,
152 .header
.proto
={0x81,0x00},
153 .tag_proto
={0x00,0x39},
154 .llc
={0x42,0x42,0x3},
164 * 2/3 PORT ROLE: 00 UNKNOWN 01 ALT/BACKUP 10 ROOT 11 DESIGNATED
165 * 4 LEARNING 5 FORWARDING
167 * 7 TOPOLOGY CHANGE ACK
170 #define STP_FLAGS(VLAN,PORT,AGR,TC,TCACK) \
172 (BA_CHECK(fsttab[(VLAN)]->backup,port) != 0) << 1 | \
173 (BA_CHECK(fsttab[(VLAN)]->backup,port) == 0) << 2 | \
174 (fsttab[vlan]->rootport != (PORT)) << 3 |\
175 port_get_status((PORT),(VLAN)) << 4 | \
179 int fstnewvlan(int vlan
)
181 /*printf("F new vlan %d\n",vlan);*/
182 register unsigned int port
;
183 int newvlan
=(fsttab
[vlan
] == NULL
);
185 ((fsttab
[vlan
]=malloc(sizeof(struct vlst
))) == NULL
||
186 (fsttab
[vlan
]->untag
= BA_ALLOC(numports
)) == NULL
||
187 (fsttab
[vlan
]->tagged
= BA_ALLOC(numports
)) == NULL
||
188 (fsttab
[vlan
]->edge
= BA_ALLOC(numports
)) == NULL
||
189 (fsttab
[vlan
]->rcvhist
[0] = BA_ALLOC(numports
)) == NULL
||
190 (fsttab
[vlan
]->rcvhist
[1] = BA_ALLOC(numports
)) == NULL
||
191 (fsttab
[vlan
]->backup
= BA_ALLOC(numports
)) == NULL
))
194 memcpy(fsttab
[vlan
]->root
,myid
,SWITCHID_LEN
);
195 memset(fsttab
[vlan
]->rootcost
,0,4);
196 memset(fsttab
[vlan
]->dessw
,0xff,SWITCHID_LEN
);
197 memset(fsttab
[vlan
]->port
,0,4);
198 fsttab
[vlan
]->rootport
=fsttab
[vlan
]->roottimestamp
=0;
200 fsttab
[vlan
]->bonusport
=fsttab
[vlan
]->bonuscost
=0;
201 fsttab
[vlan
]->tctime
=0;
203 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
205 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1],
206 fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
207 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5],
208 fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
209 EVENTOUT(DBGFSTPROOT
,0,vlan
,fsttab
[vlan
]->root
);
210 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
211 BA_CLR(fsttab
[vlan
]->backup
,port
);
212 port_set_status(port
,vlan
,FORWARDING
);
218 int fstremovevlan(int vlan
)
220 /*printf("F remove vlan %d\n",vlan);*/
221 if (fsttab
[vlan
] == NULL
)
224 struct vlst
*old
=fsttab
[vlan
];
230 free(old
->rcvhist
[0]);
231 free(old
->rcvhist
[1]);
237 void fstsetnumports (int val
)
240 /*printf("F numports %d\n",val);*/
241 for (i
=0;i
<NUMOFVLAN
;i
++) {
243 fsttab
[i
]->untag
=BA_REALLOC(fsttab
[i
]->untag
,numports
,val
);
244 if (fsttab
[i
]->untag
== NULL
) {
245 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/untag %s",strerror(errno
));
248 fsttab
[i
]->tagged
=BA_REALLOC(fsttab
[i
]->tagged
,numports
,val
);
249 if (fsttab
[i
]->tagged
== NULL
) {
250 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/tagged %s",strerror(errno
));
253 fsttab
[i
]->backup
=BA_REALLOC(fsttab
[i
]->backup
,numports
,val
);
254 if (fsttab
[i
]->backup
== NULL
) {
255 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/backup %s",strerror(errno
));
258 fsttab
[i
]->edge
=BA_REALLOC(fsttab
[i
]->edge
,numports
,val
);
259 if (fsttab
[i
]->edge
== NULL
) {
260 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/edge %s",strerror(errno
));
263 fsttab
[i
]->rcvhist
[0]=BA_REALLOC(fsttab
[i
]->rcvhist
[0],numports
,val
);
264 if (fsttab
[i
]->rcvhist
[0] == NULL
) {
265 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist0 %s",strerror(errno
));
268 fsttab
[i
]->rcvhist
[1]=BA_REALLOC(fsttab
[i
]->rcvhist
[1],numports
,val
);
269 if (fsttab
[i
]->rcvhist
[1] == NULL
) {
270 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist1 %s",strerror(errno
));
279 static void fst_hello_vlan(int vlan
,int now
)
283 /* timeout on the root port */
284 if (fsttab
[vlan
]->rootport
!= 0 && (now
- fsttab
[vlan
]->roottimestamp
) > 3*helloperiod
)
286 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
287 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
288 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
289 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
290 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
291 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
292 if (age
> 0xffff) age
=0xffff;
293 outpacket
.stp_age
[0] = outtagpacket
.stp_age
[0]=age
;
294 outpacket
.stp_age
[1] = outtagpacket
.stp_age
[1]=age
>>8;
295 outpacket
.stp_fwddelay
[0] = outtagpacket
.stp_fwddelay
[0]=0;
296 outpacket
.stp_fwddelay
[1] = outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
297 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
298 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
299 outpacket
.stp_port
[0]=0x80| (port
>>4);
300 outpacket
.stp_port
[1]=port
;
301 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
302 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
305 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
306 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
307 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
308 outtagpacket
.stp_port
[1]=port
;
309 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
310 outtagpacket
.tag_vlan
[1]=vlan
;
311 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
312 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
317 /* a port that is not handling control packets for a while cannot be
318 * a backup port. It means that the other end is not speaking FSTP anymore.
319 * It must be reverted to a designed forwarding port.
321 static void fst_updatebackup(int vlan
,int index
)
324 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
325 if (!FSTP_ACTIVE(vlan
,port
)) {
326 BA_CLR(fsttab
[vlan
]->backup
,port
);
327 port_set_status(port
,vlan
,FORWARDING
);
331 BA_FORALL(fsttab
[vlan
]->untag
,numports
,({
332 if (BA_CHECK(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(BA_CHECK(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
333 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
334 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
336 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,({
337 if (BA_CHECK(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(BA_CHECK(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
338 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
339 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
342 BA_ZAP(fsttab
[vlan
]->rcvhist
[index
],numports
);
345 static void fst_hello(void *arg
)
348 static int hellocounter
;
351 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fst_hello_vlan
,now
);
352 if ((hellocounter
& 0x3) == 0) {
353 rcvhistindex
=1-rcvhistindex
;
354 BAC_FORALLFUN(validvlan
,NUMOFVLAN
, fst_updatebackup
,rcvhistindex
);
358 static void fst_sendbpdu(int vlan
,int port
,int agr
,int tc
,int tcack
)
362 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
363 if (BA_CHECK(fsttab
[vlan
]->untag
,port
)) {
364 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
365 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
366 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
367 if (age
> 0xffff) age
=0xffff;
368 outpacket
.stp_age
[0] = age
;
369 outpacket
.stp_age
[1] = age
>>8;
370 outpacket
.stp_fwddelay
[0] = 0;
371 outpacket
.stp_fwddelay
[1] = 0; /* XXX */
372 outpacket
.stp_port
[0]=0x80| (port
>>4);
373 outpacket
.stp_port
[1]=port
;
374 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
375 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
377 if (BA_CHECK(fsttab
[vlan
]->tagged
,port
)) {
378 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
379 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
380 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
381 if (age
> 0xffff) age
=0xffff;
382 outtagpacket
.stp_age
[0]=age
;
383 outtagpacket
.stp_age
[1]=age
>>8;
384 outtagpacket
.stp_fwddelay
[0]=0;
385 outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
386 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
387 outtagpacket
.stp_port
[1]=port
;
388 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
389 outtagpacket
.tag_vlan
[1]=vlan
;
390 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
391 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
395 /* Topology change flood
396 * two main difference between this and 802.1d/w:
397 * - it flushes all the hash table for this vlan (including the "calling" port
398 * - do not send all the packet with TC but just this
400 static void topology_change(int vlan
, int genport
)
404 //if (now - fsttab[vlan]->tctime > 2*helloperiod) { /*limit age?*/
405 /*printf("TOPOLOGY CHANGE %d\n",vlan);*/
406 fsttab
[vlan
]->tctime
=now
;
407 hash_delete_vlan(vlan
);
408 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
409 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
410 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
411 fst_sendbpdu(vlan
,port
,0,1,0); }
413 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
414 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
415 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
416 fst_sendbpdu(vlan
,port
,0,1,0); }
421 /* heart of the fast protocol:
422 * 1- receive a proposal
423 * 2- stop all the designed ports
424 * 3- give back the acknowledge and put the new root in fwd*/
425 static void fastprotocol(int vlan
, int newrootport
)
428 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
429 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
430 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
431 port_set_status(port
,vlan
,DISCARDING
);
432 BA_SET(fsttab
[vlan
]->backup
,port
);
433 fst_sendbpdu(vlan
,port
,0,0,0); }
435 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
436 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
437 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
438 port_set_status(port
,vlan
,DISCARDING
);
439 BA_SET(fsttab
[vlan
]->backup
,port
);
440 fst_sendbpdu(vlan
,port
,0,0,0); }
442 BA_CLR(fsttab
[vlan
]->backup
,newrootport
); /* forward ON */
443 port_set_status(newrootport
,vlan
,FORWARDING
);
444 fst_sendbpdu(vlan
,newrootport
,1,0,0);
447 /* handling of bpdu incoming packets */
448 void fst_in_bpdu(int port
, struct packet
*inpacket
, int len
, int vlan
, int tagged
)
451 /* XXX check the header for fake info? */
452 struct vlst
*v
=fsttab
[vlan
];
454 if (!(pflag
& FSTP_TAG
) || (BA_CHECK(fsttab
[vlan
]->edge
,port
)))
455 return; /*FST IS TURNED OFF or EDGE*/
457 if (!FSTP_ACTIVE(vlan
,port
)) {
458 DBGOUT(DBGFSTPPLUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
459 EVENTOUT(DBGFSTPPLUS
,port
,vlan
);
462 BA_SET(fsttab
[vlan
]->rcvhist
[rcvhistindex
],port
);
465 p
=(struct fstbpdu
*)(((unsigned char *)inpacket
)+4);
468 p
=(struct fstbpdu
*)(inpacket
);
469 if (len
< 51 || v
==NULL
|| p
->stp_version
!= 2 || p
->stp_type
!= 2)
470 return; /* faulty packet */
471 /* this is a topology change packet */
472 if (p
->stp_flags
& STP_TC
)
473 topology_change(vlan
,port
);
474 *((u_int32_t
*)(p
->stp_rootcost
))=
475 htonl(ntohl(*((u_int32_t
*)(p
->stp_rootcost
)))+
476 (port_getcost(port
)-((port
==v
->bonusport
)?v
->bonuscost
:0)));
478 /* >0 means new root, == 0 root unchanged, <0 sender must change topology */
479 if ((val
=valroot
=memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
)) == 0)
480 if ((val
=memcmp(v
->rootcost
,p
->stp_rootcost
,4)) == 0)
481 if ((val
=memcmp(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
)) == 0)
482 val
=memcmp(v
->port
,p
->stp_port
,2);
483 /*printf("VAL = %d root=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
484 " recv=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n",val,
485 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
486 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
487 p->stp_root[0], p->stp_root[1], p->stp_root[2], p->stp_root[3],
488 p->stp_root[4], p->stp_root[5], p->stp_root[6], p->stp_root[7]);
489 printf("++ stp_bridge=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
490 " cost=%02x:%02x:%02x:%02x: port %02x:%02x \n",
491 p->stp_bridge[0], p->stp_bridge[1], p->stp_bridge[2], p->stp_bridge[3],
492 p->stp_bridge[4], p->stp_bridge[5], p->stp_bridge[6], p->stp_bridge[7],
493 p->stp_rootcost[0], p->stp_rootcost[1], p->stp_rootcost[2], p->stp_rootcost[3],
494 p->stp_port[0], p->stp_port[1]); */
495 if (val
== 0) { /* root unchanged / new root announce*/
496 v
->roottimestamp
=qtime();
497 } else { /* new root or new root info*/
498 if (val
> 0 || (port
== fsttab
[vlan
]->rootport
&& val
<0)) {
499 if (memcmp(v
->root
,outpacket
.header
.src
,8) <= 0)
501 /* printf("NEW ROOT\n");*/
502 memcpy(v
->root
,p
->stp_root
,SWITCHID_LEN
);
503 memcpy(v
->rootcost
,p
->stp_rootcost
,4);
504 memcpy(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
);
505 memcpy(v
->port
,p
->stp_port
,2);
507 v
->roottimestamp
=qtime();
508 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
509 port
,vlan
>>8,vlan
&0xff,
510 v
->root
[0], v
->root
[1], v
->root
[2], v
->root
[3],
511 v
->root
[4], v
->root
[5], v
->root
[6], v
->root
[7]);
512 EVENTOUT(DBGFSTPROOT
,port
,vlan
,v
->root
);
513 fastprotocol(vlan
,port
);
514 topology_change(vlan
,port
);
517 if (memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
) == 0) {
518 /* critical point: longer path to root */
519 /* root -> designated */
520 /* non-root -> blocking */
521 if ((p
->stp_flags
& STP_PORTROLEMASK
) == STP_ROOT
) {
522 if (BA_CHECK(v
->backup
,port
)) {
523 /* backup -> designated transition */
524 //printf("backup -> designated port %d\n",port);
525 BA_CLR(v
->backup
,port
); /* forward ON */
526 port_set_status(port
,vlan
,FORWARDING
);
527 topology_change(vlan
,port
);
530 if (!BA_CHECK(v
->backup
,port
)) {
531 /* designated -> backup transition */
532 //printf("designated ->backup port %d\n",port);
533 BA_SET(v
->backup
,port
); /* forward OFF */
534 port_set_status(port
,vlan
,DISCARDING
);
535 topology_change(vlan
,port
);
539 /*printf("THIS?\n");*/
540 fst_sendbpdu(vlan
,port
,0,0,0);
546 void fstaddport(int vlan
,int port
,int tagged
)
548 /*printf("F addport V %d - P %d - T%d\n",vlan,port,tagged);*/
550 BA_SET(fsttab
[vlan
]->tagged
,port
);
551 BA_CLR(fsttab
[vlan
]->untag
,port
);
553 BA_SET(fsttab
[vlan
]->untag
,port
);
554 BA_CLR(fsttab
[vlan
]->tagged
,port
);
556 BA_CLR(fsttab
[vlan
]->backup
,port
);
557 BA_CLR(fsttab
[vlan
]->edge
,port
);
558 BA_CLR(fsttab
[vlan
]->rcvhist
[0],port
);
559 BA_CLR(fsttab
[vlan
]->rcvhist
[1],port
);
560 fst_sendbpdu(vlan
,port
,0,0,0);
561 topology_change(vlan
,port
);
564 void fstdelport(int vlan
,int port
)
566 /*printf("F delport V %d - P %d\n",vlan,port);*/
567 if (FSTP_ACTIVE(vlan
,port
)) {
568 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
569 EVENTOUT(DBGFSTPMINUS
,port
,vlan
);
571 BA_CLR(fsttab
[vlan
]->untag
,port
);
572 BA_CLR(fsttab
[vlan
]->tagged
,port
);
573 BA_CLR(fsttab
[vlan
]->backup
,port
);
574 BA_CLR(fsttab
[vlan
]->edge
,port
);
575 if (port
== fsttab
[vlan
]->rootport
) {
578 topology_change(vlan
,port
);
581 static void fstinitpkt(void)
583 memcpy(outpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
584 memcpy(outtagpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
585 memcpy(outpacket
.header
.src
,switchmac
,ETH_ALEN
);
586 memcpy(outtagpacket
.header
.src
,switchmac
,ETH_ALEN
);
587 outpacket
.stp_hello
[0]=outtagpacket
.stp_hello
[0]=helloperiod
,
588 outpacket
.stp_hello
[1]=outtagpacket
.stp_hello
[1]=helloperiod
>>8,
589 outpacket
.stp_maxage
[0]=outtagpacket
.stp_maxage
[0]=maxage
,
590 outpacket
.stp_maxage
[1]=outtagpacket
.stp_maxage
[1]=maxage
>>8,
591 fst_timerno
=qtimer_add(helloperiod
,0,fst_hello
,NULL
);
594 static int fstpshowinfo(FILE *fd
)
596 printoutc(fd
,"MAC %02x:%02x:%02x:%02x:%02x:%02x Priority %d (0x%x)",
597 switchmac
[0], switchmac
[1], switchmac
[2], switchmac
[3], switchmac
[4], switchmac
[5],
599 printoutc(fd
,"FSTP=%s",(pflag
& FSTP_TAG
)?"true":"false");
603 static void fstnewvlan2(int vlan
, void *arg
)
608 static int fstpsetonoff(int val
)
610 int oldval
=((pflag
& FSTP_TAG
) != 0);
614 if (val
) { /* START FST */
616 fstflag(P_SETFLAG
,FSTP_TAG
);
617 } else { /* STOP FST */
618 qtimer_del(fst_timerno
);
619 fstflag(P_CLRFLAG
,FSTP_TAG
);
620 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
626 static char *decoderole(int vlan
, int port
)
628 if (!(BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
)))
630 if (BA_CHECK(fsttab
[vlan
]->edge
,port
))
632 if (fsttab
[vlan
]->rootport
== port
)
634 if (BA_CHECK(fsttab
[vlan
]->backup
,port
))
635 return "Alternate/Backup";
639 static void fstprintactive(int vlan
,FILE *fd
)
642 printoutc(fd
,"FST DATA VLAN %04d %s %s",vlan
,
643 memcmp(myid
,fsttab
[vlan
]->root
,SWITCHID_LEN
)==0?"ROOTSWITCH":"",
644 ((pflag
& FSTP_TAG
)==0)?"FSTP IS DISABLED":"");
645 printoutc(fd
, " ++ root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
646 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
647 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
648 printoutc(fd
, " ++ designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
649 fsttab
[vlan
]->dessw
[0], fsttab
[vlan
]->dessw
[1], fsttab
[vlan
]->dessw
[2], fsttab
[vlan
]->dessw
[3],
650 fsttab
[vlan
]->dessw
[4], fsttab
[vlan
]->dessw
[5], fsttab
[vlan
]->dessw
[6], fsttab
[vlan
]->dessw
[7]);
651 printoutc(fd
, " ++ rootport %04d cost %d age %d bonusport %04d bonuscost %d",
652 fsttab
[vlan
]->rootport
,
653 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
654 qtime()-fsttab
[vlan
]->roottimestamp
,fsttab
[vlan
]->bonusport
,fsttab
[vlan
]->bonuscost
);
655 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
656 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,0,port_getcost(i
),decoderole(vlan
,i
)),i
);
657 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
658 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,1,port_getcost(i
),decoderole(vlan
,i
)),i
);
661 static int fstprint(FILE *fd
,char *arg
)
666 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
667 if (BAC_CHECK(validvlan
,vlan
))
668 fstprintactive(vlan
,fd
);
674 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstprintactive
,fd
);
678 static int fstsetbonus(char *arg
)
680 int vlan
, port
, cost
;
681 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&cost
) != 3)
683 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
685 if (!BAC_CHECK(validvlan
,vlan
))
687 fsttab
[vlan
]->bonusport
=port
;
688 fsttab
[vlan
]->bonuscost
=cost
;
692 static int fstsetedge(char *arg
)
695 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&val
) != 3)
697 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
699 if (!BAC_CHECK(validvlan
,vlan
))
702 BA_SET(fsttab
[vlan
]->edge
,port
);
703 if (BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
))
704 port_set_status(port
,vlan
,FORWARDING
);
706 BA_CLR(fsttab
[vlan
]->edge
,port
);
707 BA_CLR(fsttab
[vlan
]->backup
,port
);
712 static struct comlist cl
[]={
713 {"fstp","============","FAST SPANNING TREE MENU",NULL
,NOARG
},
714 {"fstp/showinfo","","show fstp info",fstpshowinfo
,NOARG
|WITHFILE
},
715 {"fstp/setfstp","0/1","Fast spanning tree protocol 1=ON 0=OFF",fstpsetonoff
,INTARG
},
716 {"fstp/setedge","VLAN PORT 1/0","Define an edge port for a vlan 1=Y 0=N",fstsetedge
,STRARG
},
717 {"fstp/bonus","VLAN PORT COST","set the port bonus for a vlan",fstsetbonus
,STRARG
},
718 {"fstp/print","[N]","print fst data for the defined vlan",fstprint
,STRARG
|WITHFILE
},
721 int fstflag(int op
,int f
)
725 case P_SETFLAG
: pflag
=f
; break;
726 case P_ADDFLAG
: pflag
|= f
; break;
727 case P_CLRFLAG
: pflag
&= ~f
; break;
732 void fst_init(int initnumports
)
734 numports
=initnumports
;
735 SETFSTID(myid
,switchmac
,priority
);
736 if (pflag
& FSTP_TAG
)