From patchwork Sat May 20 00:31:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1784020 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QNPlV27zgz20PV for ; Sat, 20 May 2023 10:31:18 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id CAAF6611D5; Sat, 20 May 2023 00:31:15 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org CAAF6611D5 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 93IRw4AOUtju; Sat, 20 May 2023 00:31:14 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id C4437612CE; Sat, 20 May 2023 00:31:13 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org C4437612CE Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 94139C0035; Sat, 20 May 2023 00:31:13 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 52E3DC002A for ; Sat, 20 May 2023 00:31:12 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 2DEB760F82 for ; Sat, 20 May 2023 00:31:12 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 2DEB760F82 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id tz-Qv74uz2-4 for ; Sat, 20 May 2023 00:31:11 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 1A08260F6F Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) by smtp3.osuosl.org (Postfix) with ESMTPS id 1A08260F6F for ; Sat, 20 May 2023 00:31:10 +0000 (UTC) Received: (Authenticated sender: i.maximets@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id 5071F20005; Sat, 20 May 2023 00:31:09 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Sat, 20 May 2023 02:31:18 +0200 Message-Id: <20230520003120.1070717-2-i.maximets@ovn.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230520003120.1070717-1-i.maximets@ovn.org> References: <20230520003120.1070717-1-i.maximets@ovn.org> MIME-Version: 1.0 Cc: Ilya Maximets Subject: [ovs-dev] [PATCH 1/3] netdev-vport: Fix unsafe handling of GRE sequence number. 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" GRE sequence number is maintained as part of the tunnel config. This triggers tunnel reconfiguration every time set_tunnel_config() is called, because memset over tunnel config will never be equal to the new config constructed from database options. And sequence number incremented non-atomically without holding a mutex on tunnel push, that may lead to corruption if multiple threads are sending packets to the same tunnel. Fix that by moving sequence number to the netdev_vport structure instead and using an atomic counter. Fixes: 0ffff4975308 ("userspace: add gre sequence number support.") Fixes: 7dc18ae96d33 ("userspace: add erspan tunnel support.") Fixes: 3c6d05a02e0f ("userspace: Add GTP-U support.") Signed-off-by: Ilya Maximets Reviewed-by: Simon Horman --- lib/netdev-native-tnl.c | 14 ++++---------- lib/netdev-vport-private.h | 4 ++++ lib/netdev-vport.c | 2 ++ lib/netdev.h | 1 - 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index 9abdf5107..e31d61dd5 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -452,7 +452,6 @@ netdev_gre_push_header(const struct netdev *netdev, const struct ovs_action_push_tnl *data) { struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; struct gre_base_hdr *greh; int ip_tot_size; @@ -468,8 +467,7 @@ netdev_gre_push_header(const struct netdev *netdev, int seq_ofs = gre_header_len(greh->flags) - 4; ovs_16aligned_be32 *seq_opt = ALIGNED_CAST(ovs_16aligned_be32 *, (char *)greh + seq_ofs); - tnl_cfg = &dev->tnl_cfg; - put_16aligned_be32(seq_opt, htonl(tnl_cfg->seqno++)); + put_16aligned_be32(seq_opt, htonl(atomic_count_inc(&dev->gre_seqno))); } } @@ -605,7 +603,6 @@ netdev_erspan_push_header(const struct netdev *netdev, const struct ovs_action_push_tnl *data) { struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; struct erspan_base_hdr *ersh; struct gre_base_hdr *greh; struct erspan_md2 *md2; @@ -615,9 +612,8 @@ netdev_erspan_push_header(const struct netdev *netdev, data->header_len, &ip_tot_size); /* update GRE seqno */ - tnl_cfg = &dev->tnl_cfg; ovs_16aligned_be32 *seqno = (ovs_16aligned_be32 *) (greh + 1); - put_16aligned_be32(seqno, htonl(tnl_cfg->seqno++)); + put_16aligned_be32(seqno, htonl(atomic_count_inc(&dev->gre_seqno))); /* update v2 timestamp */ if (greh->protocol == htons(ETH_TYPE_ERSPAN2)) { @@ -786,7 +782,6 @@ netdev_gtpu_push_header(const struct netdev *netdev, const struct ovs_action_push_tnl *data) { struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; struct udp_header *udp; struct gtpuhdr *gtpuh; int ip_tot_size; @@ -801,10 +796,9 @@ netdev_gtpu_push_header(const struct netdev *netdev, gtpuh = ALIGNED_CAST(struct gtpuhdr *, udp + 1); - tnl_cfg = &dev->tnl_cfg; - if (tnl_cfg->set_seq) { + if (gtpuh->md.flags & GTPU_S_MASK) { ovs_be16 *seqno = ALIGNED_CAST(ovs_be16 *, gtpuh + 1); - *seqno = htons(tnl_cfg->seqno++); + *seqno = htons(atomic_count_inc(&dev->gre_seqno)); payload_len += sizeof(struct gtpuhdr_opt); } gtpuh->len = htons(payload_len); diff --git a/lib/netdev-vport-private.h b/lib/netdev-vport-private.h index d89a28c66..e3c3bdb43 100644 --- a/lib/netdev-vport-private.h +++ b/lib/netdev-vport-private.h @@ -22,11 +22,15 @@ #include "compiler.h" #include "netdev.h" #include "netdev-provider.h" +#include "ovs-atomic.h" #include "ovs-thread.h" struct netdev_vport { struct netdev up; + /* Sequence number for outgoing GRE packets. */ + atomic_count gre_seqno; + /* Protects all members below. */ struct ovs_mutex mutex; diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 663ee8606..6bbaa2feb 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -37,6 +37,7 @@ #include "netdev-provider.h" #include "netdev-vport-private.h" #include "openvswitch/dynamic-string.h" +#include "ovs-atomic.h" #include "ovs-router.h" #include "packets.h" #include "openvswitch/poll-loop.h" @@ -198,6 +199,7 @@ netdev_vport_construct(struct netdev *netdev_) uint16_t port = 0; ovs_mutex_init(&dev->mutex); + atomic_count_init(&dev->gre_seqno, 0); eth_addr_random(&dev->etheraddr); if (name && dpif_port && (strlen(name) > strlen(dpif_port) + 1) && diff --git a/lib/netdev.h b/lib/netdev.h index ff207f56c..1fab91273 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -130,7 +130,6 @@ struct netdev_tunnel_config { enum netdev_pt_mode pt_mode; bool set_seq; - uint32_t seqno; uint32_t erspan_idx; uint8_t erspan_ver; uint8_t erspan_dir; From patchwork Sat May 20 00:31:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1784021 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QNPlX5YDGz20PV for ; Sat, 20 May 2023 10:31:20 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 830BD6130A; Sat, 20 May 2023 00:31:18 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 830BD6130A X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id m4-zc_fBTs0t; Sat, 20 May 2023 00:31:17 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 6C19460F7F; Sat, 20 May 2023 00:31:16 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 6C19460F7F Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3F4C6C0089; Sat, 20 May 2023 00:31:16 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 7CF60C0035 for ; Sat, 20 May 2023 00:31:15 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 35A4983F53 for ; Sat, 20 May 2023 00:31:15 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 35A4983F53 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UhiSgJSnMkGN for ; Sat, 20 May 2023 00:31:14 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 40AB883EFE Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::227]) by smtp1.osuosl.org (Postfix) with ESMTPS id 40AB883EFE for ; Sat, 20 May 2023 00:31:13 +0000 (UTC) Received: (Authenticated sender: i.maximets@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id 4135F20007; Sat, 20 May 2023 00:31:12 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Sat, 20 May 2023 02:31:19 +0200 Message-Id: <20230520003120.1070717-3-i.maximets@ovn.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230520003120.1070717-1-i.maximets@ovn.org> References: <20230520003120.1070717-1-i.maximets@ovn.org> MIME-Version: 1.0 Cc: Ilya Maximets Subject: [ovs-dev] [PATCH 2/3] smap: Make argument of smap_add_ipv6 constant. 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" The address is not getting modified inside. Signed-off-by: Ilya Maximets Reviewed-by: Simon Horman --- lib/smap.c | 2 +- lib/smap.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/smap.c b/lib/smap.c index c1633e2a1..47fb34502 100644 --- a/lib/smap.c +++ b/lib/smap.c @@ -100,7 +100,7 @@ smap_add_format(struct smap *smap, const char *key, const char *format, ...) /* Adds 'key' paired with a string representation of 'addr'. It is the * caller's responsibility to avoid duplicate keys if desirable. */ void -smap_add_ipv6(struct smap *smap, const char *key, struct in6_addr *addr) +smap_add_ipv6(struct smap *smap, const char *key, const struct in6_addr *addr) { char buf[INET6_ADDRSTRLEN]; ipv6_string_mapped(buf, addr); diff --git a/lib/smap.h b/lib/smap.h index 2fe6c540a..d1d2ae6f2 100644 --- a/lib/smap.h +++ b/lib/smap.h @@ -100,7 +100,7 @@ struct smap_node *smap_add_nocopy(struct smap *, char *, char *); bool smap_add_once(struct smap *, const char *, const char *); void smap_add_format(struct smap *, const char *key, const char *, ...) OVS_PRINTF_FORMAT(3, 4); -void smap_add_ipv6(struct smap *, const char *, struct in6_addr *); +void smap_add_ipv6(struct smap *, const char *, const struct in6_addr *); void smap_replace(struct smap *, const char *, const char *); void smap_replace_nocopy(struct smap *, const char *, char *); From patchwork Sat May 20 00:31:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1784022 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QNPlm6sTHz20PV for ; Sat, 20 May 2023 10:31:32 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 1E85C61333; Sat, 20 May 2023 00:31:31 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 1E85C61333 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aV4ZMkfWS8UM; Sat, 20 May 2023 00:31:29 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 3B9FA612FE; Sat, 20 May 2023 00:31:28 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 3B9FA612FE Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0E4BFC0035; Sat, 20 May 2023 00:31:28 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0FA7DC002A for ; Sat, 20 May 2023 00:31:27 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D199B61306 for ; Sat, 20 May 2023 00:31:21 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org D199B61306 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7ieQ1ZFiWpDe for ; Sat, 20 May 2023 00:31:18 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 633AA612F0 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::227]) by smtp3.osuosl.org (Postfix) with ESMTPS id 633AA612F0 for ; Sat, 20 May 2023 00:31:17 +0000 (UTC) Received: (Authenticated sender: i.maximets@ovn.org) by mail.gandi.net (Postfix) with ESMTPSA id 3749E20005; Sat, 20 May 2023 00:31:15 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Sat, 20 May 2023 02:31:20 +0200 Message-Id: <20230520003120.1070717-4-i.maximets@ovn.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230520003120.1070717-1-i.maximets@ovn.org> References: <20230520003120.1070717-1-i.maximets@ovn.org> MIME-Version: 1.0 Cc: Ilya Maximets Subject: [ovs-dev] [PATCH 3/3] netdev-vport: RCU-fy tunnel config. 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" Tunnel config can be accessed by multiple threads at the same time and it is supposed to be protected by the netdev_vport mutex. However, many functions are getting direct access to it via netdev API without taking the mutex, creating a potential for various race conditions. Fix that by protecting the tunnel config with RCU. The whole structure is replaced on configuration changes. Individual fields are never updated and the structure itself is constant. This way it can be safely used by different threads within RCU grace period. Signed-off-by: Ilya Maximets Reviewed-by: Simon Horman --- lib/netdev-native-tnl.c | 84 +++++------------ lib/netdev-vport-private.h | 3 +- lib/netdev-vport.c | 189 +++++++++++++++++++++---------------- lib/netdev.h | 3 + 4 files changed, 134 insertions(+), 145 deletions(-) diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index e31d61dd5..53dde61f1 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -320,7 +320,7 @@ netdev_tnl_ip_build_header(struct ovs_action_push_tnl *data, } static void * -udp_build_header(struct netdev_tunnel_config *tnl_cfg, +udp_build_header(const struct netdev_tunnel_config *tnl_cfg, struct ovs_action_push_tnl *data, const struct netdev_tnl_build_header_params *params) { @@ -476,16 +476,11 @@ netdev_gre_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, const struct netdev_tnl_build_header_params *params) { - struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; + const struct netdev_tunnel_config *tnl_cfg; struct gre_base_hdr *greh; ovs_16aligned_be32 *options; unsigned int hlen; - /* XXX: RCUfy tnl_cfg. */ - ovs_mutex_lock(&dev->mutex); - tnl_cfg = &dev->tnl_cfg; - greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE); if (params->flow->packet_type == htonl(PT_ETH)) { @@ -493,8 +488,7 @@ netdev_gre_build_header(const struct netdev *netdev, } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) { greh->protocol = pt_ns_type_be(params->flow->packet_type); } else { - ovs_mutex_unlock(&dev->mutex); - return 1; + return EINVAL; } greh->flags = 0; @@ -505,6 +499,8 @@ netdev_gre_build_header(const struct netdev *netdev, options++; } + tnl_cfg = netdev_get_tunnel_config(netdev); + if (tnl_cfg->out_key_present) { greh->flags |= htons(GRE_KEY); put_16aligned_be32(options, be64_to_be32(params->flow->tunnel.tun_id)); @@ -517,8 +513,6 @@ netdev_gre_build_header(const struct netdev *netdev, options++; } - ovs_mutex_unlock(&dev->mutex); - hlen = (uint8_t *) options - (uint8_t *) greh; data->header_len += hlen; @@ -628,8 +622,7 @@ netdev_erspan_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, const struct netdev_tnl_build_header_params *params) { - struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; + const struct netdev_tunnel_config *tnl_cfg; struct gre_base_hdr *greh; struct erspan_base_hdr *ersh; unsigned int hlen; @@ -637,21 +630,19 @@ netdev_erspan_build_header(const struct netdev *netdev, int erspan_ver; uint16_t sid; - /* XXX: RCUfy tnl_cfg. */ - ovs_mutex_lock(&dev->mutex); - tnl_cfg = &dev->tnl_cfg; greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE); ersh = ERSPAN_HDR(greh); tun_id = ntohl(be64_to_be32(params->flow->tunnel.tun_id)); /* ERSPAN only has 10-bit session ID */ if (tun_id & ~ERSPAN_SID_MASK) { - ovs_mutex_unlock(&dev->mutex); - return 1; + return EINVAL; } else { sid = (uint16_t) tun_id; } + tnl_cfg = netdev_get_tunnel_config(netdev); + if (tnl_cfg->erspan_ver_flow) { erspan_ver = params->flow->tunnel.erspan_ver; } else { @@ -698,12 +689,9 @@ netdev_erspan_build_header(const struct netdev *netdev, hlen = ERSPAN_GREHDR_LEN + sizeof *ersh + ERSPAN_V2_MDSIZE; } else { VLOG_WARN_RL(&err_rl, "ERSPAN version error %d", tnl_cfg->erspan_ver); - ovs_mutex_unlock(&dev->mutex); - return 1; + return EINVAL; } - ovs_mutex_unlock(&dev->mutex); - data->header_len += hlen; if (params->is_ipv6) { @@ -809,13 +797,12 @@ netdev_gtpu_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, const struct netdev_tnl_build_header_params *params) { - struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; + const struct netdev_tunnel_config *tnl_cfg; struct gtpuhdr *gtph; unsigned int gtpu_hlen; - ovs_mutex_lock(&dev->mutex); - tnl_cfg = &dev->tnl_cfg; + tnl_cfg = netdev_get_tunnel_config(netdev); + gtph = udp_build_header(tnl_cfg, data, params); /* Set to default if not set in flow. */ @@ -831,7 +818,6 @@ netdev_gtpu_build_header(const struct netdev *netdev, gtph->md.flags |= GTPU_S_MASK; gtpu_hlen += sizeof(struct gtpuhdr_opt); } - ovs_mutex_unlock(&dev->mutex); data->header_len += gtpu_hlen; data->tnl_type = OVS_VPORT_TYPE_GTPU; @@ -844,19 +830,15 @@ netdev_srv6_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, const struct netdev_tnl_build_header_params *params) { - struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; + const struct netdev_tunnel_config *tnl_cfg; const struct in6_addr *segs; struct srv6_base_hdr *srh; struct in6_addr *s; ovs_be16 dl_type; - int err = 0; int nr_segs; int i; - ovs_mutex_lock(&dev->mutex); - tnl_cfg = &dev->tnl_cfg; - + tnl_cfg = netdev_get_tunnel_config(netdev); if (tnl_cfg->srv6_num_segs) { nr_segs = tnl_cfg->srv6_num_segs; segs = tnl_cfg->srv6_segs; @@ -870,8 +852,7 @@ netdev_srv6_build_header(const struct netdev *netdev, } if (!ipv6_addr_equals(&segs[0], ¶ms->flow->tunnel.ipv6_dst)) { - err = EINVAL; - goto out; + return EINVAL; } srh = netdev_tnl_ip_build_header(data, params, IPPROTO_ROUTING); @@ -888,8 +869,7 @@ netdev_srv6_build_header(const struct netdev *netdev, } else if (dl_type == htons(ETH_TYPE_IPV6)) { srh->rt_hdr.nexthdr = IPPROTO_IPV6; } else { - err = EOPNOTSUPP; - goto out; + return EOPNOTSUPP; } s = ALIGNED_CAST(struct in6_addr *, @@ -902,10 +882,8 @@ netdev_srv6_build_header(const struct netdev *netdev, data->header_len += sizeof *srh + 8 * srh->rt_hdr.hdrlen; data->tnl_type = OVS_VPORT_TYPE_SRV6; -out: - ovs_mutex_unlock(&dev->mutex); - return err; + return 0; } void @@ -1044,13 +1022,10 @@ netdev_vxlan_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, const struct netdev_tnl_build_header_params *params) { - struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; + const struct netdev_tunnel_config *tnl_cfg; struct vxlanhdr *vxh; - /* XXX: RCUfy tnl_cfg. */ - ovs_mutex_lock(&dev->mutex); - tnl_cfg = &dev->tnl_cfg; + tnl_cfg = netdev_get_tunnel_config(netdev); vxh = udp_build_header(tnl_cfg, data, params); @@ -1075,10 +1050,10 @@ netdev_vxlan_build_header(const struct netdev *netdev, vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET; break; default: - goto drop; + return EINVAL; } } else { - goto drop; + return EINVAL; } } else { put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); @@ -1086,14 +1061,9 @@ netdev_vxlan_build_header(const struct netdev *netdev, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); } - ovs_mutex_unlock(&dev->mutex); data->header_len += sizeof *vxh; data->tnl_type = OVS_VPORT_TYPE_VXLAN; return 0; - -drop: - ovs_mutex_unlock(&dev->mutex); - return 1; } struct dp_packet * @@ -1157,22 +1127,14 @@ netdev_geneve_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, const struct netdev_tnl_build_header_params *params) { - struct netdev_vport *dev = netdev_vport_cast(netdev); - struct netdev_tunnel_config *tnl_cfg; struct genevehdr *gnh; int opt_len; bool crit_opt; - /* XXX: RCUfy tnl_cfg. */ - ovs_mutex_lock(&dev->mutex); - tnl_cfg = &dev->tnl_cfg; - - gnh = udp_build_header(tnl_cfg, data, params); + gnh = udp_build_header(netdev_get_tunnel_config(netdev), data, params); put_16aligned_be32(&gnh->vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); - ovs_mutex_unlock(&dev->mutex); - opt_len = tun_metadata_to_geneve_header(¶ms->flow->tunnel, gnh->options, &crit_opt); diff --git a/lib/netdev-vport-private.h b/lib/netdev-vport-private.h index e3c3bdb43..586231057 100644 --- a/lib/netdev-vport-private.h +++ b/lib/netdev-vport-private.h @@ -28,6 +28,8 @@ struct netdev_vport { struct netdev up; + OVSRCU_TYPE(const struct netdev_tunnel_config *) tnl_cfg; + /* Sequence number for outgoing GRE packets. */ atomic_count gre_seqno; @@ -38,7 +40,6 @@ struct netdev_vport { struct netdev_stats stats; /* Tunnels. */ - struct netdev_tunnel_config tnl_cfg; char egress_iface[IFNAMSIZ]; bool carrier_status; diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 6bbaa2feb..480117a14 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -69,8 +69,8 @@ static int get_patch_config(const struct netdev *netdev, struct smap *args); static int get_tunnel_config(const struct netdev *, struct smap *args); static bool tunnel_check_status_change__(struct netdev_vport *); static void update_vxlan_global_cfg(struct netdev *, - struct netdev_tunnel_config *, - struct netdev_tunnel_config *); + const struct netdev_tunnel_config *, + const struct netdev_tunnel_config *); struct vport_class { const char *dpif_port; @@ -91,10 +91,16 @@ vport_class_cast(const struct netdev_class *class) return CONTAINER_OF(class, struct vport_class, netdev_class); } +static const struct netdev_tunnel_config * +vport_tunnel_config(struct netdev_vport *netdev) +{ + return ovsrcu_get(const struct netdev_tunnel_config *, &netdev->tnl_cfg); +} + static const struct netdev_tunnel_config * get_netdev_tunnel_config(const struct netdev *netdev) { - return &netdev_vport_cast(netdev)->tnl_cfg; + return vport_tunnel_config(netdev_vport_cast(netdev)); } bool @@ -135,8 +141,6 @@ netdev_vport_get_dpif_port(const struct netdev *netdev, } if (netdev_vport_needs_dst_port(netdev)) { - const struct netdev_vport *vport = netdev_vport_cast(netdev); - /* * Note: IFNAMSIZ is 16 bytes long. Implementations should choose * a dpif port name that is short enough to fit including any @@ -145,7 +149,7 @@ netdev_vport_get_dpif_port(const struct netdev *netdev, BUILD_ASSERT(NETDEV_VPORT_NAME_BUFSIZE >= IFNAMSIZ); ovs_assert(strlen(dpif_port) + 6 < IFNAMSIZ); snprintf(namebuf, bufsize, "%s_%d", dpif_port, - ntohs(vport->tnl_cfg.dst_port)); + ntohs(netdev_get_tunnel_config(netdev)->dst_port)); return namebuf; } else { return dpif_port; @@ -163,12 +167,14 @@ netdev_vport_route_changed(void) vports = netdev_get_vports(&n_vports); for (i = 0; i < n_vports; i++) { + const struct netdev_tunnel_config *tnl_cfg; struct netdev *netdev_ = vports[i]; struct netdev_vport *netdev = netdev_vport_cast(netdev_); ovs_mutex_lock(&netdev->mutex); /* Finds all tunnel vports. */ - if (ipv6_addr_is_set(&netdev->tnl_cfg.ipv6_dst)) { + tnl_cfg = netdev_get_tunnel_config(netdev_); + if (tnl_cfg && ipv6_addr_is_set(&tnl_cfg->ipv6_dst)) { if (tunnel_check_status_change__(netdev)) { netdev_change_seq_changed(netdev_); } @@ -208,26 +214,31 @@ netdev_vport_construct(struct netdev *netdev_) port = atoi(p); } + struct netdev_tunnel_config *tnl_cfg = xzalloc(sizeof *tnl_cfg); + /* If a destination port for tunnel ports is specified in the netdev * name, use it instead of the default one. Otherwise, use the default * destination port */ if (!strcmp(type, "geneve")) { - dev->tnl_cfg.dst_port = port ? htons(port) : htons(GENEVE_DST_PORT); + tnl_cfg->dst_port = port ? htons(port) : htons(GENEVE_DST_PORT); } else if (!strcmp(type, "vxlan")) { - dev->tnl_cfg.dst_port = port ? htons(port) : htons(VXLAN_DST_PORT); - update_vxlan_global_cfg(netdev_, NULL, &dev->tnl_cfg); + tnl_cfg->dst_port = port ? htons(port) : htons(VXLAN_DST_PORT); + update_vxlan_global_cfg(netdev_, NULL, tnl_cfg); } else if (!strcmp(type, "lisp")) { - dev->tnl_cfg.dst_port = port ? htons(port) : htons(LISP_DST_PORT); + tnl_cfg->dst_port = port ? htons(port) : htons(LISP_DST_PORT); } else if (!strcmp(type, "stt")) { - dev->tnl_cfg.dst_port = port ? htons(port) : htons(STT_DST_PORT); + tnl_cfg->dst_port = port ? htons(port) : htons(STT_DST_PORT); } else if (!strcmp(type, "gtpu")) { - dev->tnl_cfg.dst_port = port ? htons(port) : htons(GTPU_DST_PORT); + tnl_cfg->dst_port = port ? htons(port) : htons(GTPU_DST_PORT); } else if (!strcmp(type, "bareudp")) { - dev->tnl_cfg.dst_port = htons(port); + tnl_cfg->dst_port = htons(port); } - dev->tnl_cfg.dont_fragment = true; - dev->tnl_cfg.ttl = DEFAULT_TTL; + tnl_cfg->dont_fragment = true; + tnl_cfg->ttl = DEFAULT_TTL; + + ovsrcu_set(&dev->tnl_cfg, tnl_cfg); + return 0; } @@ -235,12 +246,15 @@ static void netdev_vport_destruct(struct netdev *netdev_) { struct netdev_vport *netdev = netdev_vport_cast(netdev_); + const struct netdev_tunnel_config *tnl_cfg = vport_tunnel_config(netdev); const char *type = netdev_get_type(netdev_); if (!strcmp(type, "vxlan")) { - update_vxlan_global_cfg(netdev_, &netdev->tnl_cfg, NULL); + update_vxlan_global_cfg(netdev_, tnl_cfg, NULL); } + ovsrcu_set(&netdev->tnl_cfg, NULL); + ovsrcu_postpone(free, CONST_CAST(struct netdev_tunnel_config *, tnl_cfg)); free(netdev->peer); ovs_mutex_destroy(&netdev->mutex); } @@ -283,15 +297,16 @@ static bool tunnel_check_status_change__(struct netdev_vport *netdev) OVS_REQUIRES(netdev->mutex) { + const struct netdev_tunnel_config *tnl_cfg = vport_tunnel_config(netdev); + const struct in6_addr *route; char iface[IFNAMSIZ]; bool status = false; - struct in6_addr *route; struct in6_addr gw; uint32_t mark; iface[0] = '\0'; - route = &netdev->tnl_cfg.ipv6_dst; - mark = netdev->tnl_cfg.egress_pkt_mark; + route = &tnl_cfg->ipv6_dst; + mark = tnl_cfg->egress_pkt_mark; if (ovs_router_lookup(mark, route, iface, NULL, &gw)) { struct netdev *egress_netdev; @@ -498,8 +513,8 @@ vxlan_get_port_ext_gbp_str(uint16_t port, bool gbp, static void update_vxlan_global_cfg(struct netdev *netdev, - struct netdev_tunnel_config *old_cfg, - struct netdev_tunnel_config *new_cfg) + const struct netdev_tunnel_config *old_cfg, + const struct netdev_tunnel_config *new_cfg) { unsigned int count; char namebuf[20]; @@ -543,19 +558,20 @@ static bool is_concomitant_vxlan_tunnel_present(struct netdev_vport *dev, const struct netdev_tunnel_config *tnl_cfg) { - char namebuf[20]; - const char *type = netdev_get_type(&dev->up); + const struct netdev_tunnel_config *dev_tnl_cfg = vport_tunnel_config(dev); struct vport_class *vclass = vport_class_cast(netdev_get_class(&dev->up)); + const char *type = netdev_get_type(&dev->up); + char namebuf[20]; if (strcmp(type, "vxlan")) { return false; } - if (dev->tnl_cfg.dst_port == tnl_cfg->dst_port && - (dev->tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GBP)) == + if (dev_tnl_cfg->dst_port == tnl_cfg->dst_port && + (dev_tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GBP)) == (tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GBP))) { - if (ntohs(dev->tnl_cfg.dst_port) == VXLAN_DST_PORT) { + if (ntohs(dev_tnl_cfg->dst_port) == VXLAN_DST_PORT) { /* Special case where we kept the default port/gbp, only ok if the opposite of the default does not exits */ vxlan_get_port_ext_gbp_str(ntohs(tnl_cfg->dst_port), @@ -571,9 +587,9 @@ is_concomitant_vxlan_tunnel_present(struct netdev_vport *dev, } /* Same port: ok if no one is left with the previous configuration */ - if (dev->tnl_cfg.dst_port == tnl_cfg->dst_port) { - vxlan_get_port_ext_gbp_str(ntohs(dev->tnl_cfg.dst_port), - dev->tnl_cfg.exts & + if (dev_tnl_cfg->dst_port == tnl_cfg->dst_port) { + vxlan_get_port_ext_gbp_str(ntohs(dev_tnl_cfg->dst_port), + dev_tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GBP), namebuf, sizeof(namebuf)); @@ -601,6 +617,7 @@ static int set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) { struct netdev_vport *dev = netdev_vport_cast(dev_); + const struct netdev_tunnel_config *curr_tnl_cfg; const char *name = netdev_get_name(dev_); const char *type = netdev_get_type(dev_); struct ds errors = DS_EMPTY_INITIALIZER; @@ -902,11 +919,16 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) err = EEXIST; goto out; } - update_vxlan_global_cfg(dev_, &dev->tnl_cfg, &tnl_cfg); ovs_mutex_lock(&dev->mutex); - if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) { - dev->tnl_cfg = tnl_cfg; + + curr_tnl_cfg = vport_tunnel_config(dev); + update_vxlan_global_cfg(dev_, curr_tnl_cfg, &tnl_cfg); + + if (memcmp(curr_tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) { + ovsrcu_set(&dev->tnl_cfg, xmemdup(&tnl_cfg, sizeof tnl_cfg)); + ovsrcu_postpone(free, CONST_CAST(struct netdev_tunnel_config *, + curr_tnl_cfg)); tunnel_check_status_change__(dev); netdev_change_seq_changed(dev_); } @@ -931,61 +953,60 @@ out: static int get_tunnel_config(const struct netdev *dev, struct smap *args) { - struct netdev_vport *netdev = netdev_vport_cast(dev); + const struct netdev_tunnel_config *tnl_cfg = netdev_get_tunnel_config(dev); const char *type = netdev_get_type(dev); - struct netdev_tunnel_config tnl_cfg; - ovs_mutex_lock(&netdev->mutex); - tnl_cfg = netdev->tnl_cfg; - ovs_mutex_unlock(&netdev->mutex); + if (!tnl_cfg) { + return 0; + } - if (ipv6_addr_is_set(&tnl_cfg.ipv6_dst)) { - smap_add_ipv6(args, "remote_ip", &tnl_cfg.ipv6_dst); - } else if (tnl_cfg.ip_dst_flow) { + if (ipv6_addr_is_set(&tnl_cfg->ipv6_dst)) { + smap_add_ipv6(args, "remote_ip", &tnl_cfg->ipv6_dst); + } else if (tnl_cfg->ip_dst_flow) { smap_add(args, "remote_ip", "flow"); } - if (ipv6_addr_is_set(&tnl_cfg.ipv6_src)) { - smap_add_ipv6(args, "local_ip", &tnl_cfg.ipv6_src); - } else if (tnl_cfg.ip_src_flow) { + if (ipv6_addr_is_set(&tnl_cfg->ipv6_src)) { + smap_add_ipv6(args, "local_ip", &tnl_cfg->ipv6_src); + } else if (tnl_cfg->ip_src_flow) { smap_add(args, "local_ip", "flow"); } - if (tnl_cfg.in_key_flow && tnl_cfg.out_key_flow) { + if (tnl_cfg->in_key_flow && tnl_cfg->out_key_flow) { smap_add(args, "key", "flow"); - } else if (tnl_cfg.in_key_present && tnl_cfg.out_key_present - && tnl_cfg.in_key == tnl_cfg.out_key) { - smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg.in_key)); + } else if (tnl_cfg->in_key_present && tnl_cfg->out_key_present + && tnl_cfg->in_key == tnl_cfg->out_key) { + smap_add_format(args, "key", "%"PRIu64, ntohll(tnl_cfg->in_key)); } else { - if (tnl_cfg.in_key_flow) { + if (tnl_cfg->in_key_flow) { smap_add(args, "in_key", "flow"); - } else if (tnl_cfg.in_key_present) { + } else if (tnl_cfg->in_key_present) { smap_add_format(args, "in_key", "%"PRIu64, - ntohll(tnl_cfg.in_key)); + ntohll(tnl_cfg->in_key)); } - if (tnl_cfg.out_key_flow) { + if (tnl_cfg->out_key_flow) { smap_add(args, "out_key", "flow"); - } else if (tnl_cfg.out_key_present) { + } else if (tnl_cfg->out_key_present) { smap_add_format(args, "out_key", "%"PRIu64, - ntohll(tnl_cfg.out_key)); + ntohll(tnl_cfg->out_key)); } } - if (tnl_cfg.ttl_inherit) { + if (tnl_cfg->ttl_inherit) { smap_add(args, "ttl", "inherit"); - } else if (tnl_cfg.ttl != DEFAULT_TTL) { - smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg.ttl); + } else if (tnl_cfg->ttl != DEFAULT_TTL) { + smap_add_format(args, "ttl", "%"PRIu8, tnl_cfg->ttl); } - if (tnl_cfg.tos_inherit) { + if (tnl_cfg->tos_inherit) { smap_add(args, "tos", "inherit"); - } else if (tnl_cfg.tos) { - smap_add_format(args, "tos", "0x%x", tnl_cfg.tos); + } else if (tnl_cfg->tos) { + smap_add_format(args, "tos", "0x%x", tnl_cfg->tos); } - if (tnl_cfg.dst_port) { - uint16_t dst_port = ntohs(tnl_cfg.dst_port); + if (tnl_cfg->dst_port) { + uint16_t dst_port = ntohs(tnl_cfg->dst_port); if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) || (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) || @@ -997,33 +1018,33 @@ get_tunnel_config(const struct netdev *dev, struct smap *args) } } - if (tnl_cfg.csum) { + if (tnl_cfg->csum) { smap_add(args, "csum", "true"); } - if (tnl_cfg.set_seq) { + if (tnl_cfg->set_seq) { smap_add(args, "seq", "true"); } - enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg); - if (tnl_cfg.pt_mode != default_pt_mode(layers)) { + enum tunnel_layers layers = tunnel_supported_layers(type, tnl_cfg); + if (tnl_cfg->pt_mode != default_pt_mode(layers)) { smap_add(args, "packet_type", - tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L2 ? "legacy_l2" - : tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L3 ? "legacy_l3" + tnl_cfg->pt_mode == NETDEV_PT_LEGACY_L2 ? "legacy_l2" + : tnl_cfg->pt_mode == NETDEV_PT_LEGACY_L3 ? "legacy_l3" : "ptap"); } - if (!tnl_cfg.dont_fragment) { + if (!tnl_cfg->dont_fragment) { smap_add(args, "df_default", "false"); } - if (tnl_cfg.set_egress_pkt_mark) { + if (tnl_cfg->set_egress_pkt_mark) { smap_add_format(args, "egress_pkt_mark", - "%"PRIu32, tnl_cfg.egress_pkt_mark); + "%"PRIu32, tnl_cfg->egress_pkt_mark); } if (!strcmp("erspan", type) || !strcmp("ip6erspan", type)) { - if (tnl_cfg.erspan_ver_flow) { + if (tnl_cfg->erspan_ver_flow) { /* since version number is not determined, * assume print all other as flow */ @@ -1032,27 +1053,27 @@ get_tunnel_config(const struct netdev *dev, struct smap *args) smap_add(args, "erspan_dir", "flow"); smap_add(args, "erspan_hwid", "flow"); } else { - smap_add_format(args, "erspan_ver", "%d", tnl_cfg.erspan_ver); + smap_add_format(args, "erspan_ver", "%d", tnl_cfg->erspan_ver); - if (tnl_cfg.erspan_ver == 1) { - if (tnl_cfg.erspan_idx_flow) { + if (tnl_cfg->erspan_ver == 1) { + if (tnl_cfg->erspan_idx_flow) { smap_add(args, "erspan_idx", "flow"); } else { smap_add_format(args, "erspan_idx", "0x%x", - tnl_cfg.erspan_idx); + tnl_cfg->erspan_idx); } - } else if (tnl_cfg.erspan_ver == 2) { - if (tnl_cfg.erspan_dir_flow) { + } else if (tnl_cfg->erspan_ver == 2) { + if (tnl_cfg->erspan_dir_flow) { smap_add(args, "erspan_dir", "flow"); } else { smap_add_format(args, "erspan_dir", "%d", - tnl_cfg.erspan_dir); + tnl_cfg->erspan_dir); } - if (tnl_cfg.erspan_hwid_flow) { + if (tnl_cfg->erspan_hwid_flow) { smap_add(args, "erspan_hwid", "flow"); } else { smap_add_format(args, "erspan_hwid", "0x%x", - tnl_cfg.erspan_hwid); + tnl_cfg->erspan_hwid); } } } @@ -1182,9 +1203,11 @@ netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats) static enum netdev_pt_mode netdev_vport_get_pt_mode(const struct netdev *netdev) { - struct netdev_vport *dev = netdev_vport_cast(netdev); + const struct netdev_tunnel_config *tnl_cfg; + + tnl_cfg = netdev_get_tunnel_config(netdev); - return dev->tnl_cfg.pt_mode; + return tnl_cfg ? tnl_cfg->pt_mode : NETDEV_PT_UNKNOWN; } diff --git a/lib/netdev.h b/lib/netdev.h index 1fab91273..aaec9ded1 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -72,6 +72,9 @@ struct sset; struct ovs_action_push_tnl; enum netdev_pt_mode { + /* Unknown mode. The netdev is not configured yet. */ + NETDEV_PT_UNKNOWN = 0, + /* The netdev is packet type aware. It can potentially carry any kind of * packet. This "modern" mode is appropriate for both netdevs that handle * only a single kind of packet (such as a virtual or physical Ethernet