dragonflow/dragonflow/tests/fullstack/test_responder.py
Wang Jian e0d34e0e91 Fix VM deleting error in CI
We delete VM twice which may cause one of them fail

Change-Id: I9e8f6e9e8e3178cbae9c0c9ea2db90e4d52af661
2016-08-19 15:58:43 +08:00

196 lines
6.8 KiB
Python

# 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 eventlet
import re
from neutron.agent.linux import utils
from dragonflow.controller.common import constants as const
from dragonflow.tests.common import utils as test_utils
from dragonflow.tests.fullstack import test_base
from dragonflow.tests.fullstack import test_objects as objects
class ArpResponderTest(test_base.DFTestBase):
def _find_arp_responder_flow_by_ip(self, flows, ip_str):
for flow in flows:
match = flow['match']
if not re.search('\\barp\\b', match):
continue
if not re.search(
'\\barp_tpa=%s\\b' % ip_str.replace('.', '\\.'),
match):
continue
if not re.search('\\barp_op=1\\b', match):
continue
return flow
return None
def _get_arp_table_flows(self):
ovs_flows_parser = test_utils.OvsFlowsParser()
flows = ovs_flows_parser.dump(self.integration_bridge)
flows = [flow for flow in flows
if flow['table'] == str(const.ARP_TABLE)]
return flows
def _check_arp_flow_removal(self, ip):
arp_flows = self._get_arp_table_flows()
flow = self._find_arp_responder_flow_by_ip(arp_flows, ip)
if not flow:
return True
return False
def test_arp_responder(self):
"""
Add a VM. Verify it's ARP flow is there.
"""
network = self.store(objects.NetworkTestObj(self.neutron, self.nb_api))
network_id = network.create(network={'name': 'arp_responder_test'})
subnet_obj = self.store(objects.SubnetTestObj(
self.neutron,
self.nb_api,
network_id,
))
subnet = {'network_id': network_id,
'cidr': '10.10.10.0/24',
'gateway_ip': '10.10.10.1',
'ip_version': 4,
'name': 'arp_responder_test',
'enable_dhcp': True}
subnet = subnet_obj.create(subnet)
flows_before = self._get_arp_table_flows()
vm = self.store(objects.VMTestObj(self, self.neutron))
vm.create(network=network)
ip = vm.get_first_ipv4()
self.assertIsNotNone(ip)
flows_middle = self._get_arp_table_flows()
vm.close()
eventlet.sleep(test_utils.DEFAULT_CMD_TIMEOUT)
flows_delta = [flow for flow in flows_middle
if flow not in flows_before]
self.assertIsNotNone(
self._find_arp_responder_flow_by_ip(flows_delta, ip)
)
condition = lambda: self._check_arp_flow_removal(ip)
try:
utils.wait_until_true(
condition, timeout=40, sleep=1,
exception=RuntimeError(
"Timed out waiting for arp responder flow from %(ip)s"
" to be removed" % {'ip': ip}))
except Exception as e:
self.assertIsNone(e)
finally:
network.close()
class ICMPResponderTest(test_base.DFTestBase):
def _find_icmp_responder_flow_by_ip(self, flows, ip_str):
for flow in flows:
match = flow['match']
if not re.search('\\bicmp\\b', match):
continue
if not re.search(
'\\bnw_dst=%s\\b' % ip_str.replace('.', '\\.'),
match):
continue
if not re.search('\\bicmp_type=8\\b', match):
continue
return flow
return None
def _get_l2_lookup_table_flows(self):
ovs_flows_parser = test_utils.OvsFlowsParser()
flows = ovs_flows_parser.dump(self.integration_bridge)
flows = [flow for flow in flows
if flow['table'] == str(const.L2_LOOKUP_TABLE)]
return flows
def _check_icmp_flow_removal(self, ip):
l2_flows = self._get_l2_lookup_table_flows()
flow = self._find_icmp_responder_flow_by_ip(l2_flows, ip)
if not flow:
return True
return False
def test_icmp_responder(self):
"""
Add a VM. Verify the icmp flow is there.
"""
network = self.store(objects.NetworkTestObj(self.neutron, self.nb_api))
network_id = network.create(network={'name': 'icmp_responder_test'})
subnet_obj = self.store(objects.SubnetTestObj(
self.neutron,
self.nb_api,
network_id,
))
subnet = {'network_id': network_id,
'cidr': '10.10.10.0/24',
'gateway_ip': '10.10.10.1',
'ip_version': 4,
'name': 'arp_responder_test',
'enable_dhcp': True}
subnet_id = subnet_obj.create(subnet)
flows_before = self._get_l2_lookup_table_flows()
router = self.store(objects.RouterTestObj(self.neutron, self.nb_api))
router_id = router.create()
subnet_msg = {'subnet_id': subnet_id}
interface = self.neutron.add_interface_router(router_id,
body=subnet_msg)
port_id = interface['port_id']
router_port = self.neutron.list_ports(id=port_id)['ports'][0]
router_ip = None
for ip in router_port['fixed_ips']:
if ip['subnet_id'] == subnet_id:
router_ip = ip['ip_address']
break
vm = self.store(objects.VMTestObj(self, self.neutron))
vm.create(network=network)
ip = vm.get_first_ipv4()
self.assertIsNotNone(ip)
flows_middle = self._get_l2_lookup_table_flows()
vm.close()
router.close()
eventlet.sleep(test_utils.DEFAULT_CMD_TIMEOUT)
flows_delta = [flow for flow in flows_middle
if flow not in flows_before]
self.assertIsNotNone(
self._find_icmp_responder_flow_by_ip(flows_delta, router_ip)
)
condition = lambda: self._check_icmp_flow_removal(router_ip)
try:
utils.wait_until_true(
condition, timeout=40, sleep=1,
exception=RuntimeError(
"Timed out waiting for icmp responder flow from %(ip)s"
" to be removed" % {'ip': router_ip}))
except Exception as e:
self.assertIsNone(e)
finally:
network.close()