From d4a8e284f69f7e2ab18e98324f701b0e3ca41d0e Mon Sep 17 00:00:00 2001 From: Birol Bilgin Date: Sat, 4 Mar 2023 18:50:46 +0100 Subject: [PATCH] added vmware metadata provider (#3526) cloud-init data from vmware guest info as it described in the link below https://github.com/vmware/cloud-init-vmware-guestinfo Signed-off-by: Birol Bilgin Co-authored-by: Birol Bilgin --- pkg/metadata/main.go | 9 +- pkg/metadata/provider_vmware.go | 137 +++++++ pkg/metadata/provider_vmware_unsupported.go | 27 ++ .../github.com/vmware/vmw-guestinfo/LICENSE | 202 +++++++++++ .../vmware/vmw-guestinfo/bdoor/bdoor.go | 107 ++++++ .../vmware/vmw-guestinfo/bdoor/bdoor_386.go | 48 +++ .../vmware/vmw-guestinfo/bdoor/bdoor_386.s | 86 +++++ .../vmware/vmw-guestinfo/bdoor/bdoor_amd64.go | 48 +++ .../vmware/vmw-guestinfo/bdoor/bdoor_amd64.s | 86 +++++ .../vmware/vmw-guestinfo/bdoor/word.go | 77 ++++ .../vmware/vmw-guestinfo/message/log.go | 61 ++++ .../vmware/vmw-guestinfo/message/message.go | 334 ++++++++++++++++++ .../vmware/vmw-guestinfo/rpcout/rpcout.go | 93 +++++ .../vmware/vmw-guestinfo/rpcvmx/rpcvmx.go | 101 ++++++ .../vmware/vmw-guestinfo/vmcheck/vmcheck.go | 106 ++++++ .../vmw-guestinfo/vmcheck/vmcheck_386.s | 17 + .../vmw-guestinfo/vmcheck/vmcheck_amd64.s | 18 + .../vmw-guestinfo/vmcheck/vmcheck_general.go | 23 ++ .../vmw-guestinfo/vmcheck/vmcheck_linux.go | 22 ++ 19 files changed, 1600 insertions(+), 2 deletions(-) create mode 100644 pkg/metadata/provider_vmware.go create mode 100644 pkg/metadata/provider_vmware_unsupported.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/LICENSE create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.s create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.s create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/word.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/log.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/message.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcout/rpcout.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcvmx/rpcvmx.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_386.s create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_amd64.s create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_general.go create mode 100644 pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_linux.go diff --git a/pkg/metadata/main.go b/pkg/metadata/main.go index 740afd364..a96398dcb 100644 --- a/pkg/metadata/main.go +++ b/pkg/metadata/main.go @@ -77,7 +77,7 @@ func main() { log.SetLevel(log.DebugLevel) } - providers := []string{"aws", "gcp", "hetzner", "openstack", "scaleway", "vultr", "digitalocean", "packet", "metaldata", "cdrom"} + providers := []string{"aws", "gcp", "hetzner", "openstack", "scaleway", "vultr", "digitalocean", "packet", "metaldata", "vmware", "cdrom"} args := flag.Args() if len(args) > 0 { providers = args @@ -102,8 +102,13 @@ func main() { netProviders = append(netProviders, NewDigitalOcean()) case p == "metaldata": netProviders = append(netProviders, NewMetalData()) + case p == "vmware": + vmw := NewVMware() + if vmw != nil { + cdromProviders = append(cdromProviders, vmw) + } case p == "cdrom": - cdromProviders = ListCDROMs() + cdromProviders = append(cdromProviders, ListCDROMs()...) case strings.HasPrefix(p, "file="): fileProviders = append(fileProviders, fileProvider(p[5:])) default: diff --git a/pkg/metadata/provider_vmware.go b/pkg/metadata/provider_vmware.go new file mode 100644 index 000000000..a3384296d --- /dev/null +++ b/pkg/metadata/provider_vmware.go @@ -0,0 +1,137 @@ +//go:build linux && 386 && amd64 + +package main + +import ( + "compress/gzip" + "encoding/base64" + "fmt" + "io/ioutil" + "path" + "strings" + + log "github.com/sirupsen/logrus" + "github.com/vmware/vmw-guestinfo/rpcvmx" + "github.com/vmware/vmw-guestinfo/vmcheck" +) + +const ( + guestMetaData = "guestinfo.metadata" + + guestUserData = "guestinfo.userdata" + + guestVendorData = "guestinfo.vendordata" +) + +// ProviderVMware implements the Provider interface for VMware guestinfo api +type ProviderVMware struct{} + +// NewVMware returns a new VMware Provider +func NewVMware() *ProviderVMware { + return &ProviderVMware{} +} + +// String returns provider name +func (p *ProviderVMware) String() string { + return "VMWARE" +} + +// Probe checks if we are running on VMware and either userdata or metadata is set +func (p *ProviderVMware) Probe() bool { + isVM, err := vmcheck.IsVirtualWorld() + if err != nil || !isVM { + return false + } + + md, merr := vmwareGet(guestMetaData) + ud, uerr := vmwareGet(guestUserData) + + return ((merr == nil) && len(md) > 1 && string(md) != "---") || ((uerr == nil) && len(ud) > 1 && string(ud) != "---") +} + +// Extract gets the host specific metadata, generic userdata and if set vendordata +// This function returns error if it fails to write metadata or vendordata to disk +func (p *ProviderVMware) Extract() ([]byte, error) { + // Get vendor data, if empty do not fail + vendorData, err := vmwareGet(guestVendorData) + if err != nil { + log.Debugf("VMWare: Failed to get vendordata: %v", err) + } else { + err = ioutil.WriteFile(path.Join(ConfigPath, "vendordata"), vendorData, 0644) + if err != nil { + log.Debugf("VMWare: Failed to write vendordata: %v", err) + } + } + + // Get metadata + metaData, err := vmwareGet(guestMetaData) + if err != nil { + log.Printf("VMWare: Failed to get metadata: %v", err) + } else { + err = ioutil.WriteFile(path.Join(ConfigPath, "metadata"), metaData, 0644) + if err != nil { + return nil, fmt.Errorf("VMWare: Failed to write metadata: %s", err) + } + } + + // Get userdata + userData, err := vmwareGet(guestUserData) + if err != nil { + log.Printf("VMware: Failed to get userdata: %v", err) + // This is not an error + return nil, nil + } + + return userData, nil +} + +// vmwareGet gets and extracts the guestinfo data +func vmwareGet(name string) ([]byte, error) { + config := rpcvmx.NewConfig() + + // get the gusest info value + out, err := config.String(name, "") + if err != nil { + log.Debugf("Getting guest info %s failed: error %s", name, err) + return nil, err + } + + enc, err := config.String(name+".encoding", "") + if err != nil { + log.Debugf("Getting guest info %s.encoding failed: error %s", name, err) + return nil, err + } + + switch strings.TrimSuffix(enc, "\n") { + case " ": + return []byte(strings.TrimSuffix(out, "\n")), nil + case "base64": + r := base64.NewDecoder(base64.StdEncoding, strings.NewReader(out)) + + dst, err := ioutil.ReadAll(r) + if err != nil { + log.Debugf("Decoding base64 of '%s' failed %v", name, err) + return nil, err + } + + return dst, nil + case "gzip+base64": + r := base64.NewDecoder(base64.StdEncoding, strings.NewReader(out)) + + zr, err := gzip.NewReader(r) + if err != nil { + log.Debugf("New gzip reader from '%s' failed %v", name, err) + return nil, err + } + + dst, err := ioutil.ReadAll(zr) + if err != nil { + log.Debugf("Read '%s' failed %v", name, err) + return nil, err + } + + return dst, nil + default: + return nil, fmt.Errorf("Unknown encoding %s", string(enc)) + } +} diff --git a/pkg/metadata/provider_vmware_unsupported.go b/pkg/metadata/provider_vmware_unsupported.go new file mode 100644 index 000000000..5c90d4017 --- /dev/null +++ b/pkg/metadata/provider_vmware_unsupported.go @@ -0,0 +1,27 @@ +//go:build !(linux && 386 && amd64) + +package main + +// ProviderVMware implements VMware provider interface for unsupported architectures +type ProviderVMware struct{} + +// NewVMware returns a new VMware Provider +func NewVMware() *ProviderVMware { + return nil +} + +// String implements provider interface +func (p *ProviderVMware) String() string { + return "" +} + +// Probe implements provider interface +func (p *ProviderVMware) Probe() bool { + return false +} + +// Extract implements provider interface +func (p *ProviderVMware) Extract() ([]byte, error) { + // Get vendor data, if empty do not fail + return nil, nil +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/LICENSE b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/LICENSE new file mode 100644 index 000000000..2555a8a1d --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 VMware, Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor.go new file mode 100644 index 000000000..b46c91b8e --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor.go @@ -0,0 +1,107 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate go run asm.go -out bdoor_amd64.s -arch amd64 +//go:generate go run asm.go -out bdoor_386.s -arch 386 + +package bdoor + +const ( + BackdoorPort = uint16(0x5658) + BackdoorHighBWPort = uint16(0x5659) + + CommandGetVersion = uint32(10) + + CommandMessage = uint16(0x1e) + CommandHighBWMessage = uint16(0) + CommandFlagCookie = uint32(0x80000000) +) + +func (p *BackdoorProto) InOut() *BackdoorProto { + p.DX.AsUInt32().Low = BackdoorPort + p.AX.SetValue(BackdoorMagic) + + retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_inout( + p.AX.Value(), + p.BX.Value(), + p.CX.Value(), + p.DX.Value(), + p.SI.Value(), + p.DI.Value(), + p.BP.Value(), + ) + + ret := &BackdoorProto{} + ret.AX.SetValue(retax) + ret.BX.SetValue(retbx) + ret.CX.SetValue(retcx) + ret.DX.SetValue(retdx) + ret.SI.SetValue(retsi) + ret.DI.SetValue(retdi) + ret.BP.SetValue(retbp) + + return ret +} + +func (p *BackdoorProto) HighBandwidthOut() *BackdoorProto { + p.DX.AsUInt32().Low = BackdoorHighBWPort + p.AX.SetValue(BackdoorMagic) + + retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbout( + p.AX.Value(), + p.BX.Value(), + p.CX.Value(), + p.DX.Value(), + p.SI.Value(), + p.DI.Value(), + p.BP.Value(), + ) + + ret := &BackdoorProto{} + ret.AX.SetValue(retax) + ret.BX.SetValue(retbx) + ret.CX.SetValue(retcx) + ret.DX.SetValue(retdx) + ret.SI.SetValue(retsi) + ret.DI.SetValue(retdi) + ret.BP.SetValue(retbp) + + return ret +} + +func (p *BackdoorProto) HighBandwidthIn() *BackdoorProto { + p.DX.AsUInt32().Low = BackdoorHighBWPort + p.AX.SetValue(BackdoorMagic) + + retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbin( + p.AX.Value(), + p.BX.Value(), + p.CX.Value(), + p.DX.Value(), + p.SI.Value(), + p.DI.Value(), + p.BP.Value(), + ) + + ret := &BackdoorProto{} + ret.AX.SetValue(retax) + ret.BX.SetValue(retbx) + ret.CX.SetValue(retcx) + ret.DX.SetValue(retdx) + ret.SI.SetValue(retsi) + ret.DI.SetValue(retdi) + ret.BP.SetValue(retbp) + + return ret +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.go new file mode 100644 index 000000000..ea9a2f259 --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.go @@ -0,0 +1,48 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bdoor + +const ( + BackdoorMagic = uint32(0x564D5868) +) + +type BackdoorProto struct { + // typedef union { + // struct { + // DECLARE_REG_NAMED_STRUCT(ax); + // size_t size; /* Register bx. */ + // DECLARE_REG_NAMED_STRUCT(cx); + // DECLARE_REG_NAMED_STRUCT(dx); + // DECLARE_REG_NAMED_STRUCT(si); + // DECLARE_REG_NAMED_STRUCT(di); + // } in; + // struct { + // DECLARE_REG_NAMED_STRUCT(ax); + // DECLARE_REG_NAMED_STRUCT(bx); + // DECLARE_REG_NAMED_STRUCT(cx); + // DECLARE_REG_NAMED_STRUCT(dx); + // DECLARE_REG_NAMED_STRUCT(si); + // DECLARE_REG_NAMED_STRUCT(di); + // } out; + // } proto; + + AX, BX, CX, DX, SI, DI, BP UInt32 + size uint32 +} + +func bdoor_inout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32) +func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32) +func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32) +func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32) diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.s b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.s new file mode 100644 index 000000000..d75892f0b --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_386.s @@ -0,0 +1,86 @@ +// Code generated by command: go run asm.go -out bdoor_386.s -arch 386. DO NOT EDIT. + +// +build gc + +#include "textflag.h" + +// func bdoor_inout(ax uint32, bx uint32, cx uint32, dx uint32, si uint32, di uint32, bp uint32) (retax uint32, retbx uint32, retcx uint32, retdx uint32, retsi uint32, retdi uint32, retbp uint32) +TEXT ·bdoor_inout(SB), NOSPLIT|WRAPPER, $0-56 + MOVL ax+0(FP), AX + MOVL bx+4(FP), BX + MOVL cx+8(FP), CX + MOVL dx+12(FP), DX + MOVL si+16(FP), SI + MOVL di+20(FP), DI + MOVL bp+24(FP), BP + + // IN to DX from AX + INL + MOVL AX, retax+28(FP) + MOVL BX, retbx+32(FP) + MOVL CX, retcx+36(FP) + MOVL DX, retdx+40(FP) + MOVL SI, retsi+44(FP) + MOVL DI, retdi+48(FP) + MOVL BP, retbp+52(FP) + RET + +// func bdoor_hbout(ax uint32, bx uint32, cx uint32, dx uint32, si uint32, di uint32, bp uint32) (retax uint32, retbx uint32, retcx uint32, retdx uint32, retsi uint32, retdi uint32, retbp uint32) +TEXT ·bdoor_hbout(SB), NOSPLIT|WRAPPER, $0-56 + MOVL ax+0(FP), AX + MOVL bx+4(FP), BX + MOVL cx+8(FP), CX + MOVL dx+12(FP), DX + MOVL si+16(FP), SI + MOVL di+20(FP), DI + MOVL bp+24(FP), BP + CLD + REP + OUTSB + MOVL AX, retax+28(FP) + MOVL BX, retbx+32(FP) + MOVL CX, retcx+36(FP) + MOVL DX, retdx+40(FP) + MOVL SI, retsi+44(FP) + MOVL DI, retdi+48(FP) + MOVL BP, retbp+52(FP) + RET + +// func bdoor_hbin(ax uint32, bx uint32, cx uint32, dx uint32, si uint32, di uint32, bp uint32) (retax uint32, retbx uint32, retcx uint32, retdx uint32, retsi uint32, retdi uint32, retbp uint32) +TEXT ·bdoor_hbin(SB), NOSPLIT|WRAPPER, $0-56 + MOVL ax+0(FP), AX + MOVL bx+4(FP), BX + MOVL cx+8(FP), CX + MOVL dx+12(FP), DX + MOVL si+16(FP), SI + MOVL di+20(FP), DI + MOVL bp+24(FP), BP + CLD + REP + INSB + MOVL AX, retax+28(FP) + MOVL BX, retbx+32(FP) + MOVL CX, retcx+36(FP) + MOVL DX, retdx+40(FP) + MOVL SI, retsi+44(FP) + MOVL DI, retdi+48(FP) + MOVL BP, retbp+52(FP) + RET + +// func bdoor_inout_test(ax uint32, bx uint32, cx uint32, dx uint32, si uint32, di uint32, bp uint32) (retax uint32, retbx uint32, retcx uint32, retdx uint32, retsi uint32, retdi uint32, retbp uint32) +TEXT ·bdoor_inout_test(SB), NOSPLIT|WRAPPER, $0-56 + MOVL ax+0(FP), AX + MOVL bx+4(FP), BX + MOVL cx+8(FP), CX + MOVL dx+12(FP), DX + MOVL si+16(FP), SI + MOVL di+20(FP), DI + MOVL bp+24(FP), BP + MOVL AX, retax+28(FP) + MOVL BX, retbx+32(FP) + MOVL CX, retcx+36(FP) + MOVL DX, retdx+40(FP) + MOVL SI, retsi+44(FP) + MOVL DI, retdi+48(FP) + MOVL BP, retbp+52(FP) + RET diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.go new file mode 100644 index 000000000..0793c699d --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.go @@ -0,0 +1,48 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bdoor + +const ( + BackdoorMagic = uint64(0x564D5868) +) + +type BackdoorProto struct { + // typedef union { + // struct { + // DECLARE_REG_NAMED_STRUCT(ax); + // size_t size; /* Register bx. */ + // DECLARE_REG_NAMED_STRUCT(cx); + // DECLARE_REG_NAMED_STRUCT(dx); + // DECLARE_REG_NAMED_STRUCT(si); + // DECLARE_REG_NAMED_STRUCT(di); + // } in; + // struct { + // DECLARE_REG_NAMED_STRUCT(ax); + // DECLARE_REG_NAMED_STRUCT(bx); + // DECLARE_REG_NAMED_STRUCT(cx); + // DECLARE_REG_NAMED_STRUCT(dx); + // DECLARE_REG_NAMED_STRUCT(si); + // DECLARE_REG_NAMED_STRUCT(di); + // } out; + // } proto; + + AX, BX, CX, DX, SI, DI, BP UInt64 + size uint32 +} + +func bdoor_inout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64) +func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64) +func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64) +func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64) diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.s b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.s new file mode 100644 index 000000000..f35db2735 --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/bdoor_amd64.s @@ -0,0 +1,86 @@ +// Code generated by command: go run asm.go -out bdoor_amd64.s -arch amd64. DO NOT EDIT. + +// +build gc + +#include "textflag.h" + +// func bdoor_inout(ax uint64, bx uint64, cx uint64, dx uint64, si uint64, di uint64, bp uint64) (retax uint64, retbx uint64, retcx uint64, retdx uint64, retsi uint64, retdi uint64, retbp uint64) +TEXT ·bdoor_inout(SB), NOSPLIT|WRAPPER, $0-112 + MOVQ ax+0(FP), AX + MOVQ bx+8(FP), BX + MOVQ cx+16(FP), CX + MOVQ dx+24(FP), DX + MOVQ si+32(FP), SI + MOVQ di+40(FP), DI + MOVQ bp+48(FP), BP + + // IN to DX from AX + INL + MOVQ AX, retax+56(FP) + MOVQ BX, retbx+64(FP) + MOVQ CX, retcx+72(FP) + MOVQ DX, retdx+80(FP) + MOVQ SI, retsi+88(FP) + MOVQ DI, retdi+96(FP) + MOVQ BP, retbp+104(FP) + RET + +// func bdoor_hbout(ax uint64, bx uint64, cx uint64, dx uint64, si uint64, di uint64, bp uint64) (retax uint64, retbx uint64, retcx uint64, retdx uint64, retsi uint64, retdi uint64, retbp uint64) +TEXT ·bdoor_hbout(SB), NOSPLIT|WRAPPER, $0-112 + MOVQ ax+0(FP), AX + MOVQ bx+8(FP), BX + MOVQ cx+16(FP), CX + MOVQ dx+24(FP), DX + MOVQ si+32(FP), SI + MOVQ di+40(FP), DI + MOVQ bp+48(FP), BP + CLD + REP + OUTSB + MOVQ AX, retax+56(FP) + MOVQ BX, retbx+64(FP) + MOVQ CX, retcx+72(FP) + MOVQ DX, retdx+80(FP) + MOVQ SI, retsi+88(FP) + MOVQ DI, retdi+96(FP) + MOVQ BP, retbp+104(FP) + RET + +// func bdoor_hbin(ax uint64, bx uint64, cx uint64, dx uint64, si uint64, di uint64, bp uint64) (retax uint64, retbx uint64, retcx uint64, retdx uint64, retsi uint64, retdi uint64, retbp uint64) +TEXT ·bdoor_hbin(SB), NOSPLIT|WRAPPER, $0-112 + MOVQ ax+0(FP), AX + MOVQ bx+8(FP), BX + MOVQ cx+16(FP), CX + MOVQ dx+24(FP), DX + MOVQ si+32(FP), SI + MOVQ di+40(FP), DI + MOVQ bp+48(FP), BP + CLD + REP + INSB + MOVQ AX, retax+56(FP) + MOVQ BX, retbx+64(FP) + MOVQ CX, retcx+72(FP) + MOVQ DX, retdx+80(FP) + MOVQ SI, retsi+88(FP) + MOVQ DI, retdi+96(FP) + MOVQ BP, retbp+104(FP) + RET + +// func bdoor_inout_test(ax uint64, bx uint64, cx uint64, dx uint64, si uint64, di uint64, bp uint64) (retax uint64, retbx uint64, retcx uint64, retdx uint64, retsi uint64, retdi uint64, retbp uint64) +TEXT ·bdoor_inout_test(SB), NOSPLIT|WRAPPER, $0-112 + MOVQ ax+0(FP), AX + MOVQ bx+8(FP), BX + MOVQ cx+16(FP), CX + MOVQ dx+24(FP), DX + MOVQ si+32(FP), SI + MOVQ di+40(FP), DI + MOVQ bp+48(FP), BP + MOVQ AX, retax+56(FP) + MOVQ BX, retbx+64(FP) + MOVQ CX, retcx+72(FP) + MOVQ DX, retdx+80(FP) + MOVQ SI, retsi+88(FP) + MOVQ DI, retdi+96(FP) + MOVQ BP, retbp+104(FP) + RET diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/word.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/word.go new file mode 100644 index 000000000..ec1ee13ba --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/bdoor/word.go @@ -0,0 +1,77 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bdoor + +import "unsafe" + +type UInt32 struct { + High uint16 + Low uint16 +} + +func (u *UInt32) Word() uint32 { + return uint32(u.High)<<16 + uint32(u.Low) +} + +func (u *UInt32) SetWord(w uint32) { + u.High = uint16(w >> 16) + u.Low = uint16(w) +} + +func (u *UInt32) AsUInt32() *UInt32 { + return u +} + +func (u *UInt32) Value() uint32 { + return u.Word() +} + +func (u *UInt32) SetValue(val uint32) { + u.SetWord(val) +} + +func (u *UInt32) SetPointer(p unsafe.Pointer) { + u.SetWord(uint32(uintptr(p))) +} + +type UInt64 struct { + High UInt32 + Low UInt32 +} + +func (u *UInt64) Quad() uint64 { + return uint64(u.High.Word())<<32 + uint64(u.Low.Word()) +} + +func (u *UInt64) SetQuad(w uint64) { + u.High.SetWord(uint32(w >> 32)) + u.Low.SetWord(uint32(w)) +} + +func (u *UInt64) AsUInt32() *UInt32 { + return &u.Low +} + +func (u *UInt64) Value() uint64 { + return u.Quad() +} + +func (u *UInt64) SetValue(val uint64) { + u.SetQuad(val) +} + +func (u *UInt64) SetPointer(p unsafe.Pointer) { + u.SetQuad(uint64(uintptr(p))) +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/log.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/log.go new file mode 100644 index 000000000..3bb96f2e3 --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/log.go @@ -0,0 +1,61 @@ +// Copyright 2016 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package message + +import "log" + +var DefaultLogger Logger + +type Logger interface { + Errorf(format string, args ...interface{}) + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) +} + +func init() { + DefaultLogger = &logger{} +} + +type logger struct { + DebugLevel bool +} + +func (l *logger) Errorf(format string, args ...interface{}) { + log.Printf(format, args...) +} + +func (l *logger) Debugf(format string, args ...interface{}) { + if !l.DebugLevel { + return + } + + log.Printf(format, args...) +} + +func (l *logger) Infof(format string, args ...interface{}) { + log.Printf(format, args...) +} + +func Errorf(format string, args ...interface{}) { + DefaultLogger.Errorf(format, args...) +} + +func Debugf(format string, args ...interface{}) { + DefaultLogger.Debugf(format, args...) +} + +func Infof(format string, args ...interface{}) { + DefaultLogger.Infof(format, args...) +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/message.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/message.go new file mode 100644 index 000000000..a6261920f --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/message/message.go @@ -0,0 +1,334 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package message + +import ( + "bytes" + "encoding/binary" + "errors" + "unsafe" + + "github.com/vmware/vmw-guestinfo/bdoor" +) + +const ( + messageTypeOpen = iota + messageTypeSendSize + messageTypeSendPayload + messageTypeReceiveSize + messageTypeReceivePayload + messageTypeReceiveStatus + messageTypeClose + + messageStatusFail = uint16(0x0000) + messageStatusSuccess = uint16(0x0001) + messageStatusDoRecieve = uint16(0x0002) + messageStatusCheckPoint = uint16(0x0010) + messageStatusHighBW = uint16(0x0080) +) + +var ( + // ErrChannelOpen represents a failure to open a channel + ErrChannelOpen = errors.New("could not open channel") + // ErrChannelClose represents a failure to close a channel + ErrChannelClose = errors.New("could not close channel") + // ErrRpciSend represents a failure to send a message + ErrRpciSend = errors.New("unable to send RPCI command") + // ErrRpciReceive represents a failure to receive a message + ErrRpciReceive = errors.New("unable to receive RPCI command result") +) + +type Channel struct { + id uint16 + + forceLowBW bool + buf []byte + + cookie bdoor.UInt64 +} + +// NewChannel opens a new Channel +func NewChannel(proto uint32) (*Channel, error) { + flags := bdoor.CommandFlagCookie + +retry: + bp := &bdoor.BackdoorProto{} + + bp.BX.AsUInt32().SetWord(proto | flags) + bp.CX.AsUInt32().High = messageTypeOpen + bp.CX.AsUInt32().Low = bdoor.CommandMessage + + out := bp.InOut() + if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 { + if flags != 0 { + flags = 0 + goto retry + } + + Errorf("Message: Unable to open communication channel") + return nil, ErrChannelOpen + } + + ch := &Channel{} + ch.id = out.DX.AsUInt32().High + ch.cookie.High.SetWord(out.SI.AsUInt32().Word()) + ch.cookie.Low.SetWord(out.DI.AsUInt32().Word()) + + Debugf("Opened channel %d", ch.id) + return ch, nil +} + +func (c *Channel) Close() error { + bp := &bdoor.BackdoorProto{} + + bp.CX.AsUInt32().High = messageTypeClose + bp.CX.AsUInt32().Low = bdoor.CommandMessage + + bp.DX.AsUInt32().High = c.id + bp.SI.AsUInt32().SetWord(c.cookie.High.Word()) + bp.DI.AsUInt32().SetWord(c.cookie.Low.Word()) + + out := bp.InOut() + if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 { + Errorf("Message: Unable to close communication channel %d", c.id) + return ErrChannelClose + } + + Debugf("Closed channel %d", c.id) + return nil +} + +func (c *Channel) Send(buf []byte) error { +retry: + bp := &bdoor.BackdoorProto{} + bp.CX.AsUInt32().High = messageTypeSendSize + bp.CX.AsUInt32().Low = bdoor.CommandMessage + + bp.DX.AsUInt32().High = c.id + bp.SI.AsUInt32().SetWord(c.cookie.High.Word()) + bp.DI.AsUInt32().SetWord(c.cookie.Low.Word()) + + bp.BX.AsUInt32().SetWord(uint32(len(buf))) + + // send the size + out := bp.InOut() + if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 { + Errorf("Message: Unable to send a message over the communication channel %d", c.id) + return ErrRpciSend + } + + // size of buf 0 is fine, just return + if len(buf) == 0 { + return nil + } + + if !c.forceLowBW && (out.CX.AsUInt32().High&messageStatusHighBW) == messageStatusHighBW { + hbbp := &bdoor.BackdoorProto{} + + hbbp.BX.AsUInt32().Low = bdoor.CommandHighBWMessage + hbbp.BX.AsUInt32().High = messageStatusSuccess + hbbp.DX.AsUInt32().High = c.id + hbbp.BP.AsUInt32().SetWord(c.cookie.High.Word()) + hbbp.DI.AsUInt32().SetWord(c.cookie.Low.Word()) + hbbp.CX.AsUInt32().SetWord(uint32(len(buf))) + hbbp.SI.SetPointer(unsafe.Pointer(&buf[0])) + + out := hbbp.HighBandwidthOut() + if (out.BX.AsUInt32().High & messageStatusSuccess) == 0 { + if (out.BX.AsUInt32().High & messageStatusCheckPoint) != 0 { + Debugf("A checkpoint occurred. Retrying the operation") + goto retry + } + + Errorf("Message: Unable to send a message over the communication channel %d", c.id) + return ErrRpciSend + } + } else { + bp.CX.AsUInt32().High = messageTypeSendPayload + + bbuf := bytes.NewBuffer(buf) + for { + // read 4 bytes at a time + words := bbuf.Next(4) + if len(words) == 0 { + break + } + + Debugf("sending %q over %d", string(words), c.id) + switch len(words) { + case 3: + bp.BX.AsUInt32().SetWord(binary.LittleEndian.Uint32([]byte{0x0, words[2], words[1], words[0]})) + case 2: + bp.BX.AsUInt32().SetWord(uint32(binary.LittleEndian.Uint16(words))) + case 1: + bp.BX.AsUInt32().SetWord(uint32(words[0])) + default: + bp.BX.AsUInt32().SetWord(binary.LittleEndian.Uint32(words)) + } + + out = bp.InOut() + if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 { + Errorf("Message: Unable to send a message over the communication channel %d", c.id) + return ErrRpciSend + } + } + } + + return nil +} + +func (c *Channel) Receive() ([]byte, error) { +retry: + var err error + bp := &bdoor.BackdoorProto{} + bp.CX.AsUInt32().High = messageTypeReceiveSize + bp.CX.AsUInt32().Low = bdoor.CommandMessage + + bp.DX.AsUInt32().High = c.id + bp.SI.AsUInt32().SetWord(c.cookie.High.Word()) + bp.DI.AsUInt32().SetWord(c.cookie.Low.Word()) + + out := bp.InOut() + if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 { + Errorf("Message: Unable to poll for messages over the communication channel %d", c.id) + return nil, ErrRpciReceive + } + + if (out.CX.AsUInt32().High & messageStatusDoRecieve) == 0 { + Debugf("No message to retrieve") + return nil, nil + } + + // Receive the size. + if out.DX.AsUInt32().High != messageTypeSendSize { + Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDSIZE request from vmware") + return nil, ErrRpciReceive + } + + size := out.BX.Value() + + var buf []byte + + if size != 0 { + if !c.forceLowBW && (out.CX.AsUInt32().High&messageStatusHighBW == messageStatusHighBW) { + buf = make([]byte, size) + + hbbp := &bdoor.BackdoorProto{} + + hbbp.BX.AsUInt32().Low = bdoor.CommandHighBWMessage + hbbp.BX.AsUInt32().High = messageStatusSuccess + hbbp.DX.AsUInt32().High = c.id + hbbp.SI.AsUInt32().SetWord(c.cookie.High.Word()) + hbbp.BP.AsUInt32().SetWord(c.cookie.Low.Word()) + hbbp.CX.AsUInt32().SetWord(uint32(len(buf))) + hbbp.DI.SetPointer(unsafe.Pointer(&buf[0])) + + out := hbbp.HighBandwidthIn() + if (out.BX.AsUInt32().High & messageStatusSuccess) == 0 { + Errorf("Message: Unable to send a message over the communication channel %d", c.id) + c.reply(messageTypeReceivePayload, messageStatusFail) + return nil, ErrRpciReceive + } + } else { + b := bytes.NewBuffer(make([]byte, 0, size)) + + for { + if size == 0 { + break + } + + bp.CX.AsUInt32().High = messageTypeReceivePayload + bp.BX.AsUInt32().Low = messageStatusSuccess + + out = bp.InOut() + if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 { + if (out.CX.AsUInt32().High & messageStatusCheckPoint) != 0 { + Debugf("A checkpoint occurred. Retrying the operation") + goto retry + } + + Errorf("Message: Unable to receive a message over the communication channel %d", c.id) + c.reply(messageTypeReceivePayload, messageStatusFail) + return nil, ErrRpciReceive + } + + if out.DX.AsUInt32().High != messageTypeSendPayload { + Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDPAYLOAD from vmware") + c.reply(messageTypeReceivePayload, messageStatusFail) + return nil, ErrRpciReceive + } + + Debugf("Received %#v", out.BX.AsUInt32().Word()) + + switch size { + case 1: + err = binary.Write(b, binary.LittleEndian, uint8(out.BX.AsUInt32().Low)) + size = size - 1 + + case 2: + err = binary.Write(b, binary.LittleEndian, uint16(out.BX.AsUInt32().Low)) + size = size - 2 + + case 3: + err = binary.Write(b, binary.LittleEndian, uint16(out.BX.AsUInt32().Low)) + if err != nil { + c.reply(messageTypeReceivePayload, messageStatusFail) + return nil, ErrRpciReceive + } + err = binary.Write(b, binary.LittleEndian, uint8(out.BX.AsUInt32().High)) + size = size - 3 + + default: + err = binary.Write(b, binary.LittleEndian, out.BX.AsUInt32().Word()) + size = size - 4 + } + + if err != nil { + Errorf(err.Error()) + c.reply(messageTypeReceivePayload, messageStatusFail) + return nil, ErrRpciReceive + } + } + + buf = b.Bytes() + } + } + + c.reply(messageTypeReceiveStatus, messageStatusSuccess) + + return buf, nil +} + +func (c *Channel) reply(messageType, messageStatus uint16) { + bp := &bdoor.BackdoorProto{} + + bp.BX.AsUInt32().Low = messageStatus + bp.CX.AsUInt32().High = messageType + bp.CX.AsUInt32().Low = bdoor.CommandMessage + bp.DX.AsUInt32().High = c.id + bp.SI.AsUInt32().SetWord(c.cookie.High.Word()) + bp.DI.AsUInt32().SetWord(c.cookie.Low.Word()) + + out := bp.InOut() + + /* OUT: Status */ + if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 { + if messageStatus == messageStatusSuccess { + Errorf("reply Message: Unable to send a message over the communication channel %d", c.id) + } else { + Errorf("reply Message: Unable to signal an error of reception over the communication channel %d", c.id) + } + } +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcout/rpcout.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcout/rpcout.go new file mode 100644 index 000000000..3b5879b44 --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcout/rpcout.go @@ -0,0 +1,93 @@ +// Copyright 2016 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcout + +import ( + "errors" + "fmt" + + "github.com/vmware/vmw-guestinfo/message" +) + +// ErrRpciFormat represents an invalid result format +var ErrRpciFormat = errors.New("invalid format for RPCI command result") + +const rpciProtocolNum uint32 = 0x49435052 + +// SendOne is a command-oriented wrapper for SendOneRaw +func SendOne(format string, a ...interface{}) (reply []byte, ok bool, err error) { + request := fmt.Sprintf(format, a...) + return SendOneRaw([]byte(request)) +} + +// SendOneRaw uses a throw-away RPCOut to send a request +func SendOneRaw(request []byte) (reply []byte, ok bool, err error) { + out := &RPCOut{} + if err = out.Start(); err != nil { + return + } + if reply, ok, err = out.Send(request); err != nil { + return + } + if err = out.Stop(); err != nil { + return + } + return +} + +// RPCOut is an ougoing connection from the VM to the hypervisor +type RPCOut struct { + channel *message.Channel +} + +// Start opens the connection +func (out *RPCOut) Start() error { + channel, err := message.NewChannel(rpciProtocolNum) + if err != nil { + return err + } + out.channel = channel + return nil +} + +// Stop closes the connection +func (out *RPCOut) Stop() error { + err := out.channel.Close() + out.channel = nil + return err +} + +// Send emits a request and receives a response +func (out *RPCOut) Send(request []byte) (reply []byte, ok bool, err error) { + if err = out.channel.Send(request); err != nil { + return + } + + var resp []byte + if resp, err = out.channel.Receive(); err != nil { + return + } + + switch string(resp[:2]) { + case "0 ": + reply = resp[2:] + case "1 ": + reply = resp[2:] + ok = true + default: + err = ErrRpciFormat + } + return +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcvmx/rpcvmx.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcvmx/rpcvmx.go new file mode 100644 index 000000000..a832ad7fb --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/rpcvmx/rpcvmx.go @@ -0,0 +1,101 @@ +// Copyright 2016 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcvmx + +import ( + "fmt" + "strconv" + "strings" + + "github.com/vmware/vmw-guestinfo/rpcout" +) + +const ( + prefix = "guestinfo" +) + +// Config gives access to the vmx config through the VMware backdoor +type Config struct{} + +// NewConfig creates a new Config object +func NewConfig() *Config { + return &Config{} +} + +// String returns the config string in the guestinfo.* namespace +func (c *Config) String(key string, defaultValue string) (string, error) { + // add "guestinfo." prefix if missing + if !strings.HasPrefix(key, prefix) { + key = fmt.Sprintf("%s.%s", prefix, key) + } + + out, ok, err := rpcout.SendOne("info-get %s", key) + if err != nil { + return "", err + } else if !ok { + return defaultValue, nil + } + return string(out), nil +} + +// Bool returns the config boolean in the guestinfo.* namespace +func (c *Config) Bool(key string, defaultValue bool) (bool, error) { + val, err := c.String(key, fmt.Sprintf("%t", defaultValue)) + if err != nil { + return false, err + } + res, err := strconv.ParseBool(val) + if err != nil { + return defaultValue, nil + } + return res, nil +} + +// Int returns the config integer in the guestinfo.* namespace +func (c *Config) Int(key string, defaultValue int) (int, error) { + val, err := c.String(key, "") + if err != nil { + return 0, err + } + res, err := strconv.Atoi(val) + if err != nil { + return defaultValue, nil + } + return res, nil +} + +// SetString sets the guestinfo.KEY with the string VALUE +func (c *Config) SetString(key string, value string) error { + // add "guestinfo." prefix if missing + if !strings.HasPrefix(key, prefix) { + key = fmt.Sprintf("%s.%s", prefix, key) + } + + _, _, err := rpcout.SendOne("info-set %s %s", key, value) + if err != nil { + return err + } + return nil +} + +// SetString sets the guestinfo.KEY with the bool VALUE +func (c *Config) SetBool(key string, value bool) error { + return c.SetString(key, strconv.FormatBool(value)) +} + +// SetString sets the guestinfo.KEY with the int VALUE +func (c *Config) SetInt(key string, value int) error { + return c.SetString(key, strconv.Itoa(value)) +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck.go new file mode 100644 index 000000000..4f5ed3392 --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck.go @@ -0,0 +1,106 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate go run asm.go -out vmcheck_amd64.s -arch amd64 +//go:generate go run asm.go -out vmcheck_386.s -arch 386 + +package vmcheck + +import ( + "encoding/binary" + + "github.com/vmware/vmw-guestinfo/bdoor" +) + +type platform struct { + cpuid func(uint32, uint32) (uint32, uint32, uint32, uint32) + accessPorts func() error + knock func() (bool, error) +} + +var defaultPlatform = &platform{ + cpuid: cpuid_low, + accessPorts: openPortsAccess, + knock: bdoorKnock, +} + +// From https://github.com/intel-go/cpuid/blob/master/cpuidlow_amd64.s +// Get the CPU ID low level leaf values. +func cpuid_low(arg1, arg2 uint32) (eax, ebx, ecx, edx uint32) + +func bdoorKnock() (bool, error) { + bp := &bdoor.BackdoorProto{} + + bp.CX.AsUInt32().SetWord(bdoor.CommandGetVersion) + out := bp.InOut() + // if there is no device, we get back all 1s + return (0xffffffff != out.AX.AsUInt32().Word()) && (0 != out.AX.AsUInt32().Word()), nil +} + +func (p *platform) isVirtualWorld() (bool, error) { + // Test the HV bit is set + if !p.isVirtualCPU() { + return false, nil + } + + // Test if backdoor port is available. + return p.hypervisorPortCheck() +} + +func (p *platform) isVirtualCPU() bool { + HV := uint32(1 << 31) + _, _, c, _ := p.cpuid(0x1, 0) + if (c & HV) != HV { + return false + } + + _, b, c, d := p.cpuid(0x40000000, 0) + + buf := make([]byte, 12) + binary.LittleEndian.PutUint32(buf, b) + binary.LittleEndian.PutUint32(buf[4:], c) + binary.LittleEndian.PutUint32(buf[8:], d) + + if string(buf) != "VMwareVMware" { + return false + } + + return true +} + +// hypervisorPortCheck tests the availability of the HV port. +func (p *platform) hypervisorPortCheck() (bool, error) { + // Privilege level 3 to access all ports above 0x3ff + if err := p.accessPorts(); err != nil { + return false, err + } + + return p.knock() +} + +// IsVirtualCPU checks if the cpu is a virtual CPU running on ESX. It checks for +// the HV bit in the ECX register of the CPUID leaf 0x1. Intel and AMD CPUs +// reserve this bit to indicate if the CPU is running in a HV. See +// https://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits +// for details. If this bit is set, the reserved cpuid levels are used to pass +// information from the HV to the guest. In ESX, this is the repeating string +// "VMwareVMware". +func IsVirtualCPU() bool { + return defaultPlatform.isVirtualCPU() +} + +// IsVirtualWorld returns true if running in a VM and the backdoor is available. +func IsVirtualWorld() (bool, error) { + return defaultPlatform.isVirtualWorld() +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_386.s b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_386.s new file mode 100644 index 000000000..da5fac57a --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_386.s @@ -0,0 +1,17 @@ +// Code generated by command: go run asm.go -out vmcheck_386.s -arch 386. DO NOT EDIT. +// +build gc + +#include "textflag.h" + +// func cpuid_low(arg1 uint32, arg2 uint32) (eax uint32, ebx uint32, ecx uint32, edx uint32) +// Requires: CPUID +TEXT ·cpuid_low(SB), NOSPLIT, $0-24 + // From https://github.com/intel-go/cpuid/blob/master/cpuidlow_amd64.s + MOVL arg1+0(FP), AX + MOVL arg2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_amd64.s b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_amd64.s new file mode 100644 index 000000000..e05d81a0a --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_amd64.s @@ -0,0 +1,18 @@ +// Code generated by command: go run asm.go -out vmcheck_amd64.s -arch amd64. DO NOT EDIT. + +// +build gc + +#include "textflag.h" + +// func cpuid_low(arg1 uint32, arg2 uint32) (eax uint32, ebx uint32, ecx uint32, edx uint32) +// Requires: CPUID +TEXT ·cpuid_low(SB), NOSPLIT, $0-24 + // From https://github.com/intel-go/cpuid/blob/master/cpuidlow_amd64.s + MOVL arg1+0(FP), AX + MOVL arg2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_general.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_general.go new file mode 100644 index 000000000..1e9217c96 --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_general.go @@ -0,0 +1,23 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !linux + +package vmcheck + +// probably not gonna work. Instead, implement a platform-specific variant, and +// add the platform to above build flags +func openPortsAccess() error { + return nil +} diff --git a/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_linux.go b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_linux.go new file mode 100644 index 000000000..46460f9a0 --- /dev/null +++ b/pkg/metadata/vendor/github.com/vmware/vmw-guestinfo/vmcheck/vmcheck_linux.go @@ -0,0 +1,22 @@ +// Copyright 2016-2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package vmcheck + +import "syscall" + +func openPortsAccess() error { + // Privilege level 3 to access all ports above 0x3ff + return syscall.Iopl(3) +}