patchpanel: Support open a new netns via ConnectNamespace
Currently the ConnectNamespace API exposed by patchpanel via d-bus only
supports passing in a pid of a process and doing "ConnectNamespace" for
the netns associated with this process. While in the tast tests,
sometimes we need to open a new netns directly, and execute processes in
the created netns.
For this usage, this patch modifies the ConnectNamespace API so that
patchpanel accepts passing a special pid (i.e., pid==-1) to indicates
the client wants a new netns, invokes `ip netns add` for this case, and
returns the name of the created netns.
BUG=b:185210339
TEST=unit_tests;
TEST=Used this API in test VPN tast test, verified it worked;
TEST=Checked playstore still worked.
Change-Id: I3bbfab89df24899127e6087b0c0533e2c96037dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2896672
Reviewed-by: Garrick Evans <garrick@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
Tested-by: Jie Jiang <jiejiang@chromium.org>
Commit-Queue: Jie Jiang <jiejiang@chromium.org>
diff --git a/patchpanel/scoped_ns.cc b/patchpanel/scoped_ns.cc
index 431deaf..3e4585e 100644
--- a/patchpanel/scoped_ns.cc
+++ b/patchpanel/scoped_ns.cc
@@ -6,32 +6,45 @@
#include <fcntl.h>
#include <sched.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <string>
+#include <utility>
+
+#include <base/memory/ptr_util.h>
namespace patchpanel {
-ScopedNS::ScopedNS(pid_t pid, Type type) : valid_(false) {
- std::string current_ns_path;
- std::string target_ns_path;
- switch (type) {
- case Mount:
- nstype_ = CLONE_NEWNS;
- current_ns_path = "/proc/self/ns/mnt";
- target_ns_path = "/proc/" + std::to_string(pid) + "/ns/mnt";
- break;
- case Network:
- nstype_ = CLONE_NEWNET;
- current_ns_path = "/proc/self/ns/net";
- target_ns_path = "/proc/" + std::to_string(pid) + "/ns/net";
- break;
- default:
- LOG(ERROR) << "Unsupported namespace type " << type;
- return;
- }
+std::unique_ptr<ScopedNS> ScopedNS::EnterMountNS(pid_t pid) {
+ int nstype = CLONE_NEWNS;
+ const std::string current_path = "/proc/self/ns/mnt";
+ const std::string target_path = "/proc/" + std::to_string(pid) + "/ns/mnt";
+ auto ns = base::WrapUnique(new ScopedNS(nstype, current_path, target_path));
+ return ns->valid_ ? std::move(ns) : nullptr;
+}
+std::unique_ptr<ScopedNS> ScopedNS::EnterNetworkNS(pid_t pid) {
+ int nstype = CLONE_NEWNET;
+ const std::string current_path = "/proc/self/ns/net";
+ const std::string target_path = "/proc/" + std::to_string(pid) + "/ns/net";
+ auto ns = base::WrapUnique(new ScopedNS(nstype, current_path, target_path));
+ return ns->valid_ ? std::move(ns) : nullptr;
+}
+
+std::unique_ptr<ScopedNS> ScopedNS::EnterNetworkNS(
+ const std::string& netns_name) {
+ int nstype = CLONE_NEWNET;
+ const std::string current_path = "/proc/self/ns/net";
+ const std::string target_path = "/run/netns/" + netns_name;
+ auto ns = base::WrapUnique(new ScopedNS(nstype, current_path, target_path));
+ return ns->valid_ ? std::move(ns) : nullptr;
+}
+
+ScopedNS::ScopedNS(int nstype,
+ const std::string& current_ns_path,
+ const std::string& target_ns_path)
+ : nstype_(nstype), valid_(false) {
ns_fd_.reset(open(target_ns_path.c_str(), O_RDONLY | O_CLOEXEC));
if (!ns_fd_.is_valid()) {
PLOG(ERROR) << "Could not open namespace " << target_ns_path;