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 ******************/
35 #define STP_AGREEMENT 0x40
36 #define STP_FORWARDING 0x20
37 #define STP_LEARNING 0x10
38 #define STP_PORTROLEMASK 0x0c
40 #define STP_PROPOSAL 0x02
44 #define DBGFSTPSTATUS (dl)
45 #define DBGFSTPROOT (dl+1)
46 #define DBGFSTPPLUS (dl+2)
47 #define DBGFSTPMINUS (dl+3)
48 static struct dbgcl dl
[]= {
49 {"fstp/status","fstp: status change",D_FSTP
|D_STATUS
},
50 {"fstp/root","fstp: rootswitch/port change",D_FSTP
|D_ROOT
},
51 {"fstp/+","fstp: port becomes active",D_FSTP
|D_PLUS
},
52 {"fstp/-","fstp: port becomes inactive",D_FSTP
|D_MINUS
},
54 static char *fstpdecodestatus
[]={
58 "learning+forwarding"};
59 #define port_set_status(P,V,S) \
60 ({DBGOUT(DBGFSTPSTATUS,"Port %04d VLAN %02x:%02x %s",\
61 (P),(V)>>8,(V)&0xff,fstpdecodestatus[(S)]);\
62 EVENTOUT(DBGFSTPSTATUS,(P),(V),(S));\
63 port_set_status(P,V,S);})
66 #define SWITCHID_LEN (ETH_ALEN+2)
67 #define FSTP_ACTIVE(VLAN,PORT) (ba_check(fsttab[(VLAN)]->rcvhist[0],(PORT)) || \
68 ba_check(fsttab[(VLAN)]->rcvhist[1],(PORT)))
70 static int rcvhistindex
;
72 unsigned char root
[SWITCHID_LEN
];
74 unsigned char dessw
[SWITCHID_LEN
];
80 /* TC: topology change timers missing XXX */
81 unsigned int roottimestamp
;
89 #define BPDUADDR {0x01,0x80,0xc2,0x00,0x00,0x00}
90 unsigned char bpduaddrp
[]=BPDUADDR
;
91 #define SETFSTID(ID,MAC,PRIO) ({ \
92 char *id=(char *)(ID); \
95 memcpy(id,(MAC),ETH_ALEN); 0; })
96 static unsigned char myid
[SWITCHID_LEN
];
98 #define STDHELLOPERIOD 4
99 static struct vlst
*fsttab
[NUMOFVLAN
];
100 static int helloperiod
= STDHELLOPERIOD
;
101 static int maxage
= STDHELLOPERIOD
*10;
102 static int fst_timerno
;
104 /* packet prototype for untagged ports */
106 struct ethheader header
;
107 unsigned char llc
[3];
108 unsigned char stp_protocol
[2];
109 unsigned char stp_version
;
110 unsigned char stp_type
;
111 unsigned char stp_flags
;
112 unsigned char stp_root
[SWITCHID_LEN
];
113 unsigned char stp_rootcost
[4];
114 unsigned char stp_bridge
[SWITCHID_LEN
];
115 unsigned char stp_port
[2];
116 unsigned char stp_age
[2];
117 unsigned char stp_maxage
[2];
118 unsigned char stp_hello
[2];
119 unsigned char stp_fwddelay
[2];
120 unsigned char stp_v1len
;
123 /* packet prototype for tagged ports */
125 struct ethheader header
;
126 unsigned char tag_vlan
[2];
127 unsigned char tag_proto
[2];
128 unsigned char llc
[3];
129 unsigned char stp_protocol
[2];
130 unsigned char stp_version
;
131 unsigned char stp_type
;
132 unsigned char stp_flags
;
133 unsigned char stp_root
[SWITCHID_LEN
];
134 unsigned char stp_rootcost
[4];
135 unsigned char stp_bridge
[SWITCHID_LEN
];
136 unsigned char stp_port
[2];
137 unsigned char stp_age
[2];
138 unsigned char stp_maxage
[2];
139 unsigned char stp_hello
[2];
140 unsigned char stp_fwddelay
[2];
141 unsigned char stp_v1len
;
144 static struct fstbpdu outpacket
= {
145 .header
.dest
=BPDUADDR
,
146 .header
.proto
={0x00,0x39}, /* 802.3 packet length */
147 .llc
={0x42,0x42,0x3},
153 static struct fsttagbpdu outtagpacket
= {
154 .header
.dest
=BPDUADDR
,
155 .header
.proto
={0x81,0x00},
156 .tag_proto
={0x00,0x39},
157 .llc
={0x42,0x42,0x3},
167 * 2/3 PORT ROLE: 00 UNKNOWN 01 ALT/BACKUP 10 ROOT 11 DESIGNATED
168 * 4 LEARNING 5 FORWARDING
170 * 7 TOPOLOGY CHANGE ACK
173 #define STP_FLAGS(VLAN,PORT,AGR,TC,TCACK) \
175 (ba_check(fsttab[(VLAN)]->backup,port) != 0) << 1 | \
176 (ba_check(fsttab[(VLAN)]->backup,port) == 0) << 2 | \
177 (fsttab[vlan]->rootport != (PORT)) << 3 |\
178 port_get_status((PORT),(VLAN)) << 4 | \
182 int fstnewvlan(int vlan
)
184 /*printf("F new vlan %d\n",vlan);*/
185 register unsigned int port
;
186 int newvlan
=(fsttab
[vlan
] == NULL
);
188 ((fsttab
[vlan
]=malloc(sizeof(struct vlst
))) == NULL
||
189 (fsttab
[vlan
]->untag
= ba_alloc(numports
)) == NULL
||
190 (fsttab
[vlan
]->tagged
= ba_alloc(numports
)) == NULL
||
191 (fsttab
[vlan
]->edge
= ba_alloc(numports
)) == NULL
||
192 (fsttab
[vlan
]->rcvhist
[0] = ba_alloc(numports
)) == NULL
||
193 (fsttab
[vlan
]->rcvhist
[1] = ba_alloc(numports
)) == NULL
||
194 (fsttab
[vlan
]->backup
= ba_alloc(numports
)) == NULL
))
197 memcpy(fsttab
[vlan
]->root
,myid
,SWITCHID_LEN
);
198 memset(fsttab
[vlan
]->rootcost
,0,4);
199 memset(fsttab
[vlan
]->dessw
,0xff,SWITCHID_LEN
);
200 memset(fsttab
[vlan
]->port
,0,4);
201 fsttab
[vlan
]->rootport
=fsttab
[vlan
]->roottimestamp
=0;
203 fsttab
[vlan
]->bonusport
=fsttab
[vlan
]->bonuscost
=0;
204 fsttab
[vlan
]->tctime
=0;
206 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
208 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1],
209 fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
210 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5],
211 fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
212 EVENTOUT(DBGFSTPROOT
,0,vlan
,fsttab
[vlan
]->root
);
213 ba_FORALL(fsttab
[vlan
]->backup
,numports
, ({
214 ba_clr(fsttab
[vlan
]->backup
,port
);
215 port_set_status(port
,vlan
,FORWARDING
);
221 int fstremovevlan(int vlan
)
223 /*printf("F remove vlan %d\n",vlan);*/
224 if (fsttab
[vlan
] == NULL
)
227 struct vlst
*old
=fsttab
[vlan
];
233 free(old
->rcvhist
[0]);
234 free(old
->rcvhist
[1]);
240 void fstsetnumports (int val
)
243 /*printf("F numports %d\n",val);*/
244 for (i
=0;i
<NUMOFVLAN
;i
++) {
246 fsttab
[i
]->untag
=ba_realloc(fsttab
[i
]->untag
,numports
,val
);
247 if (fsttab
[i
]->untag
== NULL
) {
248 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/untag %s",strerror(errno
));
251 fsttab
[i
]->tagged
=ba_realloc(fsttab
[i
]->tagged
,numports
,val
);
252 if (fsttab
[i
]->tagged
== NULL
) {
253 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/tagged %s",strerror(errno
));
256 fsttab
[i
]->backup
=ba_realloc(fsttab
[i
]->backup
,numports
,val
);
257 if (fsttab
[i
]->backup
== NULL
) {
258 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/backup %s",strerror(errno
));
261 fsttab
[i
]->edge
=ba_realloc(fsttab
[i
]->edge
,numports
,val
);
262 if (fsttab
[i
]->edge
== NULL
) {
263 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/edge %s",strerror(errno
));
266 fsttab
[i
]->rcvhist
[0]=ba_realloc(fsttab
[i
]->rcvhist
[0],numports
,val
);
267 if (fsttab
[i
]->rcvhist
[0] == NULL
) {
268 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist0 %s",strerror(errno
));
271 fsttab
[i
]->rcvhist
[1]=ba_realloc(fsttab
[i
]->rcvhist
[1],numports
,val
);
272 if (fsttab
[i
]->rcvhist
[1] == NULL
) {
273 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist1 %s",strerror(errno
));
282 static void fst_hello_vlan(int vlan
,int now
)
286 /* timeout on the root port */
287 if (fsttab
[vlan
]->rootport
!= 0 && (now
- fsttab
[vlan
]->roottimestamp
) > 3*helloperiod
)
289 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
290 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
291 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
292 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
293 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
294 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
295 if (age
> 0xffff) age
=0xffff;
296 outpacket
.stp_age
[0] = outtagpacket
.stp_age
[0]=age
;
297 outpacket
.stp_age
[1] = outtagpacket
.stp_age
[1]=age
>>8;
298 outpacket
.stp_fwddelay
[0] = outtagpacket
.stp_fwddelay
[0]=0;
299 outpacket
.stp_fwddelay
[1] = outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
300 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
301 ({ if (!(ba_check(fsttab
[vlan
]->edge
,port
))) {
302 outpacket
.stp_port
[0]=0x80| (port
>>4);
303 outpacket
.stp_port
[1]=port
;
304 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
305 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
308 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
309 ({ if (!(ba_check(fsttab
[vlan
]->edge
,port
))) {
310 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
311 outtagpacket
.stp_port
[1]=port
;
312 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
313 outtagpacket
.tag_vlan
[1]=vlan
;
314 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
315 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
320 /* a port that is not handling control packets for a while cannot be
321 * a backup port. It means that the other end is not speaking FSTP anymore.
322 * It must be reverted to a designed forwarding port.
324 static void fst_updatebackup(int vlan
,int index
)
327 ba_FORALL(fsttab
[vlan
]->backup
,numports
, ({
328 if (!FSTP_ACTIVE(vlan
,port
)) {
329 ba_clr(fsttab
[vlan
]->backup
,port
);
330 port_set_status(port
,vlan
,FORWARDING
);
334 ba_FORALL(fsttab
[vlan
]->untag
,numports
,({
335 if (ba_check(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(ba_check(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
336 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
337 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
339 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,({
340 if (ba_check(fsttab
[(vlan
)]->rcvhist
[index
],(port
)) && !(ba_check(fsttab
[(vlan
)]->rcvhist
[1-index
],(port
)))) {
341 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
342 EVENTOUT(DBGFSTPMINUS
,port
,vlan
); }
345 ba_zap(fsttab
[vlan
]->rcvhist
[index
],numports
);
348 static void fst_hello(void *arg
)
351 static int hellocounter
;
354 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fst_hello_vlan
,now
);
355 if ((hellocounter
& 0x3) == 0) {
356 rcvhistindex
=1-rcvhistindex
;
357 bac_FORALLFUN(validvlan
,NUMOFVLAN
, fst_updatebackup
,rcvhistindex
);
361 static void fst_sendbpdu(int vlan
,int port
,int agr
,int tc
,int tcack
)
365 if (!(pflag
& FSTP_TAG
)) return;
366 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
367 if (ba_check(fsttab
[vlan
]->untag
,port
)) {
368 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
369 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
370 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
371 if (age
> 0xffff) age
=0xffff;
372 outpacket
.stp_age
[0] = age
;
373 outpacket
.stp_age
[1] = age
>>8;
374 outpacket
.stp_fwddelay
[0] = 0;
375 outpacket
.stp_fwddelay
[1] = 0; /* XXX */
376 outpacket
.stp_port
[0]=0x80| (port
>>4);
377 outpacket
.stp_port
[1]=port
;
378 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
379 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
381 if (ba_check(fsttab
[vlan
]->tagged
,port
)) {
382 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
383 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
384 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
385 if (age
> 0xffff) age
=0xffff;
386 outtagpacket
.stp_age
[0]=age
;
387 outtagpacket
.stp_age
[1]=age
>>8;
388 outtagpacket
.stp_fwddelay
[0]=0;
389 outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
390 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
391 outtagpacket
.stp_port
[1]=port
;
392 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
393 outtagpacket
.tag_vlan
[1]=vlan
;
394 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
395 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
399 /* Topology change flood
400 * two main difference between this and 802.1d/w:
401 * - it flushes all the hash table for this vlan (including the "calling" port
402 * - do not send all the packet with TC but just this
404 static void topology_change(int vlan
, int genport
)
408 //if (now - fsttab[vlan]->tctime > 2*helloperiod) { /*limit age?*/
409 /*printf("TOPOLOGY CHANGE %d\n",vlan);*/
410 fsttab
[vlan
]->tctime
=now
;
411 hash_delete_vlan(vlan
);
412 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
413 ({ if(port
!= genport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
414 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
415 fst_sendbpdu(vlan
,port
,0,1,0); }
417 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
418 ({ if(port
!= genport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
419 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
420 fst_sendbpdu(vlan
,port
,0,1,0); }
425 /* heart of the fast protocol:
426 * 1- receive a proposal
427 * 2- stop all the designed ports
428 * 3- give back the acknowledge and put the new root in fwd*/
429 static void fastprotocol(int vlan
, int newrootport
)
432 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
433 ({ if(port
!= newrootport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
434 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
435 port_set_status(port
,vlan
,DISCARDING
);
436 ba_set(fsttab
[vlan
]->backup
,port
);
437 fst_sendbpdu(vlan
,port
,0,0,0); }
439 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
440 ({ if(port
!= newrootport
&& !(ba_check(fsttab
[vlan
]->backup
,port
)) &&
441 !(ba_check(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
442 port_set_status(port
,vlan
,DISCARDING
);
443 ba_set(fsttab
[vlan
]->backup
,port
);
444 fst_sendbpdu(vlan
,port
,0,0,0); }
446 ba_clr(fsttab
[vlan
]->backup
,newrootport
); /* forward ON */
447 port_set_status(newrootport
,vlan
,FORWARDING
);
448 fst_sendbpdu(vlan
,newrootport
,1,0,0);
451 /* handling of bpdu incoming packets */
452 void fst_in_bpdu(int port
, struct packet
*inpacket
, int len
, int vlan
, int tagged
)
455 /* XXX check the header for fake info? */
456 struct vlst
*v
=fsttab
[vlan
];
458 if (ba_check(fsttab
[vlan
]->edge
,port
))
461 if (!FSTP_ACTIVE(vlan
,port
)) {
462 DBGOUT(DBGFSTPPLUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
463 EVENTOUT(DBGFSTPPLUS
,port
,vlan
);
466 ba_set(fsttab
[vlan
]->rcvhist
[rcvhistindex
],port
);
469 p
=(struct fstbpdu
*)(((unsigned char *)inpacket
)+4);
472 p
=(struct fstbpdu
*)(inpacket
);
473 if (len
< 51 || v
==NULL
|| p
->stp_version
!= 2 || p
->stp_type
!= 2)
474 return; /* faulty packet */
475 /* this is a topology change packet */
476 if (p
->stp_flags
& STP_TC
)
477 topology_change(vlan
,port
);
478 *((u_int32_t
*)(p
->stp_rootcost
))=
479 htonl(ntohl(*((u_int32_t
*)(p
->stp_rootcost
)))+
480 (port_getcost(port
)-((port
==v
->bonusport
)?v
->bonuscost
:0)));
482 /* >0 means new root, == 0 root unchanged, <0 sender must change topology */
483 if ((val
=valroot
=memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
)) == 0)
484 if ((val
=memcmp(v
->rootcost
,p
->stp_rootcost
,4)) == 0)
485 if ((val
=memcmp(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
)) == 0)
486 val
=memcmp(v
->port
,p
->stp_port
,2);
487 /*printf("VAL = %d root=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
488 " recv=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n",val,
489 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
490 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
491 p->stp_root[0], p->stp_root[1], p->stp_root[2], p->stp_root[3],
492 p->stp_root[4], p->stp_root[5], p->stp_root[6], p->stp_root[7]);
493 printf("++ stp_bridge=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
494 " cost=%02x:%02x:%02x:%02x: port %02x:%02x \n",
495 p->stp_bridge[0], p->stp_bridge[1], p->stp_bridge[2], p->stp_bridge[3],
496 p->stp_bridge[4], p->stp_bridge[5], p->stp_bridge[6], p->stp_bridge[7],
497 p->stp_rootcost[0], p->stp_rootcost[1], p->stp_rootcost[2], p->stp_rootcost[3],
498 p->stp_port[0], p->stp_port[1]); */
499 if (val
== 0) { /* root unchanged / new root announce*/
500 v
->roottimestamp
=qtime();
501 } else { /* new root or new root info*/
502 if (val
> 0 || (port
== fsttab
[vlan
]->rootport
&& val
<0)) {
503 if (memcmp(v
->root
,outpacket
.header
.src
,8) <= 0)
505 /* printf("NEW ROOT\n");*/
506 memcpy(v
->root
,p
->stp_root
,SWITCHID_LEN
);
507 memcpy(v
->rootcost
,p
->stp_rootcost
,4);
508 memcpy(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
);
509 memcpy(v
->port
,p
->stp_port
,2);
511 v
->roottimestamp
=qtime();
512 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
513 port
,vlan
>>8,vlan
&0xff,
514 v
->root
[0], v
->root
[1], v
->root
[2], v
->root
[3],
515 v
->root
[4], v
->root
[5], v
->root
[6], v
->root
[7]);
516 EVENTOUT(DBGFSTPROOT
,port
,vlan
,v
->root
);
517 fastprotocol(vlan
,port
);
518 topology_change(vlan
,port
);
521 if (memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
) == 0) {
522 /* critical point: longer path to root */
523 /* root -> designated */
524 /* non-root -> blocking */
525 if ((p
->stp_flags
& STP_PORTROLEMASK
) == STP_ROOT
) {
526 if (ba_check(v
->backup
,port
)) {
527 /* backup -> designated transition */
528 //printf("backup -> designated port %d\n",port);
529 ba_clr(v
->backup
,port
); /* forward ON */
530 port_set_status(port
,vlan
,FORWARDING
);
531 topology_change(vlan
,port
);
534 if (!ba_check(v
->backup
,port
)) {
535 /* designated -> backup transition */
536 //printf("designated ->backup port %d\n",port);
537 ba_set(v
->backup
,port
); /* forward OFF */
538 port_set_status(port
,vlan
,DISCARDING
);
539 topology_change(vlan
,port
);
543 /*printf("THIS?\n");*/
544 fst_sendbpdu(vlan
,port
,0,0,0);
550 void fstaddport(int vlan
,int port
,int tagged
)
552 /*printf("F addport V %d - P %d - T%d\n",vlan,port,tagged);*/
555 ba_set(fsttab
[vlan
]->tagged
,port
);
556 ba_clr(fsttab
[vlan
]->untag
,port
);
558 ba_set(fsttab
[vlan
]->untag
,port
);
559 ba_clr(fsttab
[vlan
]->tagged
,port
);
561 ba_clr(fsttab
[vlan
]->backup
,port
);
562 ba_clr(fsttab
[vlan
]->edge
,port
);
563 ba_clr(fsttab
[vlan
]->rcvhist
[0],port
);
564 ba_clr(fsttab
[vlan
]->rcvhist
[1],port
);
565 fst_sendbpdu(vlan
,port
,0,0,0);
566 topology_change(vlan
,port
);
569 void fstdelport(int vlan
,int port
)
571 /*printf("F delport V %d - P %d\n",vlan,port);*/
572 if (FSTP_ACTIVE(vlan
,port
)) {
573 DBGOUT(DBGFSTPMINUS
,"Port %04d VLAN %02x:%02x",port
,vlan
>>8,vlan
&0xff);
574 EVENTOUT(DBGFSTPMINUS
,port
,vlan
);
576 ba_clr(fsttab
[vlan
]->untag
,port
);
577 ba_clr(fsttab
[vlan
]->tagged
,port
);
578 ba_clr(fsttab
[vlan
]->backup
,port
);
579 ba_clr(fsttab
[vlan
]->edge
,port
);
580 if (port
== fsttab
[vlan
]->rootport
) {
583 topology_change(vlan
,port
);
586 static void fstinitpkt(void)
588 memcpy(outpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
589 memcpy(outtagpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
590 memcpy(outpacket
.header
.src
,switchmac
,ETH_ALEN
);
591 memcpy(outtagpacket
.header
.src
,switchmac
,ETH_ALEN
);
592 outpacket
.stp_hello
[0]=outtagpacket
.stp_hello
[0]=helloperiod
,
593 outpacket
.stp_hello
[1]=outtagpacket
.stp_hello
[1]=helloperiod
>>8,
594 outpacket
.stp_maxage
[0]=outtagpacket
.stp_maxage
[0]=maxage
,
595 outpacket
.stp_maxage
[1]=outtagpacket
.stp_maxage
[1]=maxage
>>8,
596 fst_timerno
=qtimer_add(helloperiod
,0,fst_hello
,NULL
);
599 static int fstpshowinfo(FILE *fd
)
601 printoutc(fd
,"MAC %02x:%02x:%02x:%02x:%02x:%02x Priority %d (0x%x)",
602 switchmac
[0], switchmac
[1], switchmac
[2], switchmac
[3], switchmac
[4], switchmac
[5],
604 printoutc(fd
,"FSTP=%s",(pflag
& FSTP_TAG
)?"true":"false");
608 static void fstnewvlan2(int vlan
, void *arg
)
613 void fstpshutdown(void)
615 if (pflag
& FSTP_TAG
)
617 qtimer_del(fst_timerno
);
618 fstflag(P_CLRFLAG
,FSTP_TAG
);
619 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
623 static int fstpsetonoff(FILE *fd
, int val
)
625 int oldval
=((pflag
& FSTP_TAG
) != 0);
626 if (portflag(P_GETFLAG
, HUB_TAG
)){
627 printoutc(fd
, "Can't use fstp in hub mode");
633 if (val
) { /* START FST */
635 fstflag(P_SETFLAG
,FSTP_TAG
);
636 } else { /* STOP FST */
637 qtimer_del(fst_timerno
);
638 fstflag(P_CLRFLAG
,FSTP_TAG
);
639 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
645 static char *decoderole(int vlan
, int port
)
647 if (!(ba_check(fsttab
[vlan
]->untag
,port
) || ba_check(fsttab
[vlan
]->untag
,port
)))
649 if (ba_check(fsttab
[vlan
]->edge
,port
))
651 if (fsttab
[vlan
]->rootport
== port
)
653 if (ba_check(fsttab
[vlan
]->backup
,port
))
654 return "Alternate/Backup";
658 static void fstprintactive(int vlan
,FILE *fd
)
661 printoutc(fd
,"FST DATA VLAN %04d %s %s",vlan
,
662 memcmp(myid
,fsttab
[vlan
]->root
,SWITCHID_LEN
)==0?"ROOTSWITCH":"",
663 ((pflag
& FSTP_TAG
)==0)?"FSTP IS DISABLED":"");
664 printoutc(fd
, " ++ root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
665 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
666 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
667 printoutc(fd
, " ++ designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
668 fsttab
[vlan
]->dessw
[0], fsttab
[vlan
]->dessw
[1], fsttab
[vlan
]->dessw
[2], fsttab
[vlan
]->dessw
[3],
669 fsttab
[vlan
]->dessw
[4], fsttab
[vlan
]->dessw
[5], fsttab
[vlan
]->dessw
[6], fsttab
[vlan
]->dessw
[7]);
670 printoutc(fd
, " ++ rootport %04d cost %d age %d bonusport %04d bonuscost %d",
671 fsttab
[vlan
]->rootport
,
672 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
673 qtime()-fsttab
[vlan
]->roottimestamp
,fsttab
[vlan
]->bonusport
,fsttab
[vlan
]->bonuscost
);
674 ba_FORALL(fsttab
[vlan
]->untag
,numports
,
675 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,0,port_getcost(i
),decoderole(vlan
,i
)),i
);
676 ba_FORALL(fsttab
[vlan
]->tagged
,numports
,
677 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,1,port_getcost(i
),decoderole(vlan
,i
)),i
);
680 static int fstprint(FILE *fd
,char *arg
)
685 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
686 if (bac_check(validvlan
,vlan
))
687 fstprintactive(vlan
,fd
);
693 bac_FORALLFUN(validvlan
,NUMOFVLAN
,fstprintactive
,fd
);
697 static int fstsetbonus(char *arg
)
699 int vlan
, port
, cost
;
700 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&cost
) != 3)
702 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
704 if (!bac_check(validvlan
,vlan
))
706 fsttab
[vlan
]->bonusport
=port
;
707 fsttab
[vlan
]->bonuscost
=cost
;
711 static int fstsetedge(char *arg
)
714 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&val
) != 3)
716 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
718 if (!bac_check(validvlan
,vlan
))
721 ba_set(fsttab
[vlan
]->edge
,port
);
722 if (ba_check(fsttab
[vlan
]->untag
,port
) || ba_check(fsttab
[vlan
]->untag
,port
))
723 port_set_status(port
,vlan
,FORWARDING
);
725 ba_clr(fsttab
[vlan
]->edge
,port
);
726 ba_clr(fsttab
[vlan
]->backup
,port
);
731 static struct comlist cl
[]={
732 {"fstp","============","FAST SPANNING TREE MENU",NULL
,NOARG
},
733 {"fstp/showinfo","","show fstp info",fstpshowinfo
,NOARG
|WITHFILE
},
734 {"fstp/setfstp","0/1","Fast spanning tree protocol 1=ON 0=OFF",fstpsetonoff
,INTARG
|WITHFILE
},
735 {"fstp/setedge","VLAN PORT 1/0","Define an edge port for a vlan 1=Y 0=N",fstsetedge
,STRARG
},
736 {"fstp/bonus","VLAN PORT COST","set the port bonus for a vlan",fstsetbonus
,STRARG
},
737 {"fstp/print","[N]","print fst data for the defined vlan",fstprint
,STRARG
|WITHFILE
},
740 int fstflag(int op
,int f
)
744 case P_GETFLAG
: oldflag
= pflag
& f
; break;
745 case P_SETFLAG
: pflag
=f
; break;
746 case P_ADDFLAG
: pflag
|= f
; break;
747 case P_CLRFLAG
: pflag
&= ~f
; break;
752 void fst_init(int initnumports
)
754 numports
=initnumports
;
755 SETFSTID(myid
,switchmac
,priority
);
756 if (pflag
& FSTP_TAG
)