- added support for Mac OSX (10.3 Panther and 10.4 Tiger). For tuntap support
[vde.git] / vde-2 / fstp.c
blob941dbedbb51693f344642d770a6c9a31e9527272
1 /* Copyright 2005 Renzo Davoli VDE-2
2 * Licensed under the GPLv2
3 */
5 #include <config.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <syslog.h>
12 #include <sys/socket.h>
13 #include <sys/un.h>
14 #include <sys/poll.h>
15 #include <netinet/in.h> /*ntoh conversion*/
17 #include <switch.h>
18 #include <hash.h>
19 #include <qtimer.h>
20 #include <port.h>
21 #include <fcntl.h>
22 #include <consmgmt.h>
23 #include <bitarray.h>
25 static int pflag=0;
26 static int numports;
28 #ifdef FSTP
29 #include <fstp.h>
30 /*********************** sending macro used by FSTP & Core ******************/
32 #define STP_TCA 0x80
33 #define STP_AGREEMENT 0x40
34 #define STP_FORWARDING 0x20
35 #define STP_LEARNING 0x10
36 #define STP_PORTROLEMASK 0x0c
37 #define STP_ROOT 0x04
38 #define STP_PROPOSAL 0x02
39 #define STP_TC 0x01
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;
45 struct vlst {
46 char root[SWITCHID_LEN];
47 char rootcost[4];
48 char dessw[SWITCHID_LEN];
49 char port[2];
50 int rootport;
51 int bonusport;
52 int bonuscost;
53 int tctime;
54 /* TC: topology change timers missing XXX */
55 unsigned int roottimestamp;
56 bitarray untag;
57 bitarray tagged;
58 bitarray backup;
59 bitarray edge;
60 bitarray rcvhist[2];
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); \
67 *(id++)=(PRIO)>>8; \
68 *(id++)=(PRIO); \
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 */
79 struct fstbpdu {
80 struct ethheader header;
81 unsigned char llc[3];
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 */
98 struct fsttagbpdu {
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},
122 .stp_protocol={0,0},
123 .stp_version=2,
124 .stp_type=2,
127 static struct fsttagbpdu outtagpacket = {
128 .header.dest=BPDUADDR,
129 .header.proto={0x81,0x00},
130 .tag_proto={0x00,0x39},
131 .llc={0x42,0x42,0x3},
132 .stp_protocol={0,0},
133 .stp_version=2,
134 .stp_type=2,
138 * BIT:
139 * 0 TOPOLOGY CHANGE
140 * 1 PROPOSAL
141 * 2/3 PORT ROLE: 00 UNKNOWN 01 ALT/BACKUP 10 ROOT 11 DESIGNATED
142 * 4 LEARNING 5 FORWARDING
143 * 6 AGREEMENT
144 * 7 TOPOLOGY CHANGE ACK
147 #define STP_FLAGS(VLAN,PORT,AGR,TC,TCACK) \
148 (TC | \
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 | \
153 (AGR) << 6 | \
154 (TCACK) << 7)
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))
170 return ENOMEM;
171 else {
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;
177 if (newvlan) {
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);
184 }), port);
185 return 0;
189 int fstremovevlan(int vlan)
191 /*printf("F remove vlan %d\n",vlan);*/
192 if (fsttab[vlan] == NULL)
193 return ENOENT;
194 else {
195 struct vlst *old=fsttab[vlan];
196 fsttab[vlan]=NULL;
197 free(old->untag);
198 free(old->tagged);
199 free(old->backup);
200 free(old->edge);
201 free(old->rcvhist[0]);
202 free(old->rcvhist[1]);
203 free(old);
204 return 0;
208 void fstsetnumports (int val)
210 register int i;
211 /*printf("F numports %d\n",val);*/
212 for (i=0;i<NUMOFVLAN;i++) {
213 if (fsttab[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));
217 exit(1);
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));
222 exit(1);
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));
227 exit(1);
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));
232 exit(1);
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));
237 exit(1);
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));
242 exit(1);
246 numports=val;
249 /* say hello! */
250 static void fst_hello_vlan(int vlan,int now)
252 int age,nowvlan;
253 register int port;
254 /* timeout on the root port */
255 if (fsttab[vlan]->rootport != 0 && (now - fsttab[vlan]->roottimestamp) > 3*helloperiod)
256 fstnewvlan(vlan);
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));
275 }), port);
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));
285 }), port);
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)
294 register int port;
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);
300 }), port);
301 BA_ZAP(fsttab[vlan]->rcvhist[index],numports);
304 static void fst_hello(void *arg)
306 int now=qtime();
307 static int hellocounter;
308 hellocounter++;
309 //printf("HELLO\n");
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)
319 int now=qtime();
320 int age,nowvlan;
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)
361 register int port;
362 int now=qtime();
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); }
371 }),port);
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); }
376 }),port);
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)
386 register int port;
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); }
393 }),port);
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); }
400 }),port);
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)
409 struct fstbpdu *p;
410 /* XXX check the header for fake info? */
411 struct vlst *v=fsttab[vlan];
412 int val,valroot;
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);
417 if (tagged) {
418 p=(struct fstbpdu *)(((unsigned char *)inpacket)+4);
419 len-=4;
420 } else
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)));
430 /* compare BPDU */
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)
453 fstnewvlan(vlan);
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);
459 v->rootport=port;
460 v->roottimestamp=qtime();
461 fastprotocol(vlan,port);
462 topology_change(vlan,port);
464 else {
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);
477 } else {
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);
486 } else {
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);*/
497 if (tagged) {
498 BA_SET(fsttab[vlan]->tagged,port);
499 BA_CLR(fsttab[vlan]->untag,port);
500 } else {
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) {
518 fstnewvlan(vlan);
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],
540 priority,priority);
541 printoutc(fd,"FSTP=%s",(pflag & FSTP_TAG)?"true":"false");
542 return 0;
545 static void fstnewvlan2(int vlan, void *arg)
547 fstnewvlan(vlan);
550 static int fstpsetonoff(int val)
552 int oldval=((pflag & FSTP_TAG) != 0);
553 val=(val != 0);
554 if (oldval != val)
556 if (val) { /* START FST */
557 fstinitpkt();
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);
565 return 0;
568 static char *decoderole(int vlan, int port)
570 if (!(BA_CHECK(fsttab[vlan]->untag,port) || BA_CHECK(fsttab[vlan]->untag,port)))
571 return "Unknown";
572 if (BA_CHECK(fsttab[vlan]->edge,port))
573 return "Edge";
574 if (fsttab[vlan]->rootport == port)
575 return "Root";
576 if (BA_CHECK(fsttab[vlan]->backup,port))
577 return "Alternate/Backup";
578 return "Designated";
581 static void fstprintactive(int vlan,int fd)
583 register int i;
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)
605 if (*arg != 0) {
606 register int vlan;
607 vlan=atoi(arg);
608 if (vlan >= 0 && vlan < NUMOFVLAN-1) {
609 if (BAC_CHECK(validvlan,vlan))
610 fstprintactive(vlan,fd);
611 else
612 return ENXIO;
613 } else
614 return EINVAL;
615 } else
616 BAC_FORALLFUN(validvlan,NUMOFVLAN,fstprintactive,fd);
617 return 0;
620 static int fstsetbonus(char *arg)
622 int vlan, port, cost;
623 if (sscanf(arg,"%i %i %i",&vlan,&port,&cost) != 3)
624 return EINVAL;
625 if (vlan <0 || vlan >= NUMOFVLAN || port < 0 || port >= numports)
626 return EINVAL;
627 if (!BAC_CHECK(validvlan,vlan))
628 return ENXIO;
629 fsttab[vlan]->bonusport=port;
630 fsttab[vlan]->bonuscost=cost;
631 return 0;
634 static int fstsetedge(char *arg)
636 int vlan, port, val;
637 if (sscanf(arg,"%i %i %i",&vlan,&port,&val) != 3)
638 return EINVAL;
639 if (vlan <0 || vlan >= NUMOFVLAN || port < 0 || port >= numports)
640 return EINVAL;
641 if (!BAC_CHECK(validvlan,vlan))
642 return ENXIO;
643 if (val) {
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);
647 } else {
648 BA_CLR(fsttab[vlan]->edge,port);
649 BA_CLR(fsttab[vlan]->backup,port);
651 return 0;
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)
665 int oldflag=pflag;
666 switch(op) {
667 case P_SETFLAG: pflag=f; break;
668 case P_ADDFLAG: pflag |= f; break;
669 case P_CLRFLAG: pflag &= ~f; break;
671 return oldflag;
674 void fst_init(int initnumports)
676 numports=initnumports;
677 SETFSTID(myid,switchmac,priority);
678 if (pflag & FSTP_TAG)
679 fstinitpkt();
680 ADDCL(cl);
682 #endif