From c7638a340ad77bc70591836d02429ced309b7129 Mon Sep 17 00:00:00 2001 From: Sahid Orentino Ferdjaoui Date: Thu, 8 Nov 2018 17:52:01 +0100 Subject: [PATCH] introduce "reserved_huge_pages" option The DEFAULT/reserved_huge_pages option will be required by NFV deployments in order to let Nova compute service knows that some huge pages allocated in the host are used by third-party components like DPDK PMDs. Since juju does not support yet list of strings options that one will be exposed using semicolons in charm. Closes-Bug: 1804169 Change-Id: I7faa3406a6bd27b9d924925ae93d40075eb0aff2 Signed-off-by: Sahid Orentino Ferdjaoui --- config.yaml | 12 +++++++ hooks/nova_compute_context.py | 6 ++++ templates/newton/nova.conf | 6 ++++ templates/ocata/nova.conf | 6 ++++ templates/pike/nova.conf | 6 ++++ unit_tests/test_nova_compute_contexts.py | 41 ++++++++++++++++++++++++ 6 files changed, 77 insertions(+) diff --git a/config.yaml b/config.yaml index 6fb5293a..a045f4c8 100644 --- a/config.yaml +++ b/config.yaml @@ -145,6 +145,18 @@ options: type: string default: 'yes' description: Whether to run nova-api and nova-network on the compute nodes. + reserved-huge-pages: + type: string + default: + description: | + Sets a reserved amont of huge pages per NUMA nodes which are used by + third-party components. Semicolons are used as separator. + . + reserved_huge_pages = node:0,size:2048,count:64;node:1,size:1GB,count:1 + . + The above will consider 64 pages of 2MiB on NUMA node 0 and 1 page of + 1GiB on NUMA node 1 reserved. They will not be used by Nova to map guests + memory. pci-passthrough-whitelist: type: string default: diff --git a/hooks/nova_compute_context.py b/hooks/nova_compute_context.py index d11938a4..66d80ef6 100644 --- a/hooks/nova_compute_context.py +++ b/hooks/nova_compute_context.py @@ -237,6 +237,12 @@ class NovaComputeLibvirtContext(context.OSContextGenerator): else: ctxt['ksm'] = "AUTO" + if config('reserved-huge-pages'): + # To bypass juju limitation with list of strings, we + # consider separate the option's values per semicolons. + ctxt['reserved_huge_pages'] = ( + [o.strip() for o in config('reserved-huge-pages').split(";")]) + if config('pci-passthrough-whitelist'): ctxt['pci_passthrough_whitelist'] = \ config('pci-passthrough-whitelist') diff --git a/templates/newton/nova.conf b/templates/newton/nova.conf index fdd3fbd3..470221b1 100644 --- a/templates/newton/nova.conf +++ b/templates/newton/nova.conf @@ -119,6 +119,12 @@ vcpu_pin_set = {{ vcpu_pin_set }} {% endif -%} reserved_host_memory_mb = {{ reserved_host_memory }} +{% if reserved_huge_pages -%} +{% for value in reserved_huge_pages -%} +reserved_huge_pages = {{ value }} +{% endfor -%} +{% endif -%} + {% if pci_passthrough_whitelist -%} pci_passthrough_whitelist = {{ pci_passthrough_whitelist }} {% endif -%} diff --git a/templates/ocata/nova.conf b/templates/ocata/nova.conf index 592e2027..891e415c 100644 --- a/templates/ocata/nova.conf +++ b/templates/ocata/nova.conf @@ -120,6 +120,12 @@ vcpu_pin_set = {{ vcpu_pin_set }} {% endif -%} reserved_host_memory_mb = {{ reserved_host_memory }} +{% if reserved_huge_pages -%} +{% for value in reserved_huge_pages -%} +reserved_huge_pages = {{ value }} +{% endfor -%} +{% endif -%} + {% if pci_passthrough_whitelist -%} pci_passthrough_whitelist = {{ pci_passthrough_whitelist }} {% endif -%} diff --git a/templates/pike/nova.conf b/templates/pike/nova.conf index a78d3bed..b707d7b3 100644 --- a/templates/pike/nova.conf +++ b/templates/pike/nova.conf @@ -120,6 +120,12 @@ vcpu_pin_set = {{ vcpu_pin_set }} {% endif -%} reserved_host_memory_mb = {{ reserved_host_memory }} +{% if reserved_huge_pages -%} +{% for value in reserved_huge_pages -%} +reserved_huge_pages = {{ value }} +{% endfor -%} +{% endif -%} + {% include "section-zeromq" %} {% if default_availability_zone -%} diff --git a/unit_tests/test_nova_compute_contexts.py b/unit_tests/test_nova_compute_contexts.py index 743e547d..85b41efb 100644 --- a/unit_tests/test_nova_compute_contexts.py +++ b/unit_tests/test_nova_compute_contexts.py @@ -218,6 +218,47 @@ class NovaComputeContextTests(CharmTestCase): 'force_raw_images': True, 'reserved_host_memory': 512}, libvirt()) + def test_libvirt_context_libvirtd_reserved_huge_pages_1(self): + self.lsb_release.return_value = {'DISTRIB_CODENAME': 'yakkety'} + self.os_release.return_value = 'ocata' + self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid}) + self.test_config.set('reserved-huge-pages', 'node:0,size:2048,count:6') + libvirt = context.NovaComputeLibvirtContext() + + self.assertEqual( + {'libvirtd_opts': '', + 'libvirt_user': 'libvirt', + 'arch': platform.machine(), + 'ksm': 'AUTO', + 'kvm_hugepages': 0, + 'listen_tls': 0, + 'host_uuid': self.host_uuid, + 'force_raw_images': True, + 'reserved_host_memory': 512, + 'reserved_huge_pages': ['node:0,size:2048,count:6']}, libvirt()) + + def test_libvirt_context_libvirtd_reserved_huge_pages_2(self): + self.lsb_release.return_value = {'DISTRIB_CODENAME': 'yakkety'} + self.os_release.return_value = 'ocata' + self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid}) + self.test_config.set( + 'reserved-huge-pages', + 'node:0,size:2048,count:6;node:1,size:1G,count:32') + libvirt = context.NovaComputeLibvirtContext() + + self.assertEqual( + {'libvirtd_opts': '', + 'libvirt_user': 'libvirt', + 'arch': platform.machine(), + 'ksm': 'AUTO', + 'kvm_hugepages': 0, + 'listen_tls': 0, + 'host_uuid': self.host_uuid, + 'force_raw_images': True, + 'reserved_host_memory': 512, + 'reserved_huge_pages': ['node:0,size:2048,count:6', + 'node:1,size:1G,count:32']}, libvirt()) + def test_libvirt_bin_context_no_migration(self): self.lsb_release.return_value = {'DISTRIB_CODENAME': 'lucid'} self.kv.return_value = FakeUnitdata(**{'host_uuid': self.host_uuid})