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:
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 ovs test utility that allows to do tests between remote hosts
33 import ovstest.args as args
34 import ovstest.rpcserver as rpcserver
36 DEFAULT_TEST_BRIDGE = "ovstestbr0"
37 DEFAULT_TEST_PORT = "ovstestport0"
38 DEFAULT_TEST_TUN = "ovstestport1"
41 def rpc_client(ip, port):
42 return xmlrpclib.Server("http://%s:%u/" % (ip, port), allow_none=True)
45 def sigint_intercept():
47 Intercept SIGINT from child (the local ovs-test server process).
49 signal.signal(signal.SIGINT, signal.SIG_IGN)
52 def start_local_server(port):
54 This function spawns an ovs-test server that listens on specified port
55 and blocks till the spawned ovs-test server is ready to accept XML RPC
58 p = subprocess.Popen(["ovs-test", "-s", str(port)],
59 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
60 preexec_fn = sigint_intercept)
61 fcntl.fcntl( p.stdout.fileno(),fcntl.F_SETFL,
62 fcntl.fcntl(p.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
64 while p.poll() is None:
65 fd = select.select([p.stdout.fileno()], [], [])[0]
67 out = p.stdout.readline()
68 if out.startswith("Starting RPC server"):
70 if p.poll() is not None:
71 raise RuntimeError("Couldn't start local instance of ovs-test server")
75 def get_datagram_sizes(mtu1, mtu2):
77 This function calculates all the "interesting" datagram sizes so that
78 we test both - receive and send side with different packets sizes.
80 s1 = set([8, mtu1 - 100, mtu1 - 28, mtu1])
81 s2 = set([8, mtu2 - 100, mtu2 - 28, mtu2])
82 return sorted(s1.union(s2))
85 def ip_from_cidr(string):
87 This function removes the netmask (if present) from the given string and
88 returns the IP address.
90 token = string.split("/")
94 def bandwidth_to_string(bwidth):
95 """Convert bandwidth from long to string and add units."""
96 bwidth = bwidth * 8 # Convert back to bits/second
97 if bwidth >= 10000000:
98 return str(int(bwidth / 1000000)) + "Mbps"
100 return str(int(bwidth / 1000)) + "Kbps"
102 return str(int(bwidth)) + "bps"
105 def collect_information(node):
106 """Print information about hosts that will do testing"""
107 print "Node %s:%u " % (node[0], node[1])
108 server = rpc_client(node[0], node[1])
109 interface_name = server.get_interface(node[0])
111 uname = server.uname()
114 if not interface_name:
115 print ("Could not find interface that has %s IP address."
116 "Make sure that you specified correct Outer IP." % (node[0]))
118 if server.is_ovs_bridge(interface_name):
119 phys_iface = server.get_iface_from_bridge(interface_name)
121 phys_iface = interface_name
124 driver = server.get_driver(phys_iface)
125 mtu = server.get_interface_mtu(phys_iface)
127 print "Will be using %s (%s) with MTU %u" % (phys_iface, node[0],
130 print "Unable to get driver information from ethtool."
132 print "On this host %s has %s." % (phys_iface, driver)
135 print "Unable to retrieve kernel information. Is this Linux?"
137 print "Running kernel %s." % uname
143 def do_udp_tests(receiver, sender, tbwidth, duration, port_sizes):
144 """Schedule UDP tests between receiver and sender"""
145 server1 = rpc_client(receiver[0], receiver[1])
146 server2 = rpc_client(sender[0], sender[1])
148 udpformat = '{0:>15} {1:>15} {2:>15} {3:>15} {4:>15}'
150 print ("UDP test from %s:%u to %s:%u with target bandwidth %s" %
151 (sender[0], sender[1], receiver[0], receiver[1],
152 bandwidth_to_string(tbwidth)))
153 print udpformat.format("Datagram Size", "Snt Datagrams", "Rcv Datagrams",
154 "Datagram Loss", "Bandwidth")
156 for size in port_sizes:
160 packetcnt = (tbwidth * duration) / size
162 listen_handle = server1.create_udp_listener(receiver[3])
163 if listen_handle == -1:
164 print ("Server could not open UDP listening socket on port"
165 " %u. Try to restart the server.\n" % receiver[3])
167 send_handle = server2.create_udp_sender(
168 (ip_from_cidr(receiver[2]),
169 receiver[3]), packetcnt, size,
172 # Using sleep here because there is no other synchronization source
173 # that would notify us when all sent packets were received
174 time.sleep(duration + 1)
176 rcv_packets = server1.get_udp_listener_results(listen_handle)
177 snt_packets = server2.get_udp_sender_results(send_handle)
179 loss = math.ceil(((snt_packets - rcv_packets) * 10000.0) /
181 bwidth = (rcv_packets * size) / duration
183 print udpformat.format(size, snt_packets, rcv_packets,
184 '%.2f%%' % loss, bandwidth_to_string(bwidth))
186 if listen_handle != -1:
187 server1.close_udp_listener(listen_handle)
188 if send_handle != -1:
189 server2.close_udp_sender(send_handle)
193 def do_tcp_tests(receiver, sender, duration):
194 """Schedule TCP tests between receiver and sender"""
195 server1 = rpc_client(receiver[0], receiver[1])
196 server2 = rpc_client(sender[0], sender[1])
198 tcpformat = '{0:>15} {1:>15} {2:>15}'
199 print "TCP test from %s:%u to %s:%u (full speed)" % (sender[0], sender[1],
200 receiver[0], receiver[1])
201 print tcpformat.format("Snt Bytes", "Rcv Bytes", "Bandwidth")
206 listen_handle = server1.create_tcp_listener(receiver[3])
207 if listen_handle == -1:
208 print ("Server was unable to open TCP listening socket on port"
209 " %u. Try to restart the server.\n" % receiver[3])
211 send_handle = server2.create_tcp_sender(ip_from_cidr(receiver[2]),
212 receiver[3], duration)
214 time.sleep(duration + 1)
216 rcv_bytes = long(server1.get_tcp_listener_results(listen_handle))
217 snt_bytes = long(server2.get_tcp_sender_results(send_handle))
219 bwidth = rcv_bytes / duration
221 print tcpformat.format(snt_bytes, rcv_bytes,
222 bandwidth_to_string(bwidth))
224 if listen_handle != -1:
225 server1.close_tcp_listener(listen_handle)
226 if send_handle != -1:
227 server2.close_tcp_sender(send_handle)
231 def do_l3_tests(node1, node2, bandwidth, duration, ps, type):
233 Do L3 tunneling tests.
235 server1 = rpc_client(node1[0], node1[1])
236 server2 = rpc_client(node2[0], node2[1])
237 servers_with_bridges = []
239 server1.create_bridge(DEFAULT_TEST_BRIDGE)
240 servers_with_bridges.append(server1)
241 server2.create_bridge(DEFAULT_TEST_BRIDGE)
242 servers_with_bridges.append(server2)
244 server1.interface_up(DEFAULT_TEST_BRIDGE)
245 server2.interface_up(DEFAULT_TEST_BRIDGE)
247 server1.interface_assign_ip(DEFAULT_TEST_BRIDGE, node1[2], None)
248 server2.interface_assign_ip(DEFAULT_TEST_BRIDGE, node2[2], None)
250 server1.add_port_to_bridge(DEFAULT_TEST_BRIDGE, DEFAULT_TEST_TUN)
251 server2.add_port_to_bridge(DEFAULT_TEST_BRIDGE, DEFAULT_TEST_TUN)
253 server1.ovs_vsctl_set("Interface", DEFAULT_TEST_TUN, "type",
255 server2.ovs_vsctl_set("Interface", DEFAULT_TEST_TUN, "type",
257 server1.ovs_vsctl_set("Interface", DEFAULT_TEST_TUN, "options",
258 "remote_ip", node2[0])
259 server2.ovs_vsctl_set("Interface", DEFAULT_TEST_TUN, "options",
260 "remote_ip", node1[0])
262 do_udp_tests(node1, node2, bandwidth, duration, ps)
263 do_udp_tests(node2, node1, bandwidth, duration, ps)
264 do_tcp_tests(node1, node2, duration)
265 do_tcp_tests(node2, node1, duration)
268 for server in servers_with_bridges:
269 server.del_bridge(DEFAULT_TEST_BRIDGE)
273 def do_vlan_tests(node1, node2, bandwidth, duration, ps, tag):
275 Do VLAN tests between node1 and node2.
277 server1 = rpc_client(node1[0], node1[1])
278 server2 = rpc_client(node2[0], node2[1])
283 servers_with_test_ports = []
286 interface_node1 = server1.get_interface(node1[0])
287 interface_node2 = server2.get_interface(node2[0])
289 if server1.is_ovs_bridge(interface_node1):
290 br_name1 = interface_node1
292 br_name1 = DEFAULT_TEST_BRIDGE
293 server1.create_test_bridge(br_name1, interface_node1)
295 if server2.is_ovs_bridge(interface_node2):
296 br_name2 = interface_node2
298 br_name2 = DEFAULT_TEST_BRIDGE
299 server2.create_test_bridge(br_name2, interface_node2)
301 server1.add_port_to_bridge(br_name1, DEFAULT_TEST_PORT)
302 servers_with_test_ports.append(server1)
303 server2.add_port_to_bridge(br_name2, DEFAULT_TEST_PORT)
304 servers_with_test_ports.append(server2)
306 server1.ovs_vsctl_set("Port", DEFAULT_TEST_PORT, "tag", None, tag)
307 server2.ovs_vsctl_set("Port", DEFAULT_TEST_PORT, "tag", None, tag)
309 server1.ovs_vsctl_set("Interface", DEFAULT_TEST_PORT, "type", None,
311 server2.ovs_vsctl_set("Interface", DEFAULT_TEST_PORT, "type", None,
314 server1.interface_assign_ip(DEFAULT_TEST_PORT, node1[2], None)
315 server2.interface_assign_ip(DEFAULT_TEST_PORT, node2[2], None)
317 server1.interface_up(DEFAULT_TEST_PORT)
318 server2.interface_up(DEFAULT_TEST_PORT)
320 do_udp_tests(node1, node2, bandwidth, duration, ps)
321 do_udp_tests(node2, node1, bandwidth, duration, ps)
322 do_tcp_tests(node1, node2, duration)
323 do_tcp_tests(node2, node1, duration)
326 for server in servers_with_test_ports:
327 server.del_port_from_bridge(DEFAULT_TEST_PORT)
328 if br_name1 == DEFAULT_TEST_BRIDGE:
329 server1.del_test_bridge(br_name1, interface_node1)
330 if br_name2 == DEFAULT_TEST_BRIDGE:
331 server2.del_test_bridge(br_name2, interface_node2)
334 def do_direct_tests(node1, node2, bandwidth, duration, ps):
336 Do tests between outer IPs without involving Open vSwitch
338 n1 = (node1[0], node1[1], node1[0], node1[3])
339 n2 = (node2[0], node2[1], node2[0], node2[3])
341 do_udp_tests(n1, n2, bandwidth, duration, ps)
342 do_udp_tests(n2, n1, bandwidth, duration, ps)
343 do_tcp_tests(n1, n2, duration)
344 do_tcp_tests(n2, n1, duration)
347 if __name__ == '__main__':
350 ovs_args = args.ovs_initialize_args()
352 if ovs_args.port is not None: # Start in pure server mode
353 rpcserver.start_rpc_server(ovs_args.port)
355 elif ovs_args.servers is not None: # Run in client mode
356 node1 = ovs_args.servers[0]
357 node2 = ovs_args.servers[1]
359 # Verify whether client will need to spawn a local instance of
360 # ovs-test server by looking at the first OuterIP. if it is a
361 # 127.0.0.1 then spawn local ovs-test server.
362 if node1[0] == "127.0.0.1":
363 local_server = start_local_server(node1[1])
364 # We must determine the IP address that local ovs-test server
366 me = rpc_client(node1[0], node1[1])
367 my_ip = me.get_my_address_from(node2[0], node2[1])
368 node1 = (my_ip, node1[1], node1[2], node1[3])
370 mtu_node2 = collect_information(node2)
371 mtu_node1 = collect_information(node1)
373 bandwidth = ovs_args.targetBandwidth
374 interval = ovs_args.testInterval
375 ps = get_datagram_sizes(mtu_node1, mtu_node2)
377 direct = ovs_args.direct
378 vlan_tag = ovs_args.vlanTag
379 tunnel_modes = ovs_args.tunnelModes
381 if direct is not None:
382 print "Performing direct tests"
383 do_direct_tests(node2, node1, bandwidth, interval, ps)
385 if vlan_tag is not None:
386 print "Performing VLAN tests"
387 do_vlan_tests(node2, node1, bandwidth, interval, ps, vlan_tag)
389 for tmode in tunnel_modes:
390 print "Performing", tmode, "tests"
391 do_l3_tests(node2, node1, bandwidth, interval, ps, tmode)
393 except KeyboardInterrupt:
395 except xmlrpclib.Fault:
396 print "Couldn't establish XMLRPC control channel"
398 print "Couldn't establish XMLRPC control channel"
399 except xmlrpclib.ProtocolError:
400 print "XMLRPC control channel was abruptly terminated"
401 except twisted.internet.error.CannotListenError:
402 print "Couldn't start XMLRPC server on port %u" % ovs_args.port
404 if local_server is not None:
405 local_server.terminate()