/[dynamips]/trunk/eth_switch.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/eth_switch.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/eth_switch.c
File MIME type: text/plain
File size: 19813 byte(s)
dynamips-0.2.7

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4     *
5     * Virtual Ethernet switch with VLAN/Trunk support.
6     */
7    
8     #include <stdio.h>
9     #include <stdlib.h>
10     #include <string.h>
11     #include <unistd.h>
12     #include <pthread.h>
13     #include <errno.h>
14     #include <sys/select.h>
15     #include <sys/time.h>
16     #include <sys/types.h>
17     #include <assert.h>
18    
19     #include "utils.h"
20     #include "net.h"
21     #include "registry.h"
22     #include "net_io.h"
23     #include "eth_switch.h"
24    
25     /* Debbuging message */
26     void ethsw_debug(ethsw_table_t *t,char *fmt,...)
27     {
28     char module[128];
29     va_list ap;
30    
31     if (t->debug) {
32     va_start(ap,fmt);
33     snprintf(module,sizeof(module),"ETHSW %s",t->name);
34     m_flog(log_file,module,fmt,ap);
35     va_end(ap);
36     }
37     }
38    
39    
40     /* Compute hash index on the specified MAC address and VLAN */
41     static inline u_int ethsw_hash_index(n_eth_addr_t *addr,u_int vlan_id)
42     {
43     u_int h_index;
44    
45     h_index = (addr->eth_addr_byte[0] << 8) | addr->eth_addr_byte[1];
46     h_index ^= (addr->eth_addr_byte[2] << 8) | addr->eth_addr_byte[3];
47     h_index ^= (addr->eth_addr_byte[4] << 8) | addr->eth_addr_byte[5];
48     h_index ^= vlan_id;
49     return(h_index & (ETHSW_HASH_SIZE - 1));
50     }
51    
52     /* Invalidate the whole MAC address table */
53     static void ethsw_invalidate(ethsw_table_t *t)
54     {
55     memset(t->mac_addr_table,0,sizeof(t->mac_addr_table));
56     }
57    
58     /* Invalidate entry of the MAC address table referring to the specified NIO */
59     static void ethsw_invalidate_port(ethsw_table_t *t,netio_desc_t *nio)
60     {
61     ethsw_mac_entry_t *entry;
62     int i;
63    
64     for(i=0;i<ETHSW_HASH_SIZE;i++) {
65     entry = &t->mac_addr_table[i];
66     if (entry->nio == nio) {
67     entry->nio = NULL;
68     entry->vlan_id = 0;
69     }
70     }
71     }
72    
73     /* Push a 802.1Q tag */
74     static void dot1q_push_tag(m_uint8_t *pkt,ethsw_packet_t *sp,u_int vlan)
75     {
76     n_eth_dot1q_hdr_t *hdr;
77    
78     memcpy(pkt,sp->pkt,(N_ETH_HLEN - 2));
79    
80     hdr = (n_eth_dot1q_hdr_t *)pkt;
81     hdr->type = htons(N_ETH_PROTO_DOT1Q);
82     hdr->vlan_id = htons(sp->input_vlan);
83    
84     memcpy(pkt + sizeof(n_eth_dot1q_hdr_t),
85     sp->pkt + (N_ETH_HLEN - 2),
86     sp->pkt_len - (N_ETH_HLEN - 2));
87     }
88    
89     /* Pop a 802.1Q tag */
90     static void dot1q_pop_tag(m_uint8_t *pkt,ethsw_packet_t *sp)
91     {
92     memcpy(pkt,sp->pkt,(N_ETH_HLEN - 2));
93    
94     memcpy(pkt + (N_ETH_HLEN - 2),
95     sp->pkt + sizeof(n_eth_dot1q_hdr_t),
96     sp->pkt_len - sizeof(n_eth_dot1q_hdr_t));
97     }
98    
99     /* Input vector for ACCESS ports */
100     static void ethsw_iv_access(ethsw_table_t *t,ethsw_packet_t *sp,
101     netio_desc_t *op)
102     {
103     m_uint8_t pkt[ETHSW_MAX_PKT_SIZE+4];
104    
105     switch(op->vlan_port_type) {
106     /* Access -> Access: no special treatment */
107     case ETHSW_PORT_TYPE_ACCESS:
108     netio_send(op,sp->pkt,sp->pkt_len);
109     break;
110    
111     /* Access -> 802.1Q: push tag */
112     case ETHSW_PORT_TYPE_DOT1Q:
113     /*
114     * If the native VLAN of output port is the same as input,
115     * forward the packet without adding the tag.
116     */
117     if (op->vlan_id == sp->input_vlan) {
118     netio_send(op,sp->pkt,sp->pkt_len);
119     } else {
120     dot1q_push_tag(pkt,sp,op->vlan_id);
121     netio_send(op,pkt,sp->pkt_len+4);
122     }
123     break;
124    
125     default:
126     fprintf(stderr,"ethsw_iv_access: unknown port type %u\n",
127     op->vlan_port_type);
128     }
129     }
130    
131     /* Input vector for 802.1Q ports */
132     static void ethsw_iv_dot1q(ethsw_table_t *t,ethsw_packet_t *sp,
133     netio_desc_t *op)
134     {
135     m_uint8_t pkt[ETHSW_MAX_PKT_SIZE+4];
136    
137     /* If we don't have an input tag, we work temporarily as an access port */
138     if (!sp->input_tag) {
139     ethsw_iv_access(t,sp,op);
140     return;
141     }
142    
143     switch(op->vlan_port_type) {
144     /* 802.1Q -> Access: pop tag */
145     case ETHSW_PORT_TYPE_ACCESS:
146     dot1q_pop_tag(pkt,sp);
147     netio_send(op,pkt,sp->pkt_len-4);
148     break;
149    
150     /* 802.1Q -> 802.1Q: pop tag if native VLAN in output otherwise no-op */
151     case ETHSW_PORT_TYPE_DOT1Q:
152     if (op->vlan_id == sp->input_vlan) {
153     dot1q_pop_tag(pkt,sp);
154     netio_send(op,pkt,sp->pkt_len-4);
155     } else {
156     netio_send(op,sp->pkt,sp->pkt_len);
157     }
158     break;
159    
160     default:
161     fprintf(stderr,"ethsw_iv_dot1q: unknown port type %u\n",
162     op->vlan_port_type);
163     }
164     }
165    
166     /* Flood a packet */
167     static void ethsw_flood(ethsw_table_t *t,ethsw_packet_t *sp)
168     {
169     ethsw_input_vector_t input_vector;
170     netio_desc_t *op;
171     int i;
172    
173     input_vector = sp->input_port->vlan_input_vector;
174     assert(input_vector != NULL);
175    
176     for(i=0;i<ETHSW_MAX_NIO;i++) {
177     op = t->nio[i];
178    
179     if (!op || (op == sp->input_port))
180     continue;
181    
182     /* skip output port configured in access mode with a different vlan */
183     if ((op->vlan_port_type == ETHSW_PORT_TYPE_ACCESS) &&
184     (op->vlan_id != sp->input_vlan))
185     continue;
186    
187     /* send the packet on output port */
188     input_vector(t,sp,op);
189     }
190     }
191    
192     /* Forward a packet */
193     static void ethsw_forward(ethsw_table_t *t,ethsw_packet_t *sp)
194     {
195     n_eth_hdr_t *hdr = (n_eth_hdr_t *)sp->pkt;
196     ethsw_input_vector_t input_vector;
197     ethsw_mac_entry_t *entry;
198     u_int h_index;
199    
200     /* Learn the source MAC address */
201     h_index = ethsw_hash_index(&hdr->saddr,sp->input_vlan);
202     entry = &t->mac_addr_table[h_index];
203    
204     entry->nio = sp->input_port;
205     entry->vlan_id = sp->input_vlan;
206     entry->mac_addr = hdr->saddr;
207    
208     /* If we have a broadcast/multicast packet, flood it */
209     if (eth_addr_is_mcast(&hdr->daddr)) {
210     ethsw_debug(t,"multicast dest, flooding packet.\n");
211     ethsw_flood(t,sp);
212     return;
213     }
214    
215     /* Lookup on the destination MAC address (unicast) */
216     h_index = ethsw_hash_index(&hdr->daddr,sp->input_vlan);
217     entry = &t->mac_addr_table[h_index];
218    
219     /* If the dest MAC is unknown, flood the packet */
220     if (memcmp(&entry->mac_addr,&hdr->daddr,N_ETH_ALEN) ||
221     (entry->vlan_id != sp->input_vlan))
222     {
223     ethsw_debug(t,"unknown dest, flooding packet.\n");
224     ethsw_flood(t,sp);
225     return;
226     }
227    
228     /* Forward the packet to the output port only */
229     if (entry->nio != sp->input_port) {
230     input_vector = sp->input_port->vlan_input_vector;
231     assert(input_vector != NULL);
232     input_vector(t,sp,entry->nio);
233     } else {
234     ethsw_debug(t,"source and dest ports identical, dropping.\n");
235     }
236     }
237    
238     /* Receive a packet and prepare its forwarding */
239     static inline int ethsw_receive(ethsw_table_t *t,netio_desc_t *nio,
240     u_char *pkt,ssize_t pkt_len)
241     {
242     n_eth_dot1q_hdr_t *dot1q_hdr;
243     n_eth_isl_hdr_t *isl_hdr;
244     n_eth_hdr_t *eth_hdr;
245     n_eth_llc_hdr_t *llc_hdr;
246     ethsw_packet_t sp;
247     u_char *ptr;
248    
249     sp.input_port = nio;
250     sp.input_vlan = 0;
251     sp.pkt = pkt;
252     sp.pkt_len = pkt_len;
253    
254     /* Skip runt packets */
255     if (sp.pkt_len < N_ETH_HLEN)
256     return(-1);
257    
258     /* Determine the input VLAN */
259     switch(nio->vlan_port_type) {
260     case ETHSW_PORT_TYPE_ACCESS:
261     sp.input_vlan = nio->vlan_id;
262     break;
263    
264     case ETHSW_PORT_TYPE_DOT1Q:
265     dot1q_hdr = (n_eth_dot1q_hdr_t *)sp.pkt;
266    
267     /* use the native VLAN if no tag is found */
268     if (ntohs(dot1q_hdr->type) != N_ETH_PROTO_DOT1Q) {
269     sp.input_vlan = nio->vlan_id;
270     sp.input_tag = FALSE;
271     } else {
272     sp.input_vlan = ntohs(dot1q_hdr->vlan_id) & 0xFFF;
273     sp.input_tag = TRUE;
274     }
275     break;
276    
277     case ETHSW_PORT_TYPE_ISL:
278     /* Check that we have an ISL packet */
279     eth_hdr = (n_eth_hdr_t *)pkt;
280    
281     if (!eth_addr_is_cisco_isl(&eth_hdr->daddr))
282     break;
283    
284     /* Verify LLC header */
285     llc_hdr = PTR_ADJUST(n_eth_llc_hdr_t *,eth_hdr,sizeof(n_eth_hdr_t));
286     if (!eth_llc_check_snap(llc_hdr))
287     break;
288    
289     /* Get the VLAN id */
290     isl_hdr = PTR_ADJUST(n_eth_isl_hdr_t *,llc_hdr,
291     sizeof(n_eth_llc_hdr_t));
292     ptr = (u_char *)&isl_hdr->vlan;
293     sp.input_vlan = (((u_int)ptr[0] << 8) | ptr[1]) >> 1;
294     break;
295    
296     default:
297     fprintf(stderr,"ethsw_receive: unknown port type %u\n",
298     nio->vlan_port_type);
299     return(-1);
300     }
301    
302     if (sp.input_vlan != 0)
303     ethsw_forward(t,&sp);
304     return(0);
305     }
306    
307     /* Receive a packet (handle the locking part) */
308     static int ethsw_recv_pkt(netio_desc_t *nio,u_char *pkt,ssize_t pkt_len,
309     ethsw_table_t *t)
310     {
311     ETHSW_LOCK(t);
312     ethsw_receive(t,nio,pkt,pkt_len);
313     ETHSW_UNLOCK(t);
314     return(0);
315     }
316    
317     /* Set a port as an access port with the specified VLAN */
318     static void set_access_port(netio_desc_t *nio,u_int vlan_id)
319     {
320     nio->vlan_port_type = ETHSW_PORT_TYPE_ACCESS;
321     nio->vlan_id = vlan_id;
322     nio->vlan_input_vector = ethsw_iv_access;
323     }
324    
325     /* Set a port as a 802.1Q trunk port */
326     static void set_dot1q_port(netio_desc_t *nio,u_int native_vlan)
327     {
328     nio->vlan_port_type = ETHSW_PORT_TYPE_DOT1Q;
329     nio->vlan_id = native_vlan;
330     nio->vlan_input_vector = ethsw_iv_dot1q;
331     }
332    
333     /* Acquire a reference to an Ethernet switch (increment reference count) */
334     ethsw_table_t *ethsw_acquire(char *name)
335     {
336     return(registry_find(name,OBJ_TYPE_ETHSW));
337     }
338    
339     /* Release an Ethernet switch (decrement reference count) */
340     int ethsw_release(char *name)
341     {
342     return(registry_unref(name,OBJ_TYPE_ETHSW));
343     }
344    
345     /* Create a virtual ethernet switch */
346     ethsw_table_t *ethsw_create(char *name)
347     {
348     ethsw_table_t *t;
349    
350     /* Allocate a new switch structure */
351     if (!(t = malloc(sizeof(*t))))
352     return NULL;
353    
354     memset(t,0,sizeof(*t));
355     pthread_mutex_init(&t->lock,NULL);
356    
357     if (!(t->name = strdup(name)))
358     goto err_name;
359    
360     /* Record this object in registry */
361     if (registry_add(t->name,OBJ_TYPE_ETHSW,t) == -1) {
362     fprintf(stderr,"ethsw_create: unable to register switch '%s'\n",name);
363     goto err_reg;
364     }
365    
366     return t;
367    
368     err_reg:
369     free(t->name);
370     err_name:
371     free(t);
372     return NULL;
373     }
374    
375     /* Add a NetIO descriptor to a virtual ethernet switch */
376     int ethsw_add_netio(ethsw_table_t *t,char *nio_name)
377     {
378     netio_desc_t *nio;
379     int i;
380    
381     ETHSW_LOCK(t);
382    
383     /* Try to find a free slot in the NIO array */
384     for(i=0;i<ETHSW_MAX_NIO;i++)
385     if (t->nio[i] == NULL)
386     break;
387    
388     /* No free slot found ... */
389     if (i == ETHSW_MAX_NIO)
390     goto error;
391    
392     /* Acquire the NIO descriptor and increment its reference count */
393     if (!(nio = netio_acquire(nio_name)))
394     goto error;
395    
396     /* By default, the port is an access port in VLAN 1 */
397     set_access_port(nio,1);
398    
399     t->nio[i] = nio;
400     netio_rxl_add(nio,(netio_rx_handler_t)ethsw_recv_pkt,t,NULL);
401     ETHSW_UNLOCK(t);
402     return(0);
403    
404     error:
405     ETHSW_UNLOCK(t);
406     return(-1);
407     }
408    
409     /* Free resources used by a NIO */
410     static void ethsw_free_nio(netio_desc_t *nio)
411     {
412     netio_rxl_remove(nio);
413     netio_release(nio->name);
414     }
415    
416     /* Remove a NetIO descriptor from a virtual ethernet switch */
417     int ethsw_remove_netio(ethsw_table_t *t,char *nio_name)
418     {
419     netio_desc_t *nio;
420     int i;
421    
422     ETHSW_LOCK(t);
423    
424     if (!(nio = registry_exists(nio_name,OBJ_TYPE_NIO)))
425     goto error;
426    
427     /* Try to find the NIO in the NIO array */
428     for(i=0;i<ETHSW_MAX_NIO;i++)
429     if (t->nio[i] == nio)
430     break;
431    
432     if (i == ETHSW_MAX_NIO)
433     goto error;
434    
435     /* Invalidate this port in the MAC address table */
436     ethsw_invalidate_port(t,nio);
437     t->nio[i] = NULL;
438    
439     ETHSW_UNLOCK(t);
440    
441     /* Remove the NIO from the RX multiplexer */
442     ethsw_free_nio(nio);
443     return(0);
444    
445     error:
446     ETHSW_UNLOCK(t);
447     return(-1);
448     }
449    
450     /* Clear the MAC address table */
451     int ethsw_clear_mac_addr_table(ethsw_table_t *t)
452     {
453     ETHSW_LOCK(t);
454     ethsw_invalidate(t);
455     ETHSW_UNLOCK(t);
456     return(0);
457     }
458    
459     /* Iterate over all entries of the MAC address table */
460     int ethsw_iterate_mac_addr_table(ethsw_table_t *t,ethsw_foreach_entry_t cb,
461     void *opt_arg)
462     {
463     ethsw_mac_entry_t *entry;
464     int i;
465    
466     ETHSW_LOCK(t);
467    
468     for(i=0;i<ETHSW_HASH_SIZE;i++) {
469     entry = &t->mac_addr_table[i];
470    
471     if (!entry->nio)
472     continue;
473    
474     cb(t,entry,opt_arg);
475     }
476    
477     ETHSW_UNLOCK(t);
478     return(0);
479     }
480    
481     /* Set port as an access port */
482     int ethsw_set_access_port(ethsw_table_t *t,char *nio_name,u_int vlan_id)
483     {
484     int i,res = -1;
485    
486     ETHSW_LOCK(t);
487    
488     for(i=0;i<ETHSW_MAX_NIO;i++)
489     if (t->nio[i] && !strcmp(t->nio[i]->name,nio_name)) {
490     set_access_port(t->nio[i],vlan_id);
491     res = 0;
492     break;
493     }
494    
495     ETHSW_UNLOCK(t);
496     return(res);
497     }
498    
499     /* Set port as a 802.1q trunk port */
500     int ethsw_set_dot1q_port(ethsw_table_t *t,char *nio_name,u_int native_vlan)
501     {
502     int i,res = -1;
503    
504     ETHSW_LOCK(t);
505    
506     for(i=0;i<ETHSW_MAX_NIO;i++)
507     if (t->nio[i] && !strcmp(t->nio[i]->name,nio_name)) {
508     set_dot1q_port(t->nio[i],native_vlan);
509     res = 0;
510     break;
511     }
512    
513     ETHSW_UNLOCK(t);
514     return(res);
515     }
516    
517     /* Save the configuration of a switch */
518     void ethsw_save_config(ethsw_table_t *t,FILE *fd)
519     {
520     netio_desc_t *nio;
521     int i;
522    
523     fprintf(fd,"ethsw create %s\n",t->name);
524    
525     ETHSW_LOCK(t);
526    
527     for(i=0;i<ETHSW_MAX_NIO;i++)
528     {
529     nio = t->nio[i];
530    
531     fprintf(fd,"ethsw add_nio %s %s\n",t->name,nio->name);
532    
533     switch(nio->vlan_port_type) {
534     case ETHSW_PORT_TYPE_ACCESS:
535     fprintf(fd,"ethsw set_access_port %s %s %u\n",
536     t->name,nio->name,nio->vlan_id);
537     break;
538    
539     case ETHSW_PORT_TYPE_DOT1Q:
540     fprintf(fd,"ethsw set_dot1q_port %s %s %u\n",
541     t->name,nio->name,nio->vlan_id);
542     break;
543    
544     default:
545     fprintf(stderr,"ethsw_save_config: unknown port type %u\n",
546     nio->vlan_port_type);
547     }
548     }
549    
550     ETHSW_UNLOCK(t);
551    
552     fprintf(fd,"\n");
553     }
554    
555     /* Save configurations of all Ethernet switches */
556     static void ethsw_reg_save_config(registry_entry_t *entry,void *opt,int *err)
557     {
558     ethsw_save_config((ethsw_table_t *)entry->data,(FILE *)opt);
559     }
560    
561     void ethsw_save_config_all(FILE *fd)
562     {
563     registry_foreach_type(OBJ_TYPE_ETHSW,ethsw_reg_save_config,fd,NULL);
564     }
565    
566     /* Free resources used by a virtual ethernet switch */
567     static int ethsw_free(void *data,void *arg)
568     {
569     ethsw_table_t *t = data;
570     int i;
571    
572     for(i=0;i<ETHSW_MAX_NIO;i++) {
573     if (!t->nio[i])
574     continue;
575    
576     ethsw_free_nio(t->nio[i]);
577     }
578    
579     free(t->name);
580     free(t);
581     return(TRUE);
582     }
583    
584     /* Delete a virtual ethernet switch */
585     int ethsw_delete(char *name)
586     {
587     return(registry_delete_if_unused(name,OBJ_TYPE_ETHSW,ethsw_free,NULL));
588     }
589    
590     /* Delete all virtual ethernet switches */
591     int ethsw_delete_all(void)
592     {
593     return(registry_delete_type(OBJ_TYPE_ETHSW,ethsw_free,NULL));
594     }
595    
596     /* Create a new interface */
597     static int ethsw_cfg_create_if(ethsw_table_t *t,char **tokens,int count)
598     {
599     netio_desc_t *nio = NULL;
600     int nio_type;
601    
602     nio_type = netio_get_type(tokens[2]);
603     switch(nio_type) {
604     case NETIO_TYPE_UNIX:
605     if (count != 5) {
606     fprintf(stderr,"ETHSW: invalid number of arguments "
607     "for UNIX NIO\n");
608     break;
609     }
610    
611     nio = netio_desc_create_unix(tokens[1],tokens[3],tokens[4]);
612     break;
613    
614     case NETIO_TYPE_TAP:
615     if (count != 4) {
616     fprintf(stderr,"ETHSW: invalid number of arguments "
617     "for TAP NIO\n");
618     break;
619     }
620    
621     nio = netio_desc_create_tap(tokens[1],tokens[3]);
622     break;
623    
624     case NETIO_TYPE_UDP:
625     if (count != 6) {
626     fprintf(stderr,"ETHSW: invalid number of arguments "
627     "for UDP NIO\n");
628     break;
629     }
630    
631     nio = netio_desc_create_udp(tokens[1],atoi(tokens[3]),
632     tokens[4],atoi(tokens[5]));
633     break;
634    
635     case NETIO_TYPE_TCP_CLI:
636     if (count != 5) {
637     fprintf(stderr,"ETHSW: invalid number of arguments "
638     "for TCP CLI NIO\n");
639     break;
640     }
641    
642     nio = netio_desc_create_tcp_cli(tokens[1],tokens[3],tokens[4]);
643     break;
644    
645     case NETIO_TYPE_TCP_SER:
646     if (count != 4) {
647     fprintf(stderr,"ETHSW: invalid number of arguments "
648     "for TCP SER NIO\n");
649     break;
650     }
651    
652     nio = netio_desc_create_tcp_ser(tokens[1],tokens[3]);
653     break;
654    
655     #ifdef GEN_ETH
656     case NETIO_TYPE_GEN_ETH:
657     if (count != 4) {
658     fprintf(stderr,"ETHSW: invalid number of arguments "
659     "for Generic Ethernet NIO\n");
660     break;
661     }
662    
663     nio = netio_desc_create_geneth(tokens[1],tokens[3]);
664     break;
665     #endif
666    
667     #ifdef LINUX_ETH
668     case NETIO_TYPE_LINUX_ETH:
669     if (count != 4) {
670     fprintf(stderr,"ETHSW: invalid number of arguments "
671     "for Linux Ethernet NIO\n");
672     break;
673     }
674    
675     nio = netio_desc_create_lnxeth(tokens[1],tokens[3]);
676     break;
677     #endif
678    
679     default:
680     fprintf(stderr,"ETHSW: unknown/invalid NETIO type '%s'\n",
681     tokens[2]);
682     }
683    
684     if (!nio) {
685     fprintf(stderr,"ETHSW: unable to create NETIO descriptor\n");
686     return(-1);
687     }
688    
689     if (ethsw_add_netio(t,tokens[1]) == -1) {
690     fprintf(stderr,"ETHSW: unable to add NETIO descriptor.\n");
691     netio_release(nio->name);
692     return(-1);
693     }
694    
695     netio_release(nio->name);
696     return(0);
697     }
698    
699     /* Set a port as an access port */
700     static int ethsw_cfg_set_access_port(ethsw_table_t *t,char **tokens,int count)
701     {
702     /* 3 parameters: "ACCESS", IF, VLAN */
703     if (count != 3) {
704     fprintf(stderr,"ETHSW: invalid access port description.\n");
705     return(-1);
706     }
707    
708     return(ethsw_set_access_port(t,tokens[1],atoi(tokens[2])));
709     }
710    
711     /* Set a port as a 802.1q trunk port */
712     static int ethsw_cfg_set_dot1q_port(ethsw_table_t *t,char **tokens,int count)
713     {
714     /* 3 parameters: "DOT1Q", IF, Native VLAN */
715     if (count != 3) {
716     fprintf(stderr,"ETHSW: invalid trunk port description.\n");
717     return(-1);
718     }
719    
720     return(ethsw_set_dot1q_port(t,tokens[1],atoi(tokens[2])));
721     }
722    
723     #define ETHSW_MAX_TOKENS 16
724    
725     /* Handle a ETHSW configuration line */
726     static int ethsw_handle_cfg_line(ethsw_table_t *t,char *str)
727     {
728     char *tokens[ETHSW_MAX_TOKENS];
729     int count;
730    
731     if ((count = m_strsplit(str,':',tokens,ETHSW_MAX_TOKENS)) <= 1)
732     return(-1);
733    
734     if (!strcmp(tokens[0],"IF"))
735     return(ethsw_cfg_create_if(t,tokens,count));
736     else if (!strcmp(tokens[0],"ACCESS"))
737     return(ethsw_cfg_set_access_port(t,tokens,count));
738     else if (!strcmp(tokens[0],"DOT1Q"))
739     return(ethsw_cfg_set_dot1q_port(t,tokens,count));
740    
741     fprintf(stderr,
742     "ETHSW: Unknown statement \"%s\" (allowed: IF,ACCESS,TRUNK)\n",
743     tokens[0]);
744     return(-1);
745     }
746    
747     /* Read a ETHSW configuration file */
748     static int ethsw_read_cfg_file(ethsw_table_t *t,char *filename)
749     {
750     char buffer[1024],*ptr;
751     FILE *fd;
752    
753     if (!(fd = fopen(filename,"r"))) {
754     perror("fopen");
755     return(-1);
756     }
757    
758     while(!feof(fd)) {
759     if (!fgets(buffer,sizeof(buffer),fd))
760     break;
761    
762     /* skip comments and end of line */
763     if ((ptr = strpbrk(buffer,"#\r\n")) != NULL)
764     *ptr = 0;
765    
766     /* analyze non-empty lines */
767     if (strchr(buffer,':'))
768     ethsw_handle_cfg_line(t,buffer);
769     }
770    
771     fclose(fd);
772     return(0);
773     }
774    
775     /* Start a virtual Ethernet switch */
776     int ethsw_start(char *filename)
777     {
778     ethsw_table_t *t;
779    
780     if (!(t = ethsw_create("default"))) {
781     fprintf(stderr,"ETHSW: unable to create virtual fabric table.\n");
782     return(-1);
783     }
784    
785     if (ethsw_read_cfg_file(t,filename) == -1) {
786     fprintf(stderr,"ETHSW: unable to parse configuration file.\n");
787     return(-1);
788     }
789    
790     ethsw_release("default");
791     return(0);
792     }

  ViewVC Help
Powered by ViewVC 1.1.26