From patchwork Thu Dec 7 02:22:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flavio Leitner X-Patchwork-Id: 845411 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3ysfSh63sxz9s84 for ; Thu, 7 Dec 2017 13:24:36 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 0E8EDD66; Thu, 7 Dec 2017 02:23:06 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 04A54CB7 for ; Thu, 7 Dec 2017 02:23:05 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-qt0-f196.google.com (mail-qt0-f196.google.com [209.85.216.196]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 76831418 for ; Thu, 7 Dec 2017 02:23:04 +0000 (UTC) Received: by mail-qt0-f196.google.com with SMTP id k19so14079024qtj.6 for ; Wed, 06 Dec 2017 18:23:04 -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:in-reply-to :references; bh=4gW0EuCuRVe+hqnnyedShKYgdW5BQBfs3i6+BcIG9JM=; b=qrkEBUUnfZ8sizZlT5MxLRLtd4mgyVHiXGZC8ctkB+Wz+6gmTHBZkQYY/zV0fX0Tzo Z6GtnvioArePJDmHVy8l0MpgMY9pFx/gl205BQtHBSZ6XboeoNQPbtbdmSiovzNrcBXP QmD+LTrjt22htmPDF3dg9ccQf/HuX0cc9L5hogOlKj9t5uhwT6L/KQVnYNkzkcW4lX6w bcFSkkPWkG7pLnq3wDO/DbbL6KrsY6GsxqLVGjEiIosSKzAwlgFQouO48EgZQ6WdNZiL i55mNl836+flbkWsKcDN/aeq7YAuPNJ/TQCc+4BGwaNTCi1cdkzNDtA++Ts7egzdJsWs Rcsw== X-Gm-Message-State: AKGB3mLgVxLL0x4sYKSgYdGYvLTrIRWgeK6oZgCQo1fXNcAFKEa4FfpV iyT/Fz3dpioJxZTzFPo43duZPGfVmp4= X-Google-Smtp-Source: AGs4zMaNIQXvXYDpwr+pP+iZBhXEz3ao9qM8XTQGmJY8AK1h3UZkYXGt5dWgORjnkBKfVMpWrSaUpA== X-Received: by 10.55.105.131 with SMTP id e125mr178607qkc.214.1512613383459; Wed, 06 Dec 2017 18:23:03 -0800 (PST) Received: from localhost ([191.248.112.218]) by smtp.gmail.com with ESMTPSA id j128sm2418307qkf.52.2017.12.06.18.23.01 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 06 Dec 2017 18:23:02 -0800 (PST) From: Flavio Leitner To: dev@openvswitch.org Date: Thu, 7 Dec 2017 00:22:21 -0200 Message-Id: <20171207022224.25215-4-fbl@redhat.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20171207022224.25215-1-fbl@redhat.com> References: <20171207022224.25215-1-fbl@redhat.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Flavio Leitner , Jiri Benc Subject: [ovs-dev] [PATCH v3 3/6] netdev-linux: use netlink to update netdev. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org The ioctl interface doesn't support network namespaces, so try updating the netdev using netlink message instead. To provide backwards compatibility, fall back to the previous method if netlink isn't supported or fails. Signed-off-by: Flavio Leitner --- lib/netdev-linux.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index bf8aee5c7..ac02deb62 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -87,6 +87,9 @@ COVERAGE_DEFINE(netdev_get_ethtool); COVERAGE_DEFINE(netdev_set_ethtool); +#ifndef IFLA_IF_NETNSID +#define IFLA_IF_NETNSID 0x45 +#endif /* These were introduced in Linux 2.6.14, so they might be missing if we have * old headers. */ #ifndef ADVERTISED_Pause @@ -608,6 +611,14 @@ netdev_linux_netnsid_is_eq(struct netdev_linux *netdev, int nsid) return netnsid_eq(netdev->netnsid, nsid); } +static bool +netdev_linux_netnsid_is_remote(struct netdev_linux *netdev) +{ + netdev_linux_netnsid_update(netdev); + return netnsid_is_remote(netdev->netnsid); +} + +static int netdev_linux_update_via_netlink(struct netdev_linux *); static void netdev_linux_update(struct netdev_linux *netdev, int, const struct rtnetlink_change *) OVS_REQUIRES(netdev->mutex); @@ -1427,6 +1438,11 @@ netdev_linux_get_etheraddr(const struct netdev *netdev_, struct eth_addr *mac) ovs_mutex_lock(&netdev->mutex); if (!(netdev->cache_valid & VALID_ETHERADDR)) { + netdev_linux_update_via_netlink(netdev); + } + + 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; @@ -1447,6 +1463,11 @@ netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup) int error; if (!(netdev->cache_valid & VALID_MTU)) { + netdev_linux_update_via_netlink(netdev); + } + + if (!(netdev->cache_valid & VALID_MTU)) { + /* Fall back to ioctl if netlink fails */ struct ifreq ifr; netdev->netdev_mtu_error = af_inet_ifreq_ioctl( @@ -2859,12 +2880,21 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off, enum netdev_flags on, enum netdev_flags *old_flagsp) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); - int error; + int error = 0; ovs_mutex_lock(&netdev->mutex); - error = update_flags(netdev, off, on, old_flagsp); + if (on || off) { + /* Changing flags over netlink isn't support yet. */ + error = update_flags(netdev, off, on, old_flagsp); + } 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); + } + } ovs_mutex_unlock(&netdev->mutex); - return error; } @@ -5506,6 +5536,11 @@ get_ifindex(const struct netdev *netdev_, int *ifindexp) struct netdev_linux *netdev = netdev_linux_cast(netdev_); if (!(netdev->cache_valid & VALID_IFINDEX)) { + netdev_linux_update_via_netlink(netdev); + } + + if (!(netdev->cache_valid & VALID_IFINDEX)) { + /* Fall back to ioctl if netlink fails */ int ifindex = linux_get_ifindex(netdev_get_name(netdev_)); if (ifindex < 0) { @@ -5522,6 +5557,79 @@ get_ifindex(const struct netdev *netdev_, int *ifindexp) return netdev->get_ifindex_error; } +static int +netdev_linux_update_via_netlink(struct netdev_linux *netdev) +{ + struct ofpbuf request; + struct ofpbuf *reply; + struct rtnetlink_change chg; + struct rtnetlink_change *change = &chg; + int error; + + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, + sizeof(struct ifinfomsg) + NL_ATTR_SIZE(IFNAMSIZ), + RTM_GETLINK, NLM_F_REQUEST); + ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg)); + + /* The correct identifiers for a Linux device are netnsid and ifindex, + * but ifindex changes as the port is moved to another network namespace + * and the interface name statically stored in ovsdb. */ + nl_msg_put_string(&request, IFLA_IFNAME, netdev_get_name(&netdev->up)); + if (netdev_linux_netnsid_is_remote(netdev)) { + nl_msg_push_u32(&request, IFLA_IF_NETNSID, netdev->netnsid); + } + error = nl_transact(NETLINK_ROUTE, &request, &reply); + ofpbuf_uninit(&request); + if (error) { + ofpbuf_delete(reply); + return error; + } + + if (rtnetlink_parse(reply, change) + && change->nlmsg_type == RTM_NEWLINK) { + bool changed = false; + error = 0; + + /* Update netdev from rtnl msg and increment its seq if needed. */ + if ((change->ifi_flags ^ netdev->ifi_flags) & IFF_RUNNING) { + netdev->carrier_resets++; + changed = true; + } + if (change->ifi_flags != netdev->ifi_flags) { + netdev->ifi_flags = change->ifi_flags; + changed = true; + } + if (change->mtu && change->mtu != netdev->mtu) { + netdev->mtu = change->mtu; + netdev->cache_valid |= VALID_MTU; + netdev->netdev_mtu_error = 0; + changed = true; + } + if (!eth_addr_is_zero(change->mac) + && !eth_addr_equals(change->mac, netdev->etheraddr)) { + netdev->etheraddr = change->mac; + netdev->cache_valid |= VALID_ETHERADDR; + netdev->ether_addr_error = 0; + changed = true; + } + if (change->if_index != netdev->ifindex) { + netdev->ifindex = change->if_index; + netdev->cache_valid |= VALID_IFINDEX; + netdev->get_ifindex_error = 0; + changed = true; + } + if (changed) { + netdev_change_seq_changed(&netdev->up); + } + } else { + error = EINVAL; + } + + ofpbuf_delete(reply); + return error; +} + static int get_etheraddr(const char *netdev_name, struct eth_addr *ea) {