On 01/20/2012 09:56 AM, D. Herrendoerfer wrote:
From: "D.
Herrendoerfer"<d.herrendoerfer(a)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(a)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) {
Instead of this custom function, you should use virPidFileRead, which
handles all of these details for you.
+ 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)
+{
You apparently have tabs turned on in your editor. libvirt coding
guidelines require all formatting to be done with spaces (and not
trailing whitespace on lines). Please run "make syntax-check" and fix
problems it reports prior to submitting any final patch. ("make check"
too, but for different reasons)
+ /* 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
again s/handeled/handled/
+
+ /* 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;
I don't think it's a good idea to call netlinkEventServiceStart here. It
will have already been called in main(), and if it failed there, calling
it again here (in code that could be executed by multiple threads) could
lead to to two threads calling it at the same time, and it is not
threadsafe. (I know this is highly unlikely, but... :-)
If you want to allow for earlier failure of the service, you should
probably make a separate function "netlinkEventServiceIsStarted()".
+
+ 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"