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
41 #define SWITCHID_LEN (ETH_ALEN+2)
42 #define FSTP_ACTIVE(VLAN,PORT) (BA_CHECK(fsttab[(VLAN)]->rcvhist[0],(PORT)) || \
43 BA_CHECK(fsttab[(VLAN)]->rcvhist[1],(PORT)))
44 static int rcvhistindex
;
46 unsigned char root
[SWITCHID_LEN
];
48 unsigned char dessw
[SWITCHID_LEN
];
54 /* TC: topology change timers missing XXX */
55 unsigned int roottimestamp
;
63 #define BPDUADDR {0x01,0x80,0xc2,0x00,0x00,0x00}
64 unsigned char bpduaddrp
[]=BPDUADDR
;
65 #define SETFSTID(ID,MAC,PRIO) ({ \
66 char *id=(char *)(ID); \
69 memcpy(id,(MAC),ETH_ALEN); 0; })
70 static unsigned char myid
[SWITCHID_LEN
];
72 #define STDHELLOPERIOD 4
73 static struct vlst
*fsttab
[NUMOFVLAN
];
74 static int helloperiod
= STDHELLOPERIOD
;
75 static int maxage
= STDHELLOPERIOD
*10;
76 static int fst_timerno
;
78 /* packet prototype for untagged ports */
80 struct ethheader header
;
82 unsigned char stp_protocol
[2];
83 unsigned char stp_version
;
84 unsigned char stp_type
;
85 unsigned char stp_flags
;
86 unsigned char stp_root
[SWITCHID_LEN
];
87 unsigned char stp_rootcost
[4];
88 unsigned char stp_bridge
[SWITCHID_LEN
];
89 unsigned char stp_port
[2];
90 unsigned char stp_age
[2];
91 unsigned char stp_maxage
[2];
92 unsigned char stp_hello
[2];
93 unsigned char stp_fwddelay
[2];
94 unsigned char stp_v1len
;
97 /* packet prototype for tagged ports */
99 struct ethheader header
;
100 unsigned char tag_vlan
[2];
101 unsigned char tag_proto
[2];
102 unsigned char llc
[3];
103 unsigned char stp_protocol
[2];
104 unsigned char stp_version
;
105 unsigned char stp_type
;
106 unsigned char stp_flags
;
107 unsigned char stp_root
[SWITCHID_LEN
];
108 unsigned char stp_rootcost
[4];
109 unsigned char stp_bridge
[SWITCHID_LEN
];
110 unsigned char stp_port
[2];
111 unsigned char stp_age
[2];
112 unsigned char stp_maxage
[2];
113 unsigned char stp_hello
[2];
114 unsigned char stp_fwddelay
[2];
115 unsigned char stp_v1len
;
118 static struct fstbpdu outpacket
= {
119 .header
.dest
=BPDUADDR
,
120 .header
.proto
={0x00,0x39}, /* 802.3 packet length */
121 .llc
={0x42,0x42,0x3},
127 static struct fsttagbpdu outtagpacket
= {
128 .header
.dest
=BPDUADDR
,
129 .header
.proto
={0x81,0x00},
130 .tag_proto
={0x00,0x39},
131 .llc
={0x42,0x42,0x3},
141 * 2/3 PORT ROLE: 00 UNKNOWN 01 ALT/BACKUP 10 ROOT 11 DESIGNATED
142 * 4 LEARNING 5 FORWARDING
144 * 7 TOPOLOGY CHANGE ACK
147 #define STP_FLAGS(VLAN,PORT,AGR,TC,TCACK) \
149 (BA_CHECK(fsttab[(VLAN)]->backup,port) != 0) << 1 | \
150 (BA_CHECK(fsttab[(VLAN)]->backup,port) == 0) << 2 | \
151 (fsttab[vlan]->rootport != (PORT)) << 3 |\
152 port_get_status((PORT),(VLAN)) << 4 | \
157 int fstnewvlan(int vlan
)
159 /*printf("F new vlan %d\n",vlan);*/
160 int newvlan
=(fsttab
[vlan
] == NULL
);
161 register unsigned int port
;
162 if ((fsttab
[vlan
] == NULL
) &&
163 ((fsttab
[vlan
]=malloc(sizeof(struct vlst
))) == NULL
||
164 (fsttab
[vlan
]->untag
= BA_ALLOC(numports
)) == NULL
||
165 (fsttab
[vlan
]->tagged
= BA_ALLOC(numports
)) == NULL
||
166 (fsttab
[vlan
]->edge
= BA_ALLOC(numports
)) == NULL
||
167 (fsttab
[vlan
]->rcvhist
[0] = BA_ALLOC(numports
)) == NULL
||
168 (fsttab
[vlan
]->rcvhist
[1] = BA_ALLOC(numports
)) == NULL
||
169 (fsttab
[vlan
]->backup
= BA_ALLOC(numports
)) == NULL
))
172 memcpy(fsttab
[vlan
]->root
,myid
,SWITCHID_LEN
);
173 memset(fsttab
[vlan
]->rootcost
,0,4);
174 memset(fsttab
[vlan
]->dessw
,0xff,SWITCHID_LEN
);
175 memset(fsttab
[vlan
]->port
,0,4);
176 fsttab
[vlan
]->rootport
=fsttab
[vlan
]->roottimestamp
=0;
178 fsttab
[vlan
]->bonusport
=fsttab
[vlan
]->bonuscost
=0;
179 fsttab
[vlan
]->tctime
=0;
181 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
182 BA_CLR(fsttab
[vlan
]->backup
,port
);
183 port_set_status(port
,vlan
,FORWARDING
);
189 int fstremovevlan(int vlan
)
191 /*printf("F remove vlan %d\n",vlan);*/
192 if (fsttab
[vlan
] == NULL
)
195 struct vlst
*old
=fsttab
[vlan
];
201 free(old
->rcvhist
[0]);
202 free(old
->rcvhist
[1]);
208 void fstsetnumports (int val
)
211 /*printf("F numports %d\n",val);*/
212 for (i
=0;i
<NUMOFVLAN
;i
++) {
214 BA_REALLOC(fsttab
[i
]->untag
,numports
,val
);
215 if (fsttab
[i
]->untag
== NULL
) {
216 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/untag %s",strerror(errno
));
219 BA_REALLOC(fsttab
[i
]->tagged
,numports
,val
);
220 if (fsttab
[i
]->tagged
== NULL
) {
221 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/tagged %s",strerror(errno
));
224 BA_REALLOC(fsttab
[i
]->backup
,numports
,val
);
225 if (fsttab
[i
]->backup
== NULL
) {
226 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/backup %s",strerror(errno
));
229 BA_REALLOC(fsttab
[i
]->edge
,numports
,val
);
230 if (fsttab
[i
]->edge
== NULL
) {
231 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/edge %s",strerror(errno
));
234 BA_REALLOC(fsttab
[i
]->rcvhist
[0],numports
,val
);
235 if (fsttab
[i
]->rcvhist
[0] == NULL
) {
236 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist0 %s",strerror(errno
));
239 BA_REALLOC(fsttab
[i
]->rcvhist
[1],numports
,val
);
240 if (fsttab
[i
]->rcvhist
[1] == NULL
) {
241 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist1 %s",strerror(errno
));
250 static void fst_hello_vlan(int vlan
,int now
)
254 /* timeout on the root port */
255 if (fsttab
[vlan
]->rootport
!= 0 && (now
- fsttab
[vlan
]->roottimestamp
) > 3*helloperiod
)
257 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
258 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
259 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
260 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
261 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
262 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
263 if (age
> 0xffff) age
=0xffff;
264 outpacket
.stp_age
[0] = outtagpacket
.stp_age
[0]=age
;
265 outpacket
.stp_age
[1] = outtagpacket
.stp_age
[1]=age
>>8;
266 outpacket
.stp_fwddelay
[0] = outtagpacket
.stp_fwddelay
[0]=0;
267 outpacket
.stp_fwddelay
[1] = outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
268 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
269 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
270 outpacket
.stp_port
[0]=0x80| (port
>>4);
271 outpacket
.stp_port
[1]=port
;
272 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
273 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
276 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
277 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
278 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
279 outtagpacket
.stp_port
[1]=port
;
280 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
281 outtagpacket
.tag_vlan
[1]=vlan
;
282 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
283 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
288 /* a port that is not handling control packets for a while cannot be
289 * a backup port. It means that the other end is not speaking FSTP anymore.
290 * It must be reverted to a designed forwarding port.
292 static void fst_updatebackup(int vlan
,int index
)
295 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
296 if (!FSTP_ACTIVE(vlan
,port
)) {
297 BA_CLR(fsttab
[vlan
]->backup
,port
);
298 port_set_status(port
,vlan
,FORWARDING
);
301 BA_ZAP(fsttab
[vlan
]->rcvhist
[index
],numports
);
304 static void fst_hello(void *arg
)
307 static int hellocounter
;
310 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fst_hello_vlan
,now
);
311 if ((hellocounter
&& 0x3) == 0) {
312 rcvhistindex
=1-rcvhistindex
;
313 BAC_FORALLFUN(validvlan
,NUMOFVLAN
, fst_updatebackup
,rcvhistindex
);
317 static void fst_sendbpdu(int vlan
,int port
,int agr
,int tc
,int tcack
)
321 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
322 if (BA_CHECK(fsttab
[vlan
]->untag
,port
)) {
323 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
324 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
325 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
326 if (age
> 0xffff) age
=0xffff;
327 outpacket
.stp_age
[0] = age
;
328 outpacket
.stp_age
[1] = age
>>8;
329 outpacket
.stp_fwddelay
[0] = 0;
330 outpacket
.stp_fwddelay
[1] = 0; /* XXX */
331 outpacket
.stp_port
[0]=0x80| (port
>>4);
332 outpacket
.stp_port
[1]=port
;
333 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
334 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
336 if (BA_CHECK(fsttab
[vlan
]->tagged
,port
)) {
337 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
338 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
339 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
340 if (age
> 0xffff) age
=0xffff;
341 outtagpacket
.stp_age
[0]=age
;
342 outtagpacket
.stp_age
[1]=age
>>8;
343 outtagpacket
.stp_fwddelay
[0]=0;
344 outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
345 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
346 outtagpacket
.stp_port
[1]=port
;
347 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
348 outtagpacket
.tag_vlan
[1]=vlan
;
349 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
350 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
354 /* Topology change flood
355 * two main difference between this and 802.1d/w:
356 * - it flushes all the hash table for this vlan (including the "calling" port
357 * - do not send all the packet with TC but just this
359 static void topology_change(int vlan
, int genport
)
363 //if (now - fsttab[vlan]->tctime > 2*helloperiod) { /*limit age?*/
364 /*printf("TOPOLOGY CHANGE %d\n",vlan);*/
365 fsttab
[vlan
]->tctime
=now
;
366 hash_delete_vlan(vlan
);
367 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
368 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
369 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
370 fst_sendbpdu(vlan
,port
,0,1,0); }
372 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
373 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
374 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
375 fst_sendbpdu(vlan
,port
,0,1,0); }
380 /* heart of the fast protocol:
381 * 1- receive a proposal
382 * 2- stop all the designed ports
383 * 3- give back the acknowledge and put the new root in fwd*/
384 static void fastprotocol(int vlan
, int newrootport
)
387 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
388 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
389 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
390 port_set_status(port
,vlan
,DISCARDING
);
391 BA_SET(fsttab
[vlan
]->backup
,port
);
392 fst_sendbpdu(vlan
,port
,0,0,0); }
394 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
395 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
396 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
397 port_set_status(port
,vlan
,DISCARDING
);
398 BA_SET(fsttab
[vlan
]->backup
,port
);
399 fst_sendbpdu(vlan
,port
,0,0,0); }
401 BA_CLR(fsttab
[vlan
]->backup
,newrootport
); /* forward ON */
402 port_set_status(newrootport
,vlan
,FORWARDING
);
403 fst_sendbpdu(vlan
,newrootport
,1,0,0);
406 /* handling of bpdu incoming packets */
407 void fst_in_bpdu(int port
, struct packet
*inpacket
, int len
, int vlan
, int tagged
)
410 /* XXX check the header for fake info? */
411 struct vlst
*v
=fsttab
[vlan
];
413 if (!(pflag
& FSTP_TAG
) || (BA_CHECK(fsttab
[vlan
]->edge
,port
)))
414 return; /*FST IS TURNED OFF or EDGE*/
415 BA_SET(fsttab
[vlan
]->rcvhist
[rcvhistindex
],port
);
418 p
=(struct fstbpdu
*)(((unsigned char *)inpacket
)+4);
421 p
=(struct fstbpdu
*)(inpacket
);
422 if (len
< 51 || v
==NULL
|| p
->stp_version
!= 2 || p
->stp_type
!= 2)
423 return; /* faulty packet */
424 /* this is a topology change packet */
425 if (p
->stp_flags
& STP_TC
)
426 topology_change(vlan
,port
);
427 *((u_int32_t
*)(p
->stp_rootcost
))=
428 htonl(ntohl(*((u_int32_t
*)(p
->stp_rootcost
)))+
429 (port_getcost(port
)-((port
==v
->bonusport
)?v
->bonuscost
:0)));
431 /* >0 means new root, == 0 root unchanged, <0 sender must change topology */
432 if ((val
=valroot
=memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
)) == 0)
433 if ((val
=memcmp(v
->rootcost
,p
->stp_rootcost
,4)) == 0)
434 if ((val
=memcmp(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
)) == 0)
435 val
=memcmp(v
->port
,p
->stp_port
,2);
436 /*printf("VAL = %d root=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
437 " recv=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n",val,
438 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
439 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
440 p->stp_root[0], p->stp_root[1], p->stp_root[2], p->stp_root[3],
441 p->stp_root[4], p->stp_root[5], p->stp_root[6], p->stp_root[7]);
442 printf("++ stp_bridge=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
443 " cost=%02x:%02x:%02x:%02x: port %02x:%02x \n",
444 p->stp_bridge[0], p->stp_bridge[1], p->stp_bridge[2], p->stp_bridge[3],
445 p->stp_bridge[4], p->stp_bridge[5], p->stp_bridge[6], p->stp_bridge[7],
446 p->stp_rootcost[0], p->stp_rootcost[1], p->stp_rootcost[2], p->stp_rootcost[3],
447 p->stp_port[0], p->stp_port[1]); */
448 if (val
== 0) { /* root unchanged / new root announce*/
449 v
->roottimestamp
=qtime();
450 } else { /* new root or new root info*/
451 if (val
> 0 || (port
== fsttab
[vlan
]->rootport
&& val
<0)) {
452 if (memcmp(v
->root
,outpacket
.header
.src
,8) <= 0)
454 /* printf("NEW ROOT\n");*/
455 memcpy(v
->root
,p
->stp_root
,SWITCHID_LEN
);
456 memcpy(v
->rootcost
,p
->stp_rootcost
,4);
457 memcpy(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
);
458 memcpy(v
->port
,p
->stp_port
,2);
460 v
->roottimestamp
=qtime();
461 fastprotocol(vlan
,port
);
462 topology_change(vlan
,port
);
465 if (memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
) == 0) {
466 /* critical point: longer path to root */
467 /* root -> designated */
468 /* non-root -> blocking */
469 if ((p
->stp_flags
& STP_PORTROLEMASK
) == STP_ROOT
) {
470 if (BA_CHECK(v
->backup
,port
)) {
471 /* backup -> designated transition */
472 //printf("backup -> designated port %d\n",port);
473 BA_CLR(v
->backup
,port
); /* forward ON */
474 port_set_status(port
,vlan
,FORWARDING
);
475 topology_change(vlan
,port
);
478 if (!BA_CHECK(v
->backup
,port
)) {
479 /* designated -> backup transition */
480 //printf("designated ->backup port %d\n",port);
481 BA_SET(v
->backup
,port
); /* forward OFF */
482 port_set_status(port
,vlan
,DISCARDING
);
483 topology_change(vlan
,port
);
487 /*printf("THIS?\n");*/
488 fst_sendbpdu(vlan
,port
,0,0,0);
494 void fstaddport(int vlan
,int port
,int tagged
)
496 /*printf("F addport V %d - P %d - T%d\n",vlan,port,tagged);*/
498 BA_SET(fsttab
[vlan
]->tagged
,port
);
499 BA_CLR(fsttab
[vlan
]->untag
,port
);
501 BA_SET(fsttab
[vlan
]->untag
,port
);
502 BA_CLR(fsttab
[vlan
]->tagged
,port
);
504 BA_CLR(fsttab
[vlan
]->backup
,port
);
505 BA_CLR(fsttab
[vlan
]->edge
,port
);
506 fst_sendbpdu(vlan
,port
,0,0,0);
507 topology_change(vlan
,port
);
510 void fstdelport(int vlan
,int port
)
512 /*printf("F delport V %d - P %d\n",vlan,port);*/
513 BA_CLR(fsttab
[vlan
]->untag
,port
);
514 BA_CLR(fsttab
[vlan
]->tagged
,port
);
515 BA_CLR(fsttab
[vlan
]->backup
,port
);
516 BA_CLR(fsttab
[vlan
]->edge
,port
);
517 if (port
== fsttab
[vlan
]->rootport
) {
520 topology_change(vlan
,port
);
523 static void fstinitpkt(void)
525 memcpy(outpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
526 memcpy(outtagpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
527 memcpy(outpacket
.header
.src
,switchmac
,ETH_ALEN
);
528 memcpy(outtagpacket
.header
.src
,switchmac
,ETH_ALEN
);
529 outpacket
.stp_hello
[0]=outtagpacket
.stp_hello
[0]=helloperiod
,
530 outpacket
.stp_hello
[1]=outtagpacket
.stp_hello
[1]=helloperiod
>>8,
531 outpacket
.stp_maxage
[0]=outtagpacket
.stp_maxage
[0]=maxage
,
532 outpacket
.stp_maxage
[1]=outtagpacket
.stp_maxage
[1]=maxage
>>8,
533 fst_timerno
=qtimer_add(helloperiod
,0,fst_hello
,NULL
);
536 static int fstpshowinfo(int fd
)
538 printoutc(fd
,"MAC %02x:%02x:%02x:%02x:%02x:%02x Priority %d (0x%x)",
539 switchmac
[0], switchmac
[1], switchmac
[2], switchmac
[3], switchmac
[4], switchmac
[5],
541 printoutc(fd
,"FSTP=%s",(pflag
& FSTP_TAG
)?"true":"false");
545 static void fstnewvlan2(int vlan
, void *arg
)
550 static int fstpsetonoff(int val
)
552 int oldval
=((pflag
& FSTP_TAG
) != 0);
556 if (val
) { /* START FST */
558 fstflag(P_SETFLAG
,FSTP_TAG
);
559 } else { /* STOP FST */
560 qtimer_del(fst_timerno
);
561 fstflag(P_CLRFLAG
,FSTP_TAG
);
562 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
568 static char *decoderole(int vlan
, int port
)
570 if (!(BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
)))
572 if (BA_CHECK(fsttab
[vlan
]->edge
,port
))
574 if (fsttab
[vlan
]->rootport
== port
)
576 if (BA_CHECK(fsttab
[vlan
]->backup
,port
))
577 return "Alternate/Backup";
581 static void fstprintactive(int vlan
,int fd
)
584 printoutc(fd
,"FST DATA VLAN %04d %s %s",vlan
,
585 memcmp(myid
,fsttab
[vlan
]->root
,SWITCHID_LEN
)==0?"ROOTSWITCH":"",
586 ((pflag
& FSTP_TAG
)==0)?"FSTP IS DISABLED":"");
587 printoutc(fd
, " ++ root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
588 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
589 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
590 printoutc(fd
, " ++ designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
591 fsttab
[vlan
]->dessw
[0], fsttab
[vlan
]->dessw
[1], fsttab
[vlan
]->dessw
[2], fsttab
[vlan
]->dessw
[3],
592 fsttab
[vlan
]->dessw
[4], fsttab
[vlan
]->dessw
[5], fsttab
[vlan
]->dessw
[6], fsttab
[vlan
]->dessw
[7]);
593 printoutc(fd
, " ++ rootport %04d cost %d age %d bonusport %04d bonuscost %d",
594 fsttab
[vlan
]->rootport
,
595 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
596 qtime()-fsttab
[vlan
]->roottimestamp
,fsttab
[vlan
]->bonusport
,fsttab
[vlan
]->bonuscost
);
597 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
598 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,0,port_getcost(i
),decoderole(vlan
,i
)),i
);
599 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
600 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,1,port_getcost(i
),decoderole(vlan
,i
)),i
);
603 static int fstprint(int fd
,char *arg
)
608 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
609 if (BAC_CHECK(validvlan
,vlan
))
610 fstprintactive(vlan
,fd
);
616 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstprintactive
,fd
);
620 static int fstsetbonus(char *arg
)
622 int vlan
, port
, cost
;
623 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&cost
) != 3)
625 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
627 if (!BAC_CHECK(validvlan
,vlan
))
629 fsttab
[vlan
]->bonusport
=port
;
630 fsttab
[vlan
]->bonuscost
=cost
;
634 static int fstsetedge(char *arg
)
637 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&val
) != 3)
639 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
641 if (!BAC_CHECK(validvlan
,vlan
))
644 BA_SET(fsttab
[vlan
]->edge
,port
);
645 if (BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
))
646 port_set_status(port
,vlan
,FORWARDING
);
648 BA_CLR(fsttab
[vlan
]->edge
,port
);
649 BA_CLR(fsttab
[vlan
]->backup
,port
);
654 static struct comlist cl
[]={
655 {"fstp","============","FAST SPANNING TREE MENU",NULL
,NOARG
},
656 {"fstp/showinfo","","show fstp info",fstpshowinfo
,NOARG
|WITHFD
},
657 {"fstp/setfstp","0/1","Fast spanning tree protocol 1=ON 0=OFF",fstpsetonoff
,INTARG
},
658 {"fstp/setedge","VLAN PORT 1/0","Define an edge port for a vlan 1=Y 0=N",fstsetedge
,STRARG
},
659 {"fstp/bonus","VLAN PORT COST","set the port bonus for a vlan",fstsetbonus
,STRARG
},
660 {"fstp/print","[N]","print fst data for the defined vlan",fstprint
,STRARG
|WITHFD
},
663 int fstflag(int op
,int f
)
667 case P_SETFLAG
: pflag
=f
; break;
668 case P_ADDFLAG
: pflag
|= f
; break;
669 case P_CLRFLAG
: pflag
&= ~f
; break;
674 void fst_init(int initnumports
)
676 numports
=initnumports
;
677 SETFSTID(myid
,switchmac
,priority
);
678 if (pflag
& FSTP_TAG
)