Merge "Add support for VPP Bond"

This commit is contained in:
Zuul 2017-11-14 00:48:52 +00:00 committed by Gerrit Code Review
commit 3cbe5c9215
9 changed files with 411 additions and 51 deletions

View File

@ -0,0 +1,23 @@
{ "network_config": [
{
"type": "vpp_bond",
"name": "net_bonding0",
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
],
"bonding_options": "mode=2,xmit_policy=l34",
"members": [
{
"type": "vpp_interface",
"name": "eth1"
},
{
"type": "vpp_interface",
"name": "eth2"
}
]
}
]
}

View File

@ -0,0 +1,17 @@
network_config:
-
type: vpp_bond
# name must be in the format of eth_bondX or net_bondingX, where X is a
# unique number for each bond.
name: net_bonding0
addresses:
-
ip_netmask: 192.0.2.1/24
bonding_options: "mode=2,xmit_policy=l34"
members:
-
type: vpp_interface
name: eth1
-
type: vpp_interface
name: eth2

View File

@ -102,6 +102,10 @@ class NetConfig(object):
self.add_ovs_dpdk_bond(obj) self.add_ovs_dpdk_bond(obj)
elif isinstance(obj, objects.VppInterface): elif isinstance(obj, objects.VppInterface):
self.add_vpp_interface(obj) self.add_vpp_interface(obj)
elif isinstance(obj, objects.VppBond):
self.add_vpp_bond(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.ContrailVrouter): elif isinstance(obj, objects.ContrailVrouter):
self.add_contrail_vrouter(obj) self.add_contrail_vrouter(obj)
elif isinstance(obj, objects.ContrailVrouterDpdk): elif isinstance(obj, objects.ContrailVrouterDpdk):
@ -219,6 +223,13 @@ class NetConfig(object):
""" """
raise NotImplementedError("add_vpp_interface is not implemented.") raise NotImplementedError("add_vpp_interface is not implemented.")
def add_vpp_bond(self, vpp_bond):
"""Add a VppBond object to the net config object.
:param vpp_bond: The VppBond object to add.
"""
raise NotImplementedError("add_vpp_bond is not implemented.")
def add_contrail_vrouter(self, contrail_vrouter): def add_contrail_vrouter(self, contrail_vrouter):
"""Add a ContrailVrouter object to the net config object. """Add a ContrailVrouter object to the net config object.

View File

@ -121,6 +121,7 @@ class IfcfgNetConfig(os_net_config.NetConfig):
self.ib_interface_data = {} self.ib_interface_data = {}
self.linuxteam_data = {} self.linuxteam_data = {}
self.vpp_interface_data = {} self.vpp_interface_data = {}
self.vpp_bond_data = {}
self.member_names = {} self.member_names = {}
self.renamed_interfaces = {} self.renamed_interfaces = {}
self.bond_primary_ifaces = {} self.bond_primary_ifaces = {}
@ -676,6 +677,9 @@ class IfcfgNetConfig(os_net_config.NetConfig):
""" """
vpp_interface.pci_dev = utils.get_pci_address(vpp_interface.name, vpp_interface.pci_dev = utils.get_pci_address(vpp_interface.name,
False) False)
if not vpp_interface.pci_dev:
vpp_interface.pci_dev = utils.get_stored_pci_address(
vpp_interface.name, False)
vpp_interface.hwaddr = utils.interface_mac(vpp_interface.name) vpp_interface.hwaddr = utils.interface_mac(vpp_interface.name)
if not self.noop: if not self.noop:
self.ifdown(vpp_interface.name) self.ifdown(vpp_interface.name)
@ -684,6 +688,14 @@ class IfcfgNetConfig(os_net_config.NetConfig):
% (vpp_interface.name, vpp_interface.pci_dev)) % (vpp_interface.name, vpp_interface.pci_dev))
self.vpp_interface_data[vpp_interface.name] = vpp_interface self.vpp_interface_data[vpp_interface.name] = vpp_interface
def add_vpp_bond(self, vpp_bond):
"""Add a VppInterface object to the net config object
:param vpp_bond: The VPPBond object to add
"""
logger.info('adding vpp bond: %s' % vpp_bond.name)
self.vpp_bond_data[vpp_bond.name] = vpp_bond
def add_contrail_vrouter(self, contrail_vrouter): def add_contrail_vrouter(self, contrail_vrouter):
"""Add a ContraiVrouter object to the net config object """Add a ContraiVrouter object to the net config object
@ -806,6 +818,7 @@ class IfcfgNetConfig(os_net_config.NetConfig):
stop_dhclient_interfaces = [] stop_dhclient_interfaces = []
ovs_needs_restart = False ovs_needs_restart = False
vpp_interfaces = self.vpp_interface_data.values() vpp_interfaces = self.vpp_interface_data.values()
vpp_bonds = self.vpp_bond_data.values()
for interface_name, iface_data in self.interface_data.items(): for interface_name, iface_data in self.interface_data.items():
route_data = self.route_data.get(interface_name, '') route_data = self.route_data.get(interface_name, '')
@ -1014,9 +1027,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
logger.info('No changes required for InfiniBand iface: %s' % logger.info('No changes required for InfiniBand iface: %s' %
interface_name) interface_name)
if self.vpp_interface_data: if self.vpp_interface_data or self.vpp_bond_data:
vpp_path = self.root_dir + vpp_config_path() vpp_path = self.root_dir + vpp_config_path()
vpp_config = utils.generate_vpp_config(vpp_path, vpp_interfaces) vpp_config = utils.generate_vpp_config(vpp_path, vpp_interfaces,
vpp_bonds)
if utils.diff(vpp_path, vpp_config): if utils.diff(vpp_path, vpp_config):
restart_vpp = True restart_vpp = True
update_files[vpp_path] = vpp_config update_files[vpp_path] = vpp_config
@ -1139,7 +1153,7 @@ class IfcfgNetConfig(os_net_config.NetConfig):
if self.vpp_interface_data: if self.vpp_interface_data:
logger.info('Updating VPP mapping') logger.info('Updating VPP mapping')
utils.update_vpp_mapping(vpp_interfaces) utils.update_vpp_mapping(vpp_interfaces, vpp_bonds)
if self.errors: if self.errors:
message = 'Failure(s) occurred when applying configuration' message = 'Failure(s) occurred when applying configuration'

View File

@ -76,6 +76,8 @@ def object_from_json(json):
return OvsDpdkBond.from_json(json) return OvsDpdkBond.from_json(json)
elif obj_type == "vpp_interface": elif obj_type == "vpp_interface":
return VppInterface.from_json(json) return VppInterface.from_json(json)
elif obj_type == "vpp_bond":
return VppBond.from_json(json)
elif obj_type == "contrail_vrouter": elif obj_type == "contrail_vrouter":
return ContrailVrouter.from_json(json) return ContrailVrouter.from_json(json)
elif obj_type == "contrail_vrouter_dpdk": elif obj_type == "contrail_vrouter_dpdk":
@ -1225,6 +1227,61 @@ class VppInterface(_BaseOpts):
options=options) options=options)
class VppBond(_BaseOpts):
"""Base class for VPP Bond."""
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
routes=None, mtu=None, primary=False, nic_mapping=None,
persist_mapping=False, defroute=True, dhclient_args=None,
dns_servers=None, nm_controlled=False, onboot=True,
members=None, bonding_options=None):
addresses = addresses or []
members = members or []
super(VppBond, self).__init__(name, use_dhcp, use_dhcpv6,
addresses, routes, mtu, primary,
nic_mapping, persist_mapping,
defroute, dhclient_args,
dns_servers, nm_controlled, onboot)
self.members = members
self.bonding_options = bonding_options
@staticmethod
def from_json(json):
name = _get_required_field(json, 'name', 'VppBond')
bonding_options = json.get('bonding_options', '')
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
persist_mapping, defroute, dhclient_args,
dns_servers, nm_controlled, onboot) = _BaseOpts.base_opts_from_json(
json, include_primary=False)
members = []
members_json = json.get('members', None)
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, VppInterface):
members.append(obj)
else:
msg = 'Members must be of type vpp_interface'
raise InvalidConfigException(msg)
else:
msg = 'Members must be a list.'
raise InvalidConfigException(msg)
return VppBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
addresses=addresses, routes=routes, mtu=mtu,
members=members, nic_mapping=nic_mapping,
persist_mapping=persist_mapping,
defroute=defroute, dhclient_args=dhclient_args,
dns_servers=dns_servers, nm_controlled=nm_controlled,
onboot=onboot, bonding_options=bonding_options)
class ContrailVrouter(_BaseOpts): class ContrailVrouter(_BaseOpts):
"""Base class for Contrail Interface. """Base class for Contrail Interface.

View File

@ -669,6 +669,54 @@ definitions:
- name - name
additionalProperties: False additionalProperties: False
vpp_bond:
type: object
properties:
type:
enum: ["vpp_bond"]
name:
$ref: "#/definitions/string_or_param"
uio_driver:
$ref: "#/definitions/string_or_param"
options:
$ref: "#/definitions/string_or_param"
# common options:
use_dhcp:
$ref: "#/definitions/bool_or_param"
use_dhcp6:
$ref: "#/definitions/bool_or_param"
addresses:
$ref: "#/definitions/list_of_address"
routes:
$ref: "#/definitions/list_of_route"
mtu:
$ref: "#/definitions/int_or_param"
nic_mapping:
$ref: "#/definitions/nic_mapping"
persist_mapping:
$ref: "#/definitions/bool_or_param"
defroute:
$ref: "#/definitions/bool_or_param"
dhclient_args:
$ref: "#/definitions/string_or_param"
dns_servers:
$ref: "#/definitions/list_of_ip_address_string_or_param"
nm_controlled:
$ref: "#/definitions/bool_or_param"
onboot:
$ref: "#/definitions/bool_or_param"
members:
type: array
items:
oneOf:
- $ref: "#/definitions/vpp_interface"
bonding_options:
$ref: "#/definitions/string_or_param"
required:
- type
- name
additionalProperties: False
contrail_vrouter: contrail_vrouter:
type: object type: object
properties: properties:
@ -1135,6 +1183,7 @@ items:
- $ref: "#/definitions/nfvswitch_internal" - $ref: "#/definitions/nfvswitch_internal"
- $ref: "#/definitions/ib_interface" - $ref: "#/definitions/ib_interface"
- $ref: "#/definitions/vpp_interface" - $ref: "#/definitions/vpp_interface"
- $ref: "#/definitions/vpp_bond"
- $ref: "#/definitions/contrail_vrouter" - $ref: "#/definitions/contrail_vrouter"
- $ref: "#/definitions/contrail_vrouter_dpdk" - $ref: "#/definitions/contrail_vrouter_dpdk"
minItems: 1 minItems: 1

View File

@ -1256,3 +1256,55 @@ class TestVppInterface(base.TestCase):
self.assertEqual("em1", vpp_interface.name) self.assertEqual("em1", vpp_interface.name)
self.assertEqual("uio_pci_generic", vpp_interface.uio_driver) self.assertEqual("uio_pci_generic", vpp_interface.uio_driver)
self.assertEqual("vlan-strip-offload off", vpp_interface.options) self.assertEqual("vlan-strip-offload off", vpp_interface.options)
class TestVppBond(base.TestCase):
def test_vpp_interface_from_json(self):
data = """{
"type": "vpp_bond",
"name": "net_bonding0",
"members": [
{
"type": "vpp_interface",
"name": "eth1"
},
{
"type": "vpp_interface",
"name": "eth2"
}
],
"bonding_options": "mode=2,xmit_policy=l34"
}
"""
vpp_bond = objects.object_from_json(json.loads(data))
self.assertEqual("net_bonding0", vpp_bond.name)
self.assertEqual("mode=2,xmit_policy=l34", vpp_bond.bonding_options)
vpp_int1 = vpp_bond.members[0]
self.assertEqual("eth1", vpp_int1.name)
vpp_int2 = vpp_bond.members[1]
self.assertEqual("eth2", vpp_int2.name)
def test_invalid_vpp_interface_from_json(self):
data = """{
"type": "vpp_bond",
"name": "net_bonding0",
"members": [
{
"type": "vpp_interface",
"name": "eth1"
},
{
"type": "interface",
"name": "eth2"
}
],
"bonding_options": "mode=2,xmit_policy=l34"
}
"""
err = self.assertRaises(objects.InvalidConfigException,
objects.object_from_json,
json.loads(data))
expected = 'Members must be of type vpp_interface'
self.assertIn(expected, six.text_type(err))

View File

@ -47,6 +47,13 @@ local0 0 down
''' '''
_VPPBOND_OUTPUT = """
Name Idx Link Hardware
BondEthernet0 3 up Slave-Idx: 1 2
TenGigabitEthernet2/0/0 1 slave TenGigabitEthernet2/0/0
TenGigabitEthernet2/0/1 2 slave TenGigabitEthernet2/0/1
"""
_INITIAL_VPP_CONFIG = ''' _INITIAL_VPP_CONFIG = '''
unix { unix {
nodaemon nodaemon
@ -339,8 +346,8 @@ class TestUtils(base.TestCase):
shutil.rmtree(tmpdir) shutil.rmtree(tmpdir)
def test_get_vpp_interface_name(self): def test_get_vpp_interface(self):
def test_execute(name, dummy1, dummy2=None, dummy3=None): def test_execute(name, *args, **kwargs):
if 'systemctl' in name: if 'systemctl' in name:
return None, None return None, None
if 'vppctl' in name: if 'vppctl' in name:
@ -348,19 +355,37 @@ class TestUtils(base.TestCase):
self.stubs.Set(processutils, 'execute', test_execute) self.stubs.Set(processutils, 'execute', test_execute)
self.assertEqual('GigabitEthernet0/9/0', int_info = utils._get_vpp_interface('0000:00:09.0')
utils._get_vpp_interface_name('0000:00:09.0')) self.assertIsNotNone(int_info)
self.assertIsNone(utils._get_vpp_interface_name(None)) self.assertEqual('GigabitEthernet0/9/0', int_info['name'])
self.assertIsNone(utils._get_vpp_interface_name('0000:01:09.0')) self.assertEqual('1', int_info['index'])
self.assertIsNone(utils._get_vpp_interface(None))
self.assertIsNone(utils._get_vpp_interface('0000:01:09.0'))
self.assertRaises(utils.VppException, self.assertRaises(utils.VppException,
utils._get_vpp_interface_name, '0000:09.0') utils._get_vpp_interface, '0000:09.0')
@mock.patch('os_net_config.utils.processutils.execute', @mock.patch('os_net_config.utils.processutils.execute',
return_value=('', None)) return_value=('', None))
def test_get_vpp_interface_name_multiple_iterations(self, mock_execute): def test_get_vpp_interface_name_multiple_iterations(self, mock_execute):
self.assertIsNone(utils._get_vpp_interface_name('0000:00:09.0', 2, 1)) self.assertIsNone(utils._get_vpp_interface('0000:00:09.0', 2, 1))
self.assertEqual(4, mock_execute.call_count) self.assertEqual(4, mock_execute.call_count)
def test_get_vpp_bond(self):
def test_execute(name, *args, **kwargs):
if 'systemctl' in name:
return None, None
if 'vppctl' in name:
return _VPPBOND_OUTPUT, None
self.stubs.Set(processutils, 'execute', test_execute)
bond_info = utils._get_vpp_bond(['1', '2'])
self.assertIsNotNone(bond_info)
self.assertEqual('BondEthernet0', bond_info['name'])
self.assertEqual('3', bond_info['index'])
self.assertIsNone(utils._get_vpp_bond(['1']))
self.assertIsNone(utils._get_vpp_bond(['1', '2', '3']))
self.assertIsNone(utils._get_vpp_bond([]))
def test_generate_vpp_config(self): def test_generate_vpp_config(self):
tmpdir = tempfile.mkdtemp() tmpdir = tempfile.mkdtemp()
config_path = os.path.join(tmpdir, 'startup.conf') config_path = os.path.join(tmpdir, 'startup.conf')
@ -374,6 +399,7 @@ class TestUtils(base.TestCase):
int2 = objects.VppInterface('em2') int2 = objects.VppInterface('em2')
int2.pci_dev = '0000:00:09.1' int2.pci_dev = '0000:00:09.1'
interfaces = [int1, int2] interfaces = [int1, int2]
bonds = []
expected_config = ''' expected_config = '''
unix { unix {
exec %s exec %s
@ -399,9 +425,45 @@ dpdk {
} }
''' % vpp_exec_path ''' % vpp_exec_path
self.assertEqual(expected_config, self.assertEqual(expected_config,
utils.generate_vpp_config(config_path, interfaces)) utils.generate_vpp_config(config_path, interfaces,
bonds))
bonds = [objects.VppBond('net_bonding0', members=interfaces,
bonding_options='mode=2,xmit_policy=l3')]
expected_config = '''
unix {
exec %s
nodaemon
log /tmp/vpp.log
full-coredump
}
api-trace {
on
}
api-segment {
gid vpp
}
dpdk {
vdev net_bonding0,slave=0000:00:09.0,slave=0000:00:09.1,mode=2,xmit_policy=l3
dev 0000:00:09.1
uio-driver vfio-pci
dev 0000:00:09.0 {vlan-strip-offload off}
}
''' % vpp_exec_path
self.assertEqual(expected_config,
utils.generate_vpp_config(config_path, interfaces,
bonds))
def test_update_vpp_mapping(self): def test_update_vpp_mapping(self):
tmpdir = tempfile.mkdtemp()
vpp_exec_path = os.path.join(tmpdir, 'vpp-exec')
utils._VPP_EXEC_FILE = vpp_exec_path
def test_get_dpdk_map(): def test_get_dpdk_map():
return [{'name': 'eth1', 'pci_address': '0000:00:09.0', return [{'name': 'eth1', 'pci_address': '0000:00:09.0',
'mac_address': '01:02:03:04:05:06', 'mac_address': '01:02:03:04:05:06',
@ -409,15 +471,15 @@ dpdk {
self.stubs.Set(utils, '_get_dpdk_map', test_get_dpdk_map) self.stubs.Set(utils, '_get_dpdk_map', test_get_dpdk_map)
def test_execute(name, dummy1, dummy2=None, dummy3=None): def test_execute(name, *args, **kwargs):
return None, None return None, None
self.stubs.Set(processutils, 'execute', test_execute) self.stubs.Set(processutils, 'execute', test_execute)
def test_get_vpp_interface_name(pci_dev, tries, timeout): def test_get_vpp_interface(pci_dev, tries, timeout):
return 'GigabitEthernet0/9/0' return {'name': 'GigabitEthernet0/9/0', 'index': '1'}
self.stubs.Set(utils, '_get_vpp_interface_name', self.stubs.Set(utils, '_get_vpp_interface',
test_get_vpp_interface_name) test_get_vpp_interface)
int1 = objects.VppInterface('eth1', options="vlan-strip-offload off") int1 = objects.VppInterface('eth1', options="vlan-strip-offload off")
int1.pci_dev = '0000:00:09.0' int1.pci_dev = '0000:00:09.0'
@ -427,7 +489,7 @@ dpdk {
int2.hwaddr = '01:02:03:04:05:07' int2.hwaddr = '01:02:03:04:05:07'
interfaces = [int1, int2] interfaces = [int1, int2]
utils.update_vpp_mapping(interfaces) utils.update_vpp_mapping(interfaces, [])
contents = utils.get_file_data(utils._DPDK_MAPPING_FILE) contents = utils.get_file_data(utils._DPDK_MAPPING_FILE)

View File

@ -355,11 +355,12 @@ def restart_vpp(vpp_interfaces):
processutils.execute('systemctl', 'restart', 'vpp') processutils.execute('systemctl', 'restart', 'vpp')
def _get_vpp_interface_name(pci_addr, tries=1, timeout=5): def _get_vpp_interface(pci_addr, tries=1, timeout=5):
"""Get VPP interface name from a given PCI address """Get VPP interface information from a given PCI address
From a running VPP instance, attempt to find the interface name from From a running VPP instance, attempt to find the interface name and index
a given PCI address of a NIC. from a given PCI address of a NIC. The index is used to identify VPP bond
interface associated with the VPP interface.
:param pci_addr: PCI address to lookup, in the form of DDDD:BB:SS.F, where :param pci_addr: PCI address to lookup, in the form of DDDD:BB:SS.F, where
- DDDD = Domain - DDDD = Domain
@ -377,7 +378,8 @@ def _get_vpp_interface_name(pci_addr, tries=1, timeout=5):
try: try:
timestamp = time.time() timestamp = time.time()
processutils.execute('systemctl', 'is-active', 'vpp') processutils.execute('systemctl', 'is-active', 'vpp')
out, err = processutils.execute('vppctl', 'show', 'interface') out, err = processutils.execute('vppctl', 'show', 'interface',
check_exit_code=False)
logger.debug("vppctl show interface\n%s\n%s\n" % (out, err)) logger.debug("vppctl show interface\n%s\n%s\n" % (out, err))
m = re.search(r':([0-9a-fA-F]{2}):([0-9a-fA-F]{2}).([0-9a-fA-F])', m = re.search(r':([0-9a-fA-F]{2}):([0-9a-fA-F]{2}).([0-9a-fA-F])',
pci_addr) pci_addr)
@ -388,10 +390,12 @@ def _get_vpp_interface_name(pci_addr, tries=1, timeout=5):
else: else:
raise VppException('Invalid PCI address format: %s' % pci_addr) raise VppException('Invalid PCI address format: %s' % pci_addr)
m = re.search(r'^(\w+%s)\s+' % formatted_pci, out, re.MULTILINE) m = re.search(r'^(\w+%s)\s+(\d+)' % formatted_pci, out,
re.MULTILINE)
if m: if m:
logger.debug('VPP interface found: %s' % m.group(1)) logger.debug('VPP interface found: %s, index: %s' %
return m.group(1) (m.group(1), m.group(2)))
return {'name': m.group(1), 'index': m.group(2)}
except processutils.ProcessExecutionError: except processutils.ProcessExecutionError:
pass pass
@ -402,7 +406,36 @@ def _get_vpp_interface_name(pci_addr, tries=1, timeout=5):
return None return None
def generate_vpp_config(vpp_config_path, vpp_interfaces): def _get_vpp_bond(member_ids):
"""Get VPP bond information from a given list of VPP interface indices
:param member_ids: list of VPP interfaces indices for the bond
:return: VPP bond name and index. None if an interface is not found.
"""
if not member_ids:
return None
member_ids.sort()
member_ids_str = ' '.join(member_ids)
out, err = processutils.execute('vppctl', 'show',
'hardware-interfaces', 'bond', 'brief',
check_exit_code=False)
logger.debug('vppctl show hardware-interfaces bond brief\n%s' % out)
m = re.search(r'^\s*(BondEthernet\d+)\s+(\d+)\s+.+Slave-Idx:\s+%s\s*$' %
member_ids_str,
out,
re.MULTILINE)
if m:
logger.debug('Bond found: %s, index: %s' % (m.group(1), m.group(2)))
return {'name': m.group(1), 'index': m.group(2)}
else:
logger.debug('Bond with member indices "%s" not found in VPP'
% member_ids_str)
return None
def generate_vpp_config(vpp_config_path, vpp_interfaces, vpp_bonds):
"""Generate configuration content for VPP """Generate configuration content for VPP
Generate interface related configuration content for VPP. Current Generate interface related configuration content for VPP. Current
@ -419,6 +452,7 @@ def generate_vpp_config(vpp_config_path, vpp_interfaces):
:param vpp_config_path: VPP Configuration file path :param vpp_config_path: VPP Configuration file path
:param vpp_interfaces: List of VPP interface objects :param vpp_interfaces: List of VPP interface objects
:param vpp_bonds: List of VPP bond objects
:return: updated VPP config content. :return: updated VPP config content.
""" """
@ -473,8 +507,32 @@ def generate_vpp_config(vpp_config_path, vpp_interfaces):
data, data,
flags=re.MULTILINE) flags=re.MULTILINE)
else: else:
logger.debug('pci address not found for interface %s, may have' raise VppException('Interface %s has no PCI address and is not'
'already been bound to vpp' % vpp_interface.name) ' found in mapping file' % vpp_interface.name)
# Add bond config to 'dpdk' section
for vpp_bond in vpp_bonds:
slave_str = ''
for member in vpp_bond.members:
slave_str += ",slave=%s" % member.pci_dev
if vpp_bond.bonding_options:
options_str = ',' + vpp_bond.bonding_options.strip(' ,')
else:
options_str = ''
if slave_str:
m = re.search(r'^\s*vdev\s+%s.*$' % vpp_bond.name,
data, re.MULTILINE)
if m:
data = re.sub(m.group(0), r' vdev %s%s%s'
% (vpp_bond.name, slave_str, options_str),
data)
else:
data = re.sub(r'(^\s*dpdk\s*\{)',
r'\1\n vdev %s%s%s'
% (vpp_bond.name, slave_str, options_str),
data,
flags=re.MULTILINE)
# Add start up script for VPP to config. This script will be executed by # Add start up script for VPP to config. This script will be executed by
# VPP on service start. # VPP on service start.
@ -497,36 +555,29 @@ def generate_vpp_config(vpp_config_path, vpp_interfaces):
return data return data
def update_vpp_mapping(vpp_interfaces): def update_vpp_mapping(vpp_interfaces, vpp_bonds):
"""Verify VPP interface binding and update mapping file """Verify VPP interface binding and update mapping file
VppException will be raised if interfaces are not properly bound. VppException will be raised if interfaces are not properly bound.
:param vpp_interfaces: List of VPP interface objects :param vpp_interfaces: List of VPP interface objects
:param vpp_bonds: List of VPP bond objects
""" """
vpp_start_cli = "" cli_list = []
for vpp_int in vpp_interfaces: for vpp_int in vpp_interfaces:
if not vpp_int.pci_dev:
dpdk_map = _get_dpdk_map()
for dpdk_int in dpdk_map:
if dpdk_int['name'] == vpp_int.name:
vpp_int.pci_dev = dpdk_int['pci_address']
break
else:
raise VppException('Interface %s has no PCI address and is not'
' found in mapping file' % vpp_int.name)
# Try to get VPP interface name. In case VPP service is down # Try to get VPP interface name. In case VPP service is down
# for some reason, we will restart VPP and try again. Currently # for some reason, we will restart VPP and try again. Currently
# only trying one more time, can turn into a retry_counter if needed # only trying one more time, can turn into a retry_counter if needed
# in the future. # in the future.
for i in range(2): for i in range(2):
vpp_name = _get_vpp_interface_name(vpp_int.pci_dev, int_info = _get_vpp_interface(vpp_int.pci_dev,
tries=12, timeout=5) tries=12, timeout=5)
if not vpp_name: if not int_info:
restart_vpp(vpp_interfaces) restart_vpp(vpp_interfaces)
else: else:
vpp_int.vpp_name = int_info['name']
vpp_int.vpp_idx = int_info['index']
break break
else: else:
raise VppException('Interface %s with pci address %s not ' raise VppException('Interface %s with pci address %s not '
@ -534,10 +585,13 @@ def update_vpp_mapping(vpp_interfaces):
% (vpp_int.name, vpp_int.pci_dev)) % (vpp_int.name, vpp_int.pci_dev))
# Generate content of startup script for VPP # Generate content of startup script for VPP
for address in vpp_int.addresses: if not vpp_bonds:
vpp_start_cli += 'set interface state %s up\n' % vpp_name cli_list.append('set interface state %s up'
vpp_start_cli += 'set interface ip address %s %s/%s\n' \ % int_info['name'])
% (vpp_name, address.ip, address.prefixlen) for address in vpp_int.addresses:
cli_list.append('set interface ip address %s %s/%s\n'
% (int_info['name'], address.ip,
address.prefixlen))
logger.info('Updating mapping for vpp interface %s:' logger.info('Updating mapping for vpp interface %s:'
'pci_dev: %s mac address: %s uio driver: %s' 'pci_dev: %s mac address: %s uio driver: %s'
@ -545,9 +599,30 @@ def update_vpp_mapping(vpp_interfaces):
vpp_int.uio_driver)) vpp_int.uio_driver))
_update_dpdk_map(vpp_int.name, vpp_int.pci_dev, vpp_int.hwaddr, _update_dpdk_map(vpp_int.name, vpp_int.pci_dev, vpp_int.hwaddr,
vpp_int.uio_driver) vpp_int.uio_driver)
# Enable VPP service to make the VPP interface configuration
# persistent. for vpp_bond in vpp_bonds:
processutils.execute('systemctl', 'enable', 'vpp') bond_ids = [member.vpp_idx for member in vpp_bond.members]
bond_info = _get_vpp_bond(bond_ids)
if bond_info:
cli_list.append('set interface state %s up'
% bond_info['name'])
for address in vpp_bond.addresses:
cli_list.append('set interface ip address %s %s/%s'
% (bond_info['name'], address.ip,
address.prefixlen))
else:
raise VppException('Bond %s not found in VPP.' % vpp_bond.name)
vpp_start_cli = get_file_data(_VPP_EXEC_FILE)
for cli_line in cli_list:
if not re.search(r'^\s*%s\s*$' % cli_line,
vpp_start_cli, re.MULTILINE):
vpp_start_cli += cli_line + '\n'
if diff(_VPP_EXEC_FILE, vpp_start_cli): if diff(_VPP_EXEC_FILE, vpp_start_cli):
write_config(_VPP_EXEC_FILE, vpp_start_cli) write_config(_VPP_EXEC_FILE, vpp_start_cli)
restart_vpp(vpp_interfaces) restart_vpp(vpp_interfaces)
# Enable VPP service to make the VPP interface configuration
# persistent.
processutils.execute('systemctl', 'enable', 'vpp')