This might fail if some other process occupies this port after this
function finished but before the neutron-server process started.
"""
- return str(helpers.get_free_namespace_port())
+ return str(helpers.get_free_namespace_port(constants.PROTO_NAME_TCP))
def _generate_api_paste(self):
return c_helpers.find_sample_file('api-paste.ini')
from neutron.agent.common import config
from neutron.agent.linux import ip_lib
from neutron.agent.linux import utils
+from neutron.common import constants
from neutron.tests import tools
CHILD_PROCESS_TIMEOUT = os.environ.get('OS_TEST_CHILD_PROCESS_TIMEOUT', 20)
SS_SOURCE_PORT_PATTERN = re.compile(
r'^.*\s+\d+\s+.*:(?P<port>\d+)\s+[0-9:].*')
+TRANSPORT_PROTOCOLS = (constants.PROTO_NAME_TCP, constants.PROTO_NAME_UDP)
+
class RecursivePermDirFixture(tools.SafeFixture):
"""Ensure at least perms permissions on directory and ancestors."""
current_directory = os.path.dirname(current_directory)
-def get_free_namespace_port(tcp=True, namespace=None):
+def get_free_namespace_port(protocol, namespace=None):
"""Return an unused port from given namespace
WARNING: This function returns a port that is free at the execution time of
is a potential danger that port will be no longer free. It's up to
the programmer to handle error if port is already in use.
- :param tcp: Return free port for TCP protocol if set to True, return free
- port for UDP protocol if set to False
+ :param protocol: Return free port for given protocol. Supported protocols
+ are 'tcp' and 'udp'.
"""
- if tcp:
+ if protocol == constants.PROTO_NAME_TCP:
param = '-tna'
- else:
+ elif protocol == constants.PROTO_NAME_UDP:
param = '-una'
+ else:
+ raise ValueError("Unsupported procotol %s" % protocol)
ip_wrapper = ip_lib.IPWrapper(namespace=namespace)
output = ip_wrapper.netns.execute(['ss', param])
class NetcatTester(object):
TESTING_STRING = 'foo'
-
- def __init__(self, client_namespace, server_namespace, server_address,
- port, client_address=None, udp=False):
+ TCP = constants.PROTO_NAME_TCP
+ UDP = constants.PROTO_NAME_UDP
+
+ def __init__(self, client_namespace, server_namespace, address,
+ dst_port, protocol, server_address='0.0.0.0', src_port=None):
+ """
+ Tool for testing connectivity on transport layer using netcat
+ executable.
+
+ The processes are spawned lazily.
+
+ :param client_namespace: Namespace in which netcat process that
+ connects to other netcat will be spawned
+ :param server_namespace: Namespace in which listening netcat process
+ will be spawned
+ :param address: Server address from client point of view
+ :param dst_port: Port on which netcat listens
+ :param protocol: Transport protocol, either 'tcp' or 'udp'
+ :param server_address: Address in server namespace on which netcat
+ should listen
+ :param src_port: Source port of netcat process spawned in client
+ namespace - packet will have src_port in TCP/UDP
+ header with this value
+
+ """
self.client_namespace = client_namespace
self.server_namespace = server_namespace
self._client_process = None
self._server_process = None
- # Use client_address to specify an address to connect client to that is
- # different from the one that server side is going to listen on (useful
- # when testing floating IPs)
- self.client_address = client_address or server_address
+ self.address = address
self.server_address = server_address
- self.port = str(port)
- self.udp = udp
+ self.dst_port = str(dst_port)
+ self.src_port = str(src_port) if src_port else None
+ if protocol not in TRANSPORT_PROTOCOLS:
+ raise ValueError("Unsupported protocol %s" % protocol)
+ self.protocol = protocol
@property
def client_process(self):
if not self._client_process:
- if not self._server_process:
- self._spawn_server_process()
- self._client_process = self._spawn_nc_in_namespace(
- self.client_namespace,
- address=self.client_address)
+ self.establish_connection()
return self._client_process
@property
address=self.server_address,
listen=True)
+ def establish_connection(self):
+ if self._client_process:
+ raise RuntimeError('%(proto)s connection to $(ip_addr)s is already'
+ ' established' %
+ {'proto': self.protocol,
+ 'ip_addr': self.address})
+
+ if not self._server_process:
+ self._spawn_server_process()
+ self._client_process = self._spawn_nc_in_namespace(
+ self.client_namespace,
+ address=self.address)
+ if self.protocol == self.UDP:
+ # Create an entry in conntrack table for UDP packets
+ self.client_process.writeline(self.TESTING_STRING)
+
def test_connectivity(self, respawn=False):
stop_required = (respawn and self._client_process and
self._client_process.poll() is not None)
return message == self.TESTING_STRING
def _spawn_nc_in_namespace(self, namespace, address, listen=False):
- cmd = ['nc', address, self.port]
- if self.udp:
+ cmd = ['nc', address, self.dst_port]
+ if self.protocol == self.UDP:
cmd.append('-u')
if listen:
cmd.append('-l')
- if not self.udp:
+ if self.protocol == self.TCP:
cmd.append('-k')
else:
cmd.extend(['-w', '20'])
+ if self.src_port:
+ cmd.extend(['-p', self.src_port])
proc = RootHelperProcess(cmd, namespace=namespace)
return proc
from neutron.agent.linux import iptables_manager
from neutron.agent.linux import utils
+from neutron.common import constants
from neutron.tests import base
from neutron.tests.common import machine_fixtures
from neutron.tests.common import net_helpers
self.client_fw, self.server_fw = self.create_firewalls()
# The port is used in isolated namespace that precludes possibility of
# port conflicts
- self.port = helpers.get_free_namespace_port(self.server.namespace)
+ self.port = helpers.get_free_namespace_port(constants.PROTO_NAME_TCP,
+ self.server.namespace)
def create_firewalls(self):
client_iptables = iptables_manager.IptablesManager(
rule = self.PROTOCOL_BLOCK_RULE % protocol
return chain, rule
- def _test_with_nc(self, fw_manager, direction, port, udp):
+ def _test_with_nc(self, fw_manager, direction, port, protocol):
netcat = helpers.NetcatTester(
self.client.namespace, self.server.namespace,
- self.server.ip, self.port, udp=udp)
+ self.server.ip, self.port, protocol)
self.addCleanup(netcat.stop_processes)
- protocol = 'tcp'
- if udp:
- protocol = 'udp'
self.assertTrue(netcat.test_connectivity())
self.filter_add_rule(
fw_manager, self.server.ip, direction, protocol, port)
self.client.assert_ping(self.server.ip)
def test_tcp_input_port(self):
- self._test_with_nc(self.server_fw, 'ingress', self.port, udp=False)
+ self._test_with_nc(self.server_fw, 'ingress', self.port,
+ protocol=helpers.NetcatTester.TCP)
def test_tcp_output_port(self):
- self._test_with_nc(self.client_fw, 'egress', self.port, udp=False)
+ self._test_with_nc(self.client_fw, 'egress', self.port,
+ protocol=helpers.NetcatTester.TCP)
def test_tcp_input(self):
- self._test_with_nc(self.server_fw, 'ingress', port=None, udp=False)
+ self._test_with_nc(self.server_fw, 'ingress', port=None,
+ protocol=helpers.NetcatTester.TCP)
def test_tcp_output(self):
- self._test_with_nc(self.client_fw, 'egress', port=None, udp=False)
+ self._test_with_nc(self.client_fw, 'egress', port=None,
+ protocol=helpers.NetcatTester.TCP)
def test_udp_input_port(self):
- self._test_with_nc(self.server_fw, 'ingress', self.port, udp=True)
+ self._test_with_nc(self.server_fw, 'ingress', self.port,
+ protocol=helpers.NetcatTester.UDP)
def test_udp_output_port(self):
- self._test_with_nc(self.client_fw, 'egress', self.port, udp=True)
+ self._test_with_nc(self.client_fw, 'egress', self.port,
+ protocol=helpers.NetcatTester.UDP)
def test_udp_input(self):
- self._test_with_nc(self.server_fw, 'ingress', port=None, udp=True)
+ self._test_with_nc(self.server_fw, 'ingress', port=None,
+ protocol=helpers.NetcatTester.UDP)
def test_udp_output(self):
- self._test_with_nc(self.client_fw, 'egress', port=None, udp=True)
+ self._test_with_nc(self.client_fw, 'egress', port=None,
+ protocol=helpers.NetcatTester.UDP)
class IptablesManagerNonRootTestCase(base.BaseTestCase):
router_info = self.generate_router_info(enable_ha=False)
router = self.manage_router(self.agent, router_info)
- port = helpers.get_free_namespace_port(router.ns_name)
+ port = helpers.get_free_namespace_port(l3_constants.PROTO_NAME_TCP,
+ router.ns_name)
client_address = '19.4.4.3'
server_address = '35.4.0.4'
router_ns = ip_lib.IPWrapper(namespace=router.ns_name)
netcat = helpers.NetcatTester(router.ns_name, router.ns_name,
- server_address, port,
- client_address=client_address,
- udp=False)
+ client_address, port,
+ protocol=helpers.NetcatTester.TCP)
self.addCleanup(netcat.stop_processes)
def assert_num_of_conntrack_rules(n):
self._add_fip(router, dst_fip, fixed_address=dst_machine.ip)
router.process(self.agent)
- protocol_port = helpers.get_free_namespace_port(dst_machine.namespace)
+ protocol_port = helpers.get_free_namespace_port(
+ l3_constants.PROTO_NAME_TCP, dst_machine.namespace)
# client sends to fip
netcat = helpers.NetcatTester(
src_machine.namespace, dst_machine.namespace,
- dst_machine.ip, protocol_port, client_address=dst_fip,
- udp=False)
+ dst_fip, protocol_port,
+ protocol=helpers.NetcatTester.TCP)
self.addCleanup(netcat.stop_processes)
self.assertTrue(netcat.test_connectivity())