From 1a923c8474b0e4d7ef78b3444d131682babfe6aa Mon Sep 17 00:00:00 2001 From: zhangkunpeng Date: Fri, 26 Jul 2019 16:34:44 +0800 Subject: [PATCH] Generate configuration option to enable numa-aware-vswitches Generate physnets configuration option in neutron group and generate neutron physnet configuration groups that specify the mapping of each physnet to colocated numa nodes on the host. nova.conf for example: [neutron] physnets = physnet0,physnet1 [neutron_physnet_physnet0] numa_nodes = 0 [neutron_physnet_physnet1] numa_nodes = 0,1 [neutron_tunneled] numa_nodes = 0 Change-Id: Iaa633fb19b2422cf6f0331f43c7b833200a5c159 Closes-Bug: 1837232 Signed-off-by: zhangkunpeng --- sysinv/sysinv/sysinv/sysinv/helm/nova.py | 78 ++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nova.py b/sysinv/sysinv/sysinv/sysinv/helm/nova.py index 201b379cd3..53442d3f36 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nova.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nova.py @@ -425,6 +425,79 @@ class NovaHelm(openstack.OpenstackBaseHelm): default_config.update(multistring) default_config.update({'reserved_host_memory_mb': reserved_host_memory}) + def _get_interface_numa_nodes(self, context): + # Process all ethernet interfaces with physical port and add each port numa_node to + # the dict of interface_numa_nodes + interface_numa_nodes = {} + + # Update the numa_node of this interface and its all used_by interfaces + def update_iface_numa_node(iface, numa_node): + if iface['ifname'] in interface_numa_nodes: + interface_numa_nodes[iface['ifname']].add(numa_node) + else: + interface_numa_nodes[iface['ifname']] = set([numa_node]) + upper_ifnames = iface['used_by'] or [] + for upper_ifname in upper_ifnames: + upper_iface = context['interfaces'][upper_ifname] + update_iface_numa_node(upper_iface, numa_node) + + for iface in context['interfaces'].values(): + if iface['iftype'] == constants.INTERFACE_TYPE_ETHERNET: + port = context['ports'][iface['id']] + if port and port.numa_node >= 0: + update_iface_numa_node(iface, port.numa_node) + + return interface_numa_nodes + + def _update_host_neutron_physnet(self, host, neutron_config, per_physnet_numa_config): + ''' + Generate physnets configuration option and dynamically-generate + configuration groups to enable nova feature numa-aware-vswitches. + ''' + # obtain interface information specific to this host + iface_context = { + 'ports': interface._get_port_interface_id_index( + self.dbapi, host), + 'interfaces': interface._get_interface_name_index( + self.dbapi, host), + 'interfaces_datanets': interface._get_interface_name_datanets( + self.dbapi, host), + } + + # find out the numa_nodes of ports which the physnet(datanetwork) is bound with + physnet_numa_nodes = {} + tunneled_net_numa_nodes = set() + interface_numa_nodes = self._get_interface_numa_nodes(iface_context) + for iface in iface_context['interfaces'].values(): + if iface['ifname'] not in interface_numa_nodes: + continue + # Only the physnets with valid numa_node can be insert into physnet_numa_nodes + # or tunneled_net_numa_nodes + if_numa_nodes = interface_numa_nodes[iface['ifname']] + for datanet in interface.get_interface_datanets(iface_context, iface): + if datanet['network_type'] in [constants.DATANETWORK_TYPE_FLAT, + constants.DATANETWORK_TYPE_VLAN]: + dname = str(datanet['name']) + if dname in physnet_numa_nodes: + physnet_numa_nodes[dname] = if_numa_nodes | physnet_numa_nodes[dname] + else: + physnet_numa_nodes[dname] = if_numa_nodes + elif datanet['network_type'] in [constants.DATANETWORK_TYPE_VXLAN]: + tunneled_net_numa_nodes = if_numa_nodes | tunneled_net_numa_nodes + + if physnet_numa_nodes: + physnet_names = ','.join(physnet_numa_nodes.keys()) + neutron_config.update({'physnets': physnet_names}) + # For L2-type networks, configuration group name must be set with 'neutron_physnet_{datanet.name}' + # For L3-type networks, configuration group name must be set with 'neutron_tunneled' + for dname in physnet_numa_nodes.keys(): + group_name = 'neutron_physnet_' + dname + numa_nodes = ','.join('%s' % n for n in physnet_numa_nodes[dname]) + per_physnet_numa_config.update({group_name: {'numa_nodes': numa_nodes}}) + if tunneled_net_numa_nodes: + numa_nodes = ','.join('%s' % n for n in tunneled_net_numa_nodes) + per_physnet_numa_config.update({'neutron_tunneled': {'numa_nodes': numa_nodes}}) + def _get_per_host_overrides(self): host_list = [] hosts = self.dbapi.ihost_get_list() @@ -439,12 +512,15 @@ class NovaHelm(openstack.OpenstackBaseHelm): vnc_config = {} libvirt_config = {} pci_config = {} + neutron_config = {} + per_physnet_numa_config = {} self._update_host_cpu_maps(host, default_config) self._update_host_storage(host, default_config, libvirt_config) self._update_host_addresses(host, default_config, vnc_config, libvirt_config) self._update_host_pci_whitelist(host, pci_config) self._update_reserved_memory(host, default_config) + self._update_host_neutron_physnet(host, neutron_config, per_physnet_numa_config) host_nova = { 'name': hostname, 'conf': { @@ -453,9 +529,11 @@ class NovaHelm(openstack.OpenstackBaseHelm): 'vnc': vnc_config, 'libvirt': libvirt_config, 'pci': pci_config if pci_config else None, + 'neutron': neutron_config } } } + host_nova['conf']['nova'].update(per_physnet_numa_config) host_list.append(host_nova) return host_list