shill: avoid virtio_net race condition
With the virtnet driver, it's possible for the kernel's IPv6 code
to transmit frames before virtnet_probe completes. This seems to confuse
the driver, making the device unable to transmit. To make use of the
device, one then has to unload and reload (rmmod+modprobe) the driver.
This makes difficult to run shill in a VM. That means that a patch
to enable shill as the default CM won't make it through the commit queue.
Work around the virtnet+IPv6 problem by sleeping before bringing
up the virtual ethernet device. Empirically, it takes about 7ms
from the time shill gets the notification about the virtnet device
being available, until the time when virtnet_probe completes.
We sleep 2 seconds (2000ms) to leave lots of slack.
Collateral change: declare some Ethernet methods as virtual.
They're already virtual (by virtual of their base class declarations),
but declaring them virtual in Ethernet makes this explicit.
BUG=chromium-os:29494
TEST=trybots, manual testing (see below)
Trybots: ran on 10 trybots, with 20 iterations of VMTest
each. (Using https://gerrit.chromium.org/gerrit/#change,19560.)
Saw no failures.
Manual testing: Ran shill in VM, verified that ethernet
was identified as using virtio driver. Ran shill on an
Alex (with linksys usb ethernet adapter), verified that
ethernet was not identified as using virtio driver.
Change-Id: I48727e65c2f64f9973faaf9eeaedfbcf452b0b82
Reviewed-on: https://gerrit.chromium.org/gerrit/20415
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
diff --git a/device_info.cc b/device_info.cc
index 34680bc..f5aa4a0 100644
--- a/device_info.cc
+++ b/device_info.cc
@@ -38,6 +38,7 @@
#include "shill/rtnl_listener.h"
#include "shill/rtnl_message.h"
#include "shill/service.h"
+#include "shill/virtio_ethernet.h"
#include "shill/wifi.h"
using base::Bind;
@@ -50,6 +51,7 @@
namespace shill {
// static
+const char DeviceInfo::kDriverVirtioNet[] = "virtio_net";
const char DeviceInfo::kInterfaceUevent[] = "/sys/class/net/%s/uevent";
const char DeviceInfo::kInterfaceUeventWifiSignature[] = "DEVTYPE=wlan\n";
const char DeviceInfo::kInterfaceDevice[] = "/sys/class/net/%s/device";
@@ -211,8 +213,17 @@
return Technology::kCellular;
}
- VLOG(2) << StringPrintf("%s: device %s is defaulted to type ethernet",
- __func__, iface_name.c_str());
+ // Special case for the virtio driver, used when run under KVM. See also
+ // the comment in VirtioEthernet::Start.
+ if (driver_name == kDriverVirtioNet) {
+ VLOG(2) << StringPrintf("%s: device %s is virtio ethernet", __func__,
+ iface_name.c_str());
+ return Technology::kVirtioEthernet;
+ }
+
+ VLOG(2) << StringPrintf("%s: device %s, with driver %s, "
+ "is defaulted to type ethernet",
+ __func__, iface_name.c_str(), driver_name.c_str());
return Technology::kEthernet;
}
@@ -332,6 +343,11 @@
manager_, link_name, address, dev_index);
device->EnableIPv6Privacy();
break;
+ case Technology::kVirtioEthernet:
+ device = new VirtioEthernet(control_interface_, dispatcher_, metrics_,
+ manager_, link_name, address, dev_index);
+ device->EnableIPv6Privacy();
+ break;
case Technology::kWifi:
device = new WiFi(control_interface_, dispatcher_, metrics_, manager_,
link_name, address, dev_index);