Skip to content

Commit d3a9240

Browse files
author
Brian Daniels
committed
Optimize TAP interface check.
Before this change, the TAP interface check would search through every active process' file descriptors to find which tap interfaces were in use. Instead, now we attempt to open each TAP interface and report any errors. This reduces the runtime of the TAP interface check from about 6 seconds to under 0.1 seconds (when tested on my workstation). Bug: 401259067 Test: check launcher.log for total runtime improvement
1 parent 401b5c0 commit d3a9240

6 files changed

Lines changed: 38 additions & 84 deletions

File tree

base/cvd/allocd/alloc_utils.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
#include "cuttlefish/host/commands/cvd/utils/common.h"
3131
#include "cuttlefish/result/result.h"
3232

33+
#ifdef __linux__
34+
#include <linux/if_tun.h>
35+
#endif
36+
37+
#include <net/if.h>
38+
3339
namespace cuttlefish {
3440

3541
bool CreateEthernetIface(std::string_view name, std::string_view bridge_name) {
@@ -124,6 +130,27 @@ bool CreateTap(std::string_view name) {
124130
return true;
125131
}
126132

133+
#ifdef __linux__
134+
Result<void> ValidateTapInterfaceIsUsable(const std::string& interface_name) {
135+
constexpr auto kTunTapDev = "/dev/net/tun";
136+
137+
auto tap_fd = SharedFD::Open(kTunTapDev, O_RDWR | O_NONBLOCK);
138+
CF_EXPECTF(tap_fd->IsOpen(), "Unable to open tun device: {}",
139+
tap_fd->StrError());
140+
141+
struct ifreq ifr;
142+
memset(&ifr, 0, sizeof(ifr));
143+
ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
144+
strncpy(ifr.ifr_name, interface_name.c_str(), IFNAMSIZ);
145+
146+
int err = tap_fd->Ioctl(TUNSETIFF, &ifr);
147+
CF_EXPECTF(err == 0, "Unable to connect to {} tap interface: {}",
148+
interface_name, tap_fd->StrError());
149+
150+
return {};
151+
}
152+
#endif
153+
127154
bool DestroyIface(std::string_view name) {
128155
if (!ShutdownIface(name).ok()) {
129156
LOG(WARNING) << "Failed to shutdown tap interface: " << name;

base/cvd/allocd/alloc_utils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include <optional>
2525
#include <string_view>
26+
#include "cuttlefish/result/result.h"
2627

2728
namespace cuttlefish {
2829

@@ -53,6 +54,10 @@ std::optional<std::string> GetUserName(uid_t uid);
5354

5455
bool CreateTap(std::string_view name);
5556

57+
#ifdef __linux__
58+
Result<void> ValidateTapInterfaceIsUsable(const std::string& interface_name);
59+
#endif
60+
5661

5762
bool DestroyIface(std::string_view name);
5863

base/cvd/cuttlefish/common/libs/utils/network.cpp

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,9 @@
1616

1717
#include "cuttlefish/common/libs/utils/network.h"
1818

19-
#ifdef __linux__
20-
#include <linux/if_ether.h>
21-
// Kernel headers don't mix well with userspace headers, but there is no
22-
// userspace header that provides the if_tun.h #defines. Include the kernel
23-
// header, but move conflicting definitions out of the way using macros.
24-
#define ethhdr __kernel_ethhdr
25-
#include <linux/if_tun.h>
26-
#undef ethhdr
27-
#endif
28-
2919
#include <arpa/inet.h>
3020
#include <fcntl.h>
3121
#include <ifaddrs.h>
32-
#include <net/if.h>
3322
#include <stdint.h>
3423

3524
#include <cstring>
@@ -86,68 +75,6 @@ bool NetworkInterfaceExists(const std::string& interface_name) {
8675
return ret;
8776
}
8877

89-
#ifdef __linux__
90-
static std::optional<Command> GrepCommand() {
91-
if (FileExists("/usr/bin/grep")) {
92-
return Command("/usr/bin/grep");
93-
} else if (FileExists("/bin/grep")) {
94-
return Command("/bin/grep");
95-
} else {
96-
return {};
97-
}
98-
}
99-
100-
std::set<std::string> TapInterfacesInUse() {
101-
std::vector<std::string> fdinfo_list;
102-
103-
Result<std::vector<std::string>> processes = DirectoryContents("/proc");
104-
if (!processes.ok()) {
105-
LOG(ERROR) << "Failed to get contents of `/proc/`";
106-
return {};
107-
}
108-
for (const std::string& process : *processes) {
109-
std::string fdinfo_path = fmt::format("/proc/{}/fdinfo", process);
110-
Result<std::vector<std::string>> fdinfos = DirectoryContents(fdinfo_path);
111-
if (!fdinfos.ok()) {
112-
VLOG(1) << "Failed to get contents of '" << fdinfo_path << "'";
113-
continue;
114-
}
115-
for (const std::string& fdinfo : *fdinfos) {
116-
std::string path = fmt::format("/proc/{}/fdinfo/{}", process, fdinfo);
117-
fdinfo_list.emplace_back(std::move(path));
118-
}
119-
}
120-
121-
std::optional<Command> cmd = GrepCommand();
122-
if (!cmd) {
123-
LOG(WARNING) << "Unable to test TAP interface usage";
124-
return {};
125-
}
126-
cmd->AddParameter("-E").AddParameter("-h").AddParameter("-e").AddParameter(
127-
"^iff:.*");
128-
129-
for (const std::string& fdinfo : fdinfo_list) {
130-
cmd->AddParameter(fdinfo);
131-
}
132-
133-
std::string stdout_str = RunAndCaptureStdout(std::move(*cmd)).value_or("");
134-
135-
std::vector<std::string_view> lines = absl::StrSplit(stdout_str, '\n');
136-
std::set<std::string> tap_interfaces;
137-
for (const auto& line : lines) {
138-
if (line.empty()) {
139-
continue;
140-
}
141-
if (!absl::StartsWith(line, "iff:\t")) {
142-
LOG(ERROR) << "Unexpected line \"" << line << "\"";
143-
continue;
144-
}
145-
tap_interfaces.emplace(line.substr(std::string("iff:\t").size()));
146-
}
147-
return tap_interfaces;
148-
}
149-
#endif
150-
15178
std::string MacAddressToString(const uint8_t mac[6]) {
15279
std::vector<uint8_t> mac_vec(mac, mac + 6);
15380
return fmt::format("{:0>2x}", fmt::join(mac_vec, ":"));

base/cvd/cuttlefish/common/libs/utils/network.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@
2222
namespace cuttlefish {
2323
// Check network interface with given name exists, such as cvd-ebr.
2424
bool NetworkInterfaceExists(const std::string& interface_name);
25-
26-
#ifdef __linux__
27-
// Returns a list of TAP devices that have open file descriptors
28-
std::set<std::string> TapInterfacesInUse();
29-
#endif
30-
3125
void GenerateCorrespondingIpv6ForMac(const uint8_t mac[6], uint8_t out[16]);
3226
void GenerateMobileMacForInstance(int index, uint8_t out[6]);
3327
void GenerateEthMacForInstance(int index, uint8_t out[6]);

base/cvd/cuttlefish/host/commands/run_cvd/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ cf_cc_library(
162162
srcs = ["validate.cpp"],
163163
hdrs = ["validate.h"],
164164
deps = [
165+
"//allocd:alloc_utils",
165166
"//cuttlefish/common/libs/utils:in_sandbox",
166167
"//cuttlefish/common/libs/utils:network",
167168
"//cuttlefish/host/libs/config:cuttlefish_config",

base/cvd/cuttlefish/host/commands/run_cvd/validate.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
#include "absl/log/log.h"
2323

24+
#include "allocd/alloc_utils.h"
2425
#include "cuttlefish/common/libs/utils/in_sandbox.h"
25-
#include "cuttlefish/common/libs/utils/network.h"
2626
#include "cuttlefish/host/libs/config/cuttlefish_config.h"
2727
#include "cuttlefish/posix/strerror.h"
2828
#include "cuttlefish/result/result.h"
@@ -35,13 +35,13 @@ static Result<void> TestTapDevices(
3535
if (InSandbox()) {
3636
return {};
3737
}
38-
auto taps = TapInterfacesInUse();
3938
auto wifi = instance.wifi_tap_name();
40-
CF_EXPECTF(taps.count(wifi) == 0, "Device \"{}\" in use", wifi);
39+
CF_EXPECTF(ValidateTapInterfaceIsUsable(wifi), "Device \"{}\" in use", wifi);
4140
auto mobile = instance.mobile_tap_name();
42-
CF_EXPECTF(taps.count(mobile) == 0, "Device \"{}\" in use", mobile);
41+
CF_EXPECTF(ValidateTapInterfaceIsUsable(mobile), "Device \"{}\" in use",
42+
mobile);
4343
auto eth = instance.ethernet_tap_name();
44-
CF_EXPECTF(taps.count(eth) == 0, "Device \"{}\" in use", eth);
44+
CF_EXPECTF(ValidateTapInterfaceIsUsable(eth), "Device \"{}\" in use", eth);
4545
#else
4646
(void)instance;
4747
#endif

0 commit comments

Comments
 (0)