From patchwork Thu Jan 24 15:50:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matteo Croce X-Patchwork-Id: 1030530 X-Patchwork-Delegate: dsahern@gmail.com Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43lmpV5hTgz9s1l for ; Fri, 25 Jan 2019 02:50:58 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728563AbfAXPu5 (ORCPT ); Thu, 24 Jan 2019 10:50:57 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:42821 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727566AbfAXPu5 (ORCPT ); Thu, 24 Jan 2019 10:50:57 -0500 Received: by mail-wr1-f66.google.com with SMTP id q18so6988806wrx.9 for ; Thu, 24 Jan 2019 07:50:55 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=iXlG8VhOHaX9pdjZRyg49/F5dDbTv1jiASrFSNhuF8E=; b=JgMxuunREfUOs1OKWnHuLxpOge0C1zlPAz7eyqWnxLGu/QZbTQnTrUzRw71EXHqcRa FUUeM5iOhmhfY2oC/iiBBI5o6qls9knBCmT63Y2IutIXJdr5kF8o6M83BNJ6si5QApft oOzOFRrJ/zK4tPEMcsGAavgJ052hrKISj/yAl9qQyg5+cH45xS+tMpFxrmuuZ9G2GWdc ljULETzkeVnamp+wDCv0c+mSRpgolWXKOqchdmY1ryNDJ5NOLx9uq1ORfuPr1Lsm8UqN oFIGQ98R057aP3/R6aQCPf+5x5+Ofs8BlJOb0COWVCnIqXeXrE8Moyp51nOraM2Pp1Rk qZTA== X-Gm-Message-State: AJcUukfKGAMNAOpK2IEB/6M14f062jEMcrT4GZVt6yoLz/xmOdWQIL8V 0KCGsMae66kxkHBF7KoW0zzoSSgLML2dgw== X-Google-Smtp-Source: ALg8bN69R+Ekkn0uVC07KMwoK5h/IxbDJLW6NTK2Za/ZMx179U9lJNx6SI9my98sXWG1TFHyFME3QA== X-Received: by 2002:a05:6000:12c4:: with SMTP id l4mr7631286wrx.134.1548345054450; Thu, 24 Jan 2019 07:50:54 -0800 (PST) Received: from mcroce-redhat.redhat.com (ovpn-brq.redhat.com. [213.175.37.11]) by smtp.gmail.com with ESMTPSA id 129sm103688209wmd.18.2019.01.24.07.50.53 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 24 Jan 2019 07:50:53 -0800 (PST) From: Matteo Croce To: netdev@vger.kernel.org Cc: David Ahern , Stephen Hemminger Subject: [PATCH iproute2-next] netns: add subcommand to attach an existing network namespace Date: Thu, 24 Jan 2019 16:50:53 +0100 Message-Id: <20190124155053.7795-1-mcroce@redhat.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org ip tracks namespaces with dummy files in /var/run/netns/, but can't see namespaces created with other tools. Creating the dummy file and bind mounting the correct procfs entry will make ip aware of that namespace. Add an ip netns subcommand to automate this task. Signed-off-by: Matteo Croce --- ip/ipnetns.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ man/man8/ip-netns.8 | 10 ++++++ 2 files changed, 94 insertions(+) diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 03879b49..86b1a36b 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -28,6 +28,7 @@ static int usage(void) { fprintf(stderr, "Usage: ip netns list\n"); fprintf(stderr, " ip netns add NAME\n"); + fprintf(stderr, " ip netns attach NAME PID\n"); fprintf(stderr, " ip netns set NAME NETNSID\n"); fprintf(stderr, " ip [-all] netns delete [NAME]\n"); fprintf(stderr, " ip netns identify [PID]\n"); @@ -811,6 +812,86 @@ static int netns_monitor(int argc, char **argv) return 0; } +static int netns_attach(int argc, char **argv) +{ + /* This function bind mounts an existing network namespace to a + * well known location in the filesystem based on the name provided. + * If everything succeeds, the result is the same as netns_add. + * + * The mount namespace is created so that any necessary + * userspace tweaks like remounting /sys, or bind mounting + * a new /etc/resolv.conf can be shared between users. + */ + char netns_path[PATH_MAX], proc_path[PATH_MAX]; + const char *name; + int fd; + pid_t pid; + int made_netns_run_dir_mount = 0; + + if (argc < 2) { + fprintf(stderr, "No netns name and PID specified\n"); + return -1; + } + name = argv[0]; + + if (get_s32(&pid, argv[1], 0) || !pid) { + fprintf(stderr, "Invalid PID: %s\n", argv[1]); + return -1; + } + + snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name); + + if (create_netns_dir()) + return -1; + + /* Make it possible for network namespace mounts to propagate between + * mount namespaces. This makes it likely that a unmounting a network + * namespace file in one namespace will unmount the network namespace + * file in all namespaces allowing the network namespace to be freed + * sooner. + */ + while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) { + /* Fail unless we need to make the mount point */ + if (errno != EINVAL || made_netns_run_dir_mount) { + fprintf(stderr, "mount --make-shared %s failed: %s\n", + NETNS_RUN_DIR, strerror(errno)); + return -1; + } + + /* Upgrade NETNS_RUN_DIR to a mount point */ + if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) { + fprintf(stderr, "mount --bind %s %s failed: %s\n", + NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno)); + return -1; + } + made_netns_run_dir_mount = 1; + } + + /* Create the filesystem state */ + fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0); + if (fd < 0) { + fprintf(stderr, "Cannot create namespace file \"%s\": %s\n", + netns_path, strerror(errno)); + return -1; + } + close(fd); + + snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid); + + /* Bind the netns last so I can watch for it */ + if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) { + fprintf(stderr, "Bind %s -> %s failed: %s\n", + proc_path, netns_path, strerror(errno)); + goto out_delete; + } + return 0; +out_delete: + if (unlink(netns_path) < 0) + fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n", + netns_path, strerror(errno)); + return -1; +} + static int invalid_name(const char *name) { return !*name || strlen(name) > NAME_MAX || @@ -866,6 +947,9 @@ int do_netns(int argc, char **argv) if (matches(*argv, "monitor") == 0) return netns_monitor(argc-1, argv+1); + if (matches(*argv, "attach") == 0) + return netns_attach(argc-1, argv+1); + fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv); exit(-1); } diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8 index d539f18b..39a10e76 100644 --- a/man/man8/ip-netns.8 +++ b/man/man8/ip-netns.8 @@ -19,6 +19,10 @@ ip-netns \- process network namespace management .B ip netns add .I NETNSNAME +.ti -8 +.B ip netns attach +.I NETNSNAME PID + .ti -8 .B ip [-all] netns del .RI "[ " NETNSNAME " ]" @@ -89,6 +93,12 @@ This command displays all of the network namespaces in /var/run/netns If NAME is available in /var/run/netns/ this command creates a new network namespace and assigns NAME. +.TP +.B ip netns attach NAME PID - create a new named network namespace +.sp +If NAME is available in /var/run/netns/ this command attaches the network +namespace of the process PID to NAME as if it were created with ip netns. + .TP .B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s) .sp