Several patches from Daniel P. Barrange, Red Hat inc. (TNX!)
[vde.git] / vde-2 / port.c
blob708716146db94545e3c129147647cbf746dd3864
1 /* Copyright 2005 Renzo Davoli VDE-2
2 * Some minor remain from uml_switch Copyright 2002 Yon Uriarte and Jeff Dike
3 * Licensed under the GPLv2
4 */
6 #include <config.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <syslog.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15 #include <sys/poll.h>
16 #include <netinet/in.h> /*ntoh conversion*/
18 #include <switch.h>
19 #include <hash.h>
20 #include <qtimer.h>
21 #include <port.h>
22 #include <fcntl.h>
23 #include <consmgmt.h>
24 #include <bitarray.h>
25 #include <fstp.h>
26 #include <vde.h>
27 #ifdef VDE_PQ
28 #include <packetq.h>
29 #endif
31 static int pflag=0;
32 static int numports;
34 // for dedugging if needed
37 void packet_dump (struct packet *p)
39 register int i;
40 printf ("packet dump dst");
41 for (i=0;i<ETH_ALEN;i++)
42 printf(":%02x",p->header.dest[i]);
43 printf(" src");
44 for (i=0;i<ETH_ALEN;i++)
45 printf(":%02x",p->header.src[i]);
46 printf(" proto");
47 for (i=0;i<2;i++)
48 printf(":%02x",p->header.proto[i]);
49 printf("\n");
50 }*/
52 struct endpoint {
53 int port;
54 int fd_ctl;
55 void *data;
56 char *descr;
57 struct endpoint *next;
60 #define NOTINPOOL 0x8000
62 struct port {
63 int fd_data;
64 struct endpoint *ep;
65 int flag;
66 /* sender is already inside ep, but it needs one more memaccess */
67 int (*sender)(int fd, int fd_ctl, void *packet, int len, void *data, int port);
68 struct mod_support *ms;
69 int vlanuntag;
70 #ifdef FSTP
71 int cost;
72 #endif
75 /* VLAN MANAGEMENT:
76 * table the vlan table (also for inactive ports)
77 * vlan bctag is the vlan table -- only tagged forwarding ports mapping
78 * vlan bcuntag is the vlan table -- only untagged forwarding ports mapping
79 * validvlan is the table of valid vlans
82 struct {
83 bitarray table;
84 bitarray bctag;
85 bitarray bcuntag;
86 bitarray notlearning;
87 } vlant[NUMOFVLAN];
88 bitarray validvlan;
90 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
92 static struct port **portv;
94 static int alloc_port(unsigned int portno)
96 int i=portno;
97 if (i==0) {
98 /* take one */
99 for (i=1;i<numports && portv[i] != NULL &&
100 (portv[i]->ep != NULL || portv[i]->flag & NOTINPOOL) ;i++)
102 } else if (i<0) /* special case MGMT client port */
103 i=0;
104 if (i >= numports)
105 return -1;
106 else {
107 if (portv[i] == NULL) {
108 struct port *port;
109 if ((port = malloc(sizeof(struct port))) == NULL){
110 printlog(LOG_WARNING,"malloc port %s",strerror(errno));
111 return -1;
112 } else
114 portv[i]=port;
115 port->fd_data=-1;
116 port->ep=NULL;
117 #ifdef FSTP
118 port->cost=DEFAULT_COST;
119 #endif
120 port->flag=0;
121 port->sender=NULL;
122 port->vlanuntag=0;
123 BA_SET(vlant[0].table,i);
126 return i;
130 static void free_port(unsigned int portno)
132 if (portno < numports) {
133 struct port *port=portv[portno];
134 if (port != NULL && port->ep==NULL) {
135 portv[portno]=NULL;
136 register int i;
137 /* delete completely the port. all vlan defs zapped */
138 BAC_FORALL(validvlan,NUMOFVLAN,BA_CLR(vlant[i].table,portno),i);
139 free(port);
144 /* initialize a port structure with control=fd, given data+data_len and sender
145 * function;
146 * and then add it to the g_fdsdata array at index i. */
147 int setup_ep(int portno, int fd_ctl,
148 void *data,
149 struct mod_support *modfun)
151 struct port *port;
152 struct endpoint *ep;
154 if ((portno = alloc_port(portno)) >= 0) {
155 port=portv[portno];
156 if (port->fd_data < 0)
157 port->fd_data=modfun->newport(fd_ctl,portno);
158 if (port->fd_data >= 0 &&
159 (ep=malloc(sizeof(struct endpoint))) != NULL) {
160 port->ms=modfun;
161 port->sender=modfun->sender;
162 ep->port=portno;
163 ep->fd_ctl=fd_ctl;
164 ep->data=data;
165 ep->descr=NULL;
166 if(port->ep == NULL) {/* WAS INACTIVE */
167 register int i;
168 /* copy all the vlan defs to the active vlan defs*/
169 ep->next=port->ep;
170 port->ep=ep;
171 BAC_FORALL(validvlan,NUMOFVLAN,
172 ({if (BA_CHECK(vlant[i].table,portno)) {
173 BA_SET(vlant[i].bctag,portno);
174 #ifdef FSTP
175 fstaddport(i,portno,(i!=port->vlanuntag));
176 #endif
178 }),i);
179 if (port->vlanuntag != NOVLAN) {
180 BA_SET(vlant[port->vlanuntag].bcuntag,portno);
181 BA_CLR(vlant[port->vlanuntag].bctag,portno);
183 BA_CLR(vlant[port->vlanuntag].notlearning,portno);
184 } else {
185 ep->next=port->ep;
186 port->ep=ep;
188 return portno;
190 else {
191 free_port(portno);
192 return -1;
195 else
196 return -1;
199 void setup_description(int portno, int fd_ctl, char *descr)
201 if (portno >=0 && portno < numports) {
202 struct port *port=portv[portno];
203 if (port != NULL) {
204 struct endpoint *ep;
205 for (ep=port->ep;ep!=NULL;ep=ep->next)
206 if (ep->fd_ctl == fd_ctl)
207 ep->descr=descr;
213 static int rec_close_ep(struct endpoint **pep, int fd_ctl)
215 struct endpoint *this=*pep;
216 if (this != NULL) {
217 if (this->fd_ctl==fd_ctl) {
218 *pep=this->next;
219 if (portv[this->port]->ms->delep)
220 portv[this->port]->ms->delep(this->fd_ctl,this->data,this->descr);
221 free(this);
222 return 0;
223 } else
224 return rec_close_ep(&(this->next),fd_ctl);
225 } else
226 return ENXIO;
229 int close_ep(int portno, int fd_ctl)
231 if (portno >=0 && portno < numports) {
232 struct port *port=portv[portno];
233 if (port != NULL) {
234 int rv=rec_close_ep(&(port->ep),fd_ctl);
235 if (port->ep == NULL) {
236 hash_delete_port(portno);
237 #ifdef VDE_PQ
238 packetq_delfd(port->fd_data);
239 #endif
240 if (portv[portno]->ms->delport)
241 portv[portno]->ms->delport(port->fd_data,portno);
242 port->fd_data=-1;
243 port->ms=NULL;
244 port->sender=NULL;
245 register int i;
246 /* inactivate port: all active vlan defs cleared */
247 BAC_FORALL(validvlan,NUMOFVLAN,({
248 BA_CLR(vlant[i].bctag,portno);
249 #ifdef FSTP
250 fstdelport(i,portno);
251 #endif
252 }),i);
253 if (port->vlanuntag < NOVLAN) BA_CLR(vlant[port->vlanuntag].bcuntag,portno);
255 return rv;
256 } else
257 return ENXIO;
258 } else
259 return EINVAL;
262 int portflag(int op,int f)
264 int oldflag=pflag;
265 switch(op) {
266 case P_SETFLAG: pflag=f; break;
267 case P_ADDFLAG: pflag |= f; break;
268 case P_CLRFLAG: pflag &= ~f; break;
270 return oldflag;
274 /*********************** sending macro used by Core ******************/
276 #ifdef VDE_PQ
277 #define SEND_PACKET_PORT(PORT,PACKET,LEN) \
278 ({ \
279 struct port *Port=(PORT); \
280 struct endpoint *ep; \
281 for (ep=Port->ep; ep != NULL; ep=ep->next) \
282 if (Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port)) \
283 packetq_add(Port->ms->sender,Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
285 #else
286 #define SEND_PACKET_PORT(PORT,PACKET,LEN) \
287 ({ \
288 struct port *Port=(PORT); \
289 struct endpoint *ep; \
290 for (ep=Port->ep; ep != NULL; ep=ep->next) \
291 Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
293 #endif
295 #ifdef FSTP
297 /* functions for FSTP */
298 void port_send_packet(int portno, void *packet, int len)
300 SEND_PACKET_PORT(portv[portno],packet,len);
303 void portset_send_packet(bitarray portset, void *packet, int len)
305 register int i;
306 BA_FORALL(portset,numports,
307 SEND_PACKET_PORT(portv[i],packet,len), i);
310 void port_set_status(int portno, int vlan, int status)
312 if (BA_CHECK(vlant[vlan].table,portno)) {
313 if (status==DISCARDING) {
314 BA_SET(vlant[vlan].notlearning,portno);
315 BA_CLR(vlant[vlan].bctag,portno);
316 BA_CLR(vlant[vlan].bcuntag,portno);
317 } else if (status==LEARNING) {
318 BA_CLR(vlant[vlan].notlearning,portno);
319 BA_CLR(vlant[vlan].bctag,portno);
320 BA_CLR(vlant[vlan].bcuntag,portno);
321 } else { /*forwarding*/
322 BA_CLR(vlant[vlan].notlearning,portno);
323 if (portv[portno]->vlanuntag == vlan)
324 BA_SET(vlant[vlan].bcuntag,portno);
325 else
326 BA_SET(vlant[vlan].bctag,portno);
331 int port_get_status(int portno, int vlan)
333 if (BA_CHECK(vlant[vlan].notlearning,portno))
334 return DISCARDING;
335 else {
336 if (BA_CHECK(vlant[vlan].bctag,portno) ||
337 BA_CHECK(vlant[vlan].bcuntag,portno))
338 return FORWARDING;
339 else
340 return LEARNING;
344 int port_getcost(int port)
346 return portv[port]->cost;
348 #endif
350 /************************************ CORE PACKET MGMT *****************************/
352 /* TAG2UNTAG packet:
353 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
354 * | Destination | Source |81 00|pvlan| L/T | data
355 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
357 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
358 * | Destination | Source | L/T | data
359 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
361 * Destination/Source: 4 byte right shift
362 * Length -4 bytes
363 * Pointer to the packet: +4 bytes
364 * */
366 #define TAG2UNTAG(P,LEN) \
367 ({ memmove((char *)(P)+4,(P),2*ETH_ALEN); LEN -= 4 ; \
368 (struct packet *)((char *)(P)+4); })
370 /* TAG2UNTAG packet:
371 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
372 * | Destination | Source | L/T | data
373 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
375 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
376 * | Destination | Source |81 00|pvlan| L/T | data
377 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
378 * Destination/Source: 4 byte left shift
379 * Length -4 bytes
380 * Pointer to the packet: +4 bytes
381 * The space has been allocated in advance (just in case); all the modules
382 * read data into a bipacket.
385 #define UNTAG2TAG(P,VLAN,LEN) \
386 ({ memmove((char *)(P)-4,(P),2*ETH_ALEN); LEN += 4 ; \
387 (P)->header.src[2]=0x81; (P)->header.src[3]=0x00;\
388 (P)->header.src[4]=(VLAN >> 8); (P)->header.src[5]=(VLAN);\
389 (struct packet *)((char *)(P)-4); })
392 void handle_in_packet(int port, struct packet *packet, int len)
393 /* static void update_src(int port, struct packet *p) */
395 int tarport;
396 int vlan,tagged;
398 if (packet->header.proto[0] == 0x81 && packet->header.proto[1] == 0x00) {
399 tagged=1;
400 vlan=((packet->data[0] << 8) + packet->data[1]) & 0xfff;
401 if (! BA_CHECK(vlant[vlan].table,port))
402 return; /*discard unwanted packets*/
403 } else {
404 tagged=0;
405 if ((vlan=portv[port]->vlanuntag) == NOVLAN)
406 return; /*discard unwanted packets*/
409 #ifdef FSTP
410 if (ISBPDU(packet)) {
411 fst_in_bpdu(port,packet,len,vlan,tagged);
412 return; /* BPDU packets are not forwarded */
414 /* The port is in blocked status, no packet received */
415 #endif
416 if (BA_CHECK(vlant[vlan].notlearning,port)) return;
418 /* We don't like broadcast source addresses */
419 if(! ((IS_BROADCAST(packet->header.src)) || (pflag & HUB_TAG))) {
421 /* int last = */ find_in_hash_update(packet->header.src,vlan,port);
422 /* old value differs from actual input port */
423 /* if(last < 0 || (port != last)){
424 if(last >= 0)
425 printf(" old port %d", last);
426 } */
428 /* static void send_dst(int port,struct packet *packet, int len) */
429 if(IS_BROADCAST(packet->header.dest) || (pflag & HUB_TAG) ||
430 (tarport = find_in_hash(packet->header.dest,vlan)) < 0 ){
431 /* FST HERE! broadcast only on active ports*/
432 /* no cache or broadcast/multicast == all ports *except* the source port! */
433 /* BROADCAST: tag/untag. Broadcast the packet untouched on the ports
434 * of the same tag-ness, then transform it to the other tag-ness for the others*/
435 if (tagged) {
436 register int i;
437 BA_FORALL(vlant[vlan].bctag,numports,
438 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
439 packet=TAG2UNTAG(packet,len);
440 BA_FORALL(vlant[vlan].bcuntag,numports,
441 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
442 } else { /* untagged */
443 register int i;
444 BA_FORALL(vlant[vlan].bcuntag,numports,
445 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
446 packet=UNTAG2TAG(packet,vlan,len);
447 BA_FORALL(vlant[vlan].bctag,numports,
448 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
451 else {
452 /* the hash table should not generate tarport not in vlan
453 * any time a port is removed from a vlan, the port is flushed from the hash */
454 if (tarport==port)
455 return; /*do not loop!*/
456 if (tagged) {
457 if (portv[tarport]->vlanuntag==vlan) /* TAG->UNTAG */
458 SEND_PACKET_PORT(portv[tarport],TAG2UNTAG(packet,len),len);
459 else /* TAG->TAG */
460 SEND_PACKET_PORT(portv[tarport],packet,len);
461 } else {
462 if (portv[tarport]->vlanuntag==vlan) /* UNTAG->UNTAG */
463 SEND_PACKET_PORT(portv[tarport],packet,len);
464 else /* UNTAG->TAG */
465 SEND_PACKET_PORT(portv[tarport],UNTAG2TAG(packet,vlan,len),len);
470 /**************************************** COMMAND MANAGEMENT ****************************************/
472 static int showinfo(int fd)
474 printoutc(fd,"Numports=%d",numports);
475 printoutc(fd,"HUB=%s",(pflag & HUB_TAG)?"true":"false");
476 return 0;
479 static int portsetnumports(int val)
481 if(val > 0) {
482 /*resize structs*/
483 int i;
484 for(i=val;i<numports;i++)
485 if(portv[i] != NULL)
486 return EADDRINUSE;
487 portv=realloc(portv,val*sizeof(struct port *));
488 if (portv == NULL) {
489 printlog(LOG_ERR,"Numport resize failed portv %s",strerror(errno));
490 exit(1);
492 for (i=0;i<NUMOFVLAN;i++) {
493 if (vlant[i].table) {
494 BA_REALLOC(vlant[i].table,numports,val);
495 if (vlant[i].table == NULL) {
496 printlog(LOG_ERR,"Numport resize failed vlan tables vlan table %s",strerror(errno));
497 exit(1);
500 if (vlant[i].bctag) {
501 BA_REALLOC(vlant[i].bctag,numports,val);
502 if (vlant[i].bctag == NULL) {
503 printlog(LOG_ERR,"Numport resize failed vlan tables vlan bctag %s",strerror(errno));
504 exit(1);
507 if (vlant[i].notlearning) {
508 BA_REALLOC(vlant[i].notlearning,numports,val);
509 if (vlant[i].notlearning == NULL) {
510 printlog(LOG_ERR,"Numport resize failed vlan tables vlan notlearning %s",strerror(errno));
511 exit(1);
515 for (i=numports;i<val;i++)
516 portv[i]=NULL;
517 #ifdef FSTP
518 fstsetnumports(val);
519 #endif
520 numports=val;
521 return 0;
522 } else
523 return EINVAL;
526 static int portallocatable(char *arg)
528 int port,value;
529 if (sscanf(arg,"%i %i",&port,&value) != 2)
530 return EINVAL;
531 if (port < 0 || port >= numports)
532 return EINVAL;
533 if (portv[port] == NULL)
534 return ENXIO;
535 if (value)
536 portv[port]->flag &= ~NOTINPOOL;
537 else
538 portv[port]->flag |= NOTINPOOL;
539 return 0;
542 static int portremove(int val)
544 if (val <0 || val>=numports)
545 return EINVAL;
546 if (portv[val] == NULL)
547 return ENXIO;
548 if (portv[val]->ep != NULL)
549 return EADDRINUSE;
550 free_port(val);
551 return 0;
554 static int portcreate(int val)
556 if (val <0 || val>=numports)
557 return EINVAL;
558 if (portv[val] != NULL)
559 return EEXIST;
560 alloc_port(val);
561 return 0;
564 static int epclose(char *arg)
566 int port,id;
567 if (sscanf(arg,"%i %i",&port,&id) != 2)
568 return EINVAL;
569 else
570 return close_ep(port,id);
573 static int print_port(int fd,int i,int inclinactive)
575 struct endpoint *ep;
576 if (portv[i] != NULL && (inclinactive || portv[i]->ep!=NULL)) {
577 printoutc(fd,"Port %04d untagged_vlan=%04d %sACTIVE - %sUnnamed Allocatable",
578 i,portv[i]->vlanuntag,
579 portv[i]->ep?"":"IN",
580 (portv[i]->flag & NOTINPOOL)?"NOT ":"");
581 for (ep=portv[i]->ep; ep != NULL; ep=ep->next)
582 printoutc(fd," -- endpoint ID %04d module %-12s: %s",ep->fd_ctl,
583 portv[i]->ms->modname,(ep->descr)?ep->descr:"no endpoint description");
584 return 0;
585 } else
586 return ENXIO;
589 static int print_ptable(int fd,char *arg)
591 register int i;
592 if (*arg != 0) {
593 i=atoi(arg);
594 if (i <0 || i>=numports)
595 return EINVAL;
596 else {
597 return print_port(fd,i,0);
599 } else {
600 for (i=0;i<numports;i++)
601 print_port(fd,i,0);
602 return 0;
606 static int print_ptableall(int fd,char *arg)
608 register int i;
609 if (*arg != 0) {
610 i=atoi(arg);
611 if (i <0 || i>=numports)
612 return EINVAL;
613 else {
614 return print_port(fd,i,1);
616 } else {
617 for (i=0;i<numports;i++)
618 print_port(fd,i,1);
619 return 0;
623 static int portsethub(int val)
625 (val)?portflag(P_SETFLAG,HUB_TAG):portflag(P_CLRFLAG,HUB_TAG);
626 return 0;
629 static int portsetvlan(char *arg)
631 int port,vlan;
632 if (sscanf(arg,"%i %i",&port,&vlan) != 2)
633 return EINVAL;
634 /* port NOVLAN is okay here, it means NO untagged traffic */
635 if (vlan <0 || vlan > NUMOFVLAN || port < 0 || port >= numports)
636 return EINVAL;
637 if ((vlan != NOVLAN && !BAC_CHECK(validvlan,vlan)) || portv[port] == NULL)
638 return ENXIO;
639 int oldvlan=portv[port]->vlanuntag;
640 portv[port]->vlanuntag=NOVLAN;
641 hash_delete_port(port);
642 if (portv[port]->ep != NULL) {
643 /*changing active port*/
644 if (oldvlan != NOVLAN)
645 BA_CLR(vlant[oldvlan].bcuntag,port);
646 if (vlan != NOVLAN) {
647 BA_SET(vlant[vlan].bcuntag,port);
648 BA_CLR(vlant[vlan].bctag,port);
650 #ifdef FSTP
651 if (oldvlan != NOVLAN) fstdelport(oldvlan,port);
652 if (vlan != NOVLAN) fstaddport(vlan,port,0);
653 #endif
655 if (oldvlan != NOVLAN) BA_CLR(vlant[oldvlan].table,port);
656 if (vlan != NOVLAN) BA_SET(vlant[vlan].table,port);
657 portv[port]->vlanuntag=vlan;
658 return 0;
661 static int vlancreate_nocheck(int vlan)
663 int rv=0;
664 vlant[vlan].table=BA_ALLOC(numports);
665 vlant[vlan].bctag=BA_ALLOC(numports);
666 vlant[vlan].bcuntag=BA_ALLOC(numports);
667 vlant[vlan].notlearning=BA_ALLOC(numports);
668 if (vlant[vlan].table == NULL || vlant[vlan].bctag == NULL ||
669 vlant[vlan].bcuntag == NULL)
670 return ENOMEM;
671 else {
672 #ifdef FSTP
673 rv=fstnewvlan(vlan);
674 #endif
675 if (rv == 0)
676 BAC_SET(validvlan,NUMOFVLAN,vlan);
677 return rv;
681 static int vlancreate(int vlan)
683 if (vlan > 0 && vlan < NUMOFVLAN-1) { /*vlan NOVLAN (0xfff a.k.a. 4095) is reserved */
684 if (BAC_CHECK(validvlan,vlan))
685 return EEXIST;
686 else
687 return vlancreate_nocheck(vlan);
688 } else
689 return EINVAL;
692 static int vlanremove(int vlan)
694 if (vlan >= 0 && vlan < NUMOFVLAN) {
695 if (BAC_CHECK(validvlan,vlan)) {
696 register int i,used=0;
697 BA_FORALL(vlant[vlan].table,numports,used++,i);
698 if (used)
699 return EADDRINUSE;
700 else {
701 BAC_CLR(validvlan,NUMOFVLAN,vlan);
702 free(vlant[vlan].table);
703 free(vlant[vlan].bctag);
704 free(vlant[vlan].bcuntag);
705 free(vlant[vlan].notlearning);
706 vlant[vlan].table=NULL;
707 vlant[vlan].bctag=NULL;
708 vlant[vlan].bcuntag=NULL;
709 vlant[vlan].notlearning=NULL;
710 #ifdef FSTP
711 fstremovevlan(vlan);
712 #endif
713 return 0;
715 } else
716 return ENXIO;
717 } else
718 return EINVAL;
721 static int vlanaddport(char *arg)
723 int port,vlan;
724 if (sscanf(arg,"%i %i",&vlan,&port) != 2)
725 return EINVAL;
726 if (vlan <0 || vlan >= NUMOFVLAN-1 || port < 0 || port >= numports)
727 return EINVAL;
728 if (!BAC_CHECK(validvlan,vlan) || portv[port] == NULL)
729 return ENXIO;
730 if (portv[port]->ep != NULL && portv[port]->vlanuntag != vlan) {
731 /* changing active port*/
732 BA_SET(vlant[vlan].bctag,port);
733 #ifdef FSTP
734 fstaddport(vlan,port,1);
735 #endif
737 BA_SET(vlant[vlan].table,port);
738 return 0;
741 static int vlandelport(char *arg)
743 int port,vlan;
744 if (sscanf(arg,"%i %i",&vlan,&port) != 2)
745 return EINVAL;
746 if (vlan <0 || vlan >= NUMOFVLAN-1 || port < 0 || port >= numports)
747 return EINVAL;
748 if (!BAC_CHECK(validvlan,vlan) || portv[port] == NULL)
749 return ENXIO;
750 if (portv[port]->vlanuntag == vlan)
751 return EADDRINUSE;
752 if (portv[port]->ep != NULL) {
753 /*changing active port*/
754 BA_CLR(vlant[vlan].bctag,port);
755 #ifdef FSTP
756 fstdelport(vlan,port);
757 #endif
759 BA_CLR(vlant[vlan].table,port);
760 hash_delete_port(port);
761 return 0;
764 #define STRSTATUS(PN,V) \
765 ((BA_CHECK(vlant[(V)].notlearning,(PN))) ? "Discarding" : \
766 (BA_CHECK(vlant[(V)].bctag,(PN)) || BA_CHECK(vlant[(V)].bcuntag,(PN))) ? \
767 "Forwarding" : "Learning")
769 static void vlanprintactive(int vlan,int fd)
771 register int i;
772 printoutc(fd,"VLAN %04d",vlan);
773 #ifdef FSTP
774 if (pflag & FSTP_TAG) {
775 #if 0
776 printoutc(fd," ++ FST root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n"
777 " designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x port %d cost %d age %d",
778 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
779 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
780 fsttab[vlan]->desbr[0], fsttab[vlan]->desbr[1], fsttab[vlan]->desbr[2], fsttab[vlan]->desbr[3],
781 fsttab[vlan]->desbr[4], fsttab[vlan]->desbr[5], fsttab[vlan]->desbr[6], fsttab[vlan]->desbr[7],
782 fsttab[vlan]->rootport,
783 ntohl(*(u_int32_t *)(&(fsttab[vlan]->rootcost))),
784 qtime()-fsttab[vlan]->roottimestamp);
785 BA_FORALL(vlant[vlan].table,numports,
786 ({ int tagged=portv[i]->vlanuntag != vlan;
787 if (portv[i]->ep)
788 printoutc(fd," -- Port %04d tagged=%d act=%d learn=%d forw=%d cost=%d role=%s",
789 i, tagged, 1, !(NOTLEARNING(i,vlan)),
790 (tagged)?(BA_CHECK(vlant[vlan].bctag,i) != 0):(BA_CHECK(vlant[vlan].bcuntag,i) != 0),
791 portv[i]->cost,
792 (fsttab[vlan]->rootport==i?"Root":
793 ((BA_CHECK(fsttab[vlan]->backup,i)?"Alternate/Backup":"Designated")))
794 ); 0;
795 }) ,i);
796 #endif
797 } else {
798 #endif
799 BA_FORALL(vlant[vlan].table,numports,
800 ({ int tagged=portv[i]->vlanuntag != vlan;
801 if (portv[i]->ep)
802 printoutc(fd," -- Port %04d tagged=%d active=1 status=%s", i, tagged,
803 STRSTATUS(i,vlan));
804 }), i);
805 #ifdef FSTP
807 #endif
810 static int vlanprint(int fd,char *arg)
812 if (*arg != 0) {
813 register int vlan;
814 vlan=atoi(arg);
815 if (vlan >= 0 && vlan < NUMOFVLAN-1) {
816 if (BAC_CHECK(validvlan,vlan))
817 vlanprintactive(vlan,fd);
818 else
819 return ENXIO;
820 } else
821 return EINVAL;
822 } else
823 BAC_FORALLFUN(validvlan,NUMOFVLAN,vlanprintactive,fd);
824 return 0;
827 static void vlanprintelem(int vlan,int fd)
829 register int i;
830 printoutc(fd,"VLAN %04d",vlan);
831 BA_FORALL(vlant[vlan].table,numports,
832 printoutc(fd," -- Port %04d tagged=%d active=%d status=%s",
833 i, portv[i]->vlanuntag != vlan, portv[i]->ep != NULL, STRSTATUS(i,vlan)),i);
836 static int vlanprintall(int fd,char *arg)
838 if (*arg != 0) {
839 register int vlan;
840 vlan=atoi(arg);
841 if (vlan > 0 && vlan < NUMOFVLAN-1) {
842 if (BAC_CHECK(validvlan,vlan))
843 vlanprintelem(vlan,fd);
844 else
845 return ENXIO;
846 } else
847 return EINVAL;
848 } else
849 BAC_FORALLFUN(validvlan,NUMOFVLAN,vlanprintelem,fd);
850 return 0;
853 /* NOT sure about the effects of changing address on FSTP */
855 #if 0
856 static int setmacaddr(char *strmac)
858 int maci[ETH_ALEN],rv;
860 if (index(strmac,':') != NULL)
861 rv=sscanf(strmac,"%x:%x:%x:%x:%x:%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
862 else
863 rv=sscanf(strmac,"%x.%x.%x.%x.%x.%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
864 if (rv < 6)
865 return EINVAL;
866 else {
867 register int i;
868 for (i=0;i<ETH_ALEN;i++)
869 switchmac[i]=maci[i];
870 return 0;
873 #endif
876 static struct comlist cl[]={
877 {"port","============","PORT STATUS MENU",NULL,NOARG},
878 {"port/showinfo","","show hash info",showinfo,NOARG|WITHFD},
879 {"port/setnumports","N","set the number of ports",portsetnumports,INTARG},
880 /*{"port/setmacaddr","MAC","set the switch MAC address",setmacaddr,STRARG},*/
881 {"port/sethub","0/1","1=HUB 0=switch",portsethub,INTARG},
882 {"port/setvlan","N VLAN","set port VLAN (untagged)",portsetvlan,STRARG},
883 {"port/create","N","create the port N (inactive)",portcreate,INTARG},
884 {"port/remove","N","remove the port N",portremove,INTARG},
885 {"port/allocatable","N 0/1","Is the port allocatable as unnamed? 1=Y 0=N",portallocatable,STRARG},
886 {"port/epclose","N ID","remove the endpoint port N/id ID",epclose,STRARG},
887 {"port/print","[N]","print the port/endpoint table",print_ptable,STRARG|WITHFD},
888 {"port/allprint","[N]","print the port/endpoint table (including inactive port)",print_ptableall,STRARG|WITHFD},
889 {"vlan","============","VLAN MANAGEMENT MENU",NULL,NOARG},
890 {"vlan/create","N","create the VLAN with tag N",vlancreate,INTARG},
891 {"vlan/remove","N","remove the VLAN with tag N",vlanremove,INTARG},
892 {"vlan/addport","N PORT","add port to the vlan N (tagged)",vlanaddport,STRARG},
893 {"vlan/delport","N PORT","add port to the vlan N (tagged)",vlandelport,STRARG},
894 {"vlan/print","[N]","print the list of defined vlan",vlanprint,STRARG|WITHFD},
895 {"vlan/allprint","[N]","print the list of defined vlan (including inactive port)",vlanprintall,STRARG|WITHFD},
898 void port_init(int initnumports)
900 if((numports=initnumports) <= 0) {
901 printlog(LOG_ERR,"The switch must have at least 1 port\n");
902 exit(1);
904 portv=calloc(numports,sizeof(struct port *));
905 /* vlan_init */
906 validvlan=BAC_ALLOC(NUMOFVLAN);
907 if (portv==NULL || validvlan == NULL) {
908 printlog(LOG_ERR,"ALLOC port data structures");
909 exit(1);
911 if (vlancreate_nocheck(0) != 0) {
912 printlog(LOG_ERR,"ALLOC vlan port data structures");
913 exit(1);
915 ADDCL(cl);