1 /* Copyright 2005 Renzo Davoli VDE-2
2 * 2008 Luca Saiu (Marionnet project): a better hub implementation
3 * Some minor remain from uml_switch Copyright 2002 Yon Uriarte and Jeff Dike
4 * Licensed under the GPLv2
13 #include <sys/socket.h>
15 #include <netinet/in.h> /*ntoh conversion*/
16 #include <sys/types.h>
23 #include <vdecommon.h>
39 static int stdqlen
=128;
42 static struct port
**portv
;
45 #define DBGPORTNEW (dl)
46 #define DBGPORTDEL (dl+1)
47 #define DBGPORTDESCR (dl+2)
48 #define DBGEPNEW (dl+3)
49 #define DBGEPDEL (dl+4)
50 #define PKTFILTIN (dl+5)
51 #define PKTFILTOUT (dl+6)
52 static struct dbgcl dl
[]= {
53 {"port/+","new port",D_PORT
|D_PLUS
},
54 {"port/-","closed port",D_PORT
|D_MINUS
},
55 {"port/descr","set port description",D_PORT
|D_DESCR
},
56 {"port/ep/+","new endpoint",D_EP
|D_PLUS
},
57 {"port/ep/-","closed endpoint",D_EP
|D_MINUS
},
58 {"packet/in",NULL
,D_PACKET
|D_IN
},
59 {"packet/out",NULL
,D_PACKET
|D_OUT
},
63 // for dedugging if needed
66 void packet_dump (struct packet *p)
69 printf ("packet dump dst");
70 for (i=0;i<ETH_ALEN;i++)
71 printf(":%02x",p->header.dest[i]);
73 for (i=0;i<ETH_ALEN;i++)
74 printf(":%02x",p->header.src[i]);
77 printf(":%02x",p->header.proto[i]);
91 struct endpoint
*next
;
94 #define NOTINPOOL 0x8000
99 /* sender is already inside ms, but it needs one more memaccess */
100 int (*sender
)(int fd_ctl
, int fd_data
, void *packet
, int len
, int port
);
101 struct mod_support
*ms
;
110 long long pktsin
,pktsout
,bytesin
,bytesout
;
115 * table the vlan table (also for inactive ports)
116 * vlan bctag is the vlan table -- only tagged forwarding ports mapping
117 * vlan bcuntag is the vlan table -- only untagged forwarding ports mapping
118 * validvlan is the table of valid vlans
125 bitarray notlearning
;
126 } vlant
[NUMOFVLAN
+1];
129 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
132 static int alloc_port(unsigned int portno
)
137 for (i
=1;i
<numports
&& portv
[i
] != NULL
&&
138 (portv
[i
]->ep
!= NULL
|| portv
[i
]->flag
& NOTINPOOL
) ;i
++)
140 } else if (i
<0) /* special case MGMT client port */
145 if (portv
[i
] == NULL
) {
147 if ((port
= malloc(sizeof(struct port
))) == NULL
){
148 printlog(LOG_WARNING
,"malloc port %s",strerror(errno
));
152 DBGOUT(DBGPORTNEW
,"%02d", i
);
153 EVENTOUT(DBGPORTNEW
,i
);
157 port
->user
=port
->group
=port
->curuser
=-1;
159 port
->cost
=DEFAULT_COST
;
170 ba_set(vlant
[0].table
,i
);
177 static void free_port(unsigned int portno
)
179 if (portno
< numports
) {
180 struct port
*port
=portv
[portno
];
181 if (port
!= NULL
&& port
->ep
==NULL
) {
184 /* delete completely the port. all vlan defs zapped */
185 bac_FORALL(validvlan
,NUMOFVLAN
,ba_clr(vlant
[i
].table
,portno
),i
);
191 /* 1 if user belongs to the group, 0 otherwise) */
192 static int user_belongs_to_group(uid_t uid
, gid_t gid
)
194 struct passwd
*pw
=getpwuid(uid
);
203 while ((grp
= getgrent())) {
204 if (grp
->gr_gid
== gid
) {
206 for (i
= 0; grp
->gr_mem
[i
]; i
++) {
207 if (strcmp(grp
->gr_mem
[i
], pw
->pw_name
)==0) {
221 /* Access Control check:
222 returns 0->OK -1->Permission Denied */
223 static int checkport_ac(struct port
*port
, uid_t user
)
226 if (port
->user
== -1 && port
->group
== -1)
228 /*root or restricted to a specific user*/
229 else if (user
==0 || (port
->user
!= -1 && port
->user
==user
))
231 /*restricted to a group*/
232 else if (port
->group
!= -1 && user_belongs_to_group(user
,port
->group
))
240 /* initialize a new endpoint */
241 struct endpoint
*setup_ep(int portno
, int fd_ctl
, int fd_data
, uid_t user
,
242 struct mod_support
*modfun
)
247 if ((portno
= alloc_port(portno
)) >= 0) {
249 if (port
->ep
== NULL
&& checkport_ac(port
,user
)==0)
251 if (port
->curuser
== user
&&
252 (ep
=malloc(sizeof(struct endpoint
))) != NULL
) {
253 DBGOUT(DBGEPNEW
,"Port %02d FD %2d", portno
,fd_ctl
);
254 EVENTOUT(DBGEPNEW
,portno
,fd_ctl
);
256 port
->sender
=modfun
->sender
;
264 ep
->vdepq_max
=stdqlen
;
266 if(port
->ep
== NULL
) {/* WAS INACTIVE */
268 /* copy all the vlan defs to the active vlan defs */
271 bac_FORALL(validvlan
,NUMOFVLAN
,
272 ({if (ba_check(vlant
[i
].table
,portno
)) {
273 ba_set(vlant
[i
].bctag
,portno
);
275 fstaddport(i
,portno
,(i
!=port
->vlanuntag
));
279 if (port
->vlanuntag
!= NOVLAN
) {
280 ba_set(vlant
[port
->vlanuntag
].bcuntag
,portno
);
281 ba_clr(vlant
[port
->vlanuntag
].bctag
,portno
);
283 ba_clr(vlant
[port
->vlanuntag
].notlearning
,portno
);
291 if (port
->curuser
!= user
)
304 int ep_get_port(struct endpoint
*ep
)
309 void setup_description(struct endpoint
*ep
, char *descr
)
311 DBGOUT(DBGPORTDESCR
,"Port %02d FD %2d -> \"%s\"",ep
->port
,ep
->fd_ctl
,descr
);
312 EVENTOUT(DBGPORTDESCR
,ep
->port
,ep
->fd_ctl
,descr
);
316 static int rec_close_ep(struct endpoint
**pep
, int fd_ctl
)
318 struct endpoint
*this=*pep
;
320 if (this->fd_ctl
==fd_ctl
) {
321 DBGOUT(DBGEPDEL
,"Port %02d FD %2d",this->port
,fd_ctl
);
322 EVENTOUT(DBGEPDEL
,this->port
,fd_ctl
);
325 vdepq_del(&(this->vdepq
));
327 if (portv
[this->port
]->ms
->delep
)
328 portv
[this->port
]->ms
->delep(this->fd_ctl
,this->fd_data
,this->descr
);
332 return rec_close_ep(&(this->next
),fd_ctl
);
337 static int close_ep_port_fd(int portno
, int fd_ctl
)
339 if (portno
>=0 && portno
< numports
) {
340 struct port
*port
=portv
[portno
];
342 int rv
=rec_close_ep(&(port
->ep
),fd_ctl
);
343 if (port
->ep
== NULL
) {
344 DBGOUT(DBGPORTDEL
,"%02d",portno
);
345 EVENTOUT(DBGPORTDEL
,portno
);
346 hash_delete_port(portno
);
351 /* inactivate port: all active vlan defs cleared */
352 bac_FORALL(validvlan
,NUMOFVLAN
,({
353 ba_clr(vlant
[i
].bctag
,portno
);
355 fstdelport(i
,portno
);
358 if (port
->vlanuntag
< NOVLAN
) ba_clr(vlant
[port
->vlanuntag
].bcuntag
,portno
);
367 int close_ep(struct endpoint
*ep
)
369 return close_ep_port_fd(ep
->port
, ep
->fd_ctl
);
373 static int rec_setqlen_ep(struct endpoint
*ep
, int fd_ctl
, int len
)
375 struct endpoint
*this=ep
;
377 if (this->fd_ctl
==fd_ctl
) {
381 return rec_setqlen_ep(this->next
, fd_ctl
, len
);
386 static int setqlen_ep_port_fd(int portno
, int fd_ctl
, int len
)
388 if (portno
>=0 && portno
< numports
) {
389 struct port
*port
=portv
[portno
];
391 return rec_setqlen_ep(port
->ep
, fd_ctl
, len
);
400 int portflag(int op
,int f
)
404 case P_GETFLAG
: oldflag
= pflag
& f
; break;
405 case P_SETFLAG
: pflag
=f
; break;
406 case P_ADDFLAG
: pflag
|= f
; break;
407 case P_CLRFLAG
: pflag
&= ~f
; break;
413 /*********************** sending macro used by Core ******************/
415 /* VDBG counter: count[port].spacket++; count[port].sbytes+=len */
417 #define SEND_COUNTER_UPD(Port,LEN) ({Port->pktsout++; Port->bytesout +=len;})
419 #define SEND_COUNTER_UPD(Port,LEN)
423 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN) \
425 struct port *Port=(PORT); \
426 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
427 struct endpoint *ep; \
428 SEND_COUNTER_UPD(Port,LEN); \
429 for (ep=Port->ep; ep != NULL; ep=ep->next) \
430 Port->ms->sender(ep->fd_ctl, ep->fd_data, (PACKET), (LEN), ep->port); \
434 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN,TMPBUF) \
436 struct port *Port=(PORT); \
437 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
438 struct endpoint *ep; \
439 SEND_COUNTER_UPD(Port,LEN); \
440 for (ep=Port->ep; ep != NULL; ep=ep->next) \
441 if (ep->vdepq_count || \
442 Port->ms->sender(ep->fd_ctl, ep->fd_data, (PACKET), (LEN), ep->port) == -EWOULDBLOCK) {\
443 if (ep->vdepq_count < ep->vdepq_max) \
444 ep->vdepq_count += vdepq_add(&(ep->vdepq), (PACKET), (LEN), TMPBUF); \
445 if (ep->vdepq_count == 1) mainloop_pollmask_add(ep->fd_data, POLLOUT);\
453 /* functions for FSTP */
454 void port_send_packet(int portno
, void *packet
, int len
)
457 SEND_PACKET_PORT(portv
[portno
],portno
,packet
,len
);
460 SEND_PACKET_PORT(portv
[portno
],portno
,packet
,len
,&tmpbuf
);
464 void portset_send_packet(bitarray portset
, void *packet
, int len
)
468 ba_FORALL(portset
,numports
,
469 SEND_PACKET_PORT(portv
[i
],i
,packet
,len
), i
);
472 ba_FORALL(portset
,numports
,
473 SEND_PACKET_PORT(portv
[i
],i
,packet
,len
,&tmpbuf
), i
);
478 void port_set_status(int portno
, int vlan
, int status
)
480 if (ba_check(vlant
[vlan
].table
,portno
)) {
481 if (status
==DISCARDING
) {
482 ba_set(vlant
[vlan
].notlearning
,portno
);
483 ba_clr(vlant
[vlan
].bctag
,portno
);
484 ba_clr(vlant
[vlan
].bcuntag
,portno
);
485 } else if (status
==LEARNING
) {
486 ba_clr(vlant
[vlan
].notlearning
,portno
);
487 ba_clr(vlant
[vlan
].bctag
,portno
);
488 ba_clr(vlant
[vlan
].bcuntag
,portno
);
489 } else { /*forwarding*/
490 ba_clr(vlant
[vlan
].notlearning
,portno
);
491 if (portv
[portno
]->vlanuntag
== vlan
)
492 ba_set(vlant
[vlan
].bcuntag
,portno
);
494 ba_set(vlant
[vlan
].bctag
,portno
);
499 int port_get_status(int portno
, int vlan
)
501 if (ba_check(vlant
[vlan
].notlearning
,portno
))
504 if (ba_check(vlant
[vlan
].bctag
,portno
) ||
505 ba_check(vlant
[vlan
].bcuntag
,portno
))
512 int port_getcost(int port
)
514 return portv
[port
]->cost
;
518 /************************************ CORE PACKET MGMT *****************************/
521 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
522 * | Destination | Source |81 00|pvlan| L/T | data
523 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
525 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
526 * | Destination | Source | L/T | data
527 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
529 * Destination/Source: 4 byte right shift
531 * Pointer to the packet: +4 bytes
534 #define TAG2UNTAG(P,LEN) \
535 ({ memmove((char *)(P)+4,(P),2*ETH_ALEN); LEN -= 4 ; \
536 (struct packet *)((char *)(P)+4); })
539 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
540 * | Destination | Source | L/T | data
541 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
543 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
544 * | Destination | Source |81 00|pvlan| L/T | data
545 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
546 * Destination/Source: 4 byte left shift
548 * Pointer to the packet: +4 bytes
549 * The space has been allocated in advance (just in case); all the modules
550 * read data into a bipacket.
553 #define UNTAG2TAG(P,VLAN,LEN) \
554 ({ memmove((char *)(P)-4,(P),2*ETH_ALEN); LEN += 4 ; \
555 (P)->header.src[2]=0x81; (P)->header.src[3]=0x00;\
556 (P)->header.src[4]=(VLAN >> 8); (P)->header.src[5]=(VLAN);\
557 (struct packet *)((char *)(P)-4); })
561 static int trysendfun(struct endpoint
*ep
, void *packet
, int len
)
564 return portv
[port
]->ms
->sender(ep
->fd_ctl
, ep
->fd_data
, packet
, len
, port
);
567 void handle_out_packet(struct endpoint
*ep
)
569 //printf("handle_out_packet %d\n",ep->vdepq_count);
570 ep
->vdepq_count
-= vdepq_try(&(ep
->vdepq
),ep
,trysendfun
);
571 if (ep
->vdepq_count
== 0)
572 mainloop_pollmask_del(ep
->fd_data
, POLLOUT
);
576 void handle_in_packet(struct endpoint
*ep
, struct packet
*packet
, int len
)
582 if(PACKETFILTER(PKTFILTIN
,port
,packet
,len
)) {
585 portv
[port
]->pktsin
++;
586 portv
[port
]->bytesin
+=len
;
588 if (pflag
& HUB_TAG
) { /* this is a HUB */
591 for(i
= 1; i
< numports
; i
++)
592 if((i
!= port
) && (portv
[i
] != NULL
))
593 SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);
596 for(i
= 1; i
< numports
; i
++)
597 if((i
!= port
) && (portv
[i
] != NULL
))
598 SEND_PACKET_PORT(portv
[i
],i
,packet
,len
,&tmpbuf
);
600 } else { /* This is a switch, not a HUB! */
601 if (packet
->header
.proto
[0] == 0x81 && packet
->header
.proto
[1] == 0x00) {
603 vlan
=((packet
->data
[0] << 8) + packet
->data
[1]) & 0xfff;
604 if (! ba_check(vlant
[vlan
].table
,port
))
605 return; /*discard unwanted packets*/
608 if ((vlan
=portv
[port
]->vlanuntag
) == NOVLAN
)
609 return; /*discard unwanted packets*/
613 /* when it works as a HUB or FSTP is off, MST packet must be forwarded */
614 if (ISBPDU(packet
) && fstflag(P_GETFLAG
, FSTP_TAG
)) {
615 fst_in_bpdu(port
,packet
,len
,vlan
,tagged
);
616 return; /* BPDU packets are not forwarded */
619 /* The port is in blocked status, no packet received */
620 if (ba_check(vlant
[vlan
].notlearning
,port
)) return;
622 /* We don't like broadcast source addresses */
623 if(! (IS_BROADCAST(packet
->header
.src
))) {
625 int last
= find_in_hash_update(packet
->header
.src
,vlan
,port
);
626 /* old value differs from actual input port */
627 if(last
>=0 && (port
!= last
)){
628 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
);
631 /* static void send_dst(int port,struct packet *packet, int len) */
632 if(IS_BROADCAST(packet
->header
.dest
) ||
633 (tarport
= find_in_hash(packet
->header
.dest
,vlan
)) < 0 ){
634 /* FST HERE! broadcast only on active ports*/
635 /* no cache or broadcast/multicast == all ports *except* the source port! */
636 /* BROADCAST: tag/untag. Broadcast the packet untouched on the ports
637 * of the same tag-ness, then transform it to the other tag-ness for the others*/
641 ba_FORALL(vlant
[vlan
].bctag
,numports
,
642 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
643 packet
=TAG2UNTAG(packet
,len
);
644 ba_FORALL(vlant
[vlan
].bcuntag
,numports
,
645 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
649 ba_FORALL(vlant
[vlan
].bctag
,numports
,
650 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
,&tmpbuft
);}),i
);
651 packet
=TAG2UNTAG(packet
,len
);
652 ba_FORALL(vlant
[vlan
].bcuntag
,numports
,
653 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
,&tmpbufu
);}),i
);
655 } else { /* untagged */
658 ba_FORALL(vlant
[vlan
].bcuntag
,numports
,
659 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
660 packet
=UNTAG2TAG(packet
,vlan
,len
);
661 ba_FORALL(vlant
[vlan
].bctag
,numports
,
662 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
666 ba_FORALL(vlant
[vlan
].bcuntag
,numports
,
667 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
,&tmpbufu
);}),i
);
668 packet
=UNTAG2TAG(packet
,vlan
,len
);
669 ba_FORALL(vlant
[vlan
].bctag
,numports
,
670 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
,&tmpbuft
);}),i
);
675 /* the hash table should not generate tarport not in vlan
676 * any time a port is removed from a vlan, the port is flushed from the hash */
678 return; /*do not loop!*/
681 if (portv
[tarport
]->vlanuntag
==vlan
) { /* TAG->UNTAG */
682 packet
= TAG2UNTAG(packet
,len
);
683 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
684 } else { /* TAG->TAG */
685 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
688 if (portv
[tarport
]->vlanuntag
==vlan
) { /* UNTAG->UNTAG */
689 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
690 } else { /* UNTAG->TAG */
691 packet
= UNTAG2TAG(packet
,vlan
,len
);
692 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
698 if (portv
[tarport
]->vlanuntag
==vlan
) { /* TAG->UNTAG */
699 packet
= TAG2UNTAG(packet
,len
);
700 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
,&tmpbuf
);
701 } else { /* TAG->TAG */
702 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
,&tmpbuf
);
706 if (portv
[tarport
]->vlanuntag
==vlan
) { /* UNTAG->UNTAG */
707 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
,&tmpbuf
);
708 } else { /* UNTAG->TAG */
709 packet
= UNTAG2TAG(packet
,vlan
,len
);
710 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
,&tmpbuf
);
714 } /* if(BROADCAST) */
716 } /* if(PACKETFILTER) */
719 /**************************************** COMMAND MANAGEMENT ****************************************/
721 static int showinfo(FILE *fd
)
723 printoutc(fd
,"Numports=%d",numports
);
724 printoutc(fd
,"HUB=%s",(pflag
& HUB_TAG
)?"true":"false");
726 printoutc(fd
,"counters=true");
728 printoutc(fd
,"counters=false");
731 printoutc(fd
,"default length of port packet queues: %d",stdqlen
);
736 static int portsetnumports(int val
)
741 for(i
=val
;i
<numports
;i
++)
744 portv
=realloc(portv
,val
*sizeof(struct port
*));
746 printlog(LOG_ERR
,"Numport resize failed portv %s",strerror(errno
));
749 for (i
=0;i
<NUMOFVLAN
;i
++) {
750 if (vlant
[i
].table
) {
751 vlant
[i
].table
=ba_realloc(vlant
[i
].table
,numports
,val
);
752 if (vlant
[i
].table
== NULL
) {
753 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan table %s",strerror(errno
));
757 if (vlant
[i
].bctag
) {
758 vlant
[i
].bctag
=ba_realloc(vlant
[i
].bctag
,numports
,val
);
759 if (vlant
[i
].bctag
== NULL
) {
760 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan bctag %s",strerror(errno
));
764 if (vlant
[i
].bcuntag
) {
765 vlant
[i
].bcuntag
=ba_realloc(vlant
[i
].bcuntag
,numports
,val
);
766 if (vlant
[i
].bcuntag
== NULL
) {
767 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan bctag %s",strerror(errno
));
771 if (vlant
[i
].notlearning
) {
772 vlant
[i
].notlearning
=ba_realloc(vlant
[i
].notlearning
,numports
,val
);
773 if (vlant
[i
].notlearning
== NULL
) {
774 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan notlearning %s",strerror(errno
));
779 for (i
=numports
;i
<val
;i
++)
790 static int portallocatable(char *arg
)
793 if (sscanf(arg
,"%i %i",&port
,&value
) != 2)
795 if (port
< 0 || port
>= numports
)
797 if (portv
[port
] == NULL
)
800 portv
[port
]->flag
&= ~NOTINPOOL
;
802 portv
[port
]->flag
|= NOTINPOOL
;
806 static int portsetuser(char *arg
)
811 while (*portuid
!= 0 && *portuid
== ' ') portuid
++;
812 while (*portuid
!= 0 && *portuid
!= ' ') portuid
++;
813 while (*portuid
!= 0 && *portuid
== ' ') portuid
++;
814 if (sscanf(arg
,"%i",&port
) != 1 || *portuid
==0)
816 if (port
< 0 || port
>= numports
)
818 if (portv
[port
] == NULL
)
820 if ((pw
=getpwnam(portuid
)) != NULL
)
821 portv
[port
]->user
=pw
->pw_uid
;
822 else if (isdigit(*portuid
))
823 portv
[port
]->user
=atoi(portuid
);
824 else if (strcmp(portuid
,"NONE")==0 || strcmp(portuid
,"ANY")==0)
825 portv
[port
]->user
= -1;
831 static int portsetgroup(char *arg
)
836 while (*portgid
!= 0 && *portgid
== ' ') portgid
++;
837 while (*portgid
!= 0 && *portgid
!= ' ') portgid
++;
838 while (*portgid
!= 0 && *portgid
== ' ') portgid
++;
839 if (sscanf(arg
,"%i",&port
) != 1 || *portgid
==0)
841 if (port
< 0 || port
>= numports
)
843 if (portv
[port
] == NULL
)
845 if ((gr
=getgrnam(portgid
)) != NULL
)
846 portv
[port
]->group
=gr
->gr_gid
;
847 else if (isdigit(*portgid
))
848 portv
[port
]->group
=atoi(portgid
);
849 else if (strcmp(portgid
,"NONE")==0 || strcmp(portgid
,"ANY")==0)
850 portv
[port
]->group
= -1;
856 static int portremove(int val
)
858 if (val
<0 || val
>=numports
)
860 if (portv
[val
] == NULL
)
862 if (portv
[val
]->ep
!= NULL
)
868 static int portcreate(int val
)
871 if (val
<0 || val
>=numports
)
873 if (portv
[val
] != NULL
)
875 port
=alloc_port(val
);
878 portv
[port
]->flag
|= NOTINPOOL
;
882 static int portcreateauto(FILE* fd
)
884 int port
= alloc_port(0);
889 portv
[port
]->flag
|= NOTINPOOL
;
890 printoutc(fd
, "Port %04d", port
);
894 static int epclose(char *arg
)
897 if (sscanf(arg
,"%i %i",&port
,&id
) != 2)
900 return close_ep_port_fd(port
,id
);
904 static int defqlen(int len
)
914 static int epqlen(char *arg
)
917 if (sscanf(arg
,"%i %i %i",&port
,&id
,&len
) != 3 || len
< 0)
920 return setqlen_ep_port_fd(port
,id
,len
);
924 static char *port_getuser(uid_t uid
)
935 sprintf(buf
,"%d",uid
);
941 static char *port_getgroup(gid_t gid
)
952 sprintf(buf
,"%d",gid
);
958 static int print_port(FILE *fd
,int i
,int inclinactive
)
961 if (portv
[i
] != NULL
&& (inclinactive
|| portv
[i
]->ep
!=NULL
)) {
962 printoutc(fd
,"Port %04d untagged_vlan=%04d %sACTIVE - %sUnnamed Allocatable",
963 i
,portv
[i
]->vlanuntag
,
964 portv
[i
]->ep
?"":"IN",
965 (portv
[i
]->flag
& NOTINPOOL
)?"NOT ":"");
966 printoutc(fd
," Current User: %s Access Control: (User: %s - Group: %s)",
967 port_getuser(portv
[i
]->curuser
),
968 port_getuser(portv
[i
]->user
),
969 port_getgroup(portv
[i
]->group
));
971 printoutc(fd
," IN: pkts %10lld bytes %20lld",portv
[i
]->pktsin
,portv
[i
]->bytesin
);
972 printoutc(fd
," OUT: pkts %10lld bytes %20lld",portv
[i
]->pktsout
,portv
[i
]->bytesout
);
974 for (ep
=portv
[i
]->ep
; ep
!= NULL
; ep
=ep
->next
) {
975 printoutc(fd
," -- endpoint ID %04d module %-12s: %s",ep
->fd_ctl
,
976 portv
[i
]->ms
->modname
,(ep
->descr
)?ep
->descr
:"no endpoint description");
978 printoutc(fd
," unsent packets: %d max %d",ep
->vdepq_count
,ep
->vdepq_max
);
986 static int print_ptable(FILE *fd
,char *arg
)
991 if (i
<0 || i
>=numports
)
994 return print_port(fd
,i
,0);
997 for (i
=0;i
<numports
;i
++)
1003 static int print_ptableall(FILE *fd
,char *arg
)
1008 if (i
<0 || i
>=numports
)
1011 return print_port(fd
,i
,1);
1014 for (i
=0;i
<numports
;i
++)
1021 static void portzerocounter(int i
)
1023 if (portv
[i
] != NULL
) {
1025 portv
[i
]->pktsout
=0;
1026 portv
[i
]->bytesin
=0;
1027 portv
[i
]->bytesout
=0;
1031 static int portresetcounters(char *arg
)
1036 if (i
<0 || i
>=numports
)
1043 for (i
=0;i
<numports
;i
++)
1050 static int portsethub(int val
)
1056 portflag(P_SETFLAG
,HUB_TAG
);
1058 portflag(P_CLRFLAG
,HUB_TAG
);
1062 static int portsetvlan(char *arg
)
1065 if (sscanf(arg
,"%i %i",&port
,&vlan
) != 2)
1067 /* port NOVLAN is okay here, it means NO untagged traffic */
1068 if (vlan
<0 || vlan
> NUMOFVLAN
|| port
< 0 || port
>= numports
)
1070 if ((vlan
!= NOVLAN
&& !bac_check(validvlan
,vlan
)) || portv
[port
] == NULL
)
1072 int oldvlan
=portv
[port
]->vlanuntag
;
1073 portv
[port
]->vlanuntag
=NOVLAN
;
1074 hash_delete_port(port
);
1075 if (portv
[port
]->ep
!= NULL
) {
1076 /*changing active port*/
1077 if (oldvlan
!= NOVLAN
)
1078 ba_clr(vlant
[oldvlan
].bcuntag
,port
);
1079 if (vlan
!= NOVLAN
) {
1080 ba_set(vlant
[vlan
].bcuntag
,port
);
1081 ba_clr(vlant
[vlan
].bctag
,port
);
1084 if (oldvlan
!= NOVLAN
) fstdelport(oldvlan
,port
);
1085 if (vlan
!= NOVLAN
) fstaddport(vlan
,port
,0);
1088 if (oldvlan
!= NOVLAN
) ba_clr(vlant
[oldvlan
].table
,port
);
1089 if (vlan
!= NOVLAN
) ba_set(vlant
[vlan
].table
,port
);
1090 portv
[port
]->vlanuntag
=vlan
;
1094 static int vlancreate_nocheck(int vlan
)
1097 vlant
[vlan
].table
=ba_alloc(numports
);
1098 vlant
[vlan
].bctag
=ba_alloc(numports
);
1099 vlant
[vlan
].bcuntag
=ba_alloc(numports
);
1100 vlant
[vlan
].notlearning
=ba_alloc(numports
);
1101 if (vlant
[vlan
].table
== NULL
|| vlant
[vlan
].bctag
== NULL
||
1102 vlant
[vlan
].bcuntag
== NULL
)
1106 rv
=fstnewvlan(vlan
);
1109 bac_set(validvlan
,NUMOFVLAN
,vlan
);
1115 static int vlancreate(int vlan
)
1117 if (vlan
> 0 && vlan
< NUMOFVLAN
-1) { /*vlan NOVLAN (0xfff a.k.a. 4095) is reserved */
1118 if (bac_check(validvlan
,vlan
))
1121 return vlancreate_nocheck(vlan
);
1126 static int vlanremove(int vlan
)
1128 if (vlan
>= 0 && vlan
< NUMOFVLAN
) {
1129 if (bac_check(validvlan
,vlan
)) {
1130 register int i
,used
=0;
1131 ba_FORALL(vlant
[vlan
].table
,numports
,used
++,i
);
1135 bac_clr(validvlan
,NUMOFVLAN
,vlan
);
1136 free(vlant
[vlan
].table
);
1137 free(vlant
[vlan
].bctag
);
1138 free(vlant
[vlan
].bcuntag
);
1139 free(vlant
[vlan
].notlearning
);
1140 vlant
[vlan
].table
=NULL
;
1141 vlant
[vlan
].bctag
=NULL
;
1142 vlant
[vlan
].bcuntag
=NULL
;
1143 vlant
[vlan
].notlearning
=NULL
;
1145 fstremovevlan(vlan
);
1155 static int vlanaddport(char *arg
)
1158 if (sscanf(arg
,"%i %i",&vlan
,&port
) != 2)
1160 if (vlan
<0 || vlan
>= NUMOFVLAN
-1 || port
< 0 || port
>= numports
)
1162 if (!bac_check(validvlan
,vlan
) || portv
[port
] == NULL
)
1164 if (portv
[port
]->ep
!= NULL
&& portv
[port
]->vlanuntag
!= vlan
) {
1165 /* changing active port*/
1166 ba_set(vlant
[vlan
].bctag
,port
);
1168 fstaddport(vlan
,port
,1);
1171 ba_set(vlant
[vlan
].table
,port
);
1175 static int vlandelport(char *arg
)
1178 if (sscanf(arg
,"%i %i",&vlan
,&port
) != 2)
1180 if (vlan
<0 || vlan
>= NUMOFVLAN
-1 || port
< 0 || port
>= numports
)
1182 if (!bac_check(validvlan
,vlan
) || portv
[port
] == NULL
)
1184 if (portv
[port
]->vlanuntag
== vlan
)
1186 if (portv
[port
]->ep
!= NULL
) {
1187 /*changing active port*/
1188 ba_clr(vlant
[vlan
].bctag
,port
);
1190 fstdelport(vlan
,port
);
1193 ba_clr(vlant
[vlan
].table
,port
);
1194 hash_delete_port(port
);
1198 #define STRSTATUS(PN,V) \
1199 ((ba_check(vlant[(V)].notlearning,(PN))) ? "Discarding" : \
1200 (ba_check(vlant[(V)].bctag,(PN)) || ba_check(vlant[(V)].bcuntag,(PN))) ? \
1201 "Forwarding" : "Learning")
1203 static void vlanprintactive(int vlan
,FILE *fd
)
1206 printoutc(fd
,"VLAN %04d",vlan
);
1208 if (pflag
& FSTP_TAG
) {
1210 printoutc(fd
," ++ FST root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n"
1211 " designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x port %d cost %d age %d",
1212 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
1213 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7],
1214 fsttab
[vlan
]->desbr
[0], fsttab
[vlan
]->desbr
[1], fsttab
[vlan
]->desbr
[2], fsttab
[vlan
]->desbr
[3],
1215 fsttab
[vlan
]->desbr
[4], fsttab
[vlan
]->desbr
[5], fsttab
[vlan
]->desbr
[6], fsttab
[vlan
]->desbr
[7],
1216 fsttab
[vlan
]->rootport
,
1217 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
1218 qtime()-fsttab
[vlan
]->roottimestamp
);
1219 ba_FORALL(vlant
[vlan
].table
,numports
,
1220 ({ int tagged
=portv
[i
]->vlanuntag
!= vlan
;
1222 printoutc(fd
," -- Port %04d tagged=%d act=%d learn=%d forw=%d cost=%d role=%s",
1223 i
, tagged
, 1, !(NOTLEARNING(i
,vlan
)),
1224 (tagged
)?(ba_check(vlant
[vlan
].bctag
,i
) != 0):(ba_check(vlant
[vlan
].bcuntag
,i
) != 0),
1226 (fsttab
[vlan
]->rootport
==i
?"Root":
1227 ((ba_check(fsttab
[vlan
]->backup
,i
)?"Alternate/Backup":"Designated")))
1233 ba_FORALL(vlant
[vlan
].table
,numports
,
1234 ({ int tagged
=portv
[i
]->vlanuntag
!= vlan
;
1236 printoutc(fd
," -- Port %04d tagged=%d active=1 status=%s", i
, tagged
,
1244 static int vlanprint(FILE *fd
,char *arg
)
1249 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
1250 if (bac_check(validvlan
,vlan
))
1251 vlanprintactive(vlan
,fd
);
1257 bac_FORALLFUN(validvlan
,NUMOFVLAN
,vlanprintactive
,fd
);
1261 static void vlanprintelem(int vlan
,FILE *fd
)
1264 printoutc(fd
,"VLAN %04d",vlan
);
1265 ba_FORALL(vlant
[vlan
].table
,numports
,
1266 printoutc(fd
," -- Port %04d tagged=%d active=%d status=%s",
1267 i
, portv
[i
]->vlanuntag
!= vlan
, portv
[i
]->ep
!= NULL
, STRSTATUS(i
,vlan
)),i
);
1270 static int vlanprintall(FILE *fd
,char *arg
)
1275 if (vlan
> 0 && vlan
< NUMOFVLAN
-1) {
1276 if (bac_check(validvlan
,vlan
))
1277 vlanprintelem(vlan
,fd
);
1283 bac_FORALLFUN(validvlan
,NUMOFVLAN
,vlanprintelem
,fd
);
1287 /* NOT sure about the effects of changing address on FSTP */
1290 static int setmacaddr(char *strmac
)
1292 int maci
[ETH_ALEN
],rv
;
1294 if (index(strmac
,':') != NULL
)
1295 rv
=sscanf(strmac
,"%x:%x:%x:%x:%x:%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
1297 rv
=sscanf(strmac
,"%x.%x.%x.%x.%x.%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
1302 for (i
=0;i
<ETH_ALEN
;i
++)
1303 switchmac
[i
]=maci
[i
];
1309 uid_t
port_user(int port
)
1311 if (port
<0 || port
>=numports
|| portv
[port
]==NULL
)
1314 return portv
[port
]->curuser
;
1317 char *port_descr(int portno
, int epn
) {
1318 if (portno
<0 || portno
>=numports
)
1321 struct port
*port
=portv
[portno
];
1325 struct endpoint
*ep
;
1326 for (ep
=port
->ep
;ep
!=NULL
&& epn
>0;ep
=ep
->next
,epn
--)
1336 static struct comlist cl
[]={
1337 {"port","============","PORT STATUS MENU",NULL
,NOARG
},
1338 {"port/showinfo","","show port info",showinfo
,NOARG
|WITHFILE
},
1339 {"port/setnumports","N","set the number of ports",portsetnumports
,INTARG
},
1340 /*{"port/setmacaddr","MAC","set the switch MAC address",setmacaddr,STRARG},*/
1341 {"port/sethub","0/1","1=HUB 0=switch",portsethub
,INTARG
},
1342 {"port/setvlan","N VLAN","set port VLAN (untagged)",portsetvlan
,STRARG
},
1343 {"port/createauto","","create a port with an automatically allocated id (inactive|notallocatable)",portcreateauto
,NOARG
|WITHFILE
},
1344 {"port/create","N","create the port N (inactive|notallocatable)",portcreate
,INTARG
},
1345 {"port/remove","N","remove the port N",portremove
,INTARG
},
1346 {"port/allocatable","N 0/1","Is the port allocatable as unnamed? 1=Y 0=N",portallocatable
,STRARG
},
1347 {"port/setuser","N user","access control: set user",portsetuser
,STRARG
},
1348 {"port/setgroup","N user","access control: set group",portsetgroup
,STRARG
},
1349 {"port/epclose","N ID","remove the endpoint port N/id ID",epclose
,STRARG
},
1351 {"port/defqlen","LEN","set the default queue length for new ports",defqlen
,INTARG
},
1352 {"port/epqlen","N ID LEN","set the lenth of the queue for port N/id IP",epqlen
,STRARG
},
1355 {"port/resetcounter","[N]","reset the port (N) counters",portresetcounters
,STRARG
},
1357 {"port/print","[N]","print the port/endpoint table",print_ptable
,STRARG
|WITHFILE
},
1358 {"port/allprint","[N]","print the port/endpoint table (including inactive port)",print_ptableall
,STRARG
|WITHFILE
},
1359 {"vlan","============","VLAN MANAGEMENT MENU",NULL
,NOARG
},
1360 {"vlan/create","N","create the VLAN with tag N",vlancreate
,INTARG
},
1361 {"vlan/remove","N","remove the VLAN with tag N",vlanremove
,INTARG
},
1362 {"vlan/addport","N PORT","add port to the vlan N (tagged)",vlanaddport
,STRARG
},
1363 {"vlan/delport","N PORT","add port to the vlan N (tagged)",vlandelport
,STRARG
},
1364 {"vlan/print","[N]","print the list of defined vlan",vlanprint
,STRARG
|WITHFILE
},
1365 {"vlan/allprint","[N]","print the list of defined vlan (including inactive port)",vlanprintall
,STRARG
|WITHFILE
},
1368 void port_init(int initnumports
)
1370 if((numports
=initnumports
) <= 0) {
1371 printlog(LOG_ERR
,"The switch must have at least 1 port\n");
1374 portv
=calloc(numports
,sizeof(struct port
*));
1376 validvlan
=bac_alloc(NUMOFVLAN
);
1377 if (portv
==NULL
|| validvlan
== NULL
) {
1378 printlog(LOG_ERR
,"ALLOC port data structures");
1385 if (vlancreate_nocheck(0) != 0) {
1386 printlog(LOG_ERR
,"ALLOC vlan port data structures");