Hyper-V Key-Value Pair Data Exchange Part 3: Linux

Hyper-V Key-Value Pair Data Exchange Part 3: Linux

Some time ago, I discovered uses for Hyper-V Key-Value Pair Data Exchange services and began exploiting them on my Windows guests. Now that I’ve started building Linux guests, I need similar functionality. This article covers the differences in the Linux implementation and includes version 1.0 of a program that allows you to receive, send, and delete KVPs.

For a primer on Hyper-V KVP Exchange, start with this article: Hyper-V Key-Value Pair Data Exchange Part 1: Explanation.

The second part of that series presented PowerShell scripts for interacting with Hyper-V KVP Exchange from both the host and the guest sides. The guest script won’t be as useful in the context of Linux. Even if you install PowerShell on Linux, the script won’t work because it reads and writes registry keys. It might still spark some implementation ideas, I suppose.

What is Hyper-V Key-Value Pair Data Exchange?

To save you a few clicks and other reading, I’ll give a quick summary of Hyper-V KVP Exchange.

Virtual machines are intended to be “walled gardens”. The host and guest should have limited ability to interact with each other. That distance sometimes causes inconvenience, but the stronger the separation, the stronger the security. Hyper-V’s KVP Exchange provides one method for moving data across the wall without introducing a crippling security hazard. Either “side” (host or guest) can “send” a message at any time. The other side can receive it — or ignore it. Essentially, they pass notes by leaving them stuck in slots in the “wall” of the “walled garden”.

KVP stands for “key-value pair”. Each of these messages consists of one text key and one text value. The value can be completely empty.

How is Hyper-V KVP Exchange Different on Linux?

On Windows guests, a service runs (Hyper-V Data Exchange Service) that monitors the “wall”. When the host leaves a message, this service copies the information into the guest’s Windows registry. To send a message to the host, you (or an application) create or modify a KVP within a different key in the Windows registry. The service then places that “note” in the “wall” where the host can pick it up. More details can be found in the first article in this series.

Linux runs a daemon that is the analog to the Windows service. It has slightly different names on different platforms, but I’ve been able to locate it on all of my distributions with sudo service --status-all | grep kvp. It may not always be running; more on that in a bit.

Linux doesn’t have a native analog to the Windows registry. Instead, the daemon maintains a set of files. It receives inbound messages from the host and places them in particular files that you can read (or ignore). You can write to one of the files. The daemon will transfer those messages up to the host.

On Windows, I’m not entirely certain of any special limits on KVP sizes. A registry key can be 16,384 characters and there is no hard-coded limit on value size. I have not tested how KVP Exchange handles these extents on Windows. However, the Linux daemon has much tighter constraints. A key can be no longer than 512 bytes. A value can be no longer than 2,048 bytes.

The keys are case sensitive on the host and on Linux guests. So, key “LinuxKey” is not the same as key “linuxkey”. Windows guests just get confused by that, but Linux handles it easily.

How does Hyper-V KVP Exchange Function on Linux?

As with Windows guests, Data Exchange must be enabled on the virtual machine’s properties:

Hyper-V KVP Exchange on Linux

The daemon must also be installed and running within the guest. Currently-supported versions of the Linux kernel contain the Hyper-V KVP framework natively, so several distributions ship with it enabled. As mentioned in the previous section, the exact name of the daemon varies. You should be able to find it with: sudo service --status-all | grep kvp. If it’s not installed, check your distribution’s instruction page on TechNet.

All of the files that the daemon uses for Hyper-V KVP exchange can be found in the /var/lib/hyperv folder. They are hidden, but you can view them with ls‘s -a parameter:

Hyper-V KVP exchange

Anyone can read any of these files. Only the root account has write permissions, but that can be misleading. Writing to any of the files that are intended to carry data from the host to the guest has no real effect. The daemon is always monitoring them and only it can carry information from the host side.

What is the Purpose of Each Hyper-V KVP Exchange File?

Each of the files is used for a different purpose.

  • .kvp_pool_0: When an administrative user or an application in the host sends data to the guest, the daemon writes the message to this file. It is the equivalent of HKLMSOFTWAREMicrosoftVirtual MachineExternal on Windows guests. From the host side, the related commands are ModifyKvpItems, AddKvpItems, and RemoveKvpItems. The guest can read this file. Changing it has no useful effect.
  • .kvp_pool_1: The root account can write to this file from within the guest. It is the equivalent of HKLMSOFTWAREMicrosoftVirtual MachineGuest on Windows guests. The daemon will transfer messages up to the host. From the host side, its messages can be retrieved from the GuestExchangeItems field of the WMI object.
  • .kvp_pool_2: The daemon will automatically write information about the Linux guest into this file. However, you never see any of the information from the guest side. The host can retrieve it through the GuestIntrinsicExchangeItems field of the WMI object. It is the equivalent of the HKLMSOFTWAREMicrosoftVirtual MachineAuto key on Windows guests. You can’t do anything useful with the file on Linux.
  • .kvp_pool_3: The host will automatically send information about itself and the virtual machine through this file. You can read the contents of this file, but changing it does nothing useful. It is the equivalent of the HKLMSOFTWAREMicrosoftVirtual MachineGuestParameter key on Windows guests.
  • .kvp_pool_4: I have no idea what this file does or what it is for.

What is the Format of the Hyper-V KVP Exchange File on Linux?

Each file uses the same format.

One KVP entry is built like this:

  • 512 bytes for the key. The key is a sequence of non-null bytes, typically interpreted as char. According to the documentation, it will be processed as using UTF8 encoding. After the characters for the key, the remainder of the 512 bytes is padded with null characters.
  • 2,048 bytes for the value. As with the key, these are non-null bytes typically interpreted as char. After the characters for the value, the remainder of the 2,048 bytes is padded with null characters.

KVP entries are written end-to-end in the file with no spacing, headers, or footers.

For the most part, you’ll treat these as text strings, but that’s not strictly necessary. I’ve been on this rant before, but the difference between “text” data and “binary” data is 100% semantics, no matter how much code we write to enforce artificial distinctions. From now until the point when computers can process something other than low voltage/high voltage (0s and 1s), there will never be anything but binary data and binary files. On the Linux side, you have 512 bytes for the key and 2,048 bytes for the value. Do with them as you see fit. However, on the host side, you’ll still need to get through the WMI processing. I haven’t pushed that very far.

How Do I Use Hyper-V KVP Exchange for Linux?

This is the part where it gets fun. Microsoft only goes so far as to supply the daemon. If you want to push or pull data, that’s all up to you. Or third parties.

But really, all you need to do is read to and/or write from files. The trick is, you need to be able to do it using the binary format that I mentioned above. If you just use a tool that writes simple strings, it will improperly pad the fields, resulting in mangled transfers. So, you’ll need a bit of proficiency in whatever tool you use. The tool itself doesn’t matter, though. Perl, Python, bash scripts,… anything will do. Just remember these guidelines:

  • Writing to files _0, _2, _3, and _4 just wastes time. The host will never see it, it will break KVP clients, and the files’ contents will be reset when the daemon restarts.
  • You do not need special permission to read from any of the files.
  • _1 is the only file that it’s useful to write to. You can, of course, read from it.
    • Deleting the existing contents deletes those KVPs. You probably want to update existing or append new.
    • The host only receives the LAST time that a KVP is set. Meaning that if you write a KVP with key “NewKey” twice in the _1 file, the host will only receive the second one.
    • Delete a KVP by zeroing its fields.
  • If the byte lengths are not honored properly, you will damage that KVP and every KVP following.

Source Code for a Hyper-V KVP Exchange Utility on Linux

I’ve built a small utility that can be used to read, write, and delete Hyper-V KVPs on Linux. I wrote it in C++ so that it can be compiled into a single, neat executable.

Long-term, I will only be maintaining this project on my GitHub site. The listing on this article will be forever locked in a 1.0 state.

Compile Instructions

Each file is set so that they all live in the same directory. Use make to build the sources and sudo make install to put the executable into the /bin folder.

Install Instructions

Paste the contents of all of these files into accordingly-named files. File names are in the matching section header and in the code preview bar.

Transfer all of the files to your Linux system. It doesn’t really matter where. They just need to be in the same folder.

Run:

Usage Instructions

Get help with:

  • hvkvp –help
  • hvkvp read –help
  • hvkvp write –help
  • hvkvp delete –help

Each includes the related keys for that command and some examples.

Code Listing

The file list:

  • makefile
  • main.cpp
  • hvkvp.h
  • hvkvp.cpp
  • hvkvpfile.h
  • hvkvpfile.cpp
  • hvkvpreader.h
  • hvkvpreader.cpp
  • hvkvpremover.h
  • hvkvpremover.cpp
  • hvkvpwriter.h
  • hvkvpwriter.cpp

makefile

main.cpp

 

hvkvp.h

 

hvkvp.cpp

 

hvkvpfile.h

 

hvkvpfile.cpp

 

hvkvpreader.h

 

hvkvpreader.cpp

 

hvkvpremover.h

 

hvkvpremover.cpp

 

hvkvpwriter.h

 

hvkvpwriter.cpp

More in this series:

Part 1: Explanation

Part 2: Implementation

Hyper-V Key-Value Pair Data Exchange Part 2: Implementation

Hyper-V Key-Value Pair Data Exchange Part 2: Implementation

In part one of this series, we talked about Hyper-V’s Key-Value Pair (KVP) data exchange feature and got an idea for how it works. As I mentioned in that piece, one of the reasons you don’t see much about it is because it can be difficult to use.

In this post, I’m going to provide you with some PowerShell modules that are intended to alleviate most of the pain. Once you’ve implemented these modules on your systems, you’ll be able to pass data back and forth from guests to hosts. What that data is, and what happens when it is received by the target system, is for your imagination to concoct. If PowerShell scripting isn’t your strong suit, I first suggest that you become acquainted. The primer in our Hyper-V and PowerShell series can set you on your way. You should also search the Internet for scripts designed by others that can accelerate implementation of your automation solutions.

Skip to part 3: Linux

Credits

If I ever figured out how to do everything you see in this article, it would have taken me a lot longer to get there without the writings of Taylor Brown and Boe Prox.

Taylor Brown’s source is mentioned in the comments for the relevant functions, I have lifted his “ProcessWMIJob” function nearly verbatim. The changes that I made were more to make it script-friendly as opposed to being meant for an interactive session. You can see the original ProcessWMIJob function on this blog article. The original script for the Add, Modify, and Remove KVP functions from WMI in a Hyper-V host is found in this blog article. That script was later copied to this TechNet article. To some degree, it might be said that my article refines that script into something more approachable and universally usable. If you’re looking for coding samples for using KVP exchange in Linux guests, that TechNet article is where you want to go.

Boe Prox’s work is not included directly in any of my modules, but is referred to heavily in the supporting sections.

The Modules

I’ll start by presenting the modules so that those of you with PowerShell experience can copy/paste them and be on your way. Explanations for each will follow.

The Host Module

This module is intended to be used on Hyper-V hosts. It exposes the following functions:

  • Get-VMWmiObject: Given the name of a virtual machine, returns the WMI object that represents it.
  • Get-VMKvpGuestToHost: Lists one or more of the KVPs transmitted from the guest to the host.
  • Get-VMKvpGuestToHostInstrinsic: Lists one or more of the KVPs transmitted from the guest to the host that are automatically generated by the Hyper-V Data Exchange service.
  • Get-VMKvpHostToGuest: Lists one or more of the KVPs transmitted from the host to the guest.
  • Send-VMKvpHostToGuest: Creates or modifies a KVP to be sent to a guest from the host. In case you jumped here without reading part one, be aware that the KVP is case-sensitive. If you use a key name that differs from an existing key by only capitalization, a duplicate KVP will be created but the guest will only see the most recent one. This is due to a flaw in the design of KVP Data Exchange and there’s nothing I can do about it short of forcing you to use all-uppercase or all-lowercase key names.
  • Remove-VMKvpHostToGuest: Deletes a host-to-guest KVP. Remember that these cannot be deleted from within the guest. This cmdlet has the same case-sensitivity caveat note as Send-VMKvpHostToGuest. Remove-KvpHostToGuest will almost always report success, even when it didn’t find a matching KVP to remove. I considered performing some pre-flight checking, but opted against it. You may want this cmdlet to work even when the virtual machine is powered off, in which case Get-VMKvpHostToGuest will not operate. I encourage you to use Get-VMKvpHostToGuest for verification.

Each of these has detailed Get-Help text.

Installation Instructions

  1. Navigate to C:WindowsSystem32WindowsPowerShellv1.0Modules.
  2. Create a folder named Hyper-V-KVP-Host.
  3. Inside that folder, create two empty text files: Hyper-V-KVP-Host.psd1 and Hyper-V-KVP-Host.psm1.
  4. Paste the contents of the following code blocks into the respective files.
Hyper-V-KVP-Host.psd1

Hyper-V-KVP-Host.psm1

 

The Guest Module

This module is intended to be used on Hyper-V guests. It exposes the following functions:

  • Get-VMKVPHostToGuest: Lists one or more of the KVPs that have been transmitted to the guest from the host.
  • Get-VMKVPGuestToHost: Lists one or more of the KVPs that the guest has transmitted to the host.
  • Send-VMKVPGuestToHost: Creates or modifies the specified KVP in the appropriate registry location, causing it to be transmitted to the host.
  • Remove-VMKVPGuestToHost: Removes a guest-to-host KVP.

As with the host module, the guest module’s cmdlets have detailed help viewable in Get-Help.

Installation Instructions

  1. Navigate to C:WindowsSystem32WindowsPowerShellv1.0Modules.
  2. Create a folder named Hyper-V-KVP-Guest.
  3. Inside that folder, create two empty text files: Hyper-V-KVP-Guest.psd1 and Hyper-V-KVP-Guest.psm1.
  4. Paste the contents of the following code blocks into the respective files.

Hyper-V-KVP-Guest.psd1

Hyper-V-KVP-Guest.psd1

Module Discussion

These modules have been marked to only operate under PowerShell 4.0, although I admit that’s mostly because I didn’t want to add in script to check for administrator privileges. I don’t think there’s anything in them that won’t operate under PS 3.0 aside from all of the #requires -RunAsAdministrator lines, so you should be able to downgrade these modules fairly easily if necessary. I’d prefer that you bring your hosts and guests up to at least PowerShell 4.0, if they aren’t there already. To check the installed version, run this at a PowerShell prompt: $PSVersionTable. If your version is below 4.0, go to the Microsoft downloads page and search for “Windows Management Framework”. Version 5 is the latest, but as of this writing it is so badly broken that it has been removed from the downloads page. I have heard of a handful of compatibility issues for PowerShell-dependent applications when upgrading to newer PowerShell releases, so you might want to look into that for any such apps that you have.

The host module is also designed to work with version 2 of the Hyper-V WMI namespace. It will be immediately compatible with Hyper-V Server 2012 and later and all versions of Client Hyper-V. I think the module will work for 2008 R2, but you’ll need to modify the $KVPVirtualizationNamespace = 'rootvirtualizationv2' line of Hyper-V-KVP-Host.psm1 to read  $KVPVirtualizationNamespace = 'rootvirtualization'. I highlighted the line in the source script pasted above, it’s very near the top.

The Host Module

For the most part, I genericized Taylor Brown’s script so that it could be run on demand with any guest and KVP. I also performed a fair bit of refactoring to transition it from short and clever script to readable and maintainable script. For the programming/scripting purists, I apologize for leaving in the magic numbers for the job states. I couldn’t find a definitive explanation of the JobState enumerator that lined up with the numbers that Brown used in his ProcessWMIJob and I didn’t want to guess, so I just left them as I found them.

The functions that are exported from the module should be very simple to figure out. I think tab completion exposure of the parameters should be sufficient to understand what to do, but they are Get-Help friendly just in case. The functions that are not exported by the module might be of interest to those scripters that would like to work with WMI and VMMS, as they do the real work; the exported functions are merely wrappers.

The Guest Module

The guest module contains work that is substantially more original. Truly, working with KVP on the guest side is just a matter of manipulating registry keys. I considered leaving that to you readers to sort out, but PowerShell’s functionality for working with the registry is a special kind of awful. I trust that you’ll find this module to be much more friendly.

As with the host module, I don’t think there’s anything in it that truly requires PowerShell version 4.0 since it is almost exclusively .Net calls, but you do need to be a local administrator to write to the KVP registry sections and I didn’t want to include a checking function. You could remove the #requires and everything should be OK as long as you run the script with administrative privileges.

Exploiting the Modules

Both modules work fine as-is.

KVP Basic Demo

KVP Basic Demo

I’m guessing that you want a little more, such as automation. OK.

Simple Automation

Open up a PowerShell prompt or the ISE inside a guest that has the Hyper-V-KVP-Guest module, and paste this into it:

If you’re using the ISE, press F5 to execute it. Do not close the ISE or the PS session. Switch to the host, which must have the Hyper-V-KVP-Host module. Inside the ISE or a PS session, there, enter something like the following:

Inside the guest, your system drive should now have a “Temp” folder if it didn’t before, and inside that temp folder should be a file named “kvp-incoming.log”, and that file should be a pure text file that contains something like:

The bad news is, that only works for as long as the PowerShell session is left open. I’m assuming you’d like something a bit more permanent. OK.

Creating a Permanent Guest-Side KVP Watcher

The following has been adapted from Boe Prox’s article on permanent WMI registrations. Something that I need to make clear up front is that this will only cause an action when a registry entry changes or is created anew. If you attempt to test by repeatedly transmitting the same KVP without modifying the value, the sending host will report success while the receiving guest reports nothing.

Inside the guest, run the following inside ISE or at an interactive PowerShell prompt. It only has to be done once, but it’s something you’ll probably want to save to use on other VMs:

There will be output indicating that the WMI event instance was created, which should look something like the following:

You can verify its existence at any time (helpful if you forget whether or not you created it on a given VM):

What you have done is tell Windows to trigger an event whenever that particular registry branch changes. Now what you need to do is subscribe to that event. In .Net, that’s called an event handler. In WMI, its an event consumer.

You will get some output to the screen to verify that the consumer was created. It will look similar to the output when you created the event. You can verify the existence of the consumer at any time:

You’ll need to supply the item designated in $ScriptPath. You can snip out the action part from the previous section for testing purposes, if you’d like. That’s recreated here for your convenience:

At this point, you have an event, and you have an event consumer. The final step is to connect the consumer to the event in an act called binding.

As before, you’ll get some output telling you that the object has been created. You can look at your bindings any time:

I’m sure you’ll want to try it out. You’ll find that everything works immediately. No service restarts or system reboots necessary.

Verifying that the Guest Heard You

Remember how I said that the event only fires when the registry changes, so you can’t just send the same data repeatedly? Well, I can help out with that, too. I’ve crafted a script that I use to ensure that each send is unique without me having to do anything fancy. You can drop this right into the Hyper-V-KVP-Host module if you like, which will make it always available. Don’t forget to add “Send-VMKVPCommandToGuest” into the ExportedFunctions line of the Hyper-V-KVP-Host.psd1 file (I highlighted that line for you above)!

As-is, this will modify or create a key named “VMCommand”. The value will be the host’s timestamp for the command was issued, in ticks, followed by whatever you supplied as the -Command parameter, optionally followed by the item(s) that you supplied for the -Arguments parameter. For example, entering the following in the host:

Should produce something like the following in the guest:

Because the host’s clock is constantly changing and it would be ridiculously difficult to submit two commands so closely together that they have the same timestamp, this all but guarantees that you’ll trigger the event in the guest every time you send anything… even if it’s technically the exact same KVP with an identical value.

You might have noticed that there is a -Verify parameter. I included this because the KVP operation in the host can only tell you if the KVP was modified on the host’s virtual machine object, which is probably going to work as long as the guest exists and you have the correct permissions. It doesn’t tell you whether or not the guest operating system received the KVP. Change your KVPResponse.ps1 script to the following (you can just include it at the beginning if you don’t want to modify the existing contents):

As shown, the “else” portion is unnecessary. Without it, duplicate commands will be ignored automatically and silently. I put it in to give you the option of handling them, if you wish. What you might choose to do is place a “return” statement in the else which would allow you to perform processing without nesting inside the “if” block. However, I would simplify that as:

Whatever works for you and your scripting style.

Note 1: If you’d rather use special KVP key names besides “VMCommand” and “VMAcknowledgement”, change them on lines 42 and 43, respectively, in the Send-VMKvpCommandToGuest function. I highlighted those lines in the above source to make them easy to find. Don’t forget to change the corresponding keys in your guest’s response script.

Note 2: I normally process the registry changes using a binary .Net module, and it picks up the changes instantly. To make this work in the PowerShell module, I had to add a delay in the verify portion of the Send-VMKVPCommandToGuest function. This means that you could fairly easily inject a secondary command while it is still waiting for the delay, which would cause the earlier Verify to fail. I made the delay a full second, but feel free to lower the number and test. It’s on line 44, which is highlighted in the above source. If you have a newer, not overloaded host, your guests might respond quickly enough that you don’t need it at all. Your mileage may vary, and I recommend that you test thoroughly.

Parsing the Command

Of course, with the command KVP containing a mashed-together string, you need to be able to unmash it on the guest. Here is a skeleton to help you do that. Just place this script into the KVPResponse.ps1 after the above bit: