Open vSwitch integration with host and configuration framework

Integrates the latest Open vSwitch with DPDK into the host management
and configuration framework and configures the default system
vswitch type to be ovs-dpdk.

Change-Id: If7ef2975e4b90ce84d170051f332f778a867a873
Signed-off-by: Matt Peters <matt.peters@windriver.com>
This commit is contained in:
Matt Peters 2018-06-07 17:47:42 -05:00
parent 69365bb834
commit 9fafe08b65
56 changed files with 873 additions and 770 deletions

View File

@ -710,7 +710,7 @@ class ConfigValidator(object):
self.vswitch_type = self.conf.get('NETWORK', self.vswitch_type = self.conf.get('NETWORK',
'VSWITCH_TYPE').upper() 'VSWITCH_TYPE').upper()
else: else:
self.vswitch_type = 'AVS' self.vswitch_type = 'OVS-DPDK'
if self.vswitch_type == 'NUAGE_VRS': if self.vswitch_type == 'NUAGE_VRS':
metadata_proxy_shared_secret = self.conf.get( metadata_proxy_shared_secret = self.conf.get(
@ -755,10 +755,10 @@ class ConfigValidator(object):
raise ConfigFail( raise ConfigFail(
"The Region Names must be unique.") "The Region Names must be unique.")
# validate VSWITCH_TYPE configuration # validate VSWITCH_TYPE configuration
if self.vswitch_type == 'AVS': if self.vswitch_type == 'OVS-DPDK':
if self.conf.has_option('SHARED_SERVICES', 'NEUTRON_SERVICE_NAME'): if self.conf.has_option('SHARED_SERVICES', 'NEUTRON_SERVICE_NAME'):
raise ConfigFail( raise ConfigFail(
"When VSWITCH_TYPE is AVS, NEUTRON service must " "When VSWITCH_TYPE is OVS-DPDK, NEUTRON service must "
"only be configured in REGION_2_SERVICES.") "only be configured in REGION_2_SERVICES.")
neutron_group = 'REGION_2_SERVICES' neutron_group = 'REGION_2_SERVICES'
neutron_region_name = region_2_name neutron_region_name = region_2_name

View File

@ -443,23 +443,7 @@ class ConfigAssistant():
# HTTPS # HTTPS
self.enable_https = False self.enable_https = False
# Network config # Network config
self.vswitch_type = "avs" self.vswitch_type = "ovs-dpdk"
self.neutron_l2_plugin = "ml2"
self.neutron_l2_agent = "vswitch"
self.neutron_l3_ext_bridge = 'provider'
self.neutron_mechanism_drivers = "vswitch,sriovnicswitch,l2population"
self.neutron_sriov_agent_required = "y"
self.neutron_type_drivers = "managed_flat,managed_vlan,managed_vxlan"
self.neutron_network_types = "vlan,vxlan"
self.neutron_host_driver = \
"neutron.plugins.wrs.drivers.host.DefaultHostDriver"
self.neutron_fm_driver = \
"neutron.plugins.wrs.drivers.fm.DefaultFmDriver"
self.neutron_network_scheduler = \
"neutron.scheduler.dhcp_host_agent_scheduler.HostBasedScheduler"
self.neutron_router_scheduler = \
"neutron.scheduler.l3_host_agent_scheduler.HostBasedScheduler"
self.metadata_proxy_shared_secret = ""
# Authentication config # Authentication config
self.admin_username = "admin" self.admin_username = "admin"
@ -2622,48 +2606,6 @@ class ConfigAssistant():
# If any of the network options are missing, use defaults. # If any of the network options are missing, use defaults.
if config.has_option('cNETWORK', 'VSWITCH_TYPE'): if config.has_option('cNETWORK', 'VSWITCH_TYPE'):
self.vswitch_type = config.get('cNETWORK', 'VSWITCH_TYPE') self.vswitch_type = config.get('cNETWORK', 'VSWITCH_TYPE')
if config.has_option('cNETWORK', 'NEUTRON_L2_PLUGIN'):
self.neutron_l2_plugin = config.get(
'cNETWORK', 'NEUTRON_L2_PLUGIN')
if config.has_option('cNETWORK', 'NEUTRON_L2_AGENT'):
self.neutron_l2_agent = config.get(
'cNETWORK', 'NEUTRON_L2_AGENT')
if config.has_option('cNETWORK', 'NEUTRON_L3_EXT_BRIDGE'):
self.neutron_l3_ext_bridge = config.get(
'cNETWORK', 'NEUTRON_L3_EXT_BRIDGE')
if config.has_option('cNETWORK',
'NEUTRON_ML2_MECHANISM_DRIVERS'):
self.neutron_mechanism_drivers = config.get(
'cNETWORK', 'NEUTRON_ML2_MECHANISM_DRIVERS')
if config.has_option('cNETWORK',
'NEUTRON_ML2_TYPE_DRIVERS'):
self.neutron_type_drivers = config.get(
'cNETWORK', 'NEUTRON_ML2_TYPE_DRIVERS')
if config.has_option('cNETWORK',
'NEUTRON_ML2_TENANT_NETWORK_TYPES'):
self.neutron_network_types = config.get(
'cNETWORK', 'NEUTRON_ML2_TENANT_NETWORK_TYPES')
if config.has_option('cNETWORK',
'NEUTRON_ML2_SRIOV_AGENT_REQUIRED'):
self.neutron_sriov_agent_required = config.get(
'cNETWORK', 'NEUTRON_ML2_SRIOV_AGENT_REQUIRED')
if config.has_option('cNETWORK', 'NEUTRON_HOST_DRIVER'):
self.neutron_host_driver = config.get(
'cNETWORK', 'NEUTRON_HOST_DRIVER')
if config.has_option('cNETWORK', 'NEUTRON_FM_DRIVER'):
self.neutron_fm_driver = config.get(
'cNETWORK', 'NEUTRON_FM_DRIVER')
if config.has_option('cNETWORK',
'NEUTRON_NETWORK_SCHEDULER'):
self.neutron_network_scheduler = config.get(
'cNETWORK', 'NEUTRON_NETWORK_SCHEDULER')
if config.has_option('cNETWORK',
'NEUTRON_ROUTER_SCHEDULER'):
self.neutron_router_scheduler = config.get(
'cNETWORK', 'NEUTRON_ROUTER_SCHEDULER')
if self.vswitch_type == "nuage_vrs":
self.metadata_proxy_shared_secret = config.get(
'cNETWORK', 'METADATA_PROXY_SHARED_SECRET')
# Authentication configuration # Authentication configuration
if config.has_section('cAUTHENTICATION'): if config.has_section('cAUTHENTICATION'):
@ -3289,31 +3231,6 @@ class ConfigAssistant():
f.write("\n[cNETWORK]") f.write("\n[cNETWORK]")
f.write("\n# Data Network Configuration\n") f.write("\n# Data Network Configuration\n")
f.write("VSWITCH_TYPE=%s\n" % self.vswitch_type) f.write("VSWITCH_TYPE=%s\n" % self.vswitch_type)
f.write("NEUTRON_L2_PLUGIN=" +
str(self.neutron_l2_plugin) + "\n")
f.write("NEUTRON_L2_AGENT=" +
str(self.neutron_l2_agent) + "\n")
f.write("NEUTRON_L3_EXT_BRIDGE=" +
str(self.neutron_l3_ext_bridge) + "\n")
f.write("NEUTRON_ML2_MECHANISM_DRIVERS=" +
str(self.neutron_mechanism_drivers) + "\n")
f.write("NEUTRON_ML2_TYPE_DRIVERS=" +
str(self.neutron_type_drivers) + "\n")
f.write("NEUTRON_ML2_TENANT_NETWORK_TYPES=" +
str(self.neutron_network_types) + "\n")
f.write("NEUTRON_ML2_SRIOV_AGENT_REQUIRED=" +
str(self.neutron_sriov_agent_required) + "\n")
f.write("NEUTRON_HOST_DRIVER=" +
str(self.neutron_host_driver) + "\n")
f.write("NEUTRON_FM_DRIVER=" +
str(self.neutron_fm_driver) + "\n")
f.write("NEUTRON_NETWORK_SCHEDULER=" +
str(self.neutron_network_scheduler) + "\n")
f.write("NEUTRON_ROUTER_SCHEDULER=" +
str(self.neutron_router_scheduler) + "\n")
if self.vswitch_type == "nuage_vrs":
f.write("METADATA_PROXY_SHARED_SECRET=" +
str(self.metadata_proxy_shared_secret) + "\n")
# Security configuration # Security configuration
f.write("\n[cSECURITY]") f.write("\n[cSECURITY]")

View File

@ -54,7 +54,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3
EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4
[cNETWORK] [cNETWORK]
VSWITCH_TYPE = avs VSWITCH_TYPE = ovs-dpdk
[cREGION] [cREGION]
REGION_CONFIG = True REGION_CONFIG = True

View File

@ -54,7 +54,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3
EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4
[cNETWORK] [cNETWORK]
VSWITCH_TYPE = avs VSWITCH_TYPE = ovs-dpdk
[cREGION] [cREGION]
REGION_CONFIG = True REGION_CONFIG = True

View File

@ -56,18 +56,7 @@ EXTERNAL_OAM_1_ADDRESS=10.10.10.4
[cNETWORK] [cNETWORK]
# Data Network Configuration # Data Network Configuration
VSWITCH_TYPE=avs VSWITCH_TYPE=ovs-dpdk
NEUTRON_L2_PLUGIN=ml2
NEUTRON_L2_AGENT=vswitch
NEUTRON_L3_EXT_BRIDGE=provider
NEUTRON_ML2_MECHANISM_DRIVERS=vswitch,sriovnicswitch
NEUTRON_ML2_TYPE_DRIVERS=managed_flat,managed_vlan,managed_vxlan
NEUTRON_ML2_TENANT_NETWORK_TYPES=vlan,vxlan
NEUTRON_ML2_SRIOV_AGENT_REQUIRED=False
NEUTRON_HOST_DRIVER=neutron.plugins.wrs.drivers.host.DefaultHostDriver
NEUTRON_FM_DRIVER=neutron.plugins.wrs.drivers.fm.DefaultFmDriver
NEUTRON_NETWORK_SCHEDULER=neutron.scheduler.dhcp_host_agent_scheduler.HostChanceScheduler
NEUTRON_ROUTER_SCHEDULER=neutron.scheduler.l3_host_agent_scheduler.HostChanceScheduler
[cSECURITY] [cSECURITY]
[cREGION] [cREGION]

View File

@ -62,18 +62,7 @@ EXTERNAL_OAM_1_ADDRESS=10.10.10.4
[cNETWORK] [cNETWORK]
# Data Network Configuration # Data Network Configuration
VSWITCH_TYPE=avs VSWITCH_TYPE=ovs-dpdk
NEUTRON_L2_PLUGIN=ml2
NEUTRON_L2_AGENT=vswitch
NEUTRON_L3_EXT_BRIDGE=provider
NEUTRON_ML2_MECHANISM_DRIVERS=vswitch,sriovnicswitch
NEUTRON_ML2_TYPE_DRIVERS=managed_flat,managed_vlan,managed_vxlan
NEUTRON_ML2_TENANT_NETWORK_TYPES=vlan,vxlan
NEUTRON_ML2_SRIOV_AGENT_REQUIRED=False
NEUTRON_HOST_DRIVER=neutron.plugins.wrs.drivers.host.DefaultHostDriver
NEUTRON_FM_DRIVER=neutron.plugins.wrs.drivers.fm.DefaultFmDriver
NEUTRON_NETWORK_SCHEDULER=neutron.scheduler.dhcp_host_agent_scheduler.HostChanceScheduler
NEUTRON_ROUTER_SCHEDULER=neutron.scheduler.l3_host_agent_scheduler.HostChanceScheduler
[cSECURITY] [cSECURITY]
[cREGION] [cREGION]

View File

@ -62,18 +62,7 @@ EXTERNAL_OAM_1_ADDRESS=abcd::4
[cNETWORK] [cNETWORK]
# Data Network Configuration # Data Network Configuration
VSWITCH_TYPE=avs VSWITCH_TYPE=ovs-dpdk
NEUTRON_L2_PLUGIN=ml2
NEUTRON_L2_AGENT=vswitch
NEUTRON_L3_EXT_BRIDGE=provider
NEUTRON_ML2_MECHANISM_DRIVERS=vswitch,sriovnicswitch
NEUTRON_ML2_TYPE_DRIVERS=managed_flat,managed_vlan,managed_vxlan
NEUTRON_ML2_TENANT_NETWORK_TYPES=vlan,vxlan
NEUTRON_ML2_SRIOV_AGENT_REQUIRED=False
NEUTRON_HOST_DRIVER=neutron.plugins.wrs.drivers.host.DefaultHostDriver
NEUTRON_FM_DRIVER=neutron.plugins.wrs.drivers.fm.DefaultFmDriver
NEUTRON_NETWORK_SCHEDULER=neutron.scheduler.dhcp_host_agent_scheduler.HostChanceScheduler
NEUTRON_ROUTER_SCHEDULER=neutron.scheduler.l3_host_agent_scheduler.HostChanceScheduler
[cSECURITY] [cSECURITY]
[cREGION] [cREGION]

View File

@ -64,18 +64,7 @@ EXTERNAL_OAM_1_ADDRESS=10.10.10.4
[cNETWORK] [cNETWORK]
# Data Network Configuration # Data Network Configuration
VSWITCH_TYPE=avs VSWITCH_TYPE=ovs-dpdk
NEUTRON_L2_PLUGIN=ml2
NEUTRON_L2_AGENT=vswitch
NEUTRON_L3_EXT_BRIDGE=provider
NEUTRON_ML2_MECHANISM_DRIVERS=vswitch,sriovnicswitch
NEUTRON_ML2_TYPE_DRIVERS=managed_flat,managed_vlan,managed_vxlan
NEUTRON_ML2_TENANT_NETWORK_TYPES=vlan,vxlan
NEUTRON_ML2_SRIOV_AGENT_REQUIRED=False
NEUTRON_HOST_DRIVER=neutron.plugins.wrs.drivers.host.DefaultHostDriver
NEUTRON_FM_DRIVER=neutron.plugins.wrs.drivers.fm.DefaultFmDriver
NEUTRON_NETWORK_SCHEDULER=neutron.scheduler.dhcp_host_agent_scheduler.HostChanceScheduler
NEUTRON_ROUTER_SCHEDULER=neutron.scheduler.l3_host_agent_scheduler.HostChanceScheduler
[cSECURITY] [cSECURITY]
[cREGION] [cREGION]

View File

@ -59,7 +59,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3
EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4
[cNETWORK] [cNETWORK]
VSWITCH_TYPE = avs VSWITCH_TYPE = ovs-dpdk
[cREGION] [cREGION]
REGION_CONFIG = True REGION_CONFIG = True

View File

@ -37,7 +37,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3
EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4
[cNETWORK] [cNETWORK]
VSWITCH_TYPE = avs VSWITCH_TYPE = ovs-dpdk
[cREGION] [cREGION]
REGION_CONFIG = True REGION_CONFIG = True

View File

@ -37,7 +37,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3
EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4
[cNETWORK] [cNETWORK]
VSWITCH_TYPE = avs VSWITCH_TYPE = ovs-dpdk
[cREGION] [cREGION]
REGION_CONFIG = True REGION_CONFIG = True

View File

@ -831,9 +831,9 @@ def test_region_config_validation():
with pytest.raises(exceptions.ConfigFail): with pytest.raises(exceptions.ConfigFail):
validate(region_config, REGION_CONFIG, None, False) validate(region_config, REGION_CONFIG, None, False)
# Test detection of neutron in wrong region for AVS VSWITCH_TYPE # Test detection of neutron in wrong region for VSWITCH_TYPE
region_config = cr.parse_system_config(nuage_vrs_regionfile) region_config = cr.parse_system_config(nuage_vrs_regionfile)
region_config.set('NETWORK', 'VSWITCH_TYPE', 'AVS') region_config.set('NETWORK', 'VSWITCH_TYPE', 'ovs-dpdk')
with pytest.raises(exceptions.ConfigFail): with pytest.raises(exceptions.ConfigFail):
cr.create_cgcs_config_file(None, region_config, None, None, None, cr.create_cgcs_config_file(None, region_config, None, None, None,
validate_only=True) validate_only=True)

View File

@ -1,6 +1,10 @@
# compute specific configuration data # compute specific configuration data
--- ---
# vswitch
vswitch::dpdk::memory_channels: 4
# neutron # neutron
neutron::agents::dhcp::interface_driver: 'openvswitch' neutron::agents::dhcp::interface_driver: 'openvswitch'
neutron::agents::dhcp::enable_isolated_metadata: true neutron::agents::dhcp::enable_isolated_metadata: true
@ -11,6 +15,11 @@ neutron::agents::l3::interface_driver: 'openvswitch'
neutron::agents::l3::metadata_port: 80 neutron::agents::l3::metadata_port: 80
neutron::agents::l3::agent_mode: 'dvr_snat' neutron::agents::l3::agent_mode: 'dvr_snat'
neutron::agents::ml2::ovs::manage_vswitch: false
neutron::agents::ml2::ovs::datapath_type: 'netdev'
neutron::agents::ml2::ovs::vhostuser_socket_dir: '/var/run/openvswitch'
neutron::agents::ml2::ovs::firewall_driver: 'noop'
neutron::agents::ml2::sriov::manage_service: true neutron::agents::ml2::sriov::manage_service: true
neutron::agents::ml2::sriov::polling_interval: 5 neutron::agents::ml2::sriov::polling_interval: 5
@ -46,6 +55,10 @@ nova::network::neutron::neutron_user_domain_name: 'Default'
nova::network::neutron::neutron_project_domain_name: 'Default' nova::network::neutron::neutron_project_domain_name: 'Default'
nova::network::neutron::neutron_region_name: RegionOne nova::network::neutron::neutron_region_name: RegionOne
nova::compute::neutron::libvirt_vif_driver: 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver'
openstack::nova::compute::compute_monitors: "cpu.virt_driver"
# ceilometer # ceilometer
ceilometer::agent::polling::central_namespace: false ceilometer::agent::polling::central_namespace: false

View File

@ -133,6 +133,10 @@ sysinv::api::keystone_project_domain: 'Default'
sysinv::conductor::enabled: false sysinv::conductor::enabled: false
# nfvi
nfv::nfvi::infrastructure_rest_api_data_port_fault_handling_enabled: false
# keystone # keystone
keystone::service::enabled: false keystone::service::enabled: false
keystone::token_provider: 'fernet' keystone::token_provider: 'fernet'
@ -235,12 +239,6 @@ nova_api_proxy::config::eventlet_pool_size: 256
nova::db::sync_api::cellv2_setup: true nova::db::sync_api::cellv2_setup: true
# neutron # neutron
neutron::core_plugin: 'neutron.plugins.ml2.plugin.Ml2Plugin'
neutron::service_plugins:
- 'router'
neutron::allow_overlapping_ips: true
neutron::vlan_transparent: true
neutron::pnet_audit_enabled: true
neutron::server::enabled: false neutron::server::enabled: false
neutron::server::database_idle_timeout: 60 neutron::server::database_idle_timeout: 60

View File

@ -35,12 +35,12 @@ neutron::logging::log_dir: false
neutron::logging::verbose: false neutron::logging::verbose: false
neutron::logging::debug: false neutron::logging::debug: false
neutron::core_plugin: 'ml2' neutron::core_plugin: 'neutron.plugins.ml2.plugin.Ml2Plugin'
neutron::service_plugins: neutron::service_plugins:
- 'router' - 'router'
neutron::allow_overlapping_ips: true neutron::allow_overlapping_ips: true
neutron::vlan_transparent: true neutron::vlan_transparent: true
neutron::pnet_audit_enabled: true neutron::pnet_audit_enabled: false
neutron::verbose: false neutron::verbose: false
neutron::root_helper: 'sudo' neutron::root_helper: 'sudo'

View File

@ -4,9 +4,9 @@ class openstack::neutron::params (
$region_name = undef, $region_name = undef,
$service_name = 'openstack-neutron', $service_name = 'openstack-neutron',
$bgp_router_id = undef, $bgp_router_id = undef,
$l3_agent_enabled = true,
$service_create = false, $service_create = false,
$configure_endpoint = true $configure_endpoint = true,
$tunnel_csum = undef,
) { } ) { }
class openstack::neutron class openstack::neutron
@ -20,7 +20,6 @@ class openstack::neutron
class { '::neutron': class { '::neutron':
rabbit_use_ssl => $::platform::amqp::params::ssl_enabled, rabbit_use_ssl => $::platform::amqp::params::ssl_enabled,
default_transport_url => $::platform::amqp::params::transport_url, default_transport_url => $::platform::amqp::params::transport_url,
pnet_audit_enabled => $::platform::params::sdn_enabled ? { true => false, default => true },
} }
} }
@ -139,8 +138,8 @@ class openstack::neutron::bgp
class openstack::neutron::sfc ( class openstack::neutron::sfc (
$sfc_drivers = undef, $sfc_drivers = 'ovs',
$flowclassifier_drivers = undef, $flowclassifier_drivers = 'ovs',
$sfc_quota_flow_classifier = undef, $sfc_quota_flow_classifier = undef,
$sfc_quota_port_chain = undef, $sfc_quota_port_chain = undef,
$sfc_quota_port_pair_group = undef, $sfc_quota_port_pair_group = undef,
@ -197,9 +196,6 @@ class openstack::neutron::agents
if str2bool($::disable_compute_services) { if str2bool($::disable_compute_services) {
$pmon_ensure = absent $pmon_ensure = absent
class {'::neutron::agents::vswitch':
service_ensure => stopped,
}
class {'::neutron::agents::l3': class {'::neutron::agents::l3':
enabled => false enabled => false
} }
@ -212,6 +208,9 @@ class openstack::neutron::agents
class {'::neutron::agents::ml2::sriov': class {'::neutron::agents::ml2::sriov':
enabled => false enabled => false
} }
class {'::neutron::agents::ml2::ovs':
enabled => false
}
} else { } else {
$pmon_ensure = link $pmon_ensure = link
@ -219,12 +218,21 @@ class openstack::neutron::agents
metadata_workers => $::platform::params::eng_workers_by_4 metadata_workers => $::platform::params::eng_workers_by_4
} }
class { '::neutron::agents::l3':
enabled => $l3_agent_enabled,
}
include ::neutron::agents::dhcp include ::neutron::agents::dhcp
include ::neutron::agents::l3
include ::neutron::agents::ml2::sriov include ::neutron::agents::ml2::sriov
include ::neutron::agents::ml2::ovs
}
if $::platform::params::vswitch_type =~ '^ovs' {
# Ensure bridges and addresses are configured before agent is started
Platform::Vswitch::Ovs::Bridge<||> ~> Service['neutron-ovs-agent-service']
Platform::Vswitch::Ovs::Address<||> ~> Service['neutron-ovs-agent-service']
# Enable/disable tunnel checksum
neutron_agent_ovs {
'agent/tunnel_csum': value => $tunnel_csum;
}
} }
file { "/etc/pmon.d/neutron-dhcp-agent.conf": file { "/etc/pmon.d/neutron-dhcp-agent.conf":

View File

@ -136,6 +136,7 @@ class openstack::nova::compute (
$migration_key_type, $migration_key_type,
$pci_pt_whitelist = [], $pci_pt_whitelist = [],
$pci_sriov_whitelist = undef, $pci_sriov_whitelist = undef,
$compute_monitors,
$iscsi_initiator_name = undef, $iscsi_initiator_name = undef,
) inherits ::openstack::nova::params { ) inherits ::openstack::nova::params {
include ::nova::pci include ::nova::pci
@ -145,6 +146,7 @@ class openstack::nova::compute (
include ::platform::network::infra::params include ::platform::network::infra::params
include ::nova::keystone::auth include ::nova::keystone::auth
include ::nova::keystone::authtoken include ::nova::keystone::authtoken
include ::nova::compute::neutron
include ::openstack::nova::sshd include ::openstack::nova::sshd
@ -268,8 +270,6 @@ class openstack::nova::compute (
$libvirt_images_type = "default" $libvirt_images_type = "default"
} }
$compute_monitors = "cpu.virt_driver"
class { '::nova::compute::libvirt': class { '::nova::compute::libvirt':
libvirt_virt_type => $libvirt_virt_type, libvirt_virt_type => $libvirt_virt_type,
vncserver_listen => $libvirt_vnc_bind_host, vncserver_listen => $libvirt_vnc_bind_host,
@ -336,11 +336,6 @@ class openstack::nova::compute (
match => '^cgroup_controllers = .*', match => '^cgroup_controllers = .*',
} }
class { '::nova::compute::neutron':
libvirt_vif_driver => 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver',
libvirt_qemu_dpdk_options => 'type=secondary,prefix=vs,channels=4,cpu=0',
}
# The pci_passthrough option in the nova::compute class is not sufficient. # The pci_passthrough option in the nova::compute class is not sufficient.
# In particular, it sets the pci_passthrough_whitelist in nova.conf to an # In particular, it sets the pci_passthrough_whitelist in nova.conf to an
# empty string if the list is empty, causing the nova-compute process to fail. # empty string if the list is empty, causing the nova-compute process to fail.

View File

@ -72,10 +72,12 @@ class platform::config::file {
} }
} }
file_line { "${platform_conf} vswitch_type": if $::platform::params::vswitch_type {
path => $platform_conf, file_line { "${platform_conf} vswitch_type":
line => "vswitch_type=${::platform::params::vswitch_type}", path => $platform_conf,
match => '^vswitch_type=', line => "vswitch_type=${::platform::params::vswitch_type}",
match => '^vswitch_type=',
}
} }
if $::platform::params::system_type { if $::platform::params::system_type {

View File

@ -29,8 +29,8 @@ class platform::ntp (
onlyif => "grep -q '^server' /etc/ntp.conf", onlyif => "grep -q '^server' /etc/ntp.conf",
} }
exec { 'systemd-daemon-reload': exec { 'ntpdate-systemd-daemon-reload':
command => '/usr/bin/systemctl daemon-reload', command => '/usr/bin/systemctl daemon-reload',
} }
exec { 'stop-ntpdate': exec { 'stop-ntpdate':
@ -57,7 +57,7 @@ class platform::ntp (
File['ntpdate_tis_override'] -> File['ntpdate_tis_override'] ->
Exec['enable-ntpdate'] -> Exec['enable-ntpdate'] ->
Exec['enable-ntpd'] -> Exec['enable-ntpd'] ->
Exec['systemd-daemon-reload'] -> Exec['ntpdate-systemd-daemon-reload'] ->
Exec['stop-ntpdate'] -> Exec['stop-ntpdate'] ->
Exec['stop-ntpd'] -> Exec['stop-ntpd'] ->
Exec['start-ntpdate'] -> Exec['start-ntpdate'] ->

View File

@ -1,35 +1,130 @@
class platform::vswitch { class platform::vswitch::params(
$iommu_enabled = true,
$hugepage_dir = '/mnt/huge-1048576kB',
$driver_type = 'vfio-pci',
) { }
class platform::vswitch
inherits ::platform::vswitch::params {
Class[$name] -> Class['::platform::network'] Class[$name] -> Class['::platform::network']
Mount[$hugepage_dir] -> Class[$name]
include ::platform::vswitch::ovsdb $enable_unsafe_noiommu_mode = bool2num(!$iommu_enabled)
exec {'vfio-iommu-mode':
command => "echo ${enable_unsafe_noiommu_mode} > /sys/module/vfio/parameters/enable_unsafe_noiommu_mode",
require => Kmod::Load[$driver_type],
}
include ::platform::vswitch::ovs
} }
class platform::vswitch::ovsdb { define platform::vswitch::ovs::device(
include ::platform::params $pci_addr,
$driver_type,
if $::platform::params::sdn_enabled { ) {
$pmon_ensure = 'link' exec { "ovs-bind-device: $title":
$service_ensure = 'running' path => ["/usr/bin", "/usr/sbin", "/usr/share/openvswitch/scripts"],
} else { command => "dpdk-devbind.py --bind=${driver_type} ${pci_addr}"
$pmon_ensure = 'absent'
$service_ensure = 'stopped'
} }
}
# ensure pmon soft link
file { "/etc/pmon.d/ovsdb-server.conf":
ensure => $pmon_ensure, define platform::vswitch::ovs::bridge(
target => "/etc/openvswitch/ovsdb-server.pmon.conf", $datapath_type = 'netdev',
owner => 'root', ) {
group => 'root', exec { "ovs-add-br: ${title}":
mode => '0755', command => template("platform/ovs.add-bridge.erb")
} } ->
exec { "ovs-link-up: ${title}":
# service management (start ovsdb-server) command => "ip link set ${name} up",
service { "openvswitch": }
ensure => $service_ensure, }
enable => $::platform::params::sdn_enabled,
}
define platform::vswitch::ovs::port(
$type = 'port',
$bridge,
$attributes = [],
$interfaces,
) {
exec { "ovs-add-port: ${title}":
command => template("platform/ovs.add-port.erb"),
logoutput => true
}
}
define platform::vswitch::ovs::address(
$ifname,
$address,
$prefixlen,
) {
exec { "ovs-add-address: ${title}":
command => "ip addr replace ${address}/${prefixlen} dev ${ifname}",
}
}
class platform::vswitch::ovs(
$devices = {},
$bridges = {},
$ports = {},
$addresses = {},
) inherits ::platform::vswitch::params {
if $::platform::params::vswitch_type == 'ovs' {
include ::vswitch::ovs
} elsif $::platform::params::vswitch_type == 'ovs-dpdk' {
include ::vswitch::dpdk
Exec['vfio-iommu-mode'] ->
Platform::Vswitch::Ovs::Device<||> ->
Platform::Vswitch::Ovs::Bridge<||>
create_resources('platform::vswitch::ovs::device', $devices, {
driver_type => $driver_type,
before => Service['openvswitch']
})
$dpdk_configs = {
'other_config:dpdk-hugepage-dir' => { value => $hugepage_dir },
}
$dpdk_dependencies = {
wait => false,
require => Service['openvswitch'],
notify => Vs_config['other_config:dpdk-init'],
}
create_resources ('vs_config', $dpdk_configs, $dpdk_dependencies)
}
if $::platform::params::vswitch_type =~ '^ovs' {
# clean bridges and ports before applying current configuration
exec { "ovs-clean":
command => template("platform/ovs.clean.erb"),
provider => shell,
require => Service['openvswitch']
} ->
Platform::Vswitch::Ovs::Bridge<||> -> Platform::Vswitch::Ovs::Port<||>
Platform::Vswitch::Ovs::Bridge<||> -> Platform::Vswitch::Ovs::Address<||>
}
create_resources('platform::vswitch::ovs::bridge', $bridges, {
require => Service['openvswitch']
})
create_resources('platform::vswitch::ovs::port', $ports, {
require => Service['openvswitch']
})
create_resources('platform::vswitch::ovs::address', $addresses, {
require => Service['openvswitch']
})
} }

View File

@ -0,0 +1,2 @@
ovs-vsctl --timeout 10 -- --may-exist add-br <%= @name -%>
-- set bridge <%= @name -%> datapath_type=<%= @datapath_type -%>

View File

@ -0,0 +1,16 @@
ovs-vsctl --timeout 10 -- --may-exist add-<%= @type -%> <%= @bridge -%> <%= @name -%>
<%- if @type == 'bond' -%>
<%- @interfaces.each do |interface| -%>
<%= interface['name'] -%>
<%- end -%>
<%- end -%>
<%- @attributes.each do |attribute| -%>
<%= attribute -%>
<%- end -%>
<%- @interfaces.each do |interface| -%>
-- set Interface <%= interface['name'] -%>
type=<%= interface['type'] -%>
<%- interface['attributes'].each do |attribute| -%>
<%= attribute -%>
<%- end -%>
<%- end -%>

View File

@ -0,0 +1,7 @@
# clean provider network ports and bridges
for bridge in $(ovs-vsctl --timeout 10 list-br|grep '^br-phy'); do
for port in $(ovs-vsctl --timeout 10 list-ports $bridge); do
ovs-vsctl --timeout 10 del-port $bridge $port
done
ovs-vsctl --timeout 10 del-br $bridge
done

View File

@ -0,0 +1,7 @@
# delete manager
ovs-vsctl -t ovsdb-server --no-wait del-manager
# delete all bridges
for bridge in $(ovs-vsctl -t ovsdb-server --timeout 10 list-br); do
ovs-vsctl -t ovsdb-server --timeout 10 --no-wait del-br $bridge
done

View File

@ -12,8 +12,8 @@ from cgtsclient import exc
CREATION_ATTRIBUTES = ['ihost_uuid', 'memtotal_mib', 'memavail_mib', CREATION_ATTRIBUTES = ['ihost_uuid', 'memtotal_mib', 'memavail_mib',
'platform_reserved_mib', 'hugepages_configured', 'platform_reserved_mib', 'hugepages_configured',
'avs_hugepages_size_mib', 'avs_hugepages_reqd', 'vswitch_hugepages_size_mib', 'vswitch_hugepages_reqd',
'avs_hugepages_nr', 'avs_hugepages_avail', 'vswitch_hugepages_nr', 'vswitch_hugepages_avail',
'vm_hugepages_nr_2M_pending', 'vm_hugepages_nr_1G_pending', 'vm_hugepages_nr_2M_pending', 'vm_hugepages_nr_1G_pending',
'vm_hugepages_nr_2M', 'vm_hugepages_avail_2M', 'vm_hugepages_nr_2M', 'vm_hugepages_avail_2M',
'vm_hugepages_nr_1G', 'vm_hugepages_avail_1G', 'vm_hugepages_nr_1G', 'vm_hugepages_avail_1G',
@ -21,6 +21,7 @@ CREATION_ATTRIBUTES = ['ihost_uuid', 'memtotal_mib', 'memavail_mib',
'vm_hugepages_possible_2M', 'vm_hugepages_possible_1G', 'vm_hugepages_possible_2M', 'vm_hugepages_possible_1G',
'capabilities', 'numa_node', 'minimum_platform_reserved_mib'] 'capabilities', 'numa_node', 'minimum_platform_reserved_mib']
class imemory(base.Resource): class imemory(base.Resource):
def __repr__(self): def __repr__(self):
return "<imemory %s>" % self._info return "<imemory %s>" % self._info

View File

@ -12,17 +12,17 @@
from cgtsclient.common import utils from cgtsclient.common import utils
from cgtsclient import exc from cgtsclient import exc
from collections import OrderedDict
from cgtsclient.v1 import ihost as ihost_utils from cgtsclient.v1 import ihost as ihost_utils
def _print_imemory_show(imemory): def _print_imemory_show(imemory):
fields = ['memtotal_mib', fields = ['memtotal_mib',
'platform_reserved_mib', 'platform_reserved_mib',
'memavail_mib', 'memavail_mib',
'hugepages_configured', 'hugepages_configured',
'avs_hugepages_size_mib', 'vswitch_hugepages_size_mib',
'avs_hugepages_nr', 'vswitch_hugepages_nr',
'avs_hugepages_avail', 'vswitch_hugepages_avail',
'vm_hugepages_nr_4K', 'vm_hugepages_nr_4K',
'vm_hugepages_nr_2M', 'vm_hugepages_nr_2M',
'vm_hugepages_nr_2M_pending', 'vm_hugepages_nr_2M_pending',
@ -36,9 +36,9 @@ def _print_imemory_show(imemory):
' Platform (MiB)', ' Platform (MiB)',
' Available (MiB)', ' Available (MiB)',
'Huge Pages Configured', 'Huge Pages Configured',
'AVS Huge Pages: Size (MiB)', 'vSwitch Huge Pages: Size (MiB)',
' Total', ' Total',
' Available', ' Available',
'VM Pages (4K): Total', 'VM Pages (4K): Total',
'VM Huge Pages (2M): Total', 'VM Huge Pages (2M): Total',
' Total Pending', ' Total Pending',
@ -110,9 +110,9 @@ def do_host_memory_list(cc, args):
'platform_reserved_mib', 'platform_reserved_mib',
'memavail_mib', 'memavail_mib',
'hugepages_configured', 'hugepages_configured',
'avs_hugepages_size_mib', 'vswitch_hugepages_size_mib',
'avs_hugepages_nr', 'vswitch_hugepages_nr',
'avs_hugepages_avail', 'vswitch_hugepages_avail',
'vm_hugepages_nr_4K', 'vm_hugepages_nr_4K',
'vm_hugepages_nr_2M', 'vm_hugepages_nr_2M',
'vm_hugepages_avail_2M', 'vm_hugepages_avail_2M',
@ -123,21 +123,21 @@ def do_host_memory_list(cc, args):
'vm_hugepages_use_1G'] 'vm_hugepages_use_1G']
field_labels = ['processor', field_labels = ['processor',
'mem_total(MiB)', 'mem_total(MiB)',
'mem_platform(MiB)', 'mem_platform(MiB)',
'mem_avail(MiB)', 'mem_avail(MiB)',
'hugepages(hp)_configured', 'hugepages(hp)_configured',
'avs_hp_size(MiB)', 'vs_hp_size(MiB)',
'avs_hp_total', 'vs_hp_total',
'avs_hp_avail', 'vs_hp_avail',
'vm_total_4K', 'vm_total_4K',
'vm_hp_total_2M', 'vm_hp_total_2M',
'vm_hp_avail_2M', 'vm_hp_avail_2M',
'vm_hp_pending_2M', 'vm_hp_pending_2M',
'vm_hp_total_1G', 'vm_hp_total_1G',
'vm_hp_avail_1G', 'vm_hp_avail_1G',
'vm_hp_pending_1G', 'vm_hp_pending_1G',
'vm_hp_use_1G'] 'vm_hp_use_1G']
utils.print_list(imemorys, fields, field_labels, sortby=1) utils.print_list(imemorys, fields, field_labels, sortby=1)

View File

@ -41,7 +41,12 @@ def _print_isystem_show(isystem):
fields.append('distributed_cloud_role') fields.append('distributed_cloud_role')
setattr(isystem, 'distributed_cloud_role', setattr(isystem, 'distributed_cloud_role',
isystem.distributed_cloud_role) isystem.distributed_cloud_role)
if isystem.capabilities.get('vswitch_type') is not None:
fields.append('vswitch_type')
setattr(isystem, 'vswitch_type',
isystem.capabilities.get('vswitch_type'))
data = dict(list([(f, getattr(isystem, f, '')) for f in fields])) data = dict(list([(f, getattr(isystem, f, '')) for f in fields]))
utils.print_dict(data) utils.print_dict(data)
@ -78,7 +83,10 @@ def do_show(cc, args):
metavar='<https_enabled>', metavar='<https_enabled>',
choices=['true', 'false'], choices=['true', 'false'],
help='The HTTPS enabled or disabled flag') help='The HTTPS enabled or disabled flag')
@utils.arg('-v', '--vswitch_type',
metavar='<vswitch_type>',
choices=['ovs-dpdk'],
help='The vswitch type for the system')
def do_modify(cc, args): def do_modify(cc, args):
"""Modify system attributes.""" """Modify system attributes."""
@ -126,7 +134,7 @@ def do_modify(cc, args):
print 'Please follow the admin guide to complete the reconfiguration.' print 'Please follow the admin guide to complete the reconfiguration.'
field_list = ['name', 'system_mode', 'description', 'location', 'contact', field_list = ['name', 'system_mode', 'description', 'location', 'contact',
'timezone', 'sdn_enabled','https_enabled'] 'timezone', 'sdn_enabled','https_enabled', 'vswitch_type']
# use field list as filter # use field list as filter
user_fields = dict((k, v) for (k, v) in vars(args).items() user_fields = dict((k, v) for (k, v) in vars(args).items()

View File

@ -74,9 +74,8 @@ install -m 644 -p -D scripts/sysinv-conductor.service %{buildroot}%{_unitdir}/sy
install -d -m 755 %{buildroot}%{local_bindir} install -d -m 755 %{buildroot}%{local_bindir}
install -p -D -m 755 sysinv/cmd/partition_info.sh %{buildroot}%{local_bindir}/partition_info.sh install -p -D -m 755 sysinv/cmd/partition_info.sh %{buildroot}%{local_bindir}/partition_info.sh
install -d -m 755 %{buildroot}%{local_bindir}
install -p -D -m 755 sysinv/cmd/manage-partitions %{buildroot}%{local_bindir}/manage-partitions install -p -D -m 755 sysinv/cmd/manage-partitions %{buildroot}%{local_bindir}/manage-partitions
install -p -D -m 755 sysinv/cmd/query_pci_id %{buildroot}%{local_bindir}/query_pci_id
%clean %clean
echo "CLEAN CALLED" echo "CLEAN CALLED"

View File

@ -29,11 +29,10 @@ import tsconfig.tsconfig as tsc
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
# Defines per-socket AVS memory requirements (in MB) for both real and virtual # Defines per-socket vswitch memory requirements (in MB) for both real and
# deployments # virtual deployments
# VSWITCH_REAL_MEMORY_MB = 1024
AVS_REAL_MEMORY_MB = 1024 VSWITCH_VIRTUAL_MEMORY_MB = 512
AVS_VBOX_MEMORY_MB = 512
class CPU: class CPU:
@ -286,32 +285,32 @@ class NodeOperator(object):
return [name for name in listdir(dir) return [name for name in listdir(dir)
if os.path.isdir(join(dir, name))] if os.path.isdir(join(dir, name))]
def _set_default_avs_hugesize(self): def _set_default_vswitch_hugesize(self):
''' """
Set the default memory size for avs hugepages when it must fallback to Set the default memory size for vswitch hugepages when it must fallback
2MB pages because there are no 1GB pages. In a virtual environment we to 2MB pages because there are no 1GB pages. In a virtual environment
set a smaller amount of memory because AVS is configured to use a we set a smaller amount of memory because vswitch is configured to use
smaller mbuf pool. In non-virtual environments we use the same amount a smaller mbuf pool. In non-virtual environments we use the same
of memory as we would if 1GB pages were available. amount of memory as we would if 1GB pages were available.
''' """
hugepage_size = 2 hugepage_size = 2
if utils.is_virtual(): if utils.is_virtual():
avs_hugepages_nr = AVS_VBOX_MEMORY_MB / hugepage_size vswitch_hugepages_nr = VSWITCH_VIRTUAL_MEMORY_MB / hugepage_size
else: else:
avs_hugepages_nr = AVS_REAL_MEMORY_MB / hugepage_size vswitch_hugepages_nr = VSWITCH_REAL_MEMORY_MB / hugepage_size
## Create a new set of dict attributes ## Create a new set of dict attributes
hp_attr = {'avs_hugepages_size_mib': hugepage_size, hp_attr = {'vswitch_hugepages_size_mib': hugepage_size,
'avs_hugepages_nr': avs_hugepages_nr, 'vswitch_hugepages_nr': vswitch_hugepages_nr,
'avs_hugepages_avail': 0} 'vswitch_hugepages_avail': 0}
return hp_attr return hp_attr
def _inode_get_memory_hugepages(self): def _inode_get_memory_hugepages(self):
'''Collect hugepage info, including avs, and vm. """Collect hugepage info, including vswitch, and vm.
Collect platform reserved if config. Collect platform reserved if config.
:param self :param self
:returns list of memory nodes and attributes :returns list of memory nodes and attributes
''' """
imemory = [] imemory = []
Ki = 1024 Ki = 1024
@ -339,7 +338,7 @@ class NodeOperator(object):
Total_HP_MiB = 0 # Total memory (MiB) currently configured in HPs Total_HP_MiB = 0 # Total memory (MiB) currently configured in HPs
Free_HP_MiB = 0 Free_HP_MiB = 0
# Check AVS and Libvirt memory # Check vswitch and libvirt memory
# Loop through configured hugepage sizes of this node and record # Loop through configured hugepage sizes of this node and record
# total number and number free # total number and number free
hugepages = "/sys/devices/system/node/node%d/hugepages" % node hugepages = "/sys/devices/system/node/node%d/hugepages" % node
@ -352,7 +351,7 @@ class NodeOperator(object):
sizesplit = subdir.split('-') sizesplit = subdir.split('-')
# role via size; also from /etc/nova/compute_reserved.conf # role via size; also from /etc/nova/compute_reserved.conf
if sizesplit[1].startswith("1048576kB"): if sizesplit[1].startswith("1048576kB"):
hugepages_role = "avs" hugepages_role = "vswitch"
size = int(SZ_1G_Ki / Ki) size = int(SZ_1G_Ki / Ki)
else: else:
hugepages_role = "vm" hugepages_role = "vm"
@ -377,27 +376,27 @@ class NodeOperator(object):
# Libvirt hugepages can now be 1G and 2M, can't only look # Libvirt hugepages can now be 1G and 2M, can't only look
# at 2M pages # at 2M pages
if hugepages_role == "avs": if hugepages_role == "vswitch":
avs_hugepages_nr = AVS_REAL_MEMORY_MB / size vswitch_hugepages_nr = VSWITCH_REAL_MEMORY_MB / size
hp_attr = { hp_attr = {
'avs_hugepages_size_mib': size, 'vswitch_hugepages_size_mib': size,
'avs_hugepages_nr': avs_hugepages_nr, 'vswitch_hugepages_nr': vswitch_hugepages_nr,
'avs_hugepages_avail': 0, 'vswitch_hugepages_avail': 0,
'vm_hugepages_nr_1G': 'vm_hugepages_nr_1G':
(nr_hugepages - avs_hugepages_nr), (nr_hugepages - vswitch_hugepages_nr),
'vm_hugepages_avail_1G': free_hugepages, 'vm_hugepages_avail_1G': free_hugepages,
'vm_hugepages_use_1G': 'True' 'vm_hugepages_use_1G': 'True'
} }
else: else:
if len(subdirs) == 1: if len(subdirs) == 1:
hp_attr = self._set_default_avs_hugesize() hp_attr = self._set_default_vswitch_hugesize()
hp_attr.update({'vm_hugepages_use_1G': 'False'}) hp_attr.update({'vm_hugepages_use_1G': 'False'})
avs_hugepages_nr = hp_attr.get('avs_hugepages_nr', 0) vswitch_hugepages_nr = hp_attr.get('vswitch_hugepages_nr', 0)
hp_attr.update({ hp_attr.update({
'vm_hugepages_avail_2M': free_hugepages, 'vm_hugepages_avail_2M': free_hugepages,
'vm_hugepages_nr_2M': 'vm_hugepages_nr_2M':
(nr_hugepages - avs_hugepages_nr) (nr_hugepages - vswitch_hugepages_nr)
}) })
attr.update(hp_attr) attr.update(hp_attr)
@ -503,8 +502,8 @@ class NodeOperator(object):
Eng_KiB = node_total_kib - base_mem_MiB * Ki Eng_KiB = node_total_kib - base_mem_MiB * Ki
vswitch_mem_kib = (attr.get('avs_hugepages_size_mib', 0) * vswitch_mem_kib = (attr.get('vswitch_hugepages_size_mib', 0) *
attr.get('avs_hugepages_nr', 0) * Ki) attr.get('vswitch_hugepages_nr', 0) * Ki)
VM_KiB = (Eng_KiB - vswitch_mem_kib) VM_KiB = (Eng_KiB - vswitch_mem_kib)

View File

@ -463,19 +463,13 @@ class PCIOperator(object):
try: try:
with open(os.devnull, "w") as fnull: with open(os.devnull, "w") as fnull:
""" subprocess.check_call(["query_pci_id", "-v " + str(vendor),
query_pci_id is from dpdk (avs/cgcs-dpdk/files/query_pci_id). "-d " + str(device)],
DPDK is removed as part of AVS. stdout=fnull, stderr=fnull)
Need add it back later. Then enable this code again. dpdksupport = True
""" LOG.debug("DPDK does support NIC "
LOG.error("******ERROR: unable to determine DPDK support or not due to lack DPDK package.******") "(vendor: %s device: %s)",
# subprocess.check_call(["query_pci_id", "-v " + str(vendor), vendor, device)
# "-d " + str(device)],
# stdout=fnull, stderr=fnull)
# dpdksupport = True
# LOG.debug("DPDK does support NIC "
# "(vendor: %s device: %s)",
# vendor, device)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
dpdksupport = False dpdksupport = False
if e.returncode == '1': if e.returncode == '1':

View File

@ -141,7 +141,7 @@ class EthernetPort(base.APIBase):
"Represent whether the port is a boot port" "Represent whether the port is a boot port"
dpdksupport = bool dpdksupport = bool
"Represent whether or not the port supported AVS acceleration" "Represent whether or not the port supports DPDK acceleration"
host_uuid = types.uuid host_uuid = types.uuid
"Represent the UUID of the host the port belongs to" "Represent the UUID of the host the port belongs to"

View File

@ -3143,10 +3143,6 @@ class HostController(rest.RestController):
Perform semantic checks against data interfaces to ensure validity of Perform semantic checks against data interfaces to ensure validity of
the node configuration prior to unlocking it. the node configuration prior to unlocking it.
""" """
vswitch_type = utils.get_vswitch_type()
if vswitch_type != constants.VSWITCH_TYPE_AVS:
return
ihost_iinterfaces = ( ihost_iinterfaces = (
pecan.request.dbapi.iinterface_get_by_ihost(ihost['uuid'])) pecan.request.dbapi.iinterface_get_by_ihost(ihost['uuid']))
data_interface_configured = False data_interface_configured = False
@ -3172,10 +3168,6 @@ class HostController(rest.RestController):
controller will be confused on won't know how to map the VXLAN VTEP controller will be confused on won't know how to map the VXLAN VTEP
endpoints. endpoints.
""" """
vswitch_type = utils.get_vswitch_type()
if vswitch_type != constants.VSWITCH_TYPE_AVS:
return
sdn_enabled = utils.get_sdn_enabled() sdn_enabled = utils.get_sdn_enabled()
if not sdn_enabled: if not sdn_enabled:
return return
@ -3431,7 +3423,7 @@ class HostController(rest.RestController):
memtotal = m.node_memtotal_mib memtotal = m.node_memtotal_mib
allocated = m.platform_reserved_mib allocated = m.platform_reserved_mib
if m.hugepages_configured: if m.hugepages_configured:
allocated += m.avs_hugepages_nr * m.avs_hugepages_size_mib allocated += m.vswitch_hugepages_nr * m.vswitch_hugepages_size_mib
if m.vm_hugepages_nr_2M_pending is not None: if m.vm_hugepages_nr_2M_pending is not None:
allocated += constants.MIB_2M * m.vm_hugepages_nr_2M_pending allocated += constants.MIB_2M * m.vm_hugepages_nr_2M_pending
pending_2M_memory = True pending_2M_memory = True
@ -3499,7 +3491,7 @@ class HostController(rest.RestController):
vm_hugepages_4K = \ vm_hugepages_4K = \
(m.node_memtotal_mib - m.platform_reserved_mib) (m.node_memtotal_mib - m.platform_reserved_mib)
vm_hugepages_4K -= \ vm_hugepages_4K -= \
(m.avs_hugepages_nr * m.avs_hugepages_size_mib) (m.vswitch_hugepages_nr * m.vswitch_hugepages_size_mib)
vm_hugepages_4K -= \ vm_hugepages_4K -= \
(constants.MIB_2M * vm_hugepages_nr_2M) (constants.MIB_2M * vm_hugepages_nr_2M)
vm_hugepages_4K -= \ vm_hugepages_4K -= \

View File

@ -878,8 +878,6 @@ def _valid_network_types():
vswitch_type = utils.get_vswitch_type() vswitch_type = utils.get_vswitch_type()
system_mode = utils.get_system_mode() system_mode = utils.get_system_mode()
if vswitch_type != constants.VSWITCH_TYPE_AVS:
valid_types -= set([constants.NETWORK_TYPE_DATA])
if vswitch_type != constants.VSWITCH_TYPE_NUAGE_VRS: if vswitch_type != constants.VSWITCH_TYPE_NUAGE_VRS:
valid_types -= set([constants.NETWORK_TYPE_DATA_VRS]) valid_types -= set([constants.NETWORK_TYPE_DATA_VRS])
if system_mode == constants.SYSTEM_MODE_SIMPLEX: if system_mode == constants.SYSTEM_MODE_SIMPLEX:
@ -1200,7 +1198,7 @@ def _check_interface_data(op, interface, ihost, existing_interface):
# check mode/pool combinations and transitions for validity # check mode/pool combinations and transitions for validity
_check_address_mode(op, interface, ihost, existing_interface) _check_address_mode(op, interface, ihost, existing_interface)
# Make sure txhashpolicy for data is layer2 ... all that AVS supports # Make sure txhashpolicy for data is layer2
aemode = interface['aemode'] aemode = interface['aemode']
txhashpolicy = interface['txhashpolicy'] txhashpolicy = interface['txhashpolicy']
@ -1821,15 +1819,16 @@ def _neutron_host_extension_supported():
necessary or not. If it is not supported then this is an indication that necessary or not. If it is not supported then this is an indication that
we are running against a vanilla openstack installation. we are running against a vanilla openstack installation.
""" """
return bool(utils.get_vswitch_type() == constants.VSWITCH_TYPE_AVS) return True
## TODO: Rather than key off of the vswitch type this should be looking at # TODO: This should be looking at the neutron extension list, but because
## the neutron extension list, but because our config file is not setup # our config file is not setup properly to have a different region on a per
## properly to have a different region on a per service basis we cannot. # service basis we cannot.
## The code should like something like this: #
## # The code should like something like this:
## extensions = pecan.request.rpcapi.neutron_extension_list( #
## pecan.request.context) # extensions = pecan.request.rpcapi.neutron_extension_list(
## return bool(constants.NEUTRON_HOST_ALIAS in extensions) # pecan.request.context)
# return bool(constants.NEUTRON_HOST_ALIAS in extensions)
def _neutron_providernet_extension_supported(): def _neutron_providernet_extension_supported():
@ -1839,15 +1838,16 @@ def _neutron_providernet_extension_supported():
necessary or not. If it is not supported then this is an indication that necessary or not. If it is not supported then this is an indication that
we are running against a vanilla openstack installation. we are running against a vanilla openstack installation.
""" """
return bool(utils.get_vswitch_type() == constants.VSWITCH_TYPE_AVS) return True
## TODO: Rather than key off of the vswitch type this should be looking at # TODO: This should be looking at the neutron extension list, but because
## the neutron extension list, but because our config file is not setup # our config file is not setup properly to have a different region on a per
## properly to have a different region on a per service basis we cannot. # service basis we cannot.
## The code should like something like this: #
## # The code should like something like this:
## extensions = pecan.request.rpcapi.neutron_extension_list( #
## pecan.request.context) # extensions = pecan.request.rpcapi.neutron_extension_list(
## return bool(constants.NEUTRON_WRS_PROVIDER_ALIAS in extensions) # pecan.request.context)
# return bool(constants.NEUTRON_WRS_PROVIDER_ALIAS in extensions)
def _neutron_providernet_list(): def _neutron_providernet_list():

View File

@ -94,17 +94,17 @@ class Memory(base.APIBase):
hugepages_configured = wtypes.text hugepages_configured = wtypes.text
"Represent whether huge pages are configured" "Represent whether huge pages are configured"
avs_hugepages_size_mib = int vswitch_hugepages_size_mib = int
"Represent the imemory avs huge pages size in MiB" "Represent the imemory vswitch huge pages size in MiB"
avs_hugepages_reqd = int vswitch_hugepages_reqd = int
"Represent the imemory avs required number of hugepages" "Represent the imemory vswitch required number of hugepages"
avs_hugepages_nr = int vswitch_hugepages_nr = int
"Represent the imemory avs number of hugepages" "Represent the imemory vswitch number of hugepages"
avs_hugepages_avail = int vswitch_hugepages_avail = int
"Represent the imemory avs number of hugepages available" "Represent the imemory vswitch number of hugepages available"
vm_hugepages_nr_2M_pending = int vm_hugepages_nr_2M_pending = int
"Represent the imemory vm number of hugepages pending (2M pages)" "Represent the imemory vm number of hugepages pending (2M pages)"
@ -182,9 +182,9 @@ class Memory(base.APIBase):
if not expand: if not expand:
memory.unset_fields_except(['uuid', 'memtotal_mib', 'memavail_mib', memory.unset_fields_except(['uuid', 'memtotal_mib', 'memavail_mib',
'platform_reserved_mib', 'hugepages_configured', 'platform_reserved_mib', 'hugepages_configured',
'avs_hugepages_size_mib', 'avs_hugepages_nr', 'vswitch_hugepages_size_mib', 'vswitch_hugepages_nr',
'avs_hugepages_reqd', 'vswitch_hugepages_reqd',
'avs_hugepages_avail', 'vswitch_hugepages_avail',
'vm_hugepages_nr_2M', 'vm_hugepages_nr_2M',
'vm_hugepages_nr_1G', 'vm_hugepages_use_1G', 'vm_hugepages_nr_1G', 'vm_hugepages_use_1G',
'vm_hugepages_nr_2M_pending', 'vm_hugepages_nr_2M_pending',
@ -576,10 +576,10 @@ def _check_memory(rpc_port, ihost, platform_reserved_mib=None,
mem_alloc += int(rpc_port['vm_hugepages_nr_1G']) * 1000 mem_alloc += int(rpc_port['vm_hugepages_nr_1G']) * 1000
LOG.debug("vm total=%s" % (mem_alloc)) LOG.debug("vm total=%s" % (mem_alloc))
avs_hp_size = rpc_port['avs_hugepages_size_mib'] vs_hp_size = rpc_port['vswitch_hugepages_size_mib']
avs_hp_nr = rpc_port['avs_hugepages_nr'] vs_hp_nr = rpc_port['vswitch_hugepages_nr']
mem_alloc += avs_hp_size * avs_hp_nr mem_alloc += vs_hp_size * vs_hp_nr
LOG.debug("avs_hp_nr=%s avs_hp_size=%s" % (avs_hp_nr, avs_hp_size)) LOG.debug("vs_hp_nr=%s vs_hp_size=%s" % (vs_hp_nr, vs_hp_size))
LOG.debug("memTotal %s mem_alloc %s" % (node_memtotal_mib, mem_alloc)) LOG.debug("memTotal %s mem_alloc %s" % (node_memtotal_mib, mem_alloc))
# Initial configuration defaults mem_alloc to consume 100% of 2M pages, # Initial configuration defaults mem_alloc to consume 100% of 2M pages,

View File

@ -117,7 +117,7 @@ class Port(base.APIBase):
"Represent the interface_id the port belongs to" "Represent the interface_id the port belongs to"
dpdksupport = bool dpdksupport = bool
"Represent whether or not the port supported AVS acceleration" "Represent whether or not the port supports DPDK acceleration"
host_uuid = types.uuid host_uuid = types.uuid
"Represent the UUID of the host the port belongs to" "Represent the UUID of the host the port belongs to"

View File

@ -48,6 +48,8 @@ from sysinv.openstack.common.gettextutils import _
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
VALID_VSWITCH_TYPES = [constants.VSWITCH_TYPE_OVS_DPDK]
class System(base.APIBase): class System(base.APIBase):
"""API representation of a system. """API representation of a system.
@ -353,6 +355,8 @@ class SystemController(rest.RestController):
change_https = False change_https = False
change_sdn = False change_sdn = False
change_dc_role = False change_dc_role = False
vswitch_type = None
# prevent description field from being updated # prevent description field from being updated
for p in jsonpatch.JsonPatch(patch): for p in jsonpatch.JsonPatch(patch):
if p['path'] == '/software_version': if p['path'] == '/software_version':
@ -412,6 +416,10 @@ class SystemController(rest.RestController):
distributed_cloud_role = p['value'] distributed_cloud_role = p['value']
patch.remove(p) patch.remove(p)
if p['path'] == '/vswitch_type':
vswitch_type = p['value']
patch.remove(p)
try: try:
patched_system = jsonpatch.apply_patch(system_dict, patched_system = jsonpatch.apply_patch(system_dict,
jsonpatch.JsonPatch(patch)) jsonpatch.JsonPatch(patch))
@ -454,6 +462,15 @@ class SystemController(rest.RestController):
raise wsme.exc.ClientSideError(_("distributed_cloud_role is already set " raise wsme.exc.ClientSideError(_("distributed_cloud_role is already set "
" as %s" % rpc_isystem['distributed_cloud_role'])) " as %s" % rpc_isystem['distributed_cloud_role']))
if 'vswitch_type' in updates:
if vswitch_type not in VALID_VSWITCH_TYPES:
raise wsme.exc.ClientSideError(_("unsupported vswitch_type: %s"
% vswitch_type))
if vswitch_type == rpc_isystem['capabilities']['vswitch_type']:
raise wsme.exc.ClientSideError(_("vswitch_type is already set"
" as %s" % vswitch_type))
patched_system['capabilities']['vswitch_type'] = vswitch_type
# Update only the fields that have changed # Update only the fields that have changed
name = "" name = ""
contact = "" contact = ""
@ -502,12 +519,16 @@ class SystemController(rest.RestController):
pecan.request.context) pecan.request.context)
if capabilities: if capabilities:
if change_sdn: if change_sdn:
LOG.info("update sdn capabilities to %s" % capabilities) LOG.info("update sdn to %s" % capabilities)
pecan.request.rpcapi.update_sdn_enabled(pecan.request.context) pecan.request.rpcapi.update_sdn_enabled(pecan.request.context)
if change_https: if change_https:
LOG.info("update capabilities / https to %s" % capabilities) LOG.info("update https to %s" % capabilities)
pecan.request.rpcapi.configure_system_https( pecan.request.rpcapi.configure_system_https(
pecan.request.context) pecan.request.context)
if vswitch_type:
LOG.info("update vswitch_type to %s" % capabilities)
pecan.request.rpcapi.update_vswitch_type(
pecan.request.context)
if distributed_cloud_role and change_dc_role: if distributed_cloud_role and change_dc_role:
LOG.info("update distributed cloud role to %s" % distributed_cloud_role) LOG.info("update distributed cloud role to %s" % distributed_cloud_role)

View File

@ -248,17 +248,9 @@ def is_aio_simplex_host_unlocked(host):
host['invprovision'] != constants.PROVISIONING) host['invprovision'] != constants.PROVISIONING)
# cache the result of the vswitch type to avoid having to query the system
# for each access to this system attribute
_vswitch_type = None
def get_vswitch_type(): def get_vswitch_type():
global _vswitch_type system = pecan.request.dbapi.isystem_get_one()
if _vswitch_type is None: return system.capabilities.get('vswitch_type')
system = pecan.request.dbapi.isystem_get_one()
_vswitch_type = system.capabilities.get('vswitch_type')
return _vswitch_type
def get_https_enabled(): def get_https_enabled():

View File

@ -0,0 +1,61 @@
#!/usr/bin/python
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import sys
import json
import subprocess
from argparse import ArgumentParser
def main():
''' The goal of this script is to discover if the supplied PCI device is
supported by the vswitch as an accelerated NIC.'''
parser = ArgumentParser(description="Query vswitch NIC support")
parser.add_argument("-v", "--vendor", dest="vid",
help="Vendor ID",
type=lambda x: hex(int(x, 0)),
action='store', metavar="HEX",
required=True)
parser.add_argument("-d", "--device", dest="did",
help="Device ID",
type=lambda x: hex(int(x, 0)),
action='store', metavar="HEX",
required=True)
args = parser.parse_args()
cmd = 'python /usr/share/openvswitch/scripts/dpdk-pmdinfo.py ' \
'-r /usr/sbin/ovs-vswitchd'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
out, err = p.communicate()
result = out.split('\n')
for line in result:
if not line:
continue
pmd_info = json.loads(line)
supported_devices = pmd_info['pci_ids']
for supported_device in supported_devices:
vid = hex(supported_device[0])
did = hex(supported_device[1])
if vid == args.vid and did == args.did:
print("Vendor ID: %s Device ID: %s is supported" %
(args.vid, args.did))
return 0
print("Vendor ID: %s Device ID: %s is not supported" %
(args.vid, args.did))
return 1
if __name__ == "__main__":
ret = main()
sys.exit(ret)

View File

@ -244,7 +244,7 @@ NEUTRON_PROVIDERNET_VXLAN = "vxlan"
NEUTRON_PROVIDERNET_VLAN = "vlan" NEUTRON_PROVIDERNET_VLAN = "vlan"
# Supported compute node vswitch types # Supported compute node vswitch types
VSWITCH_TYPE_AVS = "avs" VSWITCH_TYPE_OVS_DPDK = "ovs-dpdk"
VSWITCH_TYPE_NUAGE_VRS = "nuage_vrs" VSWITCH_TYPE_NUAGE_VRS = "nuage_vrs"
# Partition default sizes # Partition default sizes

View File

@ -1744,7 +1744,7 @@ class ConductorManager(service.PeriodicService):
mtu = constants.DEFAULT_MTU mtu = constants.DEFAULT_MTU
port = None port = None
# ignore port if no MAC address present, this will # ignore port if no MAC address present, this will
# occur for data port after they are configured via AVS # occur for data port after they are configured via DPDK driver
if not inic['mac']: if not inic['mac']:
continue continue
try: try:
@ -6645,11 +6645,6 @@ class ConductorManager(service.PeriodicService):
# Apply Neutron manifest on Controller(this # Apply Neutron manifest on Controller(this
# will update the SNAT rules for the SDN controllers) # will update the SNAT rules for the SDN controllers)
# Ideally we would also like to apply the vswitch manifest
# on Compute so as to write the vswitch.ini however AVS
# cannot resync on the fly, so mark the Compute node as
# config-out-of-date
self._config_update_hosts(context, [constants.COMPUTE], reboot=True) self._config_update_hosts(context, [constants.COMPUTE], reboot=True)
config_uuid = self._config_update_hosts(context, config_uuid = self._config_update_hosts(context,
@ -6679,6 +6674,30 @@ class ConductorManager(service.PeriodicService):
personalities = [constants.COMPUTE] personalities = [constants.COMPUTE]
self._config_update_hosts(context, personalities, reboot=True) self._config_update_hosts(context, personalities, reboot=True)
def update_vswitch_type(self, context):
"""Update the system vswitch type.
:param context: an admin context.
"""
LOG.info("update_vswitch_type")
personalities = [constants.CONTROLLER]
config_dict = {
"personalities": personalities,
"classes": ['platform::sysctl::controller::runtime',
'platform::nfv::runtime',
'openstack::neutron::server::runtime']
}
config_uuid = self._config_update_hosts(context, personalities)
self._config_apply_runtime_manifest(context, config_uuid, config_dict)
if tsc.system_type == constants.TIS_AIO_BUILD:
personalities = [constants.CONTROLLER]
else:
personalities = [constants.COMPUTE]
self._config_update_hosts(context, personalities, reboot=True)
def _update_hosts_file(self, hostname, address, active=True): def _update_hosts_file(self, hostname, address, active=True):
"""Update or add an entry to the /etc/hosts configuration file """Update or add an entry to the /etc/hosts configuration file

View File

@ -1226,6 +1226,14 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
return self.call(context, return self.call(context,
self.make_msg('update_sdn_enabled')) self.make_msg('update_sdn_enabled'))
def update_vswitch_type(self, context):
"""Synchronously, have the conductor update the system vswitch type
:param context: request context.
"""
return self.call(context,
self.make_msg('update_vswitch_type'))
def configure_keystore_account(self, context, service_name, def configure_keystore_account(self, context, service_name,
username, password): username, password):
"""Synchronously, have a conductor configure a ks(keyring) account. """Synchronously, have a conductor configure a ks(keyring) account.

View File

@ -0,0 +1,29 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (c) 2013-2016 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from sqlalchemy import MetaData, Table
ENGINE = 'InnoDB'
CHARSET = 'utf8'
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
memory = Table('i_imemory', meta, autoload=True)
memory.c.avs_hugepages_size_mib.alter(name="vswitch_hugepages_size_mib")
memory.c.avs_hugepages_reqd.alter(name="vswitch_hugepages_reqd")
memory.c.avs_hugepages_nr.alter(name="vswitch_hugepages_nr")
memory.c.avs_hugepages_avail.alter(name="vswitch_hugepages_avail")
return True
def downgrade(migrate_engine):
# As per other openstack components, downgrade is
# unsupported in this release.
raise NotImplementedError('SysInv database downgrade is unsupported.')

View File

@ -293,10 +293,10 @@ class imemory(Base):
hugepages_configured = Column(Boolean, default=False) hugepages_configured = Column(Boolean, default=False)
avs_hugepages_size_mib = Column(Integer) vswitch_hugepages_size_mib = Column(Integer)
avs_hugepages_reqd = Column(Integer) vswitch_hugepages_reqd = Column(Integer)
avs_hugepages_nr = Column(Integer) vswitch_hugepages_nr = Column(Integer)
avs_hugepages_avail = Column(Integer) vswitch_hugepages_avail = Column(Integer)
vm_hugepages_nr_2M_pending = Column(Integer) vm_hugepages_nr_2M_pending = Column(Integer)
vm_hugepages_nr_1G_pending = Column(Integer) vm_hugepages_nr_1G_pending = Column(Integer)

View File

@ -34,10 +34,10 @@ class Memory(base.SysinvObject):
'hugepages_configured': utils.str_or_none, 'hugepages_configured': utils.str_or_none,
'avs_hugepages_size_mib': utils.int_or_none, 'vswitch_hugepages_size_mib': utils.int_or_none,
'avs_hugepages_reqd': utils.int_or_none, 'vswitch_hugepages_reqd': utils.int_or_none,
'avs_hugepages_nr': utils.int_or_none, 'vswitch_hugepages_nr': utils.int_or_none,
'avs_hugepages_avail': utils.int_or_none, 'vswitch_hugepages_avail': utils.int_or_none,
'vm_hugepages_nr_2M_pending': utils.int_or_none, 'vm_hugepages_nr_2M_pending': utils.int_or_none,
'vm_hugepages_nr_1G_pending': utils.int_or_none, 'vm_hugepages_nr_1G_pending': utils.int_or_none,

View File

@ -0,0 +1,19 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import yaml
class quoted_str(str):
pass
# force strings to be single-quoted to avoid interpretation as numeric values
def quoted_presenter(dumper, data):
return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style="'")
yaml.add_representer(quoted_str, quoted_presenter)

View File

@ -16,6 +16,8 @@ from sysinv.common import constants
from sysinv.common import utils from sysinv.common import utils
from sysinv.common import exception from sysinv.common import exception
from . import quoted_str
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class BasePuppet(object): class BasePuppet(object):
@ -45,6 +47,10 @@ class BasePuppet(object):
def context(self): def context(self):
return self._operator.context return self._operator.context
@staticmethod
def quoted_str(value):
return quoted_str(value)
@staticmethod @staticmethod
def _generate_random_password(length=16): def _generate_random_password(length=16):
suffix = "Ti0*" suffix = "Ti0*"
@ -79,6 +85,13 @@ class BasePuppet(object):
system = self._get_system() system = self._get_system()
return system.capabilities.get('region_config', False) return system.capabilities.get('region_config', False)
def _vswitch_type(self):
if self.dbapi is None:
return False
system = self._get_system()
return system.capabilities.get('vswitch_type', None)
def _distributed_cloud_role(self): def _distributed_cloud_role(self):
if self.dbapi is None: if self.dbapi is None:
return None return None
@ -160,6 +173,14 @@ class BasePuppet(object):
cpus.append(c) cpus.append(c)
return cpus return cpus
def _get_vswitch_cpu_list(self, host):
cpus = self._get_host_cpu_list(host, constants.VSWITCH_FUNCTION)
return sorted(cpus, key=lambda c: c.cpu)
def _get_platform_cpu_list(self, host):
cpus = self._get_host_cpu_list(host, constants.PLATFORM_FUNCTION)
return sorted(cpus, key=lambda c: c.cpu)
def _get_service_parameters(self, service=None): def _get_service_parameters(self, service=None):
service_parameters = [] service_parameters = []
if self.dbapi is None: if self.dbapi is None:

View File

@ -12,18 +12,16 @@ import uuid
from netaddr import IPAddress from netaddr import IPAddress
from netaddr import IPNetwork from netaddr import IPNetwork
from netaddr import EUI
from netaddr import mac_unix
from sysinv.common import constants from sysinv.common import constants
from sysinv.common import exception from sysinv.common import exception
from sysinv.common import utils from sysinv.common import utils
from sysinv.conductor import openstack
from sysinv.openstack.common import log from sysinv.openstack.common import log
from . import base from . import base
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
MAC_ADDRESS_UL_BIT_VALUE = 2
PLATFORM_NETWORK_TYPES = [constants.NETWORK_TYPE_PXEBOOT, PLATFORM_NETWORK_TYPES = [constants.NETWORK_TYPE_PXEBOOT,
constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_MGMT,
@ -59,6 +57,16 @@ ADDRESS_CONFIG_RESOURCE = 'platform::addresses::address_config'
class InterfacePuppet(base.BasePuppet): class InterfacePuppet(base.BasePuppet):
"""Class to encapsulate puppet operations for interface configuration""" """Class to encapsulate puppet operations for interface configuration"""
def __init__(self, *args, **kwargs):
super(InterfacePuppet, self).__init__(*args, **kwargs)
self._openstack = None
@property
def openstack(self):
if not self._openstack:
self._openstack = openstack.OpenStackOperator(self.dbapi)
return self._openstack
def get_host_config(self, host): def get_host_config(self, host):
""" """
Generate the hiera data for the puppet network config and route config Generate the hiera data for the puppet network config and route config
@ -125,7 +133,7 @@ class InterfacePuppet(base.BasePuppet):
'networks': self._get_network_type_index(), 'networks': self._get_network_type_index(),
'gateways': self._get_gateway_index(), 'gateways': self._get_gateway_index(),
'floatingips': self._get_floating_ip_index(), 'floatingips': self._get_floating_ip_index(),
'providernets': {}, 'providernets': self._get_provider_networks(host),
} }
return context return context
@ -306,6 +314,18 @@ class InterfacePuppet(base.BasePuppet):
return floating_ips return floating_ips
def _get_provider_networks(self, host):
# TODO(alegacy): this will not work as intended for upgrades of AIO-SX
# and -DX. The call to get_providernetworksdict will return an empty
# dictionary because the neutron endpoint is not available yet. Since
# we do not currently support SDN/OVS over upgrades we will need to
# deal with this in a later commit.
pnets = {}
if (self.openstack and
constants.COMPUTE in utils.get_personalities(host)):
pnets = self.openstack.get_providernetworksdict(quiet=True)
return pnets
def is_platform_network_type(iface): def is_platform_network_type(iface):
networktype = utils.get_primary_network_type(iface) networktype = utils.get_primary_network_type(iface)
@ -733,7 +753,7 @@ def needs_interface_config(context, iface):
if is_a_mellanox_device(context, iface): if is_a_mellanox_device(context, iface):
# Check for Mellanox data interfaces. We must set the MTU sizes of # Check for Mellanox data interfaces. We must set the MTU sizes of
# Mellanox data interfaces in case it is not the default. Normally # Mellanox data interfaces in case it is not the default. Normally
# data interfaces are owned by AVS, they are not managed through # data interfaces are owned by DPDK, they are not managed through
# Linux but in the Mellanox case, the interfaces are still visible # Linux but in the Mellanox case, the interfaces are still visible
# in Linux so in case one needs to set jumbo frames, it has to be # in Linux so in case one needs to set jumbo frames, it has to be
# set in Linux as well. We only do this for combined nodes or # set in Linux as well. We only do this for combined nodes or
@ -744,21 +764,6 @@ def needs_interface_config(context, iface):
return False return False
def needs_vswitch_config(context, iface):
"""
Determine whether an interface needs to be configured as a vswitch
interface. This is true if the interface is a data interface, is required
by a platform interface (i.e., a platform VLAN over a data interface), is
required by a data interface (i.e., a data AE member, a VLAN lower
interface).
"""
if not is_compute_subfunction(context):
return False
elif is_data_interface(context, iface):
return True
return False
def get_basic_network_config(ifname, ensure='present', def get_basic_network_config(ifname, ensure='present',
method='manual', onboot='true', method='manual', onboot='true',
hotplug='false', family='inet', hotplug='false', family='inet',
@ -1001,167 +1006,6 @@ def generate_network_config(context, config, iface):
}) })
class CustomMacDialect(mac_unix):
word_fmt = '%.2x'
def _set_local_admin_bit(value):
"""
Assert the locally administered bit in the MAC address in order to avoid
conflicting with the real port that this interface is associated with.
"""
mac = EUI(value, dialect=CustomMacDialect)
mac.__setitem__(0, (mac.words[0] | MAC_ADDRESS_UL_BIT_VALUE))
return str(mac)
def get_vswitch_ethernet_command(context, iface):
"""
Produce the cli command to add a single ethernet interface to vswitch.
"""
port = get_interface_port(context, iface)
attributes = {'ifname': get_interface_os_ifname(context, iface) + '-avp',
'port_uuid': port['uuid'],
'iface_uuid': iface['uuid'],
'mtu': iface['imtu']}
if is_dpdk_compatible(context, iface):
command = ("ethernet add %(port_uuid)s %(iface_uuid)s "
"%(mtu)s\n" % attributes)
else:
# Set the locally administered bit on the MAC address because to run
# providernet connectivity tests we will need to originate packets from
# this interface. Since the other end of the interface is the actual
# avp interface in the linux kernel it will get confused if we are
# sending it packets originated from its' MAC address.
attributes.update({'mac': _set_local_admin_bit(iface['imac']),
'numa': 0})
command = ("port add avp-provider %(iface_uuid)s %(mac)s %(numa)s "
"%(mtu)s %(ifname)s\n" % attributes)
return command
def get_vswitch_vlan_command(context, iface):
"""
Produce the cli command to add a vlan ethernet interface to vswitch.
"""
lower_iface = get_lower_interface(context, iface)
attributes = {'lower_uuid': lower_iface['uuid'],
'vlan_id': iface['vlan_id'],
'iface_uuid': iface['uuid'],
'mtu': iface['imtu']}
command = ("vlan add %(lower_uuid)s %(vlan_id)s %(iface_uuid)s %(mtu)s" %
attributes)
if is_platform_interface(context, iface):
# If this is a platform VLAN than mark it as a host interface to
# prevent the vswitch bridge input handler from intercepting packets
# destined to the interface MAC. That intercept exists for providernet
# connectivity tests but those are not necessary on platform VLAN
# interfaces.
command += " host"
return command + "\n"
def get_vswitch_bond_options(iface):
"""
Return a dictionary of vswitch bond attributes based on the interface
configuration.
"""
monitor_mode = 'link-state'
ae_mode = iface['aemode']
if ae_mode in BALANCED_AE_MODES:
distribution_mode = 'hash-mac'
protection_mode = 'loadbalance'
elif ae_mode in LACP_AE_MODES:
distribution_mode = 'hash-mac'
protection_mode = '802.3ad'
else:
protection_mode = 'failover'
distribution_mode = 'none'
return {'distribution': distribution_mode,
'protection': protection_mode,
'monitor': monitor_mode}
def get_vswitch_bond_commands(context, iface):
"""
Produce the cli command to add a aggregated ethernet interface to vswitch.
"""
attributes = {'uuid': iface['uuid'],
'mtu': iface['imtu']}
attributes.update(get_vswitch_bond_options(iface))
# Setup the AE interface
commands = ("ae add %(uuid)s %(mtu)s %(protection)s %(distribution)s "
"%(monitor)s\n" % attributes)
# Add all lower interfaces as AE member interfaces
for lower_ifname in iface['uses']:
lower_iface = context['interfaces'][lower_ifname]
commands += ("ae attach member %s %s\n" %
(iface['uuid'], lower_iface['uuid']))
return commands
def get_vswitch_interface_commands(context, iface):
"""
Produce the cli command to add a single interface to vswitch.
"""
if iface['iftype'] == constants.INTERFACE_TYPE_ETHERNET:
return get_vswitch_ethernet_command(context, iface)
elif iface['iftype'] == constants.INTERFACE_TYPE_AE:
return get_vswitch_bond_commands(context, iface)
elif iface['iftype'] == constants.INTERFACE_TYPE_VLAN:
return get_vswitch_vlan_command(context, iface)
def get_vswitch_address_command(iface, address):
"""
Produce the cli command required to create an interface address.
"""
attributes = {'iface_uuid': iface['uuid'],
'address': address['address'],
'prefix': address['prefix']}
return ('interface add addr %(iface_uuid)s %(address)s/%(prefix)s\n' %
attributes)
def get_vswitch_route_command(iface, route):
"""
Produce the vswitch cli command required to create a route table entry for
a given interface.
"""
attributes = {'iface_uuid': iface['uuid'],
'network': route['network'],
'prefix': route['prefix'],
'gateway': route['gateway'],
'metric': route['metric']}
return ('route append %(network)s/%(prefix)s %(iface_uuid)s %(gateway)s '
'%(metric)s\n' % attributes)
def get_vswitch_commands(context, iface):
"""
Produce the vswitch cli commands required for configuring the logical
interfaces in vswitch for this particular interface.
"""
commands = get_vswitch_interface_commands(context, iface)
networktype = utils.get_primary_network_type(iface)
if networktype in DATA_NETWORK_TYPES:
# Add complementary commands (if needed)
for address in context['addresses'].get(iface['ifname'], []):
if address['networktype'] == networktype:
commands += get_vswitch_address_command(iface, address)
for route in context['routes'].get(iface['ifname'], []):
commands += get_vswitch_route_command(iface, route)
return commands
def find_interface_by_type(context, networktype): def find_interface_by_type(context, networktype):
""" """
Lookup an interface based on networktype. This is only intended for Lookup an interface based on networktype. This is only intended for

View File

@ -65,8 +65,6 @@ class NeutronPuppet(openstack.OpenstackBasePuppet):
ksuser = self._get_service_user_name(self.SERVICE_NAME) ksuser = self._get_service_user_name(self.SERVICE_NAME)
sdn_l3_mode_enabled = self._get_sdn_l3_mode_enabled()
config = { config = {
'neutron::server::notifications::auth_url': 'neutron::server::notifications::auth_url':
self._keystone_identity_uri(), self._keystone_identity_uri(),
@ -85,8 +83,6 @@ class NeutronPuppet(openstack.OpenstackBasePuppet):
'neutron::agents::metadata::metadata_ip': 'neutron::agents::metadata::metadata_ip':
self._get_management_address(), self._get_management_address(),
'neutron::agents::vswitch::sdn_manage_external_networks':
not sdn_l3_mode_enabled,
'neutron::keystone::authtoken::auth_url': 'neutron::keystone::authtoken::auth_url':
self._keystone_identity_uri(), self._keystone_identity_uri(),
@ -113,8 +109,6 @@ class NeutronPuppet(openstack.OpenstackBasePuppet):
'openstack::neutron::params::region_name': 'openstack::neutron::params::region_name':
self.get_region_name(), self.get_region_name(),
'openstack::neutron::params::l3_agent_enabled':
not sdn_l3_mode_enabled,
'openstack::neutron::params::service_create': 'openstack::neutron::params::service_create':
self._to_create_services(), self._to_create_services(),
} }
@ -163,33 +157,19 @@ class NeutronPuppet(openstack.OpenstackBasePuppet):
controller_config controller_config
} }
def _get_sdn_l3_mode_enabled(self):
try:
sdn_l3_mode = self.dbapi.service_parameter_get_one(
service=constants.SERVICE_TYPE_NETWORK,
section=constants.SERVICE_PARAM_SECTION_NETWORK_DEFAULT,
name=constants.SERVICE_PARAM_NAME_DEFAULT_SERVICE_PLUGINS)
if not sdn_l3_mode:
return False
allowed_vals = constants.SERVICE_PLUGINS_SDN
return (any(sp in allowed_vals
for sp in sdn_l3_mode.value.split(',')))
except:
return False
def get_host_config(self, host): def get_host_config(self, host):
interface_mappings = [] device_mappings = []
for iface in self.context['interfaces'].values(): for iface in self.context['interfaces'].values():
if (utils.get_primary_network_type(iface) == if (utils.get_primary_network_type(iface) ==
constants.NETWORK_TYPE_PCI_SRIOV): constants.NETWORK_TYPE_PCI_SRIOV):
port = interface.get_interface_port(self.context, iface) port = interface.get_interface_port(self.context, iface)
providernets = interface.get_interface_providernets(iface) providernets = interface.get_interface_providernets(iface)
for net in providernets: for net in providernets:
interface_mappings.append("%s:%s" % (net, port['name'])) device_mappings.append("%s:%s" % (net, port['name']))
config = { config = {
'neutron::agents::ml2::sriov::physical_device_mappings': 'neutron::agents::ml2::sriov::physical_device_mappings':
interface_mappings, device_mappings,
} }
if host.personality == constants.CONTROLLER: if host.personality == constants.CONTROLLER:

View File

@ -26,11 +26,9 @@ class NfvPuppet(openstack.OpenstackBasePuppet):
system = self._get_system() system = self._get_system()
if system.system_mode == constants.SYSTEM_MODE_SIMPLEX: if system.system_mode == constants.SYSTEM_MODE_SIMPLEX:
data_port_fault_handling_enabled = False
single_hypervisor = True single_hypervisor = True
single_controller = True single_controller = True
else: else:
data_port_fault_handling_enabled = True
single_hypervisor = False single_hypervisor = False
single_controller = False single_controller = False
@ -52,8 +50,6 @@ class NfvPuppet(openstack.OpenstackBasePuppet):
self._get_management_address(), self._get_management_address(),
'nfv::nfvi::host_listener_host': 'nfv::nfvi::host_listener_host':
self._get_management_address(), self._get_management_address(),
'nfv::nfvi::infrastructure_rest_api_data_port_fault_handling_enabled':
data_port_fault_handling_enabled,
'nfv::nfvi::openstack_username': 'nfv::nfvi::openstack_username':
self._operator.keystone.get_admin_user_name(), self._operator.keystone.get_admin_user_name(),

View File

@ -0,0 +1,277 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from sysinv.common import constants
from sysinv.common import utils
from . import base
from . import interface
class OVSPuppet(base.BasePuppet):
"""Class to encapsulate puppet operations for vswitch configuration"""
def __init__(self, *args, **kwargs):
super(OVSPuppet, self).__init__(*args, **kwargs)
def get_host_config(self, host):
config = {}
if (constants.COMPUTE in utils.get_personalities(host) and
self._vswitch_type() == constants.VSWITCH_TYPE_OVS_DPDK):
config.update(self._get_cpu_config(host))
config.update(self._get_memory_config(host))
config.update(self._get_port_config(host))
config.update(self._get_virtual_config(host))
config.update(self._get_neutron_config(host))
return config
def _get_port_config(self, host):
ovs_devices = {}
ovs_bridges = {}
ovs_ports = {}
ovs_addresses = {}
index = 0
for iface in sorted(self.context['interfaces'].values(),
key=interface.interface_sort_key):
if interface.is_data_network_type(iface):
# create a separate bridge for every configured data interface
brname = 'br-phy%d' % index
ovs_bridges[brname] = {}
# save the associated bridge for provider network mapping
iface['_ovs_bridge'] = brname
if iface['iftype'] == constants.INTERFACE_TYPE_ETHERNET:
port, devices = self._get_ethernet_port(
host, iface, brname, index)
elif iface['iftype'] == constants.INTERFACE_TYPE_AE:
port, devices = self._get_bond_port(
host, iface, brname, index)
elif iface['iftype'] == constants.INTERFACE_TYPE_VLAN:
port, devices = self._get_vlan_port(
host, iface, brname, index)
else:
raise Exception("unsupported interface type: %s" %
iface['iftype'])
ovs_ports.update({port['name']: port})
ovs_devices.update({d['pci_addr']: d for d in devices})
index += 1
# currently only one provider network is supported per
# interface, therefore obtain first entry
providernet = interface.get_interface_providernets(iface)[0]
# setup tunnel address if assigned provider network is vxlan
if self._is_vxlan_providernet(providernet):
address = interface.get_interface_primary_address(
self.context, iface)
if address:
ovs_addresses[brname] = {
'ifname': brname,
'address': address['address'],
'prefixlen': address['prefix'],
}
return {
'platform::vswitch::ovs::devices': ovs_devices,
'platform::vswitch::ovs::bridges': ovs_bridges,
'platform::vswitch::ovs::ports': ovs_ports,
'platform::vswitch::ovs::addresses': ovs_addresses,
}
def _get_ethernet_device(self, iface):
port = interface.get_interface_port(self.context, iface)
pci_addr = self.quoted_str(port.pciaddr)
return {
'pci_addr': pci_addr
}
def _get_ethernet_interface(self, host, iface, ifname):
port = interface.get_interface_port(self.context, iface)
rxq_count = len(self.context["_ovs_cpus"])
attributes = [
"options:dpdk-devargs=%s" % str(port.pciaddr),
"options:n_rxq=%d" % rxq_count,
"mtu_request=%d" % iface['imtu']
]
# TODO(mpeters): set other_config:pmd-rxq-affinity to pin receive
# queues to specific PMD cores
iftype = 'dpdk'
return {
'name': ifname,
'type': iftype,
'attributes': attributes,
}
def _get_ethernet_port(self, host, iface, bridge, index):
devices = []
interfaces = []
ifname = 'eth%d' % index
devices.append(self._get_ethernet_device(iface))
interfaces.append(self._get_ethernet_interface(host, iface, ifname))
port = {
'name': ifname,
'bridge': bridge,
'interfaces': interfaces,
}
return port, devices
def _get_bond_port(self, host, iface, bridge, index):
devices = []
interfaces = []
attributes = []
ifname = 'bond%d' % index
# TODO(mpeters): OVS can support balance-tcp if interface txhashpolicy
# is set to layer3+4 (currently restricted at API for data interfaces)
ae_mode = iface['aemode']
if ae_mode in interface.ACTIVE_STANDBY_AE_MODES:
attributes.append("bond_mode=active-backup")
if ae_mode in interface.BALANCED_AE_MODES:
attributes.append("bond_mode=balance-slb")
elif ae_mode in interface.LACP_AE_MODES:
attributes.append("lacp=active")
attributes.append("bond_mode=balance-slb")
attributes.append("other_config:lacp-time=fast")
for member, lower_ifname in enumerate(iface['uses']):
lower_iface = self.context['interfaces'][lower_ifname]
member_ifname = '%s.%d' % (ifname, member)
devices.append(self._get_ethernet_device(lower_iface))
interfaces.append(self._get_ethernet_interface(
host, lower_iface, member_ifname))
port = {
'type': 'bond',
'name': ifname,
'bridge': bridge,
'attributes': attributes,
'interfaces': interfaces,
}
return port, devices
def _get_vlan_port(self, host, iface, bridge, index):
devices = []
interfaces = []
ifname = 'vlan%d' % iface['vlan_id']
attributes = [
"tag=%d" % iface['vlan_id']
]
lower_iface = interface.get_lower_interface(self.context, iface)
devices.append(self._get_ethernet_device(lower_iface))
interfaces.append(self._get_ethernet_interface(
host, lower_iface, ifname))
port = {
'name': ifname,
'bridge': bridge,
'attributes': attributes,
'interfaces': interfaces,
}
return port, devices
def _get_cpu_config(self, host):
platform_cpus = self._get_platform_cpu_list(host)
vswitch_cpus = self._get_vswitch_cpu_list(host)
host_cpus = platform_cpus[:1] + vswitch_cpus[:]
host_core_list = self.quoted_str(
','.join([str(c.cpu) for c in host_cpus]))
pmd_core_list = self.quoted_str(
','.join([str(c.cpu) for c in vswitch_cpus]))
# save the assigned CPUs for port assignment
self.context["_ovs_cpus"] = [c.cpu for c in vswitch_cpus]
return {
'vswitch::dpdk::host_core_list': host_core_list,
'vswitch::dpdk::pmd_core_list': pmd_core_list,
}
def _get_memory_config(self, host):
vswitch_memory = []
host_memory = self.dbapi.imemory_get_by_ihost(host.id)
for memory in host_memory:
vswitch_size = memory.vswitch_hugepages_size_mib
vswitch_pages = memory.vswitch_hugepages_nr
vswitch_memory.append(str(vswitch_size * vswitch_pages))
dpdk_socket_mem = self.quoted_str(','.join(vswitch_memory))
return {
'vswitch::dpdk::socket_mem': dpdk_socket_mem
}
def _get_virtual_config(self, host):
config = {}
if utils.is_virtual() or utils.is_virtual_compute(host):
config.update({
'platform::vswitch::params::iommu_enabled': False,
'platform::vswitch::params::hugepage_dir': '/mnt/huge-2048kB',
'openstack::neutron::params::tunnel_csum': True,
})
return config
def _get_neutron_config(self, host):
local_ip = None
tunnel_types = set()
bridge_mappings = []
for iface in self.context['interfaces'].values():
if interface.is_data_network_type(iface):
# obtain the assigned bridge for interface
brname = iface.get('_ovs_bridge')
if brname:
providernets = interface.get_interface_providernets(iface)
for providernet in providernets:
if self._is_vxlan_providernet(providernet):
address = interface.get_interface_primary_address(
self.context, iface)
if address:
local_ip = address['address']
tunnel_types.add(
constants.NEUTRON_PROVIDERNET_VXLAN)
else:
bridge_mappings.append('%s:%s' %
(providernet, brname))
return {
'neutron::agents::ml2::ovs::local_ip': local_ip,
'neutron::agents::ml2::ovs::tunnel_types': list(tunnel_types),
'neutron::agents::ml2::ovs::bridge_mappings': bridge_mappings
}
def _get_providernet_type(self, name):
if name in self.context['providernets']:
return self.context['providernets'][name]['type']
def _is_vxlan_providernet(self, name):
providernet_type = self._get_providernet_type(name)
return bool(providernet_type == constants.NEUTRON_PROVIDERNET_VXLAN)

View File

@ -89,6 +89,7 @@ class PlatformPuppet(base.BasePuppet):
'platform::params::security_profile': system.security_profile, 'platform::params::security_profile': system.security_profile,
'platform::config::params::timezone': system.timezone, 'platform::config::params::timezone': system.timezone,
'platform::params::vswitch_type': self._vswitch_type(),
} }
def _get_hosts_config(self): def _get_hosts_config(self):
@ -586,12 +587,12 @@ class PlatformPuppet(base.BasePuppet):
total_hugepages_2M = vm_hugepages_nr_2M total_hugepages_2M = vm_hugepages_nr_2M
total_hugepages_1G = vm_hugepages_nr_1G total_hugepages_1G = vm_hugepages_nr_1G
if memory.avs_hugepages_size_mib == constants.MIB_2M: if memory.vswitch_hugepages_size_mib == constants.MIB_2M:
total_hugepages_2M += memory.avs_hugepages_nr total_hugepages_2M += memory.vswitch_hugepages_nr
vswitch_2M_page += memory.avs_hugepages_nr vswitch_2M_page += memory.vswitch_hugepages_nr
elif memory.avs_hugepages_size_mib == constants.MIB_1G: elif memory.vswitch_hugepages_size_mib == constants.MIB_1G:
total_hugepages_1G += memory.avs_hugepages_nr total_hugepages_1G += memory.vswitch_hugepages_nr
vswitch_1G_page += memory.avs_hugepages_nr vswitch_1G_page += memory.vswitch_hugepages_nr
vswitch_2M_pages.append(vswitch_2M_page) vswitch_2M_pages.append(vswitch_2M_page)
vswitch_1G_pages.append(vswitch_1G_page) vswitch_1G_pages.append(vswitch_1G_page)

View File

@ -40,6 +40,7 @@ from . import networking
from . import neutron from . import neutron
from . import nfv from . import nfv
from . import nova from . import nova
from . import ovs
from . import panko from . import panko
from . import patching from . import patching
from . import platform from . import platform
@ -89,6 +90,7 @@ class PuppetOperator(object):
self.neutron = neutron.NeutronPuppet(self) self.neutron = neutron.NeutronPuppet(self)
self.nfv = nfv.NfvPuppet(self) self.nfv = nfv.NfvPuppet(self)
self.nova = nova.NovaPuppet(self) self.nova = nova.NovaPuppet(self)
self.ovs = ovs.OVSPuppet(self)
self.panko = panko.PankoPuppet(self) self.panko = panko.PankoPuppet(self)
self.patching = patching.PatchingPuppet(self) self.patching = patching.PatchingPuppet(self)
self.platform = platform.PlatformPuppet(self) self.platform = platform.PlatformPuppet(self)
@ -215,6 +217,7 @@ class PuppetOperator(object):
config.update(self.panko.get_system_config()) config.update(self.panko.get_system_config())
config.update(self.dcmanager.get_system_config()) config.update(self.dcmanager.get_system_config())
config.update(self.dcorch.get_system_config()) config.update(self.dcorch.get_system_config())
# service_parameter must be last to permit overrides
config.update(self.service_parameter.get_system_config()) config.update(self.service_parameter.get_system_config())
filename = 'system.yaml' filename = 'system.yaml'
@ -274,6 +277,7 @@ class PuppetOperator(object):
config = {} config = {}
config.update(self.platform.get_host_config(host, config_uuid)) config.update(self.platform.get_host_config(host, config_uuid))
config.update(self.interface.get_host_config(host)) config.update(self.interface.get_host_config(host))
config.update(self.ovs.get_host_config(host))
config.update(self.networking.get_host_config(host)) config.update(self.networking.get_host_config(host))
config.update(self.storage.get_host_config(host)) config.update(self.storage.get_host_config(host))
config.update(self.ldap.get_host_config(host)) config.update(self.ldap.get_host_config(host))
@ -283,6 +287,7 @@ class PuppetOperator(object):
config.update(self.device.get_host_config(host)) config.update(self.device.get_host_config(host))
config.update(self.nova.get_host_config(host)) config.update(self.nova.get_host_config(host))
config.update(self.neutron.get_host_config(host)) config.update(self.neutron.get_host_config(host))
# service_parameter must be last to permit overrides
config.update(self.service_parameter.get_host_config(host)) config.update(self.service_parameter.get_host_config(host))
self._write_host_config(host, config) self._write_host_config(host, config)
@ -298,14 +303,16 @@ class PuppetOperator(object):
config = {} config = {}
config.update(self.platform.get_host_config(host, config_uuid)) config.update(self.platform.get_host_config(host, config_uuid))
config.update(self.interface.get_host_config(host)) config.update(self.interface.get_host_config(host))
config.update(self.ovs.get_host_config(host))
config.update(self.networking.get_host_config(host)) config.update(self.networking.get_host_config(host))
config.update(self.storage.get_host_config(host)) config.update(self.storage.get_host_config(host))
config.update(self.ceph.get_host_config(host)) config.update(self.ceph.get_host_config(host))
config.update(self.device.get_host_config(host)) config.update(self.device.get_host_config(host))
config.update(self.nova.get_host_config(host)) config.update(self.nova.get_host_config(host))
config.update(self.neutron.get_host_config(host)) config.update(self.neutron.get_host_config(host))
config.update(self.service_parameter.get_host_config(host))
config.update(self.ldap.get_host_config(host)) config.update(self.ldap.get_host_config(host))
# service_parameter must be last to permit overrides
config.update(self.service_parameter.get_host_config(host))
self._write_host_config(host, config) self._write_host_config(host, config)
except Exception: except Exception:
@ -323,8 +330,9 @@ class PuppetOperator(object):
config.update(self.networking.get_host_config(host)) config.update(self.networking.get_host_config(host))
config.update(self.storage.get_host_config(host)) config.update(self.storage.get_host_config(host))
config.update(self.ceph.get_host_config(host)) config.update(self.ceph.get_host_config(host))
config.update(self.service_parameter.get_host_config(host))
config.update(self.ldap.get_host_config(host)) config.update(self.ldap.get_host_config(host))
# service_parameter must be last to permit overrides
config.update(self.service_parameter.get_host_config(host))
self._write_host_config(host, config) self._write_host_config(host, config)
except Exception: except Exception:

View File

@ -1596,7 +1596,8 @@ class TestCpePost(InterfaceTestCase):
# Expected error: Unexpected interface network type list data # Expected error: Unexpected interface network type list data
@mock.patch.object(api_if_v1, '_neutron_providernet_extension_supported') @mock.patch.object(api_if_v1, '_neutron_providernet_extension_supported')
def test_create_invalid_non_avs(self, mock_providernet_extension_supported): def test_create_invalid_non_vswitch(self,
mock_providernet_extension_supported):
mock_providernet_extension_supported.return_value = False mock_providernet_extension_supported.return_value = False
self._create_ethernet('data0', self._create_ethernet('data0',
networktype=constants.NETWORK_TYPE_DATA, networktype=constants.NETWORK_TYPE_DATA,

View File

@ -179,7 +179,8 @@ def get_test_isystem(**kw):
'capabilities': kw.get('capabilities', 'capabilities': kw.get('capabilities',
{"cinder_backend": {"cinder_backend":
constants.CINDER_BACKEND_LVM, constants.CINDER_BACKEND_LVM,
"vswitch_type": constants.VSWITCH_TYPE_AVS, "vswitch_type":
constants.VSWITCH_TYPE_OVS_DPDK,
"region_config": False, "region_config": False,
"sdn_enabled": True, "sdn_enabled": True,
"shared_services": "[]"}), "shared_services": "[]"}),
@ -367,10 +368,10 @@ def get_test_imemory(**kw):
'hugepages_configured': kw.get('hugepages_configured', False), 'hugepages_configured': kw.get('hugepages_configured', False),
'avs_hugepages_size_mib': kw.get('avs_hugepages_size_mib', 2), 'vswitch_hugepages_size_mib': kw.get('vswitch_hugepages_size_mib', 2),
'avs_hugepages_reqd': kw.get('avs_hugepages_reqd'), 'vswitch_hugepages_reqd': kw.get('vswitch_hugepages_reqd'),
'avs_hugepages_nr': kw.get('avs_hugepages_nr', 256), 'vswitch_hugepages_nr': kw.get('vswitch_hugepages_nr', 256),
'avs_hugepages_avail': kw.get('avs_hugepages_avail', 0), 'vswitch_hugepages_avail': kw.get('vswitch_hugepages_avail', 0),
'vm_hugepages_nr_2M_pending': kw.get('vm_hugepages_nr_2M_pending'), 'vm_hugepages_nr_2M_pending': kw.get('vm_hugepages_nr_2M_pending'),
'vm_hugepages_nr_1G_pending': kw.get('vm_hugepages_nr_1G_pending'), 'vm_hugepages_nr_1G_pending': kw.get('vm_hugepages_nr_1G_pending'),

View File

@ -1,4 +1,4 @@
# Copyright (c) 2017 Wind River Systems, Inc. # Copyright (c) 2017-2018 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -400,7 +400,11 @@ class BaseTestCase(dbbase.DbTestCase):
@puppet.puppet_context @puppet.puppet_context
def _update_context(self): def _update_context(self):
self.context = self.operator.interface._create_interface_context(self.host) self.context = \
self.operator.interface._create_interface_context(self.host)
# Update the puppet context with generated interface context
self.operator.context.update(self.context)
def _setup_context(self): def _setup_context(self):
self._setup_configuration() self._setup_configuration()
@ -1363,166 +1367,6 @@ class InterfaceTestCase(BaseTestCase):
return port, iface return port, iface
class InterfaceVswitchTestCase(BaseTestCase):
def _setup_configuration(self):
# Create a single port/interface for basic function testing
self._create_test_common()
self._create_test_host(constants.COMPUTE)
self.port, self.iface = (
self._create_ethernet_test('data0',
constants.NETWORK_TYPE_DATA))
def _update_context(self):
# ensure DB entries are updated prior to updating the context which
# will re-read the entries from the DB.
self.host.save(self.admin_context)
self.port.save(self.admin_context)
self.iface.save(self.admin_context)
super(InterfaceVswitchTestCase, self)._update_context()
def setUp(self):
super(InterfaceVswitchTestCase, self).setUp()
self._setup_context()
def test_needs_vswitch_config_false_on_controller(self):
self.iface['networktype'] = constants.NETWORK_TYPE_DATA
self.host['personality'] = constants.CONTROLLER
self.host['subfunctions'] = constants.CONTROLLER
self._update_context()
needed = interface.needs_vswitch_config(self.context, self.iface)
self.assertFalse(needed)
def test_needs_vswitch_config_true_on_compute(self):
self.iface['networktype'] = constants.NETWORK_TYPE_DATA
needed = interface.needs_vswitch_config(self.context, self.iface)
self.assertTrue(needed)
def test_needs_vswitch_config_false_for_platform(self):
vlan = self._create_vlan_test('infra0',
constants.NETWORK_TYPE_INFRA, 1)
self.host['personality'] = constants.COMPUTE
self._update_context()
needed = interface.needs_vswitch_config(self.context, vlan)
self.assertFalse(needed)
def test_get_vswitch_ethernet_command(self):
cmd = interface.get_vswitch_ethernet_command(self.context, self.iface)
expected = ("ethernet add %(port_uuid)s %(iface_uuid)s %(mtu)s\n" %
{'port_uuid': self.port['uuid'],
'iface_uuid': self.iface['uuid'],
'mtu': self.iface['imtu']})
self.assertEqual(expected, cmd)
def test_get_vswitch_ethernet_command_slow_data(self):
self.port['dpdksupport'] = False
self._update_context()
cmd = interface.get_vswitch_ethernet_command(self.context, self.iface)
expected = (
"port add avp-provider %(uuid)s %(mac)s 0 %(mtu)s %(ifname)s\n" %
{'uuid': self.iface['uuid'],
'mtu': self.iface['imtu'],
'mac': interface._set_local_admin_bit(self.iface['imac']),
'ifname': self.port['name'] + '-avp'})
self.assertEqual(expected, cmd)
def test_get_vswitch_vlan_command(self):
vlan = self._create_vlan_test(
'data1', constants.NETWORK_TYPE_DATA, 1, self.iface)
self._update_context()
cmd = interface.get_vswitch_vlan_command(self.context, vlan)
expected = ("vlan add %(lower_uuid)s %(vlan_id)s %(uuid)s %(mtu)s\n" %
{'lower_uuid': self.iface['uuid'],
'vlan_id': vlan['vlan_id'],
'uuid': vlan['uuid'],
'mtu': vlan['imtu']})
self.assertEqual(expected, cmd)
def test_get_vswitch_vlan_command_for_platform(self):
vlan = self._create_vlan_test(
'infra', constants.NETWORK_TYPE_INFRA, 1, self.iface)
self._update_context()
cmd = interface.get_vswitch_vlan_command(self.context, vlan)
expected = (
"vlan add %(lower_uuid)s %(vlan_id)s %(uuid)s %(mtu)s host\n" %
{'lower_uuid': self.iface['uuid'],
'vlan_id': vlan['vlan_id'],
'uuid': vlan['uuid'],
'mtu': vlan['imtu']})
self.assertEqual(expected, cmd)
def test_get_vswitch_address_command(self):
address = self.context['addresses'].get(self.iface['ifname'])[0]
cmd = interface.get_vswitch_address_command(self.iface, address)
expected = (
"interface add addr %(iface_uuid)s %(address)s/%(prefix)s\n" %
{'iface_uuid': self.iface['uuid'],
'address': address['address'],
'prefix': address['prefix']})
self.assertEqual(expected, cmd)
def test_get_vswitch_route_command(self):
route = self.context['routes'].get(self.iface['ifname'])[0]
cmd = interface.get_vswitch_route_command(self.iface, route)
expected = (
"route append %(network)s/%(prefix)s %(iface_uuid)s %(gateway)s "
"%(metric)s\n" %
{'iface_uuid': self.iface['uuid'],
'network': route['network'],
'gateway': route['gateway'],
'prefix': route['prefix'],
'metric': route['metric']})
self.assertEqual(expected, cmd)
def test_get_vswitch_bond_options_balanced(self):
bond = self._create_bond_test('data1', constants.NETWORK_TYPE_DATA)
self._update_context()
bond['aemode'] = 'balanced'
options = interface.get_vswitch_bond_options(bond)
expected = {'distribution': 'hash-mac',
'protection': 'loadbalance',
'monitor': 'link-state'}
self.assertEqual(options, expected)
def test_get_vswitch_bond_options_8023ad(self):
bond = self._create_bond_test('data1', constants.NETWORK_TYPE_DATA)
self._update_context()
bond['aemode'] = '802.3ad'
options = interface.get_vswitch_bond_options(bond)
expected = {'distribution': 'hash-mac',
'protection': '802.3ad',
'monitor': 'link-state'}
self.assertEqual(options, expected)
def test_get_vswitch_bond_options_active_backup(self):
bond = self._create_bond_test('data1', constants.NETWORK_TYPE_DATA)
self._update_context()
bond['aemode'] = 'active_backup'
options = interface.get_vswitch_bond_options(bond)
expected = {'distribution': 'none',
'protection': 'failover',
'monitor': 'link-state'}
self.assertEqual(options, expected)
def test_get_vswitch_bond_commands(self):
bond = self._create_bond_test('data1', constants.NETWORK_TYPE_DATA)
self._update_context()
bond['aemode'] = '802.3ad'
options = interface.get_vswitch_bond_options(bond)
attributes = {'uuid': bond['uuid'],
'mtu': bond['imtu']}
attributes.update(options)
for index, lower_ifname in enumerate(bond['uses']):
lower_iface = self.context['interfaces'][lower_ifname]
attributes['member%s_uuid' % index] = lower_iface['uuid']
expected = (
"ae add %(uuid)s %(mtu)s %(protection)s %(distribution)s %(monitor)s\n"
"ae attach member %(uuid)s %(member0_uuid)s\n"
"ae attach member %(uuid)s %(member1_uuid)s\n" %
attributes)
cmds = interface.get_vswitch_bond_commands(self.context, bond)
self.assertEqual(cmds, expected)
class InterfaceHostTestCase(BaseTestCase): class InterfaceHostTestCase(BaseTestCase):
def _setup_configuration(self): def _setup_configuration(self):
# Personality is set to compute to avoid issues due to missing OAM # Personality is set to compute to avoid issues due to missing OAM
@ -1558,27 +1402,13 @@ class InterfaceHostTestCase(BaseTestCase):
class_name = self.__class__.__name__ class_name = self.__class__.__name__
return os.path.join(hiera_directory, class_name) + ".yaml" return os.path.join(hiera_directory, class_name) + ".yaml"
def _create_vswitch_directory(self):
vswitch_path = os.path.join(os.environ['VIRTUAL_ENV'], 'vswitch')
if not os.path.exists(vswitch_path):
os.mkdir(vswitch_path, 0o755)
return vswitch_path
def _get_vswitch_filename(self, vswitch_directory):
class_name = self.__class__.__name__
return os.path.join(vswitch_directory, class_name) + ".cmds"
def test_generate_interface_config(self): def test_generate_interface_config(self):
hieradata_directory = self._create_hieradata_directory() hieradata_directory = self._create_hieradata_directory()
config_filename = self._get_config_filename(hieradata_directory) config_filename = self._get_config_filename(hieradata_directory)
vswitch_directory = self._create_vswitch_directory()
vswitch_filename = self._get_vswitch_filename(vswitch_directory)
with open(config_filename, 'w') as config_file: with open(config_filename, 'w') as config_file:
config = self.operator.interface.get_host_config(self.host) config = self.operator.interface.get_host_config(self.host)
self.assertIsNotNone(config) self.assertIsNotNone(config)
yaml.dump(config, config_file, default_flow_style=False) yaml.dump(config, config_file, default_flow_style=False)
with open(vswitch_filename, 'w') as commands:
commands.write(config['cgcs_vswitch::vswitch_commands'])
def test_create_interface_context(self): def test_create_interface_context(self):
context = self.operator.interface._create_interface_context(self.host) context = self.operator.interface._create_interface_context(self.host)
@ -1612,7 +1442,7 @@ class InterfaceHostTestCase(BaseTestCase):
for iface in self.interfaces: for iface in self.interfaces:
expected = bool(iface['ifname'] in self.expected_data_interfaces) expected = bool(iface['ifname'] in self.expected_data_interfaces)
if interface.is_data_interface(self.context, iface) != expected: if interface.is_data_interface(self.context, iface) != expected:
print("iface %s is %sa vswitch interface" % ( print("iface %s is %sa data interface" % (
iface['ifname'], ('not ' if expected else ''))) iface['ifname'], ('not ' if expected else '')))
self.assertFalse(True) self.assertFalse(True)
@ -1676,19 +1506,6 @@ class InterfaceHostTestCase(BaseTestCase):
iface['ifname'], ('not ' if expected else ''))) iface['ifname'], ('not ' if expected else '')))
self.assertFalse(True) self.assertFalse(True)
def test_needs_vswitch_config(self):
expected_configured = []
if interface.is_compute_subfunction(self.context):
expected_configured += (self.expected_data_interfaces +
self.expected_slow_interfaces)
for iface in self.interfaces:
expected = bool(iface['ifname'] in expected_configured)
actual = interface.needs_vswitch_config(self.context, iface)
if expected != actual:
print("iface %s is %sconfigured" % (
iface['ifname'], ('not ' if expected else '')))
self.assertFalse(True)
class InterfaceControllerEthernet(InterfaceHostTestCase): class InterfaceControllerEthernet(InterfaceHostTestCase):
def _setup_configuration(self): def _setup_configuration(self):

View File

@ -8,7 +8,6 @@ minversion = 1.6
toxworkdir = /tmp/{env:USER}_sysinvtox toxworkdir = /tmp/{env:USER}_sysinvtox
wrsdir = {toxinidir}/../../../../../../../../.. wrsdir = {toxinidir}/../../../../../../../../..
cgcsdir = {toxinidir}/../../../../.. cgcsdir = {toxinidir}/../../../../..
avsdir = {toxinidir}/../../../../../../../../wr-avs/layers/avs
distshare={toxworkdir}/.tox/distshare distshare={toxworkdir}/.tox/distshare
[testenv] [testenv]