From db29bd6f87972e84c6383b3a77c96724875129e6 Mon Sep 17 00:00:00 2001 From: Piotr Skamruk Date: Tue, 19 Jun 2018 16:38:08 +0200 Subject: [PATCH] PoC for huge pages in libvirt domain definition There is no verification if host supports huge pages. There is no verification of any kind of libvirt/qemu configuration if it's needed for huge pages. There is no validation of nodeset value at the moment. Simply if there is VirtletHugePages annotation its value is used to construct data in memoryBacking section of libvirt domain xml (according to https://libvirt.org/formatdomain.html#elementsMemoryBacking) Whole value is split to sub entries using ";" as separator. Each entry should have 3 values, * size - as a uint * unit - single character denoting unit size (K, M, or G) * nodeset - node ranges (e.g. 0-3), or/and particular node numbers of numa nodes, combined with comma sign (please refer to libvirt docs for details - this part is passed "as is" to domain definition). --- pkg/libvirttools/virtualization.go | 13 ++++++++++ pkg/metadata/types/annotations.go | 40 +++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/pkg/libvirttools/virtualization.go b/pkg/libvirttools/virtualization.go index 2bf265c88..0bbb8b010 100644 --- a/pkg/libvirttools/virtualization.go +++ b/pkg/libvirttools/virtualization.go @@ -164,6 +164,19 @@ func (ds *domainSettings) createDomain(config *types.VMConfig) *libvirtxml.Domai }, } + if len(config.ParsedAnnotations.HugePagesSettings) > 0 { + domain.MemoryBacking = &libvirtxml.DomainMemoryBacking{ + MemoryHugePages: &libvirtxml.DomainMemoryHugepages{}, + } + for _, el := range config.ParsedAnnotations.HugePagesSettings { + domain.MemoryBacking.MemoryHugePages.Hugepages = append(domain.MemoryBacking.MemoryHugePages.Hugepages, libvirtxml.DomainMemoryHugepage{ + Size: el.Size, + Unit: el.Unit, + Nodeset: el.NodeSet, + }) + } + } + if ds.enableSriov { domain.QEMUCommandline.Envs = append(domain.QEMUCommandline.Envs, libvirtxml.DomainQEMUCommandlineEnv{Name: "VMWRAPPER_KEEP_PRIVS", Value: "1"}) diff --git a/pkg/metadata/types/annotations.go b/pkg/metadata/types/annotations.go index 6f3417c84..bf20f101f 100644 --- a/pkg/metadata/types/annotations.go +++ b/pkg/metadata/types/annotations.go @@ -35,6 +35,7 @@ const ( cloudInitUserDataKeyName = "VirtletCloudInitUserData" cloudInitUserDataScriptKeyName = "VirtletCloudInitUserDataScript" cloudInitImageType = "VirtletCloudInitImageType" + hugePagesSetupKeyName = "VirtletHugePages" sshKeysKeyName = "VirtletSSHKeys" // CloudInitUserDataSourceKeyName is the name of user data source key in the pod annotations. CloudInitUserDataSourceKeyName = "VirtletCloudInitUserDataSource" @@ -62,6 +63,12 @@ const ( DiskDriverScsi DiskDriverName = "scsi" ) +type HugePagesEntry struct { + Size uint + Unit string + NodeSet string +} + // VirtletAnnotations contains parsed values for pod annotations supported // by Virtlet. type VirtletAnnotations struct { @@ -80,7 +87,8 @@ type VirtletAnnotations struct { // SSHKets specifies ssh public keys to use. SSHKeys []string // DiskDriver specifies the disk driver to use. - DiskDriver DiskDriverName + DiskDriver DiskDriverName + HugePagesSettings []HugePagesEntry } // ExternalDataLoader is a function that loads external data that's specified @@ -197,5 +205,35 @@ func (va *VirtletAnnotations) parsePodAnnotations(ns string, podAnnotations map[ va.CDImageType = CloudInitImageType(strings.ToLower(podAnnotations[cloudInitImageType])) va.DiskDriver = DiskDriverName(podAnnotations[diskDriverKeyName]) + if hpEntryStr, found := podAnnotations[hugePagesSetupKeyName]; found { + for _, el := range strings.Split(hpEntryStr, ";") { + entry := strings.Split(el, " ") + if len(entry) != 3 { + return fmt.Errorf("huge pages entry expected to have 3 fields has incorrect number of them: %v", entry) + } + + size := 0 + var err error + if size, err = strconv.Atoi(entry[0]); err != nil { + return fmt.Errorf("huge pages entry has %q as size while expected int: %v", entry[0], err) + } + + switch entry[1] { + case "K": + case "M": + case "G": + default: + return fmt.Errorf("huge pages entry have %q as unit while expected 'K', 'M', or 'G'", entry[1]) + } + + // TODO: nodeset validation (string contains only digits, minus sign or comma character) + va.HugePagesSettings = append(va.HugePagesSettings, HugePagesEntry{ + Size: uint(size), + Unit: entry[1], + NodeSet: entry[2], + }) + } + } + return nil }