diff --git a/configutilities/configutilities/configutilities/common/validator.py b/configutilities/configutilities/configutilities/common/validator.py index a493c12594..1ad174359b 100755 --- a/configutilities/configutilities/configutilities/common/validator.py +++ b/configutilities/configutilities/configutilities/common/validator.py @@ -710,7 +710,7 @@ class ConfigValidator(object): self.vswitch_type = self.conf.get('NETWORK', 'VSWITCH_TYPE').upper() else: - self.vswitch_type = 'AVS' + self.vswitch_type = 'OVS-DPDK' if self.vswitch_type == 'NUAGE_VRS': metadata_proxy_shared_secret = self.conf.get( @@ -755,10 +755,10 @@ class ConfigValidator(object): raise ConfigFail( "The Region Names must be unique.") # 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'): 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.") neutron_group = 'REGION_2_SERVICES' neutron_region_name = region_2_name diff --git a/controllerconfig/controllerconfig/controllerconfig/configassistant.py b/controllerconfig/controllerconfig/controllerconfig/configassistant.py index 1c1d47eb86..839581bbbb 100644 --- a/controllerconfig/controllerconfig/controllerconfig/configassistant.py +++ b/controllerconfig/controllerconfig/controllerconfig/configassistant.py @@ -443,23 +443,7 @@ class ConfigAssistant(): # HTTPS self.enable_https = False # Network config - self.vswitch_type = "avs" - 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 = "" + self.vswitch_type = "ovs-dpdk" # Authentication config self.admin_username = "admin" @@ -2622,48 +2606,6 @@ class ConfigAssistant(): # If any of the network options are missing, use defaults. if config.has_option('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 if config.has_section('cAUTHENTICATION'): @@ -3289,31 +3231,6 @@ class ConfigAssistant(): f.write("\n[cNETWORK]") f.write("\n# Data Network Configuration\n") 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 f.write("\n[cSECURITY]") diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.share.keystoneonly.result b/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.share.keystoneonly.result index 033929a142..9f3b6a48a0 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.share.keystoneonly.result +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.share.keystoneonly.result @@ -54,7 +54,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 [cNETWORK] -VSWITCH_TYPE = avs +VSWITCH_TYPE = ovs-dpdk [cREGION] REGION_CONFIG = True diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.shareall.result b/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.shareall.result index c82af2cd23..8eb0ffe3b7 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.shareall.result +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/TiS_region_config.shareall.result @@ -54,7 +54,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 [cNETWORK] -VSWITCH_TYPE = avs +VSWITCH_TYPE = ovs-dpdk [cREGION] REGION_CONFIG = True diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ceph b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ceph index fca11cf504..6481d1991c 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ceph +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ceph @@ -56,18 +56,7 @@ EXTERNAL_OAM_1_ADDRESS=10.10.10.4 [cNETWORK] # Data Network Configuration -VSWITCH_TYPE=avs -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 +VSWITCH_TYPE=ovs-dpdk [cSECURITY] [cREGION] diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.default b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.default index d9f088f25c..87ff2f9cd4 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.default +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.default @@ -62,18 +62,7 @@ EXTERNAL_OAM_1_ADDRESS=10.10.10.4 [cNETWORK] # Data Network Configuration -VSWITCH_TYPE=avs -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 +VSWITCH_TYPE=ovs-dpdk [cSECURITY] [cREGION] diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ipv6 b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ipv6 index 8884a14b1a..e52aaf774b 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ipv6 +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.ipv6 @@ -62,18 +62,7 @@ EXTERNAL_OAM_1_ADDRESS=abcd::4 [cNETWORK] # Data Network Configuration -VSWITCH_TYPE=avs -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 +VSWITCH_TYPE=ovs-dpdk [cSECURITY] [cREGION] diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.region b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.region index 6634b40b70..9c57b722e5 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.region +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/cgcs_config.region @@ -64,18 +64,7 @@ EXTERNAL_OAM_1_ADDRESS=10.10.10.4 [cNETWORK] # Data Network Configuration -VSWITCH_TYPE=avs -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 +VSWITCH_TYPE=ovs-dpdk [cSECURITY] [cREGION] diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.lag.vlan.result b/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.lag.vlan.result index 828e924edf..1d8f7b406e 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.lag.vlan.result +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.lag.vlan.result @@ -59,7 +59,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 [cNETWORK] -VSWITCH_TYPE = avs +VSWITCH_TYPE = ovs-dpdk [cREGION] REGION_CONFIG = True diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.security.result b/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.security.result index 6d5d8be8df..c50f422d34 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.security.result +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.security.result @@ -37,7 +37,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 [cNETWORK] -VSWITCH_TYPE = avs +VSWITCH_TYPE = ovs-dpdk [cREGION] REGION_CONFIG = True diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.simple.result b/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.simple.result index 6d5d8be8df..c50f422d34 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.simple.result +++ b/controllerconfig/controllerconfig/controllerconfig/tests/files/region_config.simple.result @@ -37,7 +37,7 @@ EXTERNAL_OAM_0_ADDRESS = 10.10.10.3 EXTERNAL_OAM_1_ADDRESS = 10.10.10.4 [cNETWORK] -VSWITCH_TYPE = avs +VSWITCH_TYPE = ovs-dpdk [cREGION] REGION_CONFIG = True diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py b/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py index 867abe9a3a..60ec25c102 100755 --- a/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py +++ b/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py @@ -831,9 +831,9 @@ def test_region_config_validation(): with pytest.raises(exceptions.ConfigFail): 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.set('NETWORK', 'VSWITCH_TYPE', 'AVS') + region_config.set('NETWORK', 'VSWITCH_TYPE', 'ovs-dpdk') with pytest.raises(exceptions.ConfigFail): cr.create_cgcs_config_file(None, region_config, None, None, None, validate_only=True) diff --git a/puppet-manifests/src/hieradata/compute.yaml b/puppet-manifests/src/hieradata/compute.yaml index b704157dc5..5ff5863e21 100644 --- a/puppet-manifests/src/hieradata/compute.yaml +++ b/puppet-manifests/src/hieradata/compute.yaml @@ -1,6 +1,10 @@ # compute specific configuration data --- +# vswitch +vswitch::dpdk::memory_channels: 4 + + # neutron neutron::agents::dhcp::interface_driver: 'openvswitch' 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::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::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_region_name: RegionOne +nova::compute::neutron::libvirt_vif_driver: 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver' + +openstack::nova::compute::compute_monitors: "cpu.virt_driver" + # ceilometer ceilometer::agent::polling::central_namespace: false diff --git a/puppet-manifests/src/hieradata/controller.yaml b/puppet-manifests/src/hieradata/controller.yaml index d9c8b5b634..bf7ad9c2a1 100644 --- a/puppet-manifests/src/hieradata/controller.yaml +++ b/puppet-manifests/src/hieradata/controller.yaml @@ -133,6 +133,10 @@ sysinv::api::keystone_project_domain: 'Default' sysinv::conductor::enabled: false +# nfvi +nfv::nfvi::infrastructure_rest_api_data_port_fault_handling_enabled: false + + # keystone keystone::service::enabled: false keystone::token_provider: 'fernet' @@ -235,12 +239,6 @@ nova_api_proxy::config::eventlet_pool_size: 256 nova::db::sync_api::cellv2_setup: true # 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::database_idle_timeout: 60 diff --git a/puppet-manifests/src/hieradata/global.yaml b/puppet-manifests/src/hieradata/global.yaml index 403720fd19..9bdd4fee37 100644 --- a/puppet-manifests/src/hieradata/global.yaml +++ b/puppet-manifests/src/hieradata/global.yaml @@ -35,12 +35,12 @@ neutron::logging::log_dir: false neutron::logging::verbose: false neutron::logging::debug: false -neutron::core_plugin: 'ml2' +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::pnet_audit_enabled: false neutron::verbose: false neutron::root_helper: 'sudo' diff --git a/puppet-manifests/src/modules/openstack/manifests/neutron.pp b/puppet-manifests/src/modules/openstack/manifests/neutron.pp index 0e94dffdf8..db8f698989 100644 --- a/puppet-manifests/src/modules/openstack/manifests/neutron.pp +++ b/puppet-manifests/src/modules/openstack/manifests/neutron.pp @@ -4,9 +4,9 @@ class openstack::neutron::params ( $region_name = undef, $service_name = 'openstack-neutron', $bgp_router_id = undef, - $l3_agent_enabled = true, $service_create = false, - $configure_endpoint = true + $configure_endpoint = true, + $tunnel_csum = undef, ) { } class openstack::neutron @@ -20,7 +20,6 @@ class openstack::neutron class { '::neutron': rabbit_use_ssl => $::platform::amqp::params::ssl_enabled, 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 ( - $sfc_drivers = undef, - $flowclassifier_drivers = undef, + $sfc_drivers = 'ovs', + $flowclassifier_drivers = 'ovs', $sfc_quota_flow_classifier = undef, $sfc_quota_port_chain = undef, $sfc_quota_port_pair_group = undef, @@ -197,9 +196,6 @@ class openstack::neutron::agents if str2bool($::disable_compute_services) { $pmon_ensure = absent - class {'::neutron::agents::vswitch': - service_ensure => stopped, - } class {'::neutron::agents::l3': enabled => false } @@ -212,6 +208,9 @@ class openstack::neutron::agents class {'::neutron::agents::ml2::sriov': enabled => false } + class {'::neutron::agents::ml2::ovs': + enabled => false + } } else { $pmon_ensure = link @@ -219,12 +218,21 @@ class openstack::neutron::agents metadata_workers => $::platform::params::eng_workers_by_4 } - class { '::neutron::agents::l3': - enabled => $l3_agent_enabled, - } - include ::neutron::agents::dhcp + include ::neutron::agents::l3 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": diff --git a/puppet-manifests/src/modules/openstack/manifests/nova.pp b/puppet-manifests/src/modules/openstack/manifests/nova.pp index 9e5d4c3ba4..925c527528 100644 --- a/puppet-manifests/src/modules/openstack/manifests/nova.pp +++ b/puppet-manifests/src/modules/openstack/manifests/nova.pp @@ -136,6 +136,7 @@ class openstack::nova::compute ( $migration_key_type, $pci_pt_whitelist = [], $pci_sriov_whitelist = undef, + $compute_monitors, $iscsi_initiator_name = undef, ) inherits ::openstack::nova::params { include ::nova::pci @@ -145,6 +146,7 @@ class openstack::nova::compute ( include ::platform::network::infra::params include ::nova::keystone::auth include ::nova::keystone::authtoken + include ::nova::compute::neutron include ::openstack::nova::sshd @@ -268,8 +270,6 @@ class openstack::nova::compute ( $libvirt_images_type = "default" } - $compute_monitors = "cpu.virt_driver" - class { '::nova::compute::libvirt': libvirt_virt_type => $libvirt_virt_type, vncserver_listen => $libvirt_vnc_bind_host, @@ -336,11 +336,6 @@ class openstack::nova::compute ( 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. # 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. diff --git a/puppet-manifests/src/modules/platform/manifests/config.pp b/puppet-manifests/src/modules/platform/manifests/config.pp index a813b0df1f..52dacd6154 100644 --- a/puppet-manifests/src/modules/platform/manifests/config.pp +++ b/puppet-manifests/src/modules/platform/manifests/config.pp @@ -72,10 +72,12 @@ class platform::config::file { } } - file_line { "${platform_conf} vswitch_type": - path => $platform_conf, - line => "vswitch_type=${::platform::params::vswitch_type}", - match => '^vswitch_type=', + if $::platform::params::vswitch_type { + file_line { "${platform_conf} vswitch_type": + path => $platform_conf, + line => "vswitch_type=${::platform::params::vswitch_type}", + match => '^vswitch_type=', + } } if $::platform::params::system_type { diff --git a/puppet-manifests/src/modules/platform/manifests/ntp.pp b/puppet-manifests/src/modules/platform/manifests/ntp.pp index 26db63485a..90e1dbbfd3 100644 --- a/puppet-manifests/src/modules/platform/manifests/ntp.pp +++ b/puppet-manifests/src/modules/platform/manifests/ntp.pp @@ -29,8 +29,8 @@ class platform::ntp ( onlyif => "grep -q '^server' /etc/ntp.conf", } - exec { 'systemd-daemon-reload': - command => '/usr/bin/systemctl daemon-reload', + exec { 'ntpdate-systemd-daemon-reload': + command => '/usr/bin/systemctl daemon-reload', } exec { 'stop-ntpdate': @@ -57,7 +57,7 @@ class platform::ntp ( File['ntpdate_tis_override'] -> Exec['enable-ntpdate'] -> Exec['enable-ntpd'] -> - Exec['systemd-daemon-reload'] -> + Exec['ntpdate-systemd-daemon-reload'] -> Exec['stop-ntpdate'] -> Exec['stop-ntpd'] -> Exec['start-ntpdate'] -> diff --git a/puppet-manifests/src/modules/platform/manifests/vswitch.pp b/puppet-manifests/src/modules/platform/manifests/vswitch.pp index 79e502f316..48ab13dbac 100644 --- a/puppet-manifests/src/modules/platform/manifests/vswitch.pp +++ b/puppet-manifests/src/modules/platform/manifests/vswitch.pp @@ -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'] + 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 { - include ::platform::params - - if $::platform::params::sdn_enabled { - $pmon_ensure = 'link' - $service_ensure = 'running' - } else { - $pmon_ensure = 'absent' - $service_ensure = 'stopped' +define platform::vswitch::ovs::device( + $pci_addr, + $driver_type, +) { + exec { "ovs-bind-device: $title": + path => ["/usr/bin", "/usr/sbin", "/usr/share/openvswitch/scripts"], + command => "dpdk-devbind.py --bind=${driver_type} ${pci_addr}" } - - # ensure pmon soft link - file { "/etc/pmon.d/ovsdb-server.conf": - ensure => $pmon_ensure, - target => "/etc/openvswitch/ovsdb-server.pmon.conf", - owner => 'root', - group => 'root', - mode => '0755', - } - - # service management (start ovsdb-server) - service { "openvswitch": - ensure => $service_ensure, - enable => $::platform::params::sdn_enabled, - } - +} + + +define platform::vswitch::ovs::bridge( + $datapath_type = 'netdev', +) { + exec { "ovs-add-br: ${title}": + command => template("platform/ovs.add-bridge.erb") + } -> + exec { "ovs-link-up: ${title}": + command => "ip link set ${name} up", + } +} + + +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'] + }) } diff --git a/puppet-manifests/src/modules/platform/templates/ovs.add-bridge.erb b/puppet-manifests/src/modules/platform/templates/ovs.add-bridge.erb new file mode 100644 index 0000000000..59fdc07af0 --- /dev/null +++ b/puppet-manifests/src/modules/platform/templates/ovs.add-bridge.erb @@ -0,0 +1,2 @@ +ovs-vsctl --timeout 10 -- --may-exist add-br <%= @name -%> + -- set bridge <%= @name -%> datapath_type=<%= @datapath_type -%> diff --git a/puppet-manifests/src/modules/platform/templates/ovs.add-port.erb b/puppet-manifests/src/modules/platform/templates/ovs.add-port.erb new file mode 100644 index 0000000000..80d66de163 --- /dev/null +++ b/puppet-manifests/src/modules/platform/templates/ovs.add-port.erb @@ -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 -%> diff --git a/puppet-manifests/src/modules/platform/templates/ovs.clean.erb b/puppet-manifests/src/modules/platform/templates/ovs.clean.erb new file mode 100644 index 0000000000..5ec03ba2ad --- /dev/null +++ b/puppet-manifests/src/modules/platform/templates/ovs.clean.erb @@ -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 diff --git a/puppet-manifests/src/modules/platform/templates/ovsdb.clean.erb b/puppet-manifests/src/modules/platform/templates/ovsdb.clean.erb new file mode 100644 index 0000000000..600a21c605 --- /dev/null +++ b/puppet-manifests/src/modules/platform/templates/ovsdb.clean.erb @@ -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 diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory.py index 7869a23a4c..80ada455ac 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory.py @@ -12,8 +12,8 @@ from cgtsclient import exc CREATION_ATTRIBUTES = ['ihost_uuid', 'memtotal_mib', 'memavail_mib', 'platform_reserved_mib', 'hugepages_configured', - 'avs_hugepages_size_mib', 'avs_hugepages_reqd', - 'avs_hugepages_nr', 'avs_hugepages_avail', + 'vswitch_hugepages_size_mib', 'vswitch_hugepages_reqd', + 'vswitch_hugepages_nr', 'vswitch_hugepages_avail', 'vm_hugepages_nr_2M_pending', 'vm_hugepages_nr_1G_pending', 'vm_hugepages_nr_2M', 'vm_hugepages_avail_2M', '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', 'capabilities', 'numa_node', 'minimum_platform_reserved_mib'] + class imemory(base.Resource): def __repr__(self): return "" % self._info diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory_shell.py index 5907e9adc4..640f3fe563 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory_shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory_shell.py @@ -12,17 +12,17 @@ from cgtsclient.common import utils from cgtsclient import exc -from collections import OrderedDict from cgtsclient.v1 import ihost as ihost_utils + def _print_imemory_show(imemory): fields = ['memtotal_mib', 'platform_reserved_mib', 'memavail_mib', 'hugepages_configured', - 'avs_hugepages_size_mib', - 'avs_hugepages_nr', - 'avs_hugepages_avail', + 'vswitch_hugepages_size_mib', + 'vswitch_hugepages_nr', + 'vswitch_hugepages_avail', 'vm_hugepages_nr_4K', 'vm_hugepages_nr_2M', 'vm_hugepages_nr_2M_pending', @@ -36,9 +36,9 @@ def _print_imemory_show(imemory): ' Platform (MiB)', ' Available (MiB)', 'Huge Pages Configured', - 'AVS Huge Pages: Size (MiB)', - ' Total', - ' Available', + 'vSwitch Huge Pages: Size (MiB)', + ' Total', + ' Available', 'VM Pages (4K): Total', 'VM Huge Pages (2M): Total', ' Total Pending', @@ -110,9 +110,9 @@ def do_host_memory_list(cc, args): 'platform_reserved_mib', 'memavail_mib', 'hugepages_configured', - 'avs_hugepages_size_mib', - 'avs_hugepages_nr', - 'avs_hugepages_avail', + 'vswitch_hugepages_size_mib', + 'vswitch_hugepages_nr', + 'vswitch_hugepages_avail', 'vm_hugepages_nr_4K', 'vm_hugepages_nr_2M', 'vm_hugepages_avail_2M', @@ -123,21 +123,21 @@ def do_host_memory_list(cc, args): 'vm_hugepages_use_1G'] field_labels = ['processor', - 'mem_total(MiB)', - 'mem_platform(MiB)', - 'mem_avail(MiB)', - 'hugepages(hp)_configured', - 'avs_hp_size(MiB)', - 'avs_hp_total', - 'avs_hp_avail', - 'vm_total_4K', - 'vm_hp_total_2M', - 'vm_hp_avail_2M', - 'vm_hp_pending_2M', - 'vm_hp_total_1G', - 'vm_hp_avail_1G', - 'vm_hp_pending_1G', - 'vm_hp_use_1G'] + 'mem_total(MiB)', + 'mem_platform(MiB)', + 'mem_avail(MiB)', + 'hugepages(hp)_configured', + 'vs_hp_size(MiB)', + 'vs_hp_total', + 'vs_hp_avail', + 'vm_total_4K', + 'vm_hp_total_2M', + 'vm_hp_avail_2M', + 'vm_hp_pending_2M', + 'vm_hp_total_1G', + 'vm_hp_avail_1G', + 'vm_hp_pending_1G', + 'vm_hp_use_1G'] utils.print_list(imemorys, fields, field_labels, sortby=1) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/isystem_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/isystem_shell.py index f5aad3d083..c50c6b4aac 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/isystem_shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/isystem_shell.py @@ -41,7 +41,12 @@ def _print_isystem_show(isystem): fields.append('distributed_cloud_role') setattr(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])) utils.print_dict(data) @@ -78,7 +83,10 @@ def do_show(cc, args): metavar='', choices=['true', 'false'], help='The HTTPS enabled or disabled flag') - +@utils.arg('-v', '--vswitch_type', + metavar='', + choices=['ovs-dpdk'], + help='The vswitch type for the system') def do_modify(cc, args): """Modify system attributes.""" @@ -126,7 +134,7 @@ def do_modify(cc, args): print 'Please follow the admin guide to complete the reconfiguration.' 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 user_fields = dict((k, v) for (k, v) in vars(args).items() diff --git a/sysinv/sysinv/centos/sysinv.spec b/sysinv/sysinv/centos/sysinv.spec index c19d740ade..c163c5321e 100644 --- a/sysinv/sysinv/centos/sysinv.spec +++ b/sysinv/sysinv/centos/sysinv.spec @@ -74,9 +74,8 @@ install -m 644 -p -D scripts/sysinv-conductor.service %{buildroot}%{_unitdir}/sy install -d -m 755 %{buildroot}%{local_bindir} 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/query_pci_id %{buildroot}%{local_bindir}/query_pci_id %clean echo "CLEAN CALLED" diff --git a/sysinv/sysinv/sysinv/sysinv/agent/node.py b/sysinv/sysinv/sysinv/sysinv/agent/node.py index 543665efbf..19561ba23f 100644 --- a/sysinv/sysinv/sysinv/sysinv/agent/node.py +++ b/sysinv/sysinv/sysinv/sysinv/agent/node.py @@ -29,11 +29,10 @@ import tsconfig.tsconfig as tsc LOG = logging.getLogger(__name__) -# Defines per-socket AVS memory requirements (in MB) for both real and virtual -# deployments -# -AVS_REAL_MEMORY_MB = 1024 -AVS_VBOX_MEMORY_MB = 512 +# Defines per-socket vswitch memory requirements (in MB) for both real and +# virtual deployments +VSWITCH_REAL_MEMORY_MB = 1024 +VSWITCH_VIRTUAL_MEMORY_MB = 512 class CPU: @@ -286,32 +285,32 @@ class NodeOperator(object): return [name for name in listdir(dir) if os.path.isdir(join(dir, name))] - def _set_default_avs_hugesize(self): - ''' - Set the default memory size for avs hugepages when it must fallback to - 2MB pages because there are no 1GB pages. In a virtual environment we - set a smaller amount of memory because AVS is configured to use a - smaller mbuf pool. In non-virtual environments we use the same amount - of memory as we would if 1GB pages were available. - ''' + def _set_default_vswitch_hugesize(self): + """ + Set the default memory size for vswitch hugepages when it must fallback + to 2MB pages because there are no 1GB pages. In a virtual environment + we set a smaller amount of memory because vswitch is configured to use + a smaller mbuf pool. In non-virtual environments we use the same + amount of memory as we would if 1GB pages were available. + """ hugepage_size = 2 if utils.is_virtual(): - avs_hugepages_nr = AVS_VBOX_MEMORY_MB / hugepage_size + vswitch_hugepages_nr = VSWITCH_VIRTUAL_MEMORY_MB / hugepage_size 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 - hp_attr = {'avs_hugepages_size_mib': hugepage_size, - 'avs_hugepages_nr': avs_hugepages_nr, - 'avs_hugepages_avail': 0} + hp_attr = {'vswitch_hugepages_size_mib': hugepage_size, + 'vswitch_hugepages_nr': vswitch_hugepages_nr, + 'vswitch_hugepages_avail': 0} return hp_attr 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. :param self :returns list of memory nodes and attributes - ''' + """ imemory = [] Ki = 1024 @@ -339,7 +338,7 @@ class NodeOperator(object): Total_HP_MiB = 0 # Total memory (MiB) currently configured in HPs Free_HP_MiB = 0 - # Check AVS and Libvirt memory + # Check vswitch and libvirt memory # Loop through configured hugepage sizes of this node and record # total number and number free hugepages = "/sys/devices/system/node/node%d/hugepages" % node @@ -352,7 +351,7 @@ class NodeOperator(object): sizesplit = subdir.split('-') # role via size; also from /etc/nova/compute_reserved.conf if sizesplit[1].startswith("1048576kB"): - hugepages_role = "avs" + hugepages_role = "vswitch" size = int(SZ_1G_Ki / Ki) else: hugepages_role = "vm" @@ -377,27 +376,27 @@ class NodeOperator(object): # Libvirt hugepages can now be 1G and 2M, can't only look # at 2M pages - if hugepages_role == "avs": - avs_hugepages_nr = AVS_REAL_MEMORY_MB / size + if hugepages_role == "vswitch": + vswitch_hugepages_nr = VSWITCH_REAL_MEMORY_MB / size hp_attr = { - 'avs_hugepages_size_mib': size, - 'avs_hugepages_nr': avs_hugepages_nr, - 'avs_hugepages_avail': 0, + 'vswitch_hugepages_size_mib': size, + 'vswitch_hugepages_nr': vswitch_hugepages_nr, + 'vswitch_hugepages_avail': 0, 'vm_hugepages_nr_1G': - (nr_hugepages - avs_hugepages_nr), + (nr_hugepages - vswitch_hugepages_nr), 'vm_hugepages_avail_1G': free_hugepages, 'vm_hugepages_use_1G': 'True' } else: 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'}) - avs_hugepages_nr = hp_attr.get('avs_hugepages_nr', 0) + vswitch_hugepages_nr = hp_attr.get('vswitch_hugepages_nr', 0) hp_attr.update({ 'vm_hugepages_avail_2M': free_hugepages, 'vm_hugepages_nr_2M': - (nr_hugepages - avs_hugepages_nr) + (nr_hugepages - vswitch_hugepages_nr) }) attr.update(hp_attr) @@ -503,8 +502,8 @@ class NodeOperator(object): Eng_KiB = node_total_kib - base_mem_MiB * Ki - vswitch_mem_kib = (attr.get('avs_hugepages_size_mib', 0) * - attr.get('avs_hugepages_nr', 0) * Ki) + vswitch_mem_kib = (attr.get('vswitch_hugepages_size_mib', 0) * + attr.get('vswitch_hugepages_nr', 0) * Ki) VM_KiB = (Eng_KiB - vswitch_mem_kib) diff --git a/sysinv/sysinv/sysinv/sysinv/agent/pci.py b/sysinv/sysinv/sysinv/sysinv/agent/pci.py index 8a5b9238f5..1f3b48741a 100644 --- a/sysinv/sysinv/sysinv/sysinv/agent/pci.py +++ b/sysinv/sysinv/sysinv/sysinv/agent/pci.py @@ -463,19 +463,13 @@ class PCIOperator(object): try: with open(os.devnull, "w") as fnull: - """ - query_pci_id is from dpdk (avs/cgcs-dpdk/files/query_pci_id). - DPDK is removed as part of AVS. - Need add it back later. Then enable this code again. - """ - LOG.error("******ERROR: unable to determine DPDK support or not due to lack DPDK package.******") - # subprocess.check_call(["query_pci_id", "-v " + str(vendor), - # "-d " + str(device)], - # stdout=fnull, stderr=fnull) - # dpdksupport = True - # LOG.debug("DPDK does support NIC " - # "(vendor: %s device: %s)", - # vendor, device) + subprocess.check_call(["query_pci_id", "-v " + str(vendor), + "-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: dpdksupport = False if e.returncode == '1': diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ethernet_port.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ethernet_port.py index 5745ddec18..8ac1c86aab 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ethernet_port.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ethernet_port.py @@ -141,7 +141,7 @@ class EthernetPort(base.APIBase): "Represent whether the port is a boot port" dpdksupport = bool - "Represent whether or not the port supported AVS acceleration" + "Represent whether or not the port supports DPDK acceleration" host_uuid = types.uuid "Represent the UUID of the host the port belongs to" diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py index 3974962354..cc7907b7f9 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py @@ -3143,10 +3143,6 @@ class HostController(rest.RestController): Perform semantic checks against data interfaces to ensure validity of the node configuration prior to unlocking it. """ - vswitch_type = utils.get_vswitch_type() - if vswitch_type != constants.VSWITCH_TYPE_AVS: - return - ihost_iinterfaces = ( pecan.request.dbapi.iinterface_get_by_ihost(ihost['uuid'])) 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 endpoints. """ - vswitch_type = utils.get_vswitch_type() - if vswitch_type != constants.VSWITCH_TYPE_AVS: - return - sdn_enabled = utils.get_sdn_enabled() if not sdn_enabled: return @@ -3431,7 +3423,7 @@ class HostController(rest.RestController): memtotal = m.node_memtotal_mib allocated = m.platform_reserved_mib 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: allocated += constants.MIB_2M * m.vm_hugepages_nr_2M_pending pending_2M_memory = True @@ -3499,7 +3491,7 @@ class HostController(rest.RestController): vm_hugepages_4K = \ (m.node_memtotal_mib - m.platform_reserved_mib) vm_hugepages_4K -= \ - (m.avs_hugepages_nr * m.avs_hugepages_size_mib) + (m.vswitch_hugepages_nr * m.vswitch_hugepages_size_mib) vm_hugepages_4K -= \ (constants.MIB_2M * vm_hugepages_nr_2M) vm_hugepages_4K -= \ diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py index dee6c04e23..accad777e9 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py @@ -878,8 +878,6 @@ def _valid_network_types(): vswitch_type = utils.get_vswitch_type() 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: valid_types -= set([constants.NETWORK_TYPE_DATA_VRS]) 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_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'] 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 we are running against a vanilla openstack installation. """ - return bool(utils.get_vswitch_type() == constants.VSWITCH_TYPE_AVS) - ## TODO: Rather than key off of the vswitch type this should be looking at - ## the neutron extension list, but because our config file is not setup - ## properly to have a different region on a per service basis we cannot. - ## The code should like something like this: - ## - ## extensions = pecan.request.rpcapi.neutron_extension_list( - ## pecan.request.context) - ## return bool(constants.NEUTRON_HOST_ALIAS in extensions) + return True + # TODO: This should be looking at the neutron extension list, but because + # our config file is not setup properly to have a different region on a per + # service basis we cannot. + # + # The code should like something like this: + # + # extensions = pecan.request.rpcapi.neutron_extension_list( + # pecan.request.context) + # return bool(constants.NEUTRON_HOST_ALIAS in extensions) 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 we are running against a vanilla openstack installation. """ - return bool(utils.get_vswitch_type() == constants.VSWITCH_TYPE_AVS) - ## TODO: Rather than key off of the vswitch type this should be looking at - ## the neutron extension list, but because our config file is not setup - ## properly to have a different region on a per service basis we cannot. - ## The code should like something like this: - ## - ## extensions = pecan.request.rpcapi.neutron_extension_list( - ## pecan.request.context) - ## return bool(constants.NEUTRON_WRS_PROVIDER_ALIAS in extensions) + return True + # TODO: This should be looking at the neutron extension list, but because + # our config file is not setup properly to have a different region on a per + # service basis we cannot. + # + # The code should like something like this: + # + # extensions = pecan.request.rpcapi.neutron_extension_list( + # pecan.request.context) + # return bool(constants.NEUTRON_WRS_PROVIDER_ALIAS in extensions) def _neutron_providernet_list(): diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py index 721a37ab8f..585d063758 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py @@ -94,17 +94,17 @@ class Memory(base.APIBase): hugepages_configured = wtypes.text "Represent whether huge pages are configured" - avs_hugepages_size_mib = int - "Represent the imemory avs huge pages size in MiB" + vswitch_hugepages_size_mib = int + "Represent the imemory vswitch huge pages size in MiB" - avs_hugepages_reqd = int - "Represent the imemory avs required number of hugepages" + vswitch_hugepages_reqd = int + "Represent the imemory vswitch required number of hugepages" - avs_hugepages_nr = int - "Represent the imemory avs number of hugepages" + vswitch_hugepages_nr = int + "Represent the imemory vswitch number of hugepages" - avs_hugepages_avail = int - "Represent the imemory avs number of hugepages available" + vswitch_hugepages_avail = int + "Represent the imemory vswitch number of hugepages available" vm_hugepages_nr_2M_pending = int "Represent the imemory vm number of hugepages pending (2M pages)" @@ -182,9 +182,9 @@ class Memory(base.APIBase): if not expand: memory.unset_fields_except(['uuid', 'memtotal_mib', 'memavail_mib', 'platform_reserved_mib', 'hugepages_configured', - 'avs_hugepages_size_mib', 'avs_hugepages_nr', - 'avs_hugepages_reqd', - 'avs_hugepages_avail', + 'vswitch_hugepages_size_mib', 'vswitch_hugepages_nr', + 'vswitch_hugepages_reqd', + 'vswitch_hugepages_avail', 'vm_hugepages_nr_2M', 'vm_hugepages_nr_1G', 'vm_hugepages_use_1G', '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 LOG.debug("vm total=%s" % (mem_alloc)) - avs_hp_size = rpc_port['avs_hugepages_size_mib'] - avs_hp_nr = rpc_port['avs_hugepages_nr'] - mem_alloc += avs_hp_size * avs_hp_nr - LOG.debug("avs_hp_nr=%s avs_hp_size=%s" % (avs_hp_nr, avs_hp_size)) + vs_hp_size = rpc_port['vswitch_hugepages_size_mib'] + vs_hp_nr = rpc_port['vswitch_hugepages_nr'] + mem_alloc += vs_hp_size * vs_hp_nr + 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)) # Initial configuration defaults mem_alloc to consume 100% of 2M pages, diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/port.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/port.py index a59f70a992..c76db7a6ef 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/port.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/port.py @@ -117,7 +117,7 @@ class Port(base.APIBase): "Represent the interface_id the port belongs to" dpdksupport = bool - "Represent whether or not the port supported AVS acceleration" + "Represent whether or not the port supports DPDK acceleration" host_uuid = types.uuid "Represent the UUID of the host the port belongs to" diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py index b7762949ea..22bbc11b0f 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py @@ -48,6 +48,8 @@ from sysinv.openstack.common.gettextutils import _ LOG = log.getLogger(__name__) +VALID_VSWITCH_TYPES = [constants.VSWITCH_TYPE_OVS_DPDK] + class System(base.APIBase): """API representation of a system. @@ -353,6 +355,8 @@ class SystemController(rest.RestController): change_https = False change_sdn = False change_dc_role = False + vswitch_type = None + # prevent description field from being updated for p in jsonpatch.JsonPatch(patch): if p['path'] == '/software_version': @@ -412,6 +416,10 @@ class SystemController(rest.RestController): distributed_cloud_role = p['value'] patch.remove(p) + if p['path'] == '/vswitch_type': + vswitch_type = p['value'] + patch.remove(p) + try: patched_system = jsonpatch.apply_patch(system_dict, jsonpatch.JsonPatch(patch)) @@ -454,6 +462,15 @@ class SystemController(rest.RestController): raise wsme.exc.ClientSideError(_("distributed_cloud_role is already set " " 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 name = "" contact = "" @@ -502,12 +519,16 @@ class SystemController(rest.RestController): pecan.request.context) if capabilities: 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) 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.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: LOG.info("update distributed cloud role to %s" % distributed_cloud_role) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py index 78c9119305..346f357e82 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py @@ -248,17 +248,9 @@ def is_aio_simplex_host_unlocked(host): 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(): - global _vswitch_type - if _vswitch_type is None: - system = pecan.request.dbapi.isystem_get_one() - _vswitch_type = system.capabilities.get('vswitch_type') - return _vswitch_type + system = pecan.request.dbapi.isystem_get_one() + return system.capabilities.get('vswitch_type') def get_https_enabled(): diff --git a/sysinv/sysinv/sysinv/sysinv/cmd/query_pci_id b/sysinv/sysinv/sysinv/sysinv/cmd/query_pci_id new file mode 100755 index 0000000000..a86d6c5bc0 --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/cmd/query_pci_id @@ -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) diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 2c749e6265..ecedf8d163 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -244,7 +244,7 @@ NEUTRON_PROVIDERNET_VXLAN = "vxlan" NEUTRON_PROVIDERNET_VLAN = "vlan" # Supported compute node vswitch types -VSWITCH_TYPE_AVS = "avs" +VSWITCH_TYPE_OVS_DPDK = "ovs-dpdk" VSWITCH_TYPE_NUAGE_VRS = "nuage_vrs" # Partition default sizes diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index 6cf3a8b3c4..07701d02b6 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -1744,7 +1744,7 @@ class ConductorManager(service.PeriodicService): mtu = constants.DEFAULT_MTU port = None # 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']: continue try: @@ -6645,11 +6645,6 @@ class ConductorManager(service.PeriodicService): # Apply Neutron manifest on Controller(this # 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) config_uuid = self._config_update_hosts(context, @@ -6679,6 +6674,30 @@ class ConductorManager(service.PeriodicService): personalities = [constants.COMPUTE] 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): """Update or add an entry to the /etc/hosts configuration file diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py b/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py index 454af0d022..6a6e0101a7 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py @@ -1226,6 +1226,14 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy): return self.call(context, 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, username, password): """Synchronously, have a conductor configure a ks(keyring) account. diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/068_memory_column_rename.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/068_memory_column_rename.py new file mode 100644 index 0000000000..b5d2228656 --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/068_memory_column_rename.py @@ -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.') diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py index 406b92668e..d768cdb58b 100755 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py @@ -293,10 +293,10 @@ class imemory(Base): hugepages_configured = Column(Boolean, default=False) - avs_hugepages_size_mib = Column(Integer) - avs_hugepages_reqd = Column(Integer) - avs_hugepages_nr = Column(Integer) - avs_hugepages_avail = Column(Integer) + vswitch_hugepages_size_mib = Column(Integer) + vswitch_hugepages_reqd = Column(Integer) + vswitch_hugepages_nr = Column(Integer) + vswitch_hugepages_avail = Column(Integer) vm_hugepages_nr_2M_pending = Column(Integer) vm_hugepages_nr_1G_pending = Column(Integer) diff --git a/sysinv/sysinv/sysinv/sysinv/objects/memory.py b/sysinv/sysinv/sysinv/sysinv/objects/memory.py index 5958c019ac..d446680871 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/memory.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/memory.py @@ -34,10 +34,10 @@ class Memory(base.SysinvObject): 'hugepages_configured': utils.str_or_none, - 'avs_hugepages_size_mib': utils.int_or_none, - 'avs_hugepages_reqd': utils.int_or_none, - 'avs_hugepages_nr': utils.int_or_none, - 'avs_hugepages_avail': utils.int_or_none, + 'vswitch_hugepages_size_mib': utils.int_or_none, + 'vswitch_hugepages_reqd': utils.int_or_none, + 'vswitch_hugepages_nr': utils.int_or_none, + 'vswitch_hugepages_avail': utils.int_or_none, 'vm_hugepages_nr_2M_pending': utils.int_or_none, 'vm_hugepages_nr_1G_pending': utils.int_or_none, diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/__init__.py b/sysinv/sysinv/sysinv/sysinv/puppet/__init__.py index e69de29bb2..7653b2c8ef 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/__init__.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/__init__.py @@ -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) diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/base.py b/sysinv/sysinv/sysinv/sysinv/puppet/base.py index 173cdf2b0d..9865316769 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/base.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/base.py @@ -16,6 +16,8 @@ from sysinv.common import constants from sysinv.common import utils from sysinv.common import exception +from . import quoted_str + @six.add_metaclass(abc.ABCMeta) class BasePuppet(object): @@ -45,6 +47,10 @@ class BasePuppet(object): def context(self): return self._operator.context + @staticmethod + def quoted_str(value): + return quoted_str(value) + @staticmethod def _generate_random_password(length=16): suffix = "Ti0*" @@ -79,6 +85,13 @@ class BasePuppet(object): system = self._get_system() 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): if self.dbapi is None: return None @@ -160,6 +173,14 @@ class BasePuppet(object): cpus.append(c) 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): service_parameters = [] if self.dbapi is None: diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py index 17e3d3edc4..a97c317bba 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py @@ -12,18 +12,16 @@ import uuid from netaddr import IPAddress from netaddr import IPNetwork -from netaddr import EUI -from netaddr import mac_unix - from sysinv.common import constants from sysinv.common import exception from sysinv.common import utils +from sysinv.conductor import openstack from sysinv.openstack.common import log + from . import base LOG = log.getLogger(__name__) -MAC_ADDRESS_UL_BIT_VALUE = 2 PLATFORM_NETWORK_TYPES = [constants.NETWORK_TYPE_PXEBOOT, constants.NETWORK_TYPE_MGMT, @@ -59,6 +57,16 @@ ADDRESS_CONFIG_RESOURCE = 'platform::addresses::address_config' class InterfacePuppet(base.BasePuppet): """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): """ 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(), 'gateways': self._get_gateway_index(), 'floatingips': self._get_floating_ip_index(), - 'providernets': {}, + 'providernets': self._get_provider_networks(host), } return context @@ -306,6 +314,18 @@ class InterfacePuppet(base.BasePuppet): 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): networktype = utils.get_primary_network_type(iface) @@ -733,7 +753,7 @@ def needs_interface_config(context, iface): if is_a_mellanox_device(context, iface): # Check for Mellanox data interfaces. We must set the MTU sizes of # 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 # 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 @@ -744,21 +764,6 @@ def needs_interface_config(context, iface): 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', method='manual', onboot='true', 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): """ Lookup an interface based on networktype. This is only intended for diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/neutron.py b/sysinv/sysinv/sysinv/sysinv/puppet/neutron.py index 99ed1546cd..61303939b9 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/neutron.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/neutron.py @@ -65,8 +65,6 @@ class NeutronPuppet(openstack.OpenstackBasePuppet): ksuser = self._get_service_user_name(self.SERVICE_NAME) - sdn_l3_mode_enabled = self._get_sdn_l3_mode_enabled() - config = { 'neutron::server::notifications::auth_url': self._keystone_identity_uri(), @@ -85,8 +83,6 @@ class NeutronPuppet(openstack.OpenstackBasePuppet): 'neutron::agents::metadata::metadata_ip': self._get_management_address(), - 'neutron::agents::vswitch::sdn_manage_external_networks': - not sdn_l3_mode_enabled, 'neutron::keystone::authtoken::auth_url': self._keystone_identity_uri(), @@ -113,8 +109,6 @@ class NeutronPuppet(openstack.OpenstackBasePuppet): 'openstack::neutron::params::region_name': self.get_region_name(), - 'openstack::neutron::params::l3_agent_enabled': - not sdn_l3_mode_enabled, 'openstack::neutron::params::service_create': self._to_create_services(), } @@ -163,33 +157,19 @@ class NeutronPuppet(openstack.OpenstackBasePuppet): 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): - interface_mappings = [] + device_mappings = [] for iface in self.context['interfaces'].values(): if (utils.get_primary_network_type(iface) == constants.NETWORK_TYPE_PCI_SRIOV): port = interface.get_interface_port(self.context, iface) providernets = interface.get_interface_providernets(iface) for net in providernets: - interface_mappings.append("%s:%s" % (net, port['name'])) + device_mappings.append("%s:%s" % (net, port['name'])) config = { 'neutron::agents::ml2::sriov::physical_device_mappings': - interface_mappings, + device_mappings, } if host.personality == constants.CONTROLLER: diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/nfv.py b/sysinv/sysinv/sysinv/sysinv/puppet/nfv.py index 20d76ff376..f5fa3652e5 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/nfv.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/nfv.py @@ -26,11 +26,9 @@ class NfvPuppet(openstack.OpenstackBasePuppet): system = self._get_system() if system.system_mode == constants.SYSTEM_MODE_SIMPLEX: - data_port_fault_handling_enabled = False single_hypervisor = True single_controller = True else: - data_port_fault_handling_enabled = True single_hypervisor = False single_controller = False @@ -52,8 +50,6 @@ class NfvPuppet(openstack.OpenstackBasePuppet): self._get_management_address(), 'nfv::nfvi::host_listener_host': self._get_management_address(), - 'nfv::nfvi::infrastructure_rest_api_data_port_fault_handling_enabled': - data_port_fault_handling_enabled, 'nfv::nfvi::openstack_username': self._operator.keystone.get_admin_user_name(), diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/ovs.py b/sysinv/sysinv/sysinv/sysinv/puppet/ovs.py new file mode 100644 index 0000000000..842a15504c --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/puppet/ovs.py @@ -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) diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/platform.py b/sysinv/sysinv/sysinv/sysinv/puppet/platform.py index 66eb924a62..a3f57eaa8f 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/platform.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/platform.py @@ -89,6 +89,7 @@ class PlatformPuppet(base.BasePuppet): 'platform::params::security_profile': system.security_profile, 'platform::config::params::timezone': system.timezone, + 'platform::params::vswitch_type': self._vswitch_type(), } def _get_hosts_config(self): @@ -586,12 +587,12 @@ class PlatformPuppet(base.BasePuppet): total_hugepages_2M = vm_hugepages_nr_2M total_hugepages_1G = vm_hugepages_nr_1G - if memory.avs_hugepages_size_mib == constants.MIB_2M: - total_hugepages_2M += memory.avs_hugepages_nr - vswitch_2M_page += memory.avs_hugepages_nr - elif memory.avs_hugepages_size_mib == constants.MIB_1G: - total_hugepages_1G += memory.avs_hugepages_nr - vswitch_1G_page += memory.avs_hugepages_nr + if memory.vswitch_hugepages_size_mib == constants.MIB_2M: + total_hugepages_2M += memory.vswitch_hugepages_nr + vswitch_2M_page += memory.vswitch_hugepages_nr + elif memory.vswitch_hugepages_size_mib == constants.MIB_1G: + total_hugepages_1G += memory.vswitch_hugepages_nr + vswitch_1G_page += memory.vswitch_hugepages_nr vswitch_2M_pages.append(vswitch_2M_page) vswitch_1G_pages.append(vswitch_1G_page) diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/puppet.py b/sysinv/sysinv/sysinv/sysinv/puppet/puppet.py index 94e9367f9f..fe5a5deabc 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/puppet.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/puppet.py @@ -40,6 +40,7 @@ from . import networking from . import neutron from . import nfv from . import nova +from . import ovs from . import panko from . import patching from . import platform @@ -89,6 +90,7 @@ class PuppetOperator(object): self.neutron = neutron.NeutronPuppet(self) self.nfv = nfv.NfvPuppet(self) self.nova = nova.NovaPuppet(self) + self.ovs = ovs.OVSPuppet(self) self.panko = panko.PankoPuppet(self) self.patching = patching.PatchingPuppet(self) self.platform = platform.PlatformPuppet(self) @@ -215,6 +217,7 @@ class PuppetOperator(object): config.update(self.panko.get_system_config()) config.update(self.dcmanager.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()) filename = 'system.yaml' @@ -274,6 +277,7 @@ class PuppetOperator(object): config = {} config.update(self.platform.get_host_config(host, config_uuid)) 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.storage.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.nova.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)) self._write_host_config(host, config) @@ -298,14 +303,16 @@ class PuppetOperator(object): config = {} config.update(self.platform.get_host_config(host, config_uuid)) 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.storage.get_host_config(host)) config.update(self.ceph.get_host_config(host)) config.update(self.device.get_host_config(host)) config.update(self.nova.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)) + # service_parameter must be last to permit overrides + config.update(self.service_parameter.get_host_config(host)) self._write_host_config(host, config) except Exception: @@ -323,8 +330,9 @@ class PuppetOperator(object): config.update(self.networking.get_host_config(host)) config.update(self.storage.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)) + # service_parameter must be last to permit overrides + config.update(self.service_parameter.get_host_config(host)) self._write_host_config(host, config) except Exception: diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_interface.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_interface.py index 2611824ef2..aa93c37242 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_interface.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_interface.py @@ -1596,7 +1596,8 @@ class TestCpePost(InterfaceTestCase): # Expected error: Unexpected interface network type list data @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 self._create_ethernet('data0', networktype=constants.NETWORK_TYPE_DATA, diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py index dae01d9ca3..7e24e6ed04 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/utils.py @@ -179,7 +179,8 @@ def get_test_isystem(**kw): 'capabilities': kw.get('capabilities', {"cinder_backend": constants.CINDER_BACKEND_LVM, - "vswitch_type": constants.VSWITCH_TYPE_AVS, + "vswitch_type": + constants.VSWITCH_TYPE_OVS_DPDK, "region_config": False, "sdn_enabled": True, "shared_services": "[]"}), @@ -367,10 +368,10 @@ def get_test_imemory(**kw): 'hugepages_configured': kw.get('hugepages_configured', False), - 'avs_hugepages_size_mib': kw.get('avs_hugepages_size_mib', 2), - 'avs_hugepages_reqd': kw.get('avs_hugepages_reqd'), - 'avs_hugepages_nr': kw.get('avs_hugepages_nr', 256), - 'avs_hugepages_avail': kw.get('avs_hugepages_avail', 0), + 'vswitch_hugepages_size_mib': kw.get('vswitch_hugepages_size_mib', 2), + 'vswitch_hugepages_reqd': kw.get('vswitch_hugepages_reqd'), + 'vswitch_hugepages_nr': kw.get('vswitch_hugepages_nr', 256), + 'vswitch_hugepages_avail': kw.get('vswitch_hugepages_avail', 0), 'vm_hugepages_nr_2M_pending': kw.get('vm_hugepages_nr_2M_pending'), 'vm_hugepages_nr_1G_pending': kw.get('vm_hugepages_nr_1G_pending'), diff --git a/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py b/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py index a99c133411..5e84646b8f 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py @@ -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 # @@ -400,7 +400,11 @@ class BaseTestCase(dbbase.DbTestCase): @puppet.puppet_context 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): self._setup_configuration() @@ -1363,166 +1367,6 @@ class InterfaceTestCase(BaseTestCase): 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): def _setup_configuration(self): # Personality is set to compute to avoid issues due to missing OAM @@ -1558,27 +1402,13 @@ class InterfaceHostTestCase(BaseTestCase): class_name = self.__class__.__name__ 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): hieradata_directory = self._create_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: config = self.operator.interface.get_host_config(self.host) self.assertIsNotNone(config) 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): context = self.operator.interface._create_interface_context(self.host) @@ -1612,7 +1442,7 @@ class InterfaceHostTestCase(BaseTestCase): for iface in self.interfaces: expected = bool(iface['ifname'] in self.expected_data_interfaces) 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 ''))) self.assertFalse(True) @@ -1676,19 +1506,6 @@ class InterfaceHostTestCase(BaseTestCase): iface['ifname'], ('not ' if expected else ''))) 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): def _setup_configuration(self): diff --git a/sysinv/sysinv/sysinv/tox.ini b/sysinv/sysinv/sysinv/tox.ini index 2b61fb9292..cf8e3482a4 100644 --- a/sysinv/sysinv/sysinv/tox.ini +++ b/sysinv/sysinv/sysinv/tox.ini @@ -8,7 +8,6 @@ minversion = 1.6 toxworkdir = /tmp/{env:USER}_sysinvtox wrsdir = {toxinidir}/../../../../../../../../.. cgcsdir = {toxinidir}/../../../../.. -avsdir = {toxinidir}/../../../../../../../../wr-avs/layers/avs distshare={toxworkdir}/.tox/distshare [testenv]