From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:10
|
Update of /cvsroot/linux-atm/linux-atm/src/switch/tcp In directory usw-pr-cvs1:/tmp/cvs-serv10656/switch/tcp Added Files: Tag: V2_4_0 README tcpsw.c mkfiles Makefile.am Log Message: --- NEW FILE: README --- The following sequence works. Figuring out why is left as an exercise to the reader ;-) Commands: lrcpc4:~/w/atm/switch/tcp# ./sw_tcp -b -d lrcpc4:~# atmtcp virtual 1 switch localhost 1 bg lrcpc4:~# atmtcp virtual 2 switch localhost 2 bg lrcpc4:~# atmaddr -a 2 +1 lrcpc4:~/w/atm/switch/tcp# atmsigd -b -c 2.conf lrcpc15:~# atmtcp virtual 1 switch lrcpc4 3 bg lrcpc15:~# atmaddr -a 1 +2 lrcpc15:~/w/atm/switch/tcp# atmsigd -b -c 1.conf lrcpc15:~$ ttcp_atm -r -a lrcpc4:~$ ttcp_atm -t -a +2 --- switch.conf --------------------------------------------------------------- command "atmsigd -c s1.conf -b -m switch 1.0.100 /tmp/1" socket /tmp/1 { itf 2 1.0.100 route +1 } command "atmsigd -c s2.conf -b -m switch 1.0.101 /tmp/2" socket /tmp/2 { itf 3 1.0.101 default } --- s1.conf ------------------------------------------------------------------- debug log stderr debug level warn sig level debug sig vpci 0 itf 2 --- s2.conf ------------------------------------------------------------------- debug log stderr debug level warn sig level debug sig vpci 0 itf 3 --- 1.conf -------------------------------------------------------------------- debug log stderr debug level warn sig level debug io vc 1.0.5 sig vpci 0 itf 1 --- 2.conf -------------------------------------------------------------------- debug log stderr debug level warn sig level debug io vc 2.0.5 sig vpci 0 itf 2 --- - The following picture shows a simplified view of the configuration. Note that the command-line options have been choosen for clarity (and minor details like the vpci settings in the configuration file have been omitted) and are not identical with the ones given above. +-----------------------------------------------------------------------+ | ./sw_tcp | | | | +---------+ +----------------------------------+ 1.0.100 | | | |--/tmp/1--| atmsigd -m switch 1.0.100 /tmp/1 |---+ | | | | +----------------------------------+ | | | | <relay> | +-----+ | | | | +----------------------------------+ | | | | | |--/tmp/2--| atmsigd -m switch 1.0.101 /tmp/2 |---+ | | | +---------+ +----------------------------------+ 1.0.101 | | | | | | | | +--------------+ | | | | | | | | | | control | | | | | +----------------------| | itf 1 | | | <fabric> | | | | | | | | | 2.0.5 <--> 1.0.100 | | | | | 3.0.5 <--> 1.0.101 | 2 3 1 | | | | +--------------+ | | | | | | | | +-------------------------------|-----|----|------------------------|---+ | | | | +------------+ | | | | | | | +-----------------------------------+ | +-----------------------------------+ |atmtcp virtual 2 switch localhost 2| | |atmtcp virtual 1 switch localhost 1| +-----------------------------------+ | +-----------------------------------+ | | itf 2 (+1) +---- - - - - - ----+ | | +---------------+ | on lrcpc15: | | atmsigd 2.0.5 | | +---------------+ | | | | +--------------------------------+ | |atmtcp virtual 1 switch lrcpc4 3| | +--------------------------------+ | | itf 1 (+2) | | +---------------+ | atmsigd 1.0.5 | | +---------------+ In order to control the switch with swc, add the line control <path> to switch.conf, e.g. control /var/run/tcpswc Then invoke swc as follows: swc <path> show To add VCs, use add <itf>.<vpi>.<vci> , to add VPs, use add <itf>.<vpi>.? --- NEW FILE: tcpsw.c --- /* tcpsw.c - ATMTCP switch */ /* Written 1998 by Werner Almesberger, EPFL ICA */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <atm.h> #include <linux/atm_tcp.h> #include <atmd.h> #include "uni.h" #include "../fab.h" #include "../dispatch.h" #include "../swc.h" #define COMPONENT "FAB(tcp)" #define PRV(call) ((FAB *) (call)->fab) #define MAX_VCI 1024 #define PORT 2812 /* @@@ should merge with atmtcp.c */ #define MAX_PACKET (ATM_MAX_AAL5_PDU+sizeof(struct atmtcp_hdr)) #define BUFFER_SIZE (MAX_PACKET*2) typedef struct _table { struct _link *out; /* output port */ uint16_t in_vpi; /* input VPI */ int in_vci; /* input VCI (may be ATM_VCI_ANY) */ uint16_t out_vpi; /* output VPI */ uint16_t out_vci; /* output VCI */ struct _table *next; } TABLE; typedef struct _link { enum { id_none,id_set,id_reval } state; int id; /* switch port ID */ int fd; int len; /* length of data in the buffer */ char buffer[BUFFER_SIZE]; TABLE *table; /* switching table */ struct _link *next; } LINK; typedef struct _fab { int active; /* non-zero if there's an entry in the fabric */ CALL *next; /* relay.c may not keep track of calls, but WE are */ } FAB; static CALL *calls = NULL; static LINK *links = NULL; static void (*notify)(int number,int up); static LINK *find_link(int id) { LINK *lnk; for (lnk = links; lnk; lnk = lnk->next) if (lnk->state == id_set && lnk->id == id) break; return lnk; } static LINK *route(LINK *in,struct atmtcp_hdr *hdr) { TABLE *entry; for (entry = in->table; entry; entry = entry->next) if (ntohs(hdr->vpi) == entry->in_vpi && (entry->in_vci == ATM_VCI_UNSPEC || ntohs(hdr->vci) == entry->in_vci)) { hdr->vpi = htons(entry->out_vpi); if (entry->in_vci != ATM_VCI_UNSPEC) hdr->vci = htons(entry->out_vci); return entry->out; } return NULL; } static int add_entry(struct sockaddr_atmpvc *from,struct sockaddr_atmpvc *to) { LINK *l_from,*l_to; TABLE *entry; l_from = find_link(from->sap_addr.itf); l_to = find_link(to->sap_addr.itf); if (!l_from || !l_to) return -ENODEV; for (entry = l_from->table; entry; entry = entry->next) if (entry->in_vpi == from->sap_addr.vpi && (entry->in_vci == ATM_VCI_UNSPEC || from->sap_addr.vci == ATM_VCI_UNSPEC || entry->in_vci == from->sap_addr.vci)) return -EEXIST; entry = alloc_t(TABLE); entry->out = l_to; entry->in_vpi = from->sap_addr.vpi; entry->in_vci = from->sap_addr.vci; entry->out_vpi = to->sap_addr.vpi; entry->out_vci = to->sap_addr.vci; entry->next = l_from->table; l_from->table = entry; if (entry->in_vci == ATM_VCI_UNSPEC) diag(COMPONENT,DIAG_INFO,"added VP %d.%d -> %d.%d",l_from->id, entry->in_vpi,l_to->id,entry->out_vpi); else diag(COMPONENT,DIAG_INFO,"added VC %d.%d.%d -> %d.%d.%d",l_from->id, entry->in_vpi,entry->in_vci,l_to->id,entry->out_vpi,entry->out_vci); return 0; } static int del_entry(struct sockaddr_atmpvc *from,struct sockaddr_atmpvc *to) { LINK *l_from,*l_to; TABLE **entry,*this; l_from = find_link(from->sap_addr.itf); l_to = find_link(to->sap_addr.itf); if (!l_from || !l_to) return -ENODEV; for (entry = &l_from->table; *entry; entry = &(*entry)->next) if ((*entry)->out == l_to && (*entry)->in_vpi == from->sap_addr.vpi && (*entry)->in_vci == from->sap_addr.vci && ((*entry)->in_vci == ATM_VCI_UNSPEC || (*entry)->out_vci == to->sap_addr.vci)) break; if (!*entry) return -EHOSTUNREACH; this = *entry; *entry = this->next; if (this->in_vci == ATM_VCI_UNSPEC) diag(COMPONENT,DIAG_INFO,"deleted VP %d.%d -> %d.%d",l_from->id, this->in_vpi,l_to->id,this->out_vpi); else diag(COMPONENT,DIAG_INFO,"deleted VC %d.%d.%d -> %d.%d.%d",l_from->id, this->in_vpi,this->in_vci,l_to->id,this->out_vpi,this->out_vci); free(this); return 0; } static void drop_link(LINK *lnk) { diag(COMPONENT,DIAG_INFO,"dropped link %d",lnk->id); if (lnk->state == id_set) { notify(lnk->id,0); lnk->state = id_reval; } dsp_fd_remove(lnk->fd); #if 0 LINK **walk,**next_link,**entry,**next_entry; /* remove link from the list and delete all references to link */ for (walk = &links; *walk; walk = next_link) { next_link = &(*walk)->next; if (*walk == lnk) *walk = *next_link; else for (entry = &(*walk)->table; *entry; entry = next_entry) { next_entry = &(*entry)->next; if ((*entry)->out == lnk) { TABLE *this; this = *entry; *entry = *next_entry; free(this); } } } *walk = lnk->next; /* remove link's switching table */ while (lnk->table) { TABLE *next; next = lnk->table->next; free(lnk->table); lnk->table = next; } /* drop memory */ free(*lnk); #endif } static void new_data(int fd,void *user) { LINK *lnk = user; int got; got = read(fd,lnk->buffer+lnk->len,BUFFER_SIZE-lnk->len); if (got < 0) perror("read"); if (got <= 0) drop_link(lnk); lnk->len += got; if (lnk->state != id_set) { LINK *walk; char *end; int id; if (!memchr(lnk->buffer,0,lnk->len)) return; id = strtol(lnk->buffer,&end,0); if (*end) { diag(COMPONENT,DIAG_ERROR,"invalid line id \"%s\"",lnk->buffer); drop_link(lnk); return; } for (walk = links; walk; walk = walk->next) if (walk->state != id_none && id == walk->id) break; if (walk) { if (walk->state == id_set) { diag(COMPONENT,DIAG_ERROR,"line state mismatch (id %d)",id); drop_link(lnk); return; } diag(COMPONENT,DIAG_INFO,"reconnected link %d",id); walk->state = id_set; walk->fd = lnk->fd; walk->len = lnk->len; memcpy(walk->buffer,lnk->buffer,lnk->len); drop_link(lnk); lnk = walk; dsp_fd_add(lnk->fd,new_data,walk); } else { diag(COMPONENT,DIAG_INFO,"new link %d",id); lnk->state = id_set; lnk->id = id; } notify(lnk->id,1); lnk->len -= strlen(lnk->buffer)+1; memmove(lnk->buffer,lnk->buffer-strlen(lnk->buffer)-1,lnk->len); } while (lnk->len >= sizeof(struct atmtcp_hdr)) { struct atmtcp_hdr *hdr = (struct atmtcp_hdr *) lnk->buffer; LINK *out; int size; size = sizeof(struct atmtcp_hdr)+ntohl(hdr->length); if (lnk->len < size) break; out = route(lnk,hdr); if (out) { int sent; sent = write(out->fd,lnk->buffer,size); if (sent < 0) perror("write"); else if (sent != size) diag(COMPONENT,DIAG_ERROR,"bad write: %d != %d",sent,size); if (sent != size) drop_link(out); } lnk->len -= size; memmove(lnk->buffer,lnk->buffer+size,lnk->len); } } static void new_link(int sock,void *dummy) { LINK *lnk; int fd; fd = accept(sock,NULL,NULL); if (fd < 0) { perror("accept"); return; } lnk = alloc_t(LINK); lnk->state = id_none; lnk->id = -1; lnk->fd = fd; lnk->len = 0; lnk->table = NULL; lnk->next = links; links = lnk; dsp_fd_add(fd,new_data,lnk); } static int vci_exists(LINK *lnk,int vpi,int vci) { TABLE *walk; for (walk = lnk->table; walk; walk = walk->next) if (walk->in_vpi == vpi && walk->in_vci == vci) return 1; return 0; } static int check_ci(struct sockaddr_atmpvc *pvc) { LINK *lnk; TABLE *walk; int vci; lnk = find_link(pvc->sap_addr.itf); if (!lnk) return 0; if (pvc->sap_addr.vpi == ATM_VPI_ANY) pvc->sap_addr.vpi = 0; /* that was easy :-) */ for (walk = lnk->table; walk; walk = walk->next) if (walk->in_vpi == pvc->sap_addr.vpi) break; if (walk && walk->in_vci == ATM_VCI_UNSPEC) return 0; if (pvc->sap_addr.vci == ATM_VCI_UNSPEC) return !walk; if (pvc->sap_addr.vci != ATM_VCI_ANY) return !vci_exists(lnk,pvc->sap_addr.vpi,pvc->sap_addr.vci); for (vci = ATM_NOT_RSV_VCI; vci < MAX_VCI; vci++) if (!vci_exists(lnk,pvc->sap_addr.vpi,vci)) { pvc->sap_addr.vci = vci; return 1; } return 0; } void fab_option(const char *name,const char *value) { diag(COMPONENT,DIAG_FATAL,"unrecognized fabric option \"%s\"",name); } void fab_start(void (*port_notify)(int number,int up)) { struct sockaddr_in addr; int s_listen; notify = port_notify; addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); if ((s_listen = socket(PF_INET,SOCK_STREAM,0)) < 0) diag(COMPONENT,DIAG_FATAL,"socket: %s",strerror(errno)); if (bind(s_listen,(struct sockaddr *) &addr,sizeof(addr)) < 0) diag(COMPONENT,DIAG_FATAL,"bind: %s",strerror(errno)); if (listen(s_listen,5) < 0) diag(COMPONENT,DIAG_FATAL,"listen: %s",strerror(errno)); dsp_fd_add(s_listen,new_link,NULL); } void fab_init(CALL *call) { PRV(call) = alloc_t(FAB); PRV(call)->active = 0; PRV(call)->next = calls; calls = call; } void fab_destroy(CALL *call) { CALL **walk; for (walk = &calls; *walk; walk = &PRV(*walk)->next) if (*walk == call) break; if (!*walk) diag(COMPONENT,DIAG_FATAL,"fab_destroy: call %p not found",call); *walk = PRV(call)->next; free(PRV(call)); PRV(call) = NULL; } void fab_op(CALL *call,int op,const struct atm_qos *qos, void (*callback)(CALL *call,int cause,void *more,void *user),void *user) { int error,error2; diag(COMPONENT,DIAG_INFO,"fab_op%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", !op ? " FREE" : "",op & RM_RSV(_RM_ANY) ? " RM_RSV:" : "", op & RM_IN_TX ? " IN_TX" : "",op & RM_IN_RX ? " IN_RX" : "", op & RM_OUT_TX ? " OUT_TX" : "",op & RM_OUT_RX ? " OUT_RX" : "", op & RM_PATH_TX ? " PATH_TX" : "",op & RM_PATH_RX ? " PATH_RX" : "", op & RM_CLAIM(_RM_ANY) ? " RM_CLAIM:" : "", op & _RM_SHIFT(RM_IN_TX) ? " IN_TX" : "", op & _RM_SHIFT(RM_IN_RX) ? " IN_RX" : "", op & _RM_SHIFT(RM_OUT_TX) ? " OUT_TX" : "", op & _RM_SHIFT(RM_OUT_RX) ? " OUT_RX" : "", op & _RM_SHIFT(RM_PATH_TX) ? " PATH_TX" : "", op & _RM_SHIFT(RM_PATH_RX) ? " PATH_RX" : ""); if (op & (RM_RSV(RM_IN) | RM_CLAIM(RM_IN))) { if (!check_ci(&call->in.pvc)) { callback(call,ATM_CV_CI_UNAVAIL,NULL,user); return; } call->in.qos = *qos; } if (op & (RM_RSV(RM_OUT) | RM_CLAIM(RM_OUT))) { if (!check_ci(&call->out.pvc)) { callback(call,ATM_CV_CI_UNAVAIL,NULL,user); return; } call->out.qos = *qos; } if (op & RM_CLAIM(RM_PATH)) { error = 0; if (call->in.qos.txtp.traffic_class != ATM_NONE) error = add_entry(&call->in.pvc,&call->out.pvc); if (!error) { if (call->in.qos.rxtp.traffic_class != ATM_NONE) error = add_entry(&call->out.pvc,&call->in.pvc); if (error && call->in.qos.txtp.traffic_class != ATM_NONE) { error2 = del_entry(&call->in.pvc,&call->out.pvc); if (error2) diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error2)); } } if (error) { diag(COMPONENT,DIAG_ERROR,"add_entry: %s",strerror(error)); callback(call,ATM_CV_RES_UNAVAIL,NULL,user); return; } PRV(call)->active = 1; } if (!op && PRV(call)->active) { error = error2 = 0; if (call->in.qos.txtp.traffic_class != ATM_NONE) { error = del_entry(&call->in.pvc,&call->out.pvc); if (error) diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error)); } if (call->in.qos.rxtp.traffic_class != ATM_NONE) { error2 = del_entry(&call->out.pvc,&call->in.pvc); if (error2) diag(COMPONENT,DIAG_ERROR,"del_entry: %s",strerror(error2)); } if (error || error2) { callback(call,ATM_CV_TEMP_FAIL,NULL,user); return; } } callback(call,0,NULL,user); } --- NEW FILE: mkfiles --- #!/usr/bin/perl open(IN,"README") || die "open README: $!"; while (<IN>) { if (/^---\s*(\S+)\s*/) { if ($writing) { close OUT || die "close: $!"; $writing = 0; } next if $1 eq "-"; open(OUT,">$1") || die "create $1: $!"; $writing = 1; next; } print OUT $_ || die "write: $!" if $writing; } close OUT || die "close: $!" if $writing; for (@do) { print "$_\n"; system($_); sleep(1); } --- NEW FILE: Makefile.am --- noinst_PROGRAMS = sw_tcp INCLUDES = -I$(top_builddir)/src/qgen sw_tcp_SOURCES = tcpsw.c sw_tcp_XTRAS = $(top_builddir)/src/switch/libsw.a \ $(top_builddir)/src/lib/libatmd.la \ $(top_builddir)/src/lib/libatm.la sw_tcp_LDADD = $(sw_tcp_XTRAS) -lfl sw_tcp_DEPENDENCIES = $(sw_tcp_XTRAS) EXTRA_DIST = mkfiles README |