1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
2024-07-22 01:58:46 -03:00

436 lines
12 KiB
Plaintext
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#! @PYTHON@
#
# Copyright (c) 2010 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import BaseHTTPServer
import getopt
import httplib
import os
import threading
import time
import signal #Causes keyboard interrupts to go to the main thread.
import socket
import sys
print_safe_lock = threading.Lock()
def print_safe(s):
print_safe_lock.acquire()
print(s)
print_safe_lock.release()
def start_thread(target, args):
t = threading.Thread(target=target, args=args)
t.setDaemon(True)
t.start()
return t
#Caller is responsible for catching socket.error exceptions.
def send_packet(key, length, dest_ip, dest_port):
length -= 20 + 8 #IP and UDP headers.
packet = str(key)
packet += chr(0) * (length - len(packet))
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(packet, (dest_ip, dest_port))
sock.close()
#UDP Receiver
class UDPReceiver:
def __init__(self, vlan_ip, vlan_port):
self.vlan_ip = vlan_ip
self.vlan_port = vlan_port
self.recv_callbacks = {}
self.udp_run = False
def recv_packet(self, key, success_callback, timeout_callback):
event = threading.Event()
def timeout_cb():
timeout_callback()
event.set()
timer = threading.Timer(30, timeout_cb)
timer.daemon = True
def success_cb():
timer.cancel()
success_callback()
event.set()
# Start the timer first to avoid a timer.cancel() race condition.
timer.start()
self.recv_callbacks[key] = success_cb
return event
def udp_receiver(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1)
try:
sock.bind((self.vlan_ip, self.vlan_port))
except socket.error, e:
print_safe('Failed to bind to %s:%d with error: %s'
% (self.vlan_ip, self.vlan_port, e))
os._exit(1) #sys.exit only exits the current thread.
while self.udp_run:
try:
data, _ = sock.recvfrom(4096)
except socket.timeout:
continue
except socket.error, e:
print_safe('Failed to receive from %s:%d with error: %s'
% (self.vlan_ip, self.vlan_port, e))
os._exit(1)
data_str = data.split(chr(0))[0]
if not data_str.isdigit():
continue
key = int(data_str)
if key in self.recv_callbacks:
self.recv_callbacks[key]()
del self.recv_callbacks[key]
def start(self):
self.udp_run = True
start_thread(self.udp_receiver, ())
def stop(self):
self.udp_run = False
#Server
vlan_server = None
class VlanServer:
def __init__(self, server_ip, server_port, vlan_ip, vlan_port):
global vlan_server
vlan_server = self
self.server_ip = server_ip
self.server_port = server_port
self.recv_response = '%s:%d:' % (vlan_ip, vlan_port)
self.result = {}
self.result_lock = threading.Lock()
self._test_id = 0
self._test_id_lock = threading.Lock()
self.udp_recv = UDPReceiver(vlan_ip, vlan_port)
def get_test_id(self):
self._test_id_lock.acquire()
self._test_id += 1
ret = self._test_id
self._test_id_lock.release()
return ret
def set_result(self, key, value):
self.result_lock.acquire()
if key not in self.result:
self.result[key] = value
self.result_lock.release()
def recv(self, test_id):
self.udp_recv.recv_packet(test_id,
lambda : self.set_result(test_id, 'Success'),
lambda : self.set_result(test_id, 'Timeout'))
return self.recv_response + str(test_id)
def send(self, test_id, data):
try:
ip, port, size = data.split(':')
port = int(port)
size = int(size)
except ValueError:
self.set_result(test_id,
'Server failed to parse send request: %s' % data)
return
def send_thread():
send_time = 10
for _ in range(send_time * 2):
try:
send_packet(test_id, size, ip, port)
except socket.error, e:
self.set_result(test_id, 'Failure: ' + str(e))
return
time.sleep(.5)
self.set_result(test_id, 'Success')
start_thread(send_thread, ())
return str(test_id)
def run(self):
self.udp_recv.start()
try:
BaseHTTPServer.HTTPServer((self.server_ip, self.server_port),
VlanServerHandler).serve_forever()
except socket.error, e:
print_safe('Failed to start control server: %s' % e)
self.udp_recv.stop()
return 1
class VlanServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
#Guarantee three arguments.
path = (self.path.lower().lstrip('/') + '//').split('/')
resp = 404
body = None
if path[0] == 'start':
test_id = vlan_server.get_test_id()
if path[1] == 'recv':
resp = 200
body = vlan_server.recv(test_id)
elif path[1] == 'send':
resp = 200
body = vlan_server.send(test_id, path[2])
elif (path[0] == 'result'
and path[1].isdigit()
and int(path[1]) in vlan_server.result):
resp = 200
body = vlan_server.result[int(path[1])]
elif path[0] == 'ping':
resp = 200
body = 'pong'
self.send_response(resp)
self.end_headers()
if body:
self.wfile.write(body)
#Client
class VlanClient:
def __init__(self, server_ip, server_port, vlan_ip, vlan_port):
self.server_ip_port = '%s:%d' % (server_ip, server_port)
self.vlan_ip_port = "%s:%d" % (vlan_ip, vlan_port)
self.udp_recv = UDPReceiver(vlan_ip, vlan_port)
def request(self, resource):
conn = httplib.HTTPConnection(self.server_ip_port)
conn.request('GET', resource)
return conn
def send(self, size):
def error_msg(e):
print_safe('Send size %d unsuccessful: %s' % (size, e))
try:
conn = self.request('/start/recv')
data = conn.getresponse().read()
except (socket.error, httplib.HTTPException), e:
error_msg(e)
return False
try:
ip, port, test_id = data.split(':')
port = int(port)
test_id = int(test_id)
except ValueError:
error_msg("Received invalid response from control server (%s)" %
data)
return False
send_time = 5
for _ in range(send_time * 4):
try:
send_packet(test_id, size, ip, port)
resp = self.request('/result/%d' % test_id).getresponse()
data = resp.read()
except (socket.error, httplib.HTTPException), e:
error_msg(e)
return False
if resp.status == 200 and data == 'Success':
print_safe('Send size %d successful' % size)
return True
elif resp.status == 200:
error_msg(data)
return False
time.sleep(.25)
error_msg('Timeout')
return False
def recv(self, size):
def error_msg(e):
print_safe('Receive size %d unsuccessful: %s' % (size, e))
resource = '/start/send/%s:%d' % (self.vlan_ip_port, size)
try:
conn = self.request(resource)
test_id = conn.getresponse().read()
except (socket.error, httplib.HTTPException), e:
error_msg(e)
return False
if not test_id.isdigit():
error_msg('Invalid response %s' % test_id)
return False
success = [False] #Primitive datatypes can't be set from closures.
def success_cb():
success[0] = True
def failure_cb():
success[0] = False
self.udp_recv.recv_packet(int(test_id), success_cb, failure_cb).wait()
if success[0]:
print_safe('Receive size %d successful' % size)
else:
error_msg('Timeout')
return success[0]
def server_up(self):
def error_msg(e):
print_safe('Failed control server connectivity test: %s' % e)
try:
resp = self.request('/ping').getresponse()
data = resp.read()
except (socket.error, httplib.HTTPException), e:
error_msg(e)
return False
if resp.status != 200:
error_msg('Invalid status %d' % resp.status)
elif data != 'pong':
error_msg('Invalid response %s' % data)
return True
def run(self):
if not self.server_up():
return 1
self.udp_recv.start()
success = True
for size in [50, 500, 1000, 1500]:
success = self.send(size) and success
success = self.recv(size) and success
self.udp_recv.stop()
if success:
print_safe('OK')
return 0
else:
print_safe('FAILED')
return 1
def usage():
print_safe("""\
%(argv0)s: Test vlan connectivity
usage: %(argv0)s server vlan
The following options are also available:
-s, --server run in server mode
-h, --help display this help message
-V, --version display version information\
""" % {'argv0': sys.argv[0]})
def main():
try:
options, args = getopt.gnu_getopt(sys.argv[1:], 'hVs',
['help', 'version', 'server'])
except getopt.GetoptError, geo:
print_safe('%s: %s\n' % (sys.argv[0], geo.msg))
return 1
server = False
for key, _ in options:
if key in ['-h', '--help']:
usage()
return 0
elif key in ['-V', '--version']:
print_safe('ovs-vlan-test (Open vSwitch) @VERSION@')
return 0
elif key in ['-s', '--server']:
server = True
else:
print_safe('Unexpected option %s. (use --help for help)' % key)
return 1
if len(args) != 2:
print_safe('Expecting two arguments. (use --help for help)')
return 1
try:
server_ip, server_port = args[0].split(':')
server_port = int(server_port)
except ValueError:
server_ip = args[0]
server_port = 80
try:
vlan_ip, vlan_port = args[1].split(':')
vlan_port = int(vlan_port)
except ValueError:
vlan_ip = args[1]
vlan_port = 15213
if server:
return VlanServer(server_ip, server_port, vlan_ip, vlan_port).run()
else:
return VlanClient(server_ip, server_port, vlan_ip, vlan_port).run()
if __name__ == '__main__':
main_ret = main()
# Python can throw exceptions if threads are running at exit.
for th in threading.enumerate():
if th != threading.currentThread():
th.join()
sys.exit(main_ret)