Skip to contentSkip to conversation

drivers: hv: kvp

PATCH Superseded K. Y. Srinivasan 3 participants 30 messages Aug 13, 2012 – Aug 16, 2012

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover drivers: hv: kvp

This patchset expands the KVP (Key Value Pair) functionality to implement the mechanism to GET/SET IP addresses in the guest. This functionality is used in Windows Server 2012 to implement VM replication functionality. The way IP configuration information is managed is distro specific. Based on the feedback I have gotten from Olaf, Greg, Steve, Ben and Mairus, I have chosen to seperate distro specific code from this patch-set. Most of the GET operation can be implemented in a way that is completely distro independent and I have implemented that as such and is included in this patch-set. Some of the attributes that can only be fetched in a distro dependent way as well the mechanism for configuring an interface (the SET operation) that is clearly distro specific is to be implemented via external scripts that will be invoked via the KVP code. We define here the interface to these scripts.

Adding support for IP injection resulted in some changes to the protocol between the user level daemon and the kernel driver. These changes have been implemented in way that would retain compatibility with older daemons. I would like to thank Olaf and Greg for pointing out the compatibility issue.

This version of the patch set addresses all of the comments that I have received to date from Olaf, Ben and others. Specifically, I have cleanedup all of the string manipulation code. Furthermore, I have also simplified the format of the interface configuration file that is generated by the KVP daemon and gotten rid of some constant strings that may not be relevant on all distros. I would like to thank Olaf and Ben for their detailed review.

K. Y. Srinivasan (18):
Drivers: hv: vmbus: Use the standard format string to format GUIDs
Drivers: hv: Add KVP definitions for IP address injection
Drivers: hv: kvp: Cleanup error handling in KVP
Drivers: hv: kvp: Support the new IP injection messages
Tools: hv: Prepare to expand kvp_get_ip_address() functionality
Tools: hv: Further refactor kvp_get_ip_address()
Tools: hv: Gather address family information
Tools: hv: Gather subnet information
Tools: hv: Represent the ipv6 mask using CIDR notation
Tools: hv: Gather ipv[4,6] gateway information
Tools: hv: Gather DNS information
Tools: hv: Gather DHCP information
Tools: hv: Implement the KVP verb - KVP_OP_SET_IP_INFO
Tools: hv: Rename the function kvp_get_ip_address()
Tools: hv: Implement the KVP verb - KVP_OP_GET_IP_INFO
Tools: hv: Get rid of some unused variables
Tools: hv: Correctly type string variables
Tools: hv: Properly manage open streams

 drivers/hv/hv_kvp.c      |  253 +++++++++++--
 drivers/hv/hv_util.c     |    4 +-
 drivers/hv/vmbus_drv.c   |   38 +--
 include/linux/hyperv.h   |   93 +++++-
 tools/hv/hv_kvp_daemon.c |  928 +++++++++++++++++++++++++++++++++++++++++-----
 5 files changed, 1147 insertions(+), 169 deletions(-)
Signature · 1 line
1.7.4.1
#1 lore raw

PATCH v2 1/18 Drivers: hv: vmbus: Use the standard format string to format GUIDs

Format GUIDS as per MSFT standard. This makes interacting with MSFT tool stack easier.

---
 drivers/hv/vmbus_drv.c |   38 ++------------------------------------
 1 files changed, 2 insertions(+), 36 deletions(-)
drivers/hv/vmbus_drv.c +2 -36
index 4748086..b76e8b3 100644
@@ -146,43 +146,9 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
 	get_channel_info(hv_dev, device_info);
 
 	if (!strcmp(dev_attr->attr.name, "class_id")) {
-		ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-			       "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-			       device_info->chn_type.b[3],
-			       device_info->chn_type.b[2],
-			       device_info->chn_type.b[1],
-			       device_info->chn_type.b[0],
-			       device_info->chn_type.b[5],
-			       device_info->chn_type.b[4],
-			       device_info->chn_type.b[7],
-			       device_info->chn_type.b[6],
-			       device_info->chn_type.b[8],
-			       device_info->chn_type.b[9],
-			       device_info->chn_type.b[10],
-			       device_info->chn_type.b[11],
-			       device_info->chn_type.b[12],
-			       device_info->chn_type.b[13],
-			       device_info->chn_type.b[14],
-			       device_info->chn_type.b[15]);
+		ret = sprintf(buf, "{%pUl}\n", device_info->chn_type.b);
 	} else if (!strcmp(dev_attr->attr.name, "device_id")) {
-		ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-			       "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-			       device_info->chn_instance.b[3],
-			       device_info->chn_instance.b[2],
-			       device_info->chn_instance.b[1],
-			       device_info->chn_instance.b[0],
-			       device_info->chn_instance.b[5],
-			       device_info->chn_instance.b[4],
-			       device_info->chn_instance.b[7],
-			       device_info->chn_instance.b[6],
-			       device_info->chn_instance.b[8],
-			       device_info->chn_instance.b[9],
-			       device_info->chn_instance.b[10],
-			       device_info->chn_instance.b[11],
-			       device_info->chn_instance.b[12],
-			       device_info->chn_instance.b[13],
-			       device_info->chn_instance.b[14],
-			       device_info->chn_instance.b[15]);
+		ret = sprintf(buf, "{%pUl}\n", device_info->chn_instance.b);
 	} else if (!strcmp(dev_attr->attr.name, "modalias")) {
 		print_alias_name(hv_dev, alias_name);
 		ret = sprintf(buf, "vmbus:%s\n", alias_name);
Signature · 1 line
1.7.4.1
#2 lore raw

PATCH v2 2/18 Drivers: hv: Add KVP definitions for IP address injection

Add the necessary definitions for supporting the IP injection functionality.

---
 drivers/hv/hv_util.c     |    4 +-
 include/linux/hyperv.h   |   76 ++++++++++++++++++++++++++++++++++++++++++++-
 tools/hv/hv_kvp_daemon.c |    2 +-
 3 files changed, 77 insertions(+), 5 deletions(-)
drivers/hv/hv_util.c +2 -2
index d3ac6a4..a0667de 100644
@@ -263,7 +263,7 @@ static int util_probe(struct hv_device *dev,
 		(struct hv_util_service *)dev_id->driver_data;
 	int ret;
 
-	srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
 	if (!srv->recv_buffer)
 		return -ENOMEM;
 	if (srv->util_init) {
@@ -274,7 +274,7 @@ static int util_probe(struct hv_device *dev,
 		}
 	}
 
-	ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0,
+	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
 			srv->util_cb, dev->channel);
 	if (ret)
 		goto error;
include/linux/hyperv.h +74 -2

114 lines not on this page · raw message

tools/hv/hv_kvp_daemon.c +1 -1
index d9834b3..8fbcf7b 100644
@@ -69,7 +69,7 @@ enum key_index {
 };
 
 static char kvp_send_buffer[4096];
-static char kvp_recv_buffer[4096];
+static char kvp_recv_buffer[4096 * 2];
 static struct sockaddr_nl addr;
 
 static char *os_name = "";
Signature · 1 line
1.7.4.1
#3 lore raw

Re: [PATCH V2 02/18] Drivers: hv: Add KVP definitions for IP address injection

Quoted 62 lines · K. Y. Srinivasan

Add the necessary definitions for supporting the IP injection functionality.

---
 drivers/hv/hv_util.c     |    4 +-
 include/linux/hyperv.h   |   76 ++++++++++++++++++++++++++++++++++++++++++++-
 tools/hv/hv_kvp_daemon.c |    2 +-
 3 files changed, 77 insertions(+), 5 deletions(-)
drivers/hv/hv_util.c +2 -2
index d3ac6a4..a0667de 100644
@@ -263,7 +263,7 @@ static int util_probe(struct hv_device *dev,
 		(struct hv_util_service *)dev_id->driver_data;
 	int ret;
 
-	srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
 	if (!srv->recv_buffer)
 		return -ENOMEM;
 	if (srv->util_init) {
@@ -274,7 +274,7 @@ static int util_probe(struct hv_device *dev,
 		}
 	}
 
-	ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0,
+	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
 			srv->util_cb, dev->channel);
 	if (ret)
 		goto error;
include/linux/hyperv.h +20 -0
index 68ed7f7..11afc4e 100644
@@ -122,12 +122,53 @@
 #define REG_U32 4
 #define REG_U64 8
 
+/*
+ * As we look at expanding the KVP functionality to include
+ * IP injection functionality, we need to maintain binary
+ * compatibility with older daemons.
+ *
+ * The KVP opcodes are defined by the host and it was unfortunate
+ * that I chose to treat the registration operation as part of the
+ * KVP operations defined by the host.
+ * Here is the level of compatibility
+ * (between the user level daemon and the kernel KVP driver) that we
+ * will implement:
+ *
+ * An older daemon will always be supported on a newer driver.
+ * A given user level daemon will require a minimal version of the
+ * kernel driver.
+ * If we cannot handle the version differences, we will fail gracefully
+ * (this can happen when we have a user level daemon that is more
+ * advanced than the KVP driver.
+ *
+ * We will use values used in this handshake for determining if we have

include/linux/hyperv.h line 154

Quoted 10 lines
include/linux/hyperv.h +10 -0
+ * workable user level daemon and the kernel driver. We begin by taking the
+ * registration opcode out of the KVP opcode namespace. We will however,
+ * maintain compatibility with the existing user-level daemon code.
+ */
+
+/*
+ * Daemon code not supporting IP injection (legacy daemon).
+ */
+
+#define KVP_OP_REGISTER	4

Huh?

Quoted 7 lines
include/linux/hyperv.h +7 -0
+/*
+ * Daemon code supporting IP injection.
+ * The KVP opcode field is used to communicate the
+ * registration information; so define a namespace that
+ * will be distinct from the host defined KVP opcode.
+ */
+

include/linux/hyperv.h line 171

Quoted 10 lines
include/linux/hyperv.h +4 -1
+#define KVP_OP_REGISTER1 100
+
 enum hv_kvp_exchg_op {
 	KVP_OP_GET = 0,
 	KVP_OP_SET,
 	KVP_OP_DELETE,
 	KVP_OP_ENUMERATE,
-	KVP_OP_REGISTER,
+	KVP_OP_GET_IP_INFO,
+	KVP_OP_SET_IP_INFO,

So you overloaded the command and somehow think that is ok? How is that supposed to work? Why not just always keep it there, but fail if it is called as you know you have a mismatch?

Otherwise, again, you just broke older tools on a newer kernel.

Or am I missing something here?

confused,

greg k-h

#4 lore raw

Re: [PATCH V2 02/18] Drivers: hv: Add KVP definitions for IP address injection

Quoted 2 lines · Greg KH
Quoted 1 line · K. Y. Srinivasan

Add the necessary definitions for supporting the IP injection functionality.

[...]

Quoted 61 lines
Quoted 26 lines
include/linux/hyperv.h +20 -0
@@ -122,12 +122,53 @@
 #define REG_U32 4
 #define REG_U64 8
 
+/*
+ * As we look at expanding the KVP functionality to include
+ * IP injection functionality, we need to maintain binary
+ * compatibility with older daemons.
+ *
+ * The KVP opcodes are defined by the host and it was unfortunate
+ * that I chose to treat the registration operation as part of the
+ * KVP operations defined by the host.
+ * Here is the level of compatibility
+ * (between the user level daemon and the kernel KVP driver) that we
+ * will implement:
+ *
+ * An older daemon will always be supported on a newer driver.
+ * A given user level daemon will require a minimal version of the
+ * kernel driver.
+ * If we cannot handle the version differences, we will fail gracefully
+ * (this can happen when we have a user level daemon that is more
+ * advanced than the KVP driver.
+ *
+ * We will use values used in this handshake for determining if we have

include/linux/hyperv.h line 154

Quoted 10 lines
include/linux/hyperv.h +10 -0
+ * workable user level daemon and the kernel driver. We begin by taking the
+ * registration opcode out of the KVP opcode namespace. We will however,
+ * maintain compatibility with the existing user-level daemon code.
+ */
+
+/*
+ * Daemon code not supporting IP injection (legacy daemon).
+ */
+
+#define KVP_OP_REGISTER	4

Huh?

Quoted 7 lines
include/linux/hyperv.h +7 -0
+/*
+ * Daemon code supporting IP injection.
+ * The KVP opcode field is used to communicate the
+ * registration information; so define a namespace that
+ * will be distinct from the host defined KVP opcode.
+ */
+

include/linux/hyperv.h line 171

Quoted 10 lines
include/linux/hyperv.h +4 -1
+#define KVP_OP_REGISTER1 100
+
 enum hv_kvp_exchg_op {
 	KVP_OP_GET = 0,
 	KVP_OP_SET,
 	KVP_OP_DELETE,
 	KVP_OP_ENUMERATE,
-	KVP_OP_REGISTER,
+	KVP_OP_GET_IP_INFO,
+	KVP_OP_SET_IP_INFO,

So you overloaded the command and somehow think that is ok? How is that supposed to work? Why not just always keep it there, but fail if it is called as you know you have a mismatch?

Quoted 3 lines

Otherwise, again, you just broke older tools on a newer kernel.

Or am I missing something here?

You are. The above enumeration is for the hypervisor-to-guest protocol, whereas KVP_OP_REGISTER and KVP_OP_REGISTER1 are only used between daemon and driver. The registration operation code should have been defined as a sufficiently high value to avoid collision.

However, since the daemon will always send one of the registration operations at start of day (and then never again), it seems that the driver can avoid confusing registration with a reply to KVP_OP_GET_IP_INFO. Instead, the two registration operation codes distinguish the capabilities of the daemon and actually aid backward compatibility.

Ben.

Signature · 2 lines
Ben Hutchings
I say we take off; nuke the site from orbit.  It's the only way to be sure.
#5 lore raw

RE: [PATCH V2 02/18] Drivers: hv: Add KVP definitions for IP address injection

In reply to Greg KH
Quoted 113 lines

-----Original Message-----
From: Greg KH [mailto:[email protected]]
Sent: Monday, August 13, 2012 9:38 PM
To: KY Srinivasan
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH V2 02/18] Drivers: hv: Add KVP definitions for IP address injection

Quoted 9 lines · K. Y. Srinivasan

Add the necessary definitions for supporting the IP injection functionality.

---
 drivers/hv/hv_util.c     |    4 +-
 include/linux/hyperv.h   |   76

++++++++++++++++++++++++++++++++++++++++++++-

Quoted 17 lines
 tools/hv/hv_kvp_daemon.c |    2 +-
 3 files changed, 77 insertions(+), 5 deletions(-)
drivers/hv/hv_util.c +1 -1
index d3ac6a4..a0667de 100644
@@ -263,7 +263,7 @@ static int util_probe(struct hv_device *dev,
 		(struct hv_util_service *)dev_id->driver_data;
 	int ret;
 
-	srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
 	if (!srv->recv_buffer)
 		return -ENOMEM;
 	if (srv->util_init) {

drivers/hv/hv_util.c static int util_probe(struct hv_device *dev, · line 277

Quoted 4 lines
drivers/hv/hv_util.c +0 -1
@@ -274,7 +274,7 @@ static int util_probe(struct hv_device *dev,
 		}
 	}
 
-	ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL,

0,

drivers/hv/hv_util.c static int util_probe(struct hv_device *dev, · line 277

Quoted 1 line
drivers/hv/hv_util.c +1 -0
+	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL,

0,

Quoted 31 lines
drivers/hv/hv_util.c +0 -0
 			srv->util_cb, dev->channel);
 	if (ret)
 		goto error;
include/linux/hyperv.h +20 -0
index 68ed7f7..11afc4e 100644
@@ -122,12 +122,53 @@
 #define REG_U32 4
 #define REG_U64 8
 
+/*
+ * As we look at expanding the KVP functionality to include
+ * IP injection functionality, we need to maintain binary
+ * compatibility with older daemons.
+ *
+ * The KVP opcodes are defined by the host and it was unfortunate
+ * that I chose to treat the registration operation as part of the
+ * KVP operations defined by the host.
+ * Here is the level of compatibility
+ * (between the user level daemon and the kernel KVP driver) that we
+ * will implement:
+ *
+ * An older daemon will always be supported on a newer driver.
+ * A given user level daemon will require a minimal version of the
+ * kernel driver.
+ * If we cannot handle the version differences, we will fail gracefully
+ * (this can happen when we have a user level daemon that is more
+ * advanced than the KVP driver.
+ *
+ * We will use values used in this handshake for determining if we have

include/linux/hyperv.h line 154

Quoted 10 lines
include/linux/hyperv.h +10 -0
+ * workable user level daemon and the kernel driver. We begin by taking the
+ * registration opcode out of the KVP opcode namespace. We will however,
+ * maintain compatibility with the existing user-level daemon code.
+ */
+
+/*
+ * Daemon code not supporting IP injection (legacy daemon).
+ */
+
+#define KVP_OP_REGISTER	4

Huh?

Quoted 7 lines
include/linux/hyperv.h +7 -0
+/*
+ * Daemon code supporting IP injection.
+ * The KVP opcode field is used to communicate the
+ * registration information; so define a namespace that
+ * will be distinct from the host defined KVP opcode.
+ */
+

include/linux/hyperv.h line 171

Quoted 10 lines
include/linux/hyperv.h +4 -1
+#define KVP_OP_REGISTER1 100
+
 enum hv_kvp_exchg_op {
 	KVP_OP_GET = 0,
 	KVP_OP_SET,
 	KVP_OP_DELETE,
 	KVP_OP_ENUMERATE,
-	KVP_OP_REGISTER,
+	KVP_OP_GET_IP_INFO,
+	KVP_OP_SET_IP_INFO,

So you overloaded the command and somehow think that is ok? How is that supposed to work? Why not just always keep it there, but fail if it is called as you know you have a mismatch?

Quoted 3 lines

Otherwise, again, you just broke older tools on a newer kernel.

Or am I missing something here?

Greg,

The registration operation occurs when the daemon first starts up. I should have established a distinct namespace for the daemon versions that would not overlap with the host defined KVP operations initially. Unfortunately when I first implemented KVP, I did not know about the new KVP verbs and so selected a value that ended up colliding with the new KVP operations. To maintain compatibility with older daemons, I have to support this old registration value, which is what you are seeing here. Since the initial driver/daemon handshake phase does not overlap with the normal functioning of the KVP stack, we can use the old daemon registration value to distinguish that the daemon does not support IP injection. The current implementation does support a compatible environment for older daemons.

Regards,

K. Y

#6 lore raw

RE: [PATCH V2 02/18] Drivers: hv: Add KVP definitions for IP address injection

Quoted 140 lines

-----Original Message-----
From: [email protected] [mailto:devel- [email protected]] On Behalf Of KY Srinivasan
Sent: Monday, August 13, 2012 10:57 PM
To: Greg KH
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH V2 02/18] Drivers: hv: Add KVP definitions for IP address injection

Quoted 111 lines

-----Original Message-----
From: Greg KH [mailto:[email protected]]
Sent: Monday, August 13, 2012 9:38 PM
To: KY Srinivasan
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH V2 02/18] Drivers: hv: Add KVP definitions for IP address injection

Quoted 9 lines · K. Y. Srinivasan

Add the necessary definitions for supporting the IP injection functionality.

---
 drivers/hv/hv_util.c     |    4 +-
 include/linux/hyperv.h   |   76

++++++++++++++++++++++++++++++++++++++++++++-

Quoted 17 lines
 tools/hv/hv_kvp_daemon.c |    2 +-
 3 files changed, 77 insertions(+), 5 deletions(-)
drivers/hv/hv_util.c +1 -1
index d3ac6a4..a0667de 100644
@@ -263,7 +263,7 @@ static int util_probe(struct hv_device *dev,
 		(struct hv_util_service *)dev_id->driver_data;
 	int ret;
 
-	srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
 	if (!srv->recv_buffer)
 		return -ENOMEM;
 	if (srv->util_init) {

drivers/hv/hv_util.c static int util_probe(struct hv_device *dev, · line 277

Quoted 4 lines
drivers/hv/hv_util.c +0 -1
@@ -274,7 +274,7 @@ static int util_probe(struct hv_device *dev,
 		}
 	}
 
-	ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL,

0,

drivers/hv/hv_util.c static int util_probe(struct hv_device *dev, · line 277

Quoted 1 line
drivers/hv/hv_util.c +1 -0
+	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL,

0,

Quoted 31 lines
drivers/hv/hv_util.c +0 -0
 			srv->util_cb, dev->channel);
 	if (ret)
 		goto error;
include/linux/hyperv.h +20 -0
index 68ed7f7..11afc4e 100644
@@ -122,12 +122,53 @@
 #define REG_U32 4
 #define REG_U64 8
 
+/*
+ * As we look at expanding the KVP functionality to include
+ * IP injection functionality, we need to maintain binary
+ * compatibility with older daemons.
+ *
+ * The KVP opcodes are defined by the host and it was unfortunate
+ * that I chose to treat the registration operation as part of the
+ * KVP operations defined by the host.
+ * Here is the level of compatibility
+ * (between the user level daemon and the kernel KVP driver) that we
+ * will implement:
+ *
+ * An older daemon will always be supported on a newer driver.
+ * A given user level daemon will require a minimal version of the
+ * kernel driver.
+ * If we cannot handle the version differences, we will fail gracefully
+ * (this can happen when we have a user level daemon that is more
+ * advanced than the KVP driver.
+ *
+ * We will use values used in this handshake for determining if we have

include/linux/hyperv.h line 154

Quoted 10 lines
include/linux/hyperv.h +10 -0
+ * workable user level daemon and the kernel driver. We begin by taking the
+ * registration opcode out of the KVP opcode namespace. We will however,
+ * maintain compatibility with the existing user-level daemon code.
+ */
+
+/*
+ * Daemon code not supporting IP injection (legacy daemon).
+ */
+
+#define KVP_OP_REGISTER	4

Huh?

Quoted 7 lines
include/linux/hyperv.h +7 -0
+/*
+ * Daemon code supporting IP injection.
+ * The KVP opcode field is used to communicate the
+ * registration information; so define a namespace that
+ * will be distinct from the host defined KVP opcode.
+ */
+

include/linux/hyperv.h line 171

Quoted 10 lines
include/linux/hyperv.h +4 -1
+#define KVP_OP_REGISTER1 100
+
 enum hv_kvp_exchg_op {
 	KVP_OP_GET = 0,
 	KVP_OP_SET,
 	KVP_OP_DELETE,
 	KVP_OP_ENUMERATE,
-	KVP_OP_REGISTER,
+	KVP_OP_GET_IP_INFO,
+	KVP_OP_SET_IP_INFO,

So you overloaded the command and somehow think that is ok? How is that supposed to work? Why not just always keep it there, but fail if it is called as you know you have a mismatch?

Quoted 3 lines

Otherwise, again, you just broke older tools on a newer kernel.

Or am I missing something here?

Greg,

The registration operation occurs when the daemon first starts up. I should have established
a distinct namespace for the daemon versions that would not overlap with the host
defined KVP operations initially. Unfortunately when I first implemented KVP, I did not know
about the new KVP verbs and so selected a value that ended up colliding with the new KVP
operations. To maintain compatibility with older daemons, I have to support this

Quoted 9 lines

old registration
value, which is what you are seeing here. Since the initial driver/daemon handshake phase does
not overlap with the normal functioning of the KVP stack, we can use the old daemon
registration value to distinguish that the daemon does not support IP injection. The current
implementation does support a compatible environment for older daemons.

Greg,

I hope this explanation is satisfactory. If there are other issues that you would want me to address before this patch set can be accepted, let me know and I will address them right away.

Regards,

K. Y

#7 lore raw

PATCH v2 3/18 Drivers: hv: kvp: Cleanup error handling in KVP

In reply to K. Y. Srinivasan

In preparation to implementing IP injection, cleanup the way we propagate and handle errors both in the driver as well as in the user level daemon.

---
 drivers/hv/hv_kvp.c      |  114 ++++++++++++++++++++++++++++++++++++---------
 include/linux/hyperv.h   |   17 ++++--
 tools/hv/hv_kvp_daemon.c |   66 +++++++++++++-------------
 3 files changed, 135 insertions(+), 62 deletions(-)
drivers/hv/hv_kvp.c +91 -23
index 0012eed..eb4d073 100644
@@ -48,13 +48,24 @@ static struct {
 	void *kvp_context; /* for the channel callback */
 } kvp_transaction;
 
+/*
+ * Before we can accept KVP messages from the host, we need
+ * to handshake with the user level daemon. This state tracks
+ * if we are in the handshake phase.
+ */
+static bool in_hand_shake = true;
+
+/*
+ * This state maintains the version number registered by the daemon.
+ */
+static int dm_reg_value;
+
 static void kvp_send_key(struct work_struct *dummy);
 
-#define TIMEOUT_FIRED 1
 
 static void kvp_respond_to_host(char *key, char *value, int error);
 static void kvp_work_func(struct work_struct *dummy);
-static void kvp_register(void);
+static void kvp_register(int);
 
 static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
 static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
@@ -68,7 +79,7 @@ static u8 *recv_buffer;
  */
 
 static void
-kvp_register(void)
+kvp_register(int reg_value)
 {
 
 	struct cn_msg *msg;
@@ -83,7 +94,7 @@ kvp_register(void)
 		msg->id.idx =  CN_KVP_IDX;
 		msg->id.val = CN_KVP_VAL;
 
-		kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+		kvp_msg->kvp_hdr.operation = reg_value;
 		strcpy(version, HV_DRV_VERSION);
 		msg->len = sizeof(struct hv_kvp_msg);
 		cn_netlink_send(msg, 0, GFP_ATOMIC);
@@ -97,9 +108,43 @@ kvp_work_func(struct work_struct *dummy)
 	 * If the timer fires, the user-mode component has not responded;
 	 * process the pending transaction.
 	 */
-	kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED);
+	kvp_respond_to_host("Unknown key", "Guest timed out", HV_E_FAIL);
+}
+
+static int kvp_handle_handshake(struct hv_kvp_msg *msg)
+{
+	int ret = 1;
+
+	switch (msg->kvp_hdr.operation) {
+	case KVP_OP_REGISTER:
+		dm_reg_value = KVP_OP_REGISTER;
+		pr_info("KVP: IP injection functionality not available\n");
+		pr_info("KVP: Upgrade the KVP daemon\n");
+		break;
+	case KVP_OP_REGISTER1:
+		dm_reg_value = KVP_OP_REGISTER1;
+		break;
+	default:
+		pr_info("KVP: incompatible daemon\n");
+		pr_info("KVP: KVP version: %d, Daemon version: %d\n",
+			KVP_OP_REGISTER1, msg->kvp_hdr.operation);
+		ret = 0;
+	}
+
+	if (ret) {
+		/*
+		 * We have a compatible daemon; complete the handshake.
+		 */
+		pr_info("KVP: user-mode registering done.\n");
+		kvp_register(dm_reg_value);
+		kvp_transaction.active = false;
+		if (kvp_transaction.kvp_context)
+			hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+	}
+	return ret;
 }
 
+
 /*
  * Callback when data is received from user mode.
  */
@@ -109,27 +154,52 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
 {
 	struct hv_kvp_msg *message;
 	struct hv_kvp_msg_enumerate *data;
+	int	error = 0;
 
 	message = (struct hv_kvp_msg *)msg->data;
-	switch (message->kvp_hdr.operation) {
+
+	/*
+	 * If we are negotiating the version information
+	 * with the daemon; handle that first.
+	 */
+
+	if (in_hand_shake) {
+		if (kvp_handle_handshake(message))
+			in_hand_shake = false;
+		return;
+	}
+
+	/*
+	 * Based on the version of the daemon, we propagate errors from the
+	 * daemon differently.
+	 */
+
+	data = &message->body.kvp_enum_data;
+
+	switch (dm_reg_value) {
 	case KVP_OP_REGISTER:
-		pr_info("KVP: user-mode registering done.\n");
-		kvp_register();
-		kvp_transaction.active = false;
-		hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+		/*
+		 * Null string is used to pass back error condition.
+		 */
+		if (data->data.key[0] == 0)
+			error = HV_S_CONT;
 		break;
 
-	default:
-		data = &message->body.kvp_enum_data;
+	case KVP_OP_REGISTER1:
 		/*
-		 * Complete the transaction by forwarding the key value
-		 * to the host. But first, cancel the timeout.
+		 * We use the message header information from
+		 * the user level daemon to transmit errors.
 		 */
-		if (cancel_delayed_work_sync(&kvp_work))
-			kvp_respond_to_host(data->data.key,
-					 data->data.value,
-					!strlen(data->data.key));
+		error = message->error;
+		break;
 	}
+
+	/*
+	 * Complete the transaction by forwarding the key value
+	 * to the host. But first, cancel the timeout.
+	 */
+	if (cancel_delayed_work_sync(&kvp_work))
+		kvp_respond_to_host(data->data.key, data->data.value, error);
 }
 
 static void
@@ -287,6 +357,7 @@ kvp_respond_to_host(char *key, char *value, int error)
 		 */
 		return;
 
+	icmsghdrp->status = error;
 
 	/*
 	 * If the error parameter is set, terminate the host's enumeration
@@ -294,15 +365,12 @@ kvp_respond_to_host(char *key, char *value, int error)
 	 */
 	if (error) {
 		/*
-		 * Something failed or the we have timedout;
-		 * terminate the current  host-side iteration.
+		 * Something failed or we have timedout;
+		 * terminate the current host-side iteration.
 		 */
-		icmsghdrp->status = HV_S_CONT;
 		goto response_done;
 	}
 
-	icmsghdrp->status = HV_S_OK;
-
 	kvp_msg = (struct hv_kvp_msg *)
 			&recv_buffer[sizeof(struct vmbuspipe_hdr) +
 			sizeof(struct icmsg_hdr)];
include/linux/hyperv.h +11 -6
index 11afc4e..b587c44 100644
@@ -181,6 +181,17 @@ enum hv_kvp_exchg_pool {
 	KVP_POOL_COUNT /* Number of pools, must be last. */
 };
 
+/*
+ * Some Hyper-V status codes.
+ */
+
+#define HV_S_OK				0x00000000
+#define HV_E_FAIL			0x80004005
+#define HV_S_CONT			0x80070103
+#define HV_ERROR_NOT_SUPPORTED		0x80070032
+#define HV_ERROR_MACHINE_LOCKED		0x800704F7
+#define HV_ERROR_DEVICE_NOT_CONNECTED	0x8007048F
+
 #define ADDR_FAMILY_NONE	0x00
 #define ADDR_FAMILY_IPV4	0x01
 #define ADDR_FAMILY_IPV6	0x02
@@ -1048,12 +1059,6 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
 #define ICMSGHDRFLAG_REQUEST		2
 #define ICMSGHDRFLAG_RESPONSE		4
 
-#define HV_S_OK				0x00000000
-#define HV_E_FAIL			0x80004005
-#define HV_S_CONT			0x80070103
-#define HV_ERROR_NOT_SUPPORTED		0x80070032
-#define HV_ERROR_MACHINE_LOCKED		0x800704F7
-#define HV_ERROR_DEVICE_NOT_CONNECTED	0x8007048F
 
 /*
  * While we want to handle util services as regular devices,
tools/hv/hv_kvp_daemon.c +33 -33

162 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#8 lore raw

PATCH v2 4/18 Drivers: hv: kvp: Support the new IP injection messages

In reply to K. Y. Srinivasan

Implement support for the new IP injection messages in the driver code.

---
 drivers/hv/hv_kvp.c |  143 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 137 insertions(+), 6 deletions(-)
drivers/hv/hv_kvp.c +137 -6
index eb4d073..810f176 100644
@@ -63,7 +63,7 @@ static int dm_reg_value;
 static void kvp_send_key(struct work_struct *dummy);
 
 
-static void kvp_respond_to_host(char *key, char *value, int error);
+static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
 static void kvp_work_func(struct work_struct *dummy);
 static void kvp_register(int);
 
@@ -108,7 +108,7 @@ kvp_work_func(struct work_struct *dummy)
 	 * If the timer fires, the user-mode component has not responded;
 	 * process the pending transaction.
 	 */
-	kvp_respond_to_host("Unknown key", "Guest timed out", HV_E_FAIL);
+	kvp_respond_to_host(NULL, HV_E_FAIL);
 }
 
 static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -199,9 +199,120 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
 	 * to the host. But first, cancel the timeout.
 	 */
 	if (cancel_delayed_work_sync(&kvp_work))
-		kvp_respond_to_host(data->data.key, data->data.value, error);
+		kvp_respond_to_host(message, error);
 }
 
+
+static int process_ob_ipinfo(void *in_msg, void *out_msg, int op)
+{
+	struct hv_kvp_msg *in = in_msg;
+	struct hv_kvp_ip_msg *out = out_msg;
+	int len;
+
+	switch (op) {
+	case KVP_OP_GET_IP_INFO:
+		/*
+		 * Transform all parameters into utf16 encoding.
+		 */
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.ip_addr,
+				strlen((char *)in->body.kvp_ip_val.ip_addr),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.sub_net,
+				strlen((char *)in->body.kvp_ip_val.sub_net),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.gate_way,
+				strlen((char *)in->body.kvp_ip_val.gate_way),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.dns_addr,
+				strlen((char *)in->body.kvp_ip_val.dns_addr),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.adapter_id,
+				strlen((char *)in->body.kvp_ip_val.adapter_id),
+				UTF16_HOST_ENDIAN,
+				(wchar_t *)out->kvp_ip_val.adapter_id,
+				MAX_IP_ADDR_SIZE);
+		if (len < 0)
+			return len;
+
+		out->kvp_ip_val.dhcp_enabled =
+			in->body.kvp_ip_val.dhcp_enabled;
+	}
+
+	return 0;
+}
+
+static void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
+{
+	struct hv_kvp_ip_msg *in = in_msg;
+	struct hv_kvp_msg *out = out_msg;
+
+	switch (op) {
+	case KVP_OP_SET_IP_INFO:
+		/*
+		 * Transform all parameters into utf8 encoding.
+		 */
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.ip_addr,
+				MAX_IP_ADDR_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.sub_net,
+				MAX_IP_ADDR_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.gate_way,
+				MAX_GATEWAY_SIZE);
+
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.dns_addr,
+				MAX_IP_ADDR_SIZE);
+
+		out->body.kvp_ip_val.dhcp_enabled =
+			in->kvp_ip_val.dhcp_enabled;
+
+	default:
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE);
+
+		out->body.kvp_ip_val.addr_family =
+		in->kvp_ip_val.addr_family;
+	}
+}
+
+
+
+
 static void
 kvp_send_key(struct work_struct *dummy)
 {
@@ -237,6 +348,12 @@ kvp_send_key(struct work_struct *dummy)
 	 */
 
 	switch (message->kvp_hdr.operation) {
+	case KVP_OP_SET_IP_INFO:
+		process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
+		break;
+	case KVP_OP_GET_IP_INFO:
+		process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
+		break;
 	case KVP_OP_SET:
 		switch (in_msg->body.kvp_set.data.value_type) {
 		case REG_SZ:
@@ -313,17 +430,19 @@ kvp_send_key(struct work_struct *dummy)
  */
 
 static void
-kvp_respond_to_host(char *key, char *value, int error)
+kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error)
 {
 	struct hv_kvp_msg  *kvp_msg;
 	struct hv_kvp_exchg_msg_value  *kvp_data;
 	char	*key_name;
+	char	*value;
 	struct icmsg_hdr *icmsghdrp;
 	int	keylen = 0;
 	int	valuelen = 0;
 	u32	buf_len;
 	struct vmbus_channel *channel;
 	u64	req_id;
+	int ret;
 
 	/*
 	 * If a transaction is not active; log and return.
@@ -376,6 +495,16 @@ kvp_respond_to_host(char *key, char *value, int error)
 			sizeof(struct icmsg_hdr)];
 
 	switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
+	case KVP_OP_GET_IP_INFO:
+		ret = process_ob_ipinfo(msg_to_host,
+				 (struct hv_kvp_ip_msg *)kvp_msg,
+				 KVP_OP_GET_IP_INFO);
+		if (ret < 0)
+			icmsghdrp->status = HV_E_FAIL;
+
+		goto response_done;
+	case KVP_OP_SET_IP_INFO:
+		goto response_done;
 	case KVP_OP_GET:
 		kvp_data = &kvp_msg->body.kvp_get.data;
 		goto copy_value;
@@ -389,7 +518,7 @@ kvp_respond_to_host(char *key, char *value, int error)
 	}
 
 	kvp_data = &kvp_msg->body.kvp_enum_data.data;
-	key_name = key;
+	key_name = msg_to_host->body.kvp_enum_data.data.key;
 
 	/*
 	 * The windows host expects the key/value pair to be encoded
@@ -403,6 +532,7 @@ kvp_respond_to_host(char *key, char *value, int error)
 	kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
 
 copy_value:
+	value = msg_to_host->body.kvp_enum_data.data.value;
 	valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
 				(wchar_t *) kvp_data->value,
 				(HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
@@ -455,7 +585,8 @@ void hv_kvp_onchannelcallback(void *context)
 		return;
 	}
 
-	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
+	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+			 &requestid);
 
 	if (recvlen > 0) {
 		icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
Signature · 1 line
1.7.4.1
#9 lore raw

Re: [PATCH V2 04/18] Drivers: hv: kvp: Support the new IP injection messages

drivers/hv/hv_kvp.c kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) · line 309

Quoted 9 lines · K. Y. Srinivasan
drivers/hv/hv_kvp.c +9 -0
+	default:
+		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE,
+				UTF16_LITTLE_ENDIAN,
+				(__u8 *)out->body.kvp_ip_val.adapter_id,
+				MAX_ADAPTER_ID_SIZE);
+
+		out->body.kvp_ip_val.addr_family =
+		in->kvp_ip_val.addr_family;

That's some wierd indenting, did you really mean to do that?

greg k-h

#10 lore raw

PATCH v2 5/18 Tools: hv: Prepare to expand kvp_get_ip_address() functionality

In reply to K. Y. Srinivasan

kvp_get_ip_address() implemented the functionality to retrieve IP address info. Make this function more generic so that we could retrieve additional per-interface information.

---
 tools/hv/hv_kvp_daemon.c |  129 ++++++++++++++++++++++++++++++----------------
 1 files changed, 84 insertions(+), 45 deletions(-)
tools/hv/hv_kvp_daemon.c +84 -45
index 069e2b3..3af37f0 100644
@@ -492,7 +492,8 @@ done:
 }
 
 static int
-kvp_get_ip_address(int family, char *buffer, int length)
+kvp_get_ip_address(int family, char *if_name, int op,
+		 void  *out_buffer, int length)
 {
 	struct ifaddrs *ifap;
 	struct ifaddrs *curp;
@@ -502,10 +503,19 @@ kvp_get_ip_address(int family, char *buffer, int length)
 	const char *str;
 	char tmp[50];
 	int error = 0;
-
+	char *buffer;
+	struct hv_kvp_ipaddr_value *ip_buffer;
+
+	if (op == KVP_OP_ENUMERATE) {
+		buffer = out_buffer;
+	} else {
+		ip_buffer = out_buffer;
+		buffer = (char *)ip_buffer->ip_addr;
+		ip_buffer->addr_family = 0;
+	}
 	/*
 	 * On entry into this function, the buffer is capable of holding the
-	 * maximum key value (2048 bytes).
+	 * maximum key value.
 	 */
 
 	if (getifaddrs(&ifap)) {
@@ -515,58 +525,87 @@ kvp_get_ip_address(int family, char *buffer, int length)
 
 	curp = ifap;
 	while (curp != NULL) {
-		if ((curp->ifa_addr != NULL) &&
-		   (curp->ifa_addr->sa_family == family)) {
-			if (family == AF_INET) {
-				struct sockaddr_in *addr =
-				(struct sockaddr_in *) curp->ifa_addr;
-
-				str = inet_ntop(family, &addr->sin_addr,
-						tmp, 50);
-				if (str == NULL) {
-					strcpy(buffer, "inet_ntop failed\n");
-					error = 1;
-					goto getaddr_done;
-				}
-				if (offset == 0)
-					strcpy(buffer, tmp);
-				else
-					strcat(buffer, tmp);
-				strcat(buffer, ";");
+		if (curp->ifa_addr == NULL) {
+			curp = curp->ifa_next;
+			continue;
+		}
 
-				offset += strlen(str) + 1;
-				if ((length - offset) < (ipv4_len + 1))
-					goto getaddr_done;
+		if ((if_name != NULL) &&
+			(strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
+			/*
+			 * We want info about a specific interface;
+			 * just continue.
+			 */
+			curp = curp->ifa_next;
+			continue;
+		}
 
-			} else {
+		/*
+		 * We only support two address families: AF_INET and AF_INET6.
+		 * If a family value of 0 is specified, we collect both
+		 * supported address families; if not we gather info on
+		 * the specified address family.
+		 */
+		if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
+			curp = curp->ifa_next;
+			continue;
+		}
+		if ((curp->ifa_addr->sa_family != AF_INET) &&
+			(curp->ifa_addr->sa_family != AF_INET6)) {
+			curp = curp->ifa_next;
+			continue;
+		}
+
+		if ((curp->ifa_addr->sa_family == AF_INET) &&
+			((family == AF_INET) || (family == 0))) {
+			struct sockaddr_in *addr =
+			(struct sockaddr_in *) curp->ifa_addr;
+
+			str = inet_ntop(AF_INET, &addr->sin_addr, tmp, 50);
+			if (str == NULL) {
+				strcpy(buffer, "inet_ntop failed\n");
+				error = 1;
+				goto getaddr_done;
+			}
+			if (offset == 0)
+				strcpy(buffer, tmp);
+			else
+				strcat(buffer, tmp);
+			strcat(buffer, ";");
+
+			offset += strlen(str) + 1;
+			if ((length - offset) < (ipv4_len + 1))
+				goto getaddr_done;
+
+		} else if ((family == AF_INET6) || (family == 0)) {
 
 			/*
 			 * We only support AF_INET and AF_INET6
 			 * and the list of addresses is separated by a ";".
 			 */
-				struct sockaddr_in6 *addr =
+			struct sockaddr_in6 *addr =
 				(struct sockaddr_in6 *) curp->ifa_addr;
 
-				str = inet_ntop(family,
+			str = inet_ntop(AF_INET6,
 					&addr->sin6_addr.s6_addr,
 					tmp, 50);
-				if (str == NULL) {
-					strcpy(buffer, "inet_ntop failed\n");
-					error = 1;
-					goto getaddr_done;
-				}
-				if (offset == 0)
-					strcpy(buffer, tmp);
-				else
-					strcat(buffer, tmp);
-				strcat(buffer, ";");
-				offset += strlen(str) + 1;
-				if ((length - offset) < (ipv6_len + 1))
-					goto getaddr_done;
-
+			if (str == NULL) {
+				strcpy(buffer, "inet_ntop failed\n");
+				error = 1;
+				goto getaddr_done;
 			}
+			if (offset == 0)
+				strcpy(buffer, tmp);
+			else
+				strcat(buffer, tmp);
+			strcat(buffer, ";");
+			offset += strlen(str) + 1;
+			if ((length - offset) < (ipv6_len + 1))
+				goto getaddr_done;
 
 		}
+
+
 		curp = curp->ifa_next;
 	}
 
@@ -811,13 +850,13 @@ int main(void)
 			strcpy(key_value, lic_version);
 			break;
 		case NetworkAddressIPv4:
-			kvp_get_ip_address(AF_INET, key_value,
-					HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
+			kvp_get_ip_address(AF_INET, NULL, KVP_OP_ENUMERATE,
+				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 			strcpy(key_name, "NetworkAddressIPv4");
 			break;
 		case NetworkAddressIPv6:
-			kvp_get_ip_address(AF_INET6, key_value,
-					HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
+			kvp_get_ip_address(AF_INET6, NULL, KVP_OP_ENUMERATE,
+				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 			strcpy(key_name, "NetworkAddressIPv6");
 			break;
 		case OSBuildNumber:
Signature · 1 line
1.7.4.1
#11 lore raw

PATCH v2 6/18 Tools: hv: Further refactor kvp_get_ip_address()

In reply to K. Y. Srinivasan

In preparation for making kvp_get_ip_address() more generic, factor out the code for handling IP addresses.

---
 tools/hv/hv_kvp_daemon.c |   94 ++++++++++++++++++++-------------------------
 1 files changed, 42 insertions(+), 52 deletions(-)
tools/hv/hv_kvp_daemon.c +42 -52
index 3af37f0..3dc989f 100644
@@ -491,17 +491,50 @@ done:
 	return;
 }
 
+static int kvp_process_ip_address(void *addrp,
+				int family, char *buffer,
+				int length,  int *offset)
+{
+	struct sockaddr_in *addr;
+	struct sockaddr_in6 *addr6;
+	int addr_length;
+	char tmp[50];
+	const char *str;
+
+	if (family == AF_INET) {
+		addr = (struct sockaddr_in *)addrp;
+		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
+		addr_length = INET_ADDRSTRLEN;
+	} else {
+		addr6 = (struct sockaddr_in6 *)addrp;
+		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
+		addr_length = INET6_ADDRSTRLEN;
+	}
+
+	if ((length - *offset) < addr_length + 1)
+		return 1;
+	if (str == NULL) {
+		strcpy(buffer, "inet_ntop failed\n");
+		return 1;
+	}
+	if (*offset == 0)
+		strcpy(buffer, tmp);
+	else
+		strcat(buffer, tmp);
+	strcat(buffer, ";");
+
+	*offset += strlen(str) + 1;
+	return 0;
+}
+
 static int
 kvp_get_ip_address(int family, char *if_name, int op,
 		 void  *out_buffer, int length)
 {
 	struct ifaddrs *ifap;
 	struct ifaddrs *curp;
-	int ipv4_len = strlen("255.255.255.255") + 1;
-	int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
 	int offset = 0;
 	const char *str;
-	char tmp[50];
 	int error = 0;
 	char *buffer;
 	struct hv_kvp_ipaddr_value *ip_buffer;
@@ -556,55 +589,12 @@ kvp_get_ip_address(int family, char *if_name, int op,
 			continue;
 		}
 
-		if ((curp->ifa_addr->sa_family == AF_INET) &&
-			((family == AF_INET) || (family == 0))) {
-			struct sockaddr_in *addr =
-			(struct sockaddr_in *) curp->ifa_addr;
-
-			str = inet_ntop(AF_INET, &addr->sin_addr, tmp, 50);
-			if (str == NULL) {
-				strcpy(buffer, "inet_ntop failed\n");
-				error = 1;
-				goto getaddr_done;
-			}
-			if (offset == 0)
-				strcpy(buffer, tmp);
-			else
-				strcat(buffer, tmp);
-			strcat(buffer, ";");
-
-			offset += strlen(str) + 1;
-			if ((length - offset) < (ipv4_len + 1))
-				goto getaddr_done;
-
-		} else if ((family == AF_INET6) || (family == 0)) {
-
-			/*
-			 * We only support AF_INET and AF_INET6
-			 * and the list of addresses is separated by a ";".
-			 */
-			struct sockaddr_in6 *addr =
-				(struct sockaddr_in6 *) curp->ifa_addr;
-
-			str = inet_ntop(AF_INET6,
-					&addr->sin6_addr.s6_addr,
-					tmp, 50);
-			if (str == NULL) {
-				strcpy(buffer, "inet_ntop failed\n");
-				error = 1;
-				goto getaddr_done;
-			}
-			if (offset == 0)
-				strcpy(buffer, tmp);
-			else
-				strcat(buffer, tmp);
-			strcat(buffer, ";");
-			offset += strlen(str) + 1;
-			if ((length - offset) < (ipv6_len + 1))
-				goto getaddr_done;
-
-		}
-
+		error = kvp_process_ip_address(curp->ifa_addr,
+						curp->ifa_addr->sa_family,
+						buffer,
+						length, &offset);
+		if (error)
+			goto getaddr_done;
 
 		curp = curp->ifa_next;
 	}
Signature · 1 line
1.7.4.1
#12 lore raw

Re: [PATCH V2 06/18] Tools: hv: Further refactor kvp_get_ip_address()

Quoted 7 lines · K. Y. Srinivasan

In preparation for making kvp_get_ip_address() more generic, factor out the code for handling IP addresses.

I looked at your last patch set, so in a sense these have been reviewed by me. But the 'Reviewed-by' line in a commit message means the reviewer thinks it's OK; the reviewer must say that, and I didn't.

Ben.

Quoted 124 lines
---
 tools/hv/hv_kvp_daemon.c |   94 ++++++++++++++++++++-------------------------
 1 files changed, 42 insertions(+), 52 deletions(-)
tools/hv/hv_kvp_daemon.c +42 -52
index 3af37f0..3dc989f 100644
@@ -491,17 +491,50 @@ done:
 	return;
 }
 
+static int kvp_process_ip_address(void *addrp,
+				int family, char *buffer,
+				int length,  int *offset)
+{
+	struct sockaddr_in *addr;
+	struct sockaddr_in6 *addr6;
+	int addr_length;
+	char tmp[50];
+	const char *str;
+
+	if (family == AF_INET) {
+		addr = (struct sockaddr_in *)addrp;
+		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
+		addr_length = INET_ADDRSTRLEN;
+	} else {
+		addr6 = (struct sockaddr_in6 *)addrp;
+		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
+		addr_length = INET6_ADDRSTRLEN;
+	}
+
+	if ((length - *offset) < addr_length + 1)
+		return 1;
+	if (str == NULL) {
+		strcpy(buffer, "inet_ntop failed\n");
+		return 1;
+	}
+	if (*offset == 0)
+		strcpy(buffer, tmp);
+	else
+		strcat(buffer, tmp);
+	strcat(buffer, ";");
+
+	*offset += strlen(str) + 1;
+	return 0;
+}
+
 static int
 kvp_get_ip_address(int family, char *if_name, int op,
 		 void  *out_buffer, int length)
 {
 	struct ifaddrs *ifap;
 	struct ifaddrs *curp;
-	int ipv4_len = strlen("255.255.255.255") + 1;
-	int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
 	int offset = 0;
 	const char *str;
-	char tmp[50];
 	int error = 0;
 	char *buffer;
 	struct hv_kvp_ipaddr_value *ip_buffer;
@@ -556,55 +589,12 @@ kvp_get_ip_address(int family, char *if_name, int op,
 			continue;
 		}
 
-		if ((curp->ifa_addr->sa_family == AF_INET) &&
-			((family == AF_INET) || (family == 0))) {
-			struct sockaddr_in *addr =
-			(struct sockaddr_in *) curp->ifa_addr;
-
-			str = inet_ntop(AF_INET, &addr->sin_addr, tmp, 50);
-			if (str == NULL) {
-				strcpy(buffer, "inet_ntop failed\n");
-				error = 1;
-				goto getaddr_done;
-			}
-			if (offset == 0)
-				strcpy(buffer, tmp);
-			else
-				strcat(buffer, tmp);
-			strcat(buffer, ";");
-
-			offset += strlen(str) + 1;
-			if ((length - offset) < (ipv4_len + 1))
-				goto getaddr_done;
-
-		} else if ((family == AF_INET6) || (family == 0)) {
-
-			/*
-			 * We only support AF_INET and AF_INET6
-			 * and the list of addresses is separated by a ";".
-			 */
-			struct sockaddr_in6 *addr =
-				(struct sockaddr_in6 *) curp->ifa_addr;
-
-			str = inet_ntop(AF_INET6,
-					&addr->sin6_addr.s6_addr,
-					tmp, 50);
-			if (str == NULL) {
-				strcpy(buffer, "inet_ntop failed\n");
-				error = 1;
-				goto getaddr_done;
-			}
-			if (offset == 0)
-				strcpy(buffer, tmp);
-			else
-				strcat(buffer, tmp);
-			strcat(buffer, ";");
-			offset += strlen(str) + 1;
-			if ((length - offset) < (ipv6_len + 1))
-				goto getaddr_done;
-
-		}
-
+		error = kvp_process_ip_address(curp->ifa_addr,
+						curp->ifa_addr->sa_family,
+						buffer,
+						length, &offset);
+		if (error)
+			goto getaddr_done;
 
 		curp = curp->ifa_next;
 	}
Signature · 2 lines
Ben Hutchings
I say we take off; nuke the site from orbit.  It's the only way to be sure.
#13 lore raw

RE: [PATCH V2 06/18] Tools: hv: Further refactor kvp_get_ip_address()

Quoted 15 lines

-----Original Message-----
From: Ben Hutchings [mailto:[email protected]]
Sent: Monday, August 13, 2012 9:46 PM
To: KY Srinivasan
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH V2 06/18] Tools: hv: Further refactor kvp_get_ip_address()

Quoted 3 lines · K. Y. Srinivasan

In preparation for making kvp_get_ip_address() more generic, factor out the code for handling IP addresses.

Quoted 8 lines
Quoted 4 lines

I looked at your last patch set, so in a sense these have been reviewed by me. But the 'Reviewed-by' line in a commit message means the reviewer thinks it's OK; the reviewer must say that, and I didn't.

My mistake, sorry about that.

Regards,

K. Y

#14 lore raw

PATCH v2 7/18 Tools: hv: Gather address family information

In reply to K. Y. Srinivasan

Now, gather address family information for the specified interface.

---
 tools/hv/hv_kvp_daemon.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)
tools/hv/hv_kvp_daemon.c +11 -0
index 3dc989f..13ae098 100644
@@ -589,6 +589,17 @@ kvp_get_ip_address(int family, char *if_name, int op,
 			continue;
 		}
 
+		if (op == KVP_OP_GET_IP_INFO) {
+			/*
+			 * Gather info other than the IP address.
+			 * IP address info will be gathered later.
+			 */
+			if (curp->ifa_addr->sa_family == AF_INET)
+				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
+			else
+				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
+		}
+
 		error = kvp_process_ip_address(curp->ifa_addr,
 						curp->ifa_addr->sa_family,
 						buffer,
Signature · 1 line
1.7.4.1
#15 lore raw

PATCH v2 8/18 Tools: hv: Gather subnet information

In reply to K. Y. Srinivasan

Now, gather sub-net information for the specified interface.

---
 tools/hv/hv_kvp_daemon.c |   31 +++++++++++++++++++++++++++++--
 1 files changed, 29 insertions(+), 2 deletions(-)
tools/hv/hv_kvp_daemon.c +29 -2
index 13ae098..de1724c 100644
@@ -534,6 +534,7 @@ kvp_get_ip_address(int family, char *if_name, int op,
 	struct ifaddrs *ifap;
 	struct ifaddrs *curp;
 	int offset = 0;
+	int sn_offset = 0;
 	const char *str;
 	int error = 0;
 	char *buffer;
@@ -594,12 +595,38 @@ kvp_get_ip_address(int family, char *if_name, int op,
 			 * Gather info other than the IP address.
 			 * IP address info will be gathered later.
 			 */
-			if (curp->ifa_addr->sa_family == AF_INET)
+			if (curp->ifa_addr->sa_family == AF_INET) {
 				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
-			else
+				/*
+				 * Get subnet info.
+				 */
+				error = kvp_process_ip_address(
+							     curp->ifa_netmask,
+							     AF_INET,
+							     (char *)
+							     ip_buffer->sub_net,
+							     length,
+							     &sn_offset);
+				if (error)
+					goto gather_ipaddr;
+			} else {
 				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
+				/*
+				 * Get subnet info.
+				 */
+				error = kvp_process_ip_address(
+							     curp->ifa_netmask,
+							     AF_INET6,
+							     (char *)
+							     ip_buffer->sub_net,
+							     length,
+							     &sn_offset);
+				if (error)
+					goto gather_ipaddr;
+			}
 		}
 
+gather_ipaddr:
 		error = kvp_process_ip_address(curp->ifa_addr,
 						curp->ifa_addr->sa_family,
 						buffer,
Signature · 1 line
1.7.4.1
#16 lore raw

PATCH v2 9/18 Tools: hv: Represent the ipv6 mask using CIDR notation

In reply to K. Y. Srinivasan

Transform ipv6 subnet information to CIDR notation.

---
 tools/hv/hv_kvp_daemon.c |   46 ++++++++++++++++++++++++++++++++++++----------
 1 files changed, 36 insertions(+), 10 deletions(-)
tools/hv/hv_kvp_daemon.c +36 -10
index de1724c..a63e83a 100644
@@ -491,6 +491,15 @@ done:
 	return;
 }
 
+static unsigned int hweight32(unsigned int *w)
+{
+	unsigned int res = *w - ((*w >> 1) & 0x55555555);
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res + (res >> 4)) & 0x0F0F0F0F;
+	res = res + (res >> 8);
+	return (res + (res >> 16)) & 0x000000FF;
+}
+
 static int kvp_process_ip_address(void *addrp,
 				int family, char *buffer,
 				int length,  int *offset)
@@ -535,10 +544,15 @@ kvp_get_ip_address(int family, char *if_name, int op,
 	struct ifaddrs *curp;
 	int offset = 0;
 	int sn_offset = 0;
-	const char *str;
 	int error = 0;
 	char *buffer;
 	struct hv_kvp_ipaddr_value *ip_buffer;
+	char cidr_mask[5]; /* /xyz */
+	int weight;
+	int i;
+	unsigned int *w;
+	char *sn_str;
+	struct sockaddr_in6 *addr6;
 
 	if (op == KVP_OP_ENUMERATE) {
 		buffer = out_buffer;
@@ -611,18 +625,30 @@ kvp_get_ip_address(int family, char *if_name, int op,
 					goto gather_ipaddr;
 			} else {
 				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
+
 				/*
-				 * Get subnet info.
+				 * Get subnet info in CIDR format.
 				 */
-				error = kvp_process_ip_address(
-							     curp->ifa_netmask,
-							     AF_INET6,
-							     (char *)
-							     ip_buffer->sub_net,
-							     length,
-							     &sn_offset);
-				if (error)
+				weight = 0;
+				sn_str = (char *)ip_buffer->sub_net;
+				addr6 = (struct sockaddr_in6 *)
+					curp->ifa_netmask;
+				w = addr6->sin6_addr.s6_addr32;
+
+				for (i = 0; i < 4; i++)
+					weight += hweight32(&w[i]);
+
+				sprintf(cidr_mask, "/%d", weight);
+				if ((length - sn_offset) <
+					(strlen(cidr_mask) + 1))
 					goto gather_ipaddr;
+
+				if (sn_offset == 0)
+					strcpy(sn_str, cidr_mask);
+				else
+					strcat(sn_str, cidr_mask);
+				strcat((char *)ip_buffer->sub_net, ";");
+				sn_offset += strlen(sn_str) + 1;
 			}
 		}
 
Signature · 1 line
1.7.4.1
#17 lore raw

PATCH v2 10/18 Tools: hv: Gather ipv[4,6] gateway information

In reply to K. Y. Srinivasan

Gather information on the default gateways - ipv4/ipv6.

---
 tools/hv/hv_kvp_daemon.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 68 insertions(+), 0 deletions(-)
tools/hv/hv_kvp_daemon.c +68 -0
index a63e83a..65d54c8 100644
@@ -491,6 +491,68 @@ done:
 	return;
 }
 
+static void kvp_process_ipconfig_file(char *cmd,
+					char *config_buf, int len,
+					int element_size, int offset)
+{
+	char buf[256];
+	char *p;
+	char *x;
+	FILE *file;
+
+	/*
+	 * First execute the command.
+	 */
+	file = popen(cmd, "r");
+	if (file == NULL)
+		return;
+
+	if (offset == 0)
+		memset(config_buf, 0, len);
+	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
+		if ((len - strlen(config_buf)) < (element_size + 1))
+			break;
+
+		x = strchr(p, '\n');
+		*x = '\0';
+		strcat(config_buf, p);
+		strcat(config_buf, ";");
+	}
+	pclose(file);
+}
+
+static void kvp_get_ipconfig_info(char *if_name,
+				 struct hv_kvp_ipaddr_value *buffer)
+{
+	char cmd[512];
+
+	/*
+	 * Get the address of default gateway (ipv4).
+	 */
+	sprintf(cmd, "%s %s", "ip route show dev", if_name);
+	strcat(cmd, " | awk '/default/ {print $3 }'");
+
+	/*
+	 * Execute the command to gather gateway info.
+	 */
+	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
+				(MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
+
+	/*
+	 * Get the address of default gateway (ipv6).
+	 */
+	sprintf(cmd, "%s %s", "ip -f inet6  route show dev", if_name);
+	strcat(cmd, " | awk '/default/ {print $3 }'");
+
+	/*
+	 * Execute the command to gather gateway info (ipv6).
+	 */
+	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
+				(MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
+
+}
+
+
 static unsigned int hweight32(unsigned int *w)
 {
 	unsigned int res = *w - ((*w >> 1) & 0x55555555);
@@ -650,6 +712,12 @@ kvp_get_ip_address(int family, char *if_name, int op,
 				strcat((char *)ip_buffer->sub_net, ";");
 				sn_offset += strlen(sn_str) + 1;
 			}
+
+			/*
+			 * Collect other ip related configuration info.
+			 */
+
+			kvp_get_ipconfig_info(if_name, ip_buffer);
 		}
 
 gather_ipaddr:
Signature · 1 line
1.7.4.1
#18 lore raw

PATCH v2 11/18 Tools: hv: Gather DNS information

In reply to K. Y. Srinivasan

Now, gather DNS information. Invoke an external script (that can be distro dependent) to gather the DNS information.

---
 tools/hv/hv_kvp_daemon.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)
tools/hv/hv_kvp_daemon.c +23 -0
index 65d54c8..2f8e0b9 100644
@@ -550,6 +550,29 @@ static void kvp_get_ipconfig_info(char *if_name,
 	kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
 				(MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
 
+
+	/*
+	 * Gather the DNS  state.
+	 * Since there is no standard way to get this information
+	 * across various distributions of interest; we just invoke
+	 * an external script that needs to be ported across distros
+	 * of interest.
+	 *
+	 * Following is the expected format of the information from the script:
+	 *
+	 * ipaddr1 (nameserver1)
+	 * ipaddr2 (nameserver2)
+	 * .
+	 * .
+	 */
+
+	sprintf(cmd, "%s",  "hv_get_dns_info");
+
+	/*
+	 * Execute the command to gather DNS info.
+	 */
+	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
+				(MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
 }
 
 
Signature · 1 line
1.7.4.1
#19 lore raw

PATCH v2 12/18 Tools: hv: Gather DHCP information

In reply to K. Y. Srinivasan

Collect information on dhcp setting for the specified interface. We invoke an external script to get this information.

---
 tools/hv/hv_kvp_daemon.c |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
tools/hv/hv_kvp_daemon.c +31 -0
index 2f8e0b9..8a18819 100644
@@ -525,6 +525,9 @@ static void kvp_get_ipconfig_info(char *if_name,
 				 struct hv_kvp_ipaddr_value *buffer)
 {
 	char cmd[512];
+	char dhcp_info[128];
+	char *p;
+	FILE *file;
 
 	/*
 	 * Get the address of default gateway (ipv4).
@@ -573,6 +576,34 @@ static void kvp_get_ipconfig_info(char *if_name,
 	 */
 	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
 				(MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
+
+	/*
+	 * Gather the DHCP state.
+	 * We will gather this state by invoking an external script.
+	 * The parameter to the script is the interface name.
+	 * Here is the expected output:
+	 *
+	 * Enabled: DHCP enabled.
+	 */
+
+	sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
+
+	file = popen(cmd, "r");
+	if (file == NULL)
+		return;
+
+	p = fgets(dhcp_info, sizeof(dhcp_info), file);
+	if (p == NULL) {
+		pclose(file);
+		return;
+	}
+
+	if (!strncmp(p, "Enabled", 7))
+		buffer->dhcp_enabled = 1;
+	else
+		buffer->dhcp_enabled = 0;
+
+	pclose(file);
 }
 
 
Signature · 1 line
1.7.4.1
#20 lore raw

PATCH v2 13/18 Tools: hv: Implement the KVP verb - KVP_OP_SET_IP_INFO

In reply to K. Y. Srinivasan

Implement the KVP verb - KVP_OP_SET_IP_INFO. This operation configures the specified interface based on the given configuration. Since configuring an interface is very distro specific, we invoke an external script to configure the interface.

---
 include/linux/hyperv.h   |    2 +
 tools/hv/hv_kvp_daemon.c |  443 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 445 insertions(+), 0 deletions(-)
include/linux/hyperv.h +2 -0
index b587c44..588d8f2 100644
@@ -191,6 +191,8 @@ enum hv_kvp_exchg_pool {
 #define HV_ERROR_NOT_SUPPORTED		0x80070032
 #define HV_ERROR_MACHINE_LOCKED		0x800704F7
 #define HV_ERROR_DEVICE_NOT_CONNECTED	0x8007048F
+#define HV_INVALIDARG			0x80070057
+#define HV_GUID_NOTFOUND		0x80041002
 
 #define ADDR_FAMILY_NONE	0x00
 #define ADDR_FAMILY_IPV4	0x01
tools/hv/hv_kvp_daemon.c +443 -0

491 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#21 lore raw

PATCH v2 14/18 Tools: hv: Rename the function kvp_get_ip_address()

In reply to K. Y. Srinivasan

Rename the function kvp_get_ip_address() to better reflect the functionality being implemented.

---
 tools/hv/hv_kvp_daemon.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
tools/hv/hv_kvp_daemon.c +3 -3
index 59669a8..bb2a6c4 100644
@@ -766,7 +766,7 @@ static int kvp_process_ip_address(void *addrp,
 }
 
 static int
-kvp_get_ip_address(int family, char *if_name, int op,
+kvp_get_ip_info(int family, char *if_name, int op,
 		 void  *out_buffer, int length)
 {
 	struct ifaddrs *ifap;
@@ -1469,12 +1469,12 @@ int main(void)
 			strcpy(key_value, lic_version);
 			break;
 		case NetworkAddressIPv4:
-			kvp_get_ip_address(AF_INET, NULL, KVP_OP_ENUMERATE,
+			kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
 				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 			strcpy(key_name, "NetworkAddressIPv4");
 			break;
 		case NetworkAddressIPv6:
-			kvp_get_ip_address(AF_INET6, NULL, KVP_OP_ENUMERATE,
+			kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
 				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
 			strcpy(key_name, "NetworkAddressIPv6");
 			break;
Signature · 1 line
1.7.4.1
#22 lore raw

PATCH v2 15/18 Tools: hv: Implement the KVP verb - KVP_OP_GET_IP_INFO

In reply to K. Y. Srinivasan

Now implement the KVP verb - KVP_OP_GET_IP_INFO. This operation retrieves IP information for the specified interface.

---
 tools/hv/hv_kvp_daemon.c |   93 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 90 insertions(+), 3 deletions(-)
tools/hv/hv_kvp_daemon.c +90 -3
index bb2a6c4..e7db9ac 100644
@@ -604,6 +604,69 @@ static char *kvp_if_name_to_mac(char *if_name)
 }
 
 
+/*
+ * Retrieve the interface name given tha MAC address.
+ */
+
+static char *kvp_mac_to_if_name(char *mac)
+{
+	DIR *dir;
+	struct dirent *entry;
+	FILE    *file;
+	char    *p, *q, *x;
+	char    *if_name = NULL;
+	char    buf[256];
+	char *kvp_net_dir = "/sys/class/net/";
+	char dev_id[256];
+	int i;
+
+	dir = opendir(kvp_net_dir);
+	if (dir == NULL)
+		return NULL;
+
+	snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
+	q = dev_id + strlen(kvp_net_dir);
+
+	while ((entry = readdir(dir)) != NULL) {
+		/*
+		 * Set the state for the next pass.
+		 */
+		*q = '\0';
+
+		strcat(dev_id, entry->d_name);
+		strcat(dev_id, "/address");
+
+		file = fopen(dev_id, "r");
+		if (file == NULL)
+			continue;
+
+		p = fgets(buf, sizeof(buf), file);
+		if (p) {
+			x = strchr(p, '\n');
+			if (x)
+				*x = '\0';
+
+			for (i = 0; i < strlen(p); i++)
+				p[i] = toupper(p[i]);
+
+			if (!strcmp(p, mac)) {
+				/*
+				 * Found the MAC match; return the interface
+				 * name. The caller will free the memory.
+				 */
+				if_name = strdup(entry->d_name);
+				fclose(file);
+				break;
+			}
+		}
+		fclose(file);
+	}
+
+	closedir(dir);
+	return if_name;
+}
+
+
 static void kvp_process_ipconfig_file(char *cmd,
 					char *config_buf, int len,
 					int element_size, int offset)
@@ -750,10 +813,10 @@ static int kvp_process_ip_address(void *addrp,
 	}
 
 	if ((length - *offset) < addr_length + 1)
-		return 1;
+		return HV_E_FAIL;
 	if (str == NULL) {
 		strcpy(buffer, "inet_ntop failed\n");
-		return 1;
+		return HV_E_FAIL;
 	}
 	if (*offset == 0)
 		strcpy(buffer, tmp);
@@ -797,7 +860,7 @@ kvp_get_ip_info(int family, char *if_name, int op,
 
 	if (getifaddrs(&ifap)) {
 		strcpy(buffer, "getifaddrs failed\n");
-		return 1;
+		return HV_E_FAIL;
 	}
 
 	curp = ifap;
@@ -1387,6 +1450,30 @@ int main(void)
 		}
 
 		switch (op) {
+		case KVP_OP_GET_IP_INFO:
+			kvp_ip_val = &hv_msg->body.kvp_ip_val;
+			if_name =
+			kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
+
+			if (if_name == NULL) {
+				/*
+				 * We could not map the mac address to an
+				 * interface name; return error.
+				 */
+				hv_msg->error = HV_E_FAIL;
+				break;
+			}
+			error = kvp_get_ip_info(
+						0, if_name, KVP_OP_GET_IP_INFO,
+						kvp_ip_val,
+						(MAX_IP_ADDR_SIZE * 2));
+
+			if (error)
+				hv_msg->error = error;
+
+			free(if_name);
+			break;
+
 		case KVP_OP_SET_IP_INFO:
 			kvp_ip_val = &hv_msg->body.kvp_ip_val;
 			if_name = kvp_get_if_name(
Signature · 1 line
1.7.4.1
#23 lore raw

PATCH v2 16/18 Tools: hv: Get rid of some unused variables

In reply to K. Y. Srinivasan

Get rid of unused variables. I would like to thank Ben Hutchings for pointing out the issue ([email protected]).

---
 tools/hv/hv_kvp_daemon.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)
tools/hv/hv_kvp_daemon.c +1 -2
index e7db9ac..4a1428c 100644
@@ -211,7 +211,7 @@ static void kvp_update_mem_state(int pool)
 }
 static int kvp_file_init(void)
 {
-	int ret, fd;
+	int  fd;
 	FILE *filep;
 	size_t records_read;
 	__u8 *fname;
@@ -327,7 +327,6 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
 			int value_size)
 {
 	int i;
-	int j, k;
 	int num_records;
 	struct kvp_record *record;
 	int num_blocks;
Signature · 1 line
1.7.4.1
#24 lore raw

PATCH v2 17/18 Tools: hv: Correctly type string variables

In reply to K. Y. Srinivasan

Correctly type character strings. I would like to thank Ben Hutchings for pointing out the issue ([email protected]).

---
 tools/hv/hv_kvp_daemon.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
tools/hv/hv_kvp_daemon.c +4 -4
index 4a1428c..c8e1013 100644
@@ -101,8 +101,8 @@ static struct utsname uts_buf;
 #define ENTRIES_PER_BLOCK 50
 
 struct kvp_record {
-	__u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-	__u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+	char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+	char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
 };
 
 struct kvp_file_state {
@@ -110,7 +110,7 @@ struct kvp_file_state {
 	int num_blocks;
 	struct kvp_record *records;
 	int num_records;
-	__u8 fname[MAX_FILE_NAME];
+	char fname[MAX_FILE_NAME];
 };
 
 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
@@ -214,7 +214,7 @@ static int kvp_file_init(void)
 	int  fd;
 	FILE *filep;
 	size_t records_read;
-	__u8 *fname;
+	char *fname;
 	struct kvp_record *record;
 	struct kvp_record *readp;
 	int num_blocks;
Signature · 1 line
1.7.4.1
#25 lore raw

PATCH v2 18/18 Tools: hv: Properly manage open streams

In reply to K. Y. Srinivasan

Close the open streams properly.

---
 tools/hv/hv_kvp_daemon.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
tools/hv/hv_kvp_daemon.c +2 -2
index c8e1013..ca6424f 100644
@@ -160,7 +160,7 @@ static void kvp_update_file(int pool)
 				sizeof(struct kvp_record),
 				kvp_file_info[pool].num_records, filep);
 
-	fflush(filep);
+	fclose(filep);
 	kvp_release_lock(pool);
 }
 
@@ -206,7 +206,7 @@ static void kvp_update_mem_state(int pool)
 	kvp_file_info[pool].num_blocks = num_blocks;
 	kvp_file_info[pool].records = record;
 	kvp_file_info[pool].num_records = records_read;
-
+	fclose(filep);
 	kvp_release_lock(pool);
 }
 static int kvp_file_init(void)
Signature · 1 line
1.7.4.1
#26 lore raw

Re: [PATCH V2 18/18] Tools: hv: Properly manage open streams

Quoted 6 lines · K. Y. Srinivasan

Close the open streams properly.

This isn't reviewed by me, I'm the author!

Ben.

Quoted 26 lines
---
 tools/hv/hv_kvp_daemon.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
tools/hv/hv_kvp_daemon.c +2 -2
index c8e1013..ca6424f 100644
@@ -160,7 +160,7 @@ static void kvp_update_file(int pool)
 				sizeof(struct kvp_record),
 				kvp_file_info[pool].num_records, filep);
 
-	fflush(filep);
+	fclose(filep);
 	kvp_release_lock(pool);
 }
 
@@ -206,7 +206,7 @@ static void kvp_update_mem_state(int pool)
 	kvp_file_info[pool].num_blocks = num_blocks;
 	kvp_file_info[pool].records = record;
 	kvp_file_info[pool].num_records = records_read;
-
+	fclose(filep);
 	kvp_release_lock(pool);
 }
 static int kvp_file_init(void)
Signature · 2 lines
Ben Hutchings
I say we take off; nuke the site from orbit.  It's the only way to be sure.
#27 lore raw

RE: [PATCH V2 18/18] Tools: hv: Properly manage open streams

Quoted 12 lines

-----Original Message-----
From: Ben Hutchings [mailto:[email protected]]
Sent: Monday, August 13, 2012 9:58 PM
To: KY Srinivasan
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH V2 18/18] Tools: hv: Properly manage open streams

On Mon, 2012-08-13 at 10:07 -0700, K. Y. Srinivasan wrote:

Quoted 8 lines
Quoted 6 lines

Close the open streams properly.

This isn't reviewed by me, I'm the author!

I am truly sorry for this confusion. I was cleaning up the code based on the last set of comments I got from Olaf and I did not realize that you had authored this very patch! Perhaps we can drop this patch from this set.

Regards,

K. Y

Quoted 33 lines

Ben.

Quoted 18 lines
---
 tools/hv/hv_kvp_daemon.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
tools/hv/hv_kvp_daemon.c +1 -1
index c8e1013..ca6424f 100644
@@ -160,7 +160,7 @@ static void kvp_update_file(int pool)
 				sizeof(struct kvp_record),
 				kvp_file_info[pool].num_records, filep);
 
-	fflush(filep);
+	fclose(filep);
 	kvp_release_lock(pool);
 }
 

tools/hv/hv_kvp_daemon.c static void kvp_update_mem_state(int pool) · line 212

Quoted 8 lines
tools/hv/hv_kvp_daemon.c +1 -1
@@ -206,7 +206,7 @@ static void kvp_update_mem_state(int pool)
 	kvp_file_info[pool].num_blocks = num_blocks;
 	kvp_file_info[pool].records = record;
 	kvp_file_info[pool].num_records = records_read;
-
+	fclose(filep);
 	kvp_release_lock(pool);
 }
 static int kvp_file_init(void)

--
Ben Hutchings
I say we take off; nuke the site from orbit. It's the only way to be sure.

#28 lore raw
In reply to K. Y. Srinivasan
Quoted 21 lines · K. Y. Srinivasan

This patchset expands the KVP (Key Value Pair) functionality to implement the mechanism to GET/SET IP addresses in the guest. This functionality is used in Windows Server 2012 to implement VM replication functionality. The way IP configuration information is managed is distro specific. Based on the feedback I have gotten from Olaf, Greg, Steve, Ben and Mairus, I have chosen to seperate distro specific code from this patch-set. Most of the GET operation can be implemented in a way that is completely distro independent and I have implemented that as such and is included in this patch-set. Some of the attributes that can only be fetched in a distro dependent way as well the mechanism for configuring an interface (the SET operation) that is clearly distro specific is to be implemented via external scripts that will be invoked via the KVP code. We define here the interface to these scripts.

Adding support for IP injection resulted in some changes to the protocol between the user level daemon and the kernel driver. These changes have been implemented in way that would retain compatibility with older daemons. I would like to thank Olaf and Greg for pointing out the compatibility issue.

Quoted 7 lines

This version of the patch set addresses all of the comments that I have received to date from Olaf, Ben and others. Specifically, I have cleanedup all of the string manipulation code. Furthermore, I have also simplified the format of the interface configuration file that is generated by the KVP daemon and gotten rid of some constant strings that may not be relevant on all distros. I would like to thank Olaf and Ben for their detailed review.

I've applied some of these, care to resend the rest, with the change I pointed out, and get the reviewed-by: lines correct.

thanks,

greg k-h

#29 lore raw
Quoted 41 lines

-----Original Message-----
From: Greg KH [mailto:[email protected]]
Sent: Thursday, August 16, 2012 4:55 PM
To: KY Srinivasan
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH V2 00/18] drivers: hv: kvp

Quoted 21 lines · K. Y. Srinivasan

This patchset expands the KVP (Key Value Pair) functionality to implement the mechanism to GET/SET IP addresses in the guest. This functionality is used in Windows Server 2012 to implement VM replication functionality. The way IP configuration information is managed is distro specific. Based on the feedback I have gotten from Olaf, Greg, Steve, Ben and Mairus, I have chosen to seperate distro specific code from this patch-set. Most of the GET operation can be implemented in a way that is completely distro independent and I have implemented that as such and is included in this patch-set. Some of the attributes that can only be fetched in a distro dependent way as well the mechanism for configuring an interface (the SET operation) that is clearly distro specific is to be implemented via external scripts that will be invoked via the KVP code. We define here the interface to these scripts.

Adding support for IP injection resulted in some changes to the protocol between the user level daemon and the kernel driver. These changes have been implemented in way that would retain compatibility with older daemons. I would like to thank Olaf and Greg for pointing out the compatibility issue.

Quoted 7 lines

This version of the patch set addresses all of the comments that I have received to date from Olaf, Ben and others. Specifically, I have cleanedup all of the string manipulation code. Furthermore, I have also simplified the format of the interface configuration file that is generated by the KVP daemon and gotten rid of some constant strings that may not be relevant on all distros. I would like to thank Olaf and Ben for their detailed review.

Quoted 2 lines

I've applied some of these, care to resend the rest, with the change I pointed out, and get the reviewed-by: lines correct.

Will do.

Thanks,

K. Y

Quoted 6 lines

thanks,

greg k-h