[libvirt] [PATCH] Fix vlan ID detection in udev interface driver

Instead of guessing it from the interface name, look into /proc/net/vlan/<interface>. This works for devices not named <real_device>.<vlan ID>, avoiding an error flood when virt-manager keeps asking about them every second: https://bugzilla.redhat.com/show_bug.cgi?id=966329 --- src/interface/interface_backend_udev.c | 67 ++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index b05ac0e..bec8c45 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -20,11 +20,13 @@ */ #include <config.h> +#include <ctype.h> #include <errno.h> #include <dirent.h> #include <libudev.h> #include "virerror.h" +#include "virfile.h" #include "c-ctype.h" #include "datatypes.h" #include "domain_conf.h" @@ -966,31 +968,64 @@ udevGetIfaceDefVlan(struct udev *udev ATTRIBUTE_UNUSED, const char *name, virInterfaceDef *ifacedef) { - const char *vid; + char *procpath = NULL; + char *buf = NULL; + char *vid_pos, *dev_pos; + size_t vid_len, dev_len; + const char *vid_prefix = "VID: "; + const char *dev_prefix = "\nDevice: "; + int ret = -1; + + if (virAsprintf(&procpath, "/proc/net/vlan/%s", name) < 0) + goto cleanup; + + if (virFileReadAll(procpath, BUFSIZ, &buf) < 0) + goto cleanup; - /* Find the DEVICE.VID again */ - vid = strrchr(name, '.'); - if (!vid) { + if ((vid_pos = strstr(buf, vid_prefix)) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to find the VID for the VLAN device '%s'"), name); - return -1; + goto cleanup; } + vid_pos += strlen(vid_prefix); - /* Set the VLAN specifics */ - if (VIR_STRDUP(ifacedef->data.vlan.tag, vid + 1) < 0) - goto error; - if (VIR_STRNDUP(ifacedef->data.vlan.devname, - name, (vid - name)) < 0) - goto error; + if ((vid_len = strspn(vid_pos, "0123456789")) == 0 || + !isspace(vid_pos[vid_len])) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the VID for the VLAN device '%s'"), + name); + goto cleanup; + } - return 0; + if ((dev_pos = strstr(vid_pos + vid_len, dev_prefix)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the real device for the VLAN device '%s'"), + name); + goto cleanup; + } + dev_pos += strlen(dev_prefix); - error: - VIR_FREE(ifacedef->data.vlan.tag); - VIR_FREE(ifacedef->data.vlan.devname); + if ((dev_len = strcspn(dev_pos, "\n")) == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the real device for the VLAN device '%s'"), + name); + goto cleanup; + } - return -1; + if (VIR_STRNDUP(ifacedef->data.vlan.tag, vid_pos, vid_len) < 0) + goto cleanup; + if (VIR_STRNDUP(ifacedef->data.vlan.devname, dev_pos, dev_len) < 0) { + VIR_FREE(ifacedef->data.vlan.tag); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(procpath); + VIR_FREE(buf); + return ret; } static virInterfaceDef * ATTRIBUTE_NONNULL(1) -- 1.8.3.2

On Thu, Apr 24, 2014 at 03:19:45PM +0200, Ján Tomko wrote:
Instead of guessing it from the interface name, look into /proc/net/vlan/<interface>.
This works for devices not named <real_device>.<vlan ID>, avoiding an error flood when virt-manager keeps asking about them every second:
What's the equivalent virsh command that produces the errors? Dave
--- src/interface/interface_backend_udev.c | 67 ++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 16 deletions(-)
diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index b05ac0e..bec8c45 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -20,11 +20,13 @@ */ #include <config.h>
+#include <ctype.h> #include <errno.h> #include <dirent.h> #include <libudev.h>
#include "virerror.h" +#include "virfile.h" #include "c-ctype.h" #include "datatypes.h" #include "domain_conf.h" @@ -966,31 +968,64 @@ udevGetIfaceDefVlan(struct udev *udev ATTRIBUTE_UNUSED, const char *name, virInterfaceDef *ifacedef) { - const char *vid; + char *procpath = NULL; + char *buf = NULL; + char *vid_pos, *dev_pos; + size_t vid_len, dev_len; + const char *vid_prefix = "VID: "; + const char *dev_prefix = "\nDevice: "; + int ret = -1; + + if (virAsprintf(&procpath, "/proc/net/vlan/%s", name) < 0) + goto cleanup; + + if (virFileReadAll(procpath, BUFSIZ, &buf) < 0) + goto cleanup;
- /* Find the DEVICE.VID again */ - vid = strrchr(name, '.'); - if (!vid) { + if ((vid_pos = strstr(buf, vid_prefix)) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to find the VID for the VLAN device '%s'"), name); - return -1; + goto cleanup; } + vid_pos += strlen(vid_prefix);
- /* Set the VLAN specifics */ - if (VIR_STRDUP(ifacedef->data.vlan.tag, vid + 1) < 0) - goto error; - if (VIR_STRNDUP(ifacedef->data.vlan.devname, - name, (vid - name)) < 0) - goto error; + if ((vid_len = strspn(vid_pos, "0123456789")) == 0 || + !isspace(vid_pos[vid_len])) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the VID for the VLAN device '%s'"), + name); + goto cleanup; + }
- return 0; + if ((dev_pos = strstr(vid_pos + vid_len, dev_prefix)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the real device for the VLAN device '%s'"), + name); + goto cleanup; + } + dev_pos += strlen(dev_prefix);
- error: - VIR_FREE(ifacedef->data.vlan.tag); - VIR_FREE(ifacedef->data.vlan.devname); + if ((dev_len = strcspn(dev_pos, "\n")) == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the real device for the VLAN device '%s'"), + name); + goto cleanup; + }
- return -1; + if (VIR_STRNDUP(ifacedef->data.vlan.tag, vid_pos, vid_len) < 0) + goto cleanup; + if (VIR_STRNDUP(ifacedef->data.vlan.devname, dev_pos, dev_len) < 0) { + VIR_FREE(ifacedef->data.vlan.tag); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(procpath); + VIR_FREE(buf); + return ret; }
static virInterfaceDef * ATTRIBUTE_NONNULL(1) -- 1.8.3.2
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 04/25/2014 06:21 PM, Dave Allan wrote:
On Thu, Apr 24, 2014 at 03:19:45PM +0200, Ján Tomko wrote:
Instead of guessing it from the interface name, look into /proc/net/vlan/<interface>.
This works for devices not named <real_device>.<vlan ID>, avoiding an error flood when virt-manager keeps asking about them every second:
https://bugzilla.redhat.com/show_bug.cgi?id=966329 What's the equivalent virsh command that produces the errors?
virsh iface-dumpxml <some vlan interface named as described> Of course this can only be experienced on a system that is built with the udev interface driver rather than the netcf interface driver.

On Fri, Apr 25, 2014 at 08:28:32PM +0300, Laine Stump wrote:
On 04/25/2014 06:21 PM, Dave Allan wrote:
On Thu, Apr 24, 2014 at 03:19:45PM +0200, Ján Tomko wrote:
Instead of guessing it from the interface name, look into /proc/net/vlan/<interface>.
This works for devices not named <real_device>.<vlan ID>, avoiding an error flood when virt-manager keeps asking about them every second:
https://bugzilla.redhat.com/show_bug.cgi?id=966329 What's the equivalent virsh command that produces the errors?
virsh iface-dumpxml <some vlan interface named as described>
Of course this can only be experienced on a system that is built with the udev interface driver rather than the netcf interface driver.
Thanks Laine; Jan, your patch fixes the behavior on my system, so ACK to the functionality. I didn't do more than a cursory review of the code, however, so you should wait for another review before pushing. Dave

On 24.04.2014 15:19, Ján Tomko wrote:
Instead of guessing it from the interface name, look into /proc/net/vlan/<interface>.
This works for devices not named <real_device>.<vlan ID>, avoiding an error flood when virt-manager keeps asking about them every second:
https://bugzilla.redhat.com/show_bug.cgi?id=966329 --- src/interface/interface_backend_udev.c | 67 ++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 16 deletions(-)
diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index b05ac0e..bec8c45 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -20,11 +20,13 @@ */ #include <config.h>
+#include <ctype.h> #include <errno.h> #include <dirent.h> #include <libudev.h>
#include "virerror.h" +#include "virfile.h" #include "c-ctype.h" #include "datatypes.h" #include "domain_conf.h" @@ -966,31 +968,64 @@ udevGetIfaceDefVlan(struct udev *udev ATTRIBUTE_UNUSED, const char *name, virInterfaceDef *ifacedef) { - const char *vid; + char *procpath = NULL; + char *buf = NULL; + char *vid_pos, *dev_pos; + size_t vid_len, dev_len; + const char *vid_prefix = "VID: "; + const char *dev_prefix = "\nDevice: "; + int ret = -1; + + if (virAsprintf(&procpath, "/proc/net/vlan/%s", name) < 0) + goto cleanup; + + if (virFileReadAll(procpath, BUFSIZ, &buf) < 0) + goto cleanup;
- /* Find the DEVICE.VID again */ - vid = strrchr(name, '.'); - if (!vid) { + if ((vid_pos = strstr(buf, vid_prefix)) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to find the VID for the VLAN device '%s'"), name); - return -1; + goto cleanup; } + vid_pos += strlen(vid_prefix);
- /* Set the VLAN specifics */ - if (VIR_STRDUP(ifacedef->data.vlan.tag, vid + 1) < 0) - goto error; - if (VIR_STRNDUP(ifacedef->data.vlan.devname, - name, (vid - name)) < 0) - goto error; + if ((vid_len = strspn(vid_pos, "0123456789")) == 0 || + !isspace(vid_pos[vid_len])) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the VID for the VLAN device '%s'"), + name); + goto cleanup; + }
- return 0; + if ((dev_pos = strstr(vid_pos + vid_len, dev_prefix)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the real device for the VLAN device '%s'"), + name); + goto cleanup; + } + dev_pos += strlen(dev_prefix);
- error: - VIR_FREE(ifacedef->data.vlan.tag); - VIR_FREE(ifacedef->data.vlan.devname); + if ((dev_len = strcspn(dev_pos, "\n")) == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find the real device for the VLAN device '%s'"), + name); + goto cleanup; + }
- return -1; + if (VIR_STRNDUP(ifacedef->data.vlan.tag, vid_pos, vid_len) < 0) + goto cleanup; + if (VIR_STRNDUP(ifacedef->data.vlan.devname, dev_pos, dev_len) < 0) { + VIR_FREE(ifacedef->data.vlan.tag); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(procpath); + VIR_FREE(buf); + return ret; }
static virInterfaceDef * ATTRIBUTE_NONNULL(1)
ACK, but I'm not sure if this qualifies as the release material. Michal

My ACK was premature .. On 24.04.2014 15:19, Ján Tomko wrote:
Instead of guessing it from the interface name, look into /proc/net/vlan/<interface>.
This works for devices not named <real_device>.<vlan ID>, avoiding an error flood when virt-manager keeps asking about them every second:
https://bugzilla.redhat.com/show_bug.cgi?id=966329 --- src/interface/interface_backend_udev.c | 67 ++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 16 deletions(-)
diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index b05ac0e..bec8c45 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -20,11 +20,13 @@ */ #include <config.h>
+#include <ctype.h> #include <errno.h> #include <dirent.h> #include <libudev.h>
#include "virerror.h" +#include "virfile.h" #include "c-ctype.h" #include "datatypes.h" #include "domain_conf.h" @@ -966,31 +968,64 @@ udevGetIfaceDefVlan(struct udev *udev ATTRIBUTE_UNUSED, const char *name, virInterfaceDef *ifacedef) { - const char *vid; + char *procpath = NULL; + char *buf = NULL; + char *vid_pos, *dev_pos; + size_t vid_len, dev_len; + const char *vid_prefix = "VID: "; + const char *dev_prefix = "\nDevice: "; + int ret = -1; + + if (virAsprintf(&procpath, "/proc/net/vlan/%s", name) < 0) + goto cleanup; + + if (virFileReadAll(procpath, BUFSIZ, &buf) < 0) + goto cleanup;
- /* Find the DEVICE.VID again */ - vid = strrchr(name, '.'); - if (!vid) { + if ((vid_pos = strstr(buf, vid_prefix)) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to find the VID for the VLAN device '%s'"), name); - return -1; + goto cleanup; } + vid_pos += strlen(vid_prefix);
- /* Set the VLAN specifics */ - if (VIR_STRDUP(ifacedef->data.vlan.tag, vid + 1) < 0) - goto error; - if (VIR_STRNDUP(ifacedef->data.vlan.devname, - name, (vid - name)) < 0) - goto error; + if ((vid_len = strspn(vid_pos, "0123456789")) == 0 || + !isspace(vid_pos[vid_len])) {
s/isspace/c_isspace/ With this change my ACK still stands. Michal

On 04/30/2014 06:02 PM, Michal Privoznik wrote:
My ACK was premature ..
On 24.04.2014 15:19, Ján Tomko wrote:
Instead of guessing it from the interface name, look into /proc/net/vlan/<interface>.
This works for devices not named <real_device>.<vlan ID>, avoiding an error flood when virt-manager keeps asking about them every second:
https://bugzilla.redhat.com/show_bug.cgi?id=966329 --- src/interface/interface_backend_udev.c | 67 ++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 16 deletions(-)
diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index b05ac0e..bec8c45 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -20,11 +20,13 @@ */ #include <config.h>
+#include <ctype.h> #include <errno.h> #include <dirent.h> #include <libudev.h>
#include "virerror.h" +#include "virfile.h" #include "c-ctype.h" #include "datatypes.h" #include "domain_conf.h" @@ -966,31 +968,64 @@ udevGetIfaceDefVlan(struct udev *udev ATTRIBUTE_UNUSED, const char *name, virInterfaceDef *ifacedef) { - const char *vid; + char *procpath = NULL; + char *buf = NULL; + char *vid_pos, *dev_pos; + size_t vid_len, dev_len; + const char *vid_prefix = "VID: "; + const char *dev_prefix = "\nDevice: "; + int ret = -1; + + if (virAsprintf(&procpath, "/proc/net/vlan/%s", name) < 0) + goto cleanup; + + if (virFileReadAll(procpath, BUFSIZ, &buf) < 0) + goto cleanup;
- /* Find the DEVICE.VID again */ - vid = strrchr(name, '.'); - if (!vid) { + if ((vid_pos = strstr(buf, vid_prefix)) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to find the VID for the VLAN device '%s'"), name); - return -1; + goto cleanup; } + vid_pos += strlen(vid_prefix);
- /* Set the VLAN specifics */ - if (VIR_STRDUP(ifacedef->data.vlan.tag, vid + 1) < 0) - goto error; - if (VIR_STRNDUP(ifacedef->data.vlan.devname, - name, (vid - name)) < 0) - goto error; + if ((vid_len = strspn(vid_pos, "0123456789")) == 0 || + !isspace(vid_pos[vid_len])) {
s/isspace/c_isspace/
With this change my ACK still stands.
I've changed it to c_isspace and pushed. Jan
participants (4)
-
Dave Allan
-
Ján Tomko
-
Laine Stump
-
Michal Privoznik