summaryrefslogtreecommitdiffstats
path: root/nfvbench/chaining.py
diff options
context:
space:
mode:
authorahothan <ahothan@cisco.com>2019-05-13 10:34:15 -0700
committerahothan <ahothan@cisco.com>2019-05-16 16:21:57 -0700
commit7439c895c0ad2960712910ab6b72042884ce2a41 (patch)
treef1f03915eec5389d34b6180457e259b94212bf9b /nfvbench/chaining.py
parent82c15f5063f51104830ac111b392887486377655 (diff)
NFVBENCH-134 Support multiple idle interfaces per test VM
Enhance test VM to support auto-selection of PCI addresses based on MAC address Enhance syslog reporting in test VM Increase test VM version to 0.7 Add new properties to cfg.defaults.yaml to support idle interfaces Enhance cleanup to support idle networks and ports Change-Id: Ia89a2a1bee9eb5fb56f7adde074bdcec09cb0a3f Signed-off-by: ahothan <ahothan@cisco.com>
Diffstat (limited to 'nfvbench/chaining.py')
-rw-r--r--nfvbench/chaining.py86
1 files changed, 84 insertions, 2 deletions
diff --git a/nfvbench/chaining.py b/nfvbench/chaining.py
index a719c8a..60f3832 100644
--- a/nfvbench/chaining.py
+++ b/nfvbench/chaining.py
@@ -193,13 +193,15 @@ class ChainVnfPort(object):
class ChainNetwork(object):
"""Could be a shared network across all chains or a chain private network."""
- def __init__(self, manager, network_config, chain_id=None, lookup_only=False):
+ def __init__(self, manager, network_config, chain_id=None, lookup_only=False,
+ suffix=None):
"""Create a network for given chain.
network_config: a dict containing the network properties
(name, segmentation_id and physical_network)
chain_id: to which chain the networks belong.
a None value will mean that these networks are shared by all chains
+ suffix: a suffix to add to the network name (if not None)
"""
self.manager = manager
if chain_id is None:
@@ -211,6 +213,8 @@ class ChainNetwork(object):
else:
# network_config.name is a prefix string
self.name = network_config.name + str(chain_id)
+ if suffix:
+ self.name = self.name + suffix
self.segmentation_id = self._get_item(network_config.segmentation_id,
chain_id, auto_index=True)
self.physical_network = self._get_item(network_config.physical_network, chain_id)
@@ -299,6 +303,8 @@ class ChainNetwork(object):
if self.physical_network:
body['network']['provider:physical_network'] = self.physical_network
self.network = self.manager.neutron_client.create_network(body)['network']
+ # create associated subnet, all subnets have the same name (which is ok since
+ # we do not need to address them directly by name)
body = {
'subnet': {'name': network_config.subnet,
'cidr': network_config.cidr,
@@ -376,11 +382,18 @@ class ChainVnf(object):
if len(networks) > 2:
# we will have more than 1 VM in each chain
self.name += '-' + str(vnf_id)
+ # A list of ports for this chain
+ # There are normally 2 ports carrying traffic (index 0, and index 1) and
+ # potentially multiple idle ports not carrying traffic (index 2 and up)
+ # For example if 7 idle interfaces are requested, the corresp. ports will be
+ # at index 2 to 8
self.ports = []
self.status = None
self.instance = None
self.reuse = False
self.host_ip = None
+ self.idle_networks = []
+ self.idle_ports = []
try:
# the vnf_id is conveniently also the starting index in networks
# for the left and right networks associated to this VNF
@@ -415,7 +428,7 @@ class ChainVnf(object):
def _get_vnic_type(self, port_index):
"""Get the right vnic type for given port indexself.
- If SR-IOV is speficied, middle ports in multi-VNF chains
+ If SR-IOV is specified, middle ports in multi-VNF chains
can use vswitch or SR-IOV based on config.use_sriov_middle_net
"""
if self.manager.config.sriov:
@@ -430,6 +443,62 @@ class ChainVnf(object):
return 'direct'
return 'normal'
+ def _get_idle_networks_ports(self):
+ """Get the idle networks for PVP or PVVP chain (non shared net only)
+
+ For EXT packet path or shared net, returns empty list.
+ For PVP, PVVP these networks will be created if they do not exist.
+ chain_id: to which chain the networks belong.
+ a None value will mean that these networks are shared by all chains
+ """
+ networks = []
+ ports = []
+ config = self.manager.config
+ chain_id = self.chain.chain_id
+ idle_interfaces_per_vm = config.idle_interfaces_per_vm
+ if config.service_chain == ChainType.EXT or chain_id is None or \
+ idle_interfaces_per_vm == 0:
+ return
+
+ # Make a copy of the idle networks dict as we may have to modify the
+ # segmentation ID
+ idle_network_cfg = AttrDict(config.idle_networks)
+ if idle_network_cfg.segmentation_id:
+ segmentation_id = idle_network_cfg.segmentation_id + \
+ chain_id * idle_interfaces_per_vm
+ else:
+ segmentation_id = None
+ try:
+ # create as many idle networks and ports as requested
+ for idle_index in range(idle_interfaces_per_vm):
+ if config.service_chain == ChainType.PVP:
+ suffix = '.%d' % (idle_index)
+ else:
+ suffix = '.%d.%d' % (self.vnf_id, idle_index)
+ port_name = self.name + '-idle' + str(idle_index)
+ # update the segmentation id based on chain id and idle index
+ if segmentation_id:
+ idle_network_cfg.segmentation_id = segmentation_id + idle_index
+ port_name = port_name + "." + str(segmentation_id)
+
+ networks.append(ChainNetwork(self.manager,
+ idle_network_cfg,
+ chain_id,
+ suffix=suffix))
+ ports.append(ChainVnfPort(port_name,
+ self,
+ networks[idle_index],
+ 'normal'))
+ except Exception:
+ # need to cleanup all successful networks
+ for net in networks:
+ net.delete()
+ for port in ports:
+ port.delete()
+ raise
+ self.idle_networks = networks
+ self.idle_ports = ports
+
def _setup(self, networks):
flavor_id = self.manager.flavor.flavor.id
# Check if we can reuse an instance with same name
@@ -461,6 +530,12 @@ class ChainVnf(object):
self,
networks[index],
self._get_vnic_type(index)) for index in [0, 1]]
+
+ # create idle networks and ports only if instance is not reused
+ # if reused, we do not care about idle networks/ports
+ if not self.reuse:
+ self._get_idle_networks_ports()
+
# if no reuse, actual vm creation is deferred after all ports in the chain are created
# since we need to know the next mac in a multi-vnf chain
@@ -469,6 +544,9 @@ class ChainVnf(object):
if self.instance is None:
port_ids = [{'port-id': vnf_port.port['id']}
for vnf_port in self.ports]
+ # add idle ports
+ for idle_port in self.idle_ports:
+ port_ids.append({'port-id': idle_port.port['id']})
vm_config = self._get_vm_config(remote_mac_pair)
az = self.manager.placer.get_required_az()
server = self.manager.comp.create_server(self.name,
@@ -575,6 +653,10 @@ class ChainVnf(object):
LOG.info("Deleted instance %s", self.name)
for port in self.ports:
port.delete()
+ for port in self.idle_ports:
+ port.delete()
+ for network in self.idle_networks:
+ network.delete()
class Chain(object):
"""A class to manage a single chain.