Add Ethernet support to cuttlefish
Add a launcher flag (e.g. "launch_cvd -ethernet=true") which adds
another Ethernet interface to the virtual device. Ethernet devices are
already "buried" for use by wireless, but this new interface is not
wrapped and can be managed by netd. This functionality is useful for
Auto targets.
This mildly refactors some code in allocd to create separate Ethernet
and Wifi bridges and tap devices.
The code is off by default because it requires a new cuttlefish-common
package (0.9.17) and we haven't made the necessary changes to the
networkAttributes to allow Ethernet and Wifi to co-exist, so enabling
Ethernet currently breaks Wifi on phone configurations.
The created ethernet interface will be eth2 for now; once we can enable
this by default, we can move Ethernet back to eth0.
Bug: 172286896
Change-Id: I38ebf259f8eac101d867279f40cc78088a60921d
diff --git a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java
index 84998ee..43f4e3b 100644
--- a/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java
+++ b/guest/monitoring/cuttlefish_service/java/com/android/google/gce/gceservice/ConnectivityChecker.java
@@ -28,12 +28,15 @@
private static final String LOG_TAG = "GceConnChecker";
private static final String MOBILE_NETWORK_CONNECTED_MESSAGE =
"VIRTUAL_DEVICE_NETWORK_MOBILE_CONNECTED";
+ private static final String ETHERNET_NETWORK_CONNECTED_MESSAGE =
+ "VIRTUAL_DEVICE_NETWORK_ETHERNET_CONNECTED";
private final Context mContext;
private final EventReporter mEventReporter;
private final GceFuture<Boolean> mConnected = new GceFuture<Boolean>("Connectivity");
// TODO(schuffelen): Figure out why this has to be static in order to not report 3 times.
private static boolean reportedMobileConnectivity = false;
+ private static boolean reportedEthernetConnectivity = false;
public ConnectivityChecker(Context context, EventReporter eventReporter) {
super(LOG_TAG);
@@ -54,11 +57,16 @@
NetworkInfo info = connManager.getNetworkInfo(network);
if (info.isConnected()) {
NetworkCapabilities capabilities = connManager.getNetworkCapabilities(network);
- if (capabilities != null
- && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
- && !reportedMobileConnectivity) {
- mEventReporter.reportMessage(MOBILE_NETWORK_CONNECTED_MESSAGE);
- reportedMobileConnectivity = true;
+ if (capabilities != null) {
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+ && !reportedMobileConnectivity) {
+ mEventReporter.reportMessage(MOBILE_NETWORK_CONNECTED_MESSAGE);
+ reportedMobileConnectivity = true;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
+ && !reportedEthernetConnectivity) {
+ mEventReporter.reportMessage(ETHERNET_NETWORK_CONNECTED_MESSAGE);
+ reportedEthernetConnectivity = true;
+ }
}
}
}
diff --git a/host/commands/assemble_cvd/alloc.cc b/host/commands/assemble_cvd/alloc.cc
index 6b02bea..493de55 100644
--- a/host/commands/assemble_cvd/alloc.cc
+++ b/host/commands/assemble_cvd/alloc.cc
@@ -39,6 +39,11 @@
config.wireless_tap.name = StrForInstance("cvd-wtap-", num);
config.wireless_tap.resource_id = 0;
config.wireless_tap.session_id = 0;
+
+ config.ethernet_tap.name = StrForInstance("cvd-etap-", num);
+ config.ethernet_tap.resource_id = 0;
+ config.ethernet_tap.session_id = 0;
+
return config;
}
@@ -63,6 +68,8 @@
request_list.append(req);
req["iface_type"] = "wtap";
request_list.append(req);
+ req["iface_type"] = "etap";
+ request_list.append(req);
resource_config["config_request"]["request_list"] = request_list;
@@ -102,7 +109,8 @@
Json::Value resp_list = resp["response_list"];
Json::Value mtap_resp;
- Json::Value wifi_resp;
+ Json::Value wtap_resp;
+ Json::Value etap_resp;
for (Json::Value::ArrayIndex i = 0; i != resp_list.size(); ++i) {
auto ty = cuttlefish::StrToIfaceTy(resp_list[i]["iface_type"].asString());
@@ -112,7 +120,11 @@
break;
}
case cuttlefish::IfaceType::wtap: {
- wifi_resp = resp_list[i];
+ wtap_resp = resp_list[i];
+ break;
+ }
+ case cuttlefish::IfaceType::etap: {
+ etap_resp = resp_list[i];
break;
}
default: {
@@ -125,19 +137,27 @@
LOG(ERROR) << "Missing mtap response from allocd";
return std::nullopt;
}
- if (!wifi_resp.isMember("iface_type")) {
+ if (!wtap_resp.isMember("iface_type")) {
LOG(ERROR) << "Missing wtap response from allocd";
return std::nullopt;
}
+ if (!etap_resp.isMember("iface_type")) {
+ LOG(ERROR) << "Missing etap response from allocd";
+ return std::nullopt;
+ }
config.mobile_tap.name = mtap_resp["iface_name"].asString();
config.mobile_tap.resource_id = mtap_resp["resource_id"].asUInt();
config.mobile_tap.session_id = session_id;
- config.wireless_tap.name = wifi_resp["iface_name"].asString();
- config.wireless_tap.resource_id = wifi_resp["resource_id"].asUInt();
+ config.wireless_tap.name = wtap_resp["iface_name"].asString();
+ config.wireless_tap.resource_id = wtap_resp["resource_id"].asUInt();
config.wireless_tap.session_id = session_id;
+ config.ethernet_tap.name = etap_resp["iface_name"].asString();
+ config.ethernet_tap.resource_id = etap_resp["resource_id"].asUInt();
+ config.ethernet_tap.session_id = session_id;
+
return config;
}
diff --git a/host/commands/assemble_cvd/alloc.h b/host/commands/assemble_cvd/alloc.h
index 50b963b..0de8795 100644
--- a/host/commands/assemble_cvd/alloc.h
+++ b/host/commands/assemble_cvd/alloc.h
@@ -28,6 +28,7 @@
struct IfaceConfig {
IfaceData mobile_tap;
IfaceData wireless_tap;
+ IfaceData ethernet_tap;
};
IfaceConfig DefaultNetworkInterfaces(int num);
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index 1fd902b..511b6f0 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -284,6 +284,8 @@
"the vsock cid of the i th instance would be C + i where i is in [1, N]"
"If --num_instances is not given, the default value of N is used.");
+DEFINE_bool(ethernet, false, "Enable Ethernet network interface");
+
DECLARE_string(system_image_dir);
namespace {
@@ -600,6 +602,8 @@
tmp_config_obj.set_vhost_net(FLAGS_vhost_net);
+ tmp_config_obj.set_ethernet(FLAGS_ethernet);
+
std::vector<int> num_instances;
for (int i = 0; i < FLAGS_num_instances; i++) {
num_instances.push_back(cuttlefish::GetInstance() + i);
@@ -636,8 +640,8 @@
instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num));
instance.set_mobile_tap_name(iface_config.mobile_tap.name);
-
instance.set_wifi_tap_name(iface_config.wireless_tap.name);
+ instance.set_ethernet_tap_name(iface_config.ethernet_tap.name);
instance.set_vsock_guest_cid(FLAGS_vsock_guest_cid + num - cuttlefish::GetInstance());
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.cc b/host/commands/kernel_log_monitor/kernel_log_server.cc
index 089706f..66fafab 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.cc
+++ b/host/commands/kernel_log_monitor/kernel_log_server.cc
@@ -41,6 +41,7 @@
{cuttlefish::kMobileNetworkConnectedMessage,
monitor::Event::MobileNetworkConnected},
{cuttlefish::kWifiConnectedMessage, monitor::Event::WifiNetworkConnected},
+ {cuttlefish::kEthernetConnectedMessage, monitor::Event::EthernetNetworkConnected},
// TODO(b/131864854): Replace this with a string less likely to change
{"init: starting service 'adbd'...", monitor::Event::AdbdStarted},
{cuttlefish::kScreenChangedMessage, monitor::Event::ScreenChanged},
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.h b/host/commands/kernel_log_monitor/kernel_log_server.h
index 13e6a8a..659a372 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.h
+++ b/host/commands/kernel_log_monitor/kernel_log_server.h
@@ -36,6 +36,7 @@
MobileNetworkConnected = 4,
AdbdStarted = 5,
ScreenChanged = 6,
+ EthernetNetworkConnected = 7,
};
enum class SubscriptionAction {
diff --git a/host/commands/run_cvd/main.cc b/host/commands/run_cvd/main.cc
index b0b73f4..9b464c3 100644
--- a/host/commands/run_cvd/main.cc
+++ b/host/commands/run_cvd/main.cc
@@ -500,6 +500,9 @@
} else if (used_tap_devices.count(instance.mobile_tap_name())) {
LOG(ERROR) << "Mobile TAP device already in use";
return RunnerExitCodes::kTapDeviceInUse;
+ } else if (config->ethernet() &&
+ used_tap_devices.count(instance.ethernet_tap_name())) {
+ LOG(ERROR) << "Ethernet TAP device already in use";
}
auto vm_manager = GetVmManager(config->vm_manager());
diff --git a/host/libs/allocd/alloc_utils.cpp b/host/libs/allocd/alloc_utils.cpp
index 883b42c..8c91686 100644
--- a/host/libs/allocd/alloc_utils.cpp
+++ b/host/libs/allocd/alloc_utils.cpp
@@ -63,17 +63,13 @@
return status == 0;
}
-bool CreateWirelessIface(const std::string& name, bool has_ipv4_bridge,
- bool has_ipv6_bridge, bool use_ebtables_legacy) {
+bool CreateEthernetIface(const std::string& name, const std::string& bridge_name,
+ bool has_ipv4_bridge, bool has_ipv6_bridge,
+ bool use_ebtables_legacy) {
// assume bridge exists
- WirelessNetworkConfig config{false, false, false};
+ EthernetNetworkConfig config{false, false, false};
- // TODO (paulkirth): change this to cvd-wbr, to test w/ today's debian
- // package, this is required since the number of wireless bridges provided by
- // the debian package has gone from 10 down to 1, but our debian packages in
- // cloudtop are not up to date
- auto bridge_name = "cvd-wbr-01";
if (!CreateTap(name)) {
return false;
}
@@ -81,13 +77,13 @@
config.has_tap = true;
if (!LinkTapToBridge(name, bridge_name)) {
- CleanupWirelessIface(name, config);
+ CleanupEthernetIface(name, config);
return false;
}
if (!has_ipv4_bridge) {
if (!CreateEbtables(name, true, use_ebtables_legacy)) {
- CleanupWirelessIface(name, config);
+ CleanupEthernetIface(name, config);
return false;
}
config.has_broute_ipv4 = true;
@@ -95,7 +91,7 @@
if (!has_ipv6_bridge) {
if (CreateEbtables(name, false, use_ebtables_legacy)) {
- CleanupWirelessIface(name, config);
+ CleanupEthernetIface(name, config);
return false;
}
config.has_broute_ipv6 = true;
@@ -183,7 +179,7 @@
return status == 0;
}
-bool DestroyWirelessIface(const std::string& name, bool has_ipv4_bridge,
+bool DestroyEthernetIface(const std::string& name, bool has_ipv4_bridge,
bool has_ipv6_bridge, bool use_ebtables_legacy) {
if (!has_ipv6_bridge) {
DestroyEbtables(name, false, use_ebtables_legacy);
@@ -196,8 +192,8 @@
return DestroyIface(name);
}
-void CleanupWirelessIface(const std::string& name,
- const WirelessNetworkConfig& config) {
+void CleanupEthernetIface(const std::string& name,
+ const EthernetNetworkConfig& config) {
if (config.has_broute_ipv6) {
DestroyEbtables(name, false, config.use_ebtables_legacy);
}
@@ -458,12 +454,13 @@
return status == 0;
}
-bool CreateWirelessBridgeIface(const std::string& name) {
+bool CreateEthernetBridgeIface(const std::string& name,
+ const std::string& ipaddr) {
if (!CreateBridge(name)) {
return false;
}
- if (!SetupBridgeGateway(name, kWirelessIp)) {
+ if (!SetupBridgeGateway(name, ipaddr)) {
DestroyBridge(name);
return false;
}
@@ -471,12 +468,13 @@
return true;
}
-bool DestroyWirelessBridgeIface(const std::string& name) {
+bool DestroyEthernetBridgeIface(const std::string& name,
+ const std::string& ipaddr) {
GatewayConfig config{true, true, true};
// Don't need to check if removing some part of the config failed, we need to
// remove the entire interface, so just ignore any error until the end
- CleanupBridgeGateway(name, kWirelessIp, config);
+ CleanupBridgeGateway(name, ipaddr, config);
return DestroyBridge(name);
}
diff --git a/host/libs/allocd/alloc_utils.h b/host/libs/allocd/alloc_utils.h
index 5c1fd76..63f6d26 100644
--- a/host/libs/allocd/alloc_utils.h
+++ b/host/libs/allocd/alloc_utils.h
@@ -36,6 +36,8 @@
constexpr char kWirelessIp[] = "192.168.96";
// Mobile network prefix
constexpr char kMobileIp[] = "192.168.97";
+// Ethernet network prefix
+constexpr char kEthernetIp[] = "192.168.98";
// permission bits for socket
constexpr int kSocketMode = 0666;
@@ -46,7 +48,7 @@
constexpr uint32_t kMaxIfaceNameId = 63;
// struct for managing configuration state
-struct WirelessNetworkConfig {
+struct EthernetNetworkConfig {
bool has_broute_ipv4 = false;
bool has_broute_ipv6 = false;
bool has_tap = false;
@@ -89,12 +91,14 @@
bool DestroyMobileIface(const std::string& name, uint16_t id,
const std::string& ipaddr);
-bool CreateWirelessIface(const std::string& name, bool has_ipv4_bridge,
- bool has_ipv6_bridge, bool use_ebtables_legacy);
-bool DestroyWirelessIface(const std::string& name, bool has_ipv4_bridge,
- bool use_ipv6, bool use_ebtables_legacy);
-void CleanupWirelessIface(const std::string& name,
- const WirelessNetworkConfig& config);
+bool CreateEthernetIface(const std::string& name, const std::string& bridge_name,
+ bool has_ipv4_bridge, bool has_ipv6_bridge,
+ bool use_ebtables_legacy);
+bool DestroyEthernetIface(const std::string& name,
+ bool has_ipv4_bridge, bool use_ipv6,
+ bool use_ebtables_legacy);
+void CleanupEthernetIface(const std::string& name,
+ const EthernetNetworkConfig& config);
bool IptableConfig(const std::string& network, bool add);
@@ -105,8 +109,10 @@
void CleanupBridgeGateway(const std::string& name, const std::string& ipaddr,
const GatewayConfig& config);
-bool CreateWirelessBridgeIface(const std::string& name);
-bool DestroyWirelessBridgeIface(const std::string& name);
+bool CreateEthernetBridgeIface(const std::string& name,
+ const std::string &ipaddr);
+bool DestroyEthernetBridgeIface(const std::string& name,
+ const std::string &ipaddr);
bool AddGateway(const std::string& name, const std::string& gateway,
const std::string& netmask);
diff --git a/host/libs/allocd/request.h b/host/libs/allocd/request.h
index 8e1302d..1fbf6c9 100644
--- a/host/libs/allocd/request.h
+++ b/host/libs/allocd/request.h
@@ -45,7 +45,9 @@
Invalid = 0, // an invalid interface
mtap, // mobile tap
wtap, // wireless tap
- wbr // wireless bridge
+ etap, // ethernet tap
+ wbr, // wireless bridge
+ ebr // ethernet bridge
};
enum class RequestStatus : uint16_t {
diff --git a/host/libs/allocd/resource.cpp b/host/libs/allocd/resource.cpp
index 5a8b475..881dd85 100644
--- a/host/libs/allocd/resource.cpp
+++ b/host/libs/allocd/resource.cpp
@@ -30,13 +30,13 @@
return DestroyMobileIface(GetName(), iface_id_, ipaddr_);
}
-bool WirelessIface::AcquireResource() {
- return CreateWirelessIface(GetName(), has_ipv4_, has_ipv6_,
+bool EthernetIface::AcquireResource() {
+ return CreateEthernetIface(GetName(), GetBridgeName(), has_ipv4_, has_ipv6_,
use_ebtables_legacy_);
}
-bool WirelessIface::ReleaseResource() {
- return DestroyWirelessIface(GetName(), has_ipv4_, has_ipv6_,
+bool EthernetIface::ReleaseResource() {
+ return DestroyEthernetIface(GetName(), has_ipv4_, has_ipv6_,
use_ebtables_legacy_);
}
diff --git a/host/libs/allocd/resource.h b/host/libs/allocd/resource.h
index a92d38b..c30e9cc 100644
--- a/host/libs/allocd/resource.h
+++ b/host/libs/allocd/resource.h
@@ -26,8 +26,8 @@
enum class ResourceType {
Invalid = 0,
MobileIface,
- WirelessIface,
- WirelessBridge
+ EthernetIface,
+ EthernetBridge,
};
class StaticResource {
@@ -75,21 +75,25 @@
std::string ipaddr_;
};
-class WirelessIface : public StaticResource {
+class EthernetIface : public StaticResource {
public:
- WirelessIface() = default;
- ~WirelessIface() = default;
+ EthernetIface() = default;
+ ~EthernetIface() = default;
- WirelessIface(const std::string& name, uid_t uid, uint16_t iface_id,
- uint32_t global_id, std::string ipaddr)
+ EthernetIface(const std::string& name, uid_t uid, uint16_t iface_id,
+ uint32_t global_id, std::string bridge_name,
+ std::string ipaddr)
: StaticResource(name, uid, ResourceType::MobileIface, global_id),
iface_id_(iface_id),
+ bridge_name_(bridge_name),
ipaddr_(ipaddr) {}
bool ReleaseResource() override;
bool AcquireResource() override;
uint16_t GetIfaceId() { return iface_id_; }
+
+ std::string GetBridgeName() { return bridge_name_; }
std::string GetIpAddr() { return ipaddr_; }
void SetHasIpv4(bool ipv4) { has_ipv4_ = ipv4; }
@@ -105,6 +109,7 @@
private:
static constexpr char kNetmask[] = "/24";
uint16_t iface_id_;
+ std::string bridge_name_;
std::string ipaddr_;
bool has_ipv4_ = true;
bool has_ipv6_ = true;
diff --git a/host/libs/allocd/resource_manager.cpp b/host/libs/allocd/resource_manager.cpp
index 1ec6ac1..aaa8fe0 100644
--- a/host/libs/allocd/resource_manager.cpp
+++ b/host/libs/allocd/resource_manager.cpp
@@ -85,16 +85,20 @@
const char* idp = iface.c_str() + (iface.size() - 3);
int small_id = atoi(idp);
switch (ty) {
- case IfaceType::mtap: {
+ case IfaceType::mtap:
res = std::make_shared<MobileIface>(iface, uid, small_id, resource_id,
kMobileIp);
allocatedIface = res->AcquireResource();
pending_add_.insert({resource_id, res});
break;
- }
case IfaceType::wtap: {
- auto w = std::make_shared<WirelessIface>(iface, uid, small_id,
- resource_id, kMobileIp);
+ // TODO (paulkirth): change this to cvd-wbr, to test w/ today's
+ // debian package, this is required since the number of wireless
+ // bridges provided by the debian package has gone from 10 down to
+ // 1, but our debian packages in cloudtop are not up to date
+ auto w = std::make_shared<EthernetIface>(iface, uid, small_id,
+ resource_id, "cvd-wbr-01",
+ kWirelessIp);
w->SetUseEbtablesLegacy(use_ebtables_legacy_);
w->SetHasIpv4(use_ipv4_bridge_);
w->SetHasIpv6(use_ipv6_bridge_);
@@ -103,10 +107,22 @@
pending_add_.insert({resource_id, res});
break;
}
- case IfaceType::wbr: {
- allocatedIface = CreateBridge(iface);
+ case IfaceType::etap: {
+ auto w = std::make_shared<EthernetIface>(iface, uid, small_id,
+ resource_id, "cvd-ebr",
+ kEthernetIp);
+ w->SetUseEbtablesLegacy(use_ebtables_legacy_);
+ w->SetHasIpv4(use_ipv4_bridge_);
+ w->SetHasIpv6(use_ipv6_bridge_);
+ res = w;
+ allocatedIface = res->AcquireResource();
+ pending_add_.insert({resource_id, res});
break;
}
+ case IfaceType::wbr:
+ case IfaceType::ebr:
+ allocatedIface = CreateBridge(iface);
+ break;
case IfaceType::Invalid:
break;
}
@@ -138,15 +154,15 @@
removedIface = DestroyMobileIface(iface, id, kMobileIp);
break;
}
- case IfaceType::wtap: {
- removedIface = DestroyWirelessIface(
+ case IfaceType::wtap:
+ case IfaceType::etap:
+ removedIface = DestroyEthernetIface(
iface, use_ipv4_bridge_, use_ipv6_bridge_, use_ebtables_legacy_);
break;
- }
- case IfaceType::wbr: {
+ case IfaceType::wbr:
+ case IfaceType::ebr:
removedIface = DestroyBridge(iface);
break;
- }
case IfaceType::Invalid:
break;
}
diff --git a/host/libs/allocd/utils.cpp b/host/libs/allocd/utils.cpp
index 603c8d0..c60dc0c 100644
--- a/host/libs/allocd/utils.cpp
+++ b/host/libs/allocd/utils.cpp
@@ -58,13 +58,17 @@
{"invalid", IfaceType::Invalid},
{"mtap", IfaceType::mtap},
{"wtap", IfaceType::wtap},
- {"wbr", IfaceType::wbr}};
+ {"etap", IfaceType::etap},
+ {"wbr", IfaceType::wbr},
+ {"ebr", IfaceType::ebr}};
const std::map<IfaceType, std::string> IfaceTyToStrMap = {
{IfaceType::Invalid, "invalid"},
{IfaceType::mtap, "mtap"},
{IfaceType::wtap, "wtap"},
- {IfaceType::wbr, "wbr"}};
+ {IfaceType::etap, "etap"},
+ {IfaceType::wbr, "wbr"},
+ {IfaceType::ebr, "ebr"}};
const std::map<RequestStatus, std::string> ReqStatusToStrMap = {
{RequestStatus::Invalid, "invalid"},
@@ -167,8 +171,12 @@
return "mtap";
case IfaceType::wtap:
return "wtap";
+ case IfaceType::etap:
+ return "etap";
case IfaceType::wbr:
return "wbr";
+ case IfaceType::ebr:
+ return "ebr";
}
}
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 758ec51..1a50ff6 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -168,6 +168,8 @@
const char* kVhostNet = "vhost_net";
+const char* kEthernet = "ethernet";
+
} // namespace
const char* const kGpuModeAuto = "auto";
@@ -793,6 +795,13 @@
return (*dictionary_)[kVhostNet].asBool();
}
+void CuttlefishConfig::set_ethernet(bool ethernet) {
+ (*dictionary_)[kEthernet] = ethernet;
+}
+bool CuttlefishConfig::ethernet() const {
+ return (*dictionary_)[kEthernet].asBool();
+}
+
// Creates the (initially empty) config object and populates it with values from
// the config file if the CUTTLEFISH_CONFIG_FILE env variable is present.
// Returns nullptr if there was an error loading from file
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 4b2a6b5..a199728 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -48,6 +48,8 @@
"VIRTUAL_DEVICE_NETWORK_MOBILE_CONNECTED";
constexpr char kWifiConnectedMessage[] =
"VIRTUAL_DEVICE_NETWORK_WIFI_CONNECTED";
+constexpr char kEthernetConnectedMessage[] =
+ "VIRTUAL_DEVICE_NETWORK_ETHERNET_CONNECTED";
constexpr char kScreenChangedMessage[] = "VIRTUAL_DEVICE_SCREEN_CHANGED";
constexpr char kInternalDirName[] = "internal";
constexpr char kSharedDirName[] = "shared";
@@ -319,6 +321,9 @@
void set_vhost_net(bool vhost_net);
bool vhost_net() const;
+ void set_ethernet(bool ethernet);
+ bool ethernet() const;
+
class InstanceSpecific;
class MutableInstanceSpecific;
@@ -375,6 +380,7 @@
std::string mobile_bridge_name() const;
std::string mobile_tap_name() const;
std::string wifi_tap_name() const;
+ std::string ethernet_tap_name() const;
uint32_t session_id() const;
bool use_allocd() const;
int vsock_guest_cid() const;
@@ -467,6 +473,7 @@
void set_mobile_bridge_name(const std::string& mobile_bridge_name);
void set_mobile_tap_name(const std::string& mobile_tap_name);
void set_wifi_tap_name(const std::string& wifi_tap_name);
+ void set_ethernet_tap_name(const std::string& ethernet_tap_name);
void set_session_id(uint32_t session_id);
void set_use_allocd(bool use_allocd);
void set_vsock_guest_cid(int vsock_guest_cid);
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
index 8bb4c84..d0f919e 100644
--- a/host/libs/config/cuttlefish_config_instance.cpp
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -34,6 +34,7 @@
const char* kMobileBridgeName = "mobile_bridge_name";
const char* kMobileTapName = "mobile_tap_name";
const char* kWifiTapName = "wifi_tap_name";
+const char* kEthernetTapName = "ethernet_tap_name";
const char* kVsockGuestCid = "vsock_guest_cid";
const char* kSessionId = "session_id";
@@ -220,6 +221,14 @@
(*Dictionary())[kWifiTapName] = wifi_tap_name;
}
+std::string CuttlefishConfig::InstanceSpecific::ethernet_tap_name() const {
+ return (*Dictionary())[kEthernetTapName].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_ethernet_tap_name(
+ const std::string& ethernet_tap_name) {
+ (*Dictionary())[kEthernetTapName] = ethernet_tap_name;
+}
+
bool CuttlefishConfig::InstanceSpecific::use_allocd() const {
return (*Dictionary())[kUseAllocd].asBool();
}
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index b067096..5d86aac 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -286,6 +286,12 @@
"path=", instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
",input=", instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"));
+ // TODO(b/172286896): This is temporarily optional, but should be made
+ // unconditional and moved up to the other network devices area
+ if (config.ethernet()) {
+ AddTapFdParameter(&crosvm_cmd, instance.ethernet_tap_name());
+ }
+
// TODO(b/162071003): virtiofs crashes without sandboxing, this should be fixed
if (config.enable_sandbox()) {
// Set up directory shared with virtiofs
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index fabe406..fd40bf3 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -411,6 +411,17 @@
qemu_cmd.AddParameter("-device");
qemu_cmd.AddParameter("AC97");
+ // TODO(b/172286896): This is temporarily optional, but should be made
+ // unconditional and moved up to the other network devices area
+ if (config.ethernet()) {
+ qemu_cmd.AddParameter("-netdev");
+ qemu_cmd.AddParameter("tap,id=hostnet2,ifname=", instance.ethernet_tap_name(),
+ ",script=no,downscript=no", vhost_net);
+
+ qemu_cmd.AddParameter("-device");
+ qemu_cmd.AddParameter("virtio-net-pci-non-transitional,netdev=hostnet2,id=net2");
+ }
+
if (config.use_bootloader()) {
qemu_cmd.AddParameter("-bios");
qemu_cmd.AddParameter(config.bootloader());