diff -r 7365362b1198 -r 9e7175394c3c src/base/socket.hh --- a/src/base/socket.hh Tue Jun 23 15:08:07 2015 -0500 +++ b/src/base/socket.hh Fri Jun 26 20:41:46 2015 -0500 @@ -44,16 +44,54 @@ protected: bool listening; int fd; + /* + define an static fd variable to be used for all EtherTap devices + instantiated in switch, then you don't need to occupy several ports + in your system by creating so many sockets + */ + static int fd_static; public: ListenSocket(); virtual ~ListenSocket(); virtual int accept(bool nodelay = false); + /* + listenTap is called by the first instant of EtherTap. it initialize + "fd_static", then other instants of EtherTap does not need to create + a new socket and accept incoming connection by calling acceptTap + */ + virtual int acceptTap(bool nodelay = false); virtual bool listen(int port, bool reuse = true); + virtual bool listenTap(int port, bool reuse = true); int getfd() const { return fd; } + int getfd_static() const { return fd_static; } bool islistening() const { return listening; } + bool anyislistening() const { return anyListening; } }; +/* + EtherTap of pd-gem5 nodes should act as a client and connect to a + corresponding EtherTap port of the switch. + + ConnectSocket vs. ListenSocket: + ListenSocket is like a server connection + ConnectSocket is like a client connection +*/ +class ConnectSocket +{ + protected: + int fd; + + public: + ConnectSocket(); + virtual ~ConnectSocket(); + + virtual int connect(int port, const char* ip, bool nodelay = false); + + int getfd() const { return fd; } +}; + + #endif //__SOCKET_HH__ diff -r 7365362b1198 -r 9e7175394c3c src/base/socket.cc --- a/src/base/socket.cc Tue Jun 23 15:08:07 2015 -0500 +++ b/src/base/socket.cc Fri Jun 26 20:41:46 2015 -0500 @@ -39,11 +39,13 @@ #include "base/misc.hh" #include "base/socket.hh" #include "base/types.hh" +#include using namespace std; bool ListenSocket::listeningDisabled = false; bool ListenSocket::anyListening = false; +int ListenSocket::fd_static; void ListenSocket::disableAll() @@ -116,6 +118,48 @@ return true; } +// Create a socket and configure it for listening in EtherTap +bool +ListenSocket::listenTap(int port, bool reuse) +{ + if (listening) + panic("Socket already listening!"); + + fd_static = ::socket(PF_INET, SOCK_STREAM, 0); + if (fd_static < 0) + panic("Can't create socket:%s !", strerror(errno)); + + if (reuse) { + int i = 1; + if (::setsockopt(fd_static, SOL_SOCKET, SO_REUSEADDR, (char *)&i, + sizeof(i)) < 0) + panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!"); + } + + struct sockaddr_in sockaddr; + sockaddr.sin_family = PF_INET; + sockaddr.sin_addr.s_addr = INADDR_ANY; + sockaddr.sin_port = htons(port); + // finally clear sin_zero + memset(&sockaddr.sin_zero, 0, sizeof(sockaddr.sin_zero)); + int ret = ::bind(fd_static, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); + if (ret != 0) { + if (ret == -1 && errno != EADDRINUSE) + panic("ListenSocket(listen): bind() failed!"); + return false; + } + + if (::listen(fd_static, 1) == -1) { + if (errno != EADDRINUSE) + panic("ListenSocket(listen): listen() failed!"); + + return false; + } + + listening = true; + anyListening = true; + return true; +} // Open a connection. Accept will block, so if you don't want it to, // make sure a connection is ready before you call accept. @@ -134,3 +178,67 @@ return sfd; } + + +// Open a connection using an already created socket fd. Accept will block, so +// if you don't want it to, make sure a connection is ready before you call accept + +int +ListenSocket::acceptTap(bool nodelay) +{ + struct sockaddr_in sockaddr; + socklen_t slen = sizeof (sockaddr); + int sfd = ::accept(fd_static, (struct sockaddr *)&sockaddr, &slen); + if (sfd != -1 && nodelay) { + int i = 1; + if (::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, + sizeof(i)) < 0) + warn("ListenSocket(accept): setsockopt() TCP_NODELAY failed!"); + } + + return sfd; +} + +// ConnectSocket +ConnectSocket::ConnectSocket() + : fd(-1) +{} + +ConnectSocket::~ConnectSocket() +{ + if (fd != -1) + close(fd); +} + +// Create a socket and connect to a connection which is listening on "port", "ip" +int +ConnectSocket::connect(int port, const char* ip, bool nodelay) +{ + + fd = ::socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + panic("Can't create socket:%s !", strerror(errno)); + + if (nodelay) { + int i = 1; + if (::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, + sizeof(i)) < 0) + warn("ConnectSocket(connect): setsockopt() TCP_NODELAY failed!"); + } + + struct sockaddr_in sockaddr; + sockaddr.sin_family = PF_INET; + if(inet_pton(PF_INET, ip, &sockaddr.sin_addr)<=0){ + panic("\n inet_pton error occured\n"); + } + sockaddr.sin_port = htons(port); + // finally clear sin_zero + memset(&sockaddr.sin_zero, 0, sizeof(sockaddr.sin_zero)); + int ret = ::connect(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); + if (ret != 0) { + panic("ConnectSocket(connect): connect() failed!"); + } + + return fd; +} + diff -r 7365362b1198 -r 9e7175394c3c src/dev/Ethernet.py --- a/src/dev/Ethernet.py Tue Jun 23 15:08:07 2015 -0500 +++ b/src/dev/Ethernet.py Fri Jun 26 20:41:46 2015 -0500 @@ -61,6 +61,8 @@ port = Param.UInt16(3500, "tap port") tap = MasterPort("EtherTap interface") poll_rate = Param.UInt64(1000000, "check fd for incomming pkts in this rate") + server = Param.Bool(False, "Is this server or client tap") + server_ip = Param.String("127.0.0.1","Server IP address") class EtherDump(SimObject): type = 'EtherDump' diff -r 7365362b1198 -r 9e7175394c3c src/dev/ethertap.hh --- a/src/dev/ethertap.hh Tue Jun 23 15:08:07 2015 -0500 +++ b/src/dev/ethertap.hh Fri Jun 26 20:41:46 2015 -0500 @@ -48,6 +48,7 @@ class TapListener; class EtherTapInt; +class TapConnector; /* * Interface to connect a simulated ethernet device to the real world @@ -57,6 +58,8 @@ protected: friend class TapListener; TapListener *listener; + friend class TapConnector; + TapConnector *connector; int socket; char *buffer; int buflen; @@ -95,6 +98,7 @@ friend class TxEvent; TxEvent txEvent; EventWrapper tapInEvent; + bool attached; public: typedef EtherTapParams Params; @@ -114,6 +118,7 @@ virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); + bool isattached() { return attached; } }; class EtherTapInt : public EtherInt diff -r 7365362b1198 -r 9e7175394c3c src/dev/ethertap.cc --- a/src/dev/ethertap.cc Tue Jun 23 15:08:07 2015 -0500 +++ b/src/dev/ethertap.cc Fri Jun 26 20:41:46 2015 -0500 @@ -62,6 +62,7 @@ #include #include #include +#include using namespace std; @@ -98,51 +99,118 @@ ~TapListener() { if (event) delete event; } void accept(); - void listen(); + void listen(bool flag); }; void -TapListener::listen() +TapListener::listen(bool flag) { - while (!listener.listen(port, true)) { - DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); - port++; - } + //if this is the first instance of switch tap then: + //we should create a socket, otherwise we don't need to create a new socket + if (flag) { + while (!listener.listenTap(port, true)) { + DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); + port++; + } + struct ifaddrs * ifAddrStruct=NULL; + struct ifaddrs * ifa=NULL; + void * tmpAddrPtr=NULL; + getifaddrs(&ifAddrStruct); - ccprintf(cerr, "Listening for tap connection on port %d\n", port); - event = new Event(this, listener.getfd(), POLLIN|POLLERR); + //print the port and ip information of EthrTap + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + //check if it is a valid IP4 Address + if (ifa->ifa_addr->sa_family == AF_INET) { + tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + char addressBuffer[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); + if (!strcmp(ifa->ifa_name, "eth0")){ + setbuf(stdout, NULL); + ccprintf(cerr, "Listening for tap connection on %s %s %d\n", + ifa->ifa_name, addressBuffer, port); + fflush(stdout); + } + } + } + if (ifAddrStruct!=NULL) + freeifaddrs(ifAddrStruct); + } + event = new Event(this, listener.getfd_static(), POLLIN|POLLERR); pollQueue.schedule(event); } void TapListener::accept() { - // As a consequence of being called from the PollQueue, we might - // have been called from a different thread. Migrate to "our" - // thread. - EventQueue::ScopedMigration migrate(tap->eventQueue()); + if (tap->isattached()) { + DPRINTF(Ethernet, "EtherTap already attached\n"); + return; + } + // As a consequence of being called from the PollQueue, we might + // have been called from a different thread. Migrate to "our" + // thread. + EventQueue::ScopedMigration migrate(tap->eventQueue()); - if (!listener.islistening()) - panic("TapListener(accept): cannot accept if we're not listening!"); + if (!listener.anyislistening()) + panic("TapListener(accept): cannot accept if we're not listening!"); - int sfd = listener.accept(true); - if (sfd != -1) - tap->attach(sfd); + int sfd = listener.acceptTap(true); + if (sfd != -1) + tap->attach(sfd); } /** */ +class TapConnector +{ + protected: + ConnectSocket connector; + EtherTap *tap; + int port; + const char *ip; + + public: + TapConnector(EtherTap *t, int p, const char *ip_) + : tap(t), port(p), ip(ip_) {} + ~TapConnector() { } + + void connect(); +}; + +void +TapConnector::connect() +{ + //connect to the switch tap device which is listening for connections + int sfd = connector.connect(port, ip, true); + if (sfd != -1) + tap->attach(sfd); +} +/** + */ EtherTap::EtherTap(const Params *p) - : EtherObject(p), socket(-1), buflen(p->bufsz), dump(p->dump), - interface(NULL), pollRate(p->poll_rate), txEvent(this), tapInEvent(this) + : EtherObject(p), socket(-1), buflen(p->bufsz), dump(p->dump), + interface(NULL), pollRate(p->poll_rate), txEvent(this), tapInEvent(this), + attached(false) { - if (ListenSocket::allDisabled()) - fatal("All listeners are disabled! EtherTap can't work!"); + if (ListenSocket::allDisabled()) + fatal("All listeners are disabled! EtherTap can't work!"); - buffer = new char[buflen]; - listener = new TapListener(this, p->port); - listener->listen(); - interface = new EtherTapInt(name() + ".interface", this); + buffer = new char[buflen]; + static bool flag = true; + //if this is a tap connection in switch + if (p->server) { + listener = new TapListener(this, p->port); + listener->listen(flag); + flag = false; + } + //if this is a tap connection in nodes + else { + connector = new TapConnector(this, p->port, p->server_ip.c_str()); + connector->connect(); + } + interface = new EtherTapInt(name() + ".interface", this); } EtherTap::~EtherTap() @@ -164,6 +232,7 @@ data_len = 0; socket = fd; DPRINTF(Ethernet, "EtherTap attached\n"); + attached = true; int nonBlocking = 1; fcntl( socket, F_SETFL, O_NONBLOCK, nonBlocking ); if (!tapInEvent.scheduled())