From 587de9197ec7f06bff5e69f16517b03d1929c76b Mon Sep 17 00:00:00 2001 From: Nikolay Nikolaev Date: Tue, 12 Jun 2018 14:21:48 +0300 Subject: [PATCH] ovs-dpdk: add dpdk-bond-config config option This allows more fine grained control over the bond mode and LACP settings. Directly mapped to what OVS-DPDK configuration exposes. Change-Id: I1cca1043058f1ec99f194c1bdb611ebd603d646d --- config.yaml | 19 ++++++ hooks/neutron_ovs_utils.py | 89 ++++++++++++++++++++++++++++ unit_tests/test_neutron_ovs_utils.py | 39 ++++++++++++ 3 files changed, 147 insertions(+) diff --git a/config.yaml b/config.yaml index 048f3297..59b91a05 100644 --- a/config.yaml +++ b/config.yaml @@ -46,6 +46,25 @@ options: bridge as specified in data-port. . This option is supported only when enable-dpdk is true. + dpdk-bond-config: + type: string + default: ":balance-tcp:active:fast" + description: | + Space delimited list of bond:mode:lacp:lacp-time, where the arguments meaning is: + . + * bond - the bond name. If not specified the configuration applies to all bonds + * mode - the bond mode of operation. Possible values are: + - active-backup - No load balancing is offered in this mode and only one of + the member ports is active/used at a time. + - balance-slb - Considered as a static load-balancing mode. Traffic is load + balanced between member ports based on the source MAC and VLAN. + - balance-tcp - This is the preferred bonding mode. It offers traffic load + balancing based on 5-tuple header fields. LACP must be enabled + at both endpoints to use this mode. The aggregate link will + fall back to default mode (active-passive) in the event of LACP + negotiation failure. + * lacp - active, passive or off + * lacp-time - fast or slow. LACP negotiation time interval - 30 ms or 1 second disable-security-groups: type: boolean default: false diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index 130d0a29..163ab584 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -441,9 +441,11 @@ def configure_ovs(): pci_address) device_index += 1 + bond_configs = DPDKBondsConfig() for br, bonds in bridge_bond_map.items(): for bond, t in bonds.items(): dpdk_add_bridge_bond(br, bond, *t) + dpdk_set_bond_config(bond, bond_configs.get_bond_config(bond)) target = config('ipfix-target') bridges = [INT_BRIDGE, EXT_BRIDGE] @@ -635,6 +637,21 @@ def dpdk_add_bridge_bond(bridge_name, bond_name, port_list, pci_address_list): subprocess.check_call(cmd) +def dpdk_set_bond_config(bond_name, config): + if ovs_has_late_dpdk_init(): + cmd = ["ovs-vsctl", + "--", "set", "port", bond_name, + "bond_mode={}".format(config['mode']), + "--", "set", "port", bond_name, + "lacp={}".format(config['lacp']), + "--", "set", "port", bond_name, + "other_config:lacp-time=={}".format(config['lacp-time']), + ] + else: + raise Exception("Bonds are not supported for OVS pre-2.6.0") + subprocess.check_call(cmd) + + def enable_nova_metadata(): return use_dvr() or enable_local_dhcp() @@ -731,3 +748,75 @@ class DPDKBridgeBondMap(): def items(self): return list(self.map.items()) + + +class DPDKBondsConfig(): + ''' + A class to parse dpdk-bond-config into a dictionary and + provide a convenient config get interface. + ''' + + DEFAUL_LACP_CONFIG = { + 'mode': 'balance-tcp', + 'lacp': 'active', + 'lacp-time': 'fast' + } + ALL_BONDS = 'ALL_BONDS' + + BOND_MODES = ['active-backup', 'balance-slb', 'balance-tcp'] + BOND_LACP = ['active', 'passive', 'off'] + BOND_LACP_TIME = ['fast', 'slow'] + + def __init__(self): + + self.lacp_config = { + self.ALL_BONDS: deepcopy(self.DEFAUL_LACP_CONFIG) + } + + lacp_config = config('dpdk-bond-config') + if lacp_config: + lacp_config_map = lacp_config.split() + for entry in lacp_config_map: + bond, entry = self._partition_entry(entry) + if not bond: + bond = self.ALL_BONDS + + mode, entry = self._partition_entry(entry) + if not mode: + mode = self.DEFAUL_LACP_CONFIG['mode'] + assert mode in self.BOND_MODES, \ + "Bond mode {} is invalid".format(mode) + + lacp, entry = self._partition_entry(entry) + if not lacp: + lacp = self.DEFAUL_LACP_CONFIG['lacp'] + assert lacp in self.BOND_LACP, \ + "Bond lacp {} is invalid".format(lacp) + + lacp_time, entry = self._partition_entry(entry) + if not lacp_time: + lacp_time = self.DEFAUL_LACP_CONFIG['lacp-time'] + assert lacp_time in self.BOND_LACP_TIME, \ + "Bond lacp-time {} is invalid".format(lacp_time) + + self.lacp_config[bond] = { + 'mode': mode, + 'lacp': lacp, + 'lacp-time': lacp_time + } + + def _partition_entry(self, entry): + t = entry.partition(":") + return t[0], t[2] + + def get_bond_config(self, bond): + ''' + Get the LACP configuration for a bond + + :param bond: the bond name + :return: a dictionary with the configuration of the + ''' + if bond not in self.lacp_config: + return self.lacp_config[self.ALL_BONDS] + + return self.lacp_config[bond] diff --git a/unit_tests/test_neutron_ovs_utils.py b/unit_tests/test_neutron_ovs_utils.py index 95107bfe..35a6dde7 100644 --- a/unit_tests/test_neutron_ovs_utils.py +++ b/unit_tests/test_neutron_ovs_utils.py @@ -35,6 +35,7 @@ TO_PATCH = [ 'is_linuxbridge_interface', 'dpdk_add_bridge_port', 'dpdk_add_bridge_bond', + 'dpdk_set_bond_config', 'apt_install', 'apt_update', 'config', @@ -511,6 +512,21 @@ class TestNeutronOVSUtils(CharmTestCase): call('br-phynet3', 'bond2', ['dpdk2'], ['0000:001c.03'])], any_order=True ) + self.dpdk_set_bond_config.assert_has_calls([ + call('bond0', + {'mode': 'balance-tcp', + 'lacp': 'active', + 'lacp-time': 'fast'}), + call('bond1', + {'mode': 'balance-tcp', + 'lacp': 'active', + 'lacp-time': 'fast'}), + call('bond2', + {'mode': 'balance-tcp', + 'lacp': 'active', + 'lacp-time': 'fast'})], + any_order=True + ) else: self.dpdk_add_bridge_port.assert_has_calls([ call('br-phynet1', 'dpdk0', '0000:001c.01'), @@ -762,3 +778,26 @@ class TestDPDKBridgeBondMap(CharmTestCase): ] self.assertEqual(ctx.items(), expected) + + +class TestDPDKBondsConfig(CharmTestCase): + + def setUp(self): + super(TestDPDKBondsConfig, self).setUp(nutils, TO_PATCH) + self.config.side_effect = self.test_config.get + + def test_get_bond_config(self): + self.test_config.set('dpdk-bond-config', + ':active-backup bond1:balance-slb:off') + bonds_config = nutils.DPDKBondsConfig() + + self.assertEqual(bonds_config.get_bond_config('bond0'), + {'mode': 'active-backup', + 'lacp': 'active', + 'lacp-time': 'fast' + }) + self.assertEqual(bonds_config.get_bond_config('bond1'), + {'mode': 'balance-slb', + 'lacp': 'off', + 'lacp-time': 'fast' + })