32 import netifaces
as ni
38 from netifaces
import AF_INET
41 from tc_utils
import *
44 def tcp_rx_loop(clientSock, serverSock, size, ip_da, tcp_dp, count, verbose=False):
45 """TCP Rx Single-Thread Loop.
46 Requests the FPGA to send 'count' segments of 'size' bytes and expect the HOST to receive
47 them on the socket (ip_da, tcp_port). Each segment is made of the following repetitive
48 pattern '48692066726f6d200x464d4b553630210a' which decodes into "Hi from FMKU60\n".
49 :param clientSock The socket to send to.
50 :param serverSock The socket to receive from.
51 :param size The size of the expected segment.
52 :param ip_da The destination address of the host.
53 :param tcp_dp The destination port of the host.
54 :param count The number of segments to receive.
55 :param verbose Enables verbosity.
58 print(
"[INFO] Requesting the FPGA to send %d segments of %d bytes on TCP port number %d." % (count, size, tcp_dp))
61 totalReceivedBytes = 0
65 clientSock.settimeout(5)
66 clientSock.setblocking(
False)
67 serverSock.settimeout(5)
68 serverSock.setblocking(
False)
73 reqMsgAsBytes = struct.pack(
">IHH", ip_da, tcp_dp, size)
75 print(
"[DEBUG] >>> reqMsgAsBytes = %s" % reqMsgAsBytes)
77 startTime = datetime.datetime.now()
82 clientSock.sendall(reqMsgAsBytes)
83 except socket.error
as exception:
85 print(
"[EXCEPTION] Socket error while transmitting :: %s" % exception)
94 while currRxByteCnt < size:
96 data = serverSock.recv(MTU)
102 if e.errno != errno.EAGAIN
and e.errno != errno.EWOULDBLOCK:
103 print(
'\n[ERROR] Socket reading error: {}'.format(
str(e)))
106 if nonBlockingTrials > 100000:
107 print(
'\n[ERROR] Too many socket read attempts ({:d})'.format(nonBlockingTrials))
110 nonBlockingTrials += 1
111 if verbose
and (nonBlockingTrials % 100 == 0):
115 except socket.error
as exc:
117 print(
"\n[EXCEPTION] Socket error while receiving :: %s" % exc)
120 currRxByteCnt += len(data)
122 print(
"\n[INFO] Loop=%6d | RxBytes=%3d | " % (loop, len(data)))
123 print(
"RxData=%s" % data)
125 nonBlockingTrials = 0
128 totalReceivedBytes += currRxByteCnt
130 endTime = datetime.datetime.now()
131 elapseTime = endTime - startTime
133 if totalReceivedBytes < 1000000:
134 print(
"[INFO] Received a total of %d bytes." % totalReceivedBytes)
135 elif totalReceivedBytes < 1000000000:
136 megaBytes = (totalReceivedBytes * 1.0) / (1024 * 1024 * 1.0)
137 print(
"[INFO] Received a total of %.1f MB." % megaBytes)
139 gigaBytes = (totalReceivedBytes * 1.0) / (1024 * 1024 * 1024 * 1.0)
140 print(
"[INFO] Transferred a total of %.1f GB." % gigaBytes)
142 bandwidth = (totalReceivedBytes * 8 * 1.0) / (elapseTime.total_seconds() * 1024 * 1024)
143 print(
"#####################################################")
145 print(
"#### TCP Rx DONE with bandwidth = %6.1f Mb/s" % bandwidth)
147 bandwidth = bandwidth / 1000
148 print(
"#### TCP Rx DONE with bandwidth = %2.1f Gb/s" % bandwidth)
149 if (totalReceivedBytes != (size * count)):
150 print(
"#### [WARNING] TCP data loss = %.1f%%" % (100 - (totalReceivedBytes) / (size * count)))
152 print(
"#####################################################")
156 def tcp_rx_ramp(clientSock, serverSock, ip_da, tcp_dp, verbose=False, start=1, end=0xFFFF):
157 """TCP Rx Single-Thread Ramp.
158 Requests the FPGA to send 'start'-'end' number of segments to the HOST, each segment with an
159 increasing number of bytes from 'start' to 'end'. Expect the HOST to receive the segments
160 on the socket (ip_da, tcp_port). Each segment is made of the following repetitive pattern
161 pattern '48692066726f6d200x464d4b553630210a' which decodes into "Hi from FMKU60\n".
162 :param clientSock The socket to send to.
163 :param serverSock The socket to receive from.
164 :param ip_da The destination address of the host
165 :param tcp_dp The destination port of the host.
166 :param verbose Enables verbosity.
167 :param start The start size of the ramp (in bytes).
168 :param end The end size of the ramp (in bytes).
171 print(
"[INFO] Requesting the FPGA to send a ramp of segments of increasing size from %d to %d bytes." % (
175 totalReceivedBytes = 0
179 clientSock.settimeout(5)
180 clientSock.setblocking(
False)
181 serverSock.settimeout(5)
182 serverSock.setblocking(
False)
184 startTime = datetime.datetime.now()
186 for size
in range(start, end+1):
191 reqMsgAsBytes = struct.pack(
">IHH", ip_da, tcp_dp, size)
193 print(
"[DEBUG] Requesting a segment of size=%d bytes (reqMsgAsBytes = %s)" % (size, reqMsgAsBytes))
198 clientSock.sendall(reqMsgAsBytes)
199 except socket.error
as exception:
201 print(
"[EXCEPTION] Socket error while transmitting :: %s" % exception)
209 nonBlockingTrials = 0
210 while currRxByteCnt < size:
212 data = serverSock.recv(MTU)
218 if e.errno != errno.EAGAIN
and e.errno != errno.EWOULDBLOCK:
219 print(
'[ERROR] Socket reading error: {}'.format(
str(e)))
222 if nonBlockingTrials > 1000000:
223 print(
'\n[ERROR] Too many socket read attempts ({:d})'.format(nonBlockingTrials))
227 nonBlockingTrials += 1
228 if verbose
and (nonBlockingTrials % 100 == 0):
232 except socket.error
as exc:
234 print(
"[EXCEPTION] Socket error while receiving :: %s" % exc)
237 currRxByteCnt += len(data)
239 print(
"[INFO] ReqBytes=%d | RxBytes=%d\n" % (size, len(data)))
240 print(
"RxData=%s\n" % data)
242 nonBlockingTrials = 0
245 totalReceivedBytes += currRxByteCnt
247 endTime = datetime.datetime.now()
248 elapseTime = endTime - startTime
250 if totalReceivedBytes < 1000000:
251 print(
"[INFO] Received a total of %d bytes." % totalReceivedBytes)
252 elif totalReceivedBytes < 1000000000:
253 megaBytes = (totalReceivedBytes * 1.0) / (1024 * 1024 * 1.0)
254 print(
"[INFO] Received a total of %.1f MB." % megaBytes)
256 gigaBytes = (totalReceivedBytes * 1.0) / (1024 * 1024 * 1024 * 1.0)
257 print(
"[INFO] Transferred a total of %.1f GB." % gigaBytes)
259 bandwidth = (totalReceivedBytes * 8 * 1.0) / (elapseTime.total_seconds() * 1024 * 1024)
260 print(
"#####################################################")
262 print(
"#### TCP Rx DONE with bandwidth = %6.1f Mb/s" % bandwidth)
264 bandwidth = bandwidth / 1000
265 print(
"#### TCP Rx DONE with bandwidth = %2.1f Gb/s" % bandwidth)
266 if totalReceivedBytes != (end-start+1)*(start+end)/2:
267 print(
"#### [WARNING] TCP data loss = %.1f%%" % (100 - (totalReceivedBytes) / (size * count)))
268 print(
"#####################################################")
280 parser = argparse.ArgumentParser(description=
'A script to receive TCP data from an FPGA module.')
281 parser.add_argument(
'-fi',
'--fpga_ipv4', type=str, default=
'',
282 help=
'The IPv4 address of the FPGA (a.k.a image_ip / e.g. 10.12.200.163)')
283 parser.add_argument(
'-ii',
'--inst_id', type=int, default=0,
284 help=
'The instance ID assigned by the cloudFPGA Resource Manager (e.g. 42)')
285 parser.add_argument(
'-lc',
'--loop_count', type=int, default=10,
286 help=
'The number of test runs (default is 10)')
287 parser.add_argument(
'-mi',
'--mngr_ipv4', type=str, default=
'10.12.0.132',
288 help=
'The IPv4 address of the cloudFPGA Resource Manager (default is 10.12.0.132)')
289 parser.add_argument(
'-mp',
'--mngr_port', type=int, default=8080,
290 help=
'The TCP port of the cloudFPGA Resource Manager (default is 8080)')
291 parser.add_argument(
'-sd',
'--seed', type=int, default=-1,
292 help=
'The initial number to seed the pseudorandom number generator.')
293 parser.add_argument(
'-sz',
'--size', type=int, default=-1,
294 help=
'The size of the datagram to receive.')
295 parser.add_argument(
'-un',
'--user_name', type=str, default=
'',
296 help=
'A user-name as used to log in ZYC2 (.e.g \'fab\')')
297 parser.add_argument(
'-up',
'--user_passwd', type=str, default=
'',
298 help=
'The ZYC2 password attached to the user-name')
299 parser.add_argument(
'-v',
'--verbose', action=
"store_true",
300 help=
'Enable verbosity')
302 args = parser.parse_args()
304 if args.user_name ==
'' or args.user_passwd ==
'':
305 print(
"\n[WARNING] You must provide a ZYC2 user name and the corresponding password for this script to execute.\n")
322 portFpgaServer = XMIT_MODE_LSN_PORT
330 restartApp(instId, ipResMngr, portResMngr, args.user_name, args.user_passwd)
338 fpgaServerAssociation = (
str(ipFpga), portFpgaServer)
343 tcpClientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
344 except Exception
as exc:
345 print(
"[EXCEPTION] %s" % exc)
350 tcpClientSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
351 tcpClientSock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
True)
356 tcpClientSock.connect(fpgaServerAssociation)
357 print(
"[INFO] Connecting host client to FPGA server socket ", fpgaServerAssociation)
358 except Exception
as exc:
359 print(
"[EXCEPTION] %s" % exc)
362 print(
"[INFO] \tStatus --> Successful connection.")
366 hostname = socket.gethostname()
367 ipHostStr = socket.gethostbyname(hostname)
368 if ipHostStr.startswith(
'9.4.'):
370 for itf
in ni.interfaces():
372 if itf.startswith(
'tun'):
373 ip4Str = ni.ifaddresses(itf)[AF_INET][0][
'addr']
374 if ip4Str.startswith(
'10.2.'):
380 print(
"[ERROR] Could not find IPv4 address of the tunnel associated with the user-VPN.\n")
382 ipHost =
int(ipaddress.IPv4Address(ipHostStr))
384 print(
"[INFO] Hostname = %s | IP is %s (0x%8.8X)" % (hostname, ipHostStr, ipHost))
386 hostListenAssociation = (
str(ipHostStr), dpHost)
392 tcpListenSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
393 except Exception
as exc:
394 print(
"[EXCEPTION] %s" % exc)
396 tcpListenSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
407 tcpListenSock.bind(hostListenAssociation)
408 print(
"[INFO] Binding and start listening on host socket ", hostListenAssociation)
409 except Exception
as exc:
410 print(
"[EXCEPTION] %s" % exc)
412 tcpListenSock.listen(1)
418 ipHost =
int(ipaddress.IPv4Address(ipHostStr))
419 reqMsgAsBytes = struct.pack(
">IHH", ipHost, dpHost, 0)
420 print(
"[INFO] Requesting the remote FPGA client to open a connection with the host")
421 print(
"[DEBUG] With message = reqMsgAsBytes = %s" % reqMsgAsBytes)
423 tcpClientSock.sendall(reqMsgAsBytes)
424 except socket.error
as exception:
426 print(
"[EXCEPTION] Socket error while transmitting :: %s" % exception)
433 print(
"[INFO] Waiting for a connection from remote FPGA")
439 tcpListenSock.settimeout(10)
440 print(
"[INFO] tcpListenSock.timeout=10")
441 tcpServerSock, fpgaClientAssociation = tcpListenSock.accept()
442 except socket.error
as exception:
444 print(
"[EXCEPTION] Socket error while waiting for a connection from remote FPGA :: %s" % exception)
449 print(
"[INFO] Received a connection from FPGA socket address ", fpgaClientAssociation)
454 print(
"[INFO] Testcase `%s` is run with:" % (os.path.basename(__file__)))
458 seed = random.randint(0, 100000)
460 print(
"\t\t seed = %d" % seed)
463 TODO_MAX_SEG_SIZE = 2048
466 size = random.randint(1, TODO_MAX_SEG_SIZE)
467 elif size > TODO_MAX_SEG_SIZE:
469 print(
"[ERROR] This test limits the size of the received segments to %d bytes.\n" % TODO_MAX_SEG_SIZE)
472 print(
"\t\t size = %d" % size)
474 count = args.loop_count
476 print(
"\t\t loop = %d" % count)
478 verbose = args.verbose
482 print(
"[INFO] This testcase is sending traffic from FPGA-to-HOST.")
483 print(
"[INFO] This run is executed in single-threading mode.\n")
486 tcp_rx_ramp(tcpClientSock, tcpServerSock, ipHost, dpHost, args.verbose, 1, 10)
487 tcp_rx_ramp(tcpClientSock, tcpServerSock, ipHost, dpHost, args.verbose, 11, 100)
488 tcp_rx_ramp(tcpClientSock, tcpServerSock, ipHost, dpHost, args.verbose, 101, 1000)
489 tcp_rx_ramp(tcpClientSock, tcpServerSock, ipHost, dpHost, args.verbose, 1001, 2048)
491 tcp_rx_loop(tcpClientSock, tcpServerSock, size, ipHost, dpHost, count, args.verbose)
496 tcpClientSock.close()
497 tcpServerSock.close()
498 tcpListenSock.close()
def tcp_rx_ramp(clientSock, serverSock, ip_da, tcp_dp, verbose=False, start=1, end=0xFFFF)
def tcp_rx_loop(clientSock, serverSock, size, ip_da, tcp_dp, count, verbose=False)
def restartApp(instId, ipResMngr, portResMngr, user_name, user_passwd)
def getResourceManagerIpv4(args)
def getResourceManagerPort(args)