Merge "[OpenSwan] Enable usage of the MTU value of an IPSec connection"
This commit is contained in:
commit
d399aa8972
@ -28,6 +28,11 @@ conn {{ipsec_site_connection.id}}
|
|||||||
# [subnet]
|
# [subnet]
|
||||||
leftsubnet={{vpnservice.subnet.cidr}}
|
leftsubnet={{vpnservice.subnet.cidr}}
|
||||||
# leftsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
# leftsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
||||||
|
# [updown]
|
||||||
|
# What "updown" script to run to adjust routing and/or firewalling when
|
||||||
|
# the status of the connection changes (default "ipsec _updown").
|
||||||
|
# "--route yes" allows to specify such routing options as mtu and metric.
|
||||||
|
leftupdown="ipsec _updown --route yes"
|
||||||
######################
|
######################
|
||||||
# ipsec_site_connections
|
# ipsec_site_connections
|
||||||
######################
|
######################
|
||||||
@ -39,8 +44,7 @@ conn {{ipsec_site_connection.id}}
|
|||||||
rightsubnets={ {{ipsec_site_connection['peer_cidrs']|join(' ')}} }
|
rightsubnets={ {{ipsec_site_connection['peer_cidrs']|join(' ')}} }
|
||||||
# rightsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
# rightsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
||||||
# [mtu]
|
# [mtu]
|
||||||
# Note It looks like not supported in the strongswan driver
|
mtu={{ipsec_site_connection.mtu}}
|
||||||
# ignore it now
|
|
||||||
# [dpd_action]
|
# [dpd_action]
|
||||||
dpdaction={{ipsec_site_connection.dpd_action}}
|
dpdaction={{ipsec_site_connection.dpd_action}}
|
||||||
# [dpd_interval]
|
# [dpd_interval]
|
||||||
|
@ -155,14 +155,13 @@ def get_ovs_bridge(br_name):
|
|||||||
return ovs_lib.OVSBridge(br_name)
|
return ovs_lib.OVSBridge(br_name)
|
||||||
|
|
||||||
|
|
||||||
class TestIPSecScenario(base.BaseSudoTestCase):
|
class TestIPSecBase(base.BaseSudoTestCase):
|
||||||
|
|
||||||
vpn_agent_ini = os.environ.get('VPN_AGENT_INI',
|
vpn_agent_ini = os.environ.get('VPN_AGENT_INI',
|
||||||
'/etc/neutron/vpn_agent.ini')
|
'/etc/neutron/vpn_agent.ini')
|
||||||
NESTED_NAMESPACE_SEPARATOR = '@'
|
NESTED_NAMESPACE_SEPARATOR = '@'
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestIPSecScenario, self).setUp()
|
super(TestIPSecBase, self).setUp()
|
||||||
mock.patch('neutron.agent.l3.agent.L3PluginApi').start()
|
mock.patch('neutron.agent.l3.agent.L3PluginApi').start()
|
||||||
# avoid report_status running periodically
|
# avoid report_status running periodically
|
||||||
mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall').start()
|
mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall').start()
|
||||||
@ -172,7 +171,12 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
# root_helper_daemon and instead use root_helper
|
# root_helper_daemon and instead use root_helper
|
||||||
# https://bugs.launchpad.net/neutron/+bug/1482622
|
# https://bugs.launchpad.net/neutron/+bug/1482622
|
||||||
cfg.CONF.set_override('root_helper_daemon', None, group='AGENT')
|
cfg.CONF.set_override('root_helper_daemon', None, group='AGENT')
|
||||||
|
|
||||||
|
self.fake_vpn_service = copy.deepcopy(FAKE_VPN_SERVICE)
|
||||||
|
self.fake_ipsec_connection = copy.deepcopy(FAKE_IPSEC_CONNECTION)
|
||||||
|
|
||||||
self.vpn_agent = self._configure_agent('agent1')
|
self.vpn_agent = self._configure_agent('agent1')
|
||||||
|
self.driver = self.vpn_agent.device_drivers[0]
|
||||||
|
|
||||||
def connect_agents(self, agent1, agent2):
|
def connect_agents(self, agent1, agent2):
|
||||||
"""Simulate both agents in the same host.
|
"""Simulate both agents in the same host.
|
||||||
@ -301,7 +305,7 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
return agent.router_info[router['id']]
|
return agent.router_info[router['id']]
|
||||||
|
|
||||||
def prepare_vpn_service_info(self, router_id, external_ip, subnet_cidr):
|
def prepare_vpn_service_info(self, router_id, external_ip, subnet_cidr):
|
||||||
service = copy.deepcopy(FAKE_VPN_SERVICE)
|
service = copy.deepcopy(self.fake_vpn_service)
|
||||||
service.update({
|
service.update({
|
||||||
'id': _uuid(),
|
'id': _uuid(),
|
||||||
'router_id': router_id,
|
'router_id': router_id,
|
||||||
@ -310,7 +314,7 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
return service
|
return service
|
||||||
|
|
||||||
def prepare_ipsec_conn_info(self, vpn_service, peer_vpn_service):
|
def prepare_ipsec_conn_info(self, vpn_service, peer_vpn_service):
|
||||||
ipsec_conn = copy.deepcopy(FAKE_IPSEC_CONNECTION)
|
ipsec_conn = copy.deepcopy(self.fake_ipsec_connection)
|
||||||
ipsec_conn.update({
|
ipsec_conn.update({
|
||||||
'id': _uuid(),
|
'id': _uuid(),
|
||||||
'vpnservice_id': vpn_service['id'],
|
'vpnservice_id': vpn_service['id'],
|
||||||
@ -402,8 +406,7 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
break
|
break
|
||||||
return pm.active
|
return pm.active
|
||||||
|
|
||||||
def test_ipsec_site_connections(self):
|
def _create_ipsec_site_connection(self, l3ha=False):
|
||||||
device = self.vpn_agent.device_drivers[0]
|
|
||||||
# Mock the method below because it causes Exception:
|
# Mock the method below because it causes Exception:
|
||||||
# RuntimeError: Second simultaneous read on fileno 5 detected.
|
# RuntimeError: Second simultaneous read on fileno 5 detected.
|
||||||
# Unless you really know what you're doing, make sure that only
|
# Unless you really know what you're doing, make sure that only
|
||||||
@ -414,32 +417,49 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
ip_lib.send_ip_addr_adv_notif = mock.Mock()
|
ip_lib.send_ip_addr_adv_notif = mock.Mock()
|
||||||
# There are no vpn services yet. get_vpn_services_on_host returns
|
# There are no vpn services yet. get_vpn_services_on_host returns
|
||||||
# empty list
|
# empty list
|
||||||
device.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
self.driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
||||||
return_value=[])
|
return_value=[])
|
||||||
# instantiate network resources "router", "private network"
|
# instantiate network resources "router", "private network"
|
||||||
private_nets = list(PRIVATE_NET.subnet(24))
|
private_nets = list(PRIVATE_NET.subnet(24))
|
||||||
site1 = self.site_setup(PUBLIC_NET[4], private_nets[1])
|
site1 = self.site_setup(PUBLIC_NET[4], private_nets[1])
|
||||||
site2 = self.site_setup(PUBLIC_NET[5], private_nets[2])
|
if l3ha:
|
||||||
|
site2 = self.setup_ha_routers(PUBLIC_NET[5], private_nets[2])
|
||||||
|
else:
|
||||||
|
site2 = self.site_setup(PUBLIC_NET[5], private_nets[2])
|
||||||
# build vpn resources
|
# build vpn resources
|
||||||
self.prepare_ipsec_conn_info(site1['vpn_service'],
|
self.prepare_ipsec_conn_info(site1['vpn_service'],
|
||||||
site2['vpn_service'])
|
site2['vpn_service'])
|
||||||
self.prepare_ipsec_conn_info(site2['vpn_service'],
|
self.prepare_ipsec_conn_info(site2['vpn_service'],
|
||||||
site1['vpn_service'])
|
site1['vpn_service'])
|
||||||
|
|
||||||
device.report_status = mock.Mock()
|
self.driver.report_status = mock.Mock()
|
||||||
device.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
self.driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
||||||
return_value=[site1['vpn_service'],
|
return_value=[site1['vpn_service'],
|
||||||
site2['vpn_service']])
|
site2['vpn_service']])
|
||||||
|
if l3ha:
|
||||||
|
self.failover_agent_driver.agent_rpc.get_vpn_services_on_host = (
|
||||||
|
mock.Mock(return_value=[]))
|
||||||
|
self.failover_agent_driver.report_status = mock.Mock()
|
||||||
|
self.failover_agent_driver.agent_rpc.get_vpn_services_on_host = (
|
||||||
|
mock.Mock(return_value=[site2['vpn_service']]))
|
||||||
|
|
||||||
|
return site1, site2
|
||||||
|
|
||||||
|
|
||||||
|
class TestIPSecScenario(TestIPSecBase):
|
||||||
|
|
||||||
|
def test_ipsec_site_connections(self):
|
||||||
|
site1, site2 = self._create_ipsec_site_connection()
|
||||||
|
|
||||||
net_helpers.assert_no_ping(site1['port_namespace'], site2['port_ip'],
|
net_helpers.assert_no_ping(site1['port_namespace'], site2['port_ip'],
|
||||||
timeout=8, count=4)
|
timeout=8, count=4)
|
||||||
net_helpers.assert_no_ping(site2['port_namespace'], site1['port_ip'],
|
net_helpers.assert_no_ping(site2['port_namespace'], site1['port_ip'],
|
||||||
timeout=8, count=4)
|
timeout=8, count=4)
|
||||||
|
|
||||||
device.sync(mock.Mock(), [{'id': site1['router'].router_id},
|
self.driver.sync(mock.Mock(), [{'id': site1['router'].router_id},
|
||||||
{'id': site2['router'].router_id}])
|
{'id': site2['router'].router_id}])
|
||||||
self.addCleanup(
|
self.addCleanup(
|
||||||
device._delete_vpn_processes,
|
self.driver._delete_vpn_processes,
|
||||||
[site1['router'].router_id, site2['router'].router_id], [])
|
[site1['router'].router_id, site2['router'].router_id], [])
|
||||||
|
|
||||||
net_helpers.assert_ping(site1['port_namespace'], site2['port_ip'],
|
net_helpers.assert_ping(site1['port_namespace'], site2['port_ip'],
|
||||||
@ -466,39 +486,14 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
self.connect_agents(self.vpn_agent, self.failover_agent)
|
self.connect_agents(self.vpn_agent, self.failover_agent)
|
||||||
|
|
||||||
vpn_agent_driver = self.vpn_agent.device_drivers[0]
|
vpn_agent_driver = self.vpn_agent.device_drivers[0]
|
||||||
failover_agent_driver = self.failover_agent.device_drivers[0]
|
self.failover_agent_driver = self.failover_agent.device_drivers[0]
|
||||||
ip_lib.send_ip_addr_adv_notif = mock.Mock()
|
|
||||||
|
|
||||||
# There are no vpn services yet. get_vpn_services_on_host returns
|
site1, site2 = self._create_ipsec_site_connection(l3ha=True)
|
||||||
# empty list
|
|
||||||
vpn_agent_driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
|
||||||
return_value=[])
|
|
||||||
failover_agent_driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
|
||||||
return_value=[])
|
|
||||||
|
|
||||||
# instantiate network resources "router", "private network"
|
|
||||||
private_nets = list(PRIVATE_NET.subnet(24))
|
|
||||||
site1 = self.site_setup(PUBLIC_NET[4], private_nets[1])
|
|
||||||
site2 = self.setup_ha_routers(PUBLIC_NET[5], private_nets[2])
|
|
||||||
router = site1['router']
|
router = site1['router']
|
||||||
router1 = site2['router1']
|
router1 = site2['router1']
|
||||||
router2 = site2['router2']
|
router2 = site2['router2']
|
||||||
|
|
||||||
# build vpn resources
|
|
||||||
self.prepare_ipsec_conn_info(site1['vpn_service'],
|
|
||||||
site2['vpn_service'])
|
|
||||||
self.prepare_ipsec_conn_info(site2['vpn_service'],
|
|
||||||
site1['vpn_service'])
|
|
||||||
|
|
||||||
vpn_agent_driver.report_status = mock.Mock()
|
|
||||||
failover_agent_driver.report_status = mock.Mock()
|
|
||||||
|
|
||||||
vpn_agent_driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
|
||||||
return_value=[site1['vpn_service'],
|
|
||||||
site2['vpn_service']])
|
|
||||||
failover_agent_driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
|
||||||
return_value=[site2['vpn_service']])
|
|
||||||
|
|
||||||
# No ipsec connection between legacy router and HA routers
|
# No ipsec connection between legacy router and HA routers
|
||||||
net_helpers.assert_no_ping(site1['port_namespace'], site2['port_ip'],
|
net_helpers.assert_no_ping(site1['port_namespace'], site2['port_ip'],
|
||||||
timeout=8, count=4)
|
timeout=8, count=4)
|
||||||
@ -508,7 +503,8 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
# sync the routers
|
# sync the routers
|
||||||
vpn_agent_driver.sync(mock.Mock(), [{'id': router.router_id},
|
vpn_agent_driver.sync(mock.Mock(), [{'id': router.router_id},
|
||||||
{'id': router1.router_id}])
|
{'id': router1.router_id}])
|
||||||
failover_agent_driver.sync(mock.Mock(), [{'id': router1.router_id}])
|
self.failover_agent_driver.sync(mock.Mock(),
|
||||||
|
[{'id': router1.router_id}])
|
||||||
|
|
||||||
self.addCleanup(
|
self.addCleanup(
|
||||||
vpn_agent_driver._delete_vpn_processes,
|
vpn_agent_driver._delete_vpn_processes,
|
||||||
@ -529,7 +525,8 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
|||||||
|
|
||||||
# wait until ipsec process running in failover agent's HA router
|
# wait until ipsec process running in failover agent's HA router
|
||||||
# check for both strongswan and openswan processes
|
# check for both strongswan and openswan processes
|
||||||
path = failover_agent_driver.processes[router2.router_id].config_dir
|
path = self.failover_agent_driver.processes[
|
||||||
|
router2.router_id].config_dir
|
||||||
pid_files = ['%s/var/run/charon.pid' % path,
|
pid_files = ['%s/var/run/charon.pid' % path,
|
||||||
'%s/var/run/pluto.pid' % path]
|
'%s/var/run/pluto.pid' % path]
|
||||||
linux_utils.wait_until_true(
|
linux_utils.wait_until_true(
|
||||||
|
@ -20,16 +20,34 @@
|
|||||||
# functional test for the OpenSwan reference implementation. For now, just
|
# functional test for the OpenSwan reference implementation. For now, just
|
||||||
# ignore the test cases herein.
|
# ignore the test cases herein.
|
||||||
|
|
||||||
from neutron.tests.functional import base
|
import mock
|
||||||
|
from neutron.agent.linux import ip_lib
|
||||||
|
from neutron.agent.linux import utils as linux_utils
|
||||||
|
|
||||||
|
from neutron_vpnaas.tests.functional.common import test_scenario
|
||||||
|
|
||||||
|
|
||||||
class TestOpenSwanDeviceDriver(base.BaseSudoTestCase):
|
class TestOpenSwanDeviceDriver(test_scenario.TestIPSecBase):
|
||||||
|
|
||||||
"""Test the OpenSwan reference implmentation of the device driver."""
|
"""Test the OpenSwan reference implementation of the device driver."""
|
||||||
|
|
||||||
# NOTE: Tests may be added/removed/changed, when this is fleshed out
|
# NOTE: Tests may be added/removed/changed, when this is fleshed out
|
||||||
# in future commits.
|
# in future commits.
|
||||||
|
|
||||||
|
def _ping_mtu(self, namespace, ip, size):
|
||||||
|
"""Pings ip address using packets of given size and with DF=1.
|
||||||
|
|
||||||
|
In order to ping it uses following cli command:
|
||||||
|
ip netns exec <namespace> ping -c 4 -M do -s <size> <ip>
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
cmd = ['ping', '-c', 4, '-M', 'do', '-s', size, ip]
|
||||||
|
cmd = ip_lib.add_namespace_to_cmd(cmd, namespace)
|
||||||
|
linux_utils.execute(cmd, run_as_root=True)
|
||||||
|
return True
|
||||||
|
except RuntimeError:
|
||||||
|
return False
|
||||||
|
|
||||||
def test_config_files_created_on_ipsec_connection_create(self):
|
def test_config_files_created_on_ipsec_connection_create(self):
|
||||||
"""Verify that directory and config files are correct on create."""
|
"""Verify that directory and config files are correct on create."""
|
||||||
pass
|
pass
|
||||||
@ -64,3 +82,30 @@ class TestOpenSwanDeviceDriver(base.BaseSudoTestCase):
|
|||||||
def test_status_reporting(self):
|
def test_status_reporting(self):
|
||||||
"""Test status reported correctly to agent."""
|
"""Test status reported correctly to agent."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def test_ipsec_site_connections_mtu_enforcement(self):
|
||||||
|
"""Test that mtu of ipsec site connections is enforced."""
|
||||||
|
|
||||||
|
# Set up non-default mtu value
|
||||||
|
self.fake_ipsec_connection['mtu'] = 1200
|
||||||
|
|
||||||
|
# Establish an ipsec connection between two sites
|
||||||
|
site1, site2 = self._create_ipsec_site_connection()
|
||||||
|
|
||||||
|
self.driver.sync(mock.Mock(), [{'id': site1['router'].router_id},
|
||||||
|
{'id': site2['router'].router_id}])
|
||||||
|
self.addCleanup(
|
||||||
|
self.driver._delete_vpn_processes,
|
||||||
|
[site1['router'].router_id, site2['router'].router_id], [])
|
||||||
|
|
||||||
|
# Validate that ip packets with 1172 (1200) bytes of data pass
|
||||||
|
self.assertTrue(self._ping_mtu(site1['port_namespace'],
|
||||||
|
site2['port_ip'], 1172))
|
||||||
|
self.assertTrue(self._ping_mtu(site2['port_namespace'],
|
||||||
|
site1['port_ip'], 1172))
|
||||||
|
|
||||||
|
# Validate that ip packets with 1173 (1201) bytes of data are dropped
|
||||||
|
self.assertFalse(self._ping_mtu(site1['port_namespace'],
|
||||||
|
site2['port_ip'], 1173))
|
||||||
|
self.assertFalse(self._ping_mtu(site2['port_namespace'],
|
||||||
|
site1['port_ip'], 1173))
|
||||||
|
@ -67,6 +67,7 @@ FAKE_VPN_SERVICE = {
|
|||||||
'id': FAKE_IPSEC_SITE_CONNECTION1_ID,
|
'id': FAKE_IPSEC_SITE_CONNECTION1_ID,
|
||||||
'external_ip': '50.0.0.4',
|
'external_ip': '50.0.0.4',
|
||||||
'peer_address': '30.0.0.5',
|
'peer_address': '30.0.0.5',
|
||||||
|
'mtu': 1500,
|
||||||
'peer_id': '30.0.0.5',
|
'peer_id': '30.0.0.5',
|
||||||
'psk': 'password',
|
'psk': 'password',
|
||||||
'initiator': 'bi-directional',
|
'initiator': 'bi-directional',
|
||||||
@ -79,6 +80,7 @@ FAKE_VPN_SERVICE = {
|
|||||||
'external_ip': '50.0.0.4',
|
'external_ip': '50.0.0.4',
|
||||||
'peer_address': '50.0.0.5',
|
'peer_address': '50.0.0.5',
|
||||||
'peer_id': '50.0.0.5',
|
'peer_id': '50.0.0.5',
|
||||||
|
'mtu': 1500,
|
||||||
'psk': 'password',
|
'psk': 'password',
|
||||||
'id': FAKE_IPSEC_SITE_CONNECTION2_ID,
|
'id': FAKE_IPSEC_SITE_CONNECTION2_ID,
|
||||||
'initiator': 'bi-directional',
|
'initiator': 'bi-directional',
|
||||||
@ -99,8 +101,7 @@ AUTH_AH = '''ah
|
|||||||
|
|
||||||
OPENSWAN_CONNECTION_DETAILS = '''# rightsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
OPENSWAN_CONNECTION_DETAILS = '''# rightsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
||||||
# [mtu]
|
# [mtu]
|
||||||
# Note It looks like not supported in the strongswan driver
|
mtu=1500
|
||||||
# ignore it now
|
|
||||||
# [dpd_action]
|
# [dpd_action]
|
||||||
dpdaction=
|
dpdaction=
|
||||||
# [dpd_interval]
|
# [dpd_interval]
|
||||||
@ -152,6 +153,11 @@ conn %(conn1_id)s
|
|||||||
# [subnet]
|
# [subnet]
|
||||||
leftsubnet=10.0.0.0/24
|
leftsubnet=10.0.0.0/24
|
||||||
# leftsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
# leftsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
||||||
|
# [updown]
|
||||||
|
# What "updown" script to run to adjust routing and/or firewalling when
|
||||||
|
# the status of the connection changes (default "ipsec _updown").
|
||||||
|
# "--route yes" allows to specify such routing options as mtu and metric.
|
||||||
|
leftupdown="ipsec _updown --route yes"
|
||||||
######################
|
######################
|
||||||
# ipsec_site_connections
|
# ipsec_site_connections
|
||||||
######################
|
######################
|
||||||
@ -172,6 +178,11 @@ conn %(conn1_id)s
|
|||||||
# [subnet]
|
# [subnet]
|
||||||
leftsubnet=10.0.0.0/24
|
leftsubnet=10.0.0.0/24
|
||||||
# leftsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
# leftsubnet=networkA/netmaskA, networkB/netmaskB (IKEv2 only)
|
||||||
|
# [updown]
|
||||||
|
# What "updown" script to run to adjust routing and/or firewalling when
|
||||||
|
# the status of the connection changes (default "ipsec _updown").
|
||||||
|
# "--route yes" allows to specify such routing options as mtu and metric.
|
||||||
|
leftupdown="ipsec _updown --route yes"
|
||||||
######################
|
######################
|
||||||
# ipsec_site_connections
|
# ipsec_site_connections
|
||||||
######################
|
######################
|
||||||
|
Loading…
Reference in New Issue
Block a user