Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 09 Sep 2004 19:09:09 +0900
From:      "George V. Neville-Neil" <gnn@neville-neil.com>
To:        snap-users@kame.net
Cc:        Bosko Milekic <bmilekic@technokratis.com>
Subject:   Patch for NetPIPE to support IPv6
Message-ID:  <m2llfj69fe.wl@minion.local.neville-neil.com>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi,

	I have created a patch for NetPIPE version 3.6.2 that makes it
	work with IPv6.  If you're unfamiliar with NetPIPE then jump
	to here:  http://www.scl.ameslab.gov/netpipe/

	In short NetPIPE is a cool tool for generating packets and
	stressing/testing networks.  I suggest reading the papers they
	have on their web site.

	I've submitted this patch to the nice folks at ameslab as
	well, and will be using it in my own work on locking down the
	IPv6 code in FreeBSD.

	Apply the patch like this:

	cd NetPIPE-3.2.2
	patch -p0 < ~/netpipe.patch
	make tcp6

	This will generate the program NPtcp6 which must be run as a
	client/server pair.  

	server> ./NPtcp6

	client> ./NPtcp6 -h <client IPv6/name>

	You can specify IPv6 style addresses such as ::1 etc. for 
	the -h argument.  I have not tested the gethostbyname2() call
	yet as I'm trapped behind a NAT at the moment.  It ought to
	work though.

	Bugs with the IPv6 version of this code should be sent to me,
	and not to the nice folks at ameslab who wrote the original.

Later,
George


[-- Attachment #2 --]
Index: makefile
===================================================================
RCS file: /cvs/gnn/Personal/Code/Networking/NetPIPE/makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- makefile	9 Sep 2004 08:29:22 -0000	1.1.1.1
+++ makefile	9 Sep 2004 08:35:07 -0000	1.2
@@ -81,7 +81,11 @@
 
 
 tcp: $(SRC)/tcp.c $(SRC)/netpipe.c $(SRC)/netpipe.h 
-	$(CC) $(CFLAGS) $(SRC)/netpipe.c $(SRC)/tcp.c -DTCP  -o NPtcp -I$(SRC)
+	$(CC) $(CFLAGS) $(SRC)/netpipe.c $(SRC)/tcp.c -DTCP -o NPtcp -I$(SRC)
+
+tcp6: $(SRC)/tcp.c $(SRC)/netpipe.c $(SRC)/netpipe.h 
+	$(CC) $(CFLAGS) $(SRC)/netpipe.c $(SRC)/tcp6.c -DTCP6 \
+		-o NPtcp6 -I$(SRC)
 
 memcpy: $(SRC)/memcpy.c $(SRC)/netpipe.c $(SRC)/netpipe.h
 	$(CC) $(CFLAGS) $(SRC)/netpipe.c $(SRC)/memcpy.c \
Index: dox/README
===================================================================
RCS file: /cvs/gnn/Personal/Code/Networking/NetPIPE/dox/README,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 README
--- dox/README	9 Sep 2004 08:29:35 -0000	1.1.1.1
+++ dox/README	9 Sep 2004 09:56:55 -0000
@@ -85,6 +85,7 @@
   make shmem      (1-sided library for Cray and SGI systems)
 
   make tcp
+  make tcp6       (for IPv6 enabled systems)
   make gm         (for Myrinet cards, you will need to set some paths)
   make shmem      (1-sided library for Cray and SGI systems)
   make gpshmem    (SHMEM interface for other machines)
@@ -145,7 +146,7 @@
         -2: Bi-directional communications.  Transmit in both directions
             simultaneously.
 
-   TCP
+   TCP and TCP6
    ---
 
       Compile NetPIPE using 'make tcp'
Index: src/netpipe.h
===================================================================
RCS file: /cvs/gnn/Personal/Code/Networking/NetPIPE/src/netpipe.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/netpipe.h	9 Sep 2004 08:29:38 -0000	1.1.1.1
+++ src/netpipe.h	9 Sep 2004 08:35:07 -0000	1.2
@@ -23,6 +23,11 @@
 #include <stdlib.h>         /* malloc(3) */
 #include <unistd.h>         /* getopt, read, write, ... */
 
+/* Handle the case of building on MacOS X */
+#if defined(__APPLE__)
+#include <stdint.h>
+#endif 
+
 #ifdef INFINIBAND
 #include <ib_defs.h> /* ib_mtu_t */
 #endif
@@ -89,6 +94,24 @@
 };
 #endif
 
+#elif defined(TCP6)
+  #include <netdb.h>
+  #include <sys/socket.h>
+  #include <netinet/in.h>
+  #include <netinet/tcp.h>
+  #include <arpa/inet.h>
+  
+  typedef struct protocolstruct ProtocolStruct;
+  struct protocolstruct
+  {
+      struct sockaddr_in6     sin1;   /* socket structure #1              */
+      struct sockaddr_in6     sin2;   /* socket structure #2              */
+      int                     nodelay;  /* Flag for TCP nodelay           */
+      struct hostent          *addr;    /* Address of host                */
+      int                     sndbufsz; /* Size of TCP send buffer        */
+      int                     rcvbufsz; /* Size of TCP receive buffer     */
+  };
+
 #elif defined(MPI)
   typedef struct protocolstruct ProtocolStruct;
   struct protocolstruct 
@@ -197,7 +220,7 @@
   };
 
 #else
-  #error "One of TCP, MPI, PVM, TCGMSG, LAPI, SHMEM, ATOLL, MEMCPY, DISK must be defined during compilation"
+  #error "One of TCP, TCP6, MPI, PVM, TCGMSG, LAPI, SHMEM, ATOLL, MEMCPY, DISK must be defined during compilation"
 
 #endif
 
Index: src/tcp6.c
===================================================================
RCS file: src/tcp6.c
diff -N src/tcp6.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/tcp6.c	9 Sep 2004 08:35:07 -0000	1.1
@@ -0,0 +1,444 @@
+/*****************************************************************************/
+/* "NetPIPE" -- Network Protocol Independent Performance Evaluator.          */
+/* Copyright 1997, 1998 Iowa State University Research Foundation, Inc.      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation.  You should have received a copy of the     */
+/* GNU General Public License along with this program; if not, write to the  */
+/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */
+/*                                                                           */
+/* TCP6 extension Copyright 2004 George V. Neville-Neil and Neville-Neil     */
+/* Consulting                                                                */
+/*                                                                           */
+/*     * tcp6.c         ---- TCP over IPv6 calls source                      */
+/*     * tcp.h          ---- Include file for TCP6 calls and data structs    */
+/*****************************************************************************/
+#include    "netpipe.h"
+
+#if defined (MPLITE)
+#include "mplite.h"
+#endif
+
+
+int doing_reset = 0;
+
+void Init(ArgStruct *p, int* pargc, char*** pargv)
+{
+    p->reset_conn = 0; /* Default to not resetting connection */
+    p->prot.sndbufsz = p->prot.rcvbufsz = 0;
+    /* The transmitter will be set using the -h host flag. */
+    p->tr = 0;
+    p->rcv = 1;
+}
+
+void Setup(ArgStruct *p)
+{
+    int one = 1;
+    int sockfd = -1;
+    /* ptr to sockaddr_in in ArgStruct */
+    struct sockaddr_in6 *lsin1, *lsin2;      
+    
+    char *host;
+    struct hostent *hp;
+    struct protoent *proto;
+    int send_size, recv_size, sizeofint = sizeof(int);
+	
+    host = p->host;                           /* copy ptr to hostname */ 
+	
+    lsin1 = &(p->prot.sin1);
+    lsin2 = &(p->prot.sin2);
+	
+    bzero((char *) lsin1, sizeof(*lsin1));
+    bzero((char *) lsin2, sizeof(*lsin2));
+
+    if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0){
+	printf("NetPIPE: can't open stream socket! errno=%d\n", errno);
+	exit(-4);
+    }
+
+    if(!(proto = getprotobyname("tcp"))){
+	printf("NetPIPE: protocol 'tcp' unknown!\n");
+	exit(555);
+    }
+
+    /* Attempt to set TCP_NODELAY */
+
+    if(setsockopt(sockfd, proto->p_proto, TCP_NODELAY, &one, sizeof(one)) < 0)
+    {
+	printf("NetPIPE: setsockopt: TCP_NODELAY failed! errno=%d\n", errno);
+	exit(556);
+    }
+
+    /* If requested, set the send and receive buffer sizes */
+
+    if(p->prot.sndbufsz > 0)
+    {
+	if(setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &(p->prot.sndbufsz), 
+		      sizeof(p->prot.sndbufsz)) < 0)
+	{
+	    printf("NetPIPE: setsockopt: SO_SNDBUF failed! errno=%d\n", errno);
+	    printf("You may have asked for a buffer larger than the system can handle\n");
+	    exit(556);
+	}
+	if(setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &(p->prot.rcvbufsz), 
+		      sizeof(p->prot.rcvbufsz)) < 0)
+	{
+	    printf("NetPIPE: setsockopt: SO_RCVBUF failed! errno=%d\n", errno);
+	    printf("You may have asked for a buffer larger than the system can handle\n");
+	    exit(556);
+	}
+    }
+    getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
+	       (char *) &send_size, (void *) &sizeofint);
+    getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
+	       (char *) &recv_size, (void *) &sizeofint);
+ 
+    if(!doing_reset) {
+	fprintf(stderr,"Send and receive buffers are %d and %d bytes\n",
+		send_size, recv_size);
+	fprintf(stderr, "(A bug in Linux doubles the requested buffer sizes)\n");
+    }
+
+    if( p->tr ) {                             /* Primary transmitter */
+
+	lsin1->sin6_family = AF_INET6;
+
+	/* First attempt to convert the string to an IPv6 */
+	/* address. */
+	/* If the user supplied a real host name this will fail and */
+  	/* we'll then do a name lookup. */
+
+	if (inet_pton(AF_INET6, host, &lsin1->sin6_addr) == 0)
+	{
+	    if ((hp = gethostbyname2(host, AF_INET6)) == NULL)
+	    {
+		printf("NetPIPE: invalid hostname '%s'\n", host);
+		exit(-5);
+	    }
+
+	    if (hp->h_addrtype != AF_INET6) 
+	    {
+		printf("NetPIPE: invalid hostname '%s'\n", host);
+		exit(-5);
+	    }
+	    bcopy(hp->h_addr, (char*) &(lsin1->sin6_addr), 
+		  hp->h_length);
+	}
+
+	lsin1->sin6_port = htons(p->port);
+	
+	p->commfd = sockfd;
+	
+    } else if( p->rcv ) {                     /* we are the receiver */
+	bzero((char *) lsin1, sizeof(*lsin1));
+	lsin1->sin6_family  = AF_INET6;
+	lsin1->sin6_len     = sizeof(*lsin1);
+	lsin1->sin6_port    = htons(p->port);
+	/* Setting this to all 0 is the "ANY" address. */
+	bzero(&lsin1->sin6_addr, sizeof(lsin1->sin6_addr));
+   
+	if (bind(sockfd, (struct sockaddr *) lsin1, sizeof(*lsin1)) < 0){
+	    printf("NetPIPE: server: bind on local address failed! errno=%d", errno);
+	    exit(-6);
+	}
+
+	p->servicefd = sockfd;
+    }
+    p->upper = send_size + recv_size;
+
+    establish(p);                               /* Establish connections */
+
+}   
+
+static int
+readFully(int fd, void *obuf, int len)
+{
+    int bytesLeft = len;
+    char *buf = (char *) obuf;
+    int bytesRead = 0;
+
+    while (bytesLeft > 0 &&
+	   (bytesRead = read(fd, (void *) buf, bytesLeft)) > 0)
+    {
+	bytesLeft -= bytesRead;
+	buf += bytesRead;
+    }
+    if (bytesRead <= 0) return bytesRead;
+    return len;
+}
+
+void Sync(ArgStruct *p)
+{
+    char s[] = "SyncMe", response[] = "      ";
+
+    if (write(p->commfd, s, strlen(s)) < 0 ||           /* Write to nbor */
+	readFully(p->commfd, response, strlen(s)) < 0)  /* Read from nbor */
+    {
+	perror("NetPIPE: error writing or reading synchronization string");
+	exit(3);
+    }
+    if (strncmp(s, response, strlen(s)))
+    {
+	fprintf(stderr, "NetPIPE: Synchronization string incorrect! |%s|\n", response);
+	exit(3);
+    }
+}
+
+void PrepareToReceive(ArgStruct *p)
+{
+    /*
+      The Berkeley sockets interface doesn't have a method to pre-post
+      a buffer for reception of data.
+    */
+}
+
+void SendData(ArgStruct *p)
+{
+    int bytesWritten, bytesLeft;
+    char *q;
+
+    bytesLeft = p->bufflen;
+    bytesWritten = 0;
+    q = p->s_ptr;
+    while (bytesLeft > 0 &&
+	   (bytesWritten = write(p->commfd, q, bytesLeft)) > 0)
+    {
+	bytesLeft -= bytesWritten;
+	q += bytesWritten;
+    }
+    if (bytesWritten == -1)
+    {
+	printf("NetPIPE: write: error encountered, errno=%d\n", errno);
+	exit(401);
+    }
+}
+
+void RecvData(ArgStruct *p)
+{
+    int bytesLeft;
+    int bytesRead;
+    char *q;
+
+    bytesLeft = p->bufflen;
+    bytesRead = 0;
+    q = p->r_ptr;
+    while (bytesLeft > 0 &&
+	   (bytesRead = read(p->commfd, q, bytesLeft)) > 0)
+    {
+	bytesLeft -= bytesRead;
+	q += bytesRead;
+    }
+    if (bytesLeft > 0 && bytesRead == 0)
+    {
+	printf("NetPIPE: \"end of file\" encountered on reading from socket\n");
+    }
+    else if (bytesRead == -1)
+    {
+	printf("NetPIPE: read: error encountered, errno=%d\n", errno);
+	exit(401);
+    }
+}
+
+/* uint32_t is used to insure that the integer size is the same even in tests 
+ * between 64-bit and 32-bit architectures. */
+
+void SendTime(ArgStruct *p, double *t)
+{
+    uint32_t ltime, ntime;
+
+    /*
+      Multiply the number of seconds by 1e8 to get time in 0.01 microseconds
+      and convert value to an unsigned 32-bit integer.
+    */
+    ltime = (uint32_t)(*t * 1.e8);
+
+    /* Send time in network order */
+    ntime = htonl(ltime);
+    if (write(p->commfd, (char *)&ntime, sizeof(uint32_t)) < 0)
+    {
+	printf("NetPIPE: write failed in SendTime: errno=%d\n", errno);
+	exit(301);
+    }
+}
+
+void RecvTime(ArgStruct *p, double *t)
+{
+    uint32_t ltime, ntime;
+    int bytesRead;
+
+    bytesRead = readFully(p->commfd, (void *)&ntime, sizeof(uint32_t));
+    if (bytesRead < 0)
+    {
+	printf("NetPIPE: read failed in RecvTime: errno=%d\n", errno);
+	exit(302);
+    }
+    else if (bytesRead != sizeof(uint32_t))
+    {
+	fprintf(stderr, "NetPIPE: partial read in RecvTime of %d bytes\n",
+		bytesRead);
+	exit(303);
+    }
+    ltime = ntohl(ntime);
+
+    /* Result is ltime (in microseconds) divided by 1.0e8 to get seconds */
+
+    *t = (double)ltime / 1.0e8;
+}
+
+void SendRepeat(ArgStruct *p, int rpt)
+{
+    uint32_t lrpt, nrpt;
+
+    lrpt = rpt;
+    /* Send repeat count as a long in network order */
+    nrpt = htonl(lrpt);
+    if (write(p->commfd, (void *) &nrpt, sizeof(uint32_t)) < 0)
+    {
+	printf("NetPIPE: write failed in SendRepeat: errno=%d\n", errno);
+	exit(304);
+    }
+}
+
+void RecvRepeat(ArgStruct *p, int *rpt)
+{
+    uint32_t lrpt, nrpt;
+    int bytesRead;
+
+    bytesRead = readFully(p->commfd, (void *)&nrpt, sizeof(uint32_t));
+    if (bytesRead < 0)
+    {
+	printf("NetPIPE: read failed in RecvRepeat: errno=%d\n", errno);
+	exit(305);
+    }
+    else if (bytesRead != sizeof(uint32_t))
+    {
+	fprintf(stderr, "NetPIPE: partial read in RecvRepeat of %d bytes\n",
+		bytesRead);
+	exit(306);
+    }
+    lrpt = ntohl(nrpt);
+
+    *rpt = lrpt;
+}
+
+void establish(ArgStruct *p)
+{
+    int one = 1;
+    socklen_t clen;
+    struct protoent *proto;
+
+    clen = (socklen_t) sizeof(p->prot.sin2);
+
+    if( p->tr ){
+
+	while( connect(p->commfd, (struct sockaddr *) &(p->prot.sin1),
+		       sizeof(p->prot.sin1)) < 0 ) {
+
+	    /* If we are doing a reset and we get a connection refused from
+	     * the connect() call, assume that the other node has not yet
+	     * gotten to its corresponding accept() call and keep trying until
+	     * we have success.
+	     */
+	    if(!doing_reset || errno != ECONNREFUSED) {
+		printf("Client: Cannot Connect! errno=%d\n",errno);
+		exit(-10);
+	    } 
+        
+	}
+
+    } else if( p->rcv ) {
+
+	/* SERVER */
+	listen(p->servicefd, 5);
+	p->commfd = accept(p->servicefd, (struct sockaddr *) &(p->prot.sin2), &clen);
+
+	if(p->commfd < 0){
+	    printf("Server: Accept Failed! errno=%d\n",errno);
+	    exit(-12);
+	}
+
+	/*
+	  Attempt to set TCP_NODELAY. TCP_NODELAY may or may not be propagated
+	  to accepted sockets.
+	*/
+	if(!(proto = getprotobyname("tcp"))){
+	    printf("unknown protocol!\n");
+	    exit(555);
+	}
+
+	if(setsockopt(p->commfd, proto->p_proto, TCP_NODELAY,
+		      &one, sizeof(one)) < 0)
+	{
+	    printf("setsockopt: TCP_NODELAY failed! errno=%d\n", errno);
+	    exit(556);
+	}
+
+	/* If requested, set the send and receive buffer sizes */
+	if(p->prot.sndbufsz > 0)
+	{
+/*      printf("Send and Receive Buffers on accepted socket set to %d bytes\n",*/
+/*           p->prot.sndbufsz);*/
+	    if(setsockopt(p->commfd, SOL_SOCKET, SO_SNDBUF, &(p->prot.sndbufsz), 
+			  sizeof(p->prot.sndbufsz)) < 0)
+	    {
+		printf("setsockopt: SO_SNDBUF failed! errno=%d\n", errno);
+		exit(556);
+	    }
+	    if(setsockopt(p->commfd, SOL_SOCKET, SO_RCVBUF, &(p->prot.rcvbufsz), 
+			  sizeof(p->prot.rcvbufsz)) < 0)
+	    {
+		printf("setsockopt: SO_RCVBUF failed! errno=%d\n", errno);
+		exit(556);
+	    }
+	}
+    }
+}
+
+void CleanUp(ArgStruct *p)
+{
+    char *quit="QUIT";
+
+    if (p->tr) {
+
+	write(p->commfd,quit, 5);
+	read(p->commfd, quit, 5);
+	close(p->commfd);
+
+    } else if( p->rcv ) {
+
+	read(p->commfd,quit, 5);
+	write(p->commfd,quit,5);
+	close(p->commfd);
+	close(p->servicefd);
+
+    }
+}
+
+
+void Reset(ArgStruct *p)
+{
+  
+    /* Reset sockets */
+
+    if(p->reset_conn) {
+
+	doing_reset = 1;
+
+	/* Close the sockets */
+
+	CleanUp(p);
+
+	/* Now open and connect new sockets */
+
+	Setup(p);
+
+    }
+
+}
+
+void AfterAlignmentInit(ArgStruct *p)
+{
+
+}
+
home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?m2llfj69fe.wl>