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
This commit is contained in:
Ján Tomko 2014-04-24 14:58:47 +02:00
parent 5c2f782f76
commit a65871aaae

View File

@ -25,6 +25,7 @@
#include <libudev.h> #include <libudev.h>
#include "virerror.h" #include "virerror.h"
#include "virfile.h"
#include "c-ctype.h" #include "c-ctype.h"
#include "datatypes.h" #include "datatypes.h"
#include "domain_conf.h" #include "domain_conf.h"
@ -966,31 +967,64 @@ udevGetIfaceDefVlan(struct udev *udev ATTRIBUTE_UNUSED,
const char *name, const char *name,
virInterfaceDef *ifacedef) 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;
/* Find the DEVICE.VID again */ if (virAsprintf(&procpath, "/proc/net/vlan/%s", name) < 0)
vid = strrchr(name, '.'); goto cleanup;
if (!vid) {
if (virFileReadAll(procpath, BUFSIZ, &buf) < 0)
goto cleanup;
if ((vid_pos = strstr(buf, vid_prefix)) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to find the VID for the VLAN device '%s'"), _("failed to find the VID for the VLAN device '%s'"),
name); name);
return -1; goto cleanup;
}
vid_pos += strlen(vid_prefix);
if ((vid_len = strspn(vid_pos, "0123456789")) == 0 ||
!c_isspace(vid_pos[vid_len])) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to find the VID for the VLAN device '%s'"),
name);
goto cleanup;
} }
/* Set the VLAN specifics */ if ((dev_pos = strstr(vid_pos + vid_len, dev_prefix)) == NULL) {
if (VIR_STRDUP(ifacedef->data.vlan.tag, vid + 1) < 0) virReportError(VIR_ERR_INTERNAL_ERROR,
goto error; _("failed to find the real device for the VLAN device '%s'"),
if (VIR_STRNDUP(ifacedef->data.vlan.devname, name);
name, (vid - name)) < 0) goto cleanup;
goto error; }
dev_pos += strlen(dev_prefix);
return 0; 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;
}
error: if (VIR_STRNDUP(ifacedef->data.vlan.tag, vid_pos, vid_len) < 0)
VIR_FREE(ifacedef->data.vlan.tag); goto cleanup;
VIR_FREE(ifacedef->data.vlan.devname); if (VIR_STRNDUP(ifacedef->data.vlan.devname, dev_pos, dev_len) < 0) {
VIR_FREE(ifacedef->data.vlan.tag);
goto cleanup;
}
return -1; ret = 0;
cleanup:
VIR_FREE(procpath);
VIR_FREE(buf);
return ret;
} }
static virInterfaceDef * ATTRIBUTE_NONNULL(1) static virInterfaceDef * ATTRIBUTE_NONNULL(1)