diff --git a/os_net_config/objects.py b/os_net_config/objects.py index 0fecb042..c55b9bd5 100644 --- a/os_net_config/objects.py +++ b/os_net_config/objects.py @@ -521,6 +521,8 @@ class OvsBridge(_BaseOpts): self.ovs_extra = format_ovs_extra(self, ovs_extra) for member in self.members: member.bridge_name = name + if isinstance(member, SriovVF): + OvsBridge.update_vf_config(member) if not isinstance(member, OvsTunnel): member.ovs_port = True if member.primary: @@ -532,6 +534,22 @@ class OvsBridge(_BaseOpts): else: self.primary_interface_name = member.name + @staticmethod + def update_vf_config(iface): + if iface.trust is None: + logger.info("Trust is not set for VF %s:%d, defaulting to on" + % (iface.device, iface.vfid)) + iface.trust = "on" + if iface.promisc is None: + logger.info("Promisc is not set for VF %s:%d, defaulting to on" + % (iface.device, iface.vfid)) + iface.promisc = "on" + utils.update_sriov_vf_map(iface.device, iface.vfid, iface.name, + vlan_id=iface.vlan_id, qos=iface.qos, + spoofcheck=iface.spoofcheck, + trust=iface.trust, state=iface.state, + macaddr=iface.macaddr, promisc=iface.promisc) + @staticmethod def from_json(json): name = _get_required_field(json, 'name', 'OvsBridge') @@ -1055,6 +1073,21 @@ class OvsDpdkPort(_BaseOpts): self.driver = driver self.rx_queue = rx_queue + @staticmethod + def update_vf_config(iface): + if iface.trust is None: + logger.info("Trust is not set for VF %s:%d, defaulting to on" + % (iface.device, iface.vfid)) + iface.trust = "on" + if iface.promisc is not None: + logger.warning("Promisc can't be changed for ovs_dpdk_port") + iface.promisc = None + utils.update_sriov_vf_map(iface.device, iface.vfid, iface.name, + vlan_id=iface.vlan_id, qos=iface.qos, + spoofcheck=iface.spoofcheck, + trust=iface.trust, state=iface.state, + macaddr=iface.macaddr, promisc=iface.promisc) + @staticmethod def from_json(json): name = _get_required_field(json, 'name', 'OvsDpdkPort') @@ -1079,11 +1112,14 @@ class OvsDpdkPort(_BaseOpts): member.update({'nic_mapping': nic_mapping}) member.update({'persist_mapping': persist_mapping}) iface = object_from_json(member) - if (isinstance(iface, Interface) or - isinstance(iface, SriovVF)): + if isinstance(iface, Interface): + # TODO(skramaja): Add checks for IP and route not to # be set in the interface part of DPDK Port members.append(iface) + elif isinstance(iface, SriovVF): + OvsDpdkPort.update_vf_config(iface) + members.append(iface) else: msg = 'OVS DPDK Port should have only interface member' raise InvalidConfigException(msg) diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py index a7ee6b5a..8e892760 100644 --- a/os_net_config/tests/test_objects.py +++ b/os_net_config/tests/test_objects.py @@ -15,10 +15,15 @@ # under the License. import json +import os +import random import six +import yaml from os_net_config import objects +from os_net_config import sriov_config from os_net_config.tests import base +from os_net_config import utils class TestRoute(base.TestCase): @@ -319,6 +324,16 @@ class TestVlan(base.TestCase): class TestBridge(base.TestCase): + def setUp(self): + super(TestBridge, self).setUp() + rand = str(int(random.random() * 100000)) + sriov_config._SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml' + + def tearDown(self): + super(TestBridge, self).tearDown() + if os.path.isfile(sriov_config._SRIOV_CONFIG_FILE): + os.remove(sriov_config._SRIOV_CONFIG_FILE) + def test_from_json_dhcp(self): data = """{ "type": "ovs_bridge", @@ -338,6 +353,174 @@ class TestBridge(base.TestCase): self.assertTrue(interface1.ovs_port) self.assertEqual("br-foo", interface1.bridge_name) + def test_ovs_bridge_with_vf_default(self): + data = """{ +"type": "ovs_bridge", +"name": "br-foo", +"use_dhcp": true, +"members": [{ + "type": "sriov_vf", + "device": "em1", + "vfid": 1, + "vlan_id": 111, + "qos": 1, + "spoofcheck": false +}] +} +""" + vf_final = [{'device_type': 'vf', 'name': 'em1_1', + 'device': {'name': 'em1', 'vfid': 1}, + 'vlan_id': 111, 'qos': 1, + 'spoofcheck': 'off', 'trust': 'on', + 'promisc': 'on'}] + + def test_get_vf_devname(device, vfid): + return device + '_' + str(vfid) + self.stub_out('os_net_config.utils.get_vf_devname', + test_get_vf_devname) + + bridge = objects.object_from_json(json.loads(data)) + self.assertEqual("br-foo", bridge.name) + self.assertTrue(bridge.use_dhcp) + interface1 = bridge.members[0] + self.assertEqual("em1", interface1.device) + self.assertTrue(interface1.ovs_port) + self.assertEqual("br-foo", interface1.bridge_name) + + contents = utils.get_file_data(sriov_config._SRIOV_CONFIG_FILE) + vf_map = yaml.load(contents) if contents else [] + self.assertListEqual(vf_final, vf_map) + + def test_ovs_bridge_with_vf_param_provided(self): + data = """{ +"type": "ovs_bridge", +"name": "br-foo", +"use_dhcp": true, +"members": [{ + "type": "sriov_vf", + "device": "em1", + "vfid": 1, + "vlan_id": 111, + "qos": 1, + "spoofcheck": false, + "trust": false, + "promisc": false +}] +} +""" + vf_final = [{'device_type': 'vf', 'name': 'em1_1', + 'device': {'name': 'em1', 'vfid': 1}, + 'vlan_id': 111, 'qos': 1, + 'spoofcheck': 'off', 'trust': 'off', + 'promisc': 'off'}] + + def test_get_vf_devname(device, vfid): + return device + '_' + str(vfid) + self.stub_out('os_net_config.utils.get_vf_devname', + test_get_vf_devname) + + bridge = objects.object_from_json(json.loads(data)) + self.assertEqual("br-foo", bridge.name) + self.assertTrue(bridge.use_dhcp) + interface1 = bridge.members[0] + self.assertEqual("em1", interface1.device) + self.assertTrue(interface1.ovs_port) + self.assertEqual("br-foo", interface1.bridge_name) + + contents = utils.get_file_data(sriov_config._SRIOV_CONFIG_FILE) + vf_map = yaml.load(contents) if contents else [] + self.assertListEqual(vf_final, vf_map) + + def test_ovs_user_bridge_with_vf_default(self): + data = """{ +"type": "ovs_user_bridge", +"name": "br-foo", +"use_dhcp": true, +"members": [{ + "type": "ovs_dpdk_port", + "name": "dpdk0", + "members": [ + { + "type": "sriov_vf", + "device": "em1", + "vfid": 1, + "vlan_id": 111, + "qos": 1, + "spoofcheck": false + } + ] +}] +} +""" + vf_final = [{'device_type': 'vf', 'name': 'em1_1', + 'device': {'name': 'em1', 'vfid': 1}, + 'vlan_id': 111, 'qos': 1, + 'spoofcheck': 'off', 'trust': 'on' + }] + + def test_get_vf_devname(device, vfid): + return device + '_' + str(vfid) + self.stub_out('os_net_config.utils.get_vf_devname', + test_get_vf_devname) + + bridge = objects.object_from_json(json.loads(data)) + self.assertEqual("br-foo", bridge.name) + self.assertTrue(bridge.use_dhcp) + dpdk_interface = bridge.members[0] + self.assertEqual("dpdk0", dpdk_interface.name) + self.assertFalse(dpdk_interface.ovs_port) + self.assertEqual("br-foo", dpdk_interface.bridge_name) + + contents = utils.get_file_data(sriov_config._SRIOV_CONFIG_FILE) + vf_map = yaml.load(contents) if contents else [] + self.assertListEqual(vf_final, vf_map) + + def test_ovs_user_bridge_with_param_set(self): + data = """{ +"type": "ovs_user_bridge", +"name": "br-foo", +"use_dhcp": true, +"members": [{ + "type": "ovs_dpdk_port", + "name": "dpdk0", + "members": [ + { + "type": "sriov_vf", + "device": "em1", + "vfid": 1, + "vlan_id": 111, + "qos": 1, + "spoofcheck": false, + "trust": false, + "promisc": false + } + ] +}] +} +""" + vf_final = [{'device_type': 'vf', 'name': 'em1_1', + 'device': {'name': 'em1', 'vfid': 1}, + 'vlan_id': 111, 'qos': 1, + 'spoofcheck': 'off', 'trust': 'off' + }] + + def test_get_vf_devname(device, vfid): + return device + '_' + str(vfid) + self.stub_out('os_net_config.utils.get_vf_devname', + test_get_vf_devname) + + bridge = objects.object_from_json(json.loads(data)) + self.assertEqual("br-foo", bridge.name) + self.assertTrue(bridge.use_dhcp) + dpdk_interface = bridge.members[0] + self.assertEqual("dpdk0", dpdk_interface.name) + self.assertFalse(dpdk_interface.ovs_port) + self.assertEqual("br-foo", dpdk_interface.bridge_name) + + contents = utils.get_file_data(sriov_config._SRIOV_CONFIG_FILE) + vf_map = yaml.load(contents) if contents else [] + self.assertListEqual(vf_final, vf_map) + def test_from_json_dhcp_with_nic1(self): def dummy_mapped_nics(nic_mapping=None): return {"nic1": "em5"} diff --git a/os_net_config/utils.py b/os_net_config/utils.py index 3dda7259..dbdfc6a8 100644 --- a/os_net_config/utils.py +++ b/os_net_config/utils.py @@ -18,6 +18,7 @@ import glob import logging import os import re +import six import time import yaml @@ -446,21 +447,26 @@ def _set_vf_fields(vf_name, vlan_id, qos, spoofcheck, trust, state, macaddr, vf_configs['name'] = vf_name if vlan_id != 0: vf_configs['vlan_id'] = vlan_id + else: + vf_configs['vlan_id'] = None if qos != 0: vf_configs['qos'] = qos - if spoofcheck is not None: - vf_configs['spoofcheck'] = spoofcheck - if trust is not None: - vf_configs['trust'] = trust - if state is not None: - vf_configs['state'] = state - if macaddr is not None: - vf_configs['macaddr'] = macaddr - if promisc is not None: - vf_configs['promisc'] = promisc + else: + vf_configs['qos'] = None + vf_configs['spoofcheck'] = spoofcheck + vf_configs['trust'] = trust + vf_configs['state'] = state + vf_configs['macaddr'] = macaddr + vf_configs['promisc'] = promisc return vf_configs +def _clear_empty_values(vf_config): + for (key, val) in list(six.iteritems(vf_config)): + if val is None: + del vf_config[key] + + def update_sriov_vf_map(pf_name, vfid, vf_name, vlan_id=0, qos=0, spoofcheck=None, trust=None, state=None, macaddr=None, promisc=None): @@ -471,6 +477,7 @@ def update_sriov_vf_map(pf_name, vfid, vf_name, vlan_id=0, qos=0, item['device'].get('vfid') == vfid): item.update(_set_vf_fields(vf_name, vlan_id, qos, spoofcheck, trust, state, macaddr, promisc)) + _clear_empty_values(item) break else: new_item = {} @@ -478,6 +485,7 @@ def update_sriov_vf_map(pf_name, vfid, vf_name, vlan_id=0, qos=0, new_item['device'] = {"name": pf_name, "vfid": vfid} new_item.update(_set_vf_fields(vf_name, vlan_id, qos, spoofcheck, trust, state, macaddr, promisc)) + _clear_empty_values(new_item) sriov_map.append(new_item) write_yaml_config(sriov_config._SRIOV_CONFIG_FILE, sriov_map)