/[dynamips]/upstream/dynamips-0.2.6-RC1/atm.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.6-RC1/atm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Sat Oct 6 16:03:58 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 17459 byte(s)
import dynamips-0.2.6-RC1

1 /*
2 * Cisco 7200 (Predator) simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * ATM utility functions and Virtual ATM switch.
6 *
7 * HEC and AAL5 CRC computation functions are from Charles Michael Heard
8 * and can be found at (no licence specified, this is to check!):
9 *
10 * http://cell-relay.indiana.edu/cell-relay/publications/software/CRC/
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <pthread.h>
18 #include <errno.h>
19 #include <sys/select.h>
20 #include <sys/time.h>
21 #include <sys/types.h>
22
23
24 #include "utils.h"
25 #include "registry.h"
26 #include "atm.h"
27 #include "net_io.h"
28
29 /********************************************************************/
30 #define HEC_GENERATOR 0x107 /* x^8 + x^2 + x + 1 */
31 #define COSET_LEADER 0x055 /* x^6 + x^4 + x^2 + 1 */
32
33 m_uint8_t hec_syndrome_table[256];
34
35 /* Generate a table of CRC-8 syndromes for all possible input bytes */
36 static void gen_syndrome_table(void)
37 {
38 int i,j,syndrome;
39
40 for(i=0;i<256;i++) {
41 syndrome = i;
42
43 for(j=0;j<8;j++) {
44 if (syndrome & 0x80)
45 syndrome = (syndrome << 1) ^ HEC_GENERATOR;
46 else
47 syndrome = (syndrome << 1);
48 }
49 hec_syndrome_table[i] = (unsigned char)syndrome;
50 }
51 }
52
53 /* Compute HEC field for ATM header */
54 m_uint8_t atm_compute_hec(m_uint8_t *cell_header)
55 {
56 register m_uint8_t hec_accum = 0;
57 register int i;
58
59 /*
60 * calculate CRC-8 remainder over first four bytes of cell header.
61 * exclusive-or with coset leader & insert into fifth header byte.
62 */
63 for(i=0;i<4;i++)
64 hec_accum = hec_syndrome_table[hec_accum ^ cell_header[i]];
65
66 return(hec_accum ^ COSET_LEADER);
67 }
68
69 /* Insert HEC field into an ATM header */
70 void atm_insert_hec(m_uint8_t *cell_header)
71 {
72 cell_header[4] = atm_compute_hec(cell_header);
73 }
74
75 /* Initialize ATM code (for HEC checksums) */
76 void atm_init(void)
77 {
78 gen_syndrome_table();
79 }
80
81 /* VPC hash function */
82 static inline u_int atmsw_vpc_hash(u_int vpi)
83 {
84 return((vpi ^ (vpi >> 8)) & (ATMSW_VP_HASH_SIZE-1));
85 }
86
87 /* VCC hash function */
88 static inline u_int atmsw_vcc_hash(u_int vpi,u_int vci)
89 {
90 return((vpi ^ vci) & (ATMSW_VC_HASH_SIZE-1));
91 }
92
93 /* VP lookup */
94 atmsw_vp_conn_t *atmsw_vp_lookup(atmsw_table_t *t,netio_desc_t *input,
95 u_int vpi)
96 {
97 atmsw_vp_conn_t *swc;
98
99 for(swc=t->vp_table[atmsw_vpc_hash(vpi)];swc;swc=swc->next)
100 if ((swc->input == input) && (swc->vpi_in == vpi))
101 return swc;
102
103 return NULL;
104 }
105
106 /* VC lookup */
107 atmsw_vc_conn_t *atmsw_vc_lookup(atmsw_table_t *t,netio_desc_t *input,
108 u_int vpi,u_int vci)
109 {
110 atmsw_vc_conn_t *swc;
111
112 for(swc=t->vc_table[atmsw_vcc_hash(vpi,vci)];swc;swc=swc->next)
113 if ((swc->input == input) && (swc->vpi_in == vpi) &&
114 (swc->vci_in == vci))
115 return swc;
116
117 return NULL;
118 }
119
120 /* VP switching */
121 void atmsw_vp_switch(atmsw_vp_conn_t *vpc,m_uint8_t *cell)
122 {
123 m_uint32_t atm_hdr;
124
125 /* rewrite the atm header with new vpi */
126 atm_hdr = ntohl(*(m_uint32_t *)cell);
127 atm_hdr = atm_hdr & ~ATM_HDR_VPI_MASK;
128 atm_hdr |= vpc->vpi_out << ATM_HDR_VPI_SHIFT;
129 *(m_uint32_t *)cell = htonl(atm_hdr);
130
131 /* recompute HEC field */
132 atm_insert_hec(cell);
133
134 /* update the statistics counter */
135 vpc->cell_cnt++;
136 }
137
138 /* VC switching */
139 void atmsw_vc_switch(atmsw_vc_conn_t *vcc,m_uint8_t *cell)
140 {
141 m_uint32_t atm_hdr;
142
143 /* rewrite the atm header with new vpi/vci */
144 atm_hdr = ntohl(*(m_uint32_t *)cell);
145
146 atm_hdr = atm_hdr & ~(ATM_HDR_VPI_MASK|ATM_HDR_VCI_MASK);
147 atm_hdr |= vcc->vpi_out << ATM_HDR_VPI_SHIFT;
148 atm_hdr |= vcc->vci_out << ATM_HDR_VCI_SHIFT;
149 *(m_uint32_t *)cell = htonl(atm_hdr);
150
151 /* recompute HEC field */
152 atm_insert_hec(cell);
153
154 /* update the statistics counter */
155 vcc->cell_cnt++;
156 }
157
158 /* Handle an ATM cell */
159 ssize_t atmsw_handle_cell(atmsw_table_t *t,netio_desc_t *input,
160 m_uint8_t *cell)
161 {
162 m_uint32_t atm_hdr,vpi,vci;
163 netio_desc_t *output = NULL;
164 atmsw_vp_conn_t *vpc;
165 atmsw_vc_conn_t *vcc;
166 ssize_t len;
167
168 /* Extract VPI/VCI information */
169 atm_hdr = ntohl(*(m_uint32_t *)cell);
170
171 vpi = (atm_hdr & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT;
172 vci = (atm_hdr & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT;
173
174 /* VP switching */
175 if ((vpc = atmsw_vp_lookup(t,input,vpi)) != NULL) {
176 atmsw_vp_switch(vpc,cell);
177 output = vpc->output;
178 } else {
179 /* VC switching */
180 if ((vcc = atmsw_vc_lookup(t,input,vpi,vci)) != NULL) {
181 atmsw_vc_switch(vcc,cell);
182 output = vcc->output;
183 }
184 }
185
186 len = netio_send(output,cell,ATM_CELL_SIZE);
187
188 if (len != ATM_CELL_SIZE) {
189 t->cell_drop++;
190 return(-1);
191 }
192
193 return(0);
194 }
195
196 /* Receive an ATM cell */
197 static int atmsw_recv_cell(netio_desc_t *nio,u_char *atm_cell,ssize_t cell_len,
198 atmsw_table_t *t)
199 {
200 int res;
201
202 if (cell_len != ATM_CELL_SIZE)
203 return(-1);
204
205 ATMSW_LOCK(t);
206 res = atmsw_handle_cell(t,nio,atm_cell);
207 ATMSW_UNLOCK(t);
208 return(res);
209 }
210
211 /* Acquire a reference to an ATM switch (increment reference count) */
212 atmsw_table_t *atmsw_acquire(char *name)
213 {
214 return(registry_find(name,OBJ_TYPE_ATMSW));
215 }
216
217 /* Release an ATM switch (decrement reference count) */
218 int atmsw_release(char *name)
219 {
220 return(registry_unref(name,OBJ_TYPE_ATMSW));
221 }
222
223 /* Create a virtual switch table */
224 atmsw_table_t *atmsw_create_table(char *name)
225 {
226 atmsw_table_t *t;
227
228 /* Allocate a new switch structure */
229 if (!(t = malloc(sizeof(*t))))
230 return NULL;
231
232 memset(t,0,sizeof(*t));
233 pthread_mutex_init(&t->lock,NULL);
234 mp_create_fixed_pool(&t->mp,"ATM Switch");
235
236 if (!(t->name = mp_strdup(&t->mp,name)))
237 goto err_name;
238
239 /* Record this object in registry */
240 if (registry_add(t->name,OBJ_TYPE_ATMSW,t) == -1) {
241 fprintf(stderr,"atmsw_create_table: unable to create switch '%s'\n",
242 name);
243 goto err_reg;
244 }
245
246 return t;
247
248 err_reg:
249 err_name:
250 mp_free_pool(&t->mp);
251 free(t);
252 return NULL;
253 }
254
255 /* Free resources used by a VPC */
256 static void atmsw_release_vpc(atmsw_vp_conn_t *swc)
257 {
258 if (swc) {
259 /* release input NIO */
260 if (swc->input) {
261 netio_rxl_remove(swc->input);
262 netio_release(swc->input->name);
263 }
264
265 /* release output NIO */
266 if (swc->output)
267 netio_release(swc->output->name);
268 }
269 }
270
271 /* Free resources used by a VCC */
272 static void atmsw_release_vcc(atmsw_vc_conn_t *swc)
273 {
274 if (swc) {
275 /* release input NIO */
276 if (swc->input) {
277 netio_rxl_remove(swc->input);
278 netio_release(swc->input->name);
279 }
280
281 /* release output NIO */
282 if (swc->output)
283 netio_release(swc->output->name);
284 }
285 }
286
287 /* Create a VP switch connection */
288 int atmsw_create_vpc(atmsw_table_t *t,char *nio_input,u_int vpi_in,
289 char *nio_output,u_int vpi_out)
290 {
291 atmsw_vp_conn_t *swc;
292 u_int hbucket;
293
294 ATMSW_LOCK(t);
295
296 /* Allocate a new switch connection */
297 if (!(swc = mp_alloc(&t->mp,sizeof(*swc)))) {
298 ATMSW_UNLOCK(t);
299 return(-1);
300 }
301
302 swc->input = netio_acquire(nio_input);
303 swc->output = netio_acquire(nio_output);
304 swc->vpi_in = vpi_in;
305 swc->vpi_out = vpi_out;
306
307 /* Check these NIOs are valid and the input VPI does not exists */
308 if (!swc->input || !swc->output || atmsw_vp_lookup(t,swc->input,vpi_in))
309 goto error;
310
311 /* Add as a RX listener */
312 if (netio_rxl_add(swc->input,(netio_rx_handler_t)atmsw_recv_cell,
313 t,NULL) == -1)
314 goto error;
315
316 hbucket = atmsw_vpc_hash(vpi_in);
317 swc->next = t->vp_table[hbucket];
318 t->vp_table[hbucket] = swc;
319 ATMSW_UNLOCK(t);
320 return(0);
321
322 error:
323 ATMSW_UNLOCK(t);
324 atmsw_release_vpc(swc);
325 mp_free(swc);
326 return(-1);
327 }
328
329 /* Delete a VP switch connection */
330 int atmsw_delete_vpc(atmsw_table_t *t,char *nio_input,u_int vpi_in,
331 char *nio_output,u_int vpi_out)
332 {
333 netio_desc_t *input,*output;
334 atmsw_vp_conn_t **swc,*p;
335 u_int hbucket;
336
337 ATMSW_LOCK(t);
338
339 input = registry_exists(nio_input,OBJ_TYPE_NIO);
340 output = registry_exists(nio_output,OBJ_TYPE_NIO);
341
342 if (!input || !output) {
343 ATMSW_UNLOCK(t);
344 return(-1);
345 }
346
347 hbucket = atmsw_vpc_hash(vpi_in);
348 for(swc=&t->vp_table[hbucket];*swc;swc=&(*swc)->next)
349 {
350 p = *swc;
351
352 if ((p->input == input) && (p->output == output) &&
353 (p->vpi_in == vpi_in) && (p->vpi_out == vpi_out))
354 {
355 /* found a matching VP, remove it */
356 *swc = (*swc)->next;
357 ATMSW_UNLOCK(t);
358
359 atmsw_release_vpc(p);
360 mp_free(p);
361 return(0);
362 }
363 }
364
365 ATMSW_UNLOCK(t);
366 return(-1);
367 }
368
369 /* Create a VC switch connection */
370 int atmsw_create_vcc(atmsw_table_t *t,
371 char *input,u_int vpi_in,u_int vci_in,
372 char *output,u_int vpi_out,u_int vci_out)
373 {
374 atmsw_vc_conn_t *swc;
375 u_int hbucket;
376
377 ATMSW_LOCK(t);
378
379 /* Allocate a new switch connection */
380 if (!(swc = mp_alloc(&t->mp,sizeof(*swc)))) {
381 ATMSW_UNLOCK(t);
382 return(-1);
383 }
384
385 swc->input = netio_acquire(input);
386 swc->output = netio_acquire(output);
387 swc->vpi_in = vpi_in;
388 swc->vci_in = vci_in;
389 swc->vpi_out = vpi_out;
390 swc->vci_out = vci_out;
391
392 /* Ensure that there is not already VP switching */
393 if (atmsw_vp_lookup(t,swc->input,vpi_in) != NULL) {
394 fprintf(stderr,"atmsw_create_vcc: VP switching already exists for "
395 "VPI=%u\n",vpi_in);
396 goto error;
397 }
398
399 /* Check these NIOs are valid and the input VPI does not exists */
400 if (!swc->input || !swc->output ||
401 atmsw_vc_lookup(t,swc->input,vpi_in,vci_in))
402 goto error;
403
404 /* Add as a RX listener */
405 if (netio_rxl_add(swc->input,(netio_rx_handler_t)atmsw_recv_cell,
406 t,NULL) == -1)
407 goto error;
408
409 hbucket = atmsw_vcc_hash(vpi_in,vci_in);
410 swc->next = t->vc_table[hbucket];
411 t->vc_table[hbucket] = swc;
412 ATMSW_UNLOCK(t);
413 return(0);
414
415 error:
416 ATMSW_UNLOCK(t);
417 atmsw_release_vcc(swc);
418 mp_free(swc);
419 return(-1);
420 }
421
422 /* Delete a VC switch connection */
423 int atmsw_delete_vcc(atmsw_table_t *t,
424 char *nio_input,u_int vpi_in,u_int vci_in,
425 char *nio_output,u_int vpi_out,u_int vci_out)
426 {
427 netio_desc_t *input,*output;
428 atmsw_vc_conn_t **swc,*p;
429 u_int hbucket;
430
431 ATMSW_LOCK(t);
432
433 input = registry_exists(nio_input,OBJ_TYPE_NIO);
434 output = registry_exists(nio_output,OBJ_TYPE_NIO);
435
436 hbucket = atmsw_vcc_hash(vpi_in,vci_in);
437 for(swc=&t->vc_table[hbucket];*swc;swc=&(*swc)->next)
438 {
439 p = *swc;
440
441 if ((p->input == input) && (p->output == output) &&
442 (p->vpi_in == vpi_in) && (p->vci_in == vci_in) &&
443 (p->vpi_out == vpi_out) && (p->vci_out == vci_out))
444 {
445 /* found a matching VP, remove it */
446 *swc = (*swc)->next;
447 ATMSW_UNLOCK(t);
448
449 atmsw_release_vcc(p);
450 mp_free(p);
451 return(0);
452 }
453 }
454
455 ATMSW_UNLOCK(t);
456 return(-1);
457 }
458
459 /* Free resources used by an ATM switch */
460 static int atmsw_free(void *data,void *arg)
461 {
462 atmsw_table_t *t = data;
463 atmsw_vp_conn_t *vp;
464 atmsw_vc_conn_t *vc;
465 int i;
466
467 /* Remove all VPs */
468 for(i=0;i<ATMSW_VP_HASH_SIZE;i++)
469 for(vp=t->vp_table[i];vp;vp=vp->next)
470 atmsw_release_vpc(vp);
471
472 /* Remove all VCs */
473 for(i=0;i<ATMSW_VC_HASH_SIZE;i++)
474 for(vc=t->vc_table[i];vc;vc=vc->next)
475 atmsw_release_vcc(vc);
476
477 mp_free_pool(&t->mp);
478 free(t);
479 return(TRUE);
480 }
481
482 /* Delete an ATM switch */
483 int atmsw_delete(char *name)
484 {
485 return(registry_delete_if_unused(name,OBJ_TYPE_ATMSW,atmsw_free,NULL));
486 }
487
488 /* Delete all ATM switches */
489 int atmsw_delete_all(void)
490 {
491 return(registry_delete_type(OBJ_TYPE_ATMSW,atmsw_free,NULL));
492 }
493
494 /* Save the configuration of an ATM switch */
495 void atmsw_save_config(atmsw_table_t *t,FILE *fd)
496 {
497 atmsw_vp_conn_t *vp;
498 atmsw_vc_conn_t *vc;
499 int i;
500
501 fprintf(fd,"atmsw create %s\n",t->name);
502
503 ATMSW_LOCK(t);
504
505 for(i=0;i<ATMSW_VP_HASH_SIZE;i++) {
506 for(vp=t->vp_table[i];vp;vp=vp->next) {
507 fprintf(fd,"atmsw create_vpc %s %s %u %s %u\n",
508 t->name,vp->input->name,vp->vpi_in,
509 vp->output->name,vp->vpi_out);
510 }
511 }
512
513 for(i=0;i<ATMSW_VC_HASH_SIZE;i++) {
514 for(vc=t->vc_table[i];vc;vc=vc->next) {
515 fprintf(fd,"atmsw create_vcc %s %s %u %u %s %u %u\n",
516 t->name,vc->input->name,vc->vpi_in,vc->vci_in,
517 vc->output->name,vc->vpi_out,vc->vci_out);
518 }
519 }
520
521 ATMSW_UNLOCK(t);
522
523 fprintf(fd,"\n");
524 }
525
526 /* Save configurations of all ATM switches */
527 static void atmsw_reg_save_config(registry_entry_t *entry,void *opt,int *err)
528 {
529 atmsw_save_config((atmsw_table_t *)entry->data,(FILE *)opt);
530 }
531
532 void atmsw_save_config_all(FILE *fd)
533 {
534 registry_foreach_type(OBJ_TYPE_ATMSW,atmsw_reg_save_config,fd,NULL);
535 }
536
537 /* Create a new interface */
538 int atmsw_cfg_create_if(atmsw_table_t *t,char **tokens,int count)
539 {
540 netio_desc_t *nio = NULL;
541 int nio_type;
542
543 /* at least: IF, interface name, NetIO type */
544 if (count < 3) {
545 fprintf(stderr,"atmsw_cfg_create_if: invalid interface description\n");
546 return(-1);
547 }
548
549 nio_type = netio_get_type(tokens[2]);
550 switch(nio_type) {
551 case NETIO_TYPE_UNIX:
552 if (count != 5) {
553 fprintf(stderr,"ATMSW: invalid number of arguments "
554 "for UNIX NIO '%s'\n",tokens[1]);
555 break;
556 }
557
558 nio = netio_desc_create_unix(tokens[1],tokens[3],tokens[4]);
559 break;
560
561 case NETIO_TYPE_UDP:
562 if (count != 6) {
563 fprintf(stderr,"ATMSW: invalid number of arguments "
564 "for UDP NIO '%s'\n",tokens[1]);
565 break;
566 }
567
568 nio = netio_desc_create_udp(tokens[1],atoi(tokens[3]),
569 tokens[4],atoi(tokens[5]));
570 break;
571
572 case NETIO_TYPE_TCP_CLI:
573 if (count != 5) {
574 fprintf(stderr,"ATMSW: invalid number of arguments "
575 "for TCP CLI NIO '%s'\n",tokens[1]);
576 break;
577 }
578
579 nio = netio_desc_create_tcp_cli(tokens[1],tokens[3],tokens[4]);
580 break;
581
582 case NETIO_TYPE_TCP_SER:
583 if (count != 4) {
584 fprintf(stderr,"ATMSW: invalid number of arguments "
585 "for TCP SER NIO '%s'\n",tokens[1]);
586 break;
587 }
588
589 nio = netio_desc_create_tcp_ser(tokens[1],tokens[3]);
590 break;
591
592 default:
593 fprintf(stderr,"ATMSW: unknown/invalid NETIO type '%s'\n",
594 tokens[2]);
595 }
596
597 if (!nio) {
598 fprintf(stderr,"ATMSW: unable to create NETIO descriptor of "
599 "interface %s\n",tokens[1]);
600 return(-1);
601 }
602
603 netio_release(nio->name);
604 return(0);
605 }
606
607 /* Create a new Virtual Path Connection */
608 int atmsw_cfg_create_vpc(atmsw_table_t *t,char **tokens,int count)
609 {
610 /* 5 parameters: "VP", InputIF, InVPI, OutputIF, OutVPI */
611 if (count != 5) {
612 fprintf(stderr,"ATMSW: invalid VPC descriptor.\n");
613 return(-1);
614 }
615
616 return(atmsw_create_vpc(t,tokens[1],atoi(tokens[2]),
617 tokens[3],atoi(tokens[4])));
618 }
619
620 /* Create a new Virtual Channel Connection */
621 int atmsw_cfg_create_vcc(atmsw_table_t *t,char **tokens,int count)
622 {
623 /* 7 parameters: "VP", InputIF, InVPI/VCI, OutputIF, OutVPI/VCI */
624 if (count != 7) {
625 fprintf(stderr,"ATMSW: invalid VCC descriptor.\n");
626 return(-1);
627 }
628
629 return(atmsw_create_vcc(t,tokens[1],atoi(tokens[2]),atoi(tokens[3]),
630 tokens[4],atoi(tokens[5]),atoi(tokens[6])));
631 }
632
633 #define ATMSW_MAX_TOKENS 16
634
635 /* Handle an ATMSW configuration line */
636 int atmsw_handle_cfg_line(atmsw_table_t *t,char *str)
637 {
638 char *tokens[ATMSW_MAX_TOKENS];
639 int count;
640
641 if ((count = m_strsplit(str,':',tokens,ATMSW_MAX_TOKENS)) <= 1)
642 return(-1);
643
644 if (!strcmp(tokens[0],"IF"))
645 return(atmsw_cfg_create_if(t,tokens,count));
646 else if (!strcmp(tokens[0],"VP"))
647 return(atmsw_cfg_create_vpc(t,tokens,count));
648 else if (!strcmp(tokens[0],"VC"))
649 return(atmsw_cfg_create_vcc(t,tokens,count));
650
651 fprintf(stderr,"ATMSW: Unknown statement \"%s\" (allowed: IF,VP,VC)\n",
652 tokens[0]);
653 return(-1);
654 }
655
656 /* Read an ATMSW configuration file */
657 int atmsw_read_cfg_file(atmsw_table_t *t,char *filename)
658 {
659 char buffer[1024],*ptr;
660 FILE *fd;
661
662 if (!(fd = fopen(filename,"r"))) {
663 perror("fopen");
664 return(-1);
665 }
666
667 while(!feof(fd)) {
668 if (!fgets(buffer,sizeof(buffer),fd))
669 break;
670
671 /* skip comments and end of line */
672 if ((ptr = strpbrk(buffer,"#\r\n")) != NULL)
673 *ptr = 0;
674
675 /* analyze non-empty lines */
676 if (strchr(buffer,':'))
677 atmsw_handle_cfg_line(t,buffer);
678 }
679
680 fclose(fd);
681 return(0);
682 }
683
684 /* Start a virtual ATM switch */
685 int atmsw_start(char *filename)
686 {
687 atmsw_table_t *t;
688
689 if (!(t = atmsw_create_table("default"))) {
690 fprintf(stderr,"ATMSW: unable to create virtual fabric table.\n");
691 return(-1);
692 }
693
694 if (atmsw_read_cfg_file(t,filename) == -1) {
695 fprintf(stderr,"ATMSW: unable to parse configuration file.\n");
696 return(-1);
697 }
698
699 atmsw_release("default");
700 return(0);
701 }

  ViewVC Help
Powered by ViewVC 1.1.26