@@ -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);
@@ -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;
@@ -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) &&
@@ -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;
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 <i.maximets@ovn.org> --- 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(-)