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
13 #include <sys/socket.h>
16 #include <netinet/in.h> /*ntoh conversion*/
34 static struct port
**portv
;
37 #define DBGPORTNEW (dl)
38 #define DBGPORTDEL (dl+1)
39 #define DBGPORTDESCR (dl+2)
40 #define DBGEPNEW (dl+3)
41 #define DBGEPDEL (dl+4)
42 #define PKTFILTIN (dl+5)
43 #define PKTFILTOUT (dl+6)
44 static struct dbgcl dl
[]= {
45 {"port/+","new port",D_PORT
|D_PLUS
},
46 {"port/-","closed port",D_PORT
|D_MINUS
},
47 {"port/descr","set port description",D_PORT
|D_DESCR
},
48 {"port/ep/+","new endpoint",D_EP
|D_PLUS
},
49 {"port/ep/-","closed endpoint",D_EP
|D_MINUS
},
50 {"packet/in",NULL
,D_PACKET
|D_IN
},
51 {"packet/out",NULL
,D_PACKET
|D_OUT
},
55 // for dedugging if needed
58 void packet_dump (struct packet *p)
61 printf ("packet dump dst");
62 for (i=0;i<ETH_ALEN;i++)
63 printf(":%02x",p->header.dest[i]);
65 for (i=0;i<ETH_ALEN;i++)
66 printf(":%02x",p->header.src[i]);
69 printf(":%02x",p->header.proto[i]);
78 struct endpoint
*next
;
81 #define NOTINPOOL 0x8000
87 /* sender is already inside ep, but it needs one more memaccess */
88 int (*sender
)(int fd
, int fd_ctl
, void *packet
, int len
, void *data
, int port
);
89 struct mod_support
*ms
;
95 long long pktsin
,pktsout
,bytesin
,bytesout
;
100 * table the vlan table (also for inactive ports)
101 * vlan bctag is the vlan table -- only tagged forwarding ports mapping
102 * vlan bcuntag is the vlan table -- only untagged forwarding ports mapping
103 * validvlan is the table of valid vlans
110 bitarray notlearning
;
114 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
117 static int alloc_port(unsigned int portno
)
122 for (i
=1;i
<numports
&& portv
[i
] != NULL
&&
123 (portv
[i
]->ep
!= NULL
|| portv
[i
]->flag
& NOTINPOOL
) ;i
++)
125 } else if (i
<0) /* special case MGMT client port */
130 if (portv
[i
] == NULL
) {
132 if ((port
= malloc(sizeof(struct port
))) == NULL
){
133 printlog(LOG_WARNING
,"malloc port %s",strerror(errno
));
137 DBGOUT(DBGPORTNEW
,"%02d", i
);
138 EVENTOUT(DBGPORTNEW
,i
);
144 port
->cost
=DEFAULT_COST
;
155 BA_SET(vlant
[0].table
,i
);
162 static void free_port(unsigned int portno
)
164 if (portno
< numports
) {
165 struct port
*port
=portv
[portno
];
166 if (port
!= NULL
&& port
->ep
==NULL
) {
169 /* delete completely the port. all vlan defs zapped */
170 BAC_FORALL(validvlan
,NUMOFVLAN
,BA_CLR(vlant
[i
].table
,portno
),i
);
176 /* initialize a port structure with control=fd, given data+data_len and sender
178 * and then add it to the g_fdsdata array at index i. */
179 int setup_ep(int portno
, int fd_ctl
,
181 struct mod_support
*modfun
)
186 if ((portno
= alloc_port(portno
)) >= 0) {
188 if (port
->fd_data
< 0)
189 port
->fd_data
=modfun
->newport(fd_ctl
,portno
);
190 if (port
->fd_data
>= 0 &&
191 (ep
=malloc(sizeof(struct endpoint
))) != NULL
) {
192 DBGOUT(DBGEPNEW
,"Port %02d FD %2d", portno
,fd_ctl
);
193 EVENTOUT(DBGEPNEW
,portno
,fd_ctl
);
195 port
->sender
=modfun
->sender
;
200 if(port
->ep
== NULL
) {/* WAS INACTIVE */
202 /* copy all the vlan defs to the active vlan defs */
205 BAC_FORALL(validvlan
,NUMOFVLAN
,
206 ({if (BA_CHECK(vlant
[i
].table
,portno
)) {
207 BA_SET(vlant
[i
].bctag
,portno
);
209 fstaddport(i
,portno
,(i
!=port
->vlanuntag
));
213 if (port
->vlanuntag
!= NOVLAN
) {
214 BA_SET(vlant
[port
->vlanuntag
].bcuntag
,portno
);
215 BA_CLR(vlant
[port
->vlanuntag
].bctag
,portno
);
217 BA_CLR(vlant
[port
->vlanuntag
].notlearning
,portno
);
232 void setup_description(int portno
, int fd_ctl
, char *descr
)
234 if (portno
>=0 && portno
< numports
) {
235 struct port
*port
=portv
[portno
];
238 for (ep
=port
->ep
;ep
!=NULL
;ep
=ep
->next
)
239 if (ep
->fd_ctl
== fd_ctl
) {
240 DBGOUT(DBGPORTDESCR
,"Port %02d FD %2d -> \"%s\"",portno
,fd_ctl
,descr
);
241 EVENTOUT(DBGPORTDESCR
,portno
,fd_ctl
,descr
);
248 static int rec_close_ep(struct endpoint
**pep
, int fd_ctl
)
250 struct endpoint
*this=*pep
;
252 if (this->fd_ctl
==fd_ctl
) {
253 DBGOUT(DBGEPDEL
,"Port %02d FD %2d",this->port
,fd_ctl
);
254 EVENTOUT(DBGEPDEL
,this->port
,fd_ctl
);
256 if (portv
[this->port
]->ms
->delep
)
257 portv
[this->port
]->ms
->delep(this->fd_ctl
,this->data
,this->descr
);
261 return rec_close_ep(&(this->next
),fd_ctl
);
266 int close_ep(int portno
, int fd_ctl
)
268 if (portno
>=0 && portno
< numports
) {
269 struct port
*port
=portv
[portno
];
271 int rv
=rec_close_ep(&(port
->ep
),fd_ctl
);
272 if (port
->ep
== NULL
) {
273 DBGOUT(DBGPORTDEL
,"%02d",portno
);
274 EVENTOUT(DBGPORTDEL
,portno
);
275 hash_delete_port(portno
);
277 packetq_delfd(port
->fd_data
);
279 if (portv
[portno
]->ms
->delport
)
280 portv
[portno
]->ms
->delport(port
->fd_data
,portno
);
285 /* inactivate port: all active vlan defs cleared */
286 BAC_FORALL(validvlan
,NUMOFVLAN
,({
287 BA_CLR(vlant
[i
].bctag
,portno
);
289 fstdelport(i
,portno
);
292 if (port
->vlanuntag
< NOVLAN
) BA_CLR(vlant
[port
->vlanuntag
].bcuntag
,portno
);
301 int portflag(int op
,int f
)
305 case P_SETFLAG
: pflag
=f
; break;
306 case P_ADDFLAG
: pflag
|= f
; break;
307 case P_CLRFLAG
: pflag
&= ~f
; break;
313 /*********************** sending macro used by Core ******************/
315 /* VDBG counter: count[port].spacket++; count[port].sbytes+=len */
317 #define SEND_COUNTER_UPD(Port,LEN) ({Port->pktsout++; Port->bytesout +=len;})
319 #define SEND_COUNTER_UPD(Port,LEN)
323 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN) \
325 struct port *Port=(PORT); \
326 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
327 struct endpoint *ep; \
328 SEND_COUNTER_UPD(Port,LEN); \
329 for (ep=Port->ep; ep != NULL; ep=ep->next) \
330 if (Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port)) \
331 packetq_add(Port->ms->sender,Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
335 #define SEND_PACKET_PORT(PORT,PORTNO,PACKET,LEN) \
337 struct port *Port=(PORT); \
338 if (PACKETFILTER(PKTFILTOUT,(PORTNO),(PACKET), (LEN))) {\
339 struct endpoint *ep; \
340 SEND_COUNTER_UPD(Port,LEN); \
341 for (ep=Port->ep; ep != NULL; ep=ep->next) \
342 Port->ms->sender(Port->fd_data, ep->fd_ctl, (PACKET), (LEN), ep->data, ep->port); \
349 /* functions for FSTP */
350 void port_send_packet(int portno
, void *packet
, int len
)
352 SEND_PACKET_PORT(portv
[portno
],portno
,packet
,len
);
355 void portset_send_packet(bitarray portset
, void *packet
, int len
)
358 BA_FORALL(portset
,numports
,
359 SEND_PACKET_PORT(portv
[i
],i
,packet
,len
), i
);
363 void port_set_status(int portno
, int vlan
, int status
)
365 if (BA_CHECK(vlant
[vlan
].table
,portno
)) {
366 if (status
==DISCARDING
) {
367 BA_SET(vlant
[vlan
].notlearning
,portno
);
368 BA_CLR(vlant
[vlan
].bctag
,portno
);
369 BA_CLR(vlant
[vlan
].bcuntag
,portno
);
370 } else if (status
==LEARNING
) {
371 BA_CLR(vlant
[vlan
].notlearning
,portno
);
372 BA_CLR(vlant
[vlan
].bctag
,portno
);
373 BA_CLR(vlant
[vlan
].bcuntag
,portno
);
374 } else { /*forwarding*/
375 BA_CLR(vlant
[vlan
].notlearning
,portno
);
376 if (portv
[portno
]->vlanuntag
== vlan
)
377 BA_SET(vlant
[vlan
].bcuntag
,portno
);
379 BA_SET(vlant
[vlan
].bctag
,portno
);
384 int port_get_status(int portno
, int vlan
)
386 if (BA_CHECK(vlant
[vlan
].notlearning
,portno
))
389 if (BA_CHECK(vlant
[vlan
].bctag
,portno
) ||
390 BA_CHECK(vlant
[vlan
].bcuntag
,portno
))
397 int port_getcost(int port
)
399 return portv
[port
]->cost
;
403 /************************************ CORE PACKET MGMT *****************************/
406 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
407 * | Destination | Source |81 00|pvlan| L/T | data
408 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
410 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
411 * | Destination | Source | L/T | data
412 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
414 * Destination/Source: 4 byte right shift
416 * Pointer to the packet: +4 bytes
419 #define TAG2UNTAG(P,LEN) \
420 ({ memmove((char *)(P)+4,(P),2*ETH_ALEN); LEN -= 4 ; \
421 (struct packet *)((char *)(P)+4); })
424 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
425 * | Destination | Source | L/T | data
426 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
428 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
429 * | Destination | Source |81 00|pvlan| L/T | data
430 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
431 * Destination/Source: 4 byte left shift
433 * Pointer to the packet: +4 bytes
434 * The space has been allocated in advance (just in case); all the modules
435 * read data into a bipacket.
438 #define UNTAG2TAG(P,VLAN,LEN) \
439 ({ memmove((char *)(P)-4,(P),2*ETH_ALEN); LEN += 4 ; \
440 (P)->header.src[2]=0x81; (P)->header.src[3]=0x00;\
441 (P)->header.src[4]=(VLAN >> 8); (P)->header.src[5]=(VLAN);\
442 (struct packet *)((char *)(P)-4); })
445 void handle_in_packet(int port
, struct packet
*packet
, int len
)
450 if(PACKETFILTER(PKTFILTIN
,port
,packet
,len
)) {
453 portv
[port
]->pktsin
++;
454 portv
[port
]->bytesin
+=len
;
456 if (packet
->header
.proto
[0] == 0x81 && packet
->header
.proto
[1] == 0x00) {
458 vlan
=((packet
->data
[0] << 8) + packet
->data
[1]) & 0xfff;
459 if (! BA_CHECK(vlant
[vlan
].table
,port
))
460 return; /*discard unwanted packets*/
463 if ((vlan
=portv
[port
]->vlanuntag
) == NOVLAN
)
464 return; /*discard unwanted packets*/
468 /* when it works as a HUB, MST packet must be forwarded */
469 if (ISBPDU(packet
) && !(pflag
& HUB_TAG
)) {
470 fst_in_bpdu(port
,packet
,len
,vlan
,tagged
);
471 return; /* BPDU packets are not forwarded */
474 /* The port is in blocked status, no packet received */
475 if (BA_CHECK(vlant
[vlan
].notlearning
,port
)) return;
477 /* We don't like broadcast source addresses */
478 if(! ((IS_BROADCAST(packet
->header
.src
)) || (pflag
& HUB_TAG
))) {
480 int last
= find_in_hash_update(packet
->header
.src
,vlan
,port
);
481 /* old value differs from actual input port */
482 if(last
>=0 && (port
!= last
)){
483 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
);
486 /* static void send_dst(int port,struct packet *packet, int len) */
487 if(IS_BROADCAST(packet
->header
.dest
) || (pflag
& HUB_TAG
) ||
488 (tarport
= find_in_hash(packet
->header
.dest
,vlan
)) < 0 ){
489 /* FST HERE! broadcast only on active ports*/
490 /* no cache or broadcast/multicast == all ports *except* the source port! */
491 /* BROADCAST: tag/untag. Broadcast the packet untouched on the ports
492 * of the same tag-ness, then transform it to the other tag-ness for the others*/
495 BA_FORALL(vlant
[vlan
].bctag
,numports
,
496 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
497 packet
=TAG2UNTAG(packet
,len
);
498 BA_FORALL(vlant
[vlan
].bcuntag
,numports
,
499 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
500 } else { /* untagged */
502 BA_FORALL(vlant
[vlan
].bcuntag
,numports
,
503 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
504 packet
=UNTAG2TAG(packet
,vlan
,len
);
505 BA_FORALL(vlant
[vlan
].bctag
,numports
,
506 ({if (i
!= port
) SEND_PACKET_PORT(portv
[i
],i
,packet
,len
);}),i
);
510 /* the hash table should not generate tarport not in vlan
511 * any time a port is removed from a vlan, the port is flushed from the hash */
513 return; /*do not loop!*/
515 if (portv
[tarport
]->vlanuntag
==vlan
) /* TAG->UNTAG */
516 SEND_PACKET_PORT(portv
[tarport
],tarport
,TAG2UNTAG(packet
,len
),len
);
518 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
520 if (portv
[tarport
]->vlanuntag
==vlan
) /* UNTAG->UNTAG */
521 SEND_PACKET_PORT(portv
[tarport
],tarport
,packet
,len
);
522 else /* UNTAG->TAG */
523 SEND_PACKET_PORT(portv
[tarport
],tarport
,UNTAG2TAG(packet
,vlan
,len
),len
);
525 } /* if(BROADCAST) */
526 } /* if(PACKETFILTER) */
529 /**************************************** COMMAND MANAGEMENT ****************************************/
531 static int showinfo(FILE *fd
)
533 printoutc(fd
,"Numports=%d",numports
);
534 printoutc(fd
,"HUB=%s",(pflag
& HUB_TAG
)?"true":"false");
536 printoutc(fd
,"counters=true");
538 printoutc(fd
,"counters=false");
543 static int portsetnumports(int val
)
548 for(i
=val
;i
<numports
;i
++)
551 portv
=realloc(portv
,val
*sizeof(struct port
*));
553 printlog(LOG_ERR
,"Numport resize failed portv %s",strerror(errno
));
556 for (i
=0;i
<NUMOFVLAN
;i
++) {
557 if (vlant
[i
].table
) {
558 vlant
[i
].table
=BA_REALLOC(vlant
[i
].table
,numports
,val
);
559 if (vlant
[i
].table
== NULL
) {
560 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan table %s",strerror(errno
));
564 if (vlant
[i
].bctag
) {
565 vlant
[i
].bctag
=BA_REALLOC(vlant
[i
].bctag
,numports
,val
);
566 if (vlant
[i
].bctag
== NULL
) {
567 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan bctag %s",strerror(errno
));
571 if (vlant
[i
].notlearning
) {
572 vlant
[i
].notlearning
=BA_REALLOC(vlant
[i
].notlearning
,numports
,val
);
573 if (vlant
[i
].notlearning
== NULL
) {
574 printlog(LOG_ERR
,"Numport resize failed vlan tables vlan notlearning %s",strerror(errno
));
579 for (i
=numports
;i
<val
;i
++)
590 static int portallocatable(char *arg
)
593 if (sscanf(arg
,"%i %i",&port
,&value
) != 2)
595 if (port
< 0 || port
>= numports
)
597 if (portv
[port
] == NULL
)
600 portv
[port
]->flag
&= ~NOTINPOOL
;
602 portv
[port
]->flag
|= NOTINPOOL
;
606 static int portremove(int val
)
608 if (val
<0 || val
>=numports
)
610 if (portv
[val
] == NULL
)
612 if (portv
[val
]->ep
!= NULL
)
618 static int portcreate(int val
)
621 if (val
<0 || val
>=numports
)
623 if (portv
[val
] != NULL
)
625 port
=alloc_port(val
);
626 if (port
> 0) portv
[port
]->flag
|= NOTINPOOL
;
630 static int epclose(char *arg
)
633 if (sscanf(arg
,"%i %i",&port
,&id
) != 2)
636 return close_ep(port
,id
);
639 static int print_port(FILE *fd
,int i
,int inclinactive
)
642 if (portv
[i
] != NULL
&& (inclinactive
|| portv
[i
]->ep
!=NULL
)) {
643 printoutc(fd
,"Port %04d untagged_vlan=%04d %sACTIVE - %sUnnamed Allocatable",
644 i
,portv
[i
]->vlanuntag
,
645 portv
[i
]->ep
?"":"IN",
646 (portv
[i
]->flag
& NOTINPOOL
)?"NOT ":"");
648 printoutc(fd
," IN: pkts %10lld bytes %20lld",portv
[i
]->pktsin
,portv
[i
]->bytesin
);
649 printoutc(fd
," OUT: pkts %10lld bytes %20lld",portv
[i
]->pktsout
,portv
[i
]->bytesout
);
651 for (ep
=portv
[i
]->ep
; ep
!= NULL
; ep
=ep
->next
)
652 printoutc(fd
," -- endpoint ID %04d module %-12s: %s",ep
->fd_ctl
,
653 portv
[i
]->ms
->modname
,(ep
->descr
)?ep
->descr
:"no endpoint description");
659 static int print_ptable(FILE *fd
,char *arg
)
664 if (i
<0 || i
>=numports
)
667 return print_port(fd
,i
,0);
670 for (i
=0;i
<numports
;i
++)
676 static int print_ptableall(FILE *fd
,char *arg
)
681 if (i
<0 || i
>=numports
)
684 return print_port(fd
,i
,1);
687 for (i
=0;i
<numports
;i
++)
694 static void portzerocounter(int i
)
696 if (portv
[i
] != NULL
) {
700 portv
[i
]->bytesout
=0;
704 static int portresetcounters(char *arg
)
709 if (i
<0 || i
>=numports
)
716 for (i
=0;i
<numports
;i
++)
723 static int portsethub(int val
)
725 (val
)?portflag(P_SETFLAG
,HUB_TAG
):portflag(P_CLRFLAG
,HUB_TAG
);
729 static int portsetvlan(char *arg
)
732 if (sscanf(arg
,"%i %i",&port
,&vlan
) != 2)
734 /* port NOVLAN is okay here, it means NO untagged traffic */
735 if (vlan
<0 || vlan
> NUMOFVLAN
|| port
< 0 || port
>= numports
)
737 if ((vlan
!= NOVLAN
&& !BAC_CHECK(validvlan
,vlan
)) || portv
[port
] == NULL
)
739 int oldvlan
=portv
[port
]->vlanuntag
;
740 portv
[port
]->vlanuntag
=NOVLAN
;
741 hash_delete_port(port
);
742 if (portv
[port
]->ep
!= NULL
) {
743 /*changing active port*/
744 if (oldvlan
!= NOVLAN
)
745 BA_CLR(vlant
[oldvlan
].bcuntag
,port
);
746 if (vlan
!= NOVLAN
) {
747 BA_SET(vlant
[vlan
].bcuntag
,port
);
748 BA_CLR(vlant
[vlan
].bctag
,port
);
751 if (oldvlan
!= NOVLAN
) fstdelport(oldvlan
,port
);
752 if (vlan
!= NOVLAN
) fstaddport(vlan
,port
,0);
755 if (oldvlan
!= NOVLAN
) BA_CLR(vlant
[oldvlan
].table
,port
);
756 if (vlan
!= NOVLAN
) BA_SET(vlant
[vlan
].table
,port
);
757 portv
[port
]->vlanuntag
=vlan
;
761 static int vlancreate_nocheck(int vlan
)
764 vlant
[vlan
].table
=BA_ALLOC(numports
);
765 vlant
[vlan
].bctag
=BA_ALLOC(numports
);
766 vlant
[vlan
].bcuntag
=BA_ALLOC(numports
);
767 vlant
[vlan
].notlearning
=BA_ALLOC(numports
);
768 if (vlant
[vlan
].table
== NULL
|| vlant
[vlan
].bctag
== NULL
||
769 vlant
[vlan
].bcuntag
== NULL
)
776 BAC_SET(validvlan
,NUMOFVLAN
,vlan
);
782 static int vlancreate(int vlan
)
784 if (vlan
> 0 && vlan
< NUMOFVLAN
-1) { /*vlan NOVLAN (0xfff a.k.a. 4095) is reserved */
785 if (BAC_CHECK(validvlan
,vlan
))
788 return vlancreate_nocheck(vlan
);
793 static int vlanremove(int vlan
)
795 if (vlan
>= 0 && vlan
< NUMOFVLAN
) {
796 if (BAC_CHECK(validvlan
,vlan
)) {
797 register int i
,used
=0;
798 BA_FORALL(vlant
[vlan
].table
,numports
,used
++,i
);
802 BAC_CLR(validvlan
,NUMOFVLAN
,vlan
);
803 free(vlant
[vlan
].table
);
804 free(vlant
[vlan
].bctag
);
805 free(vlant
[vlan
].bcuntag
);
806 free(vlant
[vlan
].notlearning
);
807 vlant
[vlan
].table
=NULL
;
808 vlant
[vlan
].bctag
=NULL
;
809 vlant
[vlan
].bcuntag
=NULL
;
810 vlant
[vlan
].notlearning
=NULL
;
822 static int vlanaddport(char *arg
)
825 if (sscanf(arg
,"%i %i",&vlan
,&port
) != 2)
827 if (vlan
<0 || vlan
>= NUMOFVLAN
-1 || port
< 0 || port
>= numports
)
829 if (!BAC_CHECK(validvlan
,vlan
) || portv
[port
] == NULL
)
831 if (portv
[port
]->ep
!= NULL
&& portv
[port
]->vlanuntag
!= vlan
) {
832 /* changing active port*/
833 BA_SET(vlant
[vlan
].bctag
,port
);
835 fstaddport(vlan
,port
,1);
838 BA_SET(vlant
[vlan
].table
,port
);
842 static int vlandelport(char *arg
)
845 if (sscanf(arg
,"%i %i",&vlan
,&port
) != 2)
847 if (vlan
<0 || vlan
>= NUMOFVLAN
-1 || port
< 0 || port
>= numports
)
849 if (!BAC_CHECK(validvlan
,vlan
) || portv
[port
] == NULL
)
851 if (portv
[port
]->vlanuntag
== vlan
)
853 if (portv
[port
]->ep
!= NULL
) {
854 /*changing active port*/
855 BA_CLR(vlant
[vlan
].bctag
,port
);
857 fstdelport(vlan
,port
);
860 BA_CLR(vlant
[vlan
].table
,port
);
861 hash_delete_port(port
);
865 #define STRSTATUS(PN,V) \
866 ((BA_CHECK(vlant[(V)].notlearning,(PN))) ? "Discarding" : \
867 (BA_CHECK(vlant[(V)].bctag,(PN)) || BA_CHECK(vlant[(V)].bcuntag,(PN))) ? \
868 "Forwarding" : "Learning")
870 static void vlanprintactive(int vlan
,FILE *fd
)
873 printoutc(fd
,"VLAN %04d",vlan
);
875 if (pflag
& FSTP_TAG
) {
877 printoutc(fd
," ++ FST root %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n"
878 " designated %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x port %d cost %d age %d",
879 fsttab
[vlan
]->root
[0], fsttab
[vlan
]->root
[1], fsttab
[vlan
]->root
[2], fsttab
[vlan
]->root
[3],
880 fsttab
[vlan
]->root
[4], fsttab
[vlan
]->root
[5], fsttab
[vlan
]->root
[6], fsttab
[vlan
]->root
[7],
881 fsttab
[vlan
]->desbr
[0], fsttab
[vlan
]->desbr
[1], fsttab
[vlan
]->desbr
[2], fsttab
[vlan
]->desbr
[3],
882 fsttab
[vlan
]->desbr
[4], fsttab
[vlan
]->desbr
[5], fsttab
[vlan
]->desbr
[6], fsttab
[vlan
]->desbr
[7],
883 fsttab
[vlan
]->rootport
,
884 ntohl(*(u_int32_t
*)(&(fsttab
[vlan
]->rootcost
))),
885 qtime()-fsttab
[vlan
]->roottimestamp
);
886 BA_FORALL(vlant
[vlan
].table
,numports
,
887 ({ int tagged
=portv
[i
]->vlanuntag
!= vlan
;
889 printoutc(fd
," -- Port %04d tagged=%d act=%d learn=%d forw=%d cost=%d role=%s",
890 i
, tagged
, 1, !(NOTLEARNING(i
,vlan
)),
891 (tagged
)?(BA_CHECK(vlant
[vlan
].bctag
,i
) != 0):(BA_CHECK(vlant
[vlan
].bcuntag
,i
) != 0),
893 (fsttab
[vlan
]->rootport
==i
?"Root":
894 ((BA_CHECK(fsttab
[vlan
]->backup
,i
)?"Alternate/Backup":"Designated")))
900 BA_FORALL(vlant
[vlan
].table
,numports
,
901 ({ int tagged
=portv
[i
]->vlanuntag
!= vlan
;
903 printoutc(fd
," -- Port %04d tagged=%d active=1 status=%s", i
, tagged
,
911 static int vlanprint(FILE *fd
,char *arg
)
916 if (vlan
>= 0 && vlan
< NUMOFVLAN
-1) {
917 if (BAC_CHECK(validvlan
,vlan
))
918 vlanprintactive(vlan
,fd
);
924 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,vlanprintactive
,fd
);
928 static void vlanprintelem(int vlan
,FILE *fd
)
931 printoutc(fd
,"VLAN %04d",vlan
);
932 BA_FORALL(vlant
[vlan
].table
,numports
,
933 printoutc(fd
," -- Port %04d tagged=%d active=%d status=%s",
934 i
, portv
[i
]->vlanuntag
!= vlan
, portv
[i
]->ep
!= NULL
, STRSTATUS(i
,vlan
)),i
);
937 static int vlanprintall(FILE *fd
,char *arg
)
942 if (vlan
> 0 && vlan
< NUMOFVLAN
-1) {
943 if (BAC_CHECK(validvlan
,vlan
))
944 vlanprintelem(vlan
,fd
);
950 BAC_FORALLFUN(validvlan
,NUMOFVLAN
,vlanprintelem
,fd
);
954 /* NOT sure about the effects of changing address on FSTP */
957 static int setmacaddr(char *strmac
)
959 int maci
[ETH_ALEN
],rv
;
961 if (index(strmac
,':') != NULL
)
962 rv
=sscanf(strmac
,"%x:%x:%x:%x:%x:%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
964 rv
=sscanf(strmac
,"%x.%x.%x.%x.%x.%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
969 for (i
=0;i
<ETH_ALEN
;i
++)
970 switchmac
[i
]=maci
[i
];
977 static struct comlist cl
[]={
978 {"port","============","PORT STATUS MENU",NULL
,NOARG
},
979 {"port/showinfo","","show port info",showinfo
,NOARG
|WITHFILE
},
980 {"port/setnumports","N","set the number of ports",portsetnumports
,INTARG
},
981 /*{"port/setmacaddr","MAC","set the switch MAC address",setmacaddr,STRARG},*/
982 {"port/sethub","0/1","1=HUB 0=switch",portsethub
,INTARG
},
983 {"port/setvlan","N VLAN","set port VLAN (untagged)",portsetvlan
,STRARG
},
984 {"port/create","N","create the port N (inactive|notallocatable)",portcreate
,INTARG
},
985 {"port/remove","N","remove the port N",portremove
,INTARG
},
986 {"port/allocatable","N 0/1","Is the port allocatable as unnamed? 1=Y 0=N",portallocatable
,STRARG
},
987 {"port/epclose","N ID","remove the endpoint port N/id ID",epclose
,STRARG
},
989 {"port/resetcounter","[N]","reset the port (N) counters",portresetcounters
,STRARG
},
991 {"port/print","[N]","print the port/endpoint table",print_ptable
,STRARG
|WITHFILE
},
992 {"port/allprint","[N]","print the port/endpoint table (including inactive port)",print_ptableall
,STRARG
|WITHFILE
},
993 {"vlan","============","VLAN MANAGEMENT MENU",NULL
,NOARG
},
994 {"vlan/create","N","create the VLAN with tag N",vlancreate
,INTARG
},
995 {"vlan/remove","N","remove the VLAN with tag N",vlanremove
,INTARG
},
996 {"vlan/addport","N PORT","add port to the vlan N (tagged)",vlanaddport
,STRARG
},
997 {"vlan/delport","N PORT","add port to the vlan N (tagged)",vlandelport
,STRARG
},
998 {"vlan/print","[N]","print the list of defined vlan",vlanprint
,STRARG
|WITHFILE
},
999 {"vlan/allprint","[N]","print the list of defined vlan (including inactive port)",vlanprintall
,STRARG
|WITHFILE
},
1002 void port_init(int initnumports
)
1004 if((numports
=initnumports
) <= 0) {
1005 printlog(LOG_ERR
,"The switch must have at least 1 port\n");
1008 portv
=calloc(numports
,sizeof(struct port
*));
1010 validvlan
=BAC_ALLOC(NUMOFVLAN
);
1011 if (portv
==NULL
|| validvlan
== NULL
) {
1012 printlog(LOG_ERR
,"ALLOC port data structures");
1019 if (vlancreate_nocheck(0) != 0) {
1020 printlog(LOG_ERR
,"ALLOC vlan port data structures");