diff mbox series

[ovs-dev,v3] Bareudp Tunnel Support

Message ID 1589474981-3542-1-git-send-email-martinvarghesenokia@gmail.com
State New
Headers show
Series [ovs-dev,v3] Bareudp Tunnel Support | expand

Commit Message

Martin Varghese May 14, 2020, 4:49 p.m. UTC
From: Martin Varghese <martin.varghese@nokia.com>

UDP encapsulation support for tunnelling different protocols like
MPLS, IP, NSH etc.

Upstream commit:

    commit 571912c69f0ed731bd1e071ade9dc7ca4aa52065
    Author: Martin Varghese <martin.varghese@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.varghese@nokia.com>
    Acked-by: Willem de Bruijn <willemb@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Signed-off-by: Martin Varghese <martin.varghese@nokia.com>
---
 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

Comments

Gregory Rose May 14, 2020, 5:47 p.m. UTC | #1
On 5/14/2020 9:49 AM, Martin Varghese wrote:
> From: Martin Varghese <martin.varghese@nokia.com>
> 
> UDP encapsulation support for tunnelling different protocols like
> MPLS, IP, NSH etc.
> 
> Upstream commit:
> 
>      commit 571912c69f0ed731bd1e071ade9dc7ca4aa52065
>      Author: Martin Varghese <martin.varghese@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.varghese@nokia.com>
>      Acked-by: Willem de Bruijn <willemb@google.com>
>      Signed-off-by: David S. Miller <davem@davemloft.net>
> 
> Signed-off-by: Martin Varghese <martin.varghese@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.

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.varghese@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
>
Martin Varghese May 15, 2020, 3:08 a.m. UTC | #2
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.varghese@nokia.com>
> >
> >UDP encapsulation support for tunnelling different protocols like
> >MPLS, IP, NSH etc.
> >
> >Upstream commit:
> >
> >     commit 571912c69f0ed731bd1e071ade9dc7ca4aa52065
> >     Author: Martin Varghese <martin.varghese@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.varghese@nokia.com>
> >     Acked-by: Willem de Bruijn <willemb@google.com>
> >     Signed-off-by: David S. Miller <davem@davemloft.net>
> >
> >Signed-off-by: Martin Varghese <martin.varghese@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
> 
> 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.varghese@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
> >
Gregory Rose May 15, 2020, 11:51 p.m. UTC | #3
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.varghese@nokia.com>
>>>
>>> UDP encapsulation support for tunnelling different protocols like
>>> MPLS, IP, NSH etc.
>>>
>>> Upstream commit:
>>>
>>>      commit 571912c69f0ed731bd1e071ade9dc7ca4aa52065
>>>      Author: Martin Varghese <martin.varghese@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.varghese@nokia.com>
>>>      Acked-by: Willem de Bruijn <willemb@google.com>
>>>      Signed-off-by: David S. Miller <davem@davemloft.net>
>>>
>>> Signed-off-by: Martin Varghese <martin.varghese@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.

Thanks,

- 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.varghese@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
>>>
Martin Varghese May 21, 2020, 4:08 p.m. UTC | #4
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.varghese@nokia.com>
> >>>
> >>>UDP encapsulation support for tunnelling different protocols like
> >>>MPLS, IP, NSH etc.
> >>>
> >>>Upstream commit:
> >>>
> >>>     commit 571912c69f0ed731bd1e071ade9dc7ca4aa52065
> >>>     Author: Martin Varghese <martin.varghese@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.varghese@nokia.com>
> >>>     Acked-by: Willem de Bruijn <willemb@google.com>
> >>>     Signed-off-by: David S. Miller <davem@davemloft.net>
> >>>
> >>>Signed-off-by: Martin Varghese <martin.varghese@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.varghese@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
> >>>
Gregory Rose May 21, 2020, 4:16 p.m. UTC | #5
On 5/21/2020 9:08 AM, Martin Varghese wrote:
> 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.varghese@nokia.com>
>>>>>
>>>>> UDP encapsulation support for tunnelling different protocols like
>>>>> MPLS, IP, NSH etc.
>>>>>
>>>>> Upstream commit:
>>>>>
>>>>>      commit 571912c69f0ed731bd1e071ade9dc7ca4aa52065
>>>>>      Author: Martin Varghese <martin.varghese@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.varghese@nokia.com>
>>>>>      Acked-by: Willem de Bruijn <willemb@google.com>
>>>>>      Signed-off-by: David S. Miller <davem@davemloft.net>
>>>>>
>>>>> Signed-off-by: Martin Varghese <martin.varghese@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

That sounds like a workable plan.

Thanks,

- Greg


>>
>> - 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.varghese@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
>>>>>
diff mbox series

Patch

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.varghese@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