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 static struct dbgcl dl
[]= {
45 {"fstp/status","fstp: status change",D_FSTP
|D_STATUS
},
46 {"fstp/root","fstp: rootswitch/port change",D_FSTP
|D_ROOT
},
48 static char *fstpdecodestatus
[]={
52 "learning+forwarding"};
53 #define port_set_status(P,V,S) \
54 ({DBGOUT(DBGFSTPSTATUS,"Port %04d VLAN %02x:%02x %s",\
55 (P),(V)>>8,(V)&0xff,fstpdecodestatus[(S)]);\
56 EVENTOUT(DBGFSTPSTATUS,(P),(V),(S));\
57 port_set_status(P,V,S);})
60 #define SWITCHID_LEN (ETH_ALEN+2)
61 #define FSTP_ACTIVE(VLAN,PORT) (BA_CHECK(fsttab[(VLAN)]->rcvhist[0],(PORT)) || \
62 BA_CHECK(fsttab[(VLAN)]->rcvhist[1],(PORT)))
64 static int rcvhistindex
;
66 unsigned char root
[SWITCHID_LEN
];
68 unsigned char dessw
[SWITCHID_LEN
];
74 /* TC: topology change timers missing XXX */
75 unsigned int roottimestamp
;
83 #define BPDUADDR {0x01,0x80,0xc2,0x00,0x00,0x00}
84 unsigned char bpduaddrp
[]=BPDUADDR
;
85 #define SETFSTID(ID,MAC,PRIO) ({ \
86 char *id=(char *)(ID); \
89 memcpy(id,(MAC),ETH_ALEN); 0; })
90 static unsigned char myid
[SWITCHID_LEN
];
92 #define STDHELLOPERIOD 4
93 static struct vlst
*fsttab
[NUMOFVLAN
];
94 static int helloperiod
= STDHELLOPERIOD
;
95 static int maxage
= STDHELLOPERIOD
*10;
96 static int fst_timerno
;
98 /* packet prototype for untagged ports */
100 struct ethheader header
;
101 unsigned char llc
[3];
102 unsigned char stp_protocol
[2];
103 unsigned char stp_version
;
104 unsigned char stp_type
;
105 unsigned char stp_flags
;
106 unsigned char stp_root
[SWITCHID_LEN
];
107 unsigned char stp_rootcost
[4];
108 unsigned char stp_bridge
[SWITCHID_LEN
];
109 unsigned char stp_port
[2];
110 unsigned char stp_age
[2];
111 unsigned char stp_maxage
[2];
112 unsigned char stp_hello
[2];
113 unsigned char stp_fwddelay
[2];
114 unsigned char stp_v1len
;
117 /* packet prototype for tagged ports */
119 struct ethheader header
;
120 unsigned char tag_vlan
[2];
121 unsigned char tag_proto
[2];
122 unsigned char llc
[3];
123 unsigned char stp_protocol
[2];
124 unsigned char stp_version
;
125 unsigned char stp_type
;
126 unsigned char stp_flags
;
127 unsigned char stp_root
[SWITCHID_LEN
];
128 unsigned char stp_rootcost
[4];
129 unsigned char stp_bridge
[SWITCHID_LEN
];
130 unsigned char stp_port
[2];
131 unsigned char stp_age
[2];
132 unsigned char stp_maxage
[2];
133 unsigned char stp_hello
[2];
134 unsigned char stp_fwddelay
[2];
135 unsigned char stp_v1len
;
138 static struct fstbpdu outpacket
= {
139 .header
.dest
=BPDUADDR
,
140 .header
.proto
={0x00,0x39}, /* 802.3 packet length */
141 .llc
={0x42,0x42,0x3},
147 static struct fsttagbpdu outtagpacket
= {
148 .header
.dest
=BPDUADDR
,
149 .header
.proto
={0x81,0x00},
150 .tag_proto
={0x00,0x39},
151 .llc
={0x42,0x42,0x3},
161 * 2/3 PORT ROLE: 00 UNKNOWN 01 ALT/BACKUP 10 ROOT 11 DESIGNATED
162 * 4 LEARNING 5 FORWARDING
164 * 7 TOPOLOGY CHANGE ACK
167 #define STP_FLAGS(VLAN,PORT,AGR,TC,TCACK) \
169 (BA_CHECK(fsttab[(VLAN)]->backup,port) != 0) << 1 | \
170 (BA_CHECK(fsttab[(VLAN)]->backup,port) == 0) << 2 | \
171 (fsttab[vlan]->rootport != (PORT)) << 3 |\
172 port_get_status((PORT),(VLAN)) << 4 | \
176 int fstnewvlan(int vlan
)
178 /*printf("F new vlan %d\n",vlan);*/
179 register unsigned int port
;
180 int newvlan
=(fsttab
[vlan
] == NULL
);
182 ((fsttab
[vlan
]=malloc(sizeof(struct vlst
))) == NULL
||
183 (fsttab
[vlan
]->untag
= BA_ALLOC(numports
)) == NULL
||
184 (fsttab
[vlan
]->tagged
= BA_ALLOC(numports
)) == NULL
||
185 (fsttab
[vlan
]->edge
= BA_ALLOC(numports
)) == NULL
||
186 (fsttab
[vlan
]->rcvhist
[0] = BA_ALLOC(numports
)) == NULL
||
187 (fsttab
[vlan
]->rcvhist
[1] = BA_ALLOC(numports
)) == NULL
||
188 (fsttab
[vlan
]->backup
= BA_ALLOC(numports
)) == NULL
))
191 memcpy(fsttab
[vlan
]->root
,myid
,SWITCHID_LEN
);
192 memset(fsttab
[vlan
]->rootcost
,0,4);
193 memset(fsttab
[vlan
]->dessw
,0xff,SWITCHID_LEN
);
194 memset(fsttab
[vlan
]->port
,0,4);
195 fsttab
[vlan
]->rootport
=fsttab
[vlan
]->roottimestamp
=0;
197 fsttab
[vlan
]->bonusport
=fsttab
[vlan
]->bonuscost
=0;
198 fsttab
[vlan
]->tctime
=0;
200 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
202 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1],
203 fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
204 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5],
205 fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
206 EVENTOUT(DBGFSTPROOT
,0,vlan
,fsttab
[vlan
]->root
);
207 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
208 BA_CLR(fsttab
[vlan
]->backup
,port
);
209 port_set_status(port
,vlan
,FORWARDING
);
215 int fstremovevlan(int vlan
)
217 /*printf("F remove vlan %d\n",vlan);*/
218 if (fsttab
[vlan
] == NULL
)
221 struct vlst
*old
=fsttab
[vlan
];
227 free(old
->rcvhist
[0]);
228 free(old
->rcvhist
[1]);
234 void fstsetnumports (int val
)
237 /*printf("F numports %d\n",val);*/
238 for (i
=0;i
<NUMOFVLAN
;i
++) {
240 BA_REALLOC(fsttab
[i
]->untag
,numports
,val
);
241 if (fsttab
[i
]->untag
== NULL
) {
242 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/untag %s",strerror(errno
));
245 BA_REALLOC(fsttab
[i
]->tagged
,numports
,val
);
246 if (fsttab
[i
]->tagged
== NULL
) {
247 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/tagged %s",strerror(errno
));
250 BA_REALLOC(fsttab
[i
]->backup
,numports
,val
);
251 if (fsttab
[i
]->backup
== NULL
) {
252 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/backup %s",strerror(errno
));
255 BA_REALLOC(fsttab
[i
]->edge
,numports
,val
);
256 if (fsttab
[i
]->edge
== NULL
) {
257 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/edge %s",strerror(errno
));
260 BA_REALLOC(fsttab
[i
]->rcvhist
[0],numports
,val
);
261 if (fsttab
[i
]->rcvhist
[0] == NULL
) {
262 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist0 %s",strerror(errno
));
265 BA_REALLOC(fsttab
[i
]->rcvhist
[1],numports
,val
);
266 if (fsttab
[i
]->rcvhist
[1] == NULL
) {
267 printlog(LOG_ERR
,"Numport resize failed vlan tables fstab/rcvhist1 %s",strerror(errno
));
276 static void fst_hello_vlan(int vlan
,int now
)
280 /* timeout on the root port */
281 if (fsttab
[vlan
]->rootport
!= 0 && (now
- fsttab
[vlan
]->roottimestamp
) > 3*helloperiod
)
283 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
284 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
285 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
286 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
287 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
288 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
289 if (age
> 0xffff) age
=0xffff;
290 outpacket
.stp_age
[0] = outtagpacket
.stp_age
[0]=age
;
291 outpacket
.stp_age
[1] = outtagpacket
.stp_age
[1]=age
>>8;
292 outpacket
.stp_fwddelay
[0] = outtagpacket
.stp_fwddelay
[0]=0;
293 outpacket
.stp_fwddelay
[1] = outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
294 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
295 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
296 outpacket
.stp_port
[0]=0x80| (port
>>4);
297 outpacket
.stp_port
[1]=port
;
298 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
299 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
302 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
303 ({ if (!(BA_CHECK(fsttab
[vlan
]->edge
,port
))) {
304 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
305 outtagpacket
.stp_port
[1]=port
;
306 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
307 outtagpacket
.tag_vlan
[1]=vlan
;
308 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,1,0,0);
309 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
314 /* a port that is not handling control packets for a while cannot be
315 * a backup port. It means that the other end is not speaking FSTP anymore.
316 * It must be reverted to a designed forwarding port.
318 static void fst_updatebackup(int vlan
,int index
)
321 BA_FORALL(fsttab
[vlan
]->backup
,numports
, ({
322 if (!FSTP_ACTIVE(vlan
,port
)) {
323 BA_CLR(fsttab
[vlan
]->backup
,port
);
324 port_set_status(port
,vlan
,FORWARDING
);
327 BA_ZAP(fsttab
[vlan
]->rcvhist
[index
],numports
);
330 static void fst_hello(void *arg
)
333 static int hellocounter
;
336 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fst_hello_vlan
,now
);
337 if ((hellocounter
& 0x3) == 0) {
338 rcvhistindex
=1-rcvhistindex
;
339 BAC_FORALLFUN(validvlan
,NUMOFVLAN
, fst_updatebackup
,rcvhistindex
);
343 static void fst_sendbpdu(int vlan
,int port
,int agr
,int tc
,int tcack
)
347 nowvlan
=(fsttab
[vlan
]->rootport
==0)?0:now
; /* This switch is the root */
348 if (BA_CHECK(fsttab
[vlan
]->untag
,port
)) {
349 memcpy(outpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
350 memcpy(outpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
351 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
352 if (age
> 0xffff) age
=0xffff;
353 outpacket
.stp_age
[0] = age
;
354 outpacket
.stp_age
[1] = age
>>8;
355 outpacket
.stp_fwddelay
[0] = 0;
356 outpacket
.stp_fwddelay
[1] = 0; /* XXX */
357 outpacket
.stp_port
[0]=0x80| (port
>>4);
358 outpacket
.stp_port
[1]=port
;
359 outpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
360 port_send_packet(port
,&outpacket
,sizeof(outpacket
));
362 if (BA_CHECK(fsttab
[vlan
]->tagged
,port
)) {
363 memcpy(outtagpacket
.stp_root
,fsttab
[vlan
]->root
,SWITCHID_LEN
);
364 memcpy(outtagpacket
.stp_rootcost
,fsttab
[vlan
]->rootcost
,4);
365 age
=nowvlan
-fsttab
[vlan
]->roottimestamp
;
366 if (age
> 0xffff) age
=0xffff;
367 outtagpacket
.stp_age
[0]=age
;
368 outtagpacket
.stp_age
[1]=age
>>8;
369 outtagpacket
.stp_fwddelay
[0]=0;
370 outtagpacket
.stp_fwddelay
[1]=0; /* XXX */
371 outtagpacket
.stp_port
[0]=0x80| (port
>>4);
372 outtagpacket
.stp_port
[1]=port
;
373 outtagpacket
.tag_vlan
[0]=vlan
>>8 & 0xf;
374 outtagpacket
.tag_vlan
[1]=vlan
;
375 outtagpacket
.stp_flags
=STP_FLAGS(vlan
,port
,agr
,tc
,tcack
);
376 port_send_packet(port
,&outtagpacket
,sizeof(outtagpacket
));
380 /* Topology change flood
381 * two main difference between this and 802.1d/w:
382 * - it flushes all the hash table for this vlan (including the "calling" port
383 * - do not send all the packet with TC but just this
385 static void topology_change(int vlan
, int genport
)
389 //if (now - fsttab[vlan]->tctime > 2*helloperiod) { /*limit age?*/
390 /*printf("TOPOLOGY CHANGE %d\n",vlan);*/
391 fsttab
[vlan
]->tctime
=now
;
392 hash_delete_vlan(vlan
);
393 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
394 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
395 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
396 fst_sendbpdu(vlan
,port
,0,1,0); }
398 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
399 ({ if(port
!= genport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
400 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
401 fst_sendbpdu(vlan
,port
,0,1,0); }
406 /* heart of the fast protocol:
407 * 1- receive a proposal
408 * 2- stop all the designed ports
409 * 3- give back the acknowledge and put the new root in fwd*/
410 static void fastprotocol(int vlan
, int newrootport
)
413 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
414 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
415 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
416 port_set_status(port
,vlan
,DISCARDING
);
417 BA_SET(fsttab
[vlan
]->backup
,port
);
418 fst_sendbpdu(vlan
,port
,0,0,0); }
420 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
421 ({ if(port
!= newrootport
&& !(BA_CHECK(fsttab
[vlan
]->backup
,port
)) &&
422 !(BA_CHECK(fsttab
[vlan
]->edge
,port
)) && FSTP_ACTIVE(vlan
,port
)) {
423 port_set_status(port
,vlan
,DISCARDING
);
424 BA_SET(fsttab
[vlan
]->backup
,port
);
425 fst_sendbpdu(vlan
,port
,0,0,0); }
427 BA_CLR(fsttab
[vlan
]->backup
,newrootport
); /* forward ON */
428 port_set_status(newrootport
,vlan
,FORWARDING
);
429 fst_sendbpdu(vlan
,newrootport
,1,0,0);
432 /* handling of bpdu incoming packets */
433 void fst_in_bpdu(int port
, struct packet
*inpacket
, int len
, int vlan
, int tagged
)
436 /* XXX check the header for fake info? */
437 struct vlst
*v
=fsttab
[vlan
];
439 if (!(pflag
& FSTP_TAG
) || (BA_CHECK(fsttab
[vlan
]->edge
,port
)))
440 return; /*FST IS TURNED OFF or EDGE*/
441 BA_SET(fsttab
[vlan
]->rcvhist
[rcvhistindex
],port
);
444 p
=(struct fstbpdu
*)(((unsigned char *)inpacket
)+4);
447 p
=(struct fstbpdu
*)(inpacket
);
448 if (len
< 51 || v
==NULL
|| p
->stp_version
!= 2 || p
->stp_type
!= 2)
449 return; /* faulty packet */
450 /* this is a topology change packet */
451 if (p
->stp_flags
& STP_TC
)
452 topology_change(vlan
,port
);
453 *((u_int32_t
*)(p
->stp_rootcost
))=
454 htonl(ntohl(*((u_int32_t
*)(p
->stp_rootcost
)))+
455 (port_getcost(port
)-((port
==v
->bonusport
)?v
->bonuscost
:0)));
457 /* >0 means new root, == 0 root unchanged, <0 sender must change topology */
458 if ((val
=valroot
=memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
)) == 0)
459 if ((val
=memcmp(v
->rootcost
,p
->stp_rootcost
,4)) == 0)
460 if ((val
=memcmp(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
)) == 0)
461 val
=memcmp(v
->port
,p
->stp_port
,2);
462 /*printf("VAL = %d root=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
463 " recv=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n",val,
464 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
465 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
466 p->stp_root[0], p->stp_root[1], p->stp_root[2], p->stp_root[3],
467 p->stp_root[4], p->stp_root[5], p->stp_root[6], p->stp_root[7]);
468 printf("++ stp_bridge=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
469 " cost=%02x:%02x:%02x:%02x: port %02x:%02x \n",
470 p->stp_bridge[0], p->stp_bridge[1], p->stp_bridge[2], p->stp_bridge[3],
471 p->stp_bridge[4], p->stp_bridge[5], p->stp_bridge[6], p->stp_bridge[7],
472 p->stp_rootcost[0], p->stp_rootcost[1], p->stp_rootcost[2], p->stp_rootcost[3],
473 p->stp_port[0], p->stp_port[1]); */
474 if (val
== 0) { /* root unchanged / new root announce*/
475 v
->roottimestamp
=qtime();
476 } else { /* new root or new root info*/
477 if (val
> 0 || (port
== fsttab
[vlan
]->rootport
&& val
<0)) {
478 if (memcmp(v
->root
,outpacket
.header
.src
,8) <= 0)
480 /* printf("NEW ROOT\n");*/
481 memcpy(v
->root
,p
->stp_root
,SWITCHID_LEN
);
482 memcpy(v
->rootcost
,p
->stp_rootcost
,4);
483 memcpy(v
->dessw
,p
->stp_bridge
,SWITCHID_LEN
);
484 memcpy(v
->port
,p
->stp_port
,2);
486 v
->roottimestamp
=qtime();
487 DBGOUT(DBGFSTPROOT
,"Port %04d VLAN %02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
488 port
,vlan
>>8,vlan
&0xff,
489 v
->root
[0], v
->root
[1], v
->root
[2], v
->root
[3],
490 v
->root
[4], v
->root
[5], v
->root
[6], v
->root
[7]);
491 EVENTOUT(DBGFSTPROOT
,port
,vlan
,v
->root
);
492 fastprotocol(vlan
,port
);
493 topology_change(vlan
,port
);
496 if (memcmp(v
->root
,p
->stp_root
,SWITCHID_LEN
) == 0) {
497 /* critical point: longer path to root */
498 /* root -> designated */
499 /* non-root -> blocking */
500 if ((p
->stp_flags
& STP_PORTROLEMASK
) == STP_ROOT
) {
501 if (BA_CHECK(v
->backup
,port
)) {
502 /* backup -> designated transition */
503 //printf("backup -> designated port %d\n",port);
504 BA_CLR(v
->backup
,port
); /* forward ON */
505 port_set_status(port
,vlan
,FORWARDING
);
506 topology_change(vlan
,port
);
509 if (!BA_CHECK(v
->backup
,port
)) {
510 /* designated -> backup transition */
511 //printf("designated ->backup port %d\n",port);
512 BA_SET(v
->backup
,port
); /* forward OFF */
513 port_set_status(port
,vlan
,DISCARDING
);
514 topology_change(vlan
,port
);
518 /*printf("THIS?\n");*/
519 fst_sendbpdu(vlan
,port
,0,0,0);
525 void fstaddport(int vlan
,int port
,int tagged
)
527 /*printf("F addport V %d - P %d - T%d\n",vlan,port,tagged);*/
529 BA_SET(fsttab
[vlan
]->tagged
,port
);
530 BA_CLR(fsttab
[vlan
]->untag
,port
);
532 BA_SET(fsttab
[vlan
]->untag
,port
);
533 BA_CLR(fsttab
[vlan
]->tagged
,port
);
535 BA_CLR(fsttab
[vlan
]->backup
,port
);
536 BA_CLR(fsttab
[vlan
]->edge
,port
);
537 fst_sendbpdu(vlan
,port
,0,0,0);
538 topology_change(vlan
,port
);
541 void fstdelport(int vlan
,int port
)
543 /*printf("F delport V %d - P %d\n",vlan,port);*/
544 BA_CLR(fsttab
[vlan
]->untag
,port
);
545 BA_CLR(fsttab
[vlan
]->tagged
,port
);
546 BA_CLR(fsttab
[vlan
]->backup
,port
);
547 BA_CLR(fsttab
[vlan
]->edge
,port
);
548 if (port
== fsttab
[vlan
]->rootport
) {
551 topology_change(vlan
,port
);
554 static void fstinitpkt(void)
556 memcpy(outpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
557 memcpy(outtagpacket
.stp_bridge
,myid
,SWITCHID_LEN
);
558 memcpy(outpacket
.header
.src
,switchmac
,ETH_ALEN
);
559 memcpy(outtagpacket
.header
.src
,switchmac
,ETH_ALEN
);
560 outpacket
.stp_hello
[0]=outtagpacket
.stp_hello
[0]=helloperiod
,
561 outpacket
.stp_hello
[1]=outtagpacket
.stp_hello
[1]=helloperiod
>>8,
562 outpacket
.stp_maxage
[0]=outtagpacket
.stp_maxage
[0]=maxage
,
563 outpacket
.stp_maxage
[1]=outtagpacket
.stp_maxage
[1]=maxage
>>8,
564 fst_timerno
=qtimer_add(helloperiod
,0,fst_hello
,NULL
);
567 static int fstpshowinfo(FILE *fd
)
569 printoutc(fd
,"MAC %02x:%02x:%02x:%02x:%02x:%02x Priority %d (0x%x)",
570 switchmac
[0], switchmac
[1], switchmac
[2], switchmac
[3], switchmac
[4], switchmac
[5],
572 printoutc(fd
,"FSTP=%s",(pflag
& FSTP_TAG
)?"true":"false");
576 static void fstnewvlan2(int vlan
, void *arg
)
581 static int fstpsetonoff(int val
)
583 int oldval
=((pflag
& FSTP_TAG
) != 0);
587 if (val
) { /* START FST */
589 fstflag(P_SETFLAG
,FSTP_TAG
);
590 } else { /* STOP FST */
591 qtimer_del(fst_timerno
);
592 fstflag(P_CLRFLAG
,FSTP_TAG
);
593 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstnewvlan2
,NULL
);
599 static char *decoderole(int vlan
, int port
)
601 if (!(BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
)))
603 if (BA_CHECK(fsttab
[vlan
]->edge
,port
))
605 if (fsttab
[vlan
]->rootport
== port
)
607 if (BA_CHECK(fsttab
[vlan
]->backup
,port
))
608 return "Alternate/Backup";
612 static void fstprintactive(int vlan
,FILE *fd
)
615 printoutc(fd
,"FST DATA VLAN %04d %s %s",vlan
,
616 memcmp(myid
,fsttab
[vlan
]->root
,SWITCHID_LEN
)==0?"ROOTSWITCH":"",
617 ((pflag
& FSTP_TAG
)==0)?"FSTP IS DISABLED":"");
618 printoutc(fd
, " ++ root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
619 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
620 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7]);
621 printoutc(fd
, " ++ designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
622 fsttab
[vlan
]->dessw
[0], fsttab
[vlan
]->dessw
[1], fsttab
[vlan
]->dessw
[2], fsttab
[vlan
]->dessw
[3],
623 fsttab
[vlan
]->dessw
[4], fsttab
[vlan
]->dessw
[5], fsttab
[vlan
]->dessw
[6], fsttab
[vlan
]->dessw
[7]);
624 printoutc(fd
, " ++ rootport %04d cost %d age %d bonusport %04d bonuscost %d",
625 fsttab
[vlan
]->rootport
,
626 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
627 qtime()-fsttab
[vlan
]->roottimestamp
,fsttab
[vlan
]->bonusport
,fsttab
[vlan
]->bonuscost
);
628 BA_FORALL(fsttab
[vlan
]->untag
,numports
,
629 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,0,port_getcost(i
),decoderole(vlan
,i
)),i
);
630 BA_FORALL(fsttab
[vlan
]->tagged
,numports
,
631 printoutc(fd
," -- Port %04d tagged=%d portcost=%d role=%s",i
,1,port_getcost(i
),decoderole(vlan
,i
)),i
);
634 static int fstprint(FILE *fd
,char *arg
)
639 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
640 if (BAC_CHECK(validvlan
,vlan
))
641 fstprintactive(vlan
,fd
);
647 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,fstprintactive
,fd
);
651 static int fstsetbonus(char *arg
)
653 int vlan
, port
, cost
;
654 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&cost
) != 3)
656 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
658 if (!BAC_CHECK(validvlan
,vlan
))
660 fsttab
[vlan
]->bonusport
=port
;
661 fsttab
[vlan
]->bonuscost
=cost
;
665 static int fstsetedge(char *arg
)
668 if (sscanf(arg
,"%i %i %i",&vlan
,&port
,&val
) != 3)
670 if (vlan
<0 || vlan
>= NUMOFVLAN
|| port
< 0 || port
>= numports
)
672 if (!BAC_CHECK(validvlan
,vlan
))
675 BA_SET(fsttab
[vlan
]->edge
,port
);
676 if (BA_CHECK(fsttab
[vlan
]->untag
,port
) || BA_CHECK(fsttab
[vlan
]->untag
,port
))
677 port_set_status(port
,vlan
,FORWARDING
);
679 BA_CLR(fsttab
[vlan
]->edge
,port
);
680 BA_CLR(fsttab
[vlan
]->backup
,port
);
685 static struct comlist cl
[]={
686 {"fstp","============","FAST SPANNING TREE MENU",NULL
,NOARG
},
687 {"fstp/showinfo","","show fstp info",fstpshowinfo
,NOARG
|WITHFILE
},
688 {"fstp/setfstp","0/1","Fast spanning tree protocol 1=ON 0=OFF",fstpsetonoff
,INTARG
},
689 {"fstp/setedge","VLAN PORT 1/0","Define an edge port for a vlan 1=Y 0=N",fstsetedge
,STRARG
},
690 {"fstp/bonus","VLAN PORT COST","set the port bonus for a vlan",fstsetbonus
,STRARG
},
691 {"fstp/print","[N]","print fst data for the defined vlan",fstprint
,STRARG
|WITHFILE
},
694 int fstflag(int op
,int f
)
698 case P_SETFLAG
: pflag
=f
; break;
699 case P_ADDFLAG
: pflag
|= f
; break;
700 case P_CLRFLAG
: pflag
&= ~f
; break;
705 void fst_init(int initnumports
)
707 numports
=initnumports
;
708 SETFSTID(myid
,switchmac
,priority
);
709 if (pflag
& FSTP_TAG
)