Merge "Bugfix and refactoring for ovs_lib flow methods"

This commit is contained in:
Jenkins 2014-03-21 05:53:41 +00:00 committed by Gerrit Code Review
commit b035a58a07
3 changed files with 130 additions and 82 deletions

View File

@ -20,6 +20,7 @@ from oslo.config import cfg
from neutron.agent.linux import ip_lib from neutron.agent.linux import ip_lib
from neutron.agent.linux import utils from neutron.agent.linux import utils
from neutron.common import exceptions
from neutron.openstack.common import excutils from neutron.openstack.common import excutils
from neutron.openstack.common import jsonutils from neutron.openstack.common import jsonutils
from neutron.openstack.common import log as logging from neutron.openstack.common import log as logging
@ -178,75 +179,26 @@ class OVSBridge(BaseOVS):
return self.db_get_val('Bridge', return self.db_get_val('Bridge',
self.br_name, 'datapath_id').strip('"') self.br_name, 'datapath_id').strip('"')
def _build_flow_expr_arr(self, **kwargs):
flow_expr_arr = []
is_delete_expr = kwargs.get('delete', False)
if not is_delete_expr:
prefix = ("hard_timeout=%s,idle_timeout=%s,priority=%s" %
(kwargs.get('hard_timeout', '0'),
kwargs.get('idle_timeout', '0'),
kwargs.get('priority', '1')))
flow_expr_arr.append(prefix)
elif 'priority' in kwargs:
raise Exception(_("Cannot match priority on flow deletion"))
table = ('table' in kwargs and ",table=%s" %
kwargs['table'] or '')
in_port = ('in_port' in kwargs and ",in_port=%s" %
kwargs['in_port'] or '')
dl_type = ('dl_type' in kwargs and ",dl_type=%s" %
kwargs['dl_type'] or '')
dl_vlan = ('dl_vlan' in kwargs and ",dl_vlan=%s" %
kwargs['dl_vlan'] or '')
dl_src = 'dl_src' in kwargs and ",dl_src=%s" % kwargs['dl_src'] or ''
dl_dst = 'dl_dst' in kwargs and ",dl_dst=%s" % kwargs['dl_dst'] or ''
nw_src = 'nw_src' in kwargs and ",nw_src=%s" % kwargs['nw_src'] or ''
nw_dst = 'nw_dst' in kwargs and ",nw_dst=%s" % kwargs['nw_dst'] or ''
tun_id = 'tun_id' in kwargs and ",tun_id=%s" % kwargs['tun_id'] or ''
proto = 'proto' in kwargs and ",%s" % kwargs['proto'] or ''
ip = ('nw_src' in kwargs or 'nw_dst' in kwargs) and ',ip' or ''
match = (table + in_port + dl_type + dl_vlan + dl_src + dl_dst +
(proto or ip) + nw_src + nw_dst + tun_id)
if match:
match = match[1:] # strip leading comma
flow_expr_arr.append(match)
return flow_expr_arr
def add_or_mod_flow_str(self, **kwargs):
if "actions" not in kwargs:
raise Exception(_("Must specify one or more actions"))
if "priority" not in kwargs:
kwargs["priority"] = "0"
flow_expr_arr = self._build_flow_expr_arr(**kwargs)
flow_expr_arr.append("actions=%s" % (kwargs["actions"]))
flow_str = ",".join(flow_expr_arr)
return flow_str
def add_flow(self, **kwargs): def add_flow(self, **kwargs):
flow_str = self.add_or_mod_flow_str(**kwargs) flow_str = _build_flow_expr_str(kwargs, 'add')
if self.defer_apply_flows: if self.defer_apply_flows:
self.deferred_flows['add'] += flow_str + '\n' self.deferred_flows['add'] += flow_str + '\n'
else: else:
self.run_ofctl("add-flow", [flow_str]) self.run_ofctl("add-flow", [flow_str])
def mod_flow(self, **kwargs): def mod_flow(self, **kwargs):
flow_str = self.add_or_mod_flow_str(**kwargs) flow_str = _build_flow_expr_str(kwargs, 'mod')
if self.defer_apply_flows: if self.defer_apply_flows:
self.deferred_flows['mod'] += flow_str + '\n' self.deferred_flows['mod'] += flow_str + '\n'
else: else:
self.run_ofctl("mod-flows", [flow_str]) self.run_ofctl("mod-flows", [flow_str])
def delete_flows(self, **kwargs): def delete_flows(self, **kwargs):
kwargs['delete'] = True flow_expr_str = _build_flow_expr_str(kwargs, 'del')
flow_expr_arr = self._build_flow_expr_arr(**kwargs)
if "actions" in kwargs:
flow_expr_arr.append("actions=%s" % (kwargs["actions"]))
flow_str = ",".join(flow_expr_arr)
if self.defer_apply_flows: if self.defer_apply_flows:
self.deferred_flows['del'] += flow_str + '\n' self.deferred_flows['del'] += flow_expr_str + '\n'
else: else:
self.run_ofctl("del-flows", [flow_str]) self.run_ofctl("del-flows", [flow_expr_str])
def defer_apply_on(self): def defer_apply_on(self):
LOG.debug(_('defer_apply_on')) LOG.debug(_('defer_apply_on'))
@ -576,3 +528,37 @@ def check_ovs_vxlan_version(root_helper):
_compare_installed_and_required_version(installed_klm_version, _compare_installed_and_required_version(installed_klm_version,
min_required_version, min_required_version,
'kernel', 'VXLAN') 'kernel', 'VXLAN')
def _build_flow_expr_str(flow_dict, cmd):
flow_expr_arr = []
actions = None
if cmd == 'add':
flow_expr_arr.append("hard_timeout=%s" %
flow_dict.pop('hard_timeout', '0'))
flow_expr_arr.append("idle_timeout=%s" %
flow_dict.pop('idle_timeout', '0'))
flow_expr_arr.append("priority=%s" %
flow_dict.pop('priority', '1'))
elif 'priority' in flow_dict:
msg = _("Cannot match priority on flow deletion or modification")
raise exceptions.InvalidInput(error_message=msg)
if cmd != 'del':
if "actions" not in flow_dict:
msg = _("Must specify one or more actions on flow addition"
" or modification")
raise exceptions.InvalidInput(error_message=msg)
actions = "actions=%s" % flow_dict.pop('actions')
for key, value in flow_dict.iteritems():
if key == 'proto':
flow_expr_arr.append(value)
else:
flow_expr_arr.append("%s=%s" % (key, str(value)))
if actions:
flow_expr_arr.append(actions)
return ','.join(flow_expr_arr)

View File

@ -12,12 +12,17 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
import mock import mock
from oslo.config import cfg from oslo.config import cfg
import testtools import testtools
from neutron.agent.linux import ovs_lib from neutron.agent.linux import ovs_lib
from neutron.agent.linux import utils from neutron.agent.linux import utils
from neutron.common import exceptions
from neutron.openstack.common import jsonutils from neutron.openstack.common import jsonutils
from neutron.openstack.common import uuidutils from neutron.openstack.common import uuidutils
from neutron.plugins.openvswitch.common import constants from neutron.plugins.openvswitch.common import constants
@ -207,19 +212,38 @@ class OVS_Lib_Test(base.BaseTestCase):
lsw_id = 18 lsw_id = 18
cidr = '192.168.1.0/24' cidr = '192.168.1.0/24'
self.br.add_flow(priority=2, dl_src="ca:fe:de:ad:be:ef", flow_dict_1 = OrderedDict([('priority', 2),
actions="strip_vlan,output:0") ('dl_src', 'ca:fe:de:ad:be:ef'),
self.br.add_flow(priority=1, actions="normal") ('actions', 'strip_vlan,output:0')])
self.br.add_flow(priority=2, actions="drop") flow_dict_2 = OrderedDict([('priority', 1),
self.br.add_flow(priority=2, in_port=ofport, actions="drop") ('actions', 'normal')])
flow_dict_3 = OrderedDict([('priority', 2),
('actions', 'drop')])
flow_dict_4 = OrderedDict([('priority', 2),
('in_port', ofport),
('actions', 'drop')])
flow_dict_5 = OrderedDict([
('priority', 4),
('in_port', ofport),
('dl_vlan', vid),
('actions', "strip_vlan,set_tunnel:%s,normal" % (lsw_id))])
flow_dict_6 = OrderedDict([
('priority', 3),
('tun_id', lsw_id),
('actions', "mod_vlan_vid:%s,output:%s" % (vid, ofport))])
flow_dict_7 = OrderedDict([
('priority', 4),
('nw_src', cidr),
('proto', 'arp'),
('actions', 'drop')])
self.br.add_flow(priority=4, in_port=ofport, dl_vlan=vid, self.br.add_flow(**flow_dict_1)
actions="strip_vlan,set_tunnel:%s,normal" % self.br.add_flow(**flow_dict_2)
(lsw_id)) self.br.add_flow(**flow_dict_3)
self.br.add_flow(priority=3, tun_id=lsw_id, self.br.add_flow(**flow_dict_4)
actions="mod_vlan_vid:%s,output:%s" % self.br.add_flow(**flow_dict_5)
(vid, ofport)) self.br.add_flow(**flow_dict_6)
self.br.add_flow(priority=4, proto='arp', nw_src=cidr, actions='drop') self.br.add_flow(**flow_dict_7)
expected_calls = [ expected_calls = [
mock.call(["ovs-ofctl", "add-flow", self.BR_NAME, mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
"hard_timeout=0,idle_timeout=0," "hard_timeout=0,idle_timeout=0,"
@ -240,9 +264,9 @@ class OVS_Lib_Test(base.BaseTestCase):
process_input=None, root_helper=self.root_helper), process_input=None, root_helper=self.root_helper),
mock.call(["ovs-ofctl", "add-flow", self.BR_NAME, mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
"hard_timeout=0,idle_timeout=0," "hard_timeout=0,idle_timeout=0,"
"priority=4,in_port=%s,dl_vlan=%s," "priority=4,dl_vlan=%s,in_port=%s,"
"actions=strip_vlan,set_tunnel:%s,normal" "actions=strip_vlan,set_tunnel:%s,normal"
% (ofport, vid, lsw_id)], % (vid, ofport, lsw_id)],
process_input=None, root_helper=self.root_helper), process_input=None, root_helper=self.root_helper),
mock.call(["ovs-ofctl", "add-flow", self.BR_NAME, mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
"hard_timeout=0,idle_timeout=0," "hard_timeout=0,idle_timeout=0,"
@ -252,11 +276,34 @@ class OVS_Lib_Test(base.BaseTestCase):
process_input=None, root_helper=self.root_helper), process_input=None, root_helper=self.root_helper),
mock.call(["ovs-ofctl", "add-flow", self.BR_NAME, mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
"hard_timeout=0,idle_timeout=0," "hard_timeout=0,idle_timeout=0,"
"priority=4,arp,nw_src=%s,actions=drop" % cidr], "priority=4,nw_src=%s,arp,actions=drop" % cidr],
process_input=None, root_helper=self.root_helper), process_input=None, root_helper=self.root_helper),
] ]
self.execute.assert_has_calls(expected_calls) self.execute.assert_has_calls(expected_calls)
def test_add_flow_timeout_set(self):
flow_dict = OrderedDict([('priority', 1),
('hard_timeout', 1000),
('idle_timeout', 2000),
('actions', 'normal')])
self.br.add_flow(**flow_dict)
self.execute.assert_called_once_with(
["ovs-ofctl", "add-flow", self.BR_NAME,
"hard_timeout=1000,idle_timeout=2000,priority=1,actions=normal"],
process_input=None,
root_helper=self.root_helper)
def test_add_flow_default_priority(self):
flow_dict = OrderedDict([('actions', 'normal')])
self.br.add_flow(**flow_dict)
self.execute.assert_called_once_with(
["ovs-ofctl", "add-flow", self.BR_NAME,
"hard_timeout=0,idle_timeout=0,priority=1,actions=normal"],
process_input=None,
root_helper=self.root_helper)
def test_get_port_ofport(self): def test_get_port_ofport(self):
pname = "tap99" pname = "tap99"
ofport = "6" ofport = "6"
@ -304,27 +351,41 @@ class OVS_Lib_Test(base.BaseTestCase):
] ]
self.execute.assert_has_calls(expected_calls) self.execute.assert_has_calls(expected_calls)
def test_defer_apply_flows(self): def test_delete_flow_with_priority_set(self):
add_mod_flow = mock.patch.object(self.br, params = {'in_port': '1',
'add_or_mod_flow_str').start() 'priority': '1'}
add_mod_flow.side_effect = ['added_flow_1', 'added_flow_2']
flow_expr = mock.patch.object(self.br, '_build_flow_expr_arr').start() self.assertRaises(exceptions.InvalidInput,
flow_expr.return_value = ['deleted_flow_1'] self.br.delete_flows,
**params)
def test_mod_flow_no_actions_set(self):
params = {'in_port': '1'}
self.assertRaises(exceptions.InvalidInput,
self.br.mod_flow,
**params)
def test_defer_apply_flows(self):
flow_expr = mock.patch.object(ovs_lib, '_build_flow_expr_str').start()
flow_expr.side_effect = ['added_flow_1', 'added_flow_2',
'deleted_flow_1']
run_ofctl = mock.patch.object(self.br, 'run_ofctl').start() run_ofctl = mock.patch.object(self.br, 'run_ofctl').start()
self.br.defer_apply_on() self.br.defer_apply_on()
self.br.add_flow(flow='added_flow_1') self.br.add_flow(flow='add_flow_1')
self.br.defer_apply_on() self.br.defer_apply_on()
self.br.add_flow(flow='added_flow_2') self.br.add_flow(flow='add_flow_2')
self.br.delete_flows(flow='deleted_flow_1') self.br.delete_flows(flow='delete_flow_1')
self.br.defer_apply_off() self.br.defer_apply_off()
add_mod_flow.assert_has_calls([ flow_expr.assert_has_calls([
mock.call(flow='added_flow_1'), mock.call({'flow': 'add_flow_1'}, 'add'),
mock.call(flow='added_flow_2') mock.call({'flow': 'add_flow_2'}, 'add'),
mock.call({'flow': 'delete_flow_1'}, 'del')
]) ])
flow_expr.assert_called_once_with(delete=True, flow='deleted_flow_1')
run_ofctl.assert_has_calls([ run_ofctl.assert_has_calls([
mock.call('add-flows', ['-'], 'added_flow_1\nadded_flow_2\n'), mock.call('add-flows', ['-'], 'added_flow_1\nadded_flow_2\n'),
mock.call('del-flows', ['-'], 'deleted_flow_1\n') mock.call('del-flows', ['-'], 'deleted_flow_1\n')

View File

@ -6,6 +6,7 @@ discover
fixtures>=0.3.14 fixtures>=0.3.14
mock>=1.0 mock>=1.0
python-subunit>=0.0.18 python-subunit>=0.0.18
ordereddict
sphinx>=1.1.2,<1.2 sphinx>=1.1.2,<1.2
testrepository>=0.0.18 testrepository>=0.0.18
testtools>=0.9.34 testtools>=0.9.34