[libvirt] [PATCH 2/2] macvtap: listen for netlink messages from lldpad

D. Herrendoerfer d.herrendoerfer at herrendoerfer.name
Fri Jan 20 14:56:27 UTC 2012


From: "D. Herrendoerfer" <d.herrendoerfer at herrendoerfer.name>

Make macvtap setup code register a callback to handle link status
changes sent by lldpad.

This is prototype code for reference only.

Signed-off-by: D. Herrendoerfer <d.herrendoerfer at herrendoerfer.name>
---
 src/util/virnetdevmacvlan.c |  161 ++++++++++++++++++++++++++++++++++++++++++-
 src/util/virnetdevmacvlan.h |    1 +
 2 files changed, 161 insertions(+), 1 deletions(-)

diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index 5e55b72..e4a280b 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -46,7 +46,6 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
               "passthrough")
 
 #if WITH_MACVTAP
-
 # include <stdint.h>
 # include <stdio.h>
 # include <errno.h>
@@ -57,6 +56,8 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
 # include <linux/if.h>
 # include <linux/if_tun.h>
 
+# include <c-ctype.h>
+
 /* Older kernels lacked this enum value.  */
 # if !HAVE_DECL_MACVLAN_MODE_PASSTHRU
 #  define MACVLAN_MODE_PASSTHRU 8
@@ -67,6 +68,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
 # include "uuid.h"
 # include "virfile.h"
 # include "netlink.h"
+# include "netlink-event.h"
 # include "virnetdev.h"
 
 # define MACVTAP_NAME_PREFIX	"macvtap"
@@ -75,6 +77,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
 # define MACVLAN_NAME_PREFIX	"macvlan"
 # define MACVLAN_NAME_PATTERN	"macvlan%d"
 
+
 /**
  * virNetDevMacVLanCreate:
  *
@@ -445,6 +448,142 @@ static const uint32_t modeMap[VIR_NETDEV_MACVLAN_MODE_LAST] = {
     [VIR_NETDEV_MACVLAN_MODE_PASSTHRU] = MACVLAN_MODE_PASSTHRU,
 };
 
+# define LLDPAD_PID_FILE  "/var/run/lldpad.pid"
+
+static uint32_t
+GetLldpadPid(void) {
+    int fd;
+    uint32_t pid = 0;
+
+    fd = open(LLDPAD_PID_FILE, O_RDONLY);
+    if (fd >= 0) {
+        char buffer[10];
+
+        if (saferead(fd, buffer, sizeof(buffer)) <= sizeof(buffer)) {
+            unsigned int res;
+            char *endptr;
+
+            if (virStrToLong_ui(buffer, &endptr, 10, &res) == 0
+                && (*endptr == '\0' || c_isspace(*endptr))
+                && res != 0) {
+                pid = res;
+            } else {
+                virNetDevError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("error parsing pid of lldpad"));
+            }
+        }
+    } else {
+        virReportSystemError(errno,
+                             _("Error opening file %s"), LLDPAD_PID_FILE);
+    }
+
+    VIR_FORCE_CLOSE(fd);
+
+    return pid;
+}
+
+/* Struct to hold the state and configuration of a 802.1qbg port */
+struct netlinkCallbackData {
+	char cr_ifname[64];
+	virNetDevVPortProfilePtr virtPortProfile;
+	const unsigned char *macaddress;
+	const char *linkdev;
+	const unsigned char *vmuuid;
+	enum virNetDevVPortProfileOp vmOp;
+	unsigned int linkState;
+};
+typedef struct netlinkCallbackData *netlinkCallbackDataPtr;
+
+/**
+ * virNetDevMacVLanVPortProfileCallback:
+ *
+ * @msg: The buffer containing the received netlink message
+ * @length: The length of the received netlink message.
+ * @peer: The netling sockaddr containing the peer information
+ * @handeled: Contains information if the message has been replied to yet
+ * @opaque: Contains vital information regarding the associated vm an interface
+ *
+ * This function is called when a netlink message is received. The function
+ * reads the message and responds if it is pertinent to the running VMs
+ * network interface.
+ */
+
+static void
+virNetDevMacVLanVPortProfileCallback( unsigned char *msg,
+											int length,
+		 	 	 	 	 	 	 	 	 	struct sockaddr_nl *peer,
+		 	 	 	 	 	 	 	 	 	int *handled,
+		 	 	 	 	 	 	 	 	 	void *opaque)
+{
+	/* ToDo : There is no valid lldpad message yet :(
+	 *
+	 * */
+
+	struct nlmsghdr *hdr;
+	void *data;
+	int i=0;
+    netlinkCallbackDataPtr calld = opaque;
+
+	VIR_INFO("Netlink message received from nl_sockaddr: %p", peer);
+
+	hdr = (struct nlmsghdr *) msg;
+    data = nlmsg_data(hdr);
+
+    /* Quickly decide if we want this or not */
+    if (hdr->nlmsg_pid != GetLldpadPid())
+    	return; // we only care for lldpad messages
+    if (hdr->nlmsg_type != RTM_SETLINK)
+    	return; // we only care for RTM_SETLINK
+    if (handled != 0)
+    	return; // if it has been handeled - dont handle again
+
+    /* DEBUG start */
+    VIR_INFO("buffer length=%d",length);
+    VIR_INFO("nlmsg_type  = 0x%02x",hdr->nlmsg_type);
+    VIR_INFO("nlmsg_len   = 0x%04x",hdr->nlmsg_len );
+    VIR_INFO("nlmsg_pid   = %d",hdr->nlmsg_pid );
+    VIR_INFO("nlmsg_seq   = 0x%08x",hdr->nlmsg_seq );
+    VIR_INFO("nlmsg_flags = 0x%04x",hdr->nlmsg_flags );
+
+	switch (hdr->nlmsg_type) {
+	case RTM_NEWLINK:
+	case RTM_DELLINK:
+	case RTM_SETLINK:
+	case RTM_GETLINK:
+		VIR_INFO(" IFINFOMSG\n");
+		VIR_INFO("        ifi_family = 0x%02x\n",
+			((struct ifinfomsg *)data)->ifi_family);
+		VIR_INFO("        ifi_type   = 0x%x\n",
+			((struct ifinfomsg *)data)->ifi_type);
+		VIR_INFO("        ifi_index  = %i\n",
+			((struct ifinfomsg *)data)->ifi_index);
+		VIR_INFO("        ifi_flags  = 0x%04x\n",
+			((struct ifinfomsg *)data)->ifi_flags);
+		VIR_INFO("        ifi_change = 0x%04x\n",
+			((struct ifinfomsg *)data)->ifi_change);
+	}
+    /* DEBUG end */
+
+
+	/* FAKE (try) */
+	VIR_INFO("Re-Send associate request:");
+
+	VIR_INFO("  if: %s",calld->cr_ifname );
+	VIR_INFO("  lf: %s",calld->linkdev );
+	VIR_INFO(" mac: %04x:%04x:%04x:%04x:%04x:%04x",calld->macaddress[0],
+                                                       calld->macaddress[1],
+                                                       calld->macaddress[2],
+                                                       calld->macaddress[3],
+                                                       calld->macaddress[4],
+                                                       calld->macaddress[5] );
+	/* ToDo : Send an associate to lldpad
+	 *
+	 * */
+
+	handled++;
+	return;
+}
+
 /**
  * virNetDevMacVLanCreateWithVPortProfile:
  * Create an instance of a macvtap device and open its tap character
@@ -589,6 +728,23 @@ create_name:
         goto disassociate_exit;
     }
 
+    if (netlinkEventServiceStart() == 0) {
+        netlinkCallbackDataPtr calld;
+
+    	if (VIR_ALLOC(calld) < 0) {
+    		 virReportOOMError();
+    		 goto disassociate_exit;
+    	}
+
+    	strncpy(calld->cr_ifname,cr_ifname,64);
+        calld->virtPortProfile=virtPortProfile;
+        calld->macaddress=macaddress;
+        calld->linkdev=linkdev;
+        calld->vmuuid=vmuuid;
+        calld->vmOp=vmOp;
+
+        netlinkEventAddClient(virNetDevMacVLanVPortProfileCallback, calld, macaddress);
+    }
 
     return rc;
 
@@ -638,6 +794,9 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
         if (virNetDevMacVLanDelete(ifname) < 0)
             ret = -1;
     }
+
+    netlinkEventRemoveClient(0,macaddr);
+
     return ret;
 }
 
diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
index 130ecea..fe54cae 100644
--- a/src/util/virnetdevmacvlan.h
+++ b/src/util/virnetdevmacvlan.h
@@ -24,6 +24,7 @@
 # define __UTIL_MACVTAP_H__
 
 # include "internal.h"
+# include "netlink.h"
 # include "virsocketaddr.h"
 # include "virnetdevbandwidth.h"
 # include "virnetdevvportprofile.h"
-- 
1.7.7.5




More information about the libvir-list mailing list