aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/os-net-config/samples/ovs_dpdk.json1
-rw-r--r--etc/os-net-config/samples/ovs_dpdk.yaml6
-rw-r--r--os_net_config/impl_ifcfg.py4
-rw-r--r--os_net_config/objects.py144
-rw-r--r--os_net_config/tests/test_impl_ifcfg.py45
-rw-r--r--os_net_config/tests/test_objects.py107
6 files changed, 220 insertions, 87 deletions
diff --git a/etc/os-net-config/samples/ovs_dpdk.json b/etc/os-net-config/samples/ovs_dpdk.json
index 37b79e0..5c84044 100644
--- a/etc/os-net-config/samples/ovs_dpdk.json
+++ b/etc/os-net-config/samples/ovs_dpdk.json
@@ -8,6 +8,7 @@
"name": "dpdk0",
"driver": "igb_uio",
"mtu": 8192,
+ "rx_queue": 4,
"members": [
{
"type": "interface",
diff --git a/etc/os-net-config/samples/ovs_dpdk.yaml b/etc/os-net-config/samples/ovs_dpdk.yaml
index 47fd3ab..81aa212 100644
--- a/etc/os-net-config/samples/ovs_dpdk.yaml
+++ b/etc/os-net-config/samples/ovs_dpdk.yaml
@@ -16,6 +16,12 @@ network_config:
driver: igb_uio
# MTU is optional, used for jumbo frames
mtu: 8192
+ # rx_queue is optional, used for multi-queue option. It configures the
+ # maximum number of queues for a physical interface. If not defined,
+ # the physical interface will have single queue. The number of queues
+ # should be less than the PMD cores as each queue will have one PMD
+ # thread (CPU) associated with it.
+ rx_queue: 4
members:
- type: interface
name: nic2
diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py
index d33ebd2..997b695 100644
--- a/os_net_config/impl_ifcfg.py
+++ b/os_net_config/impl_ifcfg.py
@@ -301,6 +301,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
if base_opt.mtu:
ovs_extra.append("set Interface $DEVICE mtu_request=$MTU")
+ if base_opt.rx_queue:
+ data += "RX_QUEUE=%i\n" % base_opt.rx_queue
+ ovs_extra.append("set Interface $DEVICE " +
+ "options:n_rxq=$RX_QUEUE")
elif isinstance(base_opt, objects.OvsDpdkBond):
ovs_extra.extend(base_opt.ovs_extra)
# Referring to bug:1643026, the below commenting of the interfaces,
diff --git a/os_net_config/objects.py b/os_net_config/objects.py
index 5124a1e..5fe6e49 100644
--- a/os_net_config/objects.py
+++ b/os_net_config/objects.py
@@ -81,6 +81,32 @@ def _get_required_field(json, name, object_name):
return field
+def _update_members(json, nic_mapping, persist_mapping):
+ """Update object's members fields and pass mapping info to each member.
+
+ :param json: dictionary containing object values
+ :param nic_mapping: mapping of abstractions to actual nic names
+ :param persist_mapping: bool indicating mapping file should be permanent
+ :returns members: updated members
+ """
+ members = []
+
+ members_json = json.get('members')
+ if members_json:
+ if isinstance(members_json, list):
+ for member in members_json:
+ # If this member already has a nic mapping, don't overwrite it
+ if not member.get('nic_mapping'):
+ member.update({'nic_mapping': nic_mapping})
+ member.update({'persist_mapping': persist_mapping})
+ members.append(object_from_json(member))
+ else:
+ msg = 'Members must be a list.'
+ raise InvalidConfigException(msg)
+
+ return members
+
+
def _mapped_nics(nic_mapping=None):
mapping = nic_mapping or {}
global _MAPPED_NICS
@@ -466,17 +492,8 @@ class OvsBridge(_BaseOpts):
if not isinstance(ovs_extra, list):
ovs_extra = [ovs_extra]
fail_mode = json.get('ovs_fail_mode', DEFAULT_OVS_BRIDGE_FAIL_MODE)
- members = []
- # members
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
return OvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@@ -534,17 +551,8 @@ class OvsUserBridge(_BaseOpts):
if not isinstance(ovs_extra, list):
ovs_extra = [ovs_extra]
fail_mode = json.get('ovs_fail_mode', DEFAULT_OVS_BRIDGE_FAIL_MODE)
- members = []
- # members
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
return OvsUserBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@@ -592,17 +600,8 @@ class LinuxBridge(_BaseOpts):
persist_mapping, defroute, dhclient_args,
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
- members = []
- # members
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
return LinuxBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@@ -655,17 +654,8 @@ class IvsBridge(_BaseOpts):
persist_mapping, defroute, dhclient_args,
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
- members = []
- # members
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
return IvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@@ -715,16 +705,7 @@ class NfvswitchBridge(_BaseOpts):
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
- # members
- members = []
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
options = json.get('options')
if not options:
@@ -778,17 +759,8 @@ class LinuxTeam(_BaseOpts):
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
bonding_options = json.get('bonding_options')
- members = []
- # members
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
return LinuxTeam(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@@ -837,17 +809,8 @@ class LinuxBond(_BaseOpts):
dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
bonding_options = json.get('bonding_options')
- members = []
- # members
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
return LinuxBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@@ -902,17 +865,8 @@ class OvsBond(_BaseOpts):
ovs_extra = json.get('ovs_extra', [])
if not isinstance(ovs_extra, list):
ovs_extra = [ovs_extra]
- members = []
- # members
- members_json = json.get('members')
- if members_json:
- if isinstance(members_json, list):
- for member in members_json:
- members.append(object_from_json(member))
- else:
- msg = 'Members must be a list.'
- raise InvalidConfigException(msg)
+ members = _update_members(json, nic_mapping, persist_mapping)
return OvsBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
@@ -1025,7 +979,8 @@ class OvsDpdkPort(_BaseOpts):
routes=None, mtu=None, primary=False, nic_mapping=None,
persist_mapping=False, defroute=True, dhclient_args=None,
dns_servers=None, nm_controlled=False, members=None,
- driver='vfio-pci', ovs_options=None, ovs_extra=None):
+ driver='vfio-pci', ovs_options=None, ovs_extra=None,
+ rx_queue=None):
super(OvsDpdkPort, self).__init__(name, use_dhcp, use_dhcpv6,
addresses, routes, mtu, primary,
@@ -1036,11 +991,16 @@ class OvsDpdkPort(_BaseOpts):
self.ovs_options = ovs_options or []
self.ovs_extra = format_ovs_extra(self, ovs_extra)
self.driver = driver
+ self.rx_queue = rx_queue
@staticmethod
def from_json(json):
name = _get_required_field(json, 'name', 'OvsDpdkPort')
# driver name by default will be 'vfio-pci' if not specified
+ (use_dhcp, use_dhcpv6, addresses, routes, mtu, primary, nic_mapping,
+ persist_mapping, defroute, dhclient_args,
+ dns_servers, nm_controlled) = _BaseOpts.base_opts_from_json(json)
+
driver = json.get('driver')
if not driver:
driver = 'vfio-pci'
@@ -1051,7 +1011,11 @@ class OvsDpdkPort(_BaseOpts):
if members_json:
if isinstance(members_json, list):
if len(members_json) == 1:
- iface = object_from_json(members_json[0])
+ member = members_json[0]
+ if not member.get('nic_mapping'):
+ member.update({'nic_mapping': nic_mapping})
+ member.update({'persist_mapping': persist_mapping})
+ iface = object_from_json(member)
if isinstance(iface, Interface):
# TODO(skramaja): Add checks for IP and route not to
# be set in the interface part of DPDK Port
@@ -1069,14 +1033,21 @@ class OvsDpdkPort(_BaseOpts):
msg = 'DPDK Port should have one member as Interface'
raise InvalidConfigException(msg)
+ rx_queue = json.get('rx_queue', None)
ovs_options = json.get('ovs_options', [])
ovs_options = ['options:%s' % opt for opt in ovs_options]
ovs_extra = json.get('ovs_extra', [])
if not isinstance(ovs_extra, list):
ovs_extra = [ovs_extra]
- opts = _BaseOpts.base_opts_from_json(json)
- return OvsDpdkPort(name, *opts, members=members, driver=driver,
- ovs_options=ovs_options, ovs_extra=ovs_extra)
+ return OvsDpdkPort(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
+ addresses=addresses, routes=routes, mtu=mtu,
+ primary=primary, nic_mapping=nic_mapping,
+ persist_mapping=persist_mapping, defroute=defroute,
+ dhclient_args=dhclient_args,
+ dns_servers=dns_servers,
+ nm_controlled=nm_controlled, members=members,
+ driver=driver, ovs_options=ovs_options,
+ ovs_extra=ovs_extra, rx_queue=rx_queue)
class OvsDpdkBond(_BaseOpts):
@@ -1130,6 +1101,9 @@ class OvsDpdkBond(_BaseOpts):
if members_json:
if isinstance(members_json, list):
for member in members_json:
+ if not member.get('nic_mapping'):
+ member.update({'nic_mapping': nic_mapping})
+ member.update({'persist_mapping': persist_mapping})
obj = object_from_json(member)
if isinstance(obj, OvsDpdkPort):
members.append(obj)
diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py
index 2d25a39..80f83f1 100644
--- a/os_net_config/tests/test_impl_ifcfg.py
+++ b/os_net_config/tests/test_impl_ifcfg.py
@@ -885,8 +885,47 @@ DNS2=5.6.7.8
self.stubbed_mapped_nics = nic_mapping
interface = objects.Interface(name='nic3')
+ dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface])
+ bridge = objects.OvsUserBridge('br-link', members=[dpdk_port])
+
+ def test_bind_dpdk_interfaces(ifname, driver, noop):
+ self.assertEqual(ifname, 'eth2')
+ self.assertEqual(driver, 'vfio-pci')
+ self.stubs.Set(utils, 'bind_dpdk_interfaces',
+ test_bind_dpdk_interfaces)
+
+ self.provider.add_ovs_dpdk_port(dpdk_port)
+ self.provider.add_ovs_user_bridge(bridge)
+ br_link_config = """# This file is autogenerated by os-net-config
+DEVICE=br-link
+ONBOOT=yes
+HOTPLUG=no
+NM_CONTROLLED=no
+PEERDNS=no
+DEVICETYPE=ovs
+TYPE=OVSUserBridge
+"""
+ dpdk0_config = """# This file is autogenerated by os-net-config
+DEVICE=dpdk0
+ONBOOT=yes
+HOTPLUG=no
+NM_CONTROLLED=no
+PEERDNS=no
+DEVICETYPE=ovs
+TYPE=OVSDPDKPort
+OVS_BRIDGE=br-link
+"""
+ self.assertEqual(br_link_config,
+ self.provider.bridge_data['br-link'])
+ self.assertEqual(dpdk0_config, self.get_interface_config('dpdk0'))
+
+ def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue(self):
+ nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'}
+ self.stubbed_mapped_nics = nic_mapping
+
+ interface = objects.Interface(name='nic3')
dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface],
- mtu=9000)
+ mtu=9000, rx_queue=4)
bridge = objects.OvsUserBridge('br-link', members=[dpdk_port])
def test_bind_dpdk_interfaces(ifname, driver, noop):
@@ -915,8 +954,10 @@ PEERDNS=no
DEVICETYPE=ovs
TYPE=OVSDPDKPort
OVS_BRIDGE=br-link
+RX_QUEUE=4
MTU=9000
-OVS_EXTRA="set Interface $DEVICE mtu_request=$MTU"
+OVS_EXTRA="set Interface $DEVICE mtu_request=$MTU \
+-- set Interface $DEVICE options:n_rxq=$RX_QUEUE"
"""
self.assertEqual(br_link_config,
self.provider.bridge_data['br-link'])
diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py
index 1199bb2..eb5adaf 100644
--- a/os_net_config/tests/test_objects.py
+++ b/os_net_config/tests/test_objects.py
@@ -621,6 +621,17 @@ class TestBond(base.TestCase):
interface2 = bridge.members[1]
self.assertEqual("em2", interface2.name)
+ def _stub_active_nics(self, nics):
+ def dummy_ordered_active_nics():
+ return nics
+ self.stubs.Set(utils, 'ordered_active_nics', dummy_ordered_active_nics)
+
+ def _stub_available_nics(self, nics):
+ def dummy_ordered_available_nics():
+ return nics
+ self.stubs.Set(utils, 'ordered_available_nics',
+ dummy_ordered_available_nics)
+
class TestLinuxTeam(base.TestCase):
@@ -1007,6 +1018,102 @@ class TestNicMapping(base.TestCase):
# This only emits a warning, so it should still work
self.assertEqual(expected, objects._mapped_nics())
+ # Test that mapping file is passed to interface members from parent object
+ def _test_mapped_nics_with_parent(self, type, name):
+ self._stub_available_nics(['foo', 'bar'])
+ mapping = {"nic1": "foo", "nic2": "bar"}
+
+ data = """{
+ "members": [{"type": "interface", "name": "nic1"},
+ {"type": "interface", "name": "nic2"}]
+ }
+ """
+ json_output = json.loads(data)
+ json_output.update({'type': type})
+ json_output.update({'name': name})
+ json_output.update({'nic_mapping': mapping})
+ obj = objects.object_from_json(json_output)
+
+ self.assertEqual("foo", obj.members[0].name)
+ self.assertEqual("bar", obj.members[1].name)
+
+ def test_mapped_nics_ovs_bond(self):
+ self._test_mapped_nics_with_parent("ovs_bond", "bond1")
+
+ def test_mapped_nics_linux_bond(self):
+ self._test_mapped_nics_with_parent("linux_bond", "bond1")
+
+ def test_mapped_nics_ovs_bridge(self):
+ self._test_mapped_nics_with_parent("ovs_bridge", "br-foo")
+
+ def test_mapped_nics_ovs_user_bridge(self):
+ self._test_mapped_nics_with_parent("ovs_user_bridge", "br-foo")
+
+ def test_mapped_nics_linux_bridge(self):
+ self._test_mapped_nics_with_parent("linux_bridge", "br-foo")
+
+ def test_mapped_nics_ivs_bridge(self):
+ self._test_mapped_nics_with_parent("ivs_bridge", "br-foo")
+
+ def test_mapped_nics_linux_team(self):
+ self._test_mapped_nics_with_parent("team", "team-foo")
+
+ def test_mapped_nics_bridge_and_bond(self):
+ self._stub_available_nics(['foo', 'bar'])
+ mapping = {"nic1": "foo", "nic2": "bar"}
+
+ data = """{
+"type": "ovs_bridge",
+"name": "br-foo",
+"members": [
+ {
+ "type": "ovs_bond",
+ "name": "bond0",
+ "members": [{"type": "interface", "name": "nic1"},
+ {"type": "interface", "name": "nic2"}]
+ }
+]
+}
+"""
+ json_output = json.loads(data)
+ json_output.update({'nic_mapping': mapping})
+ obj = objects.object_from_json(json_output)
+
+ interface1 = obj.members[0].members[0]
+ interface2 = obj.members[0].members[1]
+ self.assertEqual("foo", interface1.name)
+ self.assertEqual("bar", interface2.name)
+
+ def test_mapped_nics_ovs_dpdk_bond(self):
+ self._stub_available_nics(['foo', 'bar'])
+ mapping = {"nic2": "foo", "nic3": "bar"}
+
+ data = """{
+"type": "ovs_dpdk_bond",
+"name": "dpdkbond0",
+"members": [
+ {
+ "type": "ovs_dpdk_port",
+ "name": "dpdk0",
+ "members": [{"type": "interface", "name": "nic2"}]
+ },
+ {
+ "type": "ovs_dpdk_port",
+ "name": "dpdk1",
+ "members": [{"type": "interface", "name": "nic3"}]
+ }
+]
+}
+"""
+ json_output = json.loads(data)
+ json_output.update({'nic_mapping': mapping})
+ dpdk_port = objects.object_from_json(json_output)
+ interface1 = dpdk_port.members[0].members[0]
+ interface2 = dpdk_port.members[1].members[0]
+
+ self.assertEqual("foo", interface1.name)
+ self.assertEqual("bar", interface2.name)
+
class TestOvsDpdkBond(base.TestCase):