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