Add fullstack test for snat

Change-Id: I5fdaf510c9653c4fc57ee0529e575ded82c099e3
Closes-Bug: 1651988
This commit is contained in:
Omer Anson 2017-05-17 11:41:17 +03:00
parent 9029522f40
commit ebe78138bd
7 changed files with 176 additions and 21 deletions

View File

@ -21,6 +21,8 @@ export OVERRIDE_ENABLED_SERVICES=key,n-api,n-api-meta,n-cpu,n-cond,n-sch,n-crt,n
export DEVSTACK_LOCAL_CONFIG+=$'\n'"DF_REDIS_PUBSUB=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"DF_RUNNING_IN_GATE=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"EXTERNAL_HOST_IP=172.24.4.100"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"OVS_INSTALL_FROM_GIT=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"OVS_BRANCH=v2.7.1"
if [ -n "${DEVSTACK_GATE_TEMPEST}" ] && [ ${DEVSTACK_GATE_TEMPEST} -gt 0 ]; then
# Only include tempest if this is a tempest job

View File

@ -25,6 +25,8 @@ export DEVSTACK_LOCAL_CONFIG+=$'\n'"ENABLE_ACTIVE_DETECTION=False"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"DF_RUNNING_IN_GATE=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"EXTERNAL_HOST_IP=172.24.4.100"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"ENABLE_DF_SFC=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"OVS_INSTALL_FROM_GIT=True"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"OVS_BRANCH=v2.7.1"
if [ -n "${DEVSTACK_GATE_TEMPEST}" ] && [ ${DEVSTACK_GATE_TEMPEST} -gt 0 ]; then
# Only include tempest if this is a tempest job

View File

@ -69,7 +69,7 @@ function _neutron_ovs_install_ovs_fedora {
}
function _neutron_ovs_install_ovs_deps_ubuntu {
install_package -y build-essential fakeroot devscripts equivs dkms
install_package -y build-essential fakeroot devscripts equivs dkms linux-libc-dev linux-headers-$(uname -r)
sudo mk-build-deps -i -t "/usr/bin/apt-get --no-install-recommends -y"
}

View File

@ -40,6 +40,8 @@ class ChassisSNATApp(df_base_app.DFlowApp, snat_mixin.SNATApp_mixin):
LOG.info("Loading SNAT application ... ")
self.external_network_bridge = (
cfg.CONF.df_snat_app.external_network_bridge)
self.external_bridge_mac = self.vswitch_api.get_port_mac_in_use(
self.external_network_bridge) or const.EMPTY_MAC
self.chassis = None
# new application configuration
@ -58,7 +60,7 @@ class ChassisSNATApp(df_base_app.DFlowApp, snat_mixin.SNATApp_mixin):
def switch_features_handler(self, ev):
self._setup_patch_ports()
self.external_bridge_mac = self.vswitch_api.get_port_mac_in_use(
self.external_network_bridge)
self.external_network_bridge) or const.EMPTY_MAC
# install static strategy flows
if self.external_host_ip is None:

View File

@ -83,12 +83,18 @@ class SNATApp_mixin(object):
def _install_ingress_goto_rules(self):
parser = self.parser
match = parser.OFPMatch(in_port=self.external_ofport)
actions = [parser.NXActionRegLoad(
dst='in_port',
value=0,
ofs_nbits=nicira_ext.ofs_nbits(0, 31))]
self.add_flow_go_to_table(
const.INGRESS_CLASSIFICATION_DISPATCH_TABLE,
const.PRIORITY_DEFAULT,
const.INGRESS_NAT_TABLE,
match=match)
inst = [parser.OFPInstructionActions(
self.datapath.ofproto.OFPIT_APPLY_ACTIONS, actions),
parser.OFPInstructionGotoTable(const.INGRESS_NAT_TABLE)]
self.mod_flow(inst=inst,
table_id=const.INGRESS_CLASSIFICATION_DISPATCH_TABLE,
priority=const.PRIORITY_DEFAULT,
match=match)
def _install_snat_egress_conntrack(self, match, ext_host_ip):
"""implements single sNAT pass for multiple tenant deployment
@ -162,16 +168,12 @@ class SNATApp_mixin(object):
actions = [
parser.OFPActionSetField(eth_src=ext_host_mac),
parser.OFPActionSetField(eth_dst=self.external_bridge_mac)
]
action_inst = parser.OFPInstructionActions(
ofproto.OFPIT_APPLY_ACTIONS, actions)
goto_inst = parser.OFPInstructionGotoTable(const.EGRESS_EXTERNAL_TABLE)
inst = [action_inst, goto_inst]
parser.OFPActionSetField(eth_dst=self.external_bridge_mac),
parser.OFPActionOutput(self.external_ofport,
ofproto.OFPCML_NO_BUFFER)]
self.mod_flow(
inst=inst,
actions=actions,
table_id=const.EGRESS_SNAT_TABLE,
priority=const.PRIORITY_LOW,
match=match)
@ -247,3 +249,10 @@ class SNATApp_mixin(object):
table_id=const.INGRESS_SNAT_TABLE,
priority=const.PRIORITY_LOW,
match=match)
actions = [self.parser.OFPActionOutput(
self.external_ofport, self.ofproto.OFPCML_NO_BUFFER)]
self.mod_flow(
actions=actions,
table_id=const.INGRESS_DISPATCH_TABLE,
priority=const.PRIORITY_DEFAULT)

View File

@ -16,6 +16,7 @@ import struct
import sys
import time
from neutron.agent.common import ip_lib
from neutron.agent.common import utils
from neutron_lib import constants as n_const
from oslo_log import log
@ -2661,3 +2662,142 @@ class TestTrunkApp(test_base.DFTestBase):
result.add_protocol(icmp)
result.serialize()
return result.data
class TestSNat(test_base.DFTestBase):
namespace_name = 'test-snat'
iface0_name = 'snat_veth0'
iface1_name = 'snat_veth1'
def setUp(self):
super(TestSNat, self).setUp()
ipwrapper = ip_lib.IPWrapper()
snat_veth0_device, snat_veth1_device = ipwrapper.add_veth(
self.iface0_name,
self.iface1_name, self.namespace_name)
snat_veth1_device.link.set_up()
snat_veth1_device.addr.add('10.0.1.2/30')
snat_veth0_device.link.set_up()
snat_veth0_device.addr.add('10.0.1.1/30')
snat_veth1_device.route.add_gateway('10.0.1.1')
time.sleep(10)
def tearDown(self):
ipwrapper = ip_lib.IPWrapper()
ipwrapper.del_veth(self.iface0_name)
ipwrapper.netns.delete(self.namespace_name)
super(TestSNat, self).tearDown()
def test_icmp_ping_pong_with_external_peer(self):
self._create_topology()
policy = self._create_policy()
policy.start(self.topology)
policy.wait(const.DEFAULT_RESOURCE_READY_TIMEOUT)
if len(policy.exceptions) > 0:
raise policy.exceptions[0]
def _create_topology(self):
self.topology = self.store(
app_testing_objects.Topology(
self.neutron,
self.nb_api
)
)
self.subnet1 = self.topology.create_subnet(cidr='192.168.15.0/24')
self.port1 = self.subnet1.create_port()
self.router = self.topology.create_router([self.subnet1.subnet_id])
self.topology.create_external_network([self.router.router_id])
time.sleep(const.DEFAULT_RESOURCE_READY_TIMEOUT)
def _create_policy(self):
port_policies = self._create_port_policies()
initial_packet = self._create_packet(
'10.0.1.2', ryu.lib.packet.ipv4.inet.IPPROTO_ICMP)
policy = self.store(
app_testing_objects.Policy(
initial_actions=[
app_testing_objects.SendAction(
self.subnet1.subnet_id,
self.port1.port_id,
initial_packet
),
],
port_policies=port_policies,
unknown_port_action=app_testing_objects.IgnoreAction()
)
)
return policy
def _create_port_policies(self):
ignore_action = app_testing_objects.IgnoreAction()
raise_action = app_testing_objects.RaiseAction("Unexpected packet")
key1 = (self.subnet1.subnet_id, self.port1.port_id)
actions = [app_testing_objects.DisableRuleAction(),
app_testing_objects.StopSimulationAction()]
rules1 = [
app_testing_objects.PortPolicyRule(
# Detect pong, end simulation
app_testing_objects.RyuICMPPongFilter(self._get_ping),
actions=actions
),
app_testing_objects.PortPolicyRule(
# Ignore gratuitous ARP packets
app_testing_objects.RyuARPGratuitousFilter(),
actions=[
ignore_action
]
),
app_testing_objects.PortPolicyRule(
# Ignore IPv6 packets
app_testing_objects.RyuIPv6Filter(),
actions=[
ignore_action
]
),
]
policy1 = app_testing_objects.PortPolicy(
rules=rules1,
default_action=raise_action
)
return {
key1: policy1,
}
def _create_packet(self, dst_ip, proto, ttl=255):
router_interface = self.router.router_interfaces[
self.subnet1.subnet_id
]
router_interface_port = self.neutron.show_port(
router_interface['port_id']
)
ethernet = ryu.lib.packet.ethernet.ethernet(
src=self.port1.port.get_logical_port().mac,
dst=router_interface_port['port']['mac_address'],
ethertype=ryu.lib.packet.ethernet.ether.ETH_TYPE_IP,
)
ip = ryu.lib.packet.ipv4.ipv4(
src=self.port1.port.get_logical_port().ip,
dst=dst_ip,
ttl=ttl,
proto=proto,
)
ip_data = ryu.lib.packet.icmp.icmp(
type_=ryu.lib.packet.icmp.ICMP_ECHO_REQUEST,
data=ryu.lib.packet.icmp.echo(
data=self._create_random_string())
)
self._ping = ip_data
self._ip = ip
result = ryu.lib.packet.packet.Packet()
result.add_protocol(ethernet)
result.add_protocol(ip)
result.add_protocol(ip_data)
result.serialize()
return result.data
def _get_ping(self):
return self._ping

View File

@ -39,11 +39,6 @@ class TestChassisSNATApp(test_app_base.DFAppTestBase):
self.SNAT_app.add_flow_go_to_table.assert_has_calls(
[mock.call(
constants.INGRESS_CLASSIFICATION_DISPATCH_TABLE,
constants.PRIORITY_DEFAULT,
constants.INGRESS_NAT_TABLE,
match=mock.ANY),
mock.call(
constants.L3_LOOKUP_TABLE,
constants.PRIORITY_MEDIUM_LOW,
constants.EGRESS_NAT_TABLE,
@ -51,6 +46,11 @@ class TestChassisSNATApp(test_app_base.DFAppTestBase):
self.SNAT_app.mod_flow.assert_has_calls(
[mock.call(
inst=mock.ANY,
table_id=constants.INGRESS_CLASSIFICATION_DISPATCH_TABLE,
priority=constants.PRIORITY_DEFAULT,
match=mock.ANY),
mock.call(
inst=mock.ANY,
table_id=constants.INGRESS_NAT_TABLE,
priority=constants.PRIORITY_LOW,
@ -61,7 +61,7 @@ class TestChassisSNATApp(test_app_base.DFAppTestBase):
priority=constants.PRIORITY_LOW,
match=mock.ANY),
mock.call(
inst=mock.ANY,
actions=mock.ANY,
table_id=constants.EGRESS_SNAT_TABLE,
priority=constants.PRIORITY_LOW,
match=mock.ANY)])