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
This commit is contained in:
Nikolay Nikolaev 2018-06-12 14:21:48 +03:00
parent 8225b4dca9
commit 587de9197e
3 changed files with 147 additions and 0 deletions

View File

@ -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

View File

@ -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]

View File

@ -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'
})