syslimits.h fix for OSX
[vde.git] / vde-2 / port.c
blobe3f941a3768709dd47373b9ab213415530eab508
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 return -1;
194 else
195 return -1;
198 void setup_description(int portno, int fd_ctl, char *descr)
200 if (portno >=0 && portno < numports) {
201 struct port *port=portv[portno];
202 if (port != NULL) {
203 struct endpoint *ep;
204 for (ep=port->ep;ep!=NULL;ep=ep->next)
205 if (ep->fd_ctl == fd_ctl)
206 ep->descr=descr;
212 static int rec_close_ep(struct endpoint **pep, int fd_ctl)
214 struct endpoint *this=*pep;
215 if (this != NULL) {
216 if (this->fd_ctl==fd_ctl) {
217 *pep=this->next;
218 if (portv[this->port]->ms->delep)
219 portv[this->port]->ms->delep(this->fd_ctl,this->data,this->descr);
220 free(this);
221 return 0;
222 } else
223 return rec_close_ep(&(this->next),fd_ctl);
224 } else
225 return ENXIO;
228 int close_ep(int portno, int fd_ctl)
230 if (portno >=0 && portno < numports) {
231 struct port *port=portv[portno];
232 if (port != NULL) {
233 int rv=rec_close_ep(&(port->ep),fd_ctl);
234 if (port->ep == NULL) {
235 hash_delete_port(portno);
236 #ifdef VDE_PQ
237 packetq_delfd(port->fd_data);
238 #endif
239 if (portv[portno]->ms->delport)
240 portv[portno]->ms->delport(port->fd_data,portno);
241 port->fd_data=-1;
242 port->ms=NULL;
243 port->sender=NULL;
244 register int i;
245 /* inactivate port: all active vlan defs cleared */
246 BAC_FORALL(validvlan,NUMOFVLAN,({
247 BA_CLR(vlant[i].bctag,portno);
248 #ifdef FSTP
249 fstdelport(i,portno);
250 #endif
251 }),i);
252 if (port->vlanuntag < NOVLAN) BA_CLR(vlant[port->vlanuntag].bcuntag,portno);
254 return rv;
255 } else
256 return ENXIO;
257 } else
258 return EINVAL;
261 int portflag(int op,int f)
263 int oldflag=pflag;
264 switch(op) {
265 case P_SETFLAG: pflag=f; break;
266 case P_ADDFLAG: pflag |= f; break;
267 case P_CLRFLAG: pflag &= ~f; break;
269 return oldflag;
273 /*********************** sending macro used by Core ******************/
275 #ifdef VDE_PQ
276 #define SEND_PACKET_PORT(PORT,PACKET,LEN) \
277 ({ \
278 struct port *Port=(PORT); \
279 struct endpoint *ep; \
280 for (ep=Port->ep; ep != NULL; ep=ep->next) \
281 if (Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port)) \
282 packetq_add(Port->ms->sender,Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
284 #else
285 #define SEND_PACKET_PORT(PORT,PACKET,LEN) \
286 ({ \
287 struct port *Port=(PORT); \
288 struct endpoint *ep; \
289 for (ep=Port->ep; ep != NULL; ep=ep->next) \
290 Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
292 #endif
294 #ifdef FSTP
296 /* functions for FSTP */
297 void port_send_packet(int portno, void *packet, int len)
299 SEND_PACKET_PORT(portv[portno],packet,len);
302 void portset_send_packet(bitarray portset, void *packet, int len)
304 register int i;
305 BA_FORALL(portset,numports,
306 SEND_PACKET_PORT(portv[i],packet,len), i);
309 void port_set_status(int portno, int vlan, int status)
311 if (BA_CHECK(vlant[vlan].table,portno)) {
312 if (status==DISCARDING) {
313 BA_SET(vlant[vlan].notlearning,portno);
314 BA_CLR(vlant[vlan].bctag,portno);
315 BA_CLR(vlant[vlan].bcuntag,portno);
316 } else if (status==LEARNING) {
317 BA_CLR(vlant[vlan].notlearning,portno);
318 BA_CLR(vlant[vlan].bctag,portno);
319 BA_CLR(vlant[vlan].bcuntag,portno);
320 } else { /*forwarding*/
321 BA_CLR(vlant[vlan].notlearning,portno);
322 if (portv[portno]->vlanuntag == vlan)
323 BA_SET(vlant[vlan].bcuntag,portno);
324 else
325 BA_SET(vlant[vlan].bctag,portno);
330 int port_get_status(int portno, int vlan)
332 if (BA_CHECK(vlant[vlan].notlearning,portno))
333 return DISCARDING;
334 else {
335 if (BA_CHECK(vlant[vlan].bctag,portno) ||
336 BA_CHECK(vlant[vlan].bcuntag,portno))
337 return FORWARDING;
338 else
339 return LEARNING;
343 int port_getcost(int port)
345 return portv[port]->cost;
347 #endif
349 /************************************ CORE PACKET MGMT *****************************/
351 /* TAG2UNTAG packet:
352 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
353 * | Destination | Source |81 00|pvlan| L/T | data
354 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
356 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
357 * | Destination | Source | L/T | data
358 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
360 * Destination/Source: 4 byte right shift
361 * Length -4 bytes
362 * Pointer to the packet: +4 bytes
363 * */
365 #define TAG2UNTAG(P,LEN) \
366 ({ memmove((char *)(P)+4,(P),2*ETH_ALEN); LEN -= 4 ; \
367 (struct packet *)((char *)(P)+4); })
369 /* TAG2UNTAG packet:
370 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
371 * | Destination | Source | L/T | data
372 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
374 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
375 * | Destination | Source |81 00|pvlan| L/T | data
376 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
377 * Destination/Source: 4 byte left shift
378 * Length -4 bytes
379 * Pointer to the packet: +4 bytes
380 * The space has been allocated in advance (just in case); all the modules
381 * read data into a bipacket.
384 #define UNTAG2TAG(P,VLAN,LEN) \
385 ({ memmove((char *)(P)-4,(P),2*ETH_ALEN); LEN += 4 ; \
386 (P)->header.src[2]=0x81; (P)->header.src[3]=0x00;\
387 (P)->header.src[4]=(VLAN >> 8); (P)->header.src[5]=(VLAN);\
388 (struct packet *)((char *)(P)-4); })
391 void handle_in_packet(int port, struct packet *packet, int len)
392 /* static void update_src(int port, struct packet *p) */
394 int tarport;
395 int vlan,tagged;
397 if (packet->header.proto[0] == 0x81 && packet->header.proto[1] == 0x00) {
398 tagged=1;
399 vlan=((packet->data[0] << 8) + packet->data[1]) & 0xfff;
400 if (! BA_CHECK(vlant[vlan].table,port))
401 return; /*discard unwanted packets*/
402 } else {
403 tagged=0;
404 if ((vlan=portv[port]->vlanuntag) == NOVLAN)
405 return; /*discard unwanted packets*/
408 #ifdef FSTP
409 /* when it works as a HUB, MST packet must be forwarded */
410 if (ISBPDU(packet) && !(pflag & HUB_TAG)) {
411 fst_in_bpdu(port,packet,len,vlan,tagged);
412 return; /* BPDU packets are not forwarded */
414 #endif
415 /* The port is in blocked status, no packet received */
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 printlog(LOG_INFO,"MAC %02x:%02x:%02x:%02x:%02x:%02x moved from port %d to port %d",packet->header.src[0],packet->header.src[1],packet->header.src[2],packet->header.src[3],packet->header.src[4],packet->header.src[5],last,port);
427 /* static void send_dst(int port,struct packet *packet, int len) */
428 if(IS_BROADCAST(packet->header.dest) || (pflag & HUB_TAG) ||
429 (tarport = find_in_hash(packet->header.dest,vlan)) < 0 ){
430 /* FST HERE! broadcast only on active ports*/
431 /* no cache or broadcast/multicast == all ports *except* the source port! */
432 /* BROADCAST: tag/untag. Broadcast the packet untouched on the ports
433 * of the same tag-ness, then transform it to the other tag-ness for the others*/
434 if (tagged) {
435 register int i;
436 BA_FORALL(vlant[vlan].bctag,numports,
437 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
438 packet=TAG2UNTAG(packet,len);
439 BA_FORALL(vlant[vlan].bcuntag,numports,
440 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
441 } else { /* untagged */
442 register int i;
443 BA_FORALL(vlant[vlan].bcuntag,numports,
444 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
445 packet=UNTAG2TAG(packet,vlan,len);
446 BA_FORALL(vlant[vlan].bctag,numports,
447 ({if (i != port) SEND_PACKET_PORT(portv[i],packet,len);}),i);
450 else {
451 /* the hash table should not generate tarport not in vlan
452 * any time a port is removed from a vlan, the port is flushed from the hash */
453 if (tarport==port)
454 return; /*do not loop!*/
455 if (tagged) {
456 if (portv[tarport]->vlanuntag==vlan) /* TAG->UNTAG */
457 SEND_PACKET_PORT(portv[tarport],TAG2UNTAG(packet,len),len);
458 else /* TAG->TAG */
459 SEND_PACKET_PORT(portv[tarport],packet,len);
460 } else {
461 if (portv[tarport]->vlanuntag==vlan) /* UNTAG->UNTAG */
462 SEND_PACKET_PORT(portv[tarport],packet,len);
463 else /* UNTAG->TAG */
464 SEND_PACKET_PORT(portv[tarport],UNTAG2TAG(packet,vlan,len),len);
469 /**************************************** COMMAND MANAGEMENT ****************************************/
471 static int showinfo(int fd)
473 printoutc(fd,"Numports=%d",numports);
474 printoutc(fd,"HUB=%s",(pflag & HUB_TAG)?"true":"false");
475 return 0;
478 static int portsetnumports(int val)
480 if(val > 0) {
481 /*resize structs*/
482 int i;
483 for(i=val;i<numports;i++)
484 if(portv[i] != NULL)
485 return EADDRINUSE;
486 portv=realloc(portv,val*sizeof(struct port *));
487 if (portv == NULL) {
488 printlog(LOG_ERR,"Numport resize failed portv %s",strerror(errno));
489 exit(1);
491 for (i=0;i<NUMOFVLAN;i++) {
492 if (vlant[i].table) {
493 BA_REALLOC(vlant[i].table,numports,val);
494 if (vlant[i].table == NULL) {
495 printlog(LOG_ERR,"Numport resize failed vlan tables vlan table %s",strerror(errno));
496 exit(1);
499 if (vlant[i].bctag) {
500 BA_REALLOC(vlant[i].bctag,numports,val);
501 if (vlant[i].bctag == NULL) {
502 printlog(LOG_ERR,"Numport resize failed vlan tables vlan bctag %s",strerror(errno));
503 exit(1);
506 if (vlant[i].notlearning) {
507 BA_REALLOC(vlant[i].notlearning,numports,val);
508 if (vlant[i].notlearning == NULL) {
509 printlog(LOG_ERR,"Numport resize failed vlan tables vlan notlearning %s",strerror(errno));
510 exit(1);
514 for (i=numports;i<val;i++)
515 portv[i]=NULL;
516 #ifdef FSTP
517 fstsetnumports(val);
518 #endif
519 numports=val;
520 return 0;
521 } else
522 return EINVAL;
525 static int portallocatable(char *arg)
527 int port,value;
528 if (sscanf(arg,"%i %i",&port,&value) != 2)
529 return EINVAL;
530 if (port < 0 || port >= numports)
531 return EINVAL;
532 if (portv[port] == NULL)
533 return ENXIO;
534 if (value)
535 portv[port]->flag &= ~NOTINPOOL;
536 else
537 portv[port]->flag |= NOTINPOOL;
538 return 0;
541 static int portremove(int val)
543 if (val <0 || val>=numports)
544 return EINVAL;
545 if (portv[val] == NULL)
546 return ENXIO;
547 if (portv[val]->ep != NULL)
548 return EADDRINUSE;
549 free_port(val);
550 return 0;
553 static int portcreate(int val)
555 if (val <0 || val>=numports)
556 return EINVAL;
557 if (portv[val] != NULL)
558 return EEXIST;
559 alloc_port(val);
560 return 0;
563 static int epclose(char *arg)
565 int port,id;
566 if (sscanf(arg,"%i %i",&port,&id) != 2)
567 return EINVAL;
568 else
569 return close_ep(port,id);
572 static int print_port(int fd,int i,int inclinactive)
574 struct endpoint *ep;
575 if (portv[i] != NULL && (inclinactive || portv[i]->ep!=NULL)) {
576 printoutc(fd,"Port %04d untagged_vlan=%04d %sACTIVE - %sUnnamed Allocatable",
577 i,portv[i]->vlanuntag,
578 portv[i]->ep?"":"IN",
579 (portv[i]->flag & NOTINPOOL)?"NOT ":"");
580 for (ep=portv[i]->ep; ep != NULL; ep=ep->next)
581 printoutc(fd," -- endpoint ID %04d module %-12s: %s",ep->fd_ctl,
582 portv[i]->ms->modname,(ep->descr)?ep->descr:"no endpoint description");
583 return 0;
584 } else
585 return ENXIO;
588 static int print_ptable(int fd,char *arg)
590 register int i;
591 if (*arg != 0) {
592 i=atoi(arg);
593 if (i <0 || i>=numports)
594 return EINVAL;
595 else {
596 return print_port(fd,i,0);
598 } else {
599 for (i=0;i<numports;i++)
600 print_port(fd,i,0);
601 return 0;
605 static int print_ptableall(int fd,char *arg)
607 register int i;
608 if (*arg != 0) {
609 i=atoi(arg);
610 if (i <0 || i>=numports)
611 return EINVAL;
612 else {
613 return print_port(fd,i,1);
615 } else {
616 for (i=0;i<numports;i++)
617 print_port(fd,i,1);
618 return 0;
622 static int portsethub(int val)
624 (val)?portflag(P_SETFLAG,HUB_TAG):portflag(P_CLRFLAG,HUB_TAG);
625 return 0;
628 static int portsetvlan(char *arg)
630 int port,vlan;
631 if (sscanf(arg,"%i %i",&port,&vlan) != 2)
632 return EINVAL;
633 /* port NOVLAN is okay here, it means NO untagged traffic */
634 if (vlan <0 || vlan > NUMOFVLAN || port < 0 || port >= numports)
635 return EINVAL;
636 if ((vlan != NOVLAN && !BAC_CHECK(validvlan,vlan)) || portv[port] == NULL)
637 return ENXIO;
638 int oldvlan=portv[port]->vlanuntag;
639 portv[port]->vlanuntag=NOVLAN;
640 hash_delete_port(port);
641 if (portv[port]->ep != NULL) {
642 /*changing active port*/
643 if (oldvlan != NOVLAN)
644 BA_CLR(vlant[oldvlan].bcuntag,port);
645 if (vlan != NOVLAN) {
646 BA_SET(vlant[vlan].bcuntag,port);
647 BA_CLR(vlant[vlan].bctag,port);
649 #ifdef FSTP
650 if (oldvlan != NOVLAN) fstdelport(oldvlan,port);
651 if (vlan != NOVLAN) fstaddport(vlan,port,0);
652 #endif
654 if (oldvlan != NOVLAN) BA_CLR(vlant[oldvlan].table,port);
655 if (vlan != NOVLAN) BA_SET(vlant[vlan].table,port);
656 portv[port]->vlanuntag=vlan;
657 return 0;
660 static int vlancreate_nocheck(int vlan)
662 int rv=0;
663 vlant[vlan].table=BA_ALLOC(numports);
664 vlant[vlan].bctag=BA_ALLOC(numports);
665 vlant[vlan].bcuntag=BA_ALLOC(numports);
666 vlant[vlan].notlearning=BA_ALLOC(numports);
667 if (vlant[vlan].table == NULL || vlant[vlan].bctag == NULL ||
668 vlant[vlan].bcuntag == NULL)
669 return ENOMEM;
670 else {
671 #ifdef FSTP
672 rv=fstnewvlan(vlan);
673 #endif
674 if (rv == 0)
675 BAC_SET(validvlan,NUMOFVLAN,vlan);
676 return rv;
680 static int vlancreate(int vlan)
682 if (vlan > 0 && vlan < NUMOFVLAN-1) { /*vlan NOVLAN (0xfff a.k.a. 4095) is reserved */
683 if (BAC_CHECK(validvlan,vlan))
684 return EEXIST;
685 else
686 return vlancreate_nocheck(vlan);
687 } else
688 return EINVAL;
691 static int vlanremove(int vlan)
693 if (vlan >= 0 && vlan < NUMOFVLAN) {
694 if (BAC_CHECK(validvlan,vlan)) {
695 register int i,used=0;
696 BA_FORALL(vlant[vlan].table,numports,used++,i);
697 if (used)
698 return EADDRINUSE;
699 else {
700 BAC_CLR(validvlan,NUMOFVLAN,vlan);
701 free(vlant[vlan].table);
702 free(vlant[vlan].bctag);
703 free(vlant[vlan].bcuntag);
704 free(vlant[vlan].notlearning);
705 vlant[vlan].table=NULL;
706 vlant[vlan].bctag=NULL;
707 vlant[vlan].bcuntag=NULL;
708 vlant[vlan].notlearning=NULL;
709 #ifdef FSTP
710 fstremovevlan(vlan);
711 #endif
712 return 0;
714 } else
715 return ENXIO;
716 } else
717 return EINVAL;
720 static int vlanaddport(char *arg)
722 int port,vlan;
723 if (sscanf(arg,"%i %i",&vlan,&port) != 2)
724 return EINVAL;
725 if (vlan <0 || vlan >= NUMOFVLAN-1 || port < 0 || port >= numports)
726 return EINVAL;
727 if (!BAC_CHECK(validvlan,vlan) || portv[port] == NULL)
728 return ENXIO;
729 if (portv[port]->ep != NULL && portv[port]->vlanuntag != vlan) {
730 /* changing active port*/
731 BA_SET(vlant[vlan].bctag,port);
732 #ifdef FSTP
733 fstaddport(vlan,port,1);
734 #endif
736 BA_SET(vlant[vlan].table,port);
737 return 0;
740 static int vlandelport(char *arg)
742 int port,vlan;
743 if (sscanf(arg,"%i %i",&vlan,&port) != 2)
744 return EINVAL;
745 if (vlan <0 || vlan >= NUMOFVLAN-1 || port < 0 || port >= numports)
746 return EINVAL;
747 if (!BAC_CHECK(validvlan,vlan) || portv[port] == NULL)
748 return ENXIO;
749 if (portv[port]->vlanuntag == vlan)
750 return EADDRINUSE;
751 if (portv[port]->ep != NULL) {
752 /*changing active port*/
753 BA_CLR(vlant[vlan].bctag,port);
754 #ifdef FSTP
755 fstdelport(vlan,port);
756 #endif
758 BA_CLR(vlant[vlan].table,port);
759 hash_delete_port(port);
760 return 0;
763 #define STRSTATUS(PN,V) \
764 ((BA_CHECK(vlant[(V)].notlearning,(PN))) ? "Discarding" : \
765 (BA_CHECK(vlant[(V)].bctag,(PN)) || BA_CHECK(vlant[(V)].bcuntag,(PN))) ? \
766 "Forwarding" : "Learning")
768 static void vlanprintactive(int vlan,int fd)
770 register int i;
771 printoutc(fd,"VLAN %04d",vlan);
772 #ifdef FSTP
773 if (pflag & FSTP_TAG) {
774 #if 0
775 printoutc(fd," ++ FST root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n"
776 " designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x port %d cost %d age %d",
777 fsttab[vlan]->root[0], fsttab[vlan]->root[1], fsttab[vlan]->root[2], fsttab[vlan]->root[3],
778 fsttab[vlan]->root[4], fsttab[vlan]->root[5], fsttab[vlan]->root[6], fsttab[vlan]->root[7],
779 fsttab[vlan]->desbr[0], fsttab[vlan]->desbr[1], fsttab[vlan]->desbr[2], fsttab[vlan]->desbr[3],
780 fsttab[vlan]->desbr[4], fsttab[vlan]->desbr[5], fsttab[vlan]->desbr[6], fsttab[vlan]->desbr[7],
781 fsttab[vlan]->rootport,
782 ntohl(*(u_int32_t *)(&(fsttab[vlan]->rootcost))),
783 qtime()-fsttab[vlan]->roottimestamp);
784 BA_FORALL(vlant[vlan].table,numports,
785 ({ int tagged=portv[i]->vlanuntag != vlan;
786 if (portv[i]->ep)
787 printoutc(fd," -- Port %04d tagged=%d act=%d learn=%d forw=%d cost=%d role=%s",
788 i, tagged, 1, !(NOTLEARNING(i,vlan)),
789 (tagged)?(BA_CHECK(vlant[vlan].bctag,i) != 0):(BA_CHECK(vlant[vlan].bcuntag,i) != 0),
790 portv[i]->cost,
791 (fsttab[vlan]->rootport==i?"Root":
792 ((BA_CHECK(fsttab[vlan]->backup,i)?"Alternate/Backup":"Designated")))
793 ); 0;
794 }) ,i);
795 #endif
796 } else {
797 #endif
798 BA_FORALL(vlant[vlan].table,numports,
799 ({ int tagged=portv[i]->vlanuntag != vlan;
800 if (portv[i]->ep)
801 printoutc(fd," -- Port %04d tagged=%d active=1 status=%s", i, tagged,
802 STRSTATUS(i,vlan));
803 }), i);
804 #ifdef FSTP
806 #endif
809 static int vlanprint(int fd,char *arg)
811 if (*arg != 0) {
812 register int vlan;
813 vlan=atoi(arg);
814 if (vlan >= 0 && vlan < NUMOFVLAN-1) {
815 if (BAC_CHECK(validvlan,vlan))
816 vlanprintactive(vlan,fd);
817 else
818 return ENXIO;
819 } else
820 return EINVAL;
821 } else
822 BAC_FORALLFUN(validvlan,NUMOFVLAN,vlanprintactive,fd);
823 return 0;
826 static void vlanprintelem(int vlan,int fd)
828 register int i;
829 printoutc(fd,"VLAN %04d",vlan);
830 BA_FORALL(vlant[vlan].table,numports,
831 printoutc(fd," -- Port %04d tagged=%d active=%d status=%s",
832 i, portv[i]->vlanuntag != vlan, portv[i]->ep != NULL, STRSTATUS(i,vlan)),i);
835 static int vlanprintall(int fd,char *arg)
837 if (*arg != 0) {
838 register int vlan;
839 vlan=atoi(arg);
840 if (vlan > 0 && vlan < NUMOFVLAN-1) {
841 if (BAC_CHECK(validvlan,vlan))
842 vlanprintelem(vlan,fd);
843 else
844 return ENXIO;
845 } else
846 return EINVAL;
847 } else
848 BAC_FORALLFUN(validvlan,NUMOFVLAN,vlanprintelem,fd);
849 return 0;
852 /* NOT sure about the effects of changing address on FSTP */
854 #if 0
855 static int setmacaddr(char *strmac)
857 int maci[ETH_ALEN],rv;
859 if (index(strmac,':') != NULL)
860 rv=sscanf(strmac,"%x:%x:%x:%x:%x:%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
861 else
862 rv=sscanf(strmac,"%x.%x.%x.%x.%x.%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
863 if (rv < 6)
864 return EINVAL;
865 else {
866 register int i;
867 for (i=0;i<ETH_ALEN;i++)
868 switchmac[i]=maci[i];
869 return 0;
872 #endif
875 static struct comlist cl[]={
876 {"port","============","PORT STATUS MENU",NULL,NOARG},
877 {"port/showinfo","","show hash info",showinfo,NOARG|WITHFD},
878 {"port/setnumports","N","set the number of ports",portsetnumports,INTARG},
879 /*{"port/setmacaddr","MAC","set the switch MAC address",setmacaddr,STRARG},*/
880 {"port/sethub","0/1","1=HUB 0=switch",portsethub,INTARG},
881 {"port/setvlan","N VLAN","set port VLAN (untagged)",portsetvlan,STRARG},
882 {"port/create","N","create the port N (inactive)",portcreate,INTARG},
883 {"port/remove","N","remove the port N",portremove,INTARG},
884 {"port/allocatable","N 0/1","Is the port allocatable as unnamed? 1=Y 0=N",portallocatable,STRARG},
885 {"port/epclose","N ID","remove the endpoint port N/id ID",epclose,STRARG},
886 {"port/print","[N]","print the port/endpoint table",print_ptable,STRARG|WITHFD},
887 {"port/allprint","[N]","print the port/endpoint table (including inactive port)",print_ptableall,STRARG|WITHFD},
888 {"vlan","============","VLAN MANAGEMENT MENU",NULL,NOARG},
889 {"vlan/create","N","create the VLAN with tag N",vlancreate,INTARG},
890 {"vlan/remove","N","remove the VLAN with tag N",vlanremove,INTARG},
891 {"vlan/addport","N PORT","add port to the vlan N (tagged)",vlanaddport,STRARG},
892 {"vlan/delport","N PORT","add port to the vlan N (tagged)",vlandelport,STRARG},
893 {"vlan/print","[N]","print the list of defined vlan",vlanprint,STRARG|WITHFD},
894 {"vlan/allprint","[N]","print the list of defined vlan (including inactive port)",vlanprintall,STRARG|WITHFD},
897 void port_init(int initnumports)
899 if((numports=initnumports) <= 0) {
900 printlog(LOG_ERR,"The switch must have at least 1 port\n");
901 exit(1);
903 portv=calloc(numports,sizeof(struct port *));
904 /* vlan_init */
905 validvlan=BAC_ALLOC(NUMOFVLAN);
906 if (portv==NULL || validvlan == NULL) {
907 printlog(LOG_ERR,"ALLOC port data structures");
908 exit(1);
910 if (vlancreate_nocheck(0) != 0) {
911 printlog(LOG_ERR,"ALLOC vlan port data structures");
912 exit(1);
914 ADDCL(cl);