]>
Commit | Line | Data |
---|---|---|
0be6140a AA |
1 | #! @PYTHON@ |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | # you may not use this file except in compliance with the License. | |
5 | # You may obtain a copy of the License at: | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, | |
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | # See the License for the specific language governing permissions and | |
13 | # limitations under the License. | |
14 | ||
15 | """ | |
16 | ovs test utility that allows to do tests between remote hosts | |
17 | """ | |
18 | ||
19 | import twisted | |
20 | import xmlrpclib | |
21 | import time | |
22 | import socket | |
23 | import math | |
24 | from ovstest import args, rpcserver | |
25 | ||
26 | ||
27 | def bandwidth_to_string(bwidth): | |
28 | """Convert bandwidth from long to string and add units""" | |
29 | bwidth = bwidth * 8 # Convert back to bits/second | |
30 | if bwidth >= 10000000: | |
31 | return str(int(bwidth / 1000000)) + "Mbps" | |
32 | elif bwidth > 10000: | |
33 | return str(int(bwidth / 1000)) + "Kbps" | |
34 | else: | |
35 | return str(int(bwidth)) + "bps" | |
36 | ||
37 | ||
38 | def collect_information(node): | |
39 | """Print information about hosts that will do testing""" | |
40 | print "Node %s:%u " % (node[0], node[1]) | |
41 | server1 = xmlrpclib.Server("http://%s:%u/" % (node[0], node[1])) | |
42 | interface_name = server1.get_interface(node[2]) | |
43 | uname = server1.uname() | |
44 | mtu = 1500 | |
45 | ||
46 | if interface_name == "": | |
47 | print ("Could not find interface that has %s IP address." | |
48 | "Make sure that you specified correct Test IP." % (node[2])) | |
49 | else: | |
50 | mtu = server1.get_interface_mtu(interface_name) | |
51 | driver = server1.get_driver(interface_name) | |
52 | print "Will be using %s(%s) with MTU %u" % (interface_name, node[2], | |
53 | mtu) | |
54 | if driver == "": | |
55 | print "Install ethtool on this host to get NIC driver information" | |
56 | else: | |
57 | print "On this host %s has %s." % (interface_name, driver) | |
58 | ||
59 | if uname == "": | |
60 | print "Unable to retrieve kernel information. Is this Linux?" | |
61 | else: | |
62 | print "Running kernel %s." % uname | |
63 | print "\n" | |
64 | return mtu | |
65 | ||
66 | ||
67 | def do_udp_tests(receiver, sender, tbwidth, duration, sender_mtu): | |
68 | """Schedule UDP tests between receiver and sender""" | |
69 | server1 = xmlrpclib.Server("http://%s:%u/" % (receiver[0], receiver[1])) | |
70 | server2 = xmlrpclib.Server("http://%s:%u/" % (sender[0], sender[1])) | |
71 | ||
72 | udpformat = '{0:>15} {1:>15} {2:>15} {3:>15} {4:>15}' | |
73 | ||
74 | print ("UDP test from %s:%u to %s:%u with target bandwidth %s" % | |
75 | (sender[0], sender[1], receiver[0], receiver[1], | |
76 | bandwidth_to_string(tbwidth))) | |
77 | print udpformat.format("Datagram Size", "Snt Datagrams", "Rcv Datagrams", | |
78 | "Datagram Loss", "Bandwidth") | |
79 | ||
80 | for size in [8, sender_mtu - 100, sender_mtu - 28, sender_mtu]: | |
81 | listen_handle = -1 | |
82 | send_handle = -1 | |
83 | try: | |
84 | packetcnt = (tbwidth * duration) / size | |
85 | ||
86 | listen_handle = server1.create_udp_listener(receiver[3]) | |
87 | if listen_handle == -1: | |
88 | print ("Server could not open UDP listening socket on port" | |
89 | " %u. Try to restart the server.\n" % receiver[3]) | |
90 | return | |
91 | send_handle = server2.create_udp_sender( | |
92 | (receiver[2], receiver[3]), | |
93 | packetcnt, size, duration) | |
94 | ||
95 | #Using sleep here because there is no other synchronization source | |
96 | #that would notify us when all sent packets were received | |
97 | time.sleep(duration + 1) | |
98 | ||
99 | rcv_packets = server1.get_udp_listener_results(listen_handle) | |
100 | snt_packets = server2.get_udp_sender_results(send_handle) | |
101 | ||
102 | loss = math.ceil(((snt_packets - rcv_packets) * 10000.0) / | |
103 | snt_packets) / 100 | |
104 | bwidth = (rcv_packets * size) / duration | |
105 | ||
106 | print udpformat.format(size, snt_packets, rcv_packets, | |
107 | '%.2f%%' % loss, bandwidth_to_string(bwidth)) | |
108 | finally: | |
109 | if listen_handle != -1: | |
110 | server1.close_udp_listener(listen_handle) | |
111 | if send_handle != -1: | |
112 | server2.close_udp_sender(send_handle) | |
113 | print "\n" | |
114 | ||
115 | ||
116 | def do_tcp_tests(receiver, sender, duration): | |
117 | """Schedule TCP tests between receiver and sender""" | |
118 | server1 = xmlrpclib.Server("http://%s:%u/" % (receiver[0], receiver[1])) | |
119 | server2 = xmlrpclib.Server("http://%s:%u/" % (sender[0], sender[1])) | |
120 | ||
121 | tcpformat = '{0:>15} {1:>15} {2:>15}' | |
122 | print "TCP test from %s:%u to %s:%u (full speed)" % (sender[0], sender[1], | |
123 | receiver[0], receiver[1]) | |
124 | print tcpformat.format("Snt Bytes", "Rcv Bytes", "Bandwidth") | |
125 | ||
126 | listen_handle = -1 | |
127 | send_handle = -1 | |
128 | try: | |
129 | listen_handle = server1.create_tcp_listener(receiver[3]) | |
130 | if listen_handle == -1: | |
131 | print ("Server was unable to open TCP listening socket on port" | |
132 | " %u. Try to restart the server.\n" % receiver[3]) | |
133 | return | |
134 | send_handle = server2.create_tcp_sender(receiver[2], receiver[3], | |
135 | duration) | |
136 | ||
137 | time.sleep(duration + 1) | |
138 | ||
139 | rcv_bytes = long(server1.get_tcp_listener_results(listen_handle)) | |
140 | snt_bytes = long(server2.get_tcp_sender_results(send_handle)) | |
141 | ||
142 | bwidth = rcv_bytes / duration | |
143 | ||
144 | print tcpformat.format(snt_bytes, rcv_bytes, | |
145 | bandwidth_to_string(bwidth)) | |
146 | finally: | |
147 | if listen_handle != -1: | |
148 | server1.close_tcp_listener(listen_handle) | |
149 | if send_handle != -1: | |
150 | server2.close_tcp_sender(send_handle) | |
151 | print "\n" | |
152 | ||
153 | ||
154 | if __name__ == '__main__': | |
155 | try: | |
156 | ovs_args = args.ovs_initialize_args() | |
157 | ||
158 | if ovs_args.port is not None: # Start in server mode | |
159 | print "Starting RPC server" | |
160 | try: | |
161 | rpcserver.start_rpc_server(ovs_args.port) | |
162 | except twisted.internet.error.CannotListenError: | |
163 | print "Couldn't start XMLRPC server on port %u" % ovs_args.port | |
164 | ||
165 | elif ovs_args.servers is not None: # Run in client mode | |
166 | node1 = ovs_args.servers[0] | |
167 | node2 = ovs_args.servers[1] | |
168 | bandwidth = ovs_args.targetBandwidth | |
169 | ||
170 | mtu_node1 = collect_information(node1) | |
171 | mtu_node2 = collect_information(node2) | |
172 | ||
173 | do_udp_tests(node1, node2, bandwidth, 5, mtu_node1) | |
174 | do_udp_tests(node2, node1, bandwidth, 5, mtu_node2) | |
175 | do_tcp_tests(node1, node2, 5) | |
176 | do_tcp_tests(node2, node1, 5) | |
177 | except KeyboardInterrupt: | |
178 | pass | |
179 | except socket.error: | |
180 | print "Couldn't establish XMLRPC control channel" |