From patchwork Thu Sep 10 03:09:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: yang_y_yi X-Patchwork-Id: 1361170 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=163.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.a=rsa-sha256 header.s=s110527 header.b=Luh3VhAp; dkim-atps=neutral Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Bn3lm5bnqz9sTX for ; Thu, 10 Sep 2020 13:09:56 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 063678761A; Thu, 10 Sep 2020 03:09:51 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id haq-e2fbTLKs; Thu, 10 Sep 2020 03:09:48 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 46A1087459; Thu, 10 Sep 2020 03:09:48 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 25BCEC0052; Thu, 10 Sep 2020 03:09:48 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id F1F76C0051 for ; Thu, 10 Sep 2020 03:09:46 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id D8A5786FDC for ; Thu, 10 Sep 2020 03:09:46 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SIIP359vFz91 for ; Thu, 10 Sep 2020 03:09:45 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-m971.mail.163.com (mail-m971.mail.163.com [123.126.97.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 55DF786DE0 for ; Thu, 10 Sep 2020 03:09:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-Id:MIME-Version; bh=Ihbru F6/8JLJiLxvZ4Jl1LoyDM2UPPOjqz5SJIVulHw=; b=Luh3VhApI6Av3PWMGZxjn 2raH0i0lhcAK4c6ps4IPrDWnNU4IOTU+Xjjhf7MGAopHEQRVqkx7ID62mymcuVQz UwVIKEIg07xwPzvrMYHbbHpmz5qPpb+EFshDO9C24uJuePOAvZFOg5CzjDRgfBpy pfP4mvhTFo0XCZOu3S6ROk= Received: from yangyi0100.home.langchao.com (unknown [111.207.123.58]) by smtp1 (Coremail) with SMTP id GdxpCgDnTzDvmFlfaPxiBQ--.766S3; Thu, 10 Sep 2020 11:09:36 +0800 (CST) From: yang_y_yi@163.com To: ovs-dev@openvswitch.org Date: Thu, 10 Sep 2020 11:09:32 +0800 Message-Id: <20200910030934.116248-2-yang_y_yi@163.com> X-Mailer: git-send-email 2.19.2.windows.1 In-Reply-To: <20200910030934.116248-1-yang_y_yi@163.com> References: <20200910030934.116248-1-yang_y_yi@163.com> MIME-Version: 1.0 X-CM-TRANSID: GdxpCgDnTzDvmFlfaPxiBQ--.766S3 X-Coremail-Antispam: 1Uf129KBjvJXoWxWFW3Cw43uFWfGr4DGw1fCrg_yoW5AFWfpa y5JF15Jr1rGFW3Xrn3J3sxWr15Wr4kCr47C34fAa43Xryqv348Wa1vgry7Cr9xC3y5AFn5 Jw4j9FW8K34xZaDanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07UmJPiUUUUU= X-Originating-IP: [111.207.123.58] X-CM-SenderInfo: 51dqwsp1b1xqqrwthudrp/xtbBEBCbi1UMToLKJwAAso Cc: i.maximets@ovn.org, yang_y_yi@163.com, fbl@sysclose.org Subject: [ovs-dev] [PATCH v2 1/3] Add netns option for tap interface in userspace datapath X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Yi Yang In userspace datapath, "ovs-vsctl list interface" can't get interface statistics and there are many WARN log, we can enable it work normally if it has correct network namespace. This patch enabled netns option for tap interface , it is the prerequisite interface statistics and other ioctl can work normally. Signed-off-by: Yi Yang --- lib/netdev-linux-private.h | 1 + lib/netdev-linux.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/lib/netdev-linux-private.h b/lib/netdev-linux-private.h index c7c515f..fbedfd9 100644 --- a/lib/netdev-linux-private.h +++ b/lib/netdev-linux-private.h @@ -68,6 +68,7 @@ struct netdev_linux { struct timer miimon_timer; int netnsid; /* Network namespace ID. */ + char *netns; /* Network namespace name. */ /* The following are figured out "on demand" only. They are only valid * when the corresponding VALID_* bit in 'cache_valid' is set. */ int ifindex; diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index fe7fb9b..ebe4ddb 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -1054,6 +1054,9 @@ netdev_linux_destruct(struct netdev *netdev_) { ioctl(netdev->tap_fd, TUNSETPERSIST, 0); close(netdev->tap_fd); + if (netdev->netns != NULL) { + free(netdev->netns); + } } if (netdev->miimon_interval > 0) { @@ -3509,6 +3512,48 @@ exit: return error; } +static int +netdev_tap_set_config(struct netdev *netdev, const struct smap *args, + char **errp OVS_UNUSED) +{ + struct netdev_linux *dev = netdev_linux_cast(netdev); + const char *netns; + + ovs_mutex_lock(&dev->mutex); + netns = smap_get(args, "netns"); + if (netns != NULL) { + char nspath[128]; + int nsfd; + + sprintf(nspath, "/var/run/netns/%s", netns); + nsfd = open(nspath, O_RDONLY); + if (nsfd < 0) { + ovs_mutex_unlock(&dev->mutex); + VLOG_ERR("%s: netns %s doesn't exist.", + netdev_get_name(netdev), netns); + return EINVAL; + } + close(nsfd); + } + + if (netns != NULL) { + dev->netns = xstrdup(netns); + } + ovs_mutex_unlock(&dev->mutex); + return 0; +} + +static int +netdev_tap_get_config(const struct netdev *netdev, struct smap *args) +{ + struct netdev_linux *dev = netdev_linux_cast(netdev); + + ovs_mutex_lock(&dev->mutex); + smap_add_format(args, "netns", "%s", dev->netns); + ovs_mutex_unlock(&dev->mutex); + return 0; +} + #define NETDEV_LINUX_CLASS_COMMON \ .run = netdev_linux_run, \ .wait = netdev_linux_wait, \ @@ -3573,6 +3618,8 @@ const struct netdev_class netdev_tap_class = { .get_stats = netdev_tap_get_stats, .get_features = netdev_linux_get_features, .get_status = netdev_linux_get_status, + .set_config = netdev_tap_set_config, + .get_config = netdev_tap_get_config, .send = netdev_linux_send, .rxq_construct = netdev_linux_rxq_construct, .rxq_destruct = netdev_linux_rxq_destruct, From patchwork Thu Sep 10 03:09:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: yang_y_yi X-Patchwork-Id: 1361171 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=163.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.a=rsa-sha256 header.s=s110527 header.b=gguGZKCv; dkim-atps=neutral Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Bn3ln1RDbz9sTd for ; Thu, 10 Sep 2020 13:09:57 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 84CB387642; Thu, 10 Sep 2020 03:09:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OKZpNVjGkJC7; Thu, 10 Sep 2020 03:09:49 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 2177287638; Thu, 10 Sep 2020 03:09:49 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D929EC0893; Thu, 10 Sep 2020 03:09:48 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 62FEAC0051 for ; Thu, 10 Sep 2020 03:09:47 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 52F5D86DE0 for ; Thu, 10 Sep 2020 03:09:47 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id wWxV5zT2cMgx for ; Thu, 10 Sep 2020 03:09:46 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-m971.mail.163.com (mail-m971.mail.163.com [123.126.97.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 6949986E00 for ; Thu, 10 Sep 2020 03:09:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-Id:MIME-Version; bh=ACrf2 yZUsYn1gDl+51B9mqyNXOYehuLKSuBD+m+VE9Y=; b=gguGZKCv+PsruQCneBT3s 1jvaBzgD3W1+7eiM8OdSHhhBInVN3+cOvRkwWiZmNgwzvWCcDDZkgQ1zMqXb7KO8 ohOko8mJ5kzUL5C17VegI0BKP3Uavxbg2Ew3leifH7V/of5e397XFIIN2F/HECLL cG+uDzgrl+drNKecyv5qyQ= Received: from yangyi0100.home.langchao.com (unknown [111.207.123.58]) by smtp1 (Coremail) with SMTP id GdxpCgDnTzDvmFlfaPxiBQ--.766S4; Thu, 10 Sep 2020 11:09:36 +0800 (CST) From: yang_y_yi@163.com To: ovs-dev@openvswitch.org Date: Thu, 10 Sep 2020 11:09:33 +0800 Message-Id: <20200910030934.116248-3-yang_y_yi@163.com> X-Mailer: git-send-email 2.19.2.windows.1 In-Reply-To: <20200910030934.116248-1-yang_y_yi@163.com> References: <20200910030934.116248-1-yang_y_yi@163.com> MIME-Version: 1.0 X-CM-TRANSID: GdxpCgDnTzDvmFlfaPxiBQ--.766S4 X-Coremail-Antispam: 1Uf129KBjvAXoW3uFWrXw1UWFWrZw4xtFWfGrg_yoW8Jry8Ao WxArnFqF18Gr1Uuryjgwn3JryUZ3y7GF4rAFs8Can0kF1Iqw4Fqr4xCw4YvFW5ZF4FqF47 urWIyayfKF4DWF93n29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxUOKsjDUUUU X-Originating-IP: [111.207.123.58] X-CM-SenderInfo: 51dqwsp1b1xqqrwthudrp/1tbiEBGbi18YDCwJuQAAsG Cc: i.maximets@ovn.org, yang_y_yi@163.com, fbl@sysclose.org Subject: [ovs-dev] [PATCH v2 2/3] Fix tap interface statistics issue X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Yi Yang After tap interface is moved to network namespace, "ovs-vsctl list interface tapXXX" can get statistics info of tap interface, the root cause is OVS still gets statistics info in root namespace. With netns option help, OVS can get statistics info in tap interface netns. This patch added enter and exit netns helpers and change statistics-related functions for those tap interfaces which have been moved into netns and make sure "ovs-vsctl list interface tapXXX" can get statistics info correctly. Here is a result sample for reference: name : tap1 ofport : 4 ofport_request : [] options : {netns=ns01} other_config : {} statistics : {rx_bytes=6228, rx_packets=68, tx_bytes=8310, tx_packets=95} status : {} type : tap Signed-off-by: Yi Yang --- lib/dpif-netlink.c | 51 ++++++++++++++++++ lib/dpif-netlink.h | 3 ++ lib/netdev-linux.c | 63 +++++++++++++++++++++- lib/netlink-socket.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/netlink-socket.h | 2 + 5 files changed, 263 insertions(+), 2 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 7da4fb5..8ed37ed 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -4282,6 +4282,43 @@ dpif_netlink_vport_transact(const struct dpif_netlink_vport *request, return error; } +static int +dpif_netlink_vport_transact_nopool(const struct dpif_netlink_vport *request, + struct dpif_netlink_vport *reply, + struct ofpbuf **bufp) +{ + struct ofpbuf *request_buf; + int error; + + ovs_assert((reply != NULL) == (bufp != NULL)); + + error = dpif_netlink_init(); + if (error) { + if (reply) { + *bufp = NULL; + dpif_netlink_vport_init(reply); + } + return error; + } + + request_buf = ofpbuf_new(1024); + dpif_netlink_vport_to_ofpbuf(request, request_buf); + error = nl_transact_nopool(NETLINK_GENERIC, request_buf, bufp); + ofpbuf_delete(request_buf); + + if (reply) { + if (!error) { + error = dpif_netlink_vport_from_ofpbuf(reply, *bufp); + } + if (error) { + dpif_netlink_vport_init(reply); + ofpbuf_delete(*bufp); + *bufp = NULL; + } + } + return error; +} + /* Obtains information about the kernel vport named 'name' and stores it into * '*reply' and '*bufp'. The caller must free '*bufp' when the reply is no * longer needed ('reply' will contain pointers into '*bufp'). */ @@ -4298,6 +4335,20 @@ dpif_netlink_vport_get(const char *name, struct dpif_netlink_vport *reply, return dpif_netlink_vport_transact(&request, reply, bufp); } +int +dpif_netlink_vport_get_nopool(const char *name, + struct dpif_netlink_vport *reply, + struct ofpbuf **bufp) +{ + struct dpif_netlink_vport request; + + dpif_netlink_vport_init(&request); + request.cmd = OVS_VPORT_CMD_GET; + request.name = name; + + return dpif_netlink_vport_transact_nopool(&request, reply, bufp); +} + /* Parses the contents of 'buf', which contains a "struct ovs_header" followed * by Netlink attributes, into 'dp'. Returns 0 if successful, otherwise a * positive errno value. diff --git a/lib/dpif-netlink.h b/lib/dpif-netlink.h index 24294bc..9372241 100644 --- a/lib/dpif-netlink.h +++ b/lib/dpif-netlink.h @@ -55,6 +55,9 @@ int dpif_netlink_vport_transact(const struct dpif_netlink_vport *request, struct ofpbuf **bufp); int dpif_netlink_vport_get(const char *name, struct dpif_netlink_vport *reply, struct ofpbuf **bufp); +int dpif_netlink_vport_get_nopool(const char *name, + struct dpif_netlink_vport *reply, + struct ofpbuf **bufp); bool dpif_netlink_is_internal_device(const char *name); diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index ebe4ddb..346dc94 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -520,8 +520,16 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); * changes in the device miimon status, so we can use atomic_count. */ static atomic_count miimon_cnt = ATOMIC_COUNT_INIT(0); +struct netns_knob { + int main_fd; + int netns_fd; + char nspath[128]; +}; + static int netdev_linux_parse_vnet_hdr(struct dp_packet *b); static void netdev_linux_prepend_vnet_hdr(struct dp_packet *b, int mtu); +static int enter_netns(struct netns_knob *netns_knob, const char *netns); +static void exit_netns(struct netns_knob *netns_knob); static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *, int cmd, const char *cmd_name); static int get_flags(const struct netdev *, unsigned int *flags); @@ -2158,11 +2166,18 @@ netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst, static int get_stats_via_vport__(const struct netdev *netdev, struct netdev_stats *stats) { + struct netdev_linux *netdev_linux = netdev_linux_cast(netdev); struct dpif_netlink_vport reply; struct ofpbuf *buf; int error; - error = dpif_netlink_vport_get(netdev_get_name(netdev), &reply, &buf); + if (is_tap_netdev(netdev) && (netdev_linux->netns != NULL)) { + error = dpif_netlink_vport_get_nopool(netdev_get_name(netdev), + &reply, &buf); + } else { + error = dpif_netlink_vport_get(netdev_get_name(netdev), + &reply, &buf); + } if (error) { return error; } else if (!reply.stats) { @@ -2237,6 +2252,33 @@ netdev_linux_get_stats(const struct netdev *netdev_, return error; } +static int +enter_netns(struct netns_knob *netns_knob, const char *netns) +{ + sprintf(netns_knob->nspath, "/proc/%d/ns/net", getpid()); + netns_knob->main_fd = open(netns_knob->nspath, O_RDONLY); + if (netns_knob->main_fd < 0) { + return errno; + } + + sprintf(netns_knob->nspath, "/var/run/netns/%s", netns); + netns_knob->netns_fd = open(netns_knob->nspath, O_RDONLY); + if (netns_knob->netns_fd < 0) { + close(netns_knob->main_fd); + return errno; + } + setns(netns_knob->netns_fd, CLONE_NEWNET); + return 0; +} + +static void +exit_netns(struct netns_knob *netns_knob) +{ + setns(netns_knob->main_fd, CLONE_NEWNET); + close(netns_knob->netns_fd); + close(netns_knob->main_fd); +} + /* Retrieves current device stats for 'netdev-tap' netdev or * netdev-internal. */ static int @@ -2245,6 +2287,14 @@ netdev_tap_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) struct netdev_linux *netdev = netdev_linux_cast(netdev_); struct netdev_stats dev_stats; int error; + struct netns_knob netns_knob; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } ovs_mutex_lock(&netdev->mutex); get_stats_via_vport(netdev_, stats); @@ -2298,6 +2348,10 @@ netdev_tap_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) stats->rx_dropped += netdev->rx_dropped; ovs_mutex_unlock(&netdev->mutex); + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + exit_netns(&netns_knob); + } + return error; } @@ -6245,6 +6299,7 @@ netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst, int get_stats_via_netlink(const struct netdev *netdev_, struct netdev_stats *stats) { + struct netdev_linux *netdev = netdev_linux_cast(netdev_); struct ofpbuf request; struct ofpbuf *reply; int error; @@ -6258,7 +6313,11 @@ get_stats_via_netlink(const struct netdev *netdev_, struct netdev_stats *stats) RTM_GETLINK, NLM_F_REQUEST); ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg)); nl_msg_put_string(&request, IFLA_IFNAME, netdev_get_name(netdev_)); - error = nl_transact(NETLINK_ROUTE, &request, &reply); + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + error = nl_transact_nopool(NETLINK_ROUTE, &request, &reply); + } else { + error = nl_transact(NETLINK_ROUTE, &request, &reply); + } ofpbuf_uninit(&request); if (error) { return error; diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c index 47077e9..2377ca7 100644 --- a/lib/netlink-socket.c +++ b/lib/netlink-socket.c @@ -1807,6 +1807,152 @@ nl_transact(int protocol, const struct ofpbuf *request, return error; } +static int +nl_sock_create_nopool(int protocol, struct nl_sock **sockp) +{ + struct nl_sock *sock; +#ifndef _WIN32 + struct sockaddr_nl local, remote; +#endif + socklen_t local_size; + int rcvbuf; + int retval = 0; + + *sockp = NULL; + sock = xmalloc(sizeof *sock); + +#ifdef _WIN32 + sock->overlapped.hEvent = NULL; + sock->handle = CreateFile(OVS_DEVICE_NAME_USER, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + + if (sock->handle == INVALID_HANDLE_VALUE) { + VLOG_ERR("fcntl: %s", ovs_lasterror_to_string()); + goto error; + } + + memset(&sock->overlapped, 0, sizeof sock->overlapped); + sock->overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (sock->overlapped.hEvent == NULL) { + VLOG_ERR("fcntl: %s", ovs_lasterror_to_string()); + goto error; + } + /* Initialize the type/ioctl to Generic */ + sock->read_ioctl = OVS_IOCTL_READ; +#else + sock->fd = socket(AF_NETLINK, SOCK_RAW, protocol); + if (sock->fd < 0) { + VLOG_ERR("fcntl: %s", ovs_strerror(errno)); + goto error; + } +#endif + + sock->protocol = protocol; + sock->next_seq = 1; + + rcvbuf = 1024 * 1024; +#ifdef _WIN32 + sock->rcvbuf = rcvbuf; + retval = get_sock_pid_from_kernel(sock); + if (retval != 0) { + goto error; + } + retval = set_sock_property(sock); + if (retval != 0) { + goto error; + } +#else + if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE, + &rcvbuf, sizeof rcvbuf)) { + /* Only root can use SO_RCVBUFFORCE. Everyone else gets EPERM. + * Warn only if the failure is therefore unexpected. */ + if (errno != EPERM) { + VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed " + "(%s)", rcvbuf, ovs_strerror(errno)); + } + } + + retval = get_socket_rcvbuf(sock->fd); + if (retval < 0) { + retval = -retval; + goto error; + } + sock->rcvbuf = retval; + retval = 0; + + /* Connect to kernel (pid 0) as remote address. */ + memset(&remote, 0, sizeof remote); + remote.nl_family = AF_NETLINK; + remote.nl_pid = 0; + if (connect(sock->fd, (struct sockaddr *) &remote, sizeof remote) < 0) { + VLOG_ERR("connect(0): %s", ovs_strerror(errno)); + goto error; + } + + /* Obtain pid assigned by kernel. */ + local_size = sizeof local; + if (getsockname(sock->fd, (struct sockaddr *) &local, &local_size) < 0) { + VLOG_ERR("getsockname: %s", ovs_strerror(errno)); + goto error; + } + if (local_size < sizeof local || local.nl_family != AF_NETLINK) { + VLOG_ERR("getsockname returned bad Netlink name"); + retval = EINVAL; + goto error; + } + sock->pid = local.nl_pid; +#endif + + *sockp = sock; + return 0; + +error: + if (retval == 0) { + retval = errno; + if (retval == 0) { + retval = EINVAL; + } + } +#ifdef _WIN32 + if (sock->overlapped.hEvent) { + CloseHandle(sock->overlapped.hEvent); + } + if (sock->handle != INVALID_HANDLE_VALUE) { + CloseHandle(sock->handle); + } +#else + if (sock->fd >= 0) { + close(sock->fd); + } +#endif + free(sock); + return retval; +} + +int +nl_transact_nopool(int protocol, const struct ofpbuf *request, + struct ofpbuf **replyp) +{ + struct nl_sock *sock; + int error; + + error = nl_sock_create_nopool(protocol, &sock); + if (error) { + if (replyp) { + *replyp = NULL; + } + return error; + } + + error = nl_sock_transact(sock, request, replyp); + nl_sock_destroy(sock); + + return error; +} + /* Sends the 'request' member of the 'n' transactions in 'transactions' on a * Netlink socket for the given 'protocol' (e.g. NETLINK_ROUTE or * NETLINK_GENERIC), in order, and receives responses to all of them. Fills in diff --git a/lib/netlink-socket.h b/lib/netlink-socket.h index 7852ad0..08cbab8 100644 --- a/lib/netlink-socket.h +++ b/lib/netlink-socket.h @@ -254,6 +254,8 @@ struct nl_transaction { int nl_transact(int protocol, const struct ofpbuf *request, struct ofpbuf **replyp); void nl_transact_multiple(int protocol, struct nl_transaction **, size_t n); +int nl_transact_nopool(int protocol, const struct ofpbuf *request, + struct ofpbuf **replyp); /* Table dumping. */ #define NL_DUMP_BUFSIZE 4096 From patchwork Thu Sep 10 03:09:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: yang_y_yi X-Patchwork-Id: 1361174 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=163.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.a=rsa-sha256 header.s=s110527 header.b=RxjYGGpq; dkim-atps=neutral Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Bn3xn0vhDz9sTX for ; Thu, 10 Sep 2020 13:18:36 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 1A8B42E1BA; Thu, 10 Sep 2020 03:18:35 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id txiK9-aVH0OO; Thu, 10 Sep 2020 03:18:14 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 0FA3D2E1EA; Thu, 10 Sep 2020 03:10:16 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 04209C0052; Thu, 10 Sep 2020 03:10:16 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 531D8C0052 for ; Thu, 10 Sep 2020 03:10:14 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id F3FA52E1E6 for ; Thu, 10 Sep 2020 03:10:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id PG4TCSV+VF0G for ; Thu, 10 Sep 2020 03:09:47 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-m971.mail.163.com (mail-m971.mail.163.com [123.126.97.1]) by silver.osuosl.org (Postfix) with ESMTP id D0D03203EF for ; Thu, 10 Sep 2020 03:09:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-Id:MIME-Version; bh=wwIk5 gog0lboJWp04IAdAucWR6Jrbl0SV7gORmliYRE=; b=RxjYGGpqgQUf87bNJSGuz XiOIKxMzIBltwg4a6sSgP+A175HGMXlLrqV2q1Uswr29BfPWtkH/A+KtcEUebeO1 ztheFjetAPzt3VzBrY2TEWTUcNRL+rXeBO3Jj8KxGIN+jGV9K3nL9ATAUt7S4Dwh mIIzqgtRSYg7StajIXviSM= Received: from yangyi0100.home.langchao.com (unknown [111.207.123.58]) by smtp1 (Coremail) with SMTP id GdxpCgDnTzDvmFlfaPxiBQ--.766S5; Thu, 10 Sep 2020 11:09:37 +0800 (CST) From: yang_y_yi@163.com To: ovs-dev@openvswitch.org Date: Thu, 10 Sep 2020 11:09:34 +0800 Message-Id: <20200910030934.116248-4-yang_y_yi@163.com> X-Mailer: git-send-email 2.19.2.windows.1 In-Reply-To: <20200910030934.116248-1-yang_y_yi@163.com> References: <20200910030934.116248-1-yang_y_yi@163.com> MIME-Version: 1.0 X-CM-TRANSID: GdxpCgDnTzDvmFlfaPxiBQ--.766S5 X-Coremail-Antispam: 1Uf129KBjvAXoWfWr1rJF47WFyruw1fAFWkJFb_yoW5Gw45to Z3JF13tr18Gr1UuryUGr15JF4UXw1DGFs5AFs8Xr4q9FyIq345Gr4xGw45Ar43XF4rXFnr Wa97Jay3GFs8WFyfn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxU2QJ5UUUUU X-Originating-IP: [111.207.123.58] X-CM-SenderInfo: 51dqwsp1b1xqqrwthudrp/1tbiqBGbi1c7RvRbbQAAsB Cc: i.maximets@ovn.org, yang_y_yi@163.com, fbl@sysclose.org Subject: [ovs-dev] [PATCH v2 3/3] Fix tap interface status update issue in network namespace X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Yi Yang Currently OVS can't get link state, mtu, mac, driver, etc. when tap interface is in network namespace, with netns option and netns helper functions, these info can be gotten. This patch fixed all these issues and make sure tap interface in network namespace can get same info as it is in root network namespace. Here is a result sample for reference: $ sudo ./ovs-vsctl list interface tap1 _uuid : 283b0daf-1baf-4d46-8a0e-3774eb39d0e3 admin_state : up bfd : {} bfd_status : {} cfm_fault : [] cfm_fault_status : [] cfm_flap_count : [] cfm_health : [] cfm_mpid : [] cfm_remote_mpids : [] cfm_remote_opstate : [] duplex : full error : [] external_ids : {} ifindex : 1276 ingress_policing_burst: 0 ingress_policing_rate: 0 lacp_current : [] link_resets : 1 link_speed : 10000000 link_state : up lldp : {} mac : [] mac_in_use : "f6:8d:3f:0a:3a:dd" mtu : 1450 mtu_request : 1450 name : tap1 ofport : 4 ofport_request : [] options : {netns=ns01} other_config : {} statistics : {rx_bytes=726, rx_packets=9, tx_bytes=2178,...} status : {driver_name=tun, driver_version="1.6",...} type : tap $ Signed-off-by: Yi Yang --- lib/netdev-linux.c | 371 ++++++++++++++++++++++++++++++++++++++++++------- lib/socket-util-unix.c | 37 +++++ lib/socket-util.h | 3 + 3 files changed, 364 insertions(+), 47 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 346dc94..289ebab 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -532,17 +532,19 @@ static int enter_netns(struct netns_knob *netns_knob, const char *netns); static void exit_netns(struct netns_knob *netns_knob); static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *, int cmd, const char *cmd_name); -static int get_flags(const struct netdev *, unsigned int *flags); -static int set_flags(const char *, unsigned int flags); +static int get_flags(const struct netdev *, unsigned int *flags, + bool is_tap_in_netns); +static int set_flags(const char *, unsigned int flags, bool is_tap_in_netns); static int update_flags(struct netdev_linux *netdev, enum netdev_flags off, - enum netdev_flags on, enum netdev_flags *old_flagsp) + enum netdev_flags on, enum netdev_flags *old_flagsp, + bool is_tap_in_netns) OVS_REQUIRES(netdev->mutex); static int get_ifindex(const struct netdev *, int *ifindexp); static int do_set_addr(struct netdev *netdev, int ioctl_nr, const char *ioctl_name, - struct in_addr addr); -static int get_etheraddr(const char *netdev_name, struct eth_addr *ea); -static int set_etheraddr(const char *netdev_name, const struct eth_addr); + struct in_addr addr, bool is_tap_in_netns); +static int get_etheraddr(const struct netdev *netdev_, struct eth_addr *ea); +static int set_etheraddr(const struct netdev *netdev_, const struct eth_addr); static int af_packet_sock(void); static bool netdev_linux_miimon_enabled(void); static void netdev_linux_miimon_run(void); @@ -791,13 +793,28 @@ netdev_linux_run(const struct netdev_class *netdev_class OVS_UNUSED) struct netdev *netdev_ = node->data; struct netdev_linux *netdev = netdev_linux_cast(netdev_); unsigned int flags; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + netdev_close(netdev_); + continue; + } + } ovs_mutex_lock(&netdev->mutex); - get_flags(netdev_, &flags); + get_flags(netdev_, &flags, is_tap_in_netns); netdev_linux_changed(netdev, flags, 0); ovs_mutex_unlock(&netdev->mutex); netdev_close(netdev_); + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } } shash_destroy(&device_shash); } else if (error != EAGAIN) { @@ -952,7 +969,7 @@ netdev_linux_construct(struct netdev *netdev_) return error; } - error = get_flags(&netdev->up, &netdev->ifi_flags); + error = get_flags(&netdev->up, &netdev->ifi_flags, false); if (error == ENODEV) { if (netdev->up.netdev_class != &netdev_internal_class) { /* The device does not exist, so don't allow it to be opened. */ @@ -996,7 +1013,7 @@ netdev_linux_construct_tap(struct netdev *netdev_) } /* Create tap device. */ - get_flags(&netdev->up, &netdev->ifi_flags); + get_flags(&netdev->up, &netdev->ifi_flags, false); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; if (userspace_tso_enabled()) { ifr.ifr_flags |= IFF_VNET_HDR; @@ -1528,10 +1545,33 @@ static int netdev_linux_rxq_drain(struct netdev_rxq *rxq_) { struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_); + struct netdev *netdev_ = netdev_rxq_get_netdev(&rx->up); + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + int error; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } + if (rx->is_tap) { struct ifreq ifr; - int error = af_inet_ifreq_ioctl(netdev_rxq_get_name(rxq_), &ifr, + if (is_tap_in_netns) { + error = af_inet_ifreq_ioctl_netns(netdev_rxq_get_name(rxq_), + &ifr, + SIOCGIFTXQLEN, "SIOCGIFTXQLEN"); + } else { + error = af_inet_ifreq_ioctl(netdev_rxq_get_name(rxq_), &ifr, SIOCGIFTXQLEN, "SIOCGIFTXQLEN"); + } + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } if (error) { return error; } @@ -1790,6 +1830,16 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac) struct netdev_linux *netdev = netdev_linux_cast(netdev_); enum netdev_flags old_flags = 0; int error; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } ovs_mutex_lock(&netdev->mutex); if (netdev_linux_netnsid_is_remote(netdev)) { @@ -1807,9 +1857,9 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac) /* Tap devices must be brought down before setting the address. */ if (is_tap_netdev(netdev_)) { - update_flags(netdev, NETDEV_UP, 0, &old_flags); + update_flags(netdev, NETDEV_UP, 0, &old_flags, is_tap_in_netns); } - error = set_etheraddr(netdev_get_name(netdev_), mac); + error = set_etheraddr(netdev_, mac); if (!error || error == ENODEV) { netdev->ether_addr_error = error; netdev->cache_valid |= VALID_ETHERADDR; @@ -1819,11 +1869,16 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, const struct eth_addr mac) } if (is_tap_netdev(netdev_) && old_flags & NETDEV_UP) { - update_flags(netdev, 0, NETDEV_UP, &old_flags); + update_flags(netdev, 0, NETDEV_UP, &old_flags, is_tap_in_netns); } exit: ovs_mutex_unlock(&netdev->mutex); + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return error; } @@ -1833,6 +1888,16 @@ netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } ovs_mutex_lock(&netdev->mutex); if (!(netdev->cache_valid & VALID_ETHERADDR)) { @@ -1841,17 +1906,23 @@ netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac) if (!(netdev->cache_valid & VALID_ETHERADDR)) { /* Fall back to ioctl if netlink fails */ - netdev->ether_addr_error = get_etheraddr(netdev_get_name(netdev_), - &netdev->etheraddr); - netdev->cache_valid |= VALID_ETHERADDR; + netdev->ether_addr_error = get_etheraddr(netdev_, &netdev->etheraddr); + if (!netdev->ether_addr_error) { + netdev->cache_valid |= VALID_ETHERADDR; + } } error = netdev->ether_addr_error; + if (!error) { *mac = netdev->etheraddr; } ovs_mutex_unlock(&netdev->mutex); + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return error; } @@ -1859,6 +1930,11 @@ static int netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup) { int error; + bool is_tap_in_netns = false; + + if (is_tap_netdev(&netdev->up) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + } if (!(netdev->cache_valid & VALID_MTU)) { netdev_linux_update_via_netlink(netdev); @@ -1868,8 +1944,13 @@ netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup) /* Fall back to ioctl if netlink fails */ struct ifreq ifr; - netdev->netdev_mtu_error = af_inet_ifreq_ioctl( - netdev_get_name(&netdev->up), &ifr, SIOCGIFMTU, "SIOCGIFMTU"); + if (is_tap_in_netns) { + netdev->netdev_mtu_error = af_inet_ifreq_ioctl_netns( + netdev_get_name(&netdev->up), &ifr, SIOCGIFMTU, "SIOCGIFMTU"); + } else { + netdev->netdev_mtu_error = af_inet_ifreq_ioctl( + netdev_get_name(&netdev->up), &ifr, SIOCGIFMTU, "SIOCGIFMTU"); + } netdev->mtu = ifr.ifr_mtu; netdev->cache_valid |= VALID_MTU; } @@ -1890,11 +1971,25 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } ovs_mutex_lock(&netdev->mutex); error = netdev_linux_get_mtu__(netdev, mtup); ovs_mutex_unlock(&netdev->mutex); + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return error; } @@ -1907,6 +2002,16 @@ netdev_linux_set_mtu(struct netdev *netdev_, int mtu) struct netdev_linux *netdev = netdev_linux_cast(netdev_); struct ifreq ifr; int error; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } ovs_mutex_lock(&netdev->mutex); if (netdev_linux_netnsid_is_remote(netdev)) { @@ -1931,8 +2036,13 @@ netdev_linux_set_mtu(struct netdev *netdev_, int mtu) netdev->cache_valid &= ~VALID_MTU; } ifr.ifr_mtu = mtu; - error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr, - SIOCSIFMTU, "SIOCSIFMTU"); + if (is_tap_in_netns) { + error = af_inet_ifreq_ioctl_netns(netdev_get_name(netdev_), &ifr, + SIOCSIFMTU, "SIOCSIFMTU"); + } else { + error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr, + SIOCSIFMTU, "SIOCSIFMTU"); + } if (!error || error == ENODEV) { netdev->netdev_mtu_error = error; netdev->mtu = ifr.ifr_mtu; @@ -1940,6 +2050,11 @@ netdev_linux_set_mtu(struct netdev *netdev_, int mtu) } exit: ovs_mutex_unlock(&netdev->mutex); + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return error; } @@ -1994,39 +2109,62 @@ netdev_linux_get_carrier_resets(const struct netdev *netdev_) static int netdev_linux_do_miimon(const char *name, int cmd, const char *cmd_name, - struct mii_ioctl_data *data) + struct mii_ioctl_data *data, bool is_tap_in_netns) { struct ifreq ifr; int error; memset(&ifr, 0, sizeof ifr); memcpy(&ifr.ifr_data, data, sizeof *data); - error = af_inet_ifreq_ioctl(name, &ifr, cmd, cmd_name); + if (is_tap_in_netns) { + error = af_inet_ifreq_ioctl_netns(name, &ifr, cmd, cmd_name); + } else { + error = af_inet_ifreq_ioctl(name, &ifr, cmd, cmd_name); + } memcpy(data, &ifr.ifr_data, sizeof *data); return error; } static int -netdev_linux_get_miimon(const char *name, bool *miimon) +netdev_linux_get_miimon(const struct netdev *netdev_, bool *miimon) { struct mii_ioctl_data data; int error; + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + const char *name = netdev_get_name(netdev_); + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + *miimon = false; + return error; + } + } *miimon = false; memset(&data, 0, sizeof data); - error = netdev_linux_do_miimon(name, SIOCGMIIPHY, "SIOCGMIIPHY", &data); + error = netdev_linux_do_miimon(name, SIOCGMIIPHY, "SIOCGMIIPHY", &data, + is_tap_in_netns); if (!error) { /* data.phy_id is filled out by previous SIOCGMIIPHY miimon call. */ data.reg_num = MII_BMSR; error = netdev_linux_do_miimon(name, SIOCGMIIREG, "SIOCGMIIREG", - &data); + &data, is_tap_in_netns); if (!error) { *miimon = !!(data.val_out & BMSR_LSTATUS); } } + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + if (error) { struct ethtool_cmd ecmd; @@ -2088,7 +2226,7 @@ netdev_linux_miimon_run(void) ovs_mutex_lock(&dev->mutex); if (dev->miimon_interval > 0 && timer_expired(&dev->miimon_timer)) { - netdev_linux_get_miimon(dev->up.name, &miimon); + netdev_linux_get_miimon(netdev, &miimon); if (miimon != dev->miimon) { dev->miimon = miimon; netdev_linux_changed(dev, dev->ifi_flags, 0); @@ -2518,7 +2656,9 @@ netdev_linux_read_features(struct netdev_linux *netdev) } out: - netdev->cache_valid |= VALID_FEATURES; + if (!error) { + netdev->cache_valid |= VALID_FEATURES; + } netdev->get_features_error = error; } @@ -3246,6 +3386,16 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address, { struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } ovs_mutex_lock(&netdev->mutex); if (netdev_linux_netnsid_is_remote(netdev)) { @@ -3253,16 +3403,22 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address, goto exit; } - error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address); + error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address, + is_tap_in_netns); if (!error) { if (address.s_addr != INADDR_ANY) { error = do_set_addr(netdev_, SIOCSIFNETMASK, - "SIOCSIFNETMASK", netmask); + "SIOCSIFNETMASK", netmask, is_tap_in_netns); } } exit: ovs_mutex_unlock(&netdev->mutex); + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return error; } @@ -3304,13 +3460,19 @@ make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr) static int do_set_addr(struct netdev *netdev, - int ioctl_nr, const char *ioctl_name, struct in_addr addr) + int ioctl_nr, const char *ioctl_name, struct in_addr addr, + bool is_tap_in_netns) { struct ifreq ifr; make_in4_sockaddr(&ifr.ifr_addr, addr); - return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr, - ioctl_name); + if (is_tap_in_netns) { + return af_inet_ifreq_ioctl_netns(netdev_get_name(netdev), &ifr, + ioctl_nr, ioctl_name); + } else { + return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr, + ioctl_name); + } } /* Adds 'router' as a default IP gateway. */ @@ -3437,6 +3599,17 @@ netdev_linux_get_block_id(struct netdev *netdev_) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); uint32_t block_id = 0; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + int error; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return block_id; + } + } ovs_mutex_lock(&netdev->mutex); /* Ensure the linux netdev has had its fields populated. */ @@ -3450,6 +3623,10 @@ netdev_linux_get_block_id(struct netdev *netdev_) } ovs_mutex_unlock(&netdev->mutex); + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return block_id; } @@ -3520,7 +3697,8 @@ iff_to_nd_flags(unsigned int iff) static int update_flags(struct netdev_linux *netdev, enum netdev_flags off, - enum netdev_flags on, enum netdev_flags *old_flagsp) + enum netdev_flags on, enum netdev_flags *old_flagsp, + bool is_tap_in_netns) OVS_REQUIRES(netdev->mutex) { unsigned int old_flags, new_flags; @@ -3530,8 +3708,9 @@ update_flags(struct netdev_linux *netdev, enum netdev_flags off, *old_flagsp = iff_to_nd_flags(old_flags); new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on); if (new_flags != old_flags) { - error = set_flags(netdev_get_name(&netdev->up), new_flags); - get_flags(&netdev->up, &netdev->ifi_flags); + error = set_flags(netdev_get_name(&netdev->up), new_flags, + is_tap_in_netns); + get_flags(&netdev->up, &netdev->ifi_flags, is_tap_in_netns); } return error; @@ -3543,6 +3722,16 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off, { struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error = 0; + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + return error; + } + } ovs_mutex_lock(&netdev->mutex); if (on || off) { @@ -3551,18 +3740,23 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off, error = EOPNOTSUPP; goto exit; } - error = update_flags(netdev, off, on, old_flagsp); + error = update_flags(netdev, off, on, old_flagsp, is_tap_in_netns); } else { /* Try reading flags over netlink, or fall back to ioctl. */ if (!netdev_linux_update_via_netlink(netdev)) { *old_flagsp = iff_to_nd_flags(netdev->ifi_flags); } else { - error = update_flags(netdev, off, on, old_flagsp); + error = update_flags(netdev, off, on, old_flagsp, is_tap_in_netns); } } exit: ovs_mutex_unlock(&netdev->mutex); + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return error; } @@ -6349,13 +6543,19 @@ get_stats_via_netlink(const struct netdev *netdev_, struct netdev_stats *stats) } static int -get_flags(const struct netdev *dev, unsigned int *flags) +get_flags(const struct netdev *dev, unsigned int *flags, bool is_tap_in_netns) { struct ifreq ifr; int error; *flags = 0; - error = af_inet_ifreq_ioctl(dev->name, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); + if (is_tap_in_netns) { + error = af_inet_ifreq_ioctl_netns(dev->name, &ifr, SIOCGIFFLAGS, + "SIOCGIFFLAGS"); + } else { + error = af_inet_ifreq_ioctl(dev->name, &ifr, SIOCGIFFLAGS, + "SIOCGIFFLAGS"); + } if (!error) { *flags = ifr.ifr_flags; } @@ -6363,12 +6563,17 @@ get_flags(const struct netdev *dev, unsigned int *flags) } static int -set_flags(const char *name, unsigned int flags) +set_flags(const char *name, unsigned int flags, bool is_tap_in_netns) { struct ifreq ifr; ifr.ifr_flags = flags; - return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); + if (is_tap_in_netns) { + return af_inet_ifreq_ioctl_netns(name, &ifr, SIOCSIFFLAGS, + "SIOCSIFFLAGS"); + } else { + return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); + } } int @@ -6397,6 +6602,19 @@ static int get_ifindex(const struct netdev *netdev_, int *ifindexp) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + int error; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + netdev->get_ifindex_error = -error; + netdev->ifindex = 0; + return netdev->get_ifindex_error; + } + } if (!(netdev->cache_valid & VALID_IFINDEX)) { netdev_linux_update_via_netlink(netdev); @@ -6417,6 +6635,11 @@ get_ifindex(const struct netdev *netdev_, int *ifindexp) } *ifindexp = netdev->ifindex; + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return netdev->get_ifindex_error; } @@ -6428,6 +6651,11 @@ netdev_linux_update_via_netlink(struct netdev_linux *netdev) struct rtnetlink_change chg; struct rtnetlink_change *change = &chg; int error; + bool is_tap_in_netns = false; + + if (is_tap_netdev(&netdev->up) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + } ofpbuf_init(&request, 0); nl_msg_put_nlmsghdr(&request, @@ -6442,7 +6670,11 @@ netdev_linux_update_via_netlink(struct netdev_linux *netdev) if (netdev_linux_netnsid_is_remote(netdev)) { nl_msg_put_u32(&request, IFLA_IF_NETNSID, netdev->netnsid); } - error = nl_transact(NETLINK_ROUTE, &request, &reply); + if (is_tap_in_netns) { + error = nl_transact_nopool(NETLINK_ROUTE, &request, &reply); + } else { + error = nl_transact(NETLINK_ROUTE, &request, &reply); + } ofpbuf_uninit(&request); if (error) { ofpbuf_delete(reply); @@ -6497,16 +6729,27 @@ netdev_linux_update_via_netlink(struct netdev_linux *netdev) } static int -get_etheraddr(const char *netdev_name, struct eth_addr *ea) +get_etheraddr(const struct netdev *netdev_, struct eth_addr *ea) { + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + const char *netdev_name = netdev_get_name(netdev_); struct ifreq ifr; int hwaddr_family; int error; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + } memset(&ifr, 0, sizeof ifr); ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); COVERAGE_INC(netdev_get_hwaddr); - error = af_inet_ioctl(SIOCGIFHWADDR, &ifr); + if (is_tap_in_netns) { + error = af_inet_ioctl_netns(SIOCGIFHWADDR, &ifr); + } else { + error = af_inet_ioctl(SIOCGIFHWADDR, &ifr); + } if (error) { /* ENODEV probably means that a vif disappeared asynchronously and * hasn't been removed from the database yet, so reduce the log level @@ -6528,17 +6771,28 @@ get_etheraddr(const char *netdev_name, struct eth_addr *ea) } static int -set_etheraddr(const char *netdev_name, const struct eth_addr mac) +set_etheraddr(const struct netdev *netdev_, const struct eth_addr mac) { + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + const char *netdev_name = netdev_get_name(netdev_); struct ifreq ifr; int error; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + } memset(&ifr, 0, sizeof ifr); ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; memcpy(ifr.ifr_hwaddr.sa_data, &mac, ETH_ADDR_LEN); COVERAGE_INC(netdev_set_hwaddr); - error = af_inet_ioctl(SIOCSIFHWADDR, &ifr); + if (is_tap_in_netns) { + error = af_inet_ioctl_netns(SIOCSIFHWADDR, &ifr); + } else { + error = af_inet_ioctl(SIOCSIFHWADDR, &ifr); + } if (error) { VLOG_ERR("ioctl(SIOCSIFHWADDR) on %s device failed: %s", netdev_name, ovs_strerror(error)); @@ -6552,13 +6806,31 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd, { struct ifreq ifr; int error; + struct netdev *netdev_ = netdev_from_name(name); + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + struct netns_knob netns_knob; + bool is_tap_in_netns = false; + + if (is_tap_netdev(netdev_) && (netdev->netns != NULL)) { + is_tap_in_netns = true; + error = enter_netns(&netns_knob, netdev->netns); + if (error) { + netdev_close(netdev_); + return error; + } + } + netdev_close(netdev_); memset(&ifr, 0, sizeof ifr); ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); ifr.ifr_data = (caddr_t) ecmd; ecmd->cmd = cmd; - error = af_inet_ioctl(SIOCETHTOOL, &ifr); + if (is_tap_in_netns) { + error = af_inet_ioctl_netns(SIOCETHTOOL, &ifr); + } else { + error = af_inet_ioctl(SIOCETHTOOL, &ifr); + } if (error) { if (error != EOPNOTSUPP) { VLOG_WARN_RL(&rl, "ethtool command %s on network device %s " @@ -6568,6 +6840,11 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd, * common, so there's no point in logging anything. */ } } + + if (is_tap_in_netns) { + exit_netns(&netns_knob); + } + return error; } diff --git a/lib/socket-util-unix.c b/lib/socket-util-unix.c index 59f63fc..4923461 100644 --- a/lib/socket-util-unix.c +++ b/lib/socket-util-unix.c @@ -419,6 +419,27 @@ af_inet_ioctl(unsigned long int command, const void *arg) } int +af_inet_ioctl_netns(unsigned long int command, const void *arg) +{ + int sock; + int error = 0; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + error = -sock_errno(); + VLOG_ERR("failed to create inet socket: %s", sock_strerror(error)); + } + + if (sock >= 0) { + if (ioctl(sock, command, arg) == -1) { + error = errno; + } + close(sock); + } + return error; +} + +int af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd, const char *cmd_name) { @@ -433,3 +454,19 @@ af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd, } return error; } + +int +af_inet_ifreq_ioctl_netns(const char *name, struct ifreq *ifr, + unsigned long int cmd, const char *cmd_name) +{ + int error; + + ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name); + error = af_inet_ioctl_netns(cmd, ifr); + if (error) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name, + ovs_strerror(error)); + } + return error; +} diff --git a/lib/socket-util.h b/lib/socket-util.h index 9ccb7d4..d92e4c4 100644 --- a/lib/socket-util.h +++ b/lib/socket-util.h @@ -140,6 +140,9 @@ struct ifreq; int af_inet_ioctl(unsigned long int command, const void *arg); int af_inet_ifreq_ioctl(const char *name, struct ifreq *, unsigned long int cmd, const char *cmd_name); +int af_inet_ioctl_netns(unsigned long int command, const void *arg); +int af_inet_ifreq_ioctl_netns(const char *name, struct ifreq *, + unsigned long int cmd, const char *cmd_name); #define closesocket close #endif