On Fri, May 15, 2020 at 04:51:05PM -0700, Gregory Rose wrote:
> 
> On 5/14/2020 8:08 PM, Martin Varghese wrote:
> >On Thu, May 14, 2020 at 10:47:30AM -0700, Gregory Rose wrote:
> >>
> >>On 5/14/2020 9:49 AM, Martin Varghese wrote:
> >>>From: Martin Varghese <martin.vargh...@nokia.com>
> >>>
> >>>UDP encapsulation support for tunnelling different protocols like
> >>>MPLS, IP, NSH etc.
> >>>
> >>>Upstream commit:
> >>>
> >>>     commit 571912c69f0ed731bd1e071ade9dc7ca4aa52065
> >>>     Author: Martin Varghese <martin.vargh...@nokia.com>
> >>>     Date:   Mon Feb 24 10:57:50 2020 +0530
> >>>
> >>>     net: UDP tunnel encapsulation module for tunnelling different
> >>>     protocols like MPLS, IP, NSH etc.
> >>>
> >>>     The Bareudp tunnel module provides a generic L3 encapsulation
> >>>     tunnelling module for tunnelling different protocols like MPLS,
> >>>     IP,NSH etc inside a UDP tunnel.
> >>>
> >>>     Signed-off-by: Martin Varghese <martin.vargh...@nokia.com>
> >>>     Acked-by: Willem de Bruijn <will...@google.com>
> >>>     Signed-off-by: David S. Miller <da...@davemloft.net>
> >>>
> >>>Signed-off-by: Martin Varghese <martin.vargh...@nokia.com>
> >>
> >>Hi Martin,
> >>
> >>First, thanks for all your work on this!
> >>
> >>This is closer to what we want but I'd prefer that it be broken up
> >>into two patches.  The first patch should be the one referred to in
> >>the commit message above and is all the kernel datapath bits.  The
> >>second patch would be the userspace bits with a separate and
> >>informative commit message. As this patch stands it has nothing to
> >>say about non kernel datapath code even though that makes up a
> >>significant portion of the patch.
> >>
> >>I will go ahead and begin testing and review of this patch for
> >>functional use and checking for regressions but before acceptance I
> >>think it will need to be split up.
> >
> >Allrite.
> >
> >Thanks,
> >Martin
> 
> Hi Martin,
> 
> I applied your patch and ran Travis CI here:
> https://travis-ci.org/github/gvrose8192/ovs-experimental/builds/687634520
> 
> 
> I got these errors:
> /home/travis/build/gvrose8192/ovs-experimental/datapath/linux/bareudp.c:515:2:
> error: unknown field ‘ndo_fill_metadata_dst’ specified in
> initializer
> 
>   .ndo_fill_metadata_dst  = bareudp_fill_metadata_dst,
>   ^
> In file included from 
> /home/travis/build/gvrose8192/ovs-experimental/datapath/linux/bareudp.c:21:0:
> 
> /home/travis/build/gvrose8192/ovs-experimental/datapath/linux/compat/include/net/bareudp.h:56:35:
> warning: initialization from incompatible pointer type
> [-Wincompatible-pointer-types]
> 
>  #define bareudp_fill_metadata_dst ovs_bareudp_fill_metadata_dst
>                                    ^
> /home/travis/build/gvrose8192/ovs-experimental/datapath/linux/bareudp.c:515:28:
> note: in expansion of macro ‘bareudp_fill_metadata_dst’
> 
>   .ndo_fill_metadata_dst  = bareudp_fill_metadata_dst,
>                             ^
> /home/travis/build/gvrose8192/ovs-experimental/datapath/linux/compat/include/net/bareudp.h:56:35:
> note: (near initialization for ‘bareudp_netdev_ops.ndo_get_stats’)
> 
>  #define bareudp_fill_metadata_dst ovs_bareudp_fill_metadata_dst
>                                    ^
> /home/travis/build/gvrose8192/ovs-experimental/datapath/linux/bareudp.c:515:28:
> note: in expansion of macro
> 
> If you could fix those up I can continue to review and test.  This
> might be a good time to split the patch up as I suggested earlier.
> 

I ran Travis CI myself and found couple of issues more.The IPv6 functions
which i use in the patch are not present in the older kernels against which it
is compiled.

Hence at this point i will post only the userspace bareudp patch which works 
with 
5.6 kernel.

I will defer the backport of bareudp driver as i may have to redo some of the 
functions
to get it working with older kernels

Thanks,
Martin
> 
> - Greg
> 
> >>
> >>Thanks,
> >>
> >>- Greg
> >>
> >>>---
> >>>  Documentation/automake.mk                         |   1 +
> >>>  Documentation/faq/bareudp.rst                     |  62 ++
> >>>  Documentation/faq/index.rst                       |   1 +
> >>>  Documentation/faq/releases.rst                    |   1 +
> >>>  NEWS                                              |   3 +-
> >>>  datapath/linux/Modules.mk                         |   2 +
> >>>  datapath/linux/compat/bareudp.c                   | 978 
> >>> ++++++++++++++++++++++
> >>>  datapath/linux/compat/include/linux/if_link.h     |  11 +
> >>>  datapath/linux/compat/include/linux/openvswitch.h |  11 +
> >>>  datapath/linux/compat/include/net/bareudp.h       |  59 ++
> >>>  datapath/linux/compat/include/net/ip6_tunnel.h    |   9 +
> >>>  datapath/linux/compat/include/net/ip_tunnels.h    |   7 +
> >>>  datapath/linux/compat/ip6_tunnel.c                |  60 ++
> >>>  datapath/linux/compat/ip_tunnel.c                 |  47 ++
> >>>  datapath/vport.c                                  |  11 +-
> >>>  lib/dpif-netlink-rtnl.c                           |  53 ++
> >>>  lib/dpif-netlink.c                                |  10 +
> >>>  lib/netdev-vport.c                                |  25 +-
> >>>  lib/netdev.h                                      |   1 +
> >>>  ofproto/ofproto-dpif-xlate.c                      |   1 +
> >>>  tests/system-layer3-tunnels.at                    |  47 ++
> >>>  21 files changed, 1396 insertions(+), 4 deletions(-)
> >>>  create mode 100644 Documentation/faq/bareudp.rst
> >>>  create mode 100644 datapath/linux/compat/bareudp.c
> >>>  create mode 100644 datapath/linux/compat/include/net/bareudp.h
> >>>
> >>>diff --git a/Documentation/automake.mk b/Documentation/automake.mk
> >>>index f85c432..ea3475f 100644
> >>>--- a/Documentation/automake.mk
> >>>+++ b/Documentation/automake.mk
> >>>@@ -88,6 +88,7 @@ DOC_SOURCE = \
> >>>   Documentation/faq/terminology.rst \
> >>>   Documentation/faq/vlan.rst \
> >>>   Documentation/faq/vxlan.rst \
> >>>+  Documentation/faq/bareudp.rst \
> >>>   Documentation/internals/index.rst \
> >>>   Documentation/internals/authors.rst \
> >>>   Documentation/internals/bugs.rst \
> >>>diff --git a/Documentation/faq/bareudp.rst b/Documentation/faq/bareudp.rst
> >>>new file mode 100644
> >>>index 0000000..7fdf05d
> >>>--- /dev/null
> >>>+++ b/Documentation/faq/bareudp.rst
> >>>@@ -0,0 +1,62 @@
> >>>+..
> >>>+      Licensed under the Apache License, Version 2.0 (the "License"); you 
> >>>may
> >>>+      not use this file except in compliance with the License. You may 
> >>>obtain
> >>>+      a copy of the License at
> >>>+
> >>>+          http://www.apache.org/licenses/LICENSE-2.0
> >>>+
> >>>+      Unless required by applicable law or agreed to in writing, software
> >>>+      distributed under the License is distributed on an "AS IS" BASIS, 
> >>>WITHOUT
> >>>+      WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
> >>>See the
> >>>+      License for the specific language governing permissions and 
> >>>limitations
> >>>+      under the License.
> >>>+
> >>>+      Convention for heading levels in Open vSwitch documentation:
> >>>+
> >>>+      =======  Heading 0 (reserved for the title in a document)
> >>>+      -------  Heading 1
> >>>+      ~~~~~~~  Heading 2
> >>>+      +++++++  Heading 3
> >>>+      '''''''  Heading 4
> >>>+
> >>>+      Avoid deeper levels because they do not render well.
> >>>+
> >>>+=======
> >>>+Bareudp
> >>>+=======
> >>>+
> >>>+Q: What is Bareudp?
> >>>+
> >>>+    A: There are various L3 encapsulation standards using UDP being 
> >>>discussed
> >>>+       to leverage the UDP based load balancing capability of different
> >>>+       networks. MPLSoUDP (__ https://tools.ietf.org/html/rfc7510) is one 
> >>>among
> >>>+       them.
> >>>+
> >>>+       The Bareudp tunnel provides a generic L3 encapsulation tunnelling
> >>>+       support for tunnelling different L3 protocols like MPLS, IP, NSH 
> >>>etc.
> >>>+       inside a UDP tunnel.
> >>>+
> >>>+       The bareudp device supports special handling for MPLS & IP as they 
> >>>can
> >>>+       have multiple ethertypes.
> >>>+       MPLS procotcol can have ethertypes ETH_P_MPLS_UC (unicast) &
> >>>+       ETH_P_MPLS_MC (multicast). IP protocol can have ethertypes 
> >>>ETH_P_IP (v4)
> >>>+       & ETH_P_IPV6 (v6).
> >>>+
> >>>+       An example to create bareudp device to tunnel MPLS traffic is given
> >>>+       below.::
> >>>+
> >>>+           $ ovs-vsctl add-port br_mpls udp_port -- set interface 
> >>>udp_port \
> >>>+             type=bareudp options:remote_ip=2.1.1.3 
> >>>options:local_ip=2.1.1.2 \
> >>>+             options:payload_type=0x8847 options:dst_port=6635 \
> >>>+             options:packet_type="legacy_l3" \
> >>>+             ofport_request=$bareudp_egress_port
> >>>+
> >>>+       The bareudp device to tunnel L3 traffic with muptiple ethertypes
> >>>+       (MPLS & IP) can be created by passing the L3 protocol name as 
> >>>string in
> >>>+       the field payload_type. An example to create bareudp device to 
> >>>tunnel
> >>>+       MPLS unicast & multicast traffic is given below.::
> >>>+
> >>>+            $ ovs-vsctl add-port  br_mpls udp_port -- set interface 
> >>>udp_port \
> >>>+              type=bareudp options:remote_ip=2.1.1.3 
> >>>options:local_ip=2.1.1.2 \
> >>>+              options:payload_type=mpls options:dst_port=6635 \
> >>>+              options:packet_type="legacy_l3"
> >>>diff --git a/Documentation/faq/index.rst b/Documentation/faq/index.rst
> >>>index 334b828..1dd2998 100644
> >>>--- a/Documentation/faq/index.rst
> >>>+++ b/Documentation/faq/index.rst
> >>>@@ -30,6 +30,7 @@ Open vSwitch FAQ
> >>>  .. toctree::
> >>>     :maxdepth: 2
> >>>+   bareudp
> >>>     configuration
> >>>     contributing
> >>>     design
> >>>diff --git a/Documentation/faq/releases.rst 
> >>>b/Documentation/faq/releases.rst
> >>>index 3903e59..4abc824 100644
> >>>--- a/Documentation/faq/releases.rst
> >>>+++ b/Documentation/faq/releases.rst
> >>>@@ -132,6 +132,7 @@ Q: Are all features available with all datapaths?
> >>>      Tunnel - ERSPAN                 4.18           2.10         2.10     
> >>> NO
> >>>      Tunnel - ERSPAN-IPv6            4.18           2.10         2.10     
> >>> NO
> >>>      Tunnel - GTP-U                  NO             NO           2.14     
> >>> NO
> >>>+    Tunnel - Bareudp                5.6            2.14         2.14     
> >>>NO
> >>>      QoS - Policing                  YES            1.1          2.6      
> >>> NO
> >>>      QoS - Shaping                   YES            1.1          NO       
> >>> NO
> >>>      sFlow                           YES            1.0          1.0      
> >>> NO
> >>>diff --git a/NEWS b/NEWS
> >>>index 3dbd8ec..0d5bc25 100644
> >>>--- a/NEWS
> >>>+++ b/NEWS
> >>>@@ -16,7 +16,8 @@ Post-v2.13.0
> >>>         by enabling interrupt mode.
> >>>     - Userspace datapath:
> >>>       * Add support for conntrack zone-based timeout policy.
> >>>-
> >>>+   - Bareudp Tunnel
> >>>+     * Userspace datapath support is not added.
> >>>  v2.13.0 - 14 Feb 2020
> >>>  ---------------------
> >>>diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
> >>>index 63a5cba..2028afc 100644
> >>>--- a/datapath/linux/Modules.mk
> >>>+++ b/datapath/linux/Modules.mk
> >>>@@ -1,4 +1,5 @@
> >>>  openvswitch_sources += \
> >>>+  linux/compat/bareudp.c \
> >>>   linux/compat/dev-openvswitch.c \
> >>>   linux/compat/dst_cache.c \
> >>>   linux/compat/exthdrs_core.c \
> >>>@@ -77,6 +78,7 @@ openvswitch_headers += \
> >>>   linux/compat/include/net/dst_metadata.h \
> >>>   linux/compat/include/net/genetlink.h \
> >>>   linux/compat/include/net/geneve.h \
> >>>+  linux/compat/include/net/bareudp.h \
> >>>   linux/compat/include/net/gre.h \
> >>>   linux/compat/include/net/inet_ecn.h \
> >>>   linux/compat/include/net/inet_frag.h \
> >>>diff --git a/datapath/linux/compat/bareudp.c 
> >>>b/datapath/linux/compat/bareudp.c
> >>>new file mode 100644
> >>>index 0000000..c432d79
> >>>--- /dev/null
> >>>+++ b/datapath/linux/compat/bareudp.c
> >>>@@ -0,0 +1,978 @@
> >>>+// SPDX-License-Identifier: GPL-2.0
> >>>+/* Bareudp: UDP  tunnel encasulation for different Payload types like
> >>>+ * MPLS, NSH, IP, etc.
> >>>+ * Copyright (c) 2019 Nokia, Inc.
> >>>+ * Authors:  Martin Varghese, <martin.vargh...@nokia.com>
> >>>+ */
> >>>+
> >>>+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >>>+
> >>>+#include <linux/kernel.h>
> >>>+#include <linux/module.h>
> >>>+#include <linux/etherdevice.h>
> >>>+#include <linux/hash.h>
> >>>+#include <net/netns/generic.h>
> >>>+#include <net/dst_metadata.h>
> >>>+#include <net/rtnetlink.h>
> >>>+#include <net/protocol.h>
> >>>+#include <net/ip6_tunnel.h>
> >>>+#include <net/ip_tunnels.h>
> >>>+#include <net/udp_tunnel.h>
> >>>+#include <net/bareudp.h>
> >>>+
> >>>+#include "compat.h"
> >>>+#include "vport-netdev.h"
> >>>+
> >>>+#ifndef USE_UPSTREAM_TUNNEL
> >>>+
> >>>+#define BAREUDP_BASE_HLEN sizeof(struct udphdr)
> >>>+#define BAREUDP_IPV4_HLEN (sizeof(struct iphdr) + \
> >>>+          sizeof(struct udphdr))
> >>>+#define BAREUDP_IPV6_HLEN (sizeof(struct ipv6hdr) + \
> >>>+          sizeof(struct udphdr))
> >>>+
> >>>+static bool log_ecn_error = true;
> >>>+module_param(log_ecn_error, bool, 0644);
> >>>+MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted 
> >>>ECN");
> >>>+
> >>>+/* per-network namespace private data for this module */
> >>>+
> >>>+static unsigned int bareudp_net_id;
> >>>+
> >>>+struct bareudp_net {
> >>>+  struct list_head        bareudp_list;
> >>>+};
> >>>+
> >>>+/* Pseudo network device */
> >>>+struct bareudp_dev {
> >>>+  struct net         *net;        /* netns for packet i/o */
> >>>+  struct net_device  *dev;        /* netdev for bareudp tunnel */
> >>>+  __be16             ethertype;
> >>>+  __be16             port;
> >>>+  u16                sport_min;
> >>>+  bool               multi_proto_mode;
> >>>+  struct socket      __rcu *sock;
> >>>+  struct list_head   next;        /* bareudp node  on namespace list */
> >>>+};
> >>>+
> >>>+static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
> >>>+{
> >>>+  struct metadata_dst *tun_dst = NULL;
> >>>+  struct pcpu_sw_netstats *stats;
> >>>+  struct bareudp_dev *bareudp;
> >>>+  unsigned short family;
> >>>+  unsigned int len;
> >>>+  __be16 proto;
> >>>+  void *oiph;
> >>>+  int err;
> >>>+  union {
> >>>+          struct metadata_dst dst;
> >>>+          char buf[sizeof(struct metadata_dst) + 256];
> >>>+  } buf;
> >>>+
> >>>+  bareudp = rcu_dereference_sk_user_data(sk);
> >>>+  if (!bareudp)
> >>>+          goto drop;
> >>>+
> >>>+  if (skb->protocol ==  htons(ETH_P_IP))
> >>>+          family = AF_INET;
> >>>+  else
> >>>+          family = AF_INET6;
> >>>+
> >>>+  if (bareudp->ethertype == htons(ETH_P_IP)) {
> >>>+          struct iphdr *iphdr;
> >>>+
> >>>+          iphdr = (struct iphdr *)(skb->data + BAREUDP_BASE_HLEN);
> >>>+          if (iphdr->version == 4) {
> >>>+                  proto = bareudp->ethertype;
> >>>+          } else if (bareudp->multi_proto_mode && (iphdr->version == 6)) {
> >>>+                  proto = htons(ETH_P_IPV6);
> >>>+          } else {
> >>>+                  bareudp->dev->stats.rx_dropped++;
> >>>+                  goto drop;
> >>>+          }
> >>>+  } else if (bareudp->ethertype == htons(ETH_P_MPLS_UC)) {
> >>>+          struct iphdr *tunnel_hdr;
> >>>+
> >>>+          tunnel_hdr = (struct iphdr *)skb_network_header(skb);
> >>>+          if (tunnel_hdr->version == 4) {
> >>>+                  if (!ipv4_is_multicast(tunnel_hdr->daddr)) {
> >>>+                          proto = bareudp->ethertype;
> >>>+                  } else if (bareudp->multi_proto_mode &&
> >>>+                                  ipv4_is_multicast(tunnel_hdr->daddr)) {
> >>>+                          proto = htons(ETH_P_MPLS_MC);
> >>>+                  } else {
> >>>+                          bareudp->dev->stats.rx_dropped++;
> >>>+                          goto drop;
> >>>+                  }
> >>>+          } else {
> >>>+                  int addr_type;
> >>>+                  struct ipv6hdr *tunnel_hdr_v6;
> >>>+
> >>>+                  tunnel_hdr_v6 = (struct ipv6hdr 
> >>>*)skb_network_header(skb);
> >>>+                  addr_type =
> >>>+                          ipv6_addr_type((struct in6_addr 
> >>>*)&tunnel_hdr_v6->daddr);
> >>>+                  if (!(addr_type & IPV6_ADDR_MULTICAST)) {
> >>>+                          proto = bareudp->ethertype;
> >>>+                  } else if (bareudp->multi_proto_mode &&
> >>>+                                  (addr_type & IPV6_ADDR_MULTICAST)) {
> >>>+                          proto = htons(ETH_P_MPLS_MC);
> >>>+                  } else {
> >>>+                          bareudp->dev->stats.rx_dropped++;
> >>>+                          goto drop;
> >>>+                  }
> >>>+          }
> >>>+  } else {
> >>>+          proto = bareudp->ethertype;
> >>>+  }
> >>>+
> >>>+  if (iptunnel_pull_header(skb, BAREUDP_BASE_HLEN,
> >>>+                          proto,
> >>>+                          !net_eq(bareudp->net,
> >>>+                                  dev_net(bareudp->dev)))) {
> >>>+          bareudp->dev->stats.rx_dropped++;
> >>>+          goto drop;
> >>>+  }
> >>>+  tun_dst = &buf.dst;
> >>>+  ovs_udp_tun_rx_dst(tun_dst, skb, family, TUNNEL_KEY, 0, 0);
> >>>+  if (!tun_dst) {
> >>>+          bareudp->dev->stats.rx_dropped++;
> >>>+          goto drop;
> >>>+  }
> >>>+  ovs_skb_dst_set(skb, &tun_dst->dst);
> >>>+
> >>>+  skb->dev = bareudp->dev;
> >>>+  oiph = skb_network_header(skb);
> >>>+  skb_reset_network_header(skb);
> >>>+
> >>>+  if (family == AF_INET)
> >>>+          err = IP_ECN_decapsulate(oiph, skb);
> >>>+#if IS_ENABLED(CONFIG_IPV6)
> >>>+  else
> >>>+          err = IP6_ECN_decapsulate(oiph, skb);
> >>>+#endif
> >>>+
> >>>+  if (unlikely(err)) {
> >>>+          if (log_ecn_error) {
> >>>+                  if  (family == AF_INET)
> >>>+                          net_info_ratelimited("non-ECT from %pI4 "
> >>>+                                          "with TOS=%#x\n",
> >>>+                                          &((struct iphdr *)oiph)->saddr,
> >>>+                                          ((struct iphdr *)oiph)->tos);
> >>>+#if IS_ENABLED(CONFIG_IPV6)
> >>>+                  else
> >>>+                          net_info_ratelimited("non-ECT from %pI6\n",
> >>>+                                          &((struct ipv6hdr 
> >>>*)oiph)->saddr);
> >>>+#endif
> >>>+          }
> >>>+          if (err > 1) {
> >>>+                  ++bareudp->dev->stats.rx_frame_errors;
> >>>+                  ++bareudp->dev->stats.rx_errors;
> >>>+                  goto drop;
> >>>+          }
> >>>+  }
> >>>+
> >>>+  len = skb->len;
> >>>+  netdev_port_receive(skb, skb_tunnel_info(skb));
> >>>+  if (likely(err == NET_RX_SUCCESS)) {
> >>>+          stats = this_cpu_ptr(bareudp->dev->tstats);
> >>>+          u64_stats_update_begin(&stats->syncp);
> >>>+          stats->rx_packets++;
> >>>+          stats->rx_bytes += len;
> >>>+          u64_stats_update_end(&stats->syncp);
> >>>+  }
> >>>+  return 0;
> >>>+drop:
> >>>+  /* Consume bad packet */
> >>>+  kfree_skb(skb);
> >>>+
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static int bareudp_init(struct net_device *dev)
> >>>+{
> >>>+  dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
> >>>+  if (!dev->tstats)
> >>>+          return -ENOMEM;
> >>>+
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static void bareudp_uninit(struct net_device *dev)
> >>>+{
> >>>+  free_percpu(dev->tstats);
> >>>+}
> >>>+
> >>>+static struct socket *bareudp_create_sock(struct net *net, __be16 port)
> >>>+{
> >>>+  struct udp_port_cfg udp_conf;
> >>>+  struct socket *sock;
> >>>+  int err;
> >>>+
> >>>+  memset(&udp_conf, 0, sizeof(udp_conf));
> >>>+#if IS_ENABLED(CONFIG_IPV6)
> >>>+  udp_conf.family = AF_INET6;
> >>>+#else
> >>>+  udp_conf.family = AF_INET;
> >>>+#endif
> >>>+  udp_conf.local_udp_port = port;
> >>>+  /* Open UDP socket */
> >>>+  err = udp_sock_create(net, &udp_conf, &sock);
> >>>+  if (err < 0)
> >>>+          return ERR_PTR(err);
> >>>+
> >>>+  return sock;
> >>>+}
> >>>+
> >>>+/* Create new listen socket if needed */
> >>>+static int bareudp_socket_create(struct bareudp_dev *bareudp, __be16 port)
> >>>+{
> >>>+  struct udp_tunnel_sock_cfg tunnel_cfg;
> >>>+  struct socket *sock;
> >>>+
> >>>+  sock = bareudp_create_sock(bareudp->net, port);
> >>>+  if (IS_ERR(sock))
> >>>+          return PTR_ERR(sock);
> >>>+
> >>>+  /* Mark socket as an encapsulation socket */
> >>>+  memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
> >>>+  tunnel_cfg.sk_user_data = bareudp;
> >>>+  tunnel_cfg.encap_type = 1;
> >>>+  tunnel_cfg.encap_rcv = bareudp_udp_encap_recv;
> >>>+  tunnel_cfg.encap_destroy = NULL;
> >>>+  setup_udp_tunnel_sock(bareudp->net, sock, &tunnel_cfg);
> >>>+
> >>>+  /* As the setup_udp_tunnel_sock does not call udp_encap_enable if the
> >>>+   * socket type is v6 an explicit call to udp_encap_enable is needed.
> >>>+   */
> >>>+  if (sock->sk->sk_family == AF_INET6)
> >>>+          udp_encap_enable();
> >>>+
> >>>+  rcu_assign_pointer(bareudp->sock, sock);
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static int bareudp_open(struct net_device *dev)
> >>>+{
> >>>+  struct bareudp_dev *bareudp = netdev_priv(dev);
> >>>+  int ret = 0;
> >>>+
> >>>+  ret =  bareudp_socket_create(bareudp, bareudp->port);
> >>>+  return ret;
> >>>+}
> >>>+
> >>>+static void bareudp_sock_release(struct bareudp_dev *bareudp)
> >>>+{
> >>>+  struct socket *sock;
> >>>+
> >>>+  sock = bareudp->sock;
> >>>+  rcu_assign_pointer(bareudp->sock, NULL);
> >>>+  synchronize_net();
> >>>+  udp_tunnel_sock_release(sock);
> >>>+}
> >>>+
> >>>+static int bareudp_stop(struct net_device *dev)
> >>>+{
> >>>+  struct bareudp_dev *bareudp = netdev_priv(dev);
> >>>+
> >>>+  bareudp_sock_release(bareudp);
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev,
> >>>+          struct bareudp_dev *bareudp,
> >>>+          const struct ip_tunnel_info *info)
> >>>+{
> >>>+  bool xnet = !net_eq(bareudp->net, dev_net(bareudp->dev));
> >>>+  bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
> >>>+  struct socket *sock = rcu_dereference(bareudp->sock);
> >>>+  bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
> >>>+  const struct ip_tunnel_key *key = &info->key;
> >>>+  struct rtable *rt;
> >>>+  __be16 sport, df;
> >>>+  int min_headroom;
> >>>+  __u8 tos, ttl;
> >>>+  __be32 saddr;
> >>>+  int err;
> >>>+
> >>>+  if (!sock)
> >>>+          return -ESHUTDOWN;
> >>>+
> >>>+  rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, info,
> >>>+                  IPPROTO_UDP, use_cache);
> >>>+
> >>>+  if (IS_ERR(rt))
> >>>+          return PTR_ERR(rt);
> >>>+
> >>>+  sport = udp_flow_src_port(bareudp->net, skb,
> >>>+                  bareudp->sport_min, USHRT_MAX,
> >>>+                  true);
> >>>+  tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
> >>>+  ttl = key->ttl;
> >>>+  df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
> >>>+  skb_scrub_packet(skb, xnet);
> >>>+
> >>>+  err = -ENOSPC;
> >>>+  if (!skb_pull(skb, skb_network_offset(skb)))
> >>>+          goto free_dst;
> >>>+
> >>>+  min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len +
> >>>+          BAREUDP_BASE_HLEN + info->options_len + sizeof(struct iphdr);
> >>>+
> >>>+  err = skb_cow_head(skb, min_headroom);
> >>>+  if (unlikely(err))
> >>>+          goto free_dst;
> >>>+
> >>>+  err = udp_tunnel_handle_offloads(skb, udp_sum);
> >>>+  if (err)
> >>>+          goto free_dst;
> >>>+
> >>>+  skb_set_inner_protocol(skb, bareudp->ethertype);
> >>>+  udp_tunnel_xmit_skb(rt, sock->sk, skb, saddr, info->key.u.ipv4.dst,
> >>>+                  tos, ttl, df, sport, bareudp->port,
> >>>+                  !net_eq(bareudp->net, dev_net(bareudp->dev)),
> >>>+                  !(info->key.tun_flags & TUNNEL_CSUM));
> >>>+  return 0;
> >>>+
> >>>+free_dst:
> >>>+  dst_release(&rt->dst);
> >>>+  return err;
> >>>+}
> >>>+
> >>>+#if IS_ENABLED(CONFIG_IPV6)
> >>>+static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
> >>>+          struct bareudp_dev *bareudp,
> >>>+          const struct ip_tunnel_info *info)
> >>>+{
> >>>+  bool xnet = !net_eq(bareudp->net, dev_net(bareudp->dev));
> >>>+  bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
> >>>+  struct socket *sock  = rcu_dereference(bareudp->sock);
> >>>+  bool udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
> >>>+  const struct ip_tunnel_key *key = &info->key;
> >>>+  struct dst_entry *dst = NULL;
> >>>+  struct in6_addr saddr, daddr;
> >>>+  int min_headroom;
> >>>+  __u8 prio, ttl;
> >>>+  __be16 sport;
> >>>+  int err;
> >>>+
> >>>+  if (!sock)
> >>>+          return -ESHUTDOWN;
> >>>+
> >>>+  dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, &saddr, info,
> >>>+                  IPPROTO_UDP, use_cache);
> >>>+  if (IS_ERR(dst))
> >>>+          return PTR_ERR(dst);
> >>>+
> >>>+  sport = udp_flow_src_port(bareudp->net, skb,
> >>>+                  bareudp->sport_min, USHRT_MAX,
> >>>+                  true);
> >>>+  prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
> >>>+  ttl = key->ttl;
> >>>+
> >>>+  skb_scrub_packet(skb, xnet);
> >>>+
> >>>+  err = -ENOSPC;
> >>>+  if (!skb_pull(skb, skb_network_offset(skb)))
> >>>+          goto free_dst;
> >>>+
> >>>+  min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len +
> >>>+          BAREUDP_BASE_HLEN + info->options_len + sizeof(struct iphdr);
> >>>+
> >>>+  err = skb_cow_head(skb, min_headroom);
> >>>+  if (unlikely(err))
> >>>+          goto free_dst;
> >>>+
> >>>+  err = udp_tunnel_handle_offloads(skb, udp_sum);
> >>>+  if (err)
> >>>+          goto free_dst;
> >>>+
> >>>+  daddr = info->key.u.ipv6.dst;
> >>>+  udp_tunnel6_xmit_skb(dst, sock->sk, skb, dev,
> >>>+                  &saddr, &daddr, prio, ttl,
> >>>+                  info->key.label, sport, bareudp->port,
> >>>+                  !(info->key.tun_flags & TUNNEL_CSUM));
> >>>+  return 0;
> >>>+
> >>>+free_dst:
> >>>+  dst_release(dst);
> >>>+  return err;
> >>>+}
> >>>+#endif
> >>>+
> >>>+netdev_tx_t rpl_bareudp_xmit(struct sk_buff *skb)
> >>>+{
> >>>+  struct net_device *dev = skb->dev;
> >>>+  struct bareudp_dev *bareudp = netdev_priv(dev);
> >>>+  struct ip_tunnel_info *info = NULL;
> >>>+  int err;
> >>>+
> >>>+  if (skb->protocol != bareudp->ethertype) {
> >>>+          if (!bareudp->multi_proto_mode ||
> >>>+                          (skb->protocol !=  htons(ETH_P_MPLS_MC) &&
> >>>+                           skb->protocol !=  htons(ETH_P_IPV6))) {
> >>>+                  err = -EINVAL;
> >>>+                  goto tx_error;
> >>>+          }
> >>>+  }
> >>>+
> >>>+  info = skb_tunnel_info(skb);
> >>>+  if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
> >>>+          err = -EINVAL;
> >>>+          goto tx_error;
> >>>+  }
> >>>+
> >>>+  rcu_read_lock();
> >>>+#if IS_ENABLED(CONFIG_IPV6)
> >>>+  if (info->mode & IP_TUNNEL_INFO_IPV6)
> >>>+          err = bareudp6_xmit_skb(skb, dev, bareudp, info);
> >>>+  else
> >>>+#endif
> >>>+          err = bareudp_xmit_skb(skb, dev, bareudp, info);
> >>>+
> >>>+  rcu_read_unlock();
> >>>+
> >>>+  if (likely(!err))
> >>>+          return NETDEV_TX_OK;
> >>>+tx_error:
> >>>+  dev_kfree_skb(skb);
> >>>+
> >>>+  if (err == -ELOOP)
> >>>+          dev->stats.collisions++;
> >>>+  else if (err == -ENETUNREACH)
> >>>+          dev->stats.tx_carrier_errors++;
> >>>+
> >>>+  dev->stats.tx_errors++;
> >>>+  return NETDEV_TX_OK;
> >>>+}
> >>>+EXPORT_SYMBOL_GPL(rpl_bareudp_xmit);
> >>>+
> >>>+static netdev_tx_t bareudp_dev_xmit(struct sk_buff *skb, struct 
> >>>net_device *dev)
> >>>+{
> >>>+  /* Drop All packets coming from networking stack. OVS-CB is
> >>>+   * not initialized for these packets.
> >>>+   */
> >>>+  dev_kfree_skb(skb);
> >>>+  dev->stats.tx_dropped++;
> >>>+  return NETDEV_TX_OK;
> >>>+}
> >>>+
> >>>+
> >>>+int ovs_bareudp_fill_metadata_dst(struct net_device *dev,
> >>>+          struct sk_buff *skb)
> >>>+{
> >>>+  struct ip_tunnel_info *info = skb_tunnel_info(skb);
> >>>+  struct bareudp_dev *bareudp = netdev_priv(dev);
> >>>+  bool use_cache;
> >>>+
> >>>+  use_cache = ip_tunnel_dst_cache_usable(skb, info);
> >>>+
> >>>+  if (ip_tunnel_info_af(info) == AF_INET) {
> >>>+          struct rtable *rt;
> >>>+          __be32 saddr;
> >>>+
> >>>+          rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr,
> >>>+                          info, IPPROTO_UDP, use_cache);
> >>>+          if (IS_ERR(rt))
> >>>+                  return PTR_ERR(rt);
> >>>+
> >>>+          ip_rt_put(rt);
> >>>+          info->key.u.ipv4.src = saddr;
> >>>+#if IS_ENABLED(CONFIG_IPV6)
> >>>+  } else if (ip_tunnel_info_af(info) == AF_INET6) {
> >>>+          struct dst_entry *dst;
> >>>+          struct in6_addr saddr;
> >>>+          struct socket *sock = rcu_dereference(bareudp->sock);
> >>>+
> >>>+          dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock,
> >>>+                          &saddr, info, IPPROTO_UDP,
> >>>+                          use_cache);
> >>>+          if (IS_ERR(dst))
> >>>+                  return PTR_ERR(dst);
> >>>+
> >>>+          dst_release(dst);
> >>>+          info->key.u.ipv6.src = saddr;
> >>>+#endif
> >>>+  } else {
> >>>+          return -EINVAL;
> >>>+  }
> >>>+
> >>>+  info->key.tp_src = udp_flow_src_port(bareudp->net, skb,
> >>>+                  bareudp->sport_min,
> >>>+                  USHRT_MAX, true);
> >>>+  info->key.tp_dst = bareudp->port;
> >>>+  return 0;
> >>>+}
> >>>+EXPORT_SYMBOL_GPL(ovs_bareudp_fill_metadata_dst);
> >>>+
> >>>+static const struct net_device_ops bareudp_netdev_ops = {
> >>>+  .ndo_init               = bareudp_init,
> >>>+  .ndo_uninit             = bareudp_uninit,
> >>>+  .ndo_open               = bareudp_open,
> >>>+  .ndo_stop               = bareudp_stop,
> >>>+  .ndo_start_xmit         = bareudp_dev_xmit,
> >>>+  .ndo_get_stats64        = ip_tunnel_get_stats64,
> >>>+  .ndo_fill_metadata_dst  = bareudp_fill_metadata_dst,
> >>>+};
> >>>+
> >>>+static const struct nla_policy bareudp_policy[IFLA_BAREUDP_MAX + 1] = {
> >>>+  [IFLA_BAREUDP_PORT]                = { .type = NLA_U16 },
> >>>+  [IFLA_BAREUDP_ETHERTYPE]           = { .type = NLA_U16 },
> >>>+  [IFLA_BAREUDP_SRCPORT_MIN]         = { .type = NLA_U16 },
> >>>+  [IFLA_BAREUDP_MULTIPROTO_MODE]     = { .type = NLA_FLAG },
> >>>+};
> >>>+
> >>>+/* Info for udev, that this is a virtual tunnel endpoint */
> >>>+static struct device_type bareudp_type = {
> >>>+  .name = "bareudp",
> >>>+};
> >>>+
> >>>+/* Initialize the device structure. */
> >>>+static void bareudp_setup(struct net_device *dev)
> >>>+{
> >>>+  dev->netdev_ops = &bareudp_netdev_ops;
> >>>+  SET_NETDEV_DEVTYPE(dev, &bareudp_type);
> >>>+  dev->features    |= NETIF_F_SG | NETIF_F_HW_CSUM;
> >>>+  dev->features    |= NETIF_F_RXCSUM;
> >>>+  dev->features    |= NETIF_F_GSO_SOFTWARE;
> >>>+  dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
> >>>+  dev->hw_features |= NETIF_F_GSO_SOFTWARE;
> >>>+  dev->hard_header_len = 0;
> >>>+  dev->addr_len = 0;
> >>>+  dev->mtu = IP_MAX_MTU - BAREUDP_BASE_HLEN;
> >>>+  dev->type = ARPHRD_NONE;
> >>>+  netif_keep_dst(dev);
> >>>+  dev->priv_flags |= IFF_NO_QUEUE;
> >>>+  dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
> >>>+}
> >>>+#ifdef  HAVE_EXT_ACK_IN_RTNL_LINKOPS
> >>>+static int bareudp_validate(struct nlattr *tb[], struct nlattr *data[],
> >>>+          struct netlink_ext_ack *extack)
> >>>+#else
> >>>+static int bareudp_validate(struct nlattr *tb[], struct nlattr *data[])
> >>>+#endif
> >>>+{
> >>>+  if (!data) {
> >>>+          return -EINVAL;
> >>>+  }
> >>>+  return 0;
> >>>+}
> >>>+#ifdef  HAVE_EXT_ACK_IN_RTNL_LINKOPS
> >>>+static int bareudp2info(struct nlattr *data[], struct bareudp_conf *conf,
> >>>+          struct netlink_ext_ack *extack)
> >>>+#else
> >>>+static int bareudp2info(struct nlattr *data[], struct bareudp_conf *conf)
> >>>+#endif
> >>>+{
> >>>+  if (!data[IFLA_BAREUDP_PORT]) {
> >>>+          return -EINVAL;
> >>>+  }
> >>>+  if (!data[IFLA_BAREUDP_ETHERTYPE]) {
> >>>+          return -EINVAL;
> >>>+  }
> >>>+
> >>>+  if (data[IFLA_BAREUDP_PORT])
> >>>+          conf->port =  nla_get_u16(data[IFLA_BAREUDP_PORT]);
> >>>+
> >>>+  if (data[IFLA_BAREUDP_ETHERTYPE])
> >>>+          conf->ethertype =  nla_get_u16(data[IFLA_BAREUDP_ETHERTYPE]);
> >>>+
> >>>+  if (data[IFLA_BAREUDP_SRCPORT_MIN])
> >>>+          conf->sport_min =  nla_get_u16(data[IFLA_BAREUDP_SRCPORT_MIN]);
> >>>+
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static struct bareudp_dev *bareudp_find_dev(struct bareudp_net *bn,
> >>>+          const struct bareudp_conf *conf)
> >>>+{
> >>>+  struct bareudp_dev *bareudp, *t = NULL;
> >>>+
> >>>+  list_for_each_entry(bareudp, &bn->bareudp_list, next) {
> >>>+          if (conf->port == bareudp->port)
> >>>+                  t = bareudp;
> >>>+  }
> >>>+  return t;
> >>>+}
> >>>+
> >>>+static int bareudp_configure(struct net *net, struct net_device *dev,
> >>>+          struct bareudp_conf *conf)
> >>>+{
> >>>+  struct bareudp_net *bn = net_generic(net, bareudp_net_id);
> >>>+  struct bareudp_dev *t, *bareudp = netdev_priv(dev);
> >>>+  int err;
> >>>+
> >>>+  bareudp->net = net;
> >>>+  bareudp->dev = dev;
> >>>+  t = bareudp_find_dev(bn, conf);
> >>>+  if (t)
> >>>+          return -EBUSY;
> >>>+
> >>>+  if (conf->multi_proto_mode &&
> >>>+                  (conf->ethertype != htons(ETH_P_MPLS_UC) &&
> >>>+                   conf->ethertype != htons(ETH_P_IP)))
> >>>+          return -EINVAL;
> >>>+
> >>>+  bareudp->port = conf->port;
> >>>+  bareudp->ethertype = conf->ethertype;
> >>>+  bareudp->sport_min = conf->sport_min;
> >>>+  bareudp->multi_proto_mode = conf->multi_proto_mode;
> >>>+  err = register_netdevice(dev);
> >>>+  if (err)
> >>>+          return err;
> >>>+
> >>>+  list_add(&bareudp->next, &bn->bareudp_list);
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static int bareudp_link_config(struct net_device *dev,
> >>>+          struct nlattr *tb[])
> >>>+{
> >>>+  int err;
> >>>+
> >>>+  if (tb[IFLA_MTU]) {
> >>>+          err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
> >>>+          if (err)
> >>>+                  return err;
> >>>+  }
> >>>+  return 0;
> >>>+}
> >>>+#ifdef  HAVE_EXT_ACK_IN_RTNL_LINKOPS
> >>>+static int bareudp_newlink(struct net *net, struct net_device *dev,
> >>>+          struct nlattr *tb[], struct nlattr *data[],
> >>>+          struct netlink_ext_ack *extack)
> >>>+#else
> >>>+static int bareudp_newlink(struct net *net, struct net_device *dev,
> >>>+          struct nlattr *tb[], struct nlattr *data[])
> >>>+#endif
> >>>+
> >>>+{
> >>>+  struct bareudp_conf conf;
> >>>+  int err;
> >>>+#ifdef  HAVE_EXT_ACK_IN_RTNL_LINKOPS
> >>>+  err = bareudp2info(data, &conf, extack);
> >>>+#else
> >>>+  err = bareudp2info(data, &conf);
> >>>+#endif
> >>>+  if (err)
> >>>+          return err;
> >>>+
> >>>+  err = bareudp_configure(net, dev, &conf);
> >>>+  if (err)
> >>>+          return err;
> >>>+
> >>>+  err = bareudp_link_config(dev, tb);
> >>>+  if (err)
> >>>+          return err;
> >>>+
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static void bareudp_dellink(struct net_device *dev, struct list_head 
> >>>*head)
> >>>+{
> >>>+  struct bareudp_dev *bareudp = netdev_priv(dev);
> >>>+
> >>>+  list_del(&bareudp->next);
> >>>+  unregister_netdevice_queue(dev, head);
> >>>+}
> >>>+
> >>>+static size_t bareudp_get_size(const struct net_device *dev)
> >>>+{
> >>>+  return  nla_total_size(sizeof(__be16)) +  /* IFLA_BAREUDP_PORT */
> >>>+          nla_total_size(sizeof(__be16)) +  /* IFLA_BAREUDP_ETHERTYPE */
> >>>+          nla_total_size(sizeof(__u16))  +  /* IFLA_BAREUDP_SRCPORT_MIN */
> >>>+          nla_total_size(0)              +  /* 
> >>>IFLA_BAREUDP_MULTIPROTO_MODE */
> >>>+          0;
> >>>+}
> >>>+
> >>>+static int bareudp_fill_info(struct sk_buff *skb, const struct net_device 
> >>>*dev)
> >>>+{
> >>>+  struct bareudp_dev *bareudp = netdev_priv(dev);
> >>>+
> >>>+  if (nla_put_be16(skb, IFLA_BAREUDP_PORT, bareudp->port))
> >>>+          goto nla_put_failure;
> >>>+  if (nla_put_be16(skb, IFLA_BAREUDP_ETHERTYPE, bareudp->ethertype))
> >>>+          goto nla_put_failure;
> >>>+  if (nla_put_u16(skb, IFLA_BAREUDP_SRCPORT_MIN, bareudp->sport_min))
> >>>+          goto nla_put_failure;
> >>>+  if (bareudp->multi_proto_mode &&
> >>>+                  nla_put_flag(skb, IFLA_BAREUDP_MULTIPROTO_MODE))
> >>>+          goto nla_put_failure;
> >>>+
> >>>+  return 0;
> >>>+
> >>>+nla_put_failure:
> >>>+  return -EMSGSIZE;
> >>>+}
> >>>+
> >>>+static struct rtnl_link_ops bareudp_link_ops __read_mostly = {
> >>>+  .kind           = "ovs_bareudp",
> >>>+  .maxtype        = IFLA_BAREUDP_MAX,
> >>>+  .policy         = bareudp_policy,
> >>>+  .priv_size      = sizeof(struct bareudp_dev),
> >>>+  .setup          = bareudp_setup,
> >>>+  .validate       = bareudp_validate,
> >>>+  .newlink        = bareudp_newlink,
> >>>+  .dellink        = bareudp_dellink,
> >>>+  .get_size       = bareudp_get_size,
> >>>+  .fill_info      = bareudp_fill_info,
> >>>+};
> >>>+
> >>>+struct net_device *rpl_bareudp_dev_create(struct net *net, const char 
> >>>*name,
> >>>+          u8 name_assign_type,
> >>>+          struct bareudp_conf *conf)
> >>>+{
> >>>+  struct nlattr *tb[IFLA_MAX + 1];
> >>>+  struct net_device *dev;
> >>>+  LIST_HEAD(list_kill);
> >>>+  int err;
> >>>+
> >>>+  memset(tb, 0, sizeof(tb));
> >>>+  dev = rtnl_create_link(net, name, name_assign_type,
> >>>+                  &bareudp_link_ops, tb);
> >>>+  if (IS_ERR(dev))
> >>>+          return dev;
> >>>+
> >>>+  err = bareudp_configure(net, dev, conf);
> >>>+  if (err) {
> >>>+          free_netdev(dev);
> >>>+          return ERR_PTR(err);
> >>>+  }
> >>>+  err = dev_set_mtu(dev, IP_MAX_MTU - BAREUDP_BASE_HLEN);
> >>>+  if (err)
> >>>+          goto err;
> >>>+
> >>>+  err = rtnl_configure_link(dev, NULL);
> >>>+  if (err < 0)
> >>>+          goto err;
> >>>+
> >>>+  return dev;
> >>>+err:
> >>>+  bareudp_dellink(dev, &list_kill);
> >>>+  unregister_netdevice_many(&list_kill);
> >>>+  return ERR_PTR(err);
> >>>+}
> >>>+EXPORT_SYMBOL_GPL(rpl_bareudp_dev_create);
> >>>+
> >>>+static __net_init int bareudp_init_net(struct net *net)
> >>>+{
> >>>+  struct bareudp_net *bn = net_generic(net, bareudp_net_id);
> >>>+
> >>>+  INIT_LIST_HEAD(&bn->bareudp_list);
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static void bareudp_destroy_tunnels(struct net *net, struct list_head 
> >>>*head)
> >>>+{
> >>>+  struct bareudp_net *bn = net_generic(net, bareudp_net_id);
> >>>+  struct bareudp_dev *bareudp, *next;
> >>>+
> >>>+  list_for_each_entry_safe(bareudp, next, &bn->bareudp_list, next)
> >>>+          unregister_netdevice_queue(bareudp->dev, head);
> >>>+}
> >>>+
> >>>+static void __net_exit bareudp_exit_batch_net(struct list_head *net_list)
> >>>+{
> >>>+  struct net *net;
> >>>+  LIST_HEAD(list);
> >>>+
> >>>+  rtnl_lock();
> >>>+  list_for_each_entry(net, net_list, exit_list)
> >>>+          bareudp_destroy_tunnels(net, &list);
> >>>+
> >>>+  /* unregister the devices gathered above */
> >>>+  unregister_netdevice_many(&list);
> >>>+  rtnl_unlock();
> >>>+}
> >>>+
> >>>+static struct pernet_operations bareudp_net_ops = {
> >>>+  .init = bareudp_init_net,
> >>>+  .exit_batch = bareudp_exit_batch_net,
> >>>+  .id   = &bareudp_net_id,
> >>>+  .size = sizeof(struct bareudp_net),
> >>>+};
> >>>+
> >>>+static struct vport_ops ovs_bareudp_vport_ops;
> >>>+
> >>>+/**
> >>>+ * struct bareudp_port - Keeps track of open UDP ports
> >>>+ * @dst_port: destination port.
> >>>+ * @payload_ethertype: ethertype of the l3 traffic tunnelled
> >>>+ */
> >>>+struct bareudp_port {
> >>>+  u16 dst_port;
> >>>+  u16 payload_ethertype;
> >>>+};
> >>>+
> >>>+static inline struct bareudp_port *bareudp_vport(const struct vport 
> >>>*vport)
> >>>+{
> >>>+  return vport_priv(vport);
> >>>+}
> >>>+
> >>>+static int bareudp_get_options(const struct vport *vport,
> >>>+          struct sk_buff *skb)
> >>>+{
> >>>+  struct bareudp_port *bareudp_port = bareudp_vport(vport);
> >>>+
> >>>+  if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, bareudp_port->dst_port))
> >>>+          return -EMSGSIZE;
> >>>+
> >>>+  if (nla_put_u16(skb, OVS_TUNNEL_ATTR_PAYLOAD_ETHERTYPE, 
> >>>bareudp_port->dst_port))
> >>>+          return -EMSGSIZE;
> >>>+
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static const struct nla_policy exts_policy[OVS_BAREUDP_EXT_MAX + 1] = {
> >>>+        [OVS_BAREUDP_EXT_MULTIPROTO_MODE]     = { .type = NLA_FLAG, },
> >>>+};
> >>>+
> >>>+static int bareudp_configure_exts(struct vport *vport, struct nlattr 
> >>>*attr,
> >>>+          struct bareudp_conf *conf)
> >>>+{
> >>>+  struct nlattr *exts[OVS_BAREUDP_EXT_MAX + 1];
> >>>+  int err;
> >>>+
> >>>+  if (nla_len(attr) < sizeof(struct nlattr))
> >>>+          return -EINVAL;
> >>>+
> >>>+  err = nla_parse_nested_deprecated(exts, OVS_BAREUDP_EXT_MAX, attr,
> >>>+                  exts_policy, NULL);
> >>>+  if (err < 0)
> >>>+          return err;
> >>>+
> >>>+  if (exts[OVS_BAREUDP_EXT_MULTIPROTO_MODE])
> >>>+          conf->multi_proto_mode = true;
> >>>+
> >>>+  return 0;
> >>>+}
> >>>+
> >>>+static struct vport *bareudp_tnl_create(const struct vport_parms *parms)
> >>>+{
> >>>+  struct net *net = ovs_dp_get_net(parms->dp);
> >>>+  struct nlattr *options = parms->options;
> >>>+  struct bareudp_port *bareudp_port;
> >>>+  struct net_device *dev;
> >>>+  struct vport *vport;
> >>>+  struct bareudp_conf conf;
> >>>+  struct nlattr *a;
> >>>+  u16 ethertype;
> >>>+  u16 dst_port;
> >>>+  int err;
> >>>+
> >>>+  if (!options) {
> >>>+          err = -EINVAL;
> >>>+          goto error;
> >>>+  }
> >>>+
> >>>+  a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
> >>>+  if (a && nla_len(a) == sizeof(u16)) {
> >>>+          dst_port = nla_get_u16(a);
> >>>+  } else {
> >>>+          /* Require destination port from userspace. */
> >>>+          err = -EINVAL;
> >>>+          goto error;
> >>>+  }
> >>>+
> >>>+  a = nla_find_nested(options, OVS_TUNNEL_ATTR_PAYLOAD_ETHERTYPE);
> >>>+  if (a && nla_len(a) == sizeof(u16)) {
> >>>+          ethertype = nla_get_u16(a);
> >>>+  } else {
> >>>+          /* Require destination port from userspace. */
> >>>+          err = -EINVAL;
> >>>+          goto error;
> >>>+  }
> >>>+
> >>>+  vport = ovs_vport_alloc(sizeof(struct bareudp_port),
> >>>+                          &ovs_bareudp_vport_ops, parms);
> >>>+  if (IS_ERR(vport))
> >>>+          return vport;
> >>>+
> >>>+  a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION);
> >>>+  if (a) {
> >>>+          err = bareudp_configure_exts(vport, a, &conf);
> >>>+          if (err) {
> >>>+                  ovs_vport_free(vport);
> >>>+                  goto error;
> >>>+          }
> >>>+  }
> >>>+
> >>>+  bareudp_port = bareudp_vport(vport);
> >>>+  bareudp_port->dst_port = dst_port;
> >>>+  bareudp_port->payload_ethertype = ethertype;
> >>>+
> >>>+  conf.ethertype = htons(ethertype);
> >>>+  conf.port = htons(dst_port);
> >>>+
> >>>+  rtnl_lock();
> >>>+  dev = bareudp_dev_create(net, parms->name, NET_NAME_USER, &conf);
> >>>+  if (IS_ERR(dev)) {
> >>>+          rtnl_unlock();
> >>>+          ovs_vport_free(vport);
> >>>+          return ERR_CAST(dev);
> >>>+  }
> >>>+
> >>>+  err = dev_change_flags(dev, dev->flags | IFF_UP, NULL);
> >>>+  if (err < 0) {
> >>>+          rtnl_delete_link(dev);
> >>>+          rtnl_unlock();
> >>>+          ovs_vport_free(vport);
> >>>+          goto error;
> >>>+  }
> >>>+
> >>>+  rtnl_unlock();
> >>>+  return vport;
> >>>+error:
> >>>+  return ERR_PTR(err);
> >>>+}
> >>>+
> >>>+static struct vport *bareudp_create(const struct vport_parms *parms)
> >>>+{
> >>>+  struct vport *vport;
> >>>+
> >>>+  vport = bareudp_tnl_create(parms);
> >>>+  if (IS_ERR(vport))
> >>>+          return vport;
> >>>+
> >>>+  return ovs_netdev_link(vport, parms->name);
> >>>+}
> >>>+
> >>>+static struct vport_ops ovs_bareudp_vport_ops = {
> >>>+        .type           = OVS_VPORT_TYPE_BAREUDP,
> >>>+        .create         = bareudp_create,
> >>>+        .destroy        = ovs_netdev_tunnel_destroy,
> >>>+        .get_options    = bareudp_get_options,
> >>>+#ifndef USE_UPSTREAM_TUNNEL
> >>>+        .fill_metadata_dst = bareudp_fill_metadata_dst,
> >>>+#endif
> >>>+        .send           = bareudp_xmit,
> >>>+};
> >>>+
> >>>+int rpl_bareudp_init_module(void)
> >>>+{
> >>>+  int rc;
> >>>+
> >>>+  rc = register_pernet_subsys(&bareudp_net_ops);
> >>>+  if (rc)
> >>>+          goto out1;
> >>>+
> >>>+  rc = rtnl_link_register(&bareudp_link_ops);
> >>>+  if (rc)
> >>>+          goto out2;
> >>>+
> >>>+  pr_info("Bareudp tunneling driver\n");
> >>>+        ovs_vport_ops_register(&ovs_bareudp_vport_ops);
> >>>+  return 0;
> >>>+out2:
> >>>+  unregister_pernet_subsys(&bareudp_net_ops);
> >>>+out1:
> >>>+  return rc;
> >>>+}
> >>>+
> >>>+void rpl_bareudp_cleanup_module(void)
> >>>+{
> >>>+        ovs_vport_ops_unregister(&ovs_bareudp_vport_ops);
> >>>+  rtnl_link_unregister(&bareudp_link_ops);
> >>>+  unregister_pernet_subsys(&bareudp_net_ops);
> >>>+}
> >>>+#endif
> >>>diff --git a/datapath/linux/compat/include/linux/if_link.h 
> >>>b/datapath/linux/compat/include/linux/if_link.h
> >>>index bd77e33..d180085 100644
> >>>--- a/datapath/linux/compat/include/linux/if_link.h
> >>>+++ b/datapath/linux/compat/include/linux/if_link.h
> >>>@@ -61,6 +61,17 @@ enum {
> >>>  };
> >>>  #define IFLA_LISP_MAX    (__IFLA_LISP_MAX - 1)
> >>>+enum {
> >>>+  IFLA_BAREUDP_UNSPEC,
> >>>+  IFLA_BAREUDP_PORT,
> >>>+  IFLA_BAREUDP_ETHERTYPE,
> >>>+  IFLA_BAREUDP_SRCPORT_MIN,
> >>>+  IFLA_BAREUDP_MULTIPROTO_MODE,
> >>>+  __IFLA_BAREUDP_MAX
> >>>+};
> >>>+
> >>>+#define IFLA_BAREUDP_MAX (__IFLA_BAREUDP_MAX - 1)
> >>>+
> >>>  /* VXLAN section */
> >>>  enum {
> >>>  #define IFLA_VXLAN_UNSPEC rpl_IFLA_VXLAN_UNSPEC
> >>>diff --git a/datapath/linux/compat/include/linux/openvswitch.h 
> >>>b/datapath/linux/compat/include/linux/openvswitch.h
> >>>index f7c3b2e..6b5b4d0 100644
> >>>--- a/datapath/linux/compat/include/linux/openvswitch.h
> >>>+++ b/datapath/linux/compat/include/linux/openvswitch.h
> >>>@@ -240,6 +240,7 @@ enum ovs_vport_type {
> >>>   OVS_VPORT_TYPE_GRE,      /* GRE tunnel. */
> >>>   OVS_VPORT_TYPE_VXLAN,    /* VXLAN tunnel. */
> >>>   OVS_VPORT_TYPE_GENEVE,   /* Geneve tunnel. */
> >>>+  OVS_VPORT_TYPE_BAREUDP,  /* Bareudp tunnel. */
> >>>   OVS_VPORT_TYPE_LISP = 105,  /* LISP tunnel */
> >>>   OVS_VPORT_TYPE_STT = 106, /* STT tunnel */
> >>>   OVS_VPORT_TYPE_ERSPAN = 107, /* ERSPAN tunnel. */
> >>>@@ -308,12 +309,22 @@ enum {
> >>>  #define OVS_VXLAN_EXT_MAX (__OVS_VXLAN_EXT_MAX - 1)
> >>>+enum {
> >>>+        OVS_BAREUDP_EXT_UNSPEC,
> >>>+        OVS_BAREUDP_EXT_MULTIPROTO_MODE,
> >>>+        /* place new values here to fill gap. */
> >>>+        __OVS_BAREUDP_EXT_MAX,
> >>>+};
> >>>+
> >>>+#define OVS_BAREUDP_EXT_MAX (__OVS_BAREUDP_EXT_MAX - 1)
> >>>+
> >>>  /* OVS_VPORT_ATTR_OPTIONS attributes for tunnels.
> >>>   */
> >>>  enum {
> >>>   OVS_TUNNEL_ATTR_UNSPEC,
> >>>   OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */
> >>>   OVS_TUNNEL_ATTR_EXTENSION,
> >>>+  OVS_TUNNEL_ATTR_PAYLOAD_ETHERTYPE, /*Ethertype of l3 packet tunnelled */
> >>>   __OVS_TUNNEL_ATTR_MAX
> >>>  };
> >>>diff --git a/datapath/linux/compat/include/net/bareudp.h 
> >>>b/datapath/linux/compat/include/net/bareudp.h
> >>>new file mode 100644
> >>>index 0000000..888194f
> >>>--- /dev/null
> >>>+++ b/datapath/linux/compat/include/net/bareudp.h
> >>>@@ -0,0 +1,59 @@
> >>>+#ifndef __NET_BAREUDP_WRAPPER_H
> >>>+#define __NET_BAREUDP_WRAPPER_H  1
> >>>+
> >>>+#ifdef CONFIG_INET
> >>>+#include <net/udp_tunnel.h>
> >>>+#endif
> >>>+
> >>>+
> >>>+#ifdef USE_UPSTREAM_TUNNEL
> >>>+#include_next <net/bareudp.h>
> >>>+
> >>>+static inline int rpl_bareudp_init_module(void)
> >>>+{
> >>>+  return 0;
> >>>+}
> >>>+static inline void rpl_bareudp_cleanup_module(void)
> >>>+{}
> >>>+
> >>>+#define bareudp_xmit dev_queue_xmit
> >>>+
> >>>+#ifdef CONFIG_INET
> >>>+#ifdef HAVE_NAME_ASSIGN_TYPE
> >>>+static inline struct net_device *rpl_bareudp_dev_create(
> >>>+  struct net *net, const char *name, u8 name_assign_type, struct 
> >>>bareudp_conf *conf) {
> >>>+  return bareudp_dev_create(net, name,name_assign_type, conf);
> >>>+}
> >>>+#define bareudp_dev_create rpl_bareudp_dev_create
> >>>+#endif
> >>>+#endif
> >>>+
> >>>+#else
> >>>+
> >>>+struct bareudp_conf {
> >>>+        __be16 ethertype;
> >>>+        __be16 port;
> >>>+        u16 sport_min;
> >>>+        bool multi_proto_mode;
> >>>+};
> >>>+
> >>>+#ifdef CONFIG_INET
> >>>+#define bareudp_dev_create rpl_bareudp_dev_create
> >>>+struct net_device *rpl_bareudp_dev_create(struct net *net, const char 
> >>>*name,
> >>>+                                    u8 name_assign_type, struct 
> >>>bareudp_conf *conf);
> >>>+#endif /*ifdef CONFIG_INET */
> >>>+
> >>>+int rpl_bareudp_init_module(void);
> >>>+void rpl_bareudp_cleanup_module(void);
> >>>+
> >>>+#define bareudp_xmit rpl_bareudp_xmit
> >>>+netdev_tx_t rpl_bareudp_xmit(struct sk_buff *skb);
> >>>+
> >>>+#endif
> >>>+#define bareudp_init_module rpl_bareudp_init_module
> >>>+#define bareudp_cleanup_module rpl_bareudp_cleanup_module
> >>>+
> >>>+#define bareudp_fill_metadata_dst ovs_bareudp_fill_metadata_dst
> >>>+int ovs_bareudp_fill_metadata_dst(struct net_device *dev, struct sk_buff 
> >>>*skb);
> >>>+
> >>>+#endif /*ifdef__NET_BAREUDP_H */
> >>>diff --git a/datapath/linux/compat/include/net/ip6_tunnel.h 
> >>>b/datapath/linux/compat/include/net/ip6_tunnel.h
> >>>index e0a33a6..02e5713 100644
> >>>--- a/datapath/linux/compat/include/net/ip6_tunnel.h
> >>>+++ b/datapath/linux/compat/include/net/ip6_tunnel.h
> >>>@@ -188,6 +188,15 @@ int rpl_ip6_tnl_get_iflink(const struct net_device 
> >>>*dev);
> >>>  #define ip6_tnl_get_iflink rpl_ip6_tnl_get_iflink
> >>>  int rpl_ip6_tnl_change_mtu(struct net_device *dev, int new_mtu);
> >>>  #define ip6_tnl_change_mtu rpl_ip6_tnl_change_mtu
> >>>+struct dst_entry *rpl_ip6_dst_lookup_tunnel(struct sk_buff *skb,
> >>>+                                      struct net_device *dev,
> >>>+                                      struct net *net,
> >>>+                                      struct socket *sock,
> >>>+                                      struct in6_addr *saddr,
> >>>+                                      const struct ip_tunnel_info *info,
> >>>+                                      u8 protocol,
> >>>+                                      bool use_cache);
> >>>+#define ip6_dst_lookup_tunnel rpl_ip6_dst_lookup_tunnel
> >>>  static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
> >>>                             struct net_device *dev)
> >>>diff --git a/datapath/linux/compat/include/net/ip_tunnels.h 
> >>>b/datapath/linux/compat/include/net/ip_tunnels.h
> >>>index 617a753..94db865 100644
> >>>--- a/datapath/linux/compat/include/net/ip_tunnels.h
> >>>+++ b/datapath/linux/compat/include/net/ip_tunnels.h
> >>>@@ -490,6 +490,13 @@ struct ip_tunnel *rpl_ip_tunnel_lookup(struct 
> >>>ip_tunnel_net *itn,
> >>>                                  __be32 remote, __be32 local,
> >>>                                  __be32 key);
> >>>+#define ip_route_output_tunnel rpl_ip_route_output_tunnel
> >>>+struct rtable *rpl_ip_route_output_tunnel(struct sk_buff *skb,
> >>>+                                    struct net_device *dev,
> >>>+                                    struct net *net, __be32 *saddr,
> >>>+                                    const struct ip_tunnel_info *info,
> >>>+                                    u8 protocol, bool use_cache);
> >>>+
> >>>  static inline int iptunnel_pull_offloads(struct sk_buff *skb)
> >>>  {
> >>>   if (skb_is_gso(skb)) {
> >>>diff --git a/datapath/linux/compat/ip6_tunnel.c 
> >>>b/datapath/linux/compat/ip6_tunnel.c
> >>>index 984a51b..3b60505 100644
> >>>--- a/datapath/linux/compat/ip6_tunnel.c
> >>>+++ b/datapath/linux/compat/ip6_tunnel.c
> >>>@@ -175,6 +175,66 @@ static struct net_device_stats *ip6_get_stats(struct 
> >>>net_device *dev)
> >>>   return &dev->stats;
> >>>  }
> >>>+struct dst_entry *rpl_ip6_dst_lookup_tunnel(struct sk_buff *skb,
> >>>+                                      struct net_device *dev,
> >>>+                                      struct net *net,
> >>>+                                      struct socket *sock,
> >>>+                                      struct in6_addr *saddr,
> >>>+                                      const struct ip_tunnel_info *info,
> >>>+                                      u8 protocol,
> >>>+                                      bool use_cache)
> >>>+{
> >>>+  struct dst_entry *dst = NULL;
> >>>+#ifdef CONFIG_DST_CACHE
> >>>+  struct dst_cache *dst_cache;
> >>>+#endif
> >>>+  struct flowi6 fl6;
> >>>+  __u8 prio;
> >>>+
> >>>+#ifdef CONFIG_DST_CACHE
> >>>+  dst_cache = (struct dst_cache *)&info->dst_cache;
> >>>+  if (use_cache) {
> >>>+          dst = dst_cache_get_ip6(dst_cache, saddr);
> >>>+          if (dst)
> >>>+                  return dst;
> >>>+  }
> >>>+#endif
> >>>+  memset(&fl6, 0, sizeof(fl6));
> >>>+  fl6.flowi6_mark = skb->mark;
> >>>+  fl6.flowi6_proto = protocol;
> >>>+  fl6.daddr = info->key.u.ipv6.dst;
> >>>+  fl6.saddr = info->key.u.ipv6.src;
> >>>+  prio = info->key.tos;
> >>>+  fl6.flowlabel = ip6_make_flowinfo(RT_TOS(prio),
> >>>+                  info->key.label);
> >>>+
> >>>+#ifdef HAVE_IPV6_DST_LOOKUP_NET
> >>>+  if (ipv6_stub->ipv6_dst_lookup(net, sock->sk, &dst, &fl6)) {
> >>>+#else
> >>>+#ifdef HAVE_IPV6_STUB
> >>>+  if (ipv6_stub->ipv6_dst_lookup(sock->sk, &dst, &fl6)) {
> >>>+#else
> >>>+  if (ip6_dst_lookup(sock->sk, &dst, &fl6)) {
> >>>+#endif
> >>>+#endif
> >>>+          netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr);
> >>>+          return ERR_PTR(-ENETUNREACH);
> >>>+  }
> >>>+
> >>>+  if (dst->dev == dev) { /* is this necessary? */
> >>>+          netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr);
> >>>+          dst_release(dst);
> >>>+          return ERR_PTR(-ELOOP);
> >>>+  }
> >>>+#ifdef CONFIG_DST_CACHE
> >>>+  if (use_cache)
> >>>+          dst_cache_set_ip6(dst_cache, dst, &fl6.saddr);
> >>>+#endif
> >>>+  *saddr = fl6.saddr;
> >>>+  return dst;
> >>>+}
> >>>+EXPORT_SYMBOL_GPL(rpl_ip6_dst_lookup_tunnel);
> >>>+
> >>>  /**
> >>>   * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
> >>>   *   @remote: the address of the tunnel exit-point
> >>>diff --git a/datapath/linux/compat/ip_tunnel.c 
> >>>b/datapath/linux/compat/ip_tunnel.c
> >>>index e7a0393..85b9812 100644
> >>>--- a/datapath/linux/compat/ip_tunnel.c
> >>>+++ b/datapath/linux/compat/ip_tunnel.c
> >>>@@ -773,4 +773,51 @@ skip_key_lookup:
> >>>  }
> >>>  EXPORT_SYMBOL_GPL(rpl_ip_tunnel_lookup);
> >>>+struct rtable *rpl_ip_route_output_tunnel(struct sk_buff *skb,
> >>>+                                    struct net_device *dev,
> >>>+                                    struct net *net, __be32 *saddr,
> >>>+                                    const struct ip_tunnel_info *info,
> >>>+                                    u8 protocol, bool use_cache)
> >>>+{
> >>>+#ifdef CONFIG_DST_CACHE
> >>>+  struct dst_cache *dst_cache;
> >>>+#endif
> >>>+  struct rtable *rt = NULL;
> >>>+  struct flowi4 fl4;
> >>>+  __u8 tos;
> >>>+
> >>>+#ifdef CONFIG_DST_CACHE
> >>>+  dst_cache = (struct dst_cache *)&info->dst_cache;
> >>>+  if (use_cache) {
> >>>+          rt = dst_cache_get_ip4(dst_cache, saddr);
> >>>+          if (rt)
> >>>+                  return rt;
> >>>+  }
> >>>+#endif
> >>>+  memset(&fl4, 0, sizeof(fl4));
> >>>+  fl4.flowi4_mark = skb->mark;
> >>>+  fl4.flowi4_proto = protocol;
> >>>+  fl4.daddr = info->key.u.ipv4.dst;
> >>>+  fl4.saddr = info->key.u.ipv4.src;
> >>>+  tos = info->key.tos;
> >>>+  fl4.flowi4_tos = RT_TOS(tos);
> >>>+
> >>>+  rt = ip_route_output_key(net, &fl4);
> >>>+  if (IS_ERR(rt)) {
> >>>+          netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr);
> >>>+          return ERR_PTR(-ENETUNREACH);
> >>>+  }
> >>>+  if (rt->dst.dev == dev) { /* is this necessary? */
> >>>+          netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr);
> >>>+          ip_rt_put(rt);
> >>>+          return ERR_PTR(-ELOOP);
> >>>+  }
> >>>+#ifdef CONFIG_DST_CACHE
> >>>+  if (use_cache)
> >>>+          dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr);
> >>>+#endif
> >>>+  *saddr = fl4.saddr;
> >>>+  return rt;
> >>>+}
> >>>+EXPORT_SYMBOL_GPL(rpl_ip_route_output_tunnel);
> >>>  #endif
> >>>diff --git a/datapath/vport.c b/datapath/vport.c
> >>>index f929282..84c95d3 100644
> >>>--- a/datapath/vport.c
> >>>+++ b/datapath/vport.c
> >>>@@ -35,6 +35,7 @@
> >>>  #include <net/geneve.h>
> >>>  #include <net/stt.h>
> >>>  #include <net/vxlan.h>
> >>>+#include <net/bareudp.h>
> >>>  #include "datapath.h"
> >>>  #include "gso.h"
> >>>@@ -77,7 +78,7 @@ int ovs_vport_init(void)
> >>>           }
> >>>           err = ipgre_init();
> >>>-          if (err && err != -EEXIST)
> >>>+          if (err && err != -EEXIST)
> >>>                   goto err_ipgre;
> >>>           compat_gre_loaded = true;
> >>>   }
> >>>@@ -108,7 +109,14 @@ skip_ip6_tunnel_init:
> >>>   if (err)
> >>>           goto err_stt;
> >>>+  err = bareudp_init_module();
> >>>+  if (err)
> >>>+          goto err_bareudp;
> >>>+
> >>>   return 0;
> >>>+  bareudp_cleanup_module();
> >>>+
> >>>+err_bareudp:
> >>>   ovs_stt_cleanup_module();
> >>>  err_stt:
> >>>   vxlan_cleanup_module();
> >>>@@ -140,6 +148,7 @@ void ovs_vport_exit(void)
> >>>           gre_exit();
> >>>           ipgre_fini();
> >>>   }
> >>>+        bareudp_cleanup_module();
> >>>   ovs_stt_cleanup_module();
> >>>   vxlan_cleanup_module();
> >>>   geneve_cleanup_module();
> >>>diff --git a/lib/dpif-netlink-rtnl.c b/lib/dpif-netlink-rtnl.c
> >>>index fd157ce..283f32a 100644
> >>>--- a/lib/dpif-netlink-rtnl.c
> >>>+++ b/lib/dpif-netlink-rtnl.c
> >>>@@ -58,6 +58,18 @@ VLOG_DEFINE_THIS_MODULE(dpif_netlink_rtnl);
> >>>  #define IFLA_GENEVE_UDP_ZERO_CSUM6_RX 10
> >>>  #endif
> >>>+#ifndef __IFLA_BAREUDP_MAX
> >>>+#define IFLA_BAREUDP_MAX 0
> >>>+#endif
> >>>+#if IFLA_BAREUDP_MAX < 4
> >>>+#define IFLA_BAREUDP_PORT 1
> >>>+#define IFLA_BAREUDP_ETHERTYPE 2
> >>>+#define IFLA_BAREUDP_SRCPORT_MIN 3
> >>>+#define IFLA_BAREUDP_MULTIPROTO_MODE 4
> >>>+#endif
> >>>+
> >>>+#define BAREUDP_MPLS_SRCPORT_MIN 49153
> >>>+
> >>>  static const struct nl_policy rtlink_policy[] = {
> >>>      [IFLA_LINKINFO] = { .type = NL_A_NESTED },
> >>>  };
> >>>@@ -81,6 +93,10 @@ static const struct nl_policy geneve_policy[] = {
> >>>      [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NL_A_U8 },
> >>>      [IFLA_GENEVE_PORT] = { .type = NL_A_U16 },
> >>>  };
> >>>+static const struct nl_policy bareudp_policy[] = {
> >>>+    [IFLA_BAREUDP_PORT] = { .type = NL_A_U16 },
> >>>+    [IFLA_BAREUDP_ETHERTYPE] = { .type = NL_A_U16 },
> >>>+};
> >>>  static const char *
> >>>  vport_type_to_kind(enum ovs_vport_type type,
> >>>@@ -113,6 +129,8 @@ vport_type_to_kind(enum ovs_vport_type type,
> >>>          }
> >>>      case OVS_VPORT_TYPE_GTPU:
> >>>          return NULL;
> >>>+    case OVS_VPORT_TYPE_BAREUDP:
> >>>+        return "bareudp";
> >>>      case OVS_VPORT_TYPE_NETDEV:
> >>>      case OVS_VPORT_TYPE_INTERNAL:
> >>>      case OVS_VPORT_TYPE_LISP:
> >>>@@ -243,6 +261,24 @@ dpif_netlink_rtnl_geneve_verify(const struct 
> >>>netdev_tunnel_config *tnl_cfg,
> >>>      return err;
> >>>  }
> >>>+static int
> >>>+dpif_netlink_rtnl_bareudp_verify(const struct netdev_tunnel_config 
> >>>*tnl_cfg,
> >>>+                                const char *kind, struct ofpbuf *reply)
> >>>+{
> >>>+    struct nlattr *bareudp[ARRAY_SIZE(bareudp_policy)];
> >>>+    int err;
> >>>+
> >>>+    err = rtnl_policy_parse(kind, reply, bareudp_policy, bareudp,
> >>>+                            ARRAY_SIZE(bareudp_policy));
> >>>+    if (!err) {
> >>>+        if ((tnl_cfg->dst_port != 
> >>>nl_attr_get_be16(bareudp[IFLA_BAREUDP_PORT]))
> >>>+            || (tnl_cfg->payload_ethertype
> >>>+                != nl_attr_get_be16(bareudp[IFLA_BAREUDP_ETHERTYPE]))) {
> >>>+            err = EINVAL;
> >>>+        }
> >>>+    }
> >>>+    return err;
> >>>+}
> >>>  static int
> >>>  dpif_netlink_rtnl_verify(const struct netdev_tunnel_config *tnl_cfg,
> >>>@@ -275,6 +311,9 @@ dpif_netlink_rtnl_verify(const struct 
> >>>netdev_tunnel_config *tnl_cfg,
> >>>      case OVS_VPORT_TYPE_GENEVE:
> >>>          err = dpif_netlink_rtnl_geneve_verify(tnl_cfg, kind, reply);
> >>>          break;
> >>>+    case OVS_VPORT_TYPE_BAREUDP:
> >>>+        err = dpif_netlink_rtnl_bareudp_verify(tnl_cfg, kind, reply);
> >>>+        break;
> >>>      case OVS_VPORT_TYPE_NETDEV:
> >>>      case OVS_VPORT_TYPE_INTERNAL:
> >>>      case OVS_VPORT_TYPE_LISP:
> >>>@@ -362,6 +401,19 @@ dpif_netlink_rtnl_create(const struct 
> >>>netdev_tunnel_config *tnl_cfg,
> >>>      case OVS_VPORT_TYPE_LISP:
> >>>      case OVS_VPORT_TYPE_STT:
> >>>      case OVS_VPORT_TYPE_GTPU:
> >>>+    case OVS_VPORT_TYPE_BAREUDP:
> >>>+        nl_msg_put_be16(&request, IFLA_BAREUDP_ETHERTYPE,
> >>>+                        tnl_cfg->payload_ethertype);
> >>>+        if ((tnl_cfg->payload_ethertype == htons(ETH_TYPE_MPLS)) ||
> >>>+            (tnl_cfg->payload_ethertype ==  htons(ETH_TYPE_MPLS_MCAST))) {
> >>>+            nl_msg_put_be16(&request, IFLA_BAREUDP_SRCPORT_MIN,
> >>>+                            BAREUDP_MPLS_SRCPORT_MIN);
> >>>+        }
> >>>+        nl_msg_put_be16(&request, IFLA_BAREUDP_PORT, tnl_cfg->dst_port);
> >>>+        if (tnl_cfg->exts & (1 << OVS_BAREUDP_EXT_MULTIPROTO_MODE)) {
> >>>+            nl_msg_put_flag(&request, IFLA_BAREUDP_MULTIPROTO_MODE);
> >>>+        }
> >>>+        break;
> >>>      case OVS_VPORT_TYPE_UNSPEC:
> >>>      case __OVS_VPORT_TYPE_MAX:
> >>>      default:
> >>>@@ -470,6 +522,7 @@ dpif_netlink_rtnl_port_destroy(const char *name, const 
> >>>char *type)
> >>>      case OVS_VPORT_TYPE_ERSPAN:
> >>>      case OVS_VPORT_TYPE_IP6ERSPAN:
> >>>      case OVS_VPORT_TYPE_IP6GRE:
> >>>+    case OVS_VPORT_TYPE_BAREUDP:
> >>>          return dpif_netlink_rtnl_destroy(name);
> >>>      case OVS_VPORT_TYPE_NETDEV:
> >>>      case OVS_VPORT_TYPE_INTERNAL:
> >>>diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> >>>index dc64210..6822bf5 100644
> >>>--- a/lib/dpif-netlink.c
> >>>+++ b/lib/dpif-netlink.c
> >>>@@ -748,6 +748,9 @@ get_vport_type(const struct dpif_netlink_vport *vport)
> >>>      case OVS_VPORT_TYPE_GTPU:
> >>>          return "gtpu";
> >>>+    case OVS_VPORT_TYPE_BAREUDP:
> >>>+        return "bareudp";
> >>>+
> >>>      case OVS_VPORT_TYPE_UNSPEC:
> >>>      case __OVS_VPORT_TYPE_MAX:
> >>>          break;
> >>>@@ -783,6 +786,8 @@ netdev_to_ovs_vport_type(const char *type)
> >>>          return OVS_VPORT_TYPE_GRE;
> >>>      } else if (!strcmp(type, "gtpu")) {
> >>>          return OVS_VPORT_TYPE_GTPU;
> >>>+    } else if (!strcmp(type, "bareudp")) {
> >>>+        return OVS_VPORT_TYPE_BAREUDP;
> >>>      } else {
> >>>          return OVS_VPORT_TYPE_UNSPEC;
> >>>      }
> >>>@@ -907,6 +912,11 @@ dpif_netlink_port_add_compat(struct dpif_netlink 
> >>>*dpif, struct netdev *netdev,
> >>>              nl_msg_put_u16(&options, OVS_TUNNEL_ATTR_DST_PORT,
> >>>                             ntohs(tnl_cfg->dst_port));
> >>>          }
> >>>+        if (tnl_cfg->payload_ethertype) {
> >>>+            nl_msg_put_u16(&options, OVS_TUNNEL_ATTR_PAYLOAD_ETHERTYPE,
> >>>+                           ntohs(tnl_cfg->payload_ethertype));
> >>>+        }
> >>>+
> >>>          if (tnl_cfg->exts) {
> >>>              size_t ext_ofs;
> >>>              int i;
> >>>diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
> >>>index 8efd1ee..1e40cfa 100644
> >>>--- a/lib/netdev-vport.c
> >>>+++ b/lib/netdev-vport.c
> >>>@@ -112,7 +112,7 @@ netdev_vport_needs_dst_port(const struct netdev *dev)
> >>>      return (class->get_config == get_tunnel_config &&
> >>>              (!strcmp("geneve", type) || !strcmp("vxlan", type) ||
> >>>               !strcmp("lisp", type) || !strcmp("stt", type) ||
> >>>-             !strcmp("gtpu", type)));
> >>>+             !strcmp("gtpu", type) || !strcmp("bareudp",type)));
> >>>  }
> >>>  const char *
> >>>@@ -219,6 +219,8 @@ netdev_vport_construct(struct netdev *netdev_)
> >>>          dev->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);
> >>>+    } else if (!strcmp(type, "bareudp")) {
> >>>+        dev->tnl_cfg.dst_port = htons(port);
> >>>      }
> >>>      dev->tnl_cfg.dont_fragment = true;
> >>>@@ -438,6 +440,8 @@ tunnel_supported_layers(const char *type,
> >>>          return TNL_L2 | TNL_L3;
> >>>      } else if (!strcmp(type, "gtpu")) {
> >>>          return TNL_L3;
> >>>+    } else if (!strcmp(type, "bareudp")) {
> >>>+        return TNL_L3;
> >>>      } else {
> >>>          return TNL_L2;
> >>>      }
> >>>@@ -745,6 +749,16 @@ set_tunnel_config(struct netdev *dev_, const struct 
> >>>smap *args, char **errp)
> >>>                      goto out;
> >>>                  }
> >>>              }
> >>>+        } else if (!strcmp(node->key, "payload_type")) {
> >>>+            if (strcmp(node->key, "mpls")) {
> >>>+                 tnl_cfg.payload_ethertype = htons(ETH_TYPE_MPLS);
> >>>+                 tnl_cfg.exts |= (1 << OVS_BAREUDP_EXT_MULTIPROTO_MODE);
> >>>+            } else if ((strcmp(node->key, "ip"))) {
> >>>+                 tnl_cfg.payload_ethertype = htons(ETH_TYPE_IP);
> >>>+                 tnl_cfg.exts |= (1 << OVS_BAREUDP_EXT_MULTIPROTO_MODE);
> >>>+            } else {
> >>>+                 tnl_cfg.payload_ethertype = htons(atoi(node->value));
> >>>+            }
> >>>          } else {
> >>>              ds_put_format(&errors, "%s: unknown %s argument '%s'\n", 
> >>> name,
> >>>                            type, node->key);
> >>>@@ -1243,7 +1257,14 @@ netdev_vport_tunnel_register(void)
> >>>            },
> >>>            {{NULL, NULL, 0, 0}}
> >>>          },
> >>>-
> >>>+        { "udp_sys",
> >>>+          {
> >>>+              TUNNEL_FUNCTIONS_COMMON,
> >>>+              .type = "bareudp",
> >>>+              .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
> >>>+          },
> >>>+          {{NULL, NULL, 0, 0}}
> >>>+        },
> >>>      };
> >>>      static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
> >>>diff --git a/lib/netdev.h b/lib/netdev.h
> >>>index fdbe0e1..f15bca5 100644
> >>>--- a/lib/netdev.h
> >>>+++ b/lib/netdev.h
> >>>@@ -107,6 +107,7 @@ struct netdev_tunnel_config {
> >>>      bool out_key_flow;
> >>>      ovs_be64 out_key;
> >>>+    ovs_be16 payload_ethertype;
> >>>      ovs_be16 dst_port;
> >>>      bool ip_src_flow;
> >>>diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> >>>index 80fba84..ea88342 100644
> >>>--- a/ofproto/ofproto-dpif-xlate.c
> >>>+++ b/ofproto/ofproto-dpif-xlate.c
> >>>@@ -3573,6 +3573,7 @@ propagate_tunnel_data_to_flow(struct xlate_ctx *ctx, 
> >>>struct eth_addr dmac,
> >>>      case OVS_VPORT_TYPE_VXLAN:
> >>>      case OVS_VPORT_TYPE_GENEVE:
> >>>      case OVS_VPORT_TYPE_GTPU:
> >>>+    case OVS_VPORT_TYPE_BAREUDP:
> >>>          nw_proto = IPPROTO_UDP;
> >>>          break;
> >>>      case OVS_VPORT_TYPE_LISP:
> >>>diff --git a/tests/system-layer3-tunnels.at 
> >>>b/tests/system-layer3-tunnels.at
> >>>index 1232964..5d9ea93 100644
> >>>--- a/tests/system-layer3-tunnels.at
> >>>+++ b/tests/system-layer3-tunnels.at
> >>>@@ -152,3 +152,50 @@ AT_CHECK([tail -1 stdout], [0],
> >>>  OVS_VSWITCHD_STOP
> >>>  AT_CLEANUP
> >>>+
> >>>+AT_SETUP([layer3 - ping over MPLS Bareudp])
> >>>+OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])
> >>>+ADD_NAMESPACES(at_ns0, at_ns1)
> >>>+
> >>>+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "36:b1:ee:7c:01:01")
> >>>+ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24", "36:b1:ee:7c:01:02")
> >>>+
> >>>+ADD_OVS_TUNNEL([bareudp], [br0], [at_bareudp0], [8.1.1.3], [8.1.1.2/24],
> >>>+               [ options:local_ip=8.1.1.2 options:packet_type="legacy_l3" 
> >>>options:payload_type=mpls options:dst_port=6635])
> >>>+
> >>>+ADD_OVS_TUNNEL([bareudp], [br1], [at_bareudp1], [8.1.1.2], [8.1.1.3/24],
> >>>+               [options:local_ip=8.1.1.3 options:packet_type="legacy_l3" 
> >>>options:payload_type=mpls options:dst_port=6635])
> >>>+
> >>>+AT_DATA([flows0.txt], [dnl
> >>>+table=0,priority=100,dl_type=0x0800 
> >>>actions=push_mpls:0x8847,set_mpls_label:3,output:at_bareudp0
> >>>+table=0,priority=100,dl_type=0x8847 in_port=at_bareudp0 
> >>>actions=pop_mpls:0x0800,set_field:36:b1:ee:7c:01:01->dl_dst,set_field:36:b1:ee:7c:01:02->dl_src,output:ovs-p0
> >>>+table=0,priority=10 actions=normal
> >>>+])
> >>>+
> >>>+AT_DATA([flows1.txt], [dnl
> >>>+table=0,priority=100,dl_type=0x0800 
> >>>actions=push_mpls:0x8847,set_mpls_label:3,output:at_bareudp1
> >>>+table=0,priority=100,dl_type=0x8847 in_port=at_bareudp1 
> >>>actions=pop_mpls:0x0800,set_field:36:b1:ee:7c:01:02->dl_dst,set_field:36:b1:ee:7c:01:01->dl_src,output:ovs-p1
> >>>+table=0,priority=10 actions=normal
> >>>+])
> >>>+
> >>>+AT_CHECK([ip link add patch0 type veth peer name patch1])
> >>>+on_exit 'ip link del patch0'
> >>>+
> >>>+AT_CHECK([ip link set dev patch0 up])
> >>>+AT_CHECK([ip link set dev patch1 up])
> >>>+AT_CHECK([ovs-vsctl add-port br0 patch0])
> >>>+AT_CHECK([ovs-vsctl add-port br1 patch1])
> >>>+
> >>>+
> >>>+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br0 flows0.txt])
> >>>+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br1 flows1.txt])
> >>>+
> >>>+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | 
> >>>FORMAT_PING], [0], [dnl
> >>>+3 packets transmitted, 3 received, 0% packet loss, time 0ms
> >>>+])
> >>>+
> >>>+NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 | 
> >>>FORMAT_PING], [0], [dnl
> >>>+3 packets transmitted, 3 received, 0% packet loss, time 0ms
> >>>+])
> >>>+OVS_TRAFFIC_VSWITCHD_STOP
> >>>+AT_CLEANUP
> >>>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to