/[dynamips]/upstream/dynamips-0.2.7-RC1/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

Contents of /upstream/dynamips-0.2.7-RC1/eth_switch.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Sat Oct 6 16:23:47 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 19813 byte(s)
dynamips-0.2.7-RC1

1 /*
2 * Cisco router simulation platform.
3 * 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