Create a guest VLAN network with a host flag.
From the host:
- A new flag is added to switch from guest vlan/no-vlan.
- no-vlan runs the same network configuration as before.
- vlan exposes just the one tap device to qemu.
- The default is to not use it, but in the future the host could use
capability_query to decide what to set as the default.
From the guest:
- ip_link_add is replaced with a single setup_network binary
- setup_network uses a flag as a signal for vlan/no-vlan
- no-vlan has the same behavior as the previous network configuration
- vlan configures the mobile and wifi vlans
- using a network namespace is possible future work
Bug: 111320496
Test: Ran cf_x86_phone-userdebug with and without vlans on a host.
Change-Id: I47cf4e1b1c70a339218d24053f29ffbcf9887263
Merged-In: I47cf4e1b1c70a339218d24053f29ffbcf9887263
diff --git a/guest/commands/ip_link_add/main.cpp b/guest/commands/ip_link_add/main.cpp
deleted file mode 100644
index 5b07798..0000000
--- a/guest/commands/ip_link_add/main.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "common/libs/net/netlink_client.h"
-#include "common/libs/net/netlink_request.h"
-#include "common/libs/net/network_interface.h"
-#include "common/libs/net/network_interface_manager.h"
-
-#include <linux/rtnetlink.h>
-#include <net/if.h>
-#include <iostream>
-#include <string>
-
-int main(int argc, char *argv[]) {
- if (!((argc == 5 && std::string(argv[1]) == "vlan") ||
- (argc == 4 && std::string(argv[1]) == "virt_wifi"))) {
- std::cerr << "usages:\n";
- std::cerr << " " << argv[0] << " vlan [ethA] [ethB] [index]\n";
- std::cerr << " " << argv[0] << " virt_wifi [ethA] [ethB]\n";
- return -1;
- }
- const char *const name = argv[2];
- int32_t index = if_nametoindex(name);
- if (index == 0) {
- fprintf(stderr, "%s: invalid interface name '%s'\n", argv[2], name);
- return -2;
- }
- const char *const new_name = argv[3];
- auto factory = cvd::NetlinkClientFactory::Default();
- std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
-
- // http://maz-programmersdiary.blogspot.com/2011/09/netlink-sockets.html
- cvd::NetlinkRequest link_add_request(RTM_NEWLINK, NLM_F_REQUEST|NLM_F_ACK|0x600);
- link_add_request.Append(ifinfomsg {
- .ifi_change = 0xFFFFFFFF,
- });
- link_add_request.AddString(IFLA_IFNAME, std::string(new_name));
- link_add_request.AddInt(IFLA_LINK, index);
-
- link_add_request.PushList(IFLA_LINKINFO);
- link_add_request.AddString(IFLA_INFO_KIND, argv[1]);
- link_add_request.PushList(IFLA_INFO_DATA);
- if (std::string(argv[1]) == "vlan") {
- uint16_t vlan_index = atoi(argv[4]);
- link_add_request.AddInt(IFLA_VLAN_ID, vlan_index);
- }
- link_add_request.PopList();
- link_add_request.PopList();
-
- nl->Send(link_add_request);
-
- cvd::NetlinkRequest bring_up_backing_request(RTM_SETLINK, NLM_F_REQUEST|NLM_F_ACK|0x600);
- bring_up_backing_request.Append(ifinfomsg {
- .ifi_index = index,
- .ifi_flags = IFF_UP,
- .ifi_change = 0xFFFFFFFF,
- });
-
- nl->Send(bring_up_backing_request);
-
- return 0;
-}
diff --git a/guest/commands/ip_link_add/Android.mk b/guest/commands/setup_network/Android.mk
similarity index 94%
rename from guest/commands/ip_link_add/Android.mk
rename to guest/commands/setup_network/Android.mk
index 993dea6..041c12f 100644
--- a/guest/commands/ip_link_add/Android.mk
+++ b/guest/commands/setup_network/Android.mk
@@ -16,10 +16,10 @@
include $(CLEAR_VARS)
-LOCAL_MODULE := ip_link_add
+LOCAL_MODULE := setup_network
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := main.cpp
-LOCAL_SHARED_LIBRARIES := cuttlefish_net cuttlefish_auto_resources
+LOCAL_SHARED_LIBRARIES := cuttlefish_net cuttlefish_auto_resources libbase liblog
LOCAL_C_INCLUDES := device/google/cuttlefish_common
LOCAL_MULTILIB := first
LOCAL_VENDOR_MODULE := true
diff --git a/guest/commands/setup_network/main.cpp b/guest/commands/setup_network/main.cpp
new file mode 100644
index 0000000..269db8c
--- /dev/null
+++ b/guest/commands/setup_network/main.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/libs/net/netlink_client.h"
+#include "common/libs/net/netlink_request.h"
+#include "common/libs/net/network_interface.h"
+#include "common/libs/net/network_interface_manager.h"
+#include "common/libs/glog/logging.h"
+
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <iostream>
+#include <string>
+#include <cstdlib>
+
+int IpLinkAdd(const std::string& source, const std::string& destination,
+ const std::string& type, int vlan_index) {
+ auto factory = cvd::NetlinkClientFactory::Default();
+ std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
+
+ // http://maz-programmersdiary.blogspot.com/2011/09/netlink-sockets.html
+ cvd::NetlinkRequest link_add_request(RTM_NEWLINK,
+ NLM_F_REQUEST|NLM_F_ACK|0x600);
+ link_add_request.Append(ifinfomsg {
+ .ifi_change = 0xFFFFFFFF,
+ });
+ int32_t index = if_nametoindex(source.c_str());
+ if (index == 0) {
+ LOG(ERROR) << "setup_network: invalid interface name '" << source << "'\n";
+ return -2;
+ }
+ link_add_request.AddString(IFLA_IFNAME, destination);
+ link_add_request.AddInt(IFLA_LINK, index);
+
+ link_add_request.PushList(IFLA_LINKINFO);
+ link_add_request.AddString(IFLA_INFO_KIND, type.c_str());
+ link_add_request.PushList(IFLA_INFO_DATA);
+ if (type == "vlan") {
+ link_add_request.AddInt(IFLA_VLAN_ID, vlan_index);
+ }
+ link_add_request.PopList();
+ link_add_request.PopList();
+
+ bool link_add_success = nl->Send(link_add_request);
+ if (!link_add_success) {
+ LOG(ERROR) << "setup_network: could not add link " << destination;
+ return -3;
+ }
+
+ cvd::NetlinkRequest bring_up_backing_request(RTM_SETLINK,
+ NLM_F_REQUEST|NLM_F_ACK|0x600);
+ bring_up_backing_request.Append(ifinfomsg {
+ .ifi_index = index,
+ .ifi_flags = IFF_UP,
+ .ifi_change = 0xFFFFFFFF,
+ });
+
+ bool link_backing_up = nl->Send(bring_up_backing_request);
+ if (!link_backing_up) {
+ LOG(ERROR) << "setup_network: could not bring up backing " << source;
+ return -4;
+ }
+
+ return 0;
+}
+
+int CreateVlan(const std::string& source, const std::string& destination,
+ int vlan_index) {
+ return IpLinkAdd(source, destination, "vlan", vlan_index);
+}
+
+int CreateWifiWrapper(const std::string& source,
+ const std::string& destination) {
+ return IpLinkAdd(source, destination, "virt_wifi", -1);
+}
+
+int RenameNetwork(const std::string& name, const std::string& new_name) {
+ static auto net_manager =
+ cvd::NetworkInterfaceManager::New(cvd::NetlinkClientFactory::Default());
+ auto connection = net_manager->Open(name, "ignore");
+ if (!connection) {
+ LOG(ERROR) << "setup_network: could not open " << name << " on device.";
+ return -1;
+ }
+ connection->SetName(new_name);
+ bool changes_applied = net_manager->ApplyChanges(*connection);
+ if (!changes_applied) {
+ LOG(ERROR) << "setup_network: can't rename " << name << " to " << new_name;
+ return -1;
+ }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ LOG(ERROR) << "setup_network: must be invoked with only "
+ << "${ro.boot.cuttlefish_network}";
+ }
+ int ret = 0;
+ if (std::string(argv[1]) == "vlan") {
+ ret += RenameNetwork("eth0", "buried_eth0");
+ ret += CreateVlan("buried_eth0", "buried_wlan0", 11);
+ ret += CreateWifiWrapper("buried_wlan0", "wlan0");
+ ret += CreateVlan("buried_eth0", "rmnet0", 12);
+ } else if (std::string(argv[1]) == "legacy") {
+ ret += RenameNetwork("eth0", "buried_eth0");
+ ret += CreateWifiWrapper("buried_eth0", "wlan0");
+ ret += RenameNetwork("eth1", "rmnet0");
+ } else {
+ LOG(ERROR) << "setup_network: unknown configuration '" << argv[1] << "'";
+ }
+ return ret;
+}
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index 0cf4f28..39461d6 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -170,6 +170,10 @@
"Network interface to use for wifi");
DEFINE_string(wifi_tap_name, "", // default handled on ParseCommandLine
"The name of the tap interface to use for wifi");
+DEFINE_string(vlan_tap_name, "", // default handled on ParseCommandLine
+ "The name of the tap interface to use for the vlan network");
+DEFINE_bool(guest_vlans, false,
+ "Force the guest to use or not use VLANs.");
// TODO(b/72969289) This should be generated
DEFINE_string(dtb, "", "Path to the cuttlefish.dtb file");
@@ -573,6 +577,8 @@
if (FLAGS_extra_kernel_cmdline.size()) {
config->add_kernel_cmdline(FLAGS_extra_kernel_cmdline);
}
+ config->add_kernel_cmdline(concat("androidboot.cuttlefish_network=",
+ FLAGS_guest_vlans ? "vlan" : "legacy"));
config->set_ramdisk_image_path(ramdisk_path);
config->set_system_image_path(FLAGS_system_image);
@@ -608,6 +614,9 @@
config->set_wifi_bridge_name(FLAGS_wifi_interface);
config->set_wifi_tap_name(FLAGS_wifi_tap_name);
+ config->set_guest_vlans(FLAGS_guest_vlans);
+ config->set_vlan_tap_name(FLAGS_vlan_tap_name);
+
config->set_wifi_guest_mac_addr(FLAGS_guest_mac_address);
config->set_wifi_host_mac_addr(FLAGS_host_mac_address);
@@ -644,6 +653,10 @@
SetCommandLineOptionWithMode("wifi_tap_name",
default_wifi_tap_name.c_str(),
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+ auto default_vlan_tap_name = GetPerInstanceDefault("cvd-net-");
+ SetCommandLineOptionWithMode("vlan_tap_name",
+ default_vlan_tap_name.c_str(),
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
auto default_instance_dir =
cvd::StringFromEnv("HOME", ".") + "/cuttlefish_runtime";
SetCommandLineOptionWithMode("instance_dir",
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index d1507f8..9c9325e 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -108,6 +108,8 @@
const char* kMobileTapName = "mobile_tap_name";
const char* kWifiBridgeName = "wifi_bridge_name";
const char* kWifiTapName = "wifi_tap_name";
+const char* kVlanTapName = "vlan_tap_name";
+const char* kGuestVlansName = "guest_vlans";
const char* kWifiGuestMacAddr = "wifi_guest_mac_addr";
const char* kWifiHostMacAddr = "wifi_host_mac_addr";
const char* kEntropySource = "entropy_source";
@@ -428,6 +430,20 @@
(*dictionary_)[kWifiTapName] = wifi_tap_name;
}
+bool CuttlefishConfig::guest_vlans() const {
+ return (*dictionary_)[kGuestVlansName].asBool();
+}
+void CuttlefishConfig::set_guest_vlans(bool guest_vlans) {
+ (*dictionary_)[kGuestVlansName] = guest_vlans;
+}
+
+std::string CuttlefishConfig::vlan_tap_name() const {
+ return (*dictionary_)[kVlanTapName].asString();
+}
+void CuttlefishConfig::set_vlan_tap_name(const std::string& vlan_tap_name) {
+ (*dictionary_)[kVlanTapName] = vlan_tap_name;
+}
+
std::string CuttlefishConfig::entropy_source() const {
return (*dictionary_)[kEntropySource].asString();
}
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index cbe280d..e48ab50 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -162,6 +162,12 @@
std::string wifi_tap_name() const;
void set_wifi_tap_name(const std::string& wifi_tap_name);
+ std::string vlan_tap_name() const;
+ void set_vlan_tap_name(const std::string& vlan_tap_name);
+
+ bool guest_vlans() const;
+ void set_guest_vlans(bool guest_vlans);
+
std::string wifi_guest_mac_addr() const;
void set_wifi_guest_mac_addr(const std::string& wifi_guest_mac_addr);
diff --git a/host/libs/vm_manager/cf_qemu.sh b/host/libs/vm_manager/cf_qemu.sh
index ee46ef2..8953b5d 100755
--- a/host/libs/vm_manager/cf_qemu.sh
+++ b/host/libs/vm_manager/cf_qemu.sh
@@ -23,12 +23,14 @@
echo "01"
fi
}
+pci_index=1
CUTTLEFISH_INSTANCE="${CUTTLEFISH_INSTANCE:-$(default_instance_number)}"
default_instance_name="cvd-${CUTTLEFISH_INSTANCE}"
default_uuid="699acfc4-c8c4-11e7-882b-5065f31dc1${CUTTLEFISH_INSTANCE}"
default_dir="${HOME}/cuttlefish_runtime"
default_mobile_tap_name="cvd-mtap-${CUTTLEFISH_INSTANCE}"
default_wifi_tap_name="cvd-wtap-${CUTTLEFISH_INSTANCE}"
+default_vlan_tap_name="cvd-net-${CUTTLEFISH_INSTANCE}"
if [[ -z "${ivshmem_vector_count}" ]]; then
echo "The required ivshmem_vector_count environment variable is not set" >&2
@@ -54,29 +56,41 @@
-kernel "${kernel_image_path:-${HOME}/kernel}"
-append "${kernel_cmdline:-"loop.max_part=7 console=ttyS0 androidboot.console=ttyS1 androidboot.hardware=vsoc enforcing=0 audit=1 androidboot.selinux=permissive mac80211_hwsim.radios=0 security=selinux buildvariant=userdebug androidboot.serialno=CUTTLEFISHCVD01 androidboot.lcd_density=160"}"
-dtb "${dtb_path:-${HOME}/config/cuttlefish.dtb}"
- -device "piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2"
- -device "virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x4"
- -drive "file=${system_image_path:-${HOME}/system.img},format=raw,if=none,id=drive-virtio-disk0,aio=threads"
- -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1"
- -drive "file=${data_image_path:-${HOME}/userdata.img},format=raw,if=none,id=drive-virtio-disk1,aio=threads"
- -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk1"
- -drive "file=${cache_image_path:-${HOME}/cache.img},format=raw,if=none,id=drive-virtio-disk2,aio=threads"
- -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=0x7,drive=drive-virtio-disk2,id=virtio-disk2"
- -drive "file=${vendor_image_path:-${HOME}/vendor.img},format=raw,if=none,id=drive-virtio-disk3,aio=threads"
- -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=0x8,drive=drive-virtio-disk3,id=virtio-disk3"
+ -device "piix3-usb-uhci,id=usb,bus=pci.0,addr=$((pci_index++)).${pci_index}"
+)
+if [ "${guest_vlans:-false}" = true ] ; then
+ args+=(
+ -netdev "tap,id=hostnet0,ifname=${vlan_tap_name:-${default_vlan_tap_name}},script=no,downscript=no"
+ -device "virtio-net-pci,netdev=hostnet0,id=net0,bus=pci.0,addr=$((pci_index++))"
+ )
+else
+ args+=(
-netdev "tap,id=hostnet0,ifname=${wifi_tap_name:-${default_wifi_tap_name}},script=no,downscript=no"
- -device "virtio-net-pci,netdev=hostnet0,id=net0,bus=pci.0,addr=0x2"
+ -device "virtio-net-pci,netdev=hostnet0,id=net0,bus=pci.0,addr=$((pci_index++))"
-netdev "tap,id=hostnet1,ifname=${mobile_tap_name:-${default_mobile_tap_name}},script=no,downscript=no"
- -device "virtio-net-pci,netdev=hostnet1,id=net1,bus=pci.0,addr=0x3"
+ -device "virtio-net-pci,netdev=hostnet1,id=net1,bus=pci.0,addr=$((pci_index++))"
+ )
+fi
+
+args+=(
+ -device "virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=$((pci_index++))"
+ -drive "file=${system_image_path:-${HOME}/system.img},format=raw,if=none,id=drive-virtio-disk0,aio=threads"
+ -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=$((pci_index++)),drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1"
+ -drive "file=${data_image_path:-${HOME}/userdata.img},format=raw,if=none,id=drive-virtio-disk1,aio=threads"
+ -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=$((pci_index++)),drive=drive-virtio-disk1,id=virtio-disk1"
+ -drive "file=${cache_image_path:-${HOME}/cache.img},format=raw,if=none,id=drive-virtio-disk2,aio=threads"
+ -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=$((pci_index++)),drive=drive-virtio-disk2,id=virtio-disk2"
+ -drive "file=${vendor_image_path:-${HOME}/vendor.img},format=raw,if=none,id=drive-virtio-disk3,aio=threads"
+ -device "virtio-blk-pci,scsi=off,bus=pci.0,addr=$((pci_index++)),drive=drive-virtio-disk3,id=virtio-disk3"
-chardev "socket,id=charserial0,path=${kernel_log_socket_name:-${default_dir}/kernel-log}"
-device "isa-serial,chardev=charserial0,id=serial0"
-chardev "socket,id=charserial1,path=${console_path:-${default_dir}/console},server,nowait"
-device "isa-serial,chardev=charserial1,id=serial1"
-chardev "file,id=charchannel0,path=${logcat_path:-${default_dir}/logcat},append=on"
-device "virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=cf-logcat"
- -device "virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x9"
+ -device "virtio-balloon-pci,id=balloon0,bus=pci.0,addr=$((pci_index++))"
-object "rng-random,id=objrng0,filename=/dev/urandom"
- -device "virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=1024,period=2000,bus=pci.0,addr=0xa"
+ -device "virtio-rng-pci,rng=objrng0,id=rng0,max-bytes=1024,period=2000,bus=pci.0,addr=$((pci_index++))"
-chardev "socket,path=${ivshmem_qemu_socket_path:-${default_dir}/ivshmem_socket_qemu},id=ivsocket"
-device "ivshmem-doorbell,chardev=ivsocket,vectors=${ivshmem_vector_count}"
-cpu host
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 7d7d92b..64b15d8 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -74,6 +74,8 @@
LogAndSetEnv("cache_image_path", config->cache_image_path());
LogAndSetEnv("vendor_image_path", config->vendor_image_path());
LogAndSetEnv("wifi_tap_name", config->wifi_tap_name());
+ LogAndSetEnv("vlan_tap_name", config->vlan_tap_name());
+ LogAndSetEnv("guest_vlans", config->guest_vlans() ? "true" : "false");
LogAndSetEnv("mobile_tap_name", config->mobile_tap_name());
LogAndSetEnv("kernel_log_socket_name",
config->kernel_log_socket_name());