ovs-test: A new tool that allows to diagnose connectivity and performance issues
[sliver-openvswitch.git] / utilities / ovs-test.in
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"