summaryrefslogtreecommitdiff
path: root/datapath/linux
diff options
context:
space:
mode:
authorGreg Rose <gvrose8192@gmail.com>2022-07-14 14:23:29 -0700
committerIlya Maximets <i.maximets@ovn.org>2022-07-15 13:45:55 +0200
commit422e90437854c441a0b274d3bf06ce7d6bbf9de0 (patch)
tree0e65141df83a618e59b00eb96e9c806bfbd51a39 /datapath/linux
parent86642de3ad8d42ab2b5dbace241d8dc398bd1195 (diff)
downloadopenvswitch-422e90437854c441a0b274d3bf06ce7d6bbf9de0.tar.gz
make: Remove the Linux datapath.
Update the necessary make and configure files to remove the Linux datapath and then remove the datapath. Move datapath/linux/compat/include/linux/openvswitch.h to include/linux/openvswitch.h because it is needed to generate header files used by the userspace switch. Also remove references to the Linux datapath from auxiliary files and utilities since it is no longer supported. Signed-off-by: Greg Rose <gvrose8192@gmail.com> Reviewed-by: David Marchand <david.marchand@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Diffstat (limited to 'datapath/linux')
-rw-r--r--datapath/linux/.gitignore8
-rw-r--r--datapath/linux/Kbuild.in27
-rw-r--r--datapath/linux/Makefile.in9
-rw-r--r--datapath/linux/Makefile.main.in107
-rw-r--r--datapath/linux/Modules.mk123
-rw-r--r--datapath/linux/compat/build-aux/export-check-allow-list1
-rw-r--r--datapath/linux/compat/dev-openvswitch.c83
-rw-r--r--datapath/linux/compat/dst_cache.c173
-rw-r--r--datapath/linux/compat/exthdrs_core.c129
-rw-r--r--datapath/linux/compat/genetlink-openvswitch.c55
-rw-r--r--datapath/linux/compat/geneve.c1854
-rw-r--r--datapath/linux/compat/gre.c239
-rw-r--r--datapath/linux/compat/gso.c317
-rw-r--r--datapath/linux/compat/gso.h214
-rw-r--r--datapath/linux/compat/include/linux/bug.h13
-rw-r--r--datapath/linux/compat/include/linux/cache.h23
-rw-r--r--datapath/linux/compat/include/linux/compiler-gcc.h20
-rw-r--r--datapath/linux/compat/include/linux/compiler.h26
-rw-r--r--datapath/linux/compat/include/linux/cpumask.h11
-rw-r--r--datapath/linux/compat/include/linux/err.h37
-rw-r--r--datapath/linux/compat/include/linux/etherdevice.h62
-rw-r--r--datapath/linux/compat/include/linux/genetlink.h16
-rw-r--r--datapath/linux/compat/include/linux/if.h6
-rw-r--r--datapath/linux/compat/include/linux/if_ether.h39
-rw-r--r--datapath/linux/compat/include/linux/if_link.h171
-rw-r--r--datapath/linux/compat/include/linux/if_vlan.h306
-rw-r--r--datapath/linux/compat/include/linux/in.h56
-rw-r--r--datapath/linux/compat/include/linux/jiffies.h34
-rw-r--r--datapath/linux/compat/include/linux/kconfig.h49
-rw-r--r--datapath/linux/compat/include/linux/kernel.h39
-rw-r--r--datapath/linux/compat/include/linux/list.h31
-rw-r--r--datapath/linux/compat/include/linux/mm.h44
-rw-r--r--datapath/linux/compat/include/linux/mpls.h40
-rw-r--r--datapath/linux/compat/include/linux/net.h62
-rw-r--r--datapath/linux/compat/include/linux/netdev_features.h77
-rw-r--r--datapath/linux/compat/include/linux/netdevice.h336
-rw-r--r--datapath/linux/compat/include/linux/netfilter.h19
-rw-r--r--datapath/linux/compat/include/linux/netfilter_ipv6.h32
-rw-r--r--datapath/linux/compat/include/linux/netlink.h19
-rw-r--r--datapath/linux/compat/include/linux/openvswitch.h1176
-rw-r--r--datapath/linux/compat/include/linux/overflow.h313
-rw-r--r--datapath/linux/compat/include/linux/percpu.h33
-rw-r--r--datapath/linux/compat/include/linux/random.h17
-rw-r--r--datapath/linux/compat/include/linux/rbtree.h19
-rw-r--r--datapath/linux/compat/include/linux/rculist.h39
-rw-r--r--datapath/linux/compat/include/linux/rcupdate.h41
-rw-r--r--datapath/linux/compat/include/linux/reciprocal_div.h37
-rw-r--r--datapath/linux/compat/include/linux/rtnetlink.h41
-rw-r--r--datapath/linux/compat/include/linux/skbuff.h491
-rw-r--r--datapath/linux/compat/include/linux/static_key.h86
-rw-r--r--datapath/linux/compat/include/linux/stddef.h15
-rw-r--r--datapath/linux/compat/include/linux/timekeeping.h11
-rw-r--r--datapath/linux/compat/include/linux/types.h11
-rw-r--r--datapath/linux/compat/include/linux/u64_stats_sync.h155
-rw-r--r--datapath/linux/compat/include/linux/udp.h33
-rw-r--r--datapath/linux/compat/include/linux/workqueue.h6
-rw-r--r--datapath/linux/compat/include/net/checksum.h39
-rw-r--r--datapath/linux/compat/include/net/dst.h77
-rw-r--r--datapath/linux/compat/include/net/dst_cache.h114
-rw-r--r--datapath/linux/compat/include/net/dst_metadata.h269
-rw-r--r--datapath/linux/compat/include/net/erspan.h342
-rw-r--r--datapath/linux/compat/include/net/genetlink.h136
-rw-r--r--datapath/linux/compat/include/net/geneve.h107
-rw-r--r--datapath/linux/compat/include/net/gre.h191
-rw-r--r--datapath/linux/compat/include/net/inet_ecn.h59
-rw-r--r--datapath/linux/compat/include/net/inet_frag.h83
-rw-r--r--datapath/linux/compat/include/net/inetpeer.h16
-rw-r--r--datapath/linux/compat/include/net/ip.h143
-rw-r--r--datapath/linux/compat/include/net/ip6_fib.h43
-rw-r--r--datapath/linux/compat/include/net/ip6_route.h16
-rw-r--r--datapath/linux/compat/include/net/ip6_tunnel.h208
-rw-r--r--datapath/linux/compat/include/net/ip_tunnels.h513
-rw-r--r--datapath/linux/compat/include/net/ipv6.h88
-rw-r--r--datapath/linux/compat/include/net/ipv6_frag.h8
-rw-r--r--datapath/linux/compat/include/net/lisp.h27
-rw-r--r--datapath/linux/compat/include/net/mpls.h62
-rw-r--r--datapath/linux/compat/include/net/net_namespace.h33
-rw-r--r--datapath/linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h42
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack.h33
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h137
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h54
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_expect.h21
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_helper.h39
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_labels.h107
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h30
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_timeout.h34
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h101
-rw-r--r--datapath/linux/compat/include/net/netfilter/nf_nat.h44
-rw-r--r--datapath/linux/compat/include/net/netlink.h185
-rw-r--r--datapath/linux/compat/include/net/nsh.h313
-rw-r--r--datapath/linux/compat/include/net/protocol.h19
-rw-r--r--datapath/linux/compat/include/net/route.h6
-rw-r--r--datapath/linux/compat/include/net/rtnetlink.h44
-rw-r--r--datapath/linux/compat/include/net/sctp/checksum.h25
-rw-r--r--datapath/linux/compat/include/net/sock.h13
-rw-r--r--datapath/linux/compat/include/net/stt.h70
-rw-r--r--datapath/linux/compat/include/net/tun_proto.h49
-rw-r--r--datapath/linux/compat/include/net/udp.h62
-rw-r--r--datapath/linux/compat/include/net/udp_tunnel.h208
-rw-r--r--datapath/linux/compat/include/net/vrf.h26
-rw-r--r--datapath/linux/compat/include/net/vxlan.h444
-rw-r--r--datapath/linux/compat/include/uapi/linux/netfilter.h14
-rw-r--r--datapath/linux/compat/inet_fragment.c31
-rw-r--r--datapath/linux/compat/ip6_gre.c2746
-rw-r--r--datapath/linux/compat/ip6_output.c470
-rw-r--r--datapath/linux/compat/ip6_tunnel.c2213
-rw-r--r--datapath/linux/compat/ip_fragment.c831
-rw-r--r--datapath/linux/compat/ip_gre.c1450
-rw-r--r--datapath/linux/compat/ip_output.c418
-rw-r--r--datapath/linux/compat/ip_tunnel.c776
-rw-r--r--datapath/linux/compat/ip_tunnels_core.c330
-rw-r--r--datapath/linux/compat/lisp.c816
-rw-r--r--datapath/linux/compat/netdevice.c167
-rw-r--r--datapath/linux/compat/nf_conncount.c621
-rw-r--r--datapath/linux/compat/nf_conntrack_core.c13
-rw-r--r--datapath/linux/compat/nf_conntrack_proto.c114
-rw-r--r--datapath/linux/compat/nf_conntrack_reasm.c740
-rw-r--r--datapath/linux/compat/nf_conntrack_timeout.c102
-rw-r--r--datapath/linux/compat/reciprocal_div.c27
-rw-r--r--datapath/linux/compat/skbuff-openvswitch.c310
-rw-r--r--datapath/linux/compat/socket.c32
-rw-r--r--datapath/linux/compat/stt.c2129
-rw-r--r--datapath/linux/compat/udp.c46
-rw-r--r--datapath/linux/compat/udp_tunnel.c292
-rw-r--r--datapath/linux/compat/utils.c112
-rw-r--r--datapath/linux/compat/vxlan.c2382
126 files changed, 0 insertions, 29293 deletions
diff --git a/datapath/linux/.gitignore b/datapath/linux/.gitignore
deleted file mode 100644
index 8e9d781b1..000000000
--- a/datapath/linux/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-/Kbuild
-/Makefile
-/Makefile.main
-/Module.markers
-/kcompat.h
-/modules.order
-/tmp
-/*.c
diff --git a/datapath/linux/Kbuild.in b/datapath/linux/Kbuild.in
deleted file mode 100644
index 395b0cbc0..000000000
--- a/datapath/linux/Kbuild.in
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- makefile -*-
-export builddir = @abs_builddir@
-export srcdir = @abs_srcdir@
-export top_srcdir = @abs_top_srcdir@
-export VERSION = @VERSION@
-
-include $(srcdir)/../Modules.mk
-include $(srcdir)/Modules.mk
-
-ccflags-y := -DVERSION=\"$(VERSION)\"
-ccflags-y += -I$(srcdir)/..
-ccflags-y += -I$(builddir)/..
-ccflags-y += -g
-ccflags-y += -include $(builddir)/kcompat.h
-
-# These include directories have to go before -I$(KSRC)/include.
-# NOSTDINC_FLAGS just happens to be a variable that goes in the
-# right place, even though it's conceptually incorrect.
-NOSTDINC_FLAGS += -include $(builddir)/kcompat.h -I$(top_srcdir)/include -I$(srcdir)/compat -I$(srcdir)/compat/include
-
-obj-m := $(subst _,-,$(patsubst %,%.o,$(build_modules)))
-
-define module_template
-$(1)-y = $$(notdir $$(patsubst %.c,%.o,$($(1)_sources)))
-endef
-
-$(foreach module,$(build_multi_modules),$(eval $(call module_template,$(module))))
diff --git a/datapath/linux/Makefile.in b/datapath/linux/Makefile.in
deleted file mode 100644
index efc1663e4..000000000
--- a/datapath/linux/Makefile.in
+++ /dev/null
@@ -1,9 +0,0 @@
-ifeq ($(KERNELRELEASE),)
-# We're being called directly by running make in this directory.
-include Makefile.main
-else
-# We're being included by the Linux kernel build system
-include Kbuild
-endif
-
-
diff --git a/datapath/linux/Makefile.main.in b/datapath/linux/Makefile.main.in
deleted file mode 100644
index 6db4aa3ab..000000000
--- a/datapath/linux/Makefile.main.in
+++ /dev/null
@@ -1,107 +0,0 @@
-# -*- makefile -*-
-export builddir = @abs_builddir@
-export srcdir = @abs_srcdir@
-export top_srcdir = @abs_top_srcdir@
-export KSRC = @KBUILD@
-export VERSION = @VERSION@
-
-include $(srcdir)/../Modules.mk
-include $(srcdir)/Modules.mk
-
-default: $(build_links)
-
-$(foreach s,$(sort $(foreach m,$(build_modules),$($(m)_sources))), \
- $(eval $(notdir $(s)): ; ln -s $(srcdir)/../$(s) $@))
-
-all: default
-distdir: clean
-install:
-install-data:
-install-exec:
-uninstall:
-install-dvi:
-install-html:
-install-info:
-install-ps:
-install-pdf:
-installdirs:
-check: all
-installcheck:
-mostlyclean:
-clean:
- rm -f *.o *.ko *.mod.* .*.gcno .*.d .*.cmd kcompat.h.new \
- .cache.mk Module.symvers modules.order .tmp_versions/*.mod
- for d in $(build_links); do if test -h $$d; then rm $$d; fi; done
-distclean: clean
- rm -f kcompat.h
-maintainer-clean: distclean
-dvi:
-pdf:
-ps:
-info:
-html:
-tags:
-TAGS:
-
-ifneq ($(KSRC),)
-
-ifeq (/lib/modules/$(shell uname -r)/source, $(KSRC))
- KOBJ := /lib/modules/$(shell uname -r)/build
-else
- KOBJ := $(KSRC)
-endif
-
-VERSION_FILE := $(KOBJ)/include/linux/version.h
-ifeq (,$(wildcard $(VERSION_FILE)))
- VERSION_FILE := $(KOBJ)/include/generated/uapi/linux/version.h
- ifeq (,$(wildcard $(VERSION_FILE)))
- $(error Linux kernel source not configured - missing version.h)
- endif
-endif
-
-CONFIG_FILE := $(KSRC)/include/generated/autoconf.h
-ifeq (,$(wildcard $(CONFIG_FILE)))
- CONFIG_FILE := $(KSRC)/include/linux/autoconf.h
- ifeq (,$(wildcard $(CONFIG_FILE)))
- $(error Linux kernel source not configured - missing autoconf.h)
- endif
-endif
-
-default:
- $(MAKE) -C $(KSRC) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules
-
-modules_install:
- $(MAKE) -C $(KSRC) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules_install
- /sbin/depmod `sed -n 's/#define UTS_RELEASE "\([^"]*\)"/\1/p' $(KSRC)/include/generated/utsrelease.h`
-endif
-
-# Much of the kernel build system in this file is derived from Intel's
-# e1000 distribution, with the following license:
-
-################################################################################
-#
-# Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2007, 2009 Intel Corporation.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms and conditions of the GNU General Public License,
-# version 2, as published by the Free Software Foundation.
-#
-# This program is distributed in the hope it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-# more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# The full GNU General Public License is included in this distribution in
-# the file called "COPYING".
-#
-# Contact Information:
-# Linux NICS <linux.nics@intel.com>
-# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-#
-################################################################################
diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
deleted file mode 100644
index 372243988..000000000
--- a/datapath/linux/Modules.mk
+++ /dev/null
@@ -1,123 +0,0 @@
-openvswitch_sources += \
- linux/compat/dev-openvswitch.c \
- linux/compat/dst_cache.c \
- linux/compat/exthdrs_core.c \
- linux/compat/geneve.c \
- linux/compat/gre.c \
- linux/compat/gso.c \
- linux/compat/genetlink-openvswitch.c \
- linux/compat/inet_fragment.c \
- linux/compat/ip_gre.c \
- linux/compat/ip_fragment.c \
- linux/compat/ip_output.c \
- linux/compat/ip_tunnel.c \
- linux/compat/ip_tunnels_core.c \
- linux/compat/ip6_output.c \
- linux/compat/ip6_gre.c \
- linux/compat/ip6_tunnel.c \
- linux/compat/lisp.c \
- linux/compat/netdevice.c \
- linux/compat/nf_conncount.c \
- linux/compat/nf_conntrack_core.c \
- linux/compat/nf_conntrack_proto.c \
- linux/compat/nf_conntrack_reasm.c \
- linux/compat/nf_conntrack_timeout.c \
- linux/compat/reciprocal_div.c \
- linux/compat/skbuff-openvswitch.c \
- linux/compat/socket.c \
- linux/compat/stt.c \
- linux/compat/udp.c \
- linux/compat/udp_tunnel.c \
- linux/compat/vxlan.c \
- linux/compat/utils.c
-openvswitch_headers += \
- linux/compat/gso.h \
- linux/compat/include/linux/percpu.h \
- linux/compat/include/linux/bug.h \
- linux/compat/include/linux/cache.h \
- linux/compat/include/linux/compiler.h \
- linux/compat/include/linux/compiler-gcc.h \
- linux/compat/include/linux/cpumask.h \
- linux/compat/include/linux/err.h \
- linux/compat/include/linux/etherdevice.h \
- linux/compat/include/linux/genetlink.h \
- linux/compat/include/linux/if.h \
- linux/compat/include/linux/if_ether.h \
- linux/compat/include/linux/if_link.h \
- linux/compat/include/linux/if_vlan.h \
- linux/compat/include/linux/in.h \
- linux/compat/include/linux/jiffies.h \
- linux/compat/include/linux/kconfig.h \
- linux/compat/include/linux/kernel.h \
- linux/compat/include/net/lisp.h \
- linux/compat/include/linux/list.h \
- linux/compat/include/linux/mpls.h \
- linux/compat/include/linux/net.h \
- linux/compat/include/linux/random.h \
- linux/compat/include/linux/netdevice.h \
- linux/compat/include/linux/netdev_features.h \
- linux/compat/include/linux/netfilter_ipv6.h \
- linux/compat/include/linux/netlink.h \
- linux/compat/include/linux/openvswitch.h \
- linux/compat/include/linux/rculist.h \
- linux/compat/include/linux/rcupdate.h \
- linux/compat/include/linux/reciprocal_div.h \
- linux/compat/include/linux/rtnetlink.h \
- linux/compat/include/linux/skbuff.h \
- linux/compat/include/linux/static_key.h \
- linux/compat/include/linux/stddef.h \
- linux/compat/include/linux/types.h \
- linux/compat/include/linux/u64_stats_sync.h \
- linux/compat/include/linux/udp.h \
- linux/compat/include/linux/workqueue.h \
- linux/compat/include/linux/timekeeping.h \
- linux/compat/include/net/checksum.h \
- linux/compat/include/net/dst.h \
- linux/compat/include/net/dst_cache.h \
- linux/compat/include/net/dst_metadata.h \
- linux/compat/include/net/genetlink.h \
- linux/compat/include/net/geneve.h \
- linux/compat/include/net/gre.h \
- linux/compat/include/net/inet_ecn.h \
- linux/compat/include/net/inet_frag.h \
- linux/compat/include/net/inetpeer.h \
- linux/compat/include/net/ip.h \
- linux/compat/include/net/ip_tunnels.h \
- linux/compat/include/net/ip6_fib.h \
- linux/compat/include/net/ip6_route.h \
- linux/compat/include/net/ip6_tunnel.h \
- linux/compat/include/net/ipv6.h \
- linux/compat/include/net/ipv6_frag.h \
- linux/compat/include/net/mpls.h \
- linux/compat/include/net/net_namespace.h \
- linux/compat/include/net/netlink.h \
- linux/compat/include/net/protocol.h \
- linux/compat/include/net/route.h \
- linux/compat/include/net/rtnetlink.h \
- linux/compat/include/net/udp.h \
- linux/compat/include/net/udp_tunnel.h \
- linux/compat/include/net/sock.h \
- linux/compat/include/net/stt.h \
- linux/compat/include/net/vrf.h \
- linux/compat/include/net/tun_proto.h \
- linux/compat/include/net/nsh.h \
- linux/compat/include/net/vxlan.h \
- linux/compat/include/net/netfilter/nf_conntrack.h \
- linux/compat/include/net/netfilter/nf_conntrack_core.h \
- linux/compat/include/net/netfilter/nf_conntrack_count.h \
- linux/compat/include/net/netfilter/nf_conntrack_expect.h \
- linux/compat/include/net/netfilter/nf_conntrack_helper.h \
- linux/compat/include/net/netfilter/nf_conntrack_labels.h \
- linux/compat/include/net/netfilter/nf_conntrack_seqadj.h \
- linux/compat/include/net/netfilter/nf_conntrack_timeout.h \
- linux/compat/include/net/netfilter/nf_conntrack_zones.h \
- linux/compat/include/net/netfilter/nf_nat.h \
- linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h \
- linux/compat/include/net/sctp/checksum.h \
- linux/compat/include/net/erspan.h \
- linux/compat/include/uapi/linux/netfilter.h \
- linux/compat/include/linux/mm.h \
- linux/compat/include/linux/netfilter.h \
- linux/compat/include/linux/overflow.h \
- linux/compat/include/linux/rbtree.h
-EXTRA_DIST += linux/compat/build-aux/export-check-allow-list
diff --git a/datapath/linux/compat/build-aux/export-check-allow-list b/datapath/linux/compat/build-aux/export-check-allow-list
deleted file mode 100644
index 1178f46ee..000000000
--- a/datapath/linux/compat/build-aux/export-check-allow-list
+++ /dev/null
@@ -1 +0,0 @@
-pskb_expand_head \ No newline at end of file
diff --git a/datapath/linux/compat/dev-openvswitch.c b/datapath/linux/compat/dev-openvswitch.c
deleted file mode 100644
index 56e1a5b68..000000000
--- a/datapath/linux/compat/dev-openvswitch.c
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <linux/if_bridge.h>
-#include <linux/netdevice.h>
-#include <linux/version.h>
-#include <net/rtnetlink.h>
-
-#include "gso.h"
-#include "vport.h"
-#include "vport-internal_dev.h"
-#include "vport-netdev.h"
-
-#ifndef HAVE_DEV_DISABLE_LRO
-
-#ifdef NETIF_F_LRO
-#include <linux/ethtool.h>
-
-/**
- * dev_disable_lro - disable Large Receive Offload on a device
- * @dev: device
- *
- * Disable Large Receive Offload (LRO) on a net device. Must be
- * called under RTNL. This is needed if received packets may be
- * forwarded to another interface.
- */
-void dev_disable_lro(struct net_device *dev)
-{
- if (dev->ethtool_ops && dev->ethtool_ops->get_flags &&
- dev->ethtool_ops->set_flags) {
- u32 flags = dev->ethtool_ops->get_flags(dev);
- if (flags & ETH_FLAG_LRO) {
- flags &= ~ETH_FLAG_LRO;
- dev->ethtool_ops->set_flags(dev, flags);
- }
- }
- WARN_ON(dev->features & NETIF_F_LRO);
-}
-#else
-void dev_disable_lro(struct net_device *dev) { }
-#endif /* NETIF_F_LRO */
-
-#endif /* HAVE_DEV_DISABLE_LRO */
-
-int rpl_rtnl_delete_link(struct net_device *dev)
-{
- const struct rtnl_link_ops *ops;
- LIST_HEAD(list_kill);
-
- ops = dev->rtnl_link_ops;
- if (!ops || !ops->dellink)
- return -EOPNOTSUPP;
-
- ops->dellink(dev, &list_kill);
- unregister_netdevice_many(&list_kill);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_rtnl_delete_link);
-
-#ifndef USE_UPSTREAM_TUNNEL
-int ovs_dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
-{
- struct ip_tunnel_info *info;
- struct vport *vport;
-
- if (!SKB_SETUP_FILL_METADATA_DST(skb))
- return -ENOMEM;
-
- vport = ovs_netdev_get_vport(dev);
- if (!vport)
- return -EINVAL;
-
- if (!vport->ops->fill_metadata_dst)
- return -EINVAL;
-
- info = skb_tunnel_info(skb);
- if (!info)
- return -ENOMEM;
- if (unlikely(!(info->mode & IP_TUNNEL_INFO_TX)))
- return -EINVAL;
-
- return vport->ops->fill_metadata_dst(dev, skb);
-}
-EXPORT_SYMBOL_GPL(ovs_dev_fill_metadata_dst);
-#endif
diff --git a/datapath/linux/compat/dst_cache.c b/datapath/linux/compat/dst_cache.c
deleted file mode 100644
index 45990cba7..000000000
--- a/datapath/linux/compat/dst_cache.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * net/core/dst_cache.c - dst entry cache
- *
- * Copyright (c) 2016 Paolo Abeni <pabeni@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef USE_BUILTIN_DST_CACHE
-#include <linux/kernel.h>
-#include <linux/percpu.h>
-#include <net/dst_cache.h>
-#include <net/route.h>
-#if IS_ENABLED(CONFIG_IPV6)
-#include <net/ip6_fib.h>
-#endif
-#include <uapi/linux/in.h>
-
-#ifndef USE_UPSTREAM_TUNNEL
-struct dst_cache_pcpu {
- unsigned long refresh_ts;
- struct dst_entry *dst;
- u32 cookie;
- union {
- struct in_addr in_saddr;
- struct in6_addr in6_saddr;
- };
-};
-
-static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
- struct dst_entry *dst, u32 cookie)
-{
- dst_release(dst_cache->dst);
- if (dst)
- dst_hold(dst);
-
- dst_cache->cookie = cookie;
- dst_cache->dst = dst;
-}
-
-static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
- struct dst_cache_pcpu *idst)
-{
- struct dst_entry *dst;
-
- dst = idst->dst;
- if (!dst)
- goto fail;
-
- /* the cache already hold a dst reference; it can't go away */
- dst_hold(dst);
-
- if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) ||
- (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) {
- dst_cache_per_cpu_dst_set(idst, NULL, 0);
- dst_release(dst);
- goto fail;
- }
- return dst;
-
-fail:
- idst->refresh_ts = jiffies;
- return NULL;
-}
-
-struct dst_entry *rpl_dst_cache_get(struct dst_cache *dst_cache)
-{
- if (!dst_cache->cache)
- return NULL;
-
- return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache));
-}
-EXPORT_SYMBOL_GPL(rpl_dst_cache_get);
-
-struct rtable *rpl_dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr)
-{
- struct dst_cache_pcpu *idst;
- struct dst_entry *dst;
-
- if (!dst_cache->cache)
- return NULL;
-
- idst = this_cpu_ptr(dst_cache->cache);
- dst = dst_cache_per_cpu_get(dst_cache, idst);
- if (!dst)
- return NULL;
-
- *saddr = idst->in_saddr.s_addr;
- return container_of(dst, struct rtable, dst);
-}
-EXPORT_SYMBOL_GPL(rpl_dst_cache_get_ip4);
-
-void rpl_dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
- __be32 saddr)
-{
- struct dst_cache_pcpu *idst;
-
- if (!dst_cache->cache)
- return;
-
- idst = this_cpu_ptr(dst_cache->cache);
- dst_cache_per_cpu_dst_set(idst, dst, 0);
- idst->in_saddr.s_addr = saddr;
-}
-EXPORT_SYMBOL_GPL(rpl_dst_cache_set_ip4);
-
-#if IS_ENABLED(CONFIG_IPV6)
-void rpl_dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
- const struct in6_addr *addr)
-{
- struct dst_cache_pcpu *idst;
-
- if (!dst_cache->cache)
- return;
-
- idst = this_cpu_ptr(dst_cache->cache);
- dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst,
- rt6_get_cookie((struct rt6_info *)dst));
- idst->in6_saddr = *addr;
-}
-EXPORT_SYMBOL_GPL(rpl_dst_cache_set_ip6);
-
-struct dst_entry *rpl_dst_cache_get_ip6(struct dst_cache *dst_cache,
- struct in6_addr *saddr)
-{
- struct dst_cache_pcpu *idst;
- struct dst_entry *dst;
-
- if (!dst_cache->cache)
- return NULL;
-
- idst = this_cpu_ptr(dst_cache->cache);
- dst = dst_cache_per_cpu_get(dst_cache, idst);
- if (!dst)
- return NULL;
-
- *saddr = idst->in6_saddr;
- return dst;
-}
-EXPORT_SYMBOL_GPL(rpl_dst_cache_get_ip6);
-
-#endif
-
-int rpl_dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp)
-{
- dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu,
- gfp | __GFP_ZERO);
- if (!dst_cache->cache)
- return -ENOMEM;
-
- dst_cache_reset(dst_cache);
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_dst_cache_init);
-
-void rpl_dst_cache_destroy(struct dst_cache *dst_cache)
-{
- int i;
-
- if (!dst_cache->cache)
- return;
-
- for_each_possible_cpu(i)
- dst_release(per_cpu_ptr(dst_cache->cache, i)->dst);
-
- free_percpu(dst_cache->cache);
-}
-EXPORT_SYMBOL_GPL(rpl_dst_cache_destroy);
-#endif /*USE_UPSTREAM_TUNNEL */
-#endif /* USE_BUILTIN_DST_CACHE */
diff --git a/datapath/linux/compat/exthdrs_core.c b/datapath/linux/compat/exthdrs_core.c
deleted file mode 100644
index 697f9d082..000000000
--- a/datapath/linux/compat/exthdrs_core.c
+++ /dev/null
@@ -1,129 +0,0 @@
-#include <linux/ipv6.h>
-#include <linux/version.h>
-#include <net/ipv6.h>
-
-#ifndef HAVE_IP6_FH_F_SKIP_RH
-/*
- * find the offset to specified header or the protocol number of last header
- * if target < 0. "last header" is transport protocol header, ESP, or
- * "No next header".
- *
- * Note that *offset is used as input/output parameter. an if it is not zero,
- * then it must be a valid offset to an inner IPv6 header. This can be used
- * to explore inner IPv6 header, eg. ICMPv6 error messages.
- *
- * If target header is found, its offset is set in *offset and return protocol
- * number. Otherwise, return -1.
- *
- * If the first fragment doesn't contain the final protocol header or
- * NEXTHDR_NONE it is considered invalid.
- *
- * Note that non-1st fragment is special case that "the protocol number
- * of last header" is "next header" field in Fragment header. In this case,
- * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
- * isn't NULL.
- *
- * if flags is not NULL and it's a fragment, then the frag flag
- * IP6_FH_F_FRAG will be set. If it's an AH header, the
- * IP6_FH_F_AUTH flag is set and target < 0, then this function will
- * stop at the AH header. If IP6_FH_F_SKIP_RH flag was passed, then this
- * function will skip all those routing headers, where segements_left was 0.
- */
-int rpl_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
- int target, unsigned short *fragoff, int *flags)
-{
- unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
- u8 nexthdr = ipv6_hdr(skb)->nexthdr;
- unsigned int len;
- bool found;
-
- if (fragoff)
- *fragoff = 0;
-
- if (*offset) {
- struct ipv6hdr _ip6, *ip6;
-
- ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6);
- if (!ip6 || (ip6->version != 6)) {
- printk(KERN_ERR "IPv6 header not found\n");
- return -EBADMSG;
- }
- start = *offset + sizeof(struct ipv6hdr);
- nexthdr = ip6->nexthdr;
- }
- len = skb->len - start;
-
- do {
- struct ipv6_opt_hdr _hdr, *hp;
- unsigned int hdrlen;
- found = (nexthdr == target);
-
- if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
- if (target < 0 || found)
- break;
- return -ENOENT;
- }
-
- hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
- if (hp == NULL)
- return -EBADMSG;
-
- if (nexthdr == NEXTHDR_ROUTING) {
- struct ipv6_rt_hdr _rh, *rh;
-
- rh = skb_header_pointer(skb, start, sizeof(_rh),
- &_rh);
- if (rh == NULL)
- return -EBADMSG;
-
- if (flags && (*flags & IP6_FH_F_SKIP_RH) &&
- rh->segments_left == 0)
- found = false;
- }
-
- if (nexthdr == NEXTHDR_FRAGMENT) {
- unsigned short _frag_off;
- __be16 *fp;
-
- if (flags) /* Indicate that this is a fragment */
- *flags |= IP6_FH_F_FRAG;
- fp = skb_header_pointer(skb,
- start+offsetof(struct frag_hdr,
- frag_off),
- sizeof(_frag_off),
- &_frag_off);
- if (fp == NULL)
- return -EBADMSG;
-
- _frag_off = ntohs(*fp) & ~0x7;
- if (_frag_off) {
- if (target < 0 &&
- ((!ipv6_ext_hdr(hp->nexthdr)) ||
- hp->nexthdr == NEXTHDR_NONE)) {
- if (fragoff)
- *fragoff = _frag_off;
- return hp->nexthdr;
- }
- return -ENOENT;
- }
- hdrlen = 8;
- } else if (nexthdr == NEXTHDR_AUTH) {
- if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0))
- break;
- hdrlen = (hp->hdrlen + 2) << 2;
- } else
- hdrlen = ipv6_optlen(hp);
-
- if (!found) {
- nexthdr = hp->nexthdr;
- len -= hdrlen;
- start += hdrlen;
- }
- } while (!found);
-
- *offset = start;
- return nexthdr;
-}
-EXPORT_SYMBOL_GPL(rpl_ipv6_find_hdr);
-
-#endif
diff --git a/datapath/linux/compat/genetlink-openvswitch.c b/datapath/linux/compat/genetlink-openvswitch.c
deleted file mode 100644
index 5b0ecfa8d..000000000
--- a/datapath/linux/compat/genetlink-openvswitch.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <net/genetlink.h>
-#include <linux/version.h>
-
-#ifndef HAVE_GENL_NOTIFY_TAKES_FAMILY
-int rpl___genl_register_family(struct rpl_genl_family *f)
-{
- int err;
-
- f->compat_family.id = f->id;
- f->compat_family.hdrsize = f->hdrsize;
- strncpy(f->compat_family.name, f->name, GENL_NAMSIZ);
- f->compat_family.version = f->version;
- f->compat_family.maxattr = f->maxattr;
- f->compat_family.netnsok = f->netnsok;
-#ifdef HAVE_PARALLEL_OPS
- f->compat_family.parallel_ops = f->parallel_ops;
-#endif
- err = genl_register_family_with_ops(&f->compat_family,
- (struct genl_ops *) f->ops, f->n_ops);
- if (err)
- goto error;
-
- if (f->mcgrps) {
- /* Need to Fix GROUP_ID() for more than one group. */
- BUG_ON(f->n_mcgrps > 1);
- err = genl_register_mc_group(&f->compat_family,
- (struct genl_multicast_group *) f->mcgrps);
- if (err)
- goto error;
- }
-error:
- return err;
-
-}
-EXPORT_SYMBOL_GPL(rpl___genl_register_family);
-#endif /* HAVE_GENL_NOTIFY_TAKES_FAMILY */
-
-#ifdef HAVE_GENL_NOTIFY_TAKES_NET
-
-#undef genl_notify
-
-void rpl_genl_notify(struct genl_family *family, struct sk_buff *skb,
- struct genl_info *info, u32 group, gfp_t flags)
-{
- struct net *net = genl_info_net(info);
- u32 portid = info->snd_portid;
- struct nlmsghdr *nlh = info->nlhdr;
-
-#ifdef HAVE_GENL_NOTIFY_TAKES_FAMILY
- genl_notify(family, skb, net, portid, group, nlh, flags);
-#else
- genl_notify(skb, net, portid, group, nlh, flags);
-#endif
-}
-#endif /* HAVE_GENL_NOTIFY_TAKES_NET */
diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c
deleted file mode 100644
index 02c6403e6..000000000
--- a/datapath/linux/compat/geneve.c
+++ /dev/null
@@ -1,1854 +0,0 @@
-/*
- * GENEVE: Generic Network Virtualization Encapsulation
- *
- * Copyright (c) 2015 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/hash.h>
-#include <linux/if_link.h>
-#include <linux/if_vlan.h>
-
-#include <net/addrconf.h>
-#include <net/dst_cache.h>
-#include <net/dst_metadata.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/rtnetlink.h>
-#include <net/geneve.h>
-#include <net/protocol.h>
-#include <net/udp_tunnel.h>
-#include <net/ip6_route.h>
-#if IS_ENABLED(CONFIG_IPV6)
-#include <net/ipv6.h>
-#include <net/addrconf.h>
-#include <net/ip6_tunnel.h>
-#include <net/ip6_checksum.h>
-#endif
-
-
-#include "gso.h"
-#include "vport-netdev.h"
-#include "compat.h"
-
-#ifndef USE_UPSTREAM_TUNNEL
-
-#define GENEVE_NETDEV_VER "0.6"
-
-#define GENEVE_UDP_PORT 6081
-
-#define GENEVE_N_VID (1u << 24)
-#define GENEVE_VID_MASK (GENEVE_N_VID - 1)
-
-#define VNI_HASH_BITS 10
-#define VNI_HASH_SIZE (1<<VNI_HASH_BITS)
-
-#define GENEVE_VER 0
-#define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr))
-
-/* per-network namespace private data for this module */
-struct geneve_net {
- struct list_head geneve_list;
- struct list_head sock_list;
-};
-
-static int geneve_net_id;
-
-union geneve_addr {
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
- struct sockaddr sa;
-};
-
-static union geneve_addr geneve_remote_unspec = { .sa.sa_family = AF_UNSPEC, };
-
-/* Pseudo network device */
-struct geneve_dev {
- struct hlist_node hlist; /* vni hash table */
- struct net *net; /* netns for packet i/o */
- struct net_device *dev; /* netdev for geneve tunnel */
- struct geneve_sock __rcu *sock4; /* IPv4 socket used for geneve tunnel */
-#if IS_ENABLED(CONFIG_IPV6)
- struct geneve_sock __rcu *sock6; /* IPv6 socket used for geneve tunnel */
-#endif
- u8 vni[3]; /* virtual network ID for tunnel */
- u8 ttl; /* TTL override */
- u8 tos; /* TOS override */
- union geneve_addr remote; /* IP address for link partner */
- struct list_head next; /* geneve's per namespace list */
- __be32 label; /* IPv6 flowlabel override */
- __be16 dst_port;
- bool collect_md;
- u32 flags;
- struct dst_cache dst_cache;
-};
-
-/* Geneve device flags */
-#define GENEVE_F_UDP_ZERO_CSUM_TX BIT(0)
-#define GENEVE_F_UDP_ZERO_CSUM6_TX BIT(1)
-#define GENEVE_F_UDP_ZERO_CSUM6_RX BIT(2)
-
-struct geneve_sock {
- bool collect_md;
- struct list_head list;
- struct socket *sock;
- struct rcu_head rcu;
- int refcnt;
- struct hlist_head vni_list[VNI_HASH_SIZE];
- u32 flags;
-#ifdef HAVE_UDP_OFFLOAD
- struct udp_offload udp_offloads;
-#endif
-};
-
-static inline __u32 geneve_net_vni_hash(u8 vni[3])
-{
- __u32 vnid;
-
- vnid = (vni[0] << 16) | (vni[1] << 8) | vni[2];
- return hash_32(vnid, VNI_HASH_BITS);
-}
-
-static __be64 vni_to_tunnel_id(const __u8 *vni)
-{
-#ifdef __BIG_ENDIAN
- return (vni[0] << 16) | (vni[1] << 8) | vni[2];
-#else
- return (__force __be64)(((__force u64)vni[0] << 40) |
- ((__force u64)vni[1] << 48) |
- ((__force u64)vni[2] << 56));
-#endif
-}
-
-static sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
-{
- return gs->sock->sk->sk_family;
-}
-
-static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
- __be32 addr, u8 vni[])
-{
- struct hlist_head *vni_list_head;
- struct geneve_dev *geneve;
- __u32 hash;
-
- /* Find the device for this VNI */
- hash = geneve_net_vni_hash(vni);
- vni_list_head = &gs->vni_list[hash];
- hlist_for_each_entry_rcu(geneve, vni_list_head, hlist) {
- if (!memcmp(vni, geneve->vni, sizeof(geneve->vni)) &&
- addr == geneve->remote.sin.sin_addr.s_addr)
- return geneve;
- }
- return NULL;
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static struct geneve_dev *geneve6_lookup(struct geneve_sock *gs,
- struct in6_addr addr6, u8 vni[])
-{
- struct hlist_head *vni_list_head;
- struct geneve_dev *geneve;
- __u32 hash;
-
- /* Find the device for this VNI */
- hash = geneve_net_vni_hash(vni);
- vni_list_head = &gs->vni_list[hash];
- hlist_for_each_entry_rcu(geneve, vni_list_head, hlist) {
- if (!memcmp(vni, geneve->vni, sizeof(geneve->vni)) &&
- ipv6_addr_equal(&addr6, &geneve->remote.sin6.sin6_addr))
- return geneve;
- }
- return NULL;
-}
-#endif
-
-static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
-{
- return (struct genevehdr *)(udp_hdr(skb) + 1);
-}
-
-static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
- struct sk_buff *skb)
-{
- u8 *vni;
- __be32 addr;
- static u8 zero_vni[3];
-#if IS_ENABLED(CONFIG_IPV6)
- static struct in6_addr zero_addr6;
-#endif
-
- if (geneve_get_sk_family(gs) == AF_INET) {
- struct iphdr *iph;
-
- iph = ip_hdr(skb); /* outer IP header... */
-
- if (gs->collect_md) {
- vni = zero_vni;
- addr = 0;
- } else {
- vni = geneve_hdr(skb)->vni;
- addr = iph->saddr;
- }
-
- return geneve_lookup(gs, addr, vni);
-#if IS_ENABLED(CONFIG_IPV6)
- } else if (geneve_get_sk_family(gs) == AF_INET6) {
- struct ipv6hdr *ip6h;
- struct in6_addr addr6;
-
- ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
-
- if (gs->collect_md) {
- vni = zero_vni;
- addr6 = zero_addr6;
- } else {
- vni = geneve_hdr(skb)->vni;
- addr6 = ip6h->saddr;
- }
-
- return geneve6_lookup(gs, addr6, vni);
-#endif
- }
- return NULL;
-}
-
-/* geneve receive/decap routine */
-static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
- struct sk_buff *skb)
-{
- struct genevehdr *gnvh = geneve_hdr(skb);
- struct metadata_dst *tun_dst = NULL;
- struct pcpu_sw_netstats *stats;
- int err = 0;
- void *oiph;
- union {
- struct metadata_dst dst;
- char buf[sizeof(struct metadata_dst) + 256];
- } buf;
-
- if (ip_tunnel_collect_metadata() || gs->collect_md) {
- __be16 flags;
-
- flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT |
- (gnvh->oam ? TUNNEL_OAM : 0) |
- (gnvh->critical ? TUNNEL_CRIT_OPT : 0);
-
- tun_dst = &buf.dst;
- ovs_udp_tun_rx_dst(tun_dst,
- skb, geneve_get_sk_family(gs), flags,
- vni_to_tunnel_id(gnvh->vni),
- gnvh->opt_len * 4);
- if (!tun_dst)
- goto drop;
- /* Update tunnel dst according to Geneve options. */
- ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
- gnvh->options, gnvh->opt_len * 4,
- TUNNEL_GENEVE_OPT);
- } else {
- /* Drop packets w/ critical options,
- * since we don't support any...
- */
- if (gnvh->critical)
- goto drop;
- }
-
- skb_reset_mac_header(skb);
- skb->protocol = eth_type_trans(skb, geneve->dev);
- skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
-
- if (tun_dst)
- ovs_skb_dst_set(skb, &tun_dst->dst);
-
- /* Ignore packet loops (and multicast echo) */
- if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr))
- goto drop;
-
- oiph = skb_network_header(skb);
- skb_reset_network_header(skb);
-
- if (geneve_get_sk_family(gs) == AF_INET)
- err = IP_ECN_decapsulate(oiph, skb);
-#if IS_ENABLED(CONFIG_IPV6)
- else
- err = IP6_ECN_decapsulate(oiph, skb);
-#endif
- if (unlikely(err > 1)) {
- ++geneve->dev->stats.rx_frame_errors;
- ++geneve->dev->stats.rx_errors;
- goto drop;
- }
-
- stats = this_cpu_ptr(geneve->dev->tstats);
- u64_stats_update_begin(&stats->syncp);
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
- u64_stats_update_end(&stats->syncp);
-
- netdev_port_receive(skb, skb_tunnel_info(skb));
- return;
-drop:
- /* Consume bad packet */
- kfree_skb(skb);
-}
-
-/* Setup stats when device is created */
-static int geneve_init(struct net_device *dev)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
- int err;
-
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- err = dst_cache_init(&geneve->dst_cache, GFP_KERNEL);
- if (err) {
- free_percpu(dev->tstats);
- return err;
- }
-
- return 0;
-}
-
-static void geneve_uninit(struct net_device *dev)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
-
- dst_cache_destroy(&geneve->dst_cache);
- free_percpu(dev->tstats);
-}
-
-/* Callback from net/ipv4/udp.c to receive packets */
-static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
-{
- struct genevehdr *geneveh;
- struct geneve_dev *geneve;
- struct geneve_sock *gs;
- int opts_len;
-
- /* Need Geneve and inner Ethernet header to be present */
- if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
- goto drop;
-
- /* Return packets with reserved bits set */
- geneveh = geneve_hdr(skb);
- if (unlikely(geneveh->ver != GENEVE_VER))
- goto drop;
-
- if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
- goto drop;
-
- gs = rcu_dereference_sk_user_data(sk);
- if (!gs)
- goto drop;
-
-#if IS_ENABLED(CONFIG_IPV6)
-#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
- if (geneve_get_sk_family(gs) == AF_INET6 &&
- !udp_hdr(skb)->check &&
- !(gs->flags & GENEVE_F_UDP_ZERO_CSUM6_RX)) {
- udp6_csum_zero_error(skb);
- goto drop;
- }
-#endif
-#endif
- geneve = geneve_lookup_skb(gs, skb);
- if (!geneve)
- goto drop;
-
- opts_len = geneveh->opt_len * 4;
- if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
- htons(ETH_P_TEB),
- !net_eq(geneve->net, dev_net(geneve->dev))))
- goto drop;
-
- geneve_rx(geneve, gs, skb);
- return 0;
-
-drop:
- /* Consume bad packet */
- kfree_skb(skb);
- return 0;
-}
-
-static struct socket *geneve_create_sock(struct net *net, bool ipv6,
- __be16 port, u32 flags)
-{
- struct socket *sock;
- struct udp_port_cfg udp_conf;
- int err;
-
- memset(&udp_conf, 0, sizeof(udp_conf));
-
- if (ipv6) {
- udp_conf.family = AF_INET6;
- udp_conf.ipv6_v6only = 1;
- udp_conf.use_udp6_rx_checksums =
- !(flags & GENEVE_F_UDP_ZERO_CSUM6_RX);
- } else {
- udp_conf.family = AF_INET;
- udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
- }
-
- 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;
-}
-
-static void geneve_notify_add_rx_port(struct geneve_sock *gs)
-{
- struct net_device *dev;
- struct sock *sk = gs->sock->sk;
- struct net *net = sock_net(sk);
- sa_family_t sa_family = geneve_get_sk_family(gs);
- int err;
-
- if (sa_family == AF_INET) {
- err = udp_add_offload(sock_net(sk), &gs->udp_offloads);
- if (err)
- pr_warn("geneve: udp_add_offload failed with status %d\n",
- err);
- }
-
- rcu_read_lock();
- for_each_netdev_rcu(net, dev) {
-#ifdef HAVE_NDO_ADD_GENEVE_PORT
- __be16 port = inet_sk(sk)->inet_sport;
-
- if (dev->netdev_ops->ndo_add_geneve_port)
- dev->netdev_ops->ndo_add_geneve_port(dev, sa_family,
- port);
-#elif defined(HAVE_NDO_UDP_TUNNEL_ADD)
- struct udp_tunnel_info ti;
- ti.type = UDP_TUNNEL_TYPE_GENEVE;
- ti.sa_family = sa_family;
- ti.port = inet_sk(sk)->inet_sport;
-
- if (dev->netdev_ops->ndo_udp_tunnel_add)
- dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti);
-#endif
- }
- rcu_read_unlock();
-}
-
-static void geneve_notify_del_rx_port(struct geneve_sock *gs)
-{
- struct net_device *dev;
- struct sock *sk = gs->sock->sk;
- struct net *net = sock_net(sk);
- sa_family_t sa_family = geneve_get_sk_family(gs);
-
- rcu_read_lock();
- for_each_netdev_rcu(net, dev) {
-#ifdef HAVE_NDO_ADD_GENEVE_PORT
- __be16 port = inet_sk(sk)->inet_sport;
-
- if (dev->netdev_ops->ndo_del_geneve_port)
- dev->netdev_ops->ndo_del_geneve_port(dev, sa_family,
- port);
-#elif defined(HAVE_NDO_UDP_TUNNEL_ADD)
- struct udp_tunnel_info ti;
- ti.type = UDP_TUNNEL_TYPE_GENEVE;
- ti.port = inet_sk(sk)->inet_sport;
- ti.sa_family = sa_family;
-
- if (dev->netdev_ops->ndo_udp_tunnel_del)
- dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti);
-#endif
- }
-
- rcu_read_unlock();
-
- if (sa_family == AF_INET)
- udp_del_offload(&gs->udp_offloads);
-}
-
-#if defined(HAVE_UDP_OFFLOAD) || \
- defined(HAVE_UDP_TUNNEL_SOCK_CFG_GRO_RECEIVE)
-
-static int geneve_hlen(struct genevehdr *gh)
-{
- return sizeof(*gh) + gh->opt_len * 4;
-}
-
-#ifndef HAVE_UDP_OFFLOAD_ARG_UOFF
-static struct sk_buff **geneve_gro_receive(struct sk_buff **head,
- struct sk_buff *skb)
-#else
-static struct sk_buff **geneve_gro_receive(struct sk_buff **head,
- struct sk_buff *skb,
- struct udp_offload *uoff)
-#endif
-{
- struct sk_buff *p, **pp = NULL;
- struct genevehdr *gh, *gh2;
- unsigned int hlen, gh_len, off_gnv;
- const struct packet_offload *ptype;
- __be16 type;
- int flush = 1;
-
- off_gnv = skb_gro_offset(skb);
- hlen = off_gnv + sizeof(*gh);
- gh = skb_gro_header_fast(skb, off_gnv);
- if (skb_gro_header_hard(skb, hlen)) {
- gh = skb_gro_header_slow(skb, hlen, off_gnv);
- if (unlikely(!gh))
- goto out;
- }
-
- if (gh->ver != GENEVE_VER || gh->oam)
- goto out;
- gh_len = geneve_hlen(gh);
-
- hlen = off_gnv + gh_len;
- if (skb_gro_header_hard(skb, hlen)) {
- gh = skb_gro_header_slow(skb, hlen, off_gnv);
- if (unlikely(!gh))
- goto out;
- }
-
- for (p = *head; p; p = p->next) {
- if (!NAPI_GRO_CB(p)->same_flow)
- continue;
-
- gh2 = (struct genevehdr *)(p->data + off_gnv);
- if (gh->opt_len != gh2->opt_len ||
- memcmp(gh, gh2, gh_len)) {
- NAPI_GRO_CB(p)->same_flow = 0;
- continue;
- }
- }
-
- type = gh->proto_type;
-
- rcu_read_lock();
- ptype = gro_find_receive_by_type(type);
- if (!ptype)
- goto out_unlock;
-
- skb_gro_pull(skb, gh_len);
- skb_gro_postpull_rcsum(skb, gh, gh_len);
- pp = ptype->callbacks.gro_receive(head, skb);
- flush = 0;
-
-out_unlock:
- rcu_read_unlock();
-out:
- NAPI_GRO_CB(skb)->flush |= flush;
-
- return pp;
-}
-
-#ifndef HAVE_UDP_OFFLOAD_ARG_UOFF
-static int geneve_gro_complete(struct sk_buff *skb, int nhoff)
-#else
-static int geneve_gro_complete(struct sk_buff *skb, int nhoff,
- struct udp_offload *uoff)
-#endif
-{
- struct genevehdr *gh;
- struct packet_offload *ptype;
- __be16 type;
- int gh_len;
- int err = -ENOSYS;
-
- udp_tunnel_gro_complete(skb, nhoff);
-
- gh = (struct genevehdr *)(skb->data + nhoff);
- gh_len = geneve_hlen(gh);
- type = gh->proto_type;
-
- rcu_read_lock();
- ptype = gro_find_complete_by_type(type);
- if (ptype)
- err = ptype->callbacks.gro_complete(skb, nhoff + gh_len);
-
- rcu_read_unlock();
-
- skb_set_inner_mac_header(skb, nhoff + gh_len);
- return err;
-}
-#endif
-
-/* Create new listen socket if needed */
-static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
- bool ipv6, u32 flags)
-{
- struct geneve_net *gn = net_generic(net, geneve_net_id);
- struct geneve_sock *gs;
- struct socket *sock;
- struct udp_tunnel_sock_cfg tunnel_cfg;
- int h;
-
- gs = kzalloc(sizeof(*gs), GFP_KERNEL);
- if (!gs)
- return ERR_PTR(-ENOMEM);
-
- sock = geneve_create_sock(net, ipv6, port, flags);
- if (IS_ERR(sock)) {
- kfree(gs);
- return ERR_CAST(sock);
- }
-
- gs->sock = sock;
- gs->refcnt = 1;
- for (h = 0; h < VNI_HASH_SIZE; ++h)
- INIT_HLIST_HEAD(&gs->vni_list[h]);
-
- /* Initialize the geneve udp offloads structure */
-#ifdef HAVE_UDP_OFFLOAD
- gs->udp_offloads.port = port;
- gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive;
- gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete;
-#endif
-
- geneve_notify_add_rx_port(gs);
- /* Mark socket as an encapsulation socket */
- memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
- tunnel_cfg.sk_user_data = gs;
- tunnel_cfg.encap_type = 1;
-#ifdef HAVE_UDP_TUNNEL_SOCK_CFG_GRO_RECEIVE
- tunnel_cfg.gro_receive = geneve_gro_receive;
- tunnel_cfg.gro_complete = geneve_gro_complete;
-#endif
- tunnel_cfg.encap_rcv = geneve_udp_encap_recv;
- tunnel_cfg.encap_destroy = NULL;
- setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
- list_add(&gs->list, &gn->sock_list);
- return gs;
-}
-
-static void __geneve_sock_release(struct geneve_sock *gs)
-{
- if (!gs || --gs->refcnt)
- return;
-
- list_del(&gs->list);
- geneve_notify_del_rx_port(gs);
- udp_tunnel_sock_release(gs->sock);
- kfree_rcu(gs, rcu);
-}
-
-static void geneve_sock_release(struct geneve_dev *geneve)
-{
- struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4);
-#if IS_ENABLED(CONFIG_IPV6)
- struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6);
-
- rcu_assign_pointer(geneve->sock6, NULL);
-#endif
-
- rcu_assign_pointer(geneve->sock4, NULL);
- synchronize_net();
-
- __geneve_sock_release(gs4);
-#if IS_ENABLED(CONFIG_IPV6)
- __geneve_sock_release(gs6);
-#endif
-}
-
-static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
- sa_family_t family,
- __be16 dst_port)
-{
- struct geneve_sock *gs;
-
- list_for_each_entry(gs, &gn->sock_list, list) {
- if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
- geneve_get_sk_family(gs) == family) {
- return gs;
- }
- }
- return NULL;
-}
-
-static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
-{
- struct net *net = geneve->net;
- struct geneve_net *gn = net_generic(net, geneve_net_id);
- struct geneve_sock *gs;
- __u32 hash;
-
- gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET, geneve->dst_port);
- if (gs) {
- gs->refcnt++;
- goto out;
- }
-
- gs = geneve_socket_create(net, geneve->dst_port, ipv6, geneve->flags);
- if (IS_ERR(gs))
- return PTR_ERR(gs);
-
-out:
- gs->collect_md = geneve->collect_md;
- gs->flags = geneve->flags;
-#if IS_ENABLED(CONFIG_IPV6)
- if (ipv6)
- rcu_assign_pointer(geneve->sock6, gs);
- else
-#endif
- rcu_assign_pointer(geneve->sock4, gs);
-
- hash = geneve_net_vni_hash(geneve->vni);
- hlist_add_head_rcu(&geneve->hlist, &gs->vni_list[hash]);
- return 0;
-}
-
-static int geneve_open(struct net_device *dev)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
- bool ipv6 = geneve->remote.sa.sa_family == AF_INET6;
- bool metadata = geneve->collect_md;
- int ret = 0;
-
-#if IS_ENABLED(CONFIG_IPV6)
- if (ipv6 || metadata)
- ret = geneve_sock_add(geneve, true);
-#endif
-
- if (!ret && (!ipv6 || metadata))
- ret = geneve_sock_add(geneve, false);
- if (ret < 0)
- geneve_sock_release(geneve);
-
- return ret;
-}
-
-static int geneve_stop(struct net_device *dev)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
-
- if (!hlist_unhashed(&geneve->hlist))
- hlist_del_rcu(&geneve->hlist);
- geneve_sock_release(geneve);
- return 0;
-}
-
-static void geneve_build_header(struct genevehdr *geneveh,
- __be16 tun_flags, u8 vni[3],
- u8 options_len, u8 *options)
-{
- geneveh->ver = GENEVE_VER;
- geneveh->opt_len = options_len / 4;
- geneveh->oam = !!(tun_flags & TUNNEL_OAM);
- geneveh->critical = !!(tun_flags & TUNNEL_CRIT_OPT);
- geneveh->rsvd1 = 0;
- memcpy(geneveh->vni, vni, 3);
- geneveh->proto_type = htons(ETH_P_TEB);
- geneveh->rsvd2 = 0;
-
- memcpy(geneveh->options, options, options_len);
-}
-
-static int push_vlan_tag(struct sk_buff *skb)
-{
- if (skb_vlan_tag_present(skb)) {
- __be16 vlan_proto = skb->vlan_proto;
- int err;
-
- err = __vlan_insert_tag(skb, skb->vlan_proto,
- skb_vlan_tag_get(skb));
-
- if (unlikely(err))
- return err;
- skb->vlan_tci = 0;
- skb->protocol = vlan_proto;
- }
- return 0;
-}
-
-static int geneve_build_skb(struct rtable *rt, struct sk_buff *skb,
- __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt,
- u32 flags, bool xnet)
-{
- struct genevehdr *gnvh;
- int min_headroom;
- int err;
- bool udp_sum = !(flags & GENEVE_F_UDP_ZERO_CSUM_TX);
-
- skb_scrub_packet(skb, xnet);
-
- min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
- + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr)
- + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
-
- err = skb_cow_head(skb, min_headroom);
- if (unlikely(err))
- goto free_rt;
-
- err = push_vlan_tag(skb);
- if (unlikely(err))
- goto free_rt;
-
- err = udp_tunnel_handle_offloads(skb, udp_sum);
- if (err)
- goto free_rt;
-
- gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len);
- geneve_build_header(gnvh, tun_flags, vni, opt_len, opt);
-
- ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB));
- return 0;
-
-free_rt:
- ip_rt_put(rt);
- return err;
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static int geneve6_build_skb(struct dst_entry *dst, struct sk_buff *skb,
- __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt,
- u32 flags, bool xnet)
-{
- struct genevehdr *gnvh;
- int min_headroom;
- int err;
- bool udp_sum = !(flags & GENEVE_F_UDP_ZERO_CSUM6_TX);
-
- skb_scrub_packet(skb, xnet);
-
- min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len
- + GENEVE_BASE_HLEN + opt_len + sizeof(struct ipv6hdr)
- + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
-
- err = skb_cow_head(skb, min_headroom);
- if (unlikely(err))
- goto free_dst;
-
- err = push_vlan_tag(skb);
- if (unlikely(err))
- goto free_dst;
-
- err = udp_tunnel_handle_offloads(skb, udp_sum);
- if (err)
- goto free_dst;
-
- gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len);
- geneve_build_header(gnvh, tun_flags, vni, opt_len, opt);
-
- ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB));
- return 0;
-
-free_dst:
- dst_release(dst);
- return err;
-}
-#endif
-
-static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi4 *fl4,
- struct ip_tunnel_info *info,
- __be16 dport, __be16 sport)
-{
- bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
- struct geneve_dev *geneve = netdev_priv(dev);
- struct dst_cache *dst_cache;
- struct rtable *rt = NULL;
- __u8 tos;
-
- if (!rcu_dereference(geneve->sock4))
- return ERR_PTR(-EIO);
-
- memset(fl4, 0, sizeof(*fl4));
- fl4->flowi4_mark = skb->mark;
- fl4->flowi4_proto = IPPROTO_UDP;
- fl4->fl4_dport = dport;
- fl4->fl4_sport = sport;
-
- if (info) {
- fl4->daddr = info->key.u.ipv4.dst;
- fl4->saddr = info->key.u.ipv4.src;
- fl4->flowi4_tos = RT_TOS(info->key.tos);
- dst_cache = &info->dst_cache;
- } else {
- tos = geneve->tos;
- if (tos == 1) {
- const struct iphdr *iip = ip_hdr(skb);
-
- tos = ip_tunnel_get_dsfield(iip, skb);
- use_cache = false;
- }
-
- fl4->flowi4_tos = RT_TOS(tos);
- fl4->daddr = geneve->remote.sin.sin_addr.s_addr;
- dst_cache = &geneve->dst_cache;
- }
-
- if (use_cache) {
- rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
- if (rt)
- return rt;
- }
-
- rt = ip_route_output_key(geneve->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);
- }
- if (use_cache)
- dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr);
- return rt;
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi6 *fl6,
- struct ip_tunnel_info *info,
- __be16 dport, __be16 sport)
-{
- bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
- struct geneve_dev *geneve = netdev_priv(dev);
- struct dst_entry *dst = NULL;
- struct dst_cache *dst_cache;
- struct geneve_sock *gs6;
- __u8 prio;
-
- gs6 = rcu_dereference(geneve->sock6);
- if (!gs6)
- return ERR_PTR(-EIO);
-
- memset(fl6, 0, sizeof(*fl6));
- fl6->flowi6_mark = skb->mark;
- fl6->flowi6_proto = IPPROTO_UDP;
- fl6->fl6_dport = dport;
- fl6->fl6_sport = sport;
-
- if (info) {
- fl6->daddr = info->key.u.ipv6.dst;
- fl6->saddr = info->key.u.ipv6.src;
- fl6->flowlabel = ip6_make_flowinfo(RT_TOS(info->key.tos),
- info->key.label);
- dst_cache = &info->dst_cache;
- } else {
- prio = geneve->tos;
- if (prio == 1) {
- const struct iphdr *iip = ip_hdr(skb);
-
- prio = ip_tunnel_get_dsfield(iip, skb);
- use_cache = false;
- }
-
- fl6->flowlabel = ip6_make_flowinfo(RT_TOS(prio),
- geneve->label);
- fl6->daddr = geneve->remote.sin6.sin6_addr;
- dst_cache = &geneve->dst_cache;
- }
-
- if (use_cache) {
- dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
- if (dst)
- return dst;
- }
-
-#if defined(HAVE_IPV6_STUB_WITH_DST_ENTRY) && defined(HAVE_IPV6_DST_LOOKUP_FLOW)
-#ifdef HAVE_IPV6_DST_LOOKUP_FLOW_NET
- dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6,
- NULL);
-#else
- dst = ipv6_stub->ipv6_dst_lookup_flow(gs6->sock->sk, fl6,
- NULL);
-#endif
- if (IS_ERR(dst)) {
-#elif defined(HAVE_IPV6_DST_LOOKUP_FLOW_NET)
- if (ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, &dst,
- fl6)) {
-#elif defined(HAVE_IPV6_DST_LOOKUP_FLOW)
- if (ipv6_stub->ipv6_dst_lookup_flow(gs6->sock->sk, &dst, fl6)) {
-#elif defined(HAVE_IPV6_DST_LOOKUP_NET)
- if (ipv6_stub->ipv6_dst_lookup(geneve->net, gs6->sock->sk, &dst, fl6)) {
-#elif defined(HAVE_IPV6_STUB)
- if (ipv6_stub->ipv6_dst_lookup(gs6->sock->sk, &dst, fl6)) {
-#else
- if (ip6_dst_lookup(gs6->sock->sk, &dst, fl6)) {
-#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);
- }
-
- if (use_cache)
- dst_cache_set_ip6(dst_cache, dst, &fl6->saddr);
- return dst;
-}
-#endif
-
-/* Convert 64 bit tunnel ID to 24 bit VNI. */
-static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
-{
-#ifdef __BIG_ENDIAN
- vni[0] = (__force __u8)(tun_id >> 16);
- vni[1] = (__force __u8)(tun_id >> 8);
- vni[2] = (__force __u8)tun_id;
-#else
- vni[0] = (__force __u8)((__force u64)tun_id >> 40);
- vni[1] = (__force __u8)((__force u64)tun_id >> 48);
- vni[2] = (__force __u8)((__force u64)tun_id >> 56);
-#endif
-}
-
-static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
- struct ip_tunnel_info *info)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
- struct geneve_sock *gs4;
- struct rtable *rt = NULL;
- const struct iphdr *iip; /* interior IP header */
- int err = -EINVAL;
- struct flowi4 fl4;
- __u8 tos, ttl;
- __be16 sport;
- __be16 df;
- bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
- u32 flags = geneve->flags;
-
- gs4 = rcu_dereference(geneve->sock4);
- if (!gs4)
- goto tx_error;
-
- if (geneve->collect_md) {
- if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
- netdev_dbg(dev, "no tunnel metadata\n");
- goto tx_error;
- }
- if (info && ip_tunnel_info_af(info) != AF_INET)
- goto tx_error;
- }
-
- sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
- rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port, sport);
- if (IS_ERR(rt)) {
- err = PTR_ERR(rt);
- goto tx_error;
- }
-
- skb_reset_mac_header(skb);
-
- iip = ip_hdr(skb);
-
- if (info) {
- const struct ip_tunnel_key *key = &info->key;
- u8 *opts = NULL;
- u8 vni[3];
-
- tunnel_id_to_vni(key->tun_id, vni);
- if (info->options_len)
- opts = ip_tunnel_info_opts(info);
-
- if (key->tun_flags & TUNNEL_CSUM)
- flags &= ~GENEVE_F_UDP_ZERO_CSUM_TX;
- else
- flags |= GENEVE_F_UDP_ZERO_CSUM_TX;
-
- err = geneve_build_skb(rt, skb, key->tun_flags, vni,
- info->options_len, opts, flags, xnet);
- if (unlikely(err))
- goto tx_error;
-
- tos = ip_tunnel_ecn_encap(key->tos, iip, skb);
- ttl = key->ttl;
- df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
- } else {
- err = geneve_build_skb(rt, skb, 0, geneve->vni,
- 0, NULL, flags, xnet);
- if (unlikely(err))
- goto tx_error;
-
- tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, iip, skb);
- ttl = geneve->ttl;
- if (!ttl && IN_MULTICAST(ntohl(fl4.daddr)))
- ttl = 1;
- ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
- df = 0;
- }
- udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
- tos, ttl, df, sport, geneve->dst_port,
- !net_eq(geneve->net, dev_net(geneve->dev)),
- !!(flags & GENEVE_F_UDP_ZERO_CSUM_TX));
-
- 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;
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
- struct ip_tunnel_info *info)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
- struct dst_entry *dst = NULL;
- const struct iphdr *iip; /* interior IP header */
- struct geneve_sock *gs6;
- int err = -EINVAL;
- struct flowi6 fl6;
- __u8 prio, ttl;
- __be16 sport;
- __be32 label;
- bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
- u32 flags = geneve->flags;
-
- gs6 = rcu_dereference(geneve->sock6);
- if (!gs6)
- goto tx_error;
-
- if (geneve->collect_md) {
- if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
- netdev_dbg(dev, "no tunnel metadata\n");
- goto tx_error;
- }
- }
-
- sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
- dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port, sport);
- if (IS_ERR(dst)) {
- err = PTR_ERR(dst);
- goto tx_error;
- }
-
- skb_reset_mac_header(skb);
-
- iip = ip_hdr(skb);
-
- if (info) {
- const struct ip_tunnel_key *key = &info->key;
- u8 *opts = NULL;
- u8 vni[3];
-
- tunnel_id_to_vni(key->tun_id, vni);
- if (info->options_len)
- opts = ip_tunnel_info_opts(info);
-
- if (key->tun_flags & TUNNEL_CSUM)
- flags &= ~GENEVE_F_UDP_ZERO_CSUM6_TX;
- else
- flags |= GENEVE_F_UDP_ZERO_CSUM6_TX;
-
- err = geneve6_build_skb(dst, skb, key->tun_flags, vni,
- info->options_len, opts,
- flags, xnet);
- if (unlikely(err))
- goto tx_error;
-
- prio = ip_tunnel_ecn_encap(key->tos, iip, skb);
- ttl = key->ttl;
- label = info->key.label;
- } else {
- err = geneve6_build_skb(dst, skb, 0, geneve->vni,
- 0, NULL, flags, xnet);
- if (unlikely(err))
- goto tx_error;
-
- prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel),
- iip, skb);
- ttl = geneve->ttl;
- if (!ttl && ipv6_addr_is_multicast(&fl6.daddr))
- ttl = 1;
- ttl = ttl ? : ip6_dst_hoplimit(dst);
- label = geneve->label;
- }
- udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
- &fl6.saddr, &fl6.daddr, prio, ttl, label,
- sport, geneve->dst_port,
- !!(flags & GENEVE_F_UDP_ZERO_CSUM6_TX));
- 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;
-}
-#endif
-
-netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- struct geneve_dev *geneve = netdev_priv(dev);
- struct ip_tunnel_info *info = NULL;
-
- if (geneve->collect_md)
- info = skb_tunnel_info(skb);
-
-#if IS_ENABLED(CONFIG_IPV6)
- if ((info && ip_tunnel_info_af(info) == AF_INET6) ||
- (!info && geneve->remote.sa.sa_family == AF_INET6))
- return geneve6_xmit_skb(skb, dev, info);
-#endif
- return geneve_xmit_skb(skb, dev, info);
-}
-EXPORT_SYMBOL_GPL(rpl_geneve_xmit);
-
-static netdev_tx_t geneve_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;
-}
-
-static int __geneve_change_mtu(struct net_device *dev, int new_mtu, bool strict)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
- /* The max_mtu calculation does not take account of GENEVE
- * options, to avoid excluding potentially valid
- * configurations.
- */
- int max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
-
- if (geneve->remote.sa.sa_family == AF_INET6)
- max_mtu -= sizeof(struct ipv6hdr);
- else
- max_mtu -= sizeof(struct iphdr);
-
- if (new_mtu < 68)
- return -EINVAL;
-
- if (new_mtu > max_mtu) {
- if (strict)
- return -EINVAL;
-
- new_mtu = max_mtu;
- }
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-static int geneve_change_mtu(struct net_device *dev, int new_mtu)
-{
- return __geneve_change_mtu(dev, new_mtu, true);
-}
-
-int ovs_geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
-{
- struct ip_tunnel_info *info = skb_tunnel_info(skb);
- struct geneve_dev *geneve = netdev_priv(dev);
- struct rtable *rt;
- struct flowi4 fl4;
- __be16 sport;
-#if IS_ENABLED(CONFIG_IPV6)
- struct dst_entry *dst;
- struct flowi6 fl6;
-#endif
-
- sport = udp_flow_src_port(geneve->net, skb,
- 1, USHRT_MAX, true);
-
- if (ip_tunnel_info_af(info) == AF_INET) {
- rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port, sport);
- if (IS_ERR(rt))
- return PTR_ERR(rt);
-
- ip_rt_put(rt);
- info->key.u.ipv4.src = fl4.saddr;
-#if IS_ENABLED(CONFIG_IPV6)
- } else if (ip_tunnel_info_af(info) == AF_INET6) {
- dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port, sport);
- if (IS_ERR(dst))
- return PTR_ERR(dst);
-
- dst_release(dst);
- info->key.u.ipv6.src = fl6.saddr;
-#endif
- } else {
- return -EINVAL;
- }
-
- info->key.tp_src = sport;
- info->key.tp_dst = geneve->dst_port;
- return 0;
-}
-EXPORT_SYMBOL_GPL(ovs_geneve_fill_metadata_dst);
-
-static const struct net_device_ops geneve_netdev_ops = {
- .ndo_init = geneve_init,
- .ndo_uninit = geneve_uninit,
- .ndo_open = geneve_open,
- .ndo_stop = geneve_stop,
- .ndo_start_xmit = geneve_dev_xmit,
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = geneve_change_mtu,
-#else
- .ndo_change_mtu = geneve_change_mtu,
-#endif
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
-#ifdef HAVE_NDO_FILL_METADATA_DST
- .ndo_fill_metadata_dst = geneve_fill_metadata_dst,
-#endif
-};
-
-static void geneve_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- strlcpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version));
- strlcpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver));
-}
-
-static const struct ethtool_ops geneve_ethtool_ops = {
- .get_drvinfo = geneve_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-
-/* Info for udev, that this is a virtual tunnel endpoint */
-static struct device_type geneve_type = {
- .name = "geneve",
-};
-
-/* Calls the ndo_add_geneve_port or ndo_udp_tunnel_add of the caller
- * in order to supply the listening GENEVE udp ports. Callers are
- * expected to implement the ndo_add_geneve_port.
- */
-static void geneve_push_rx_ports(struct net_device *dev)
-{
-#ifdef HAVE_NDO_ADD_GENEVE_PORT
- struct net *net = dev_net(dev);
- struct geneve_net *gn = net_generic(net, geneve_net_id);
- struct geneve_sock *gs;
- sa_family_t sa_family;
- struct sock *sk;
- __be16 port;
-
- if (!dev->netdev_ops->ndo_add_geneve_port)
- return;
-
- rcu_read_lock();
- list_for_each_entry_rcu(gs, &gn->sock_list, list) {
- sk = gs->sock->sk;
- sa_family = sk->sk_family;
- port = inet_sk(sk)->inet_sport;
- dev->netdev_ops->ndo_add_geneve_port(dev, sa_family, port);
- }
- rcu_read_unlock();
-#elif defined(HAVE_NDO_UDP_TUNNEL_ADD)
- struct net *net = dev_net(dev);
- struct geneve_net *gn = net_generic(net, geneve_net_id);
- struct geneve_sock *gs;
- struct sock *sk;
-
- if (!dev->netdev_ops->ndo_udp_tunnel_add)
- return;
-
- rcu_read_lock();
- list_for_each_entry_rcu(gs, &gn->sock_list, list) {
- struct udp_tunnel_info ti;
- ti.type = UDP_TUNNEL_TYPE_GENEVE;
- sk = gs->sock->sk;
- ti.port = inet_sk(sk)->inet_sport;
- ti.sa_family = sk->sk_family;
- dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti);
- }
- rcu_read_unlock();
-#endif
-}
-
-/* Initialize the device structure. */
-static void geneve_setup(struct net_device *dev)
-{
- ether_setup(dev);
-
- dev->netdev_ops = &geneve_netdev_ops;
- dev->ethtool_ops = &geneve_ethtool_ops;
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
-#endif
-
- SET_NETDEV_DEVTYPE(dev, &geneve_type);
-
- dev->features |= NETIF_F_LLTX;
- 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;
-
-#if 0
- netif_keep_dst(dev);
-#endif
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
- eth_hw_addr_random(dev);
-}
-
-static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
- [IFLA_GENEVE_ID] = { .type = NLA_U32 },
- [IFLA_GENEVE_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) },
- [IFLA_GENEVE_REMOTE6] = { .len = sizeof(struct in6_addr) },
- [IFLA_GENEVE_TTL] = { .type = NLA_U8 },
- [IFLA_GENEVE_TOS] = { .type = NLA_U8 },
- [IFLA_GENEVE_LABEL] = { .type = NLA_U32 },
- [IFLA_GENEVE_PORT] = { .type = NLA_U16 },
- [IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG },
- [IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 },
- [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
- [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
-};
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int geneve_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- if (tb[IFLA_ADDRESS]) {
- if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
- return -EINVAL;
-
- if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
- return -EADDRNOTAVAIL;
- }
-
- if (!data)
- return -EINVAL;
-
- if (data[IFLA_GENEVE_ID]) {
- __u32 vni = nla_get_u32(data[IFLA_GENEVE_ID]);
-
- if (vni >= GENEVE_VID_MASK)
- return -ERANGE;
- }
-
- return 0;
-}
-
-static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
- __be16 dst_port,
- union geneve_addr *remote,
- u8 vni[],
- bool *tun_on_same_port,
- bool *tun_collect_md)
-{
- struct geneve_dev *geneve, *t;
-
- *tun_on_same_port = false;
- *tun_collect_md = false;
- t = NULL;
- list_for_each_entry(geneve, &gn->geneve_list, next) {
- if (geneve->dst_port == dst_port) {
- *tun_collect_md = geneve->collect_md;
- *tun_on_same_port = true;
- }
- if (!memcmp(vni, geneve->vni, sizeof(geneve->vni)) &&
- !memcmp(remote, &geneve->remote, sizeof(geneve->remote)) &&
- dst_port == geneve->dst_port)
- t = geneve;
- }
- return t;
-}
-
-static int geneve_configure(struct net *net, struct net_device *dev,
- union geneve_addr *remote,
- __u32 vni, __u8 ttl, __u8 tos, __be32 label,
- __be16 dst_port, bool metadata, u32 flags)
-{
- struct geneve_net *gn = net_generic(net, geneve_net_id);
- struct geneve_dev *t, *geneve = netdev_priv(dev);
- bool tun_collect_md, tun_on_same_port;
- int err, encap_len;
-
- if (!remote)
- return -EINVAL;
- if (metadata &&
- (remote->sa.sa_family != AF_UNSPEC || vni || tos || ttl || label))
- return -EINVAL;
-
- geneve->net = net;
- geneve->dev = dev;
-
- geneve->vni[0] = (vni & 0x00ff0000) >> 16;
- geneve->vni[1] = (vni & 0x0000ff00) >> 8;
- geneve->vni[2] = vni & 0x000000ff;
-
- if ((remote->sa.sa_family == AF_INET &&
- IN_MULTICAST(ntohl(remote->sin.sin_addr.s_addr))) ||
- (remote->sa.sa_family == AF_INET6 &&
- ipv6_addr_is_multicast(&remote->sin6.sin6_addr)))
- return -EINVAL;
- if (label && remote->sa.sa_family != AF_INET6)
- return -EINVAL;
-
- geneve->remote = *remote;
-
- geneve->ttl = ttl;
- geneve->tos = tos;
- geneve->label = label;
- geneve->dst_port = dst_port;
- geneve->collect_md = metadata;
- geneve->flags = flags;
-
- t = geneve_find_dev(gn, dst_port, remote, geneve->vni,
- &tun_on_same_port, &tun_collect_md);
- if (t)
- return -EBUSY;
-
- /* make enough headroom for basic scenario */
- encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
- if (remote->sa.sa_family == AF_INET)
- encap_len += sizeof(struct iphdr);
- else
- encap_len += sizeof(struct ipv6hdr);
- dev->needed_headroom = encap_len + ETH_HLEN;
-
- if (metadata) {
- if (tun_on_same_port)
- return -EPERM;
- } else {
- if (tun_collect_md)
- return -EPERM;
- }
-
- dst_cache_reset(&geneve->dst_cache);
-
- err = register_netdevice(dev);
- if (err)
- return err;
-
- list_add(&geneve->next, &gn->geneve_list);
- return 0;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int geneve_newlink(struct net *net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int geneve_newlink(struct net *net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- __be16 dst_port = htons(GENEVE_UDP_PORT);
- __u8 ttl = 0, tos = 0;
- bool metadata = false;
- union geneve_addr remote = geneve_remote_unspec;
- __be32 label = 0;
- __u32 vni = 0;
- u32 flags = 0;
-
- if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6])
- return -EINVAL;
-
- if (data[IFLA_GENEVE_REMOTE]) {
- remote.sa.sa_family = AF_INET;
- remote.sin.sin_addr.s_addr =
- nla_get_in_addr(data[IFLA_GENEVE_REMOTE]);
- }
-
- if (data[IFLA_GENEVE_REMOTE6]) {
- if (!IS_ENABLED(CONFIG_IPV6))
- return -EPFNOSUPPORT;
-
- remote.sa.sa_family = AF_INET6;
- remote.sin6.sin6_addr =
- nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
-
- if (ipv6_addr_type(&remote.sin6.sin6_addr) &
- IPV6_ADDR_LINKLOCAL) {
- netdev_dbg(dev, "link-local remote is unsupported\n");
- return -EINVAL;
- }
- }
-
- if (data[IFLA_GENEVE_ID])
- vni = nla_get_u32(data[IFLA_GENEVE_ID]);
-
- if (data[IFLA_GENEVE_TTL])
- ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
-
- if (data[IFLA_GENEVE_TOS])
- tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
-
- if (data[IFLA_GENEVE_LABEL])
- label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
- IPV6_FLOWLABEL_MASK;
-
- if (data[IFLA_GENEVE_PORT])
- dst_port = nla_get_be16(data[IFLA_GENEVE_PORT]);
-
- if (data[IFLA_GENEVE_COLLECT_METADATA])
- metadata = true;
-
- if (data[IFLA_GENEVE_UDP_CSUM] &&
- !nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
- flags |= GENEVE_F_UDP_ZERO_CSUM_TX;
-
- if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX] &&
- nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
- flags |= GENEVE_F_UDP_ZERO_CSUM6_TX;
-
- if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX] &&
- nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
- flags |= GENEVE_F_UDP_ZERO_CSUM6_RX;
-
- return geneve_configure(net, dev, &remote, vni, ttl, tos, label,
- dst_port, metadata, flags);
-}
-
-static void geneve_dellink(struct net_device *dev, struct list_head *head)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
-
- list_del(&geneve->next);
- unregister_netdevice_queue(dev, head);
-}
-
-static size_t geneve_get_size(const struct net_device *dev)
-{
- return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */
- nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
- nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */
- nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */
- nla_total_size(sizeof(__be32)) + /* IFLA_GENEVE_LABEL */
- nla_total_size(sizeof(__be16)) + /* IFLA_GENEVE_PORT */
- nla_total_size(0) + /* IFLA_GENEVE_COLLECT_METADATA */
- nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
- nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
- nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
- 0;
-}
-
-static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- struct geneve_dev *geneve = netdev_priv(dev);
- __u32 vni;
-
- vni = (geneve->vni[0] << 16) | (geneve->vni[1] << 8) | geneve->vni[2];
- if (nla_put_u32(skb, IFLA_GENEVE_ID, vni))
- goto nla_put_failure;
-
- if (geneve->remote.sa.sa_family == AF_INET) {
- if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE,
- geneve->remote.sin.sin_addr.s_addr))
- goto nla_put_failure;
-#if IS_ENABLED(CONFIG_IPV6)
- } else {
- if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6,
- &geneve->remote.sin6.sin6_addr))
- goto nla_put_failure;
-#endif
- }
-
- if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl) ||
- nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos) ||
- nla_put_be32(skb, IFLA_GENEVE_LABEL, geneve->label))
- goto nla_put_failure;
-
- if (nla_put_be16(skb, IFLA_GENEVE_PORT, geneve->dst_port))
- goto nla_put_failure;
-
- if (geneve->collect_md) {
- if (nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA))
- goto nla_put_failure;
- }
-
- if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
- !(geneve->flags & GENEVE_F_UDP_ZERO_CSUM_TX)) ||
- nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
- !!(geneve->flags & GENEVE_F_UDP_ZERO_CSUM6_TX)) ||
- nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
- !!(geneve->flags & GENEVE_F_UDP_ZERO_CSUM6_RX)))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-static struct rtnl_link_ops geneve_link_ops __read_mostly = {
- .kind = "ovs_geneve",
- .maxtype = IFLA_GENEVE_MAX,
- .policy = geneve_policy,
- .priv_size = sizeof(struct geneve_dev),
- .setup = geneve_setup,
- .validate = geneve_validate,
- .newlink = geneve_newlink,
- .dellink = geneve_dellink,
- .get_size = geneve_get_size,
- .fill_info = geneve_fill_info,
-};
-
-struct net_device *rpl_geneve_dev_create_fb(struct net *net, const char *name,
- u8 name_assign_type, u16 dst_port)
-{
- 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,
- &geneve_link_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- err = geneve_configure(net, dev, &geneve_remote_unspec,
- 0, 0, 0, 0, htons(dst_port), true,
- GENEVE_F_UDP_ZERO_CSUM6_RX);
- if (err) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
- /* openvswitch users expect packet sizes to be unrestricted,
- * so set the largest MTU we can.
- */
- err = __geneve_change_mtu(dev, IP_MAX_MTU, false);
- if (err)
- goto err;
-
- err = rtnl_configure_link(dev, NULL);
- if (err < 0)
- goto err;
-
- return dev;
-
- err:
- geneve_dellink(dev, &list_kill);
- unregister_netdevice_many(&list_kill);
- return ERR_PTR(err);
-}
-EXPORT_SYMBOL_GPL(rpl_geneve_dev_create_fb);
-
-static int geneve_netdevice_event(struct notifier_block *unused,
- unsigned long event, void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (event == NETDEV_OFFLOAD_PUSH_GENEVE)
- geneve_push_rx_ports(dev);
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block geneve_notifier_block __read_mostly = {
- .notifier_call = geneve_netdevice_event,
-};
-
-static __net_init int geneve_init_net(struct net *net)
-{
- struct geneve_net *gn = net_generic(net, geneve_net_id);
-
- INIT_LIST_HEAD(&gn->geneve_list);
- INIT_LIST_HEAD(&gn->sock_list);
- return 0;
-}
-
-static void __net_exit geneve_exit_net(struct net *net)
-{
- struct geneve_net *gn = net_generic(net, geneve_net_id);
- struct geneve_dev *geneve, *next;
- struct net_device *dev, *aux;
- LIST_HEAD(list);
-
- rtnl_lock();
-
- /* gather any geneve devices that were moved into this ns */
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == &geneve_link_ops)
- unregister_netdevice_queue(dev, &list);
-
- /* now gather any other geneve devices that were created in this ns */
- list_for_each_entry_safe(geneve, next, &gn->geneve_list, next) {
- /* If geneve->dev is in the same netns, it was already added
- * to the list by the previous loop.
- */
- if (!net_eq(dev_net(geneve->dev), net))
- unregister_netdevice_queue(geneve->dev, &list);
- }
-
- /* unregister the devices gathered above */
- unregister_netdevice_many(&list);
- rtnl_unlock();
-}
-
-static struct pernet_operations geneve_net_ops = {
- .init = geneve_init_net,
- .exit = geneve_exit_net,
- .id = &geneve_net_id,
- .size = sizeof(struct geneve_net),
-};
-
-int rpl_geneve_init_module(void)
-{
- int rc;
-
- rc = register_pernet_subsys(&geneve_net_ops);
- if (rc)
- goto out1;
-
- rc = register_netdevice_notifier(&geneve_notifier_block);
- if (rc)
- goto out2;
-
- rc = rtnl_link_register(&geneve_link_ops);
- if (rc)
- goto out3;
-
- pr_info("Geneve tunneling driver\n");
- return 0;
-
-out3:
- unregister_netdevice_notifier(&geneve_notifier_block);
-out2:
- unregister_pernet_subsys(&geneve_net_ops);
-out1:
- pr_err("Error while initializing GENEVE %d\n", rc);
- return rc;
-}
-
-void rpl_geneve_cleanup_module(void)
-{
- rtnl_link_unregister(&geneve_link_ops);
- unregister_netdevice_notifier(&geneve_notifier_block);
- unregister_pernet_subsys(&geneve_net_ops);
-}
-
-#endif
diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c
deleted file mode 100644
index e57528f80..000000000
--- a/datapath/linux/compat/gre.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (c) 2007-2013 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-#include <linux/version.h>
-#include <linux/kconfig.h>
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/if_tunnel.h>
-#include <linux/icmp.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-
-#include <net/gre.h>
-#include <net/icmp.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <net/xfrm.h>
-
-#include "gso.h"
-
-#ifndef USE_UPSTREAM_TUNNEL
-#if IS_ENABLED(CONFIG_NET_IPGRE_DEMUX)
-
-static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
-
-int rpl_gre_add_protocol(const struct gre_protocol *proto, u8 version)
-{
- if (version >= GREPROTO_MAX)
- return -EINVAL;
-
- return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
- 0 : -EBUSY;
-}
-EXPORT_SYMBOL_GPL(rpl_gre_add_protocol);
-
-int rpl_gre_del_protocol(const struct gre_protocol *proto, u8 version)
-{
- int ret;
-
- if (version >= GREPROTO_MAX)
- return -EINVAL;
-
- ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
- 0 : -EBUSY;
-
- if (ret)
- return ret;
-
- synchronize_rcu();
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_gre_del_protocol);
-
-static int gre_rcv(struct sk_buff *skb)
-{
- const struct gre_protocol *proto;
- u8 ver;
- int ret;
-
- if (!pskb_may_pull(skb, 12))
- goto drop;
-
- ver = skb->data[1]&0x7f;
- if (ver >= GREPROTO_MAX)
- goto drop;
-
- rcu_read_lock();
- proto = rcu_dereference(gre_proto[ver]);
- if (!proto || !proto->handler)
- goto drop_unlock;
- ret = proto->handler(skb);
- rcu_read_unlock();
- return ret;
-
-drop_unlock:
- rcu_read_unlock();
-drop:
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
-static void gre_err(struct sk_buff *skb, u32 info)
-{
- const struct gre_protocol *proto;
- const struct iphdr *iph = (const struct iphdr *)skb->data;
- u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
-
- if (ver >= GREPROTO_MAX)
- return;
-
- rcu_read_lock();
- proto = rcu_dereference(gre_proto[ver]);
- if (proto && proto->err_handler)
- proto->err_handler(skb, info);
- rcu_read_unlock();
-}
-
-static const struct net_protocol net_gre_protocol = {
- .handler = gre_rcv,
- .err_handler = gre_err,
- .netns_ok = 1,
-};
-
-int rpl_gre_init(void)
-{
- pr_info("GRE over IPv4 demultiplexor driver\n");
-
- if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
- pr_err("can't add protocol\n");
- return -EEXIST;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_gre_init);
-
-void rpl_gre_exit(void)
-{
- inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
-}
-EXPORT_SYMBOL_GPL(rpl_gre_exit);
-
-void rpl_gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
- int hdr_len)
-{
- struct gre_base_hdr *greh;
-
- skb_push(skb, hdr_len);
-
- skb_reset_transport_header(skb);
- greh = (struct gre_base_hdr *)skb->data;
- greh->flags = tnl_flags_to_gre_flags(tpi->flags);
- greh->protocol = tpi->proto;
-
- if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) {
- __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
-
- if (tpi->flags&TUNNEL_SEQ) {
- *ptr = tpi->seq;
- ptr--;
- }
- if (tpi->flags&TUNNEL_KEY) {
- *ptr = tpi->key;
- ptr--;
- }
- if (tpi->flags&TUNNEL_CSUM &&
- !(skb_shinfo(skb)->gso_type &
- (SKB_GSO_GRE|SKB_GSO_GRE_CSUM))) {
- *ptr = 0;
- *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
- skb->len, 0));
- }
- }
-}
-EXPORT_SYMBOL_GPL(rpl_gre_build_header);
-
-/* Fills in tpi and returns header length to be pulled. */
-int rpl_gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
- bool *csum_err, __be16 proto, int nhs)
-{
- const struct gre_base_hdr *greh;
- __be32 *options;
- int hdr_len;
-
- if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr))))
- return -EINVAL;
-
- greh = (struct gre_base_hdr *)(skb->data + nhs);
- if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
- return -EINVAL;
-
- tpi->flags = gre_flags_to_tnl_flags(greh->flags);
- hdr_len = gre_calc_hlen(tpi->flags);
-
- if (!pskb_may_pull(skb, nhs + hdr_len))
- return -EINVAL;
-
- greh = (struct gre_base_hdr *)(skb->data + nhs);
- tpi->proto = greh->protocol;
-
- options = (__be32 *)(greh + 1);
- if (greh->flags & GRE_CSUM) {
- if (skb_checksum_simple_validate(skb)) {
- *csum_err = true;
- return -EINVAL;
- }
-
- skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
- null_compute_pseudo);
- options++;
- }
-
- if (greh->flags & GRE_KEY) {
- tpi->key = *options;
- options++;
- } else {
- tpi->key = 0;
- }
- if (unlikely(greh->flags & GRE_SEQ)) {
- tpi->seq = *options;
- options++;
- } else {
- tpi->seq = 0;
- }
- /* WCCP version 1 and 2 protocol decoding.
- * - Change protocol to IPv4/IPv6
- * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
- */
- if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
- tpi->proto = proto;
- if ((*(u8 *)options & 0xF0) != 0x40)
- hdr_len += 4;
- }
- tpi->hdr_len = hdr_len;
- return hdr_len;
-}
-EXPORT_SYMBOL(rpl_gre_parse_header);
-
-#endif /* CONFIG_NET_IPGRE_DEMUX */
-#endif /* USE_UPSTREAM_TUNNEL */
diff --git a/datapath/linux/compat/gso.c b/datapath/linux/compat/gso.c
deleted file mode 100644
index 65da5d876..000000000
--- a/datapath/linux/compat/gso.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (c) 2007-2013 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-#include <linux/version.h>
-
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/if_tunnel.h>
-#include <linux/if_vlan.h>
-#include <linux/icmp.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-
-#include <net/gre.h>
-#include <net/icmp.h>
-#include <net/mpls.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <net/xfrm.h>
-
-#include "gso.h"
-
-#ifdef OVS_USE_COMPAT_GSO_SEGMENTATION
-/* Strictly this is not needed and will be optimised out
- * as this code is guarded by if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0).
- * It is here to make things explicit should the compatibility
- * code be extended in some way prior extending its life-span
- * beyond v3.19.
- */
-static bool supports_mpls_gso(void)
-{
-/* MPLS GSO was introduced in v3.11, however it was not correctly
- * activated using mpls_features until v3.19. */
-#ifdef OVS_USE_COMPAT_GSO_SEGMENTATION
- return true;
-#else
- return false;
-#endif
-}
-
-int rpl_dev_queue_xmit(struct sk_buff *skb)
-{
-#undef dev_queue_xmit
- int err = -ENOMEM;
- bool mpls;
-
- mpls = false;
-
- /* Avoid traversing any VLAN tags that are present to determine if
- * the ethtype is MPLS. Instead compare the mac_len (end of L2) and
- * skb_network_offset() (beginning of L3) whose inequality will
- * indicate the presence of an MPLS label stack. */
- if (skb->mac_len != skb_network_offset(skb) && !supports_mpls_gso())
- mpls = true;
-
- if (mpls) {
- int features;
-
- features = netif_skb_features(skb);
-
- /* As of v3.11 the kernel provides an mpls_features field in
- * struct net_device which allows devices to advertise which
- * features its supports for MPLS. This value defaults to
- * NETIF_F_SG and as of v3.19.
- *
- * This compatibility code is intended for kernels older
- * than v3.19 that do not support MPLS GSO and do not
- * use mpls_features. Thus this code uses NETIF_F_SG
- * directly in place of mpls_features.
- */
- if (mpls)
- features &= NETIF_F_SG;
-
- if (netif_needs_gso(skb, features)) {
- struct sk_buff *nskb;
-
- nskb = skb_gso_segment(skb, features);
- if (!nskb) {
- if (unlikely(skb_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
- goto drop;
-
- skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY;
- goto xmit;
- }
-
- if (IS_ERR(nskb)) {
- err = PTR_ERR(nskb);
- goto drop;
- }
- consume_skb(skb);
- skb = nskb;
-
- do {
- nskb = skb->next;
- skb->next = NULL;
- err = dev_queue_xmit(skb);
- skb = nskb;
- } while (skb);
-
- return err;
- }
- }
-xmit:
- return dev_queue_xmit(skb);
-
-drop:
- kfree_skb(skb);
- return err;
-}
-EXPORT_SYMBOL_GPL(rpl_dev_queue_xmit);
-#endif /* OVS_USE_COMPAT_GSO_SEGMENTATION */
-
-#ifndef USE_UPSTREAM_TUNNEL_GSO
-static __be16 __skb_network_protocol(struct sk_buff *skb)
-{
- __be16 type = skb->protocol;
- int vlan_depth = ETH_HLEN;
-
- while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
- struct vlan_hdr *vh;
-
- if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
- return 0;
-
- vh = (struct vlan_hdr *)(skb->data + vlan_depth);
- type = vh->h_vlan_encapsulated_proto;
- vlan_depth += VLAN_HLEN;
- }
-
- if (eth_p_mpls(type))
- type = ovs_skb_get_inner_protocol(skb);
-
- return type;
-}
-
-static struct sk_buff *tnl_skb_gso_segment(struct sk_buff *skb,
- netdev_features_t features,
- bool tx_path,
- sa_family_t sa_family)
-{
- void *iph = skb_network_header(skb);
- int pkt_hlen = skb_inner_network_offset(skb); /* inner l2 + tunnel hdr. */
- int mac_offset = skb_inner_mac_offset(skb);
- int outer_l3_offset = skb_network_offset(skb);
- int outer_l4_offset = skb_transport_offset(skb);
- struct sk_buff *skb1 = skb;
- struct dst_entry *dst = skb_dst(skb);
- struct sk_buff *segs;
- __be16 proto = skb->protocol;
- char cb[sizeof(skb->cb)];
-
- BUILD_BUG_ON(sizeof(struct ovs_gso_cb) > sizeof_field(struct sk_buff, cb));
- OVS_GSO_CB(skb)->ipv6 = (sa_family == AF_INET6);
- /* setup whole inner packet to get protocol. */
- __skb_pull(skb, mac_offset);
- skb->protocol = __skb_network_protocol(skb);
-
- /* setup l3 packet to gso, to get around segmentation bug on older kernel.*/
- __skb_pull(skb, (pkt_hlen - mac_offset));
- skb_reset_mac_header(skb);
- skb_reset_network_header(skb);
- skb_reset_transport_header(skb);
-
- /* From 3.9 kernel skb->cb is used by skb gso. Therefore
- * make copy of it to restore it back. */
- memcpy(cb, skb->cb, sizeof(cb));
-
- /* We are handling offloads by segmenting l3 packet, so
- * no need to call OVS compat segmentation function. */
-
-#ifdef HAVE___SKB_GSO_SEGMENT
-#undef __skb_gso_segment
- segs = __skb_gso_segment(skb, 0, tx_path);
-#else
-#undef skb_gso_segment
- segs = skb_gso_segment(skb, 0);
-#endif
-
- if (!segs || IS_ERR(segs))
- goto free;
-
- skb = segs;
- while (skb) {
- __skb_push(skb, pkt_hlen);
- skb_reset_mac_header(skb);
- skb_set_network_header(skb, outer_l3_offset);
- skb_set_transport_header(skb, outer_l4_offset);
- skb->mac_len = 0;
-
- memcpy(skb_network_header(skb), iph, pkt_hlen);
- memcpy(skb->cb, cb, sizeof(cb));
-
- skb->protocol = proto;
- if (skb->next)
- dst = dst_clone(dst);
-
- skb_dst_set(skb, dst);
- OVS_GSO_CB(skb)->fix_segment(skb);
-
- skb = skb->next;
- }
-free:
- consume_skb(skb1);
- return segs;
-}
-
-static int output_ip(struct sk_buff *skb)
-{
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-
-#undef ip_local_out
- return ip_local_out(skb);
-}
-
-int rpl_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
-{
- if (!OVS_GSO_CB(skb)->fix_segment)
- return output_ip(skb);
-
- /* This bit set can confuse some drivers on old kernel. */
- skb->encapsulation = 0;
-
- if (skb_is_gso(skb)) {
- int ret;
- int id;
-
- skb = tnl_skb_gso_segment(skb, 0, false, AF_INET);
- if (!skb || IS_ERR(skb))
- return NET_XMIT_DROP;
-
- id = ntohs(ip_hdr(skb)->id);
- do {
- struct sk_buff *next_skb = skb->next;
-
- skb->next = NULL;
- ip_hdr(skb)->id = htons(id++);
-
- ret = output_ip(skb);
- skb = next_skb;
- } while (skb);
- return ret;
- } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- int err;
-
- err = skb_checksum_help(skb);
- if (unlikely(err))
- return NET_XMIT_DROP;
- }
-
- return output_ip(skb);
-}
-EXPORT_SYMBOL_GPL(rpl_ip_local_out);
-
-static int output_ipv6(struct sk_buff *skb)
-{
- memset(IP6CB(skb), 0, sizeof (*IP6CB(skb)));
-#undef ip6_local_out
- return ip6_local_out(skb);
-}
-
-int rpl_ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
-{
- if (!OVS_GSO_CB(skb)->fix_segment)
- return output_ipv6(skb);
-
- /* This bit set can confuse some drivers on old kernel. */
- skb->encapsulation = 0;
-
- if (skb_is_gso(skb)) {
- int ret;
-
- skb = tnl_skb_gso_segment(skb, 0, false, AF_INET6);
- if (!skb || IS_ERR(skb))
- return NET_XMIT_DROP;
-
- do {
- struct sk_buff *next_skb = skb->next;
-
- skb->next = NULL;
- ret = output_ipv6(skb);
- skb = next_skb;
- } while (skb);
- return ret;
- } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- int err;
-
- err = skb_checksum_help(skb);
- if (unlikely(err))
- return NET_XMIT_DROP;
- }
-
- return output_ipv6(skb);
-}
-EXPORT_SYMBOL_GPL(rpl_ip6_local_out);
-#endif /* USE_UPSTREAM_TUNNEL_GSO */
diff --git a/datapath/linux/compat/gso.h b/datapath/linux/compat/gso.h
deleted file mode 100644
index 20109406a..000000000
--- a/datapath/linux/compat/gso.h
+++ /dev/null
@@ -1,214 +0,0 @@
-#ifndef __LINUX_GSO_WRAPPER_H
-#define __LINUX_GSO_WRAPPER_H
-
-#include <linux/version.h>
-#include "datapath.h"
-
-typedef void (*gso_fix_segment_t)(struct sk_buff *);
-
-struct ovs_gso_cb {
- struct ovs_skb_cb dp_cb;
-#ifndef USE_UPSTREAM_TUNNEL
- struct metadata_dst *tun_dst;
-#endif
-#ifndef USE_UPSTREAM_TUNNEL_GSO
- gso_fix_segment_t fix_segment;
- bool ipv6;
-#endif
-#ifndef HAVE_INNER_PROTOCOL
- __be16 inner_protocol;
-#endif
-#ifndef USE_UPSTREAM_TUNNEL
- /* Keep original tunnel info during userspace action execution. */
- struct metadata_dst *fill_md_dst;
-#endif
-};
-#define OVS_GSO_CB(skb) ((struct ovs_gso_cb *)(skb)->cb)
-
-
-#ifndef USE_UPSTREAM_TUNNEL_GSO
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/protocol.h>
-
-static inline void skb_clear_ovs_gso_cb(struct sk_buff *skb)
-{
- OVS_GSO_CB(skb)->fix_segment = NULL;
-#ifndef USE_UPSTREAM_TUNNEL
- OVS_GSO_CB(skb)->tun_dst = NULL;
-#endif
-}
-#else
-static inline void skb_clear_ovs_gso_cb(struct sk_buff *skb)
-{
-#ifndef USE_UPSTREAM_TUNNEL
- OVS_GSO_CB(skb)->tun_dst = NULL;
-#endif
-}
-#endif
-
-#ifndef HAVE_INNER_PROTOCOL
-static inline void ovs_skb_init_inner_protocol(struct sk_buff *skb)
-{
- OVS_GSO_CB(skb)->inner_protocol = htons(0);
-}
-
-static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb,
- __be16 ethertype)
-{
- OVS_GSO_CB(skb)->inner_protocol = ethertype;
-}
-
-static inline __be16 ovs_skb_get_inner_protocol(struct sk_buff *skb)
-{
- return OVS_GSO_CB(skb)->inner_protocol;
-}
-
-#else
-
-static inline void ovs_skb_init_inner_protocol(struct sk_buff *skb)
-{
- /* Nothing to do. The inner_protocol is either zero or
- * has been set to a value by another user.
- * Either way it may be considered initialised.
- */
-}
-
-static inline __be16 ovs_skb_get_inner_protocol(struct sk_buff *skb)
-{
- return skb->inner_protocol;
-}
-
-#ifdef ENCAP_TYPE_ETHER
-#define ovs_skb_set_inner_protocol skb_set_inner_protocol
-#else
-static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb,
- __be16 ethertype)
-{
- skb->inner_protocol = ethertype;
-}
-#endif /* ENCAP_TYPE_ETHER */
-#endif /* HAVE_INNER_PROTOCOL */
-
-#define skb_inner_mac_offset rpl_skb_inner_mac_offset
-static inline int skb_inner_mac_offset(const struct sk_buff *skb)
-{
- return skb_inner_mac_header(skb) - skb->data;
-}
-
-#ifndef USE_UPSTREAM_TUNNEL_GSO
-#define ip_local_out rpl_ip_local_out
-int rpl_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
-
-#define ip6_local_out rpl_ip6_local_out
-int rpl_ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
-#else
-
-static inline int rpl_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
-{
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-#ifdef HAVE_IP_LOCAL_OUT_TAKES_NET
- /* net and sk parameters are added at same time. */
- return ip_local_out(net, sk, skb);
-#else
- return ip_local_out(skb);
-#endif
-}
-#define ip_local_out rpl_ip_local_out
-
-static inline int rpl_ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
-{
- memset(IP6CB(skb), 0, sizeof (*IP6CB(skb)));
-#ifdef HAVE_IP_LOCAL_OUT_TAKES_NET
- return ip6_local_out(net, sk, skb);
-#else
- return ip6_local_out(skb);
-#endif
-}
-#define ip6_local_out rpl_ip6_local_out
-
-#endif /* USE_UPSTREAM_TUNNEL_GSO */
-
-#ifndef USE_UPSTREAM_TUNNEL
-/* We need two separate functions to manage different dst in this case.
- * First is dst_entry and second is tunnel-dst.
- * So define ovs_* separate functions for tun_dst.
- */
-static inline void ovs_skb_dst_set(struct sk_buff *skb, void *dst)
-{
- OVS_GSO_CB(skb)->tun_dst = (void *)dst;
-}
-
-static inline struct ip_tunnel_info *ovs_skb_tunnel_info(struct sk_buff *skb)
-{
- if (likely(OVS_GSO_CB(skb)->tun_dst))
- return &OVS_GSO_CB(skb)->tun_dst->u.tun_info;
- else
- return NULL;
-}
-
-static inline void ovs_skb_dst_drop(struct sk_buff *skb)
-{
- OVS_GSO_CB(skb)->tun_dst = NULL;
-}
-
-static inline void ovs_dst_hold(void *dst)
-{
-}
-
-static inline void ovs_dst_release(struct dst_entry *dst)
-{
- struct metadata_dst *tun_dst = (struct metadata_dst *) dst;
-
- dst_cache_destroy(&tun_dst->u.tun_info.dst_cache);
- kfree(dst);
-}
-
-#else
-#define ovs_skb_dst_set skb_dst_set
-#define ovs_skb_dst_drop skb_dst_drop
-#define ovs_dst_hold dst_hold
-#define ovs_dst_release dst_release
-#endif
-
-#ifndef USE_UPSTREAM_TUNNEL
-#define SKB_INIT_FILL_METADATA_DST(skb) OVS_GSO_CB(skb)->fill_md_dst = NULL;
-
-#define SKB_RESTORE_FILL_METADATA_DST(skb) do { \
- if (OVS_GSO_CB(skb)->fill_md_dst) { \
- kfree(OVS_GSO_CB(skb)->tun_dst); \
- OVS_GSO_CB(skb)->tun_dst = OVS_GSO_CB(skb)->fill_md_dst; \
- } \
-} while (0)
-
-
-#define SKB_SETUP_FILL_METADATA_DST(skb) ({ \
- struct metadata_dst *new_md_dst; \
- struct metadata_dst *md_dst; \
- int md_size; \
- int ret = 1; \
- \
- SKB_RESTORE_FILL_METADATA_DST(skb); \
- new_md_dst = kmalloc(sizeof(struct metadata_dst) + 256, GFP_ATOMIC); \
- if (new_md_dst) { \
- md_dst = OVS_GSO_CB(skb)->tun_dst; \
- md_size = new_md_dst->u.tun_info.options_len; \
- memcpy(&new_md_dst->u.tun_info, &md_dst->u.tun_info, \
- sizeof(struct ip_tunnel_info) + md_size); \
- \
- OVS_GSO_CB(skb)->fill_md_dst = md_dst; \
- OVS_GSO_CB(skb)->tun_dst = new_md_dst; \
- ret = 1; \
- } else { \
- ret = 0; \
- } \
- ret; \
-})
-
-#else
-#define SKB_INIT_FILL_METADATA_DST(skb) do {} while(0)
-#define SKB_SETUP_FILL_METADATA_DST(skb) (true)
-#define SKB_RESTORE_FILL_METADATA_DST(skb) do {} while(0)
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/bug.h b/datapath/linux/compat/include/linux/bug.h
deleted file mode 100644
index 6538a22fc..000000000
--- a/datapath/linux/compat/include/linux/bug.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __LINUX_BUG_WRAPPER_H
-#define __LINUX_BUG_WRAPPER_H 1
-
-#include_next <linux/bug.h>
-
-#ifdef __CHECKER__
-#ifndef BUILD_BUG_ON_INVALID
-#define BUILD_BUG_ON_INVALID(e) (0)
-#endif
-
-#endif /* __CHECKER__ */
-
-#endif
diff --git a/datapath/linux/compat/include/linux/cache.h b/datapath/linux/compat/include/linux/cache.h
deleted file mode 100644
index c8a6710b3..000000000
--- a/datapath/linux/compat/include/linux/cache.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __LINUX_CACHE_WRAPPER_H
-#define __LINUX_CACHE_WRAPPER_H 1
-
-#include_next <linux/cache.h>
-
-/* Upstream commit c74ba8b3480d ("arch: Introduce post-init read-only memory")
- * introduced the __ro_after_init attribute, however it wasn't applied to
- * generic netlink sockets until commit 34158151d2aa ("netfilter: cttimeout:
- * use nf_ct_iterate_cleanup_net to unlink timeout objs"). Using it on
- * genetlink before the latter commit leads to crash on module unload.
- * For kernels < 4.10, define it as empty. */
-#ifdef HAVE_GENL_FAMILY_LIST
-#ifdef __ro_after_init
-#undef __ro_after_init
-#endif /* #ifdef __ro_after_init */
-#define __ro_after_init
-#else
-#ifndef __ro_after_init
-#define __ro_after_init
-#endif /* #ifndef __ro_after_init */
-#endif /* #ifdef HAVE_GENL_FAMILY_LIST */
-
-#endif
diff --git a/datapath/linux/compat/include/linux/compiler-gcc.h b/datapath/linux/compat/include/linux/compiler-gcc.h
deleted file mode 100644
index 39d2e0198..000000000
--- a/datapath/linux/compat/include/linux/compiler-gcc.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __LINUX_COMPILER_H
-#if 0
-/* Disable this check - it no longer makes sense with so many backports
- * due to spectre mitigation
- */
-#ifndef HAVE_LINUX_COMPILER_TYPES_H
-#error "Please don't include <linux/compiler-gcc.h> directly, include <linux/compiler.h> instead."
-#endif
-#endif
-#endif
-
-#include_next <linux/compiler-gcc.h>
-
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
-
-#ifndef __always_unused
-#define __always_unused __attribute__((unused))
-#endif
diff --git a/datapath/linux/compat/include/linux/compiler.h b/datapath/linux/compat/include/linux/compiler.h
deleted file mode 100644
index 59b506fd4..000000000
--- a/datapath/linux/compat/include/linux/compiler.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __LINUX_COMPILER_WRAPPER_H
-#define __LINUX_COMPILER_WRAPPER_H 1
-
-#include_next <linux/compiler.h>
-
-#ifndef __percpu
-#define __percpu
-#endif
-
-#ifndef __rcu
-#define __rcu
-#endif
-
-#ifndef READ_ONCE
-#define READ_ONCE(x) (x)
-#endif
-
-#ifndef WRITE_ONCE
-#define WRITE_ONCE(x, val) \
-do { \
- *(volatile typeof(x) *)&(x) = (val); \
-} while (0)
-#endif
-
-
-#endif
diff --git a/datapath/linux/compat/include/linux/cpumask.h b/datapath/linux/compat/include/linux/cpumask.h
deleted file mode 100644
index 48c73aa8f..000000000
--- a/datapath/linux/compat/include/linux/cpumask.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __LINUX_CPUMASK_WRAPPER_H
-#define __LINUX_CPUMASK_WRAPPER_H
-
-#include_next <linux/cpumask.h>
-
-/* for_each_cpu was renamed for_each_possible_cpu in 2.6.18. */
-#ifndef for_each_possible_cpu
-#define for_each_possible_cpu for_each_cpu
-#endif
-
-#endif /* linux/cpumask.h wrapper */
diff --git a/datapath/linux/compat/include/linux/err.h b/datapath/linux/compat/include/linux/err.h
deleted file mode 100644
index 321386c21..000000000
--- a/datapath/linux/compat/include/linux/err.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __LINUX_ERR_WRAPPER_H
-#define __LINUX_ERR_WRAPPER_H 1
-
-#include_next <linux/err.h>
-
-#ifndef HAVE_ERR_CAST
-/**
- * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
- * @ptr: The pointer to cast.
- *
- * Explicitly cast an error-valued pointer to another pointer type in such a
- * way as to make it clear that's what's going on.
- */
-static inline void *ERR_CAST(const void *ptr)
-{
- /* cast away the const */
- return (void *) ptr;
-}
-#endif /* HAVE_ERR_CAST */
-
-#ifndef HAVE_IS_ERR_OR_NULL
-static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
-{
- return !ptr || IS_ERR_VALUE((unsigned long)ptr);
-}
-#endif
-
-#ifndef HAVE_PTR_ERR_OR_ZERO
-static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
-{
- if (IS_ERR(ptr))
- return PTR_ERR(ptr);
- else
- return 0;
-}
-#endif
-#endif
diff --git a/datapath/linux/compat/include/linux/etherdevice.h b/datapath/linux/compat/include/linux/etherdevice.h
deleted file mode 100644
index 4b2707455..000000000
--- a/datapath/linux/compat/include/linux/etherdevice.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __LINUX_ETHERDEVICE_WRAPPER_H
-#define __LINUX_ETHERDEVICE_WRAPPER_H 1
-
-#include <linux/version.h>
-#include_next <linux/etherdevice.h>
-
-#ifndef HAVE_ETHER_ADDR_COPY
-static inline void ether_addr_copy(u8 *dst, const u8 *src)
-{
-#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
- *(u32 *)dst = *(const u32 *)src;
- *(u16 *)(dst + 4) = *(const u16 *)(src + 4);
-#else
- u16 *a = (u16 *)dst;
- const u16 *b = (const u16 *)src;
-
- a[0] = b[0];
- a[1] = b[1];
- a[2] = b[2];
-#endif
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
-#define eth_proto_is_802_3 rpl_eth_proto_is_802_3
-static inline bool eth_proto_is_802_3(__be16 proto)
-{
-#ifndef __BIG_ENDIAN
- /* if CPU is little endian mask off bits representing LSB */
- proto &= htons(0xFF00);
-#endif
- /* cast both to u16 and compare since LSB can be ignored */
- return (__force u16)proto >= (__force u16)htons(ETH_P_802_3_MIN);
-}
-#endif
-
-#define ether_addr_equal rpl_ether_addr_equal
-static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
-{
-#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
- u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) |
- ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4)));
-
- return fold == 0;
-#else
- const u16 *a = (const u16 *)addr1;
- const u16 *b = (const u16 *)addr2;
-
- return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0;
-#endif
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0)
-#define eth_gro_receive rpl_eth_gro_receive
-struct sk_buff **rpl_eth_gro_receive(struct sk_buff **head,
- struct sk_buff *skb);
-
-#define eth_gro_complete rpl_eth_gro_complete
-int rpl_eth_gro_complete(struct sk_buff *skb, int nhoff);
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/genetlink.h b/datapath/linux/compat/include/linux/genetlink.h
deleted file mode 100644
index 3b85f3865..000000000
--- a/datapath/linux/compat/include/linux/genetlink.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _UAPI__LINUX_GENERIC_NETLINK_WRAPPER_H
-#define _UAPI__LINUX_GENERIC_NETLINK_WRAPPER_H
-
-#include_next <linux/genetlink.h>
-
-#ifndef GENL_UNS_ADMIN_PERM
-#define GENL_UNS_ADMIN_PERM GENL_ADMIN_PERM
-#endif
-
-#ifdef GENL_ID_GENERATE
-#if GENL_ID_GENERATE != 0
-#error "GENL_ID_GENERATE is assumed to be zero"
-#endif
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/if.h b/datapath/linux/compat/include/linux/if.h
deleted file mode 100644
index 3beb61df1..000000000
--- a/datapath/linux/compat/include/linux/if.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __LINUX_IF_WRAPPER_H
-#define __LINUX_IF_WRAPPER_H 1
-
-#include_next <linux/if.h>
-
-#endif
diff --git a/datapath/linux/compat/include/linux/if_ether.h b/datapath/linux/compat/include/linux/if_ether.h
deleted file mode 100644
index 8dff938b7..000000000
--- a/datapath/linux/compat/include/linux/if_ether.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __LINUX_IF_ETHER_WRAPPER_H
-#define __LINUX_IF_ETHER_WRAPPER_H 1
-
-#include_next <linux/if_ether.h>
-
-#ifndef ETH_MIN_MTU
-#define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */
-#endif
-
-#ifndef ETH_MAX_MTU
-#define ETH_MAX_MTU 0xFFFFU /* 65535, same as IP_MAX_MTU */
-#endif
-
-#ifndef ETH_P_802_3_MIN
-#define ETH_P_802_3_MIN 0x0600
-#endif
-
-#ifndef ETH_P_8021AD
-#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
-#endif
-
-#ifndef ETH_P_NSH
-#define ETH_P_NSH 0x894F /* Network Service Header */
-#endif
-
-#ifndef ETH_P_ERSPAN
-#define ETH_P_ERSPAN 0x88BE /* ERSPAN TYPE II */
-#endif
-
-#ifndef ETH_P_ERSPAN2
-#define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */
-#endif
-
-#define inner_eth_hdr rpl_inner_eth_hdr
-static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb)
-{
- return (struct ethhdr *)skb_inner_mac_header(skb);
-}
-#endif
diff --git a/datapath/linux/compat/include/linux/if_link.h b/datapath/linux/compat/include/linux/if_link.h
deleted file mode 100644
index bd77e33d3..000000000
--- a/datapath/linux/compat/include/linux/if_link.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef _LINUX_IF_LINK_WRAPPER_H
-#define _LINUX_IF_LINK_WRAPPER_H
-
-#include_next<linux/if_link.h>
-
-/* GENEVE section */
-enum {
-#define IFLA_GENEVE_UNSPEC rpl_IFLA_GENEVE_UNSPEC
- IFLA_GENEVE_UNSPEC,
-
-#define IFLA_GENEVE_ID rpl_IFLA_GENEVE_ID
- IFLA_GENEVE_ID,
-
-#define IFLA_GENEVE_REMOTE rpl_IFLA_GENEVE_REMOTE
- IFLA_GENEVE_REMOTE,
-
-#define IFLA_GENEVE_TTL rpl_IFLA_GENEVE_TTL
- IFLA_GENEVE_TTL,
-
-#define IFLA_GENEVE_TOS rpl_IFLA_GENEVE_TOS
- IFLA_GENEVE_TOS,
-
-#define IFLA_GENEVE_PORT rpl_IFLA_GENEVE_PORT
- IFLA_GENEVE_PORT, /* destination port */
-
-#define IFLA_GENEVE_COLLECT_METADATA rpl_IFLA_GENEVE_COLLECT_METADATA
- IFLA_GENEVE_COLLECT_METADATA,
-
-#define IFLA_GENEVE_REMOTE6 rpl_IFLA_GENEVE_REMOTE6
- IFLA_GENEVE_REMOTE6,
-
-#define IFLA_GENEVE_UDP_CSUM rpl_IFLA_GENEVE_UDP_CSUM
- IFLA_GENEVE_UDP_CSUM,
-
-#define IFLA_GENEVE_UDP_ZERO_CSUM6_TX rpl_IFLA_GENEVE_UDP_ZERO_CSUM6_TX
- IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
-
-#define IFLA_GENEVE_UDP_ZERO_CSUM6_RX rpl_IFLA_GENEVE_UDP_ZERO_CSUM6_RX
- IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
-
-#define IFLA_GENEVE_LABEL rpl_IFLA_GENEVE_LABEL
- IFLA_GENEVE_LABEL,
-
-#define __IFLA_GENEVE_MAX rpl__IFLA_GENEVE_MAX
- __IFLA_GENEVE_MAX
-};
-#undef IFLA_GENEVE_MAX
-#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
-
-/* STT section */
-enum {
- IFLA_STT_PORT, /* destination port */
- __IFLA_STT_MAX
-};
-#define IFLA_STT_MAX (__IFLA_STT_MAX - 1)
-
-/* LISP section */
-enum {
- IFLA_LISP_PORT, /* destination port */
- __IFLA_LISP_MAX
-};
-#define IFLA_LISP_MAX (__IFLA_LISP_MAX - 1)
-
-/* VXLAN section */
-enum {
-#define IFLA_VXLAN_UNSPEC rpl_IFLA_VXLAN_UNSPEC
- IFLA_VXLAN_UNSPEC,
-#define IFLA_VXLAN_ID rpl_IFLA_VXLAN_ID
- IFLA_VXLAN_ID,
-#define IFLA_VXLAN_GROUP rpl_IFLA_VXLAN_GROUP
- IFLA_VXLAN_GROUP, /* group or remote address */
-#define IFLA_VXLAN_LINK rpl_IFLA_VXLAN_LINK
- IFLA_VXLAN_LINK,
-#define IFLA_VXLAN_LOCAL rpl_IFLA_VXLAN_LOCAL
- IFLA_VXLAN_LOCAL,
-#define IFLA_VXLAN_TTL rpl_IFLA_VXLAN_TTL
- IFLA_VXLAN_TTL,
-#define IFLA_VXLAN_TOS rpl_IFLA_VXLAN_TOS
- IFLA_VXLAN_TOS,
-#define IFLA_VXLAN_LEARNING rpl_IFLA_VXLAN_LEARNING
- IFLA_VXLAN_LEARNING,
-#define IFLA_VXLAN_AGEING rpl_IFLA_VXLAN_AGEING
- IFLA_VXLAN_AGEING,
-#define IFLA_VXLAN_LIMIT rpl_IFLA_VXLAN_LIMIT
- IFLA_VXLAN_LIMIT,
-#define IFLA_VXLAN_PORT_RANGE rpl_IFLA_VXLAN_PORT_RANGE
- IFLA_VXLAN_PORT_RANGE, /* source port */
-#define IFLA_VXLAN_PROXY rpl_IFLA_VXLAN_PROXY
- IFLA_VXLAN_PROXY,
-#define IFLA_VXLAN_RSC rpl_IFLA_VXLAN_RSC
- IFLA_VXLAN_RSC,
-#define IFLA_VXLAN_L2MISS rpl_IFLA_VXLAN_L2MISS
- IFLA_VXLAN_L2MISS,
-#define IFLA_VXLAN_L3MISS rpl_IFLA_VXLAN_L3MISS
- IFLA_VXLAN_L3MISS,
-#define IFLA_VXLAN_PORT rpl_IFLA_VXLAN_PORT
- IFLA_VXLAN_PORT, /* destination port */
-#define IFLA_VXLAN_GROUP6 rpl_IFLA_VXLAN_GROUP6
- IFLA_VXLAN_GROUP6,
-#define IFLA_VXLAN_LOCAL6 rpl_IFLA_VXLAN_LOCAL6
- IFLA_VXLAN_LOCAL6,
-#define IFLA_VXLAN_UDP_CSUM rpl_IFLA_VXLAN_UDP_CSUM
- IFLA_VXLAN_UDP_CSUM,
-#define IFLA_VXLAN_UDP_ZERO_CSUM6_TX rpl_IFLA_VXLAN_UDP_ZERO_CSUM6_TX
- IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
-#define IFLA_VXLAN_UDP_ZERO_CSUM6_RX rpl_IFLA_VXLAN_UDP_ZERO_CSUM6_RX
- IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
-#define IFLA_VXLAN_REMCSUM_TX rpl_IFLA_VXLAN_REMCSUM_TX
- IFLA_VXLAN_REMCSUM_TX,
-#define IFLA_VXLAN_REMCSUM_RX rpl_IFLA_VXLAN_REMCSUM_RX
- IFLA_VXLAN_REMCSUM_RX,
-#define IFLA_VXLAN_GBP rpl_IFLA_VXLAN_GBP
- IFLA_VXLAN_GBP,
-#define IFLA_VXLAN_REMCSUM_NOPARTIAL rpl_IFLA_VXLAN_REMCSUM_NOPARTIAL
- IFLA_VXLAN_REMCSUM_NOPARTIAL,
-#define IFLA_VXLAN_COLLECT_METADATA rpl_IFLA_VXLAN_COLLECT_METADATA
- IFLA_VXLAN_COLLECT_METADATA,
-#define IFLA_VXLAN_LABEL rpl_IFLA_VXLAN_LABEL
- IFLA_VXLAN_LABEL,
-#define IFLA_VXLAN_GPE rpl_IFLA_VXLAN_GPE
- IFLA_VXLAN_GPE,
-
-#define __IFLA_VXLAN_MAX rpl___IFLA_VXLAN_MAX
- __IFLA_VXLAN_MAX
-};
-
-#undef IFLA_VXLAN_MAX
-#define IFLA_VXLAN_MAX (rpl___IFLA_VXLAN_MAX - 1)
-
-#define ifla_vxlan_port_range rpl_ifla_vxlan_port_range
-struct ifla_vxlan_port_range {
- __be16 low;
- __be16 high;
-};
-
-#ifndef HAVE_RTNL_LINK_STATS64
-/* The main device statistics structure */
-struct rtnl_link_stats64 {
- __u64 rx_packets; /* total packets received */
- __u64 tx_packets; /* total packets transmitted */
- __u64 rx_bytes; /* total bytes received */
- __u64 tx_bytes; /* total bytes transmitted */
- __u64 rx_errors; /* bad packets received */
- __u64 tx_errors; /* packet transmit problems */
- __u64 rx_dropped; /* no space in linux buffers */
- __u64 tx_dropped; /* no space available in linux */
- __u64 multicast; /* multicast packets received */
- __u64 collisions;
-
- /* detailed rx_errors: */
- __u64 rx_length_errors;
- __u64 rx_over_errors; /* receiver ring buff overflow */
- __u64 rx_crc_errors; /* recved pkt with crc error */
- __u64 rx_frame_errors; /* recv'd frame alignment error */
- __u64 rx_fifo_errors; /* recv'r fifo overrun */
- __u64 rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
- __u64 tx_aborted_errors;
- __u64 tx_carrier_errors;
- __u64 tx_fifo_errors;
- __u64 tx_heartbeat_errors;
- __u64 tx_window_errors;
-
- /* for cslip etc */
- __u64 rx_compressed;
- __u64 tx_compressed;
-};
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/if_vlan.h b/datapath/linux/compat/include/linux/if_vlan.h
deleted file mode 100644
index 3ed7522c7..000000000
--- a/datapath/linux/compat/include/linux/if_vlan.h
+++ /dev/null
@@ -1,306 +0,0 @@
-#ifndef __LINUX_IF_VLAN_WRAPPER_H
-#define __LINUX_IF_VLAN_WRAPPER_H 1
-
-#include <linux/skbuff.h>
-#include <linux/version.h>
-#include_next <linux/if_vlan.h>
-
-#ifndef HAVE_VLAN_INSERT_TAG_SET_PROTO
-/*
- * The behavior of __vlan_put_tag()/vlan_insert_tag_set_proto() has changed
- * over time:
- *
- * - In 2.6.26 and earlier, it adjusted both MAC and network header
- * pointers. (The latter didn't make any sense.)
- *
- * - In 2.6.27 and 2.6.28, it did not adjust any header pointers at all.
- *
- * - In 2.6.29 and later, it adjusts the MAC header pointer only.
- *
- * - In 3.19 and later, it was renamed to vlan_insert_tag_set_proto()
- *
- * This is the version from 2.6.33. We unconditionally substitute this version
- * to avoid the need to guess whether the version in the kernel tree is
- * acceptable.
- */
-#define vlan_insert_tag_set_proto(skb, proto, vlan_tci) \
- rpl_vlan_insert_tag_set_proto(skb, proto, vlan_tci)
-static inline struct sk_buff *rpl_vlan_insert_tag_set_proto(struct sk_buff *skb,
- __be16 vlan_proto,
- u16 vlan_tci)
-{
- struct vlan_ethhdr *veth;
-
- if (skb_cow_head(skb, VLAN_HLEN) < 0) {
- kfree_skb(skb);
- return NULL;
- }
- veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
-
- /* Move the mac addresses to the beginning of the new header. */
- memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
- skb->mac_header -= VLAN_HLEN;
-
- /* first, the ethernet type */
- veth->h_vlan_proto = vlan_proto;
-
- /* now, the TCI */
- veth->h_vlan_TCI = htons(vlan_tci);
-
- skb->protocol = vlan_proto;
-
- return skb;
-}
-#endif
-
-#ifndef HAVE_VLAN_HWACCEL_CLEAR_TAG
-/**
- * __vlan_hwaccel_clear_tag - clear hardware accelerated VLAN info
- * @skb: skbuff to clear
- *
- * Clears the VLAN information from @skb
- */
-#define __vlan_hwaccel_clear_tag rpl_vlan_hwaccel_clear_tag
-static inline void rpl_vlan_hwaccel_clear_tag(struct sk_buff *skb)
-{
-#ifdef HAVE_SKBUFF_VLAN_PRESENT
- skb->vlan_present = 0;
-#else
- skb->vlan_tci = 0;
- skb->vlan_proto = 0;
-#endif
-}
-#endif
-
-#ifndef HAVE_VLAN_HWACCEL_PUSH_INSIDE
-
-/*
- * __vlan_hwaccel_push_inside - pushes vlan tag to the payload
- * @skb: skbuff to tag
- *
- * Pushes the VLAN tag from @skb->vlan_tci inside to the payload.
- *
- * Following the skb_unshare() example, in case of error, the calling function
- * doesn't have to worry about freeing the original skb.
- */
-static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
-{
- skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
- vlan_tx_tag_get(skb));
- if (likely(skb))
- skb->vlan_tci = 0;
- return skb;
-}
-/*
- * vlan_hwaccel_push_inside - pushes vlan tag to the payload
- * @skb: skbuff to tag
- *
- * Checks is tag is present in @skb->vlan_tci and if it is, it pushes the
- * VLAN tag from @skb->vlan_tci inside to the payload.
- *
- * Following the skb_unshare() example, in case of error, the calling function
- * doesn't have to worry about freeing the original skb.
- */
-static inline struct sk_buff *vlan_hwaccel_push_inside(struct sk_buff *skb)
-{
- if (vlan_tx_tag_present(skb))
- skb = __vlan_hwaccel_push_inside(skb);
- return skb;
-}
-#endif
-
-#ifndef HAVE_ETH_TYPE_VLAN
-/**
- * eth_type_vlan - check for valid vlan ether type.
- * @ethertype: ether type to check
- *
- * Returns true if the ether type is a vlan ether type.
- */
-static inline bool eth_type_vlan(__be16 ethertype)
-{
- switch (ethertype) {
- case htons(ETH_P_8021Q):
- case htons(ETH_P_8021AD):
- return true;
- default:
- return false;
- }
-}
-#endif
-
-/* All of these were introduced in a single commit preceding 2.6.33, so
- * presumably all of them or none of them are present. */
-#ifndef VLAN_PRIO_MASK
-#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */
-#define VLAN_PRIO_SHIFT 13
-#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */
-#define VLAN_TAG_PRESENT VLAN_CFI_MASK
-#endif
-
-#ifndef HAVE_VLAN_SET_ENCAP_PROTO
-static inline void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr)
-{
- __be16 proto;
- unsigned char *rawp;
-
- /*
- * Was a VLAN packet, grab the encapsulated protocol, which the layer
- * three protocols care about.
- */
-
- proto = vhdr->h_vlan_encapsulated_proto;
- if (ntohs(proto) >= 1536) {
- skb->protocol = proto;
- return;
- }
-
- rawp = skb->data;
- if (*(unsigned short *) rawp == 0xFFFF)
- /*
- * This is a magic hack to spot IPX packets. Older Novell
- * breaks the protocol design and runs IPX over 802.3 without
- * an 802.2 LLC layer. We look for FFFF which isn't a used
- * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
- * but does for the rest.
- */
- skb->protocol = htons(ETH_P_802_3);
- else
- /*
- * Real 802.2 LLC
- */
- skb->protocol = htons(ETH_P_802_2);
-}
-#endif
-
-#ifndef HAVE___VLAN_INSERT_TAG
-/* Kernels which don't have __vlan_insert_tag() also don't have skb->vlan_proto
- * so ignore the proto paramter.
- */
-#define __vlan_insert_tag(skb, proto, tci) rpl_vlan_insert_tag(skb, tci)
-static inline int rpl_vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci)
-{
- struct vlan_ethhdr *veth;
-
- if (skb_cow_head(skb, VLAN_HLEN) < 0)
- return -ENOMEM;
-
- veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
-
- /* Move the mac addresses to the beginning of the new header. */
- memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
- skb->mac_header -= VLAN_HLEN;
-
- /* first, the ethernet type */
- veth->h_vlan_proto = htons(ETH_P_8021Q);
-
- /* now, the TCI */
- veth->h_vlan_TCI = htons(vlan_tci);
-
- return 0;
-}
-#endif
-
-#ifndef skb_vlan_tag_present
-#define skb_vlan_tag_present(skb) vlan_tx_tag_present(skb)
-#define skb_vlan_tag_get(skb) vlan_tx_tag_get(skb)
-#endif
-
-#ifndef HAVE_VLAN_GET_PROTOCOL
-
-static inline __be16 __vlan_get_protocol(struct sk_buff *skb, __be16 type,
- int *depth)
-{
- unsigned int vlan_depth = skb->mac_len;
-
- /* if type is 802.1Q/AD then the header should already be
- * present at mac_len - VLAN_HLEN (if mac_len > 0), or at
- * ETH_HLEN otherwise
- */
- if (eth_type_vlan(type)) {
- if (vlan_depth) {
- if (WARN_ON(vlan_depth < VLAN_HLEN))
- return 0;
- vlan_depth -= VLAN_HLEN;
- } else {
- vlan_depth = ETH_HLEN;
- }
- do {
- struct vlan_hdr *vh;
-
- if (unlikely(!pskb_may_pull(skb,
- vlan_depth + VLAN_HLEN)))
- return 0;
-
- vh = (struct vlan_hdr *)(skb->data + vlan_depth);
- type = vh->h_vlan_encapsulated_proto;
- vlan_depth += VLAN_HLEN;
- } while (eth_type_vlan(type));
- }
-
- if (depth)
- *depth = vlan_depth;
-
- return type;
-}
-
-/**
- * vlan_get_protocol - get protocol EtherType.
- * @skb: skbuff to query
- *
- * Returns the EtherType of the packet, regardless of whether it is
- * vlan encapsulated (normal or hardware accelerated) or not.
- */
-static inline __be16 vlan_get_protocol(struct sk_buff *skb)
-{
- return __vlan_get_protocol(skb, skb->protocol, NULL);
-}
-
-#endif
-
-#ifndef HAVE_SKB_VLAN_TAGGED
-/**
- * skb_vlan_tagged - check if skb is vlan tagged.
- * @skb: skbuff to query
- *
- * Returns true if the skb is tagged, regardless of whether it is hardware
- * accelerated or not.
- */
-static inline bool skb_vlan_tagged(const struct sk_buff *skb)
-{
- if (!skb_vlan_tag_present(skb) &&
- likely(!eth_type_vlan(skb->protocol)))
- return false;
-
- return true;
-}
-
-/**
- * skb_vlan_tagged_multi - check if skb is vlan tagged with multiple headers.
- * @skb: skbuff to query
- *
- * Returns true if the skb is tagged with multiple vlan headers, regardless
- * of whether it is hardware accelerated or not.
- */
-static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
-{
- __be16 protocol = skb->protocol;
-
- if (!skb_vlan_tag_present(skb)) {
- struct vlan_ethhdr *veh;
-
- if (likely(!eth_type_vlan(protocol)))
- return false;
-
- veh = (struct vlan_ethhdr *)skb->data;
- protocol = veh->h_vlan_encapsulated_proto;
- }
-
- if (!eth_type_vlan(protocol))
- return false;
-
- return true;
-}
-
-#endif /* HAVE_SKB_VLAN_TAGGED */
-
-#endif /* linux/if_vlan.h wrapper */
diff --git a/datapath/linux/compat/include/linux/in.h b/datapath/linux/compat/include/linux/in.h
deleted file mode 100644
index 78f8d7731..000000000
--- a/datapath/linux/compat/include/linux/in.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __LINUX_IN_WRAPPER_H
-#define __LINUX_IN_WRAPPER_H 1
-
-#include_next <linux/in.h>
-
-#include <linux/module.h>
-#ifndef HAVE_PROTO_PORTS_OFFSET
-static inline int proto_ports_offset(int proto)
-{
- switch (proto) {
- case IPPROTO_TCP:
- case IPPROTO_UDP:
- case IPPROTO_DCCP:
- case IPPROTO_ESP: /* SPI */
- case IPPROTO_SCTP:
- case IPPROTO_UDPLITE:
- return 0;
- case IPPROTO_AH: /* SPI */
- return 4;
- default:
- return -EINVAL;
- }
-}
-#endif
-
-#ifndef HAVE_IPV4_IS_MULTICAST
-
-static inline bool ipv4_is_loopback(__be32 addr)
-{
- return (addr & htonl(0xff000000)) == htonl(0x7f000000);
-}
-
-static inline bool ipv4_is_multicast(__be32 addr)
-{
- return (addr & htonl(0xf0000000)) == htonl(0xe0000000);
-}
-
-static inline bool ipv4_is_local_multicast(__be32 addr)
-{
- return (addr & htonl(0xffffff00)) == htonl(0xe0000000);
-}
-
-static inline bool ipv4_is_lbcast(__be32 addr)
-{
- /* limited broadcast */
- return addr == htonl(INADDR_BROADCAST);
-}
-
-static inline bool ipv4_is_zeronet(__be32 addr)
-{
- return (addr & htonl(0xff000000)) == htonl(0x00000000);
-}
-
-#endif /* !HAVE_IPV4_IS_MULTICAST */
-
-#endif
diff --git a/datapath/linux/compat/include/linux/jiffies.h b/datapath/linux/compat/include/linux/jiffies.h
deleted file mode 100644
index 642eacec7..000000000
--- a/datapath/linux/compat/include/linux/jiffies.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __LINUX_JIFFIES_WRAPPER_H
-#define __LINUX_JIFFIES_WRAPPER_H 1
-
-#include_next <linux/jiffies.h>
-
-#include <linux/version.h>
-
-/* Same as above, but does so with platform independent 64bit types.
- * These must be used when utilizing jiffies_64 (i.e. return value of
- * get_jiffies_64() */
-
-#ifndef time_after64
-#define time_after64(a, b) \
- (typecheck(__u64, a) && \
- typecheck(__u64, b) && \
- ((__s64)(b) - (__s64)(a) < 0))
-#endif
-
-#ifndef time_before64
-#define time_before64(a, b) time_after64(b, a)
-#endif
-
-#ifndef time_after_eq64
-#define time_after_eq64(a, b) \
- (typecheck(__u64, a) && \
- typecheck(__u64, b) && \
- ((__s64)(a) - (__s64)(b) >= 0))
-#endif
-
-#ifndef time_before_eq64
-#define time_before_eq64(a, b) time_after_eq64(b, a)
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/kconfig.h b/datapath/linux/compat/include/linux/kconfig.h
deleted file mode 100644
index d3fa57a6b..000000000
--- a/datapath/linux/compat/include/linux/kconfig.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef __LINUX_KCONFIG_WRAPPER_H
-#define __LINUX_KCONFIG_WRAPPER_H
-
-#include <linux/version.h>
-
-#ifndef IS_ENABLED
-
-/*
- * Helper macros to use CONFIG_ options in C/CPP expressions. Note that
- * these only work with boolean and tristate options.
- */
-
-/*
- * Getting something that works in C and CPP for an arg that may or may
- * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1"
- * we match on the placeholder define, insert the "0," for arg1 and generate
- * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one).
- * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
- * the last step cherry picks the 2nd arg, we get a zero.
- */
-#define __ARG_PLACEHOLDER_1 0,
-#define config_enabled(cfg) _config_enabled(cfg)
-#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
-#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
-#define ___config_enabled(__ignored, val, ...) val
-
-/*
- * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
- * 0 otherwise.
- *
- */
-#define IS_ENABLED(option) \
- (config_enabled(option) || config_enabled(option##_MODULE))
-
-/*
- * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
- * otherwise. For boolean options, this is equivalent to
- * IS_ENABLED(CONFIG_FOO).
- */
-#define IS_BUILTIN(option) config_enabled(option)
-
-/*
- * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
- * otherwise.
- */
-#define IS_MODULE(option) config_enabled(option##_MODULE)
-
-#endif /* IS_ENABLED */
-#endif /* __LINUX_KCONFIG_WRAPER_H */
diff --git a/datapath/linux/compat/include/linux/kernel.h b/datapath/linux/compat/include/linux/kernel.h
deleted file mode 100644
index 106b5940a..000000000
--- a/datapath/linux/compat/include/linux/kernel.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __KERNEL_H_WRAPPER
-#define __KERNEL_H_WRAPPER 1
-
-#include_next <linux/kernel.h>
-#ifndef HAVE_LOG2_H
-#include <linux/log2.h>
-#endif
-
-#include <linux/version.h>
-
-#ifndef USHRT_MAX
-#define USHRT_MAX ((u16)(~0U))
-#define SHRT_MAX ((s16)(USHRT_MAX>>1))
-#define SHRT_MIN ((s16)(-SHRT_MAX - 1))
-#endif
-
-#ifndef DIV_ROUND_UP
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
-#endif
-
-#ifndef rounddown
-#define rounddown(x, y) ( \
-{ \
- typeof(x) __x = (x); \
- __x - (__x % (y)); \
-} \
-)
-#endif
-
-/* U32_MAX was introduced in include/linux/kernel.h after version 3.14. */
-#ifndef U32_MAX
-#define U32_MAX ((u32)~0U)
-#endif
-
-#ifndef sizeof_field
-#define sizeof_field(t, f) (sizeof(((t*)0)->f))
-#endif
-
-#endif /* linux/kernel.h */
diff --git a/datapath/linux/compat/include/linux/list.h b/datapath/linux/compat/include/linux/list.h
deleted file mode 100644
index 4234c17ce..000000000
--- a/datapath/linux/compat/include/linux/list.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __LINUX_LIST_WRAPPER_H
-#define __LINUX_LIST_WRAPPER_H 1
-
-#include_next <linux/list.h>
-
-#ifndef hlist_entry_safe
-#define hlist_entry_safe(ptr, type, member) \
- ({ typeof(ptr) ____ptr = (ptr); \
- ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
- })
-
-#undef hlist_for_each_entry
-#define hlist_for_each_entry(pos, head, member) \
- for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
- pos; \
- pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-#undef hlist_for_each_entry_safe
-#define hlist_for_each_entry_safe(pos, n, head, member) \
- for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
- pos && ({ n = pos->member.next; 1; }); \
- pos = hlist_entry_safe(n, typeof(*pos), member))
-
-#endif
-
-#ifndef list_first_entry_or_null
-#define list_first_entry_or_null(ptr, type, member) \
- (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/mm.h b/datapath/linux/compat/include/linux/mm.h
deleted file mode 100644
index 681f3db89..000000000
--- a/datapath/linux/compat/include/linux/mm.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef OVS_MM_H
-#define OVS_MM_H
-
-#include <linux/overflow.h>
-
-#ifndef HAVE_KVMALLOC_ARRAY
-#ifndef HAVE_KVMALLOC_NODE
-extern void *vmalloc_node(unsigned long size, int node);
-#define kvmalloc_node(a, b, c) vmalloc_node(a, c)
-#else
-extern void *kvmalloc_node(size_t size, gfp_t flags, int node);
-#endif /* HAVE_KVMALLOC_NODE */
-static inline void *kvmalloc(size_t size, gfp_t flags)
-{
- return kvmalloc_node(size, flags, NUMA_NO_NODE);
-}
-static inline void *kvzalloc_node(size_t size, gfp_t flags, int node)
-{
- return kvmalloc_node(size, flags | __GFP_ZERO, node);
-}
-static inline void *kvzalloc(size_t size, gfp_t flags)
-{
- return kvmalloc(size, flags | __GFP_ZERO);
-}
-
-static inline void *kvmalloc_array(size_t n, size_t size, gfp_t flags)
-{
- size_t bytes;
-
- if (unlikely(check_mul_overflow(n, size, &bytes)))
- return NULL;
-
- return kvmalloc(bytes, flags);
-}
-
-static inline void *kvcalloc(size_t n, size_t size, gfp_t flags)
-{
- return kvmalloc_array(n, size, flags | __GFP_ZERO);
-}
-
-#endif
-#include_next <linux/mm.h>
-#endif /* OVS_MM_H */
-
diff --git a/datapath/linux/compat/include/linux/mpls.h b/datapath/linux/compat/include/linux/mpls.h
deleted file mode 100644
index ab99ebc30..000000000
--- a/datapath/linux/compat/include/linux/mpls.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _UAPI_MPLS_WRAPPER_H
-#define _UAPI_MPLS_WRAPPER_H
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0)
-#include_next <linux/mpls.h>
-#else
-
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-/* Reference: RFC 5462, RFC 3032
- *
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Label | TC |S| TTL |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Label: Label Value, 20 bits
- * TC: Traffic Class field, 3 bits
- * S: Bottom of Stack, 1 bit
- * TTL: Time to Live, 8 bits
- */
-
-struct mpls_label {
- __be32 entry;
-};
-
-#define MPLS_LS_LABEL_MASK 0xFFFFF000
-#define MPLS_LS_LABEL_SHIFT 12
-#define MPLS_LS_TC_MASK 0x00000E00
-#define MPLS_LS_TC_SHIFT 9
-#define MPLS_LS_S_MASK 0x00000100
-#define MPLS_LS_S_SHIFT 8
-#define MPLS_LS_TTL_MASK 0x000000FF
-#define MPLS_LS_TTL_SHIFT 0
-#endif
-
-#endif /* _UAPI_MPLS_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/net.h b/datapath/linux/compat/include/linux/net.h
deleted file mode 100644
index 2a6903d0a..000000000
--- a/datapath/linux/compat/include/linux/net.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __LINUX_NET_WRAPPER_H
-#define __LINUX_NET_WRAPPER_H 1
-
-#include_next <linux/net.h>
-#include <linux/types.h>
-
-#ifndef net_ratelimited_function
-#define net_ratelimited_function(function, ...) \
-do { \
- if (net_ratelimit()) \
- function(__VA_ARGS__); \
-} while (0)
-
-#define net_emerg_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_emerg, fmt, ##__VA_ARGS__)
-#define net_alert_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_alert, fmt, ##__VA_ARGS__)
-#define net_crit_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_crit, fmt, ##__VA_ARGS__)
-#define net_err_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_err, fmt, ##__VA_ARGS__)
-#define net_notice_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_notice, fmt, ##__VA_ARGS__)
-#define net_warn_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_warn, fmt, ##__VA_ARGS__)
-#define net_info_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_info, fmt, ##__VA_ARGS__)
-#define net_dbg_ratelimited(fmt, ...) \
- net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
-#endif
-
-#ifndef net_get_random_once
-#define __net_get_random_once rpl___net_get_random_once
-bool rpl___net_get_random_once(void *buf, int nbytes, bool *done,
- atomic_t *done_key);
-
-#define ___NET_RANDOM_STATIC_KEY_INIT ATOMIC_INIT(0)
-
-
-#define net_get_random_once(buf, nbytes) \
-({ \
- bool ___ret = false; \
- static bool ___done = false; \
- static atomic_t ___done_key = \
- ___NET_RANDOM_STATIC_KEY_INIT; \
- if (!atomic_read(&___done_key)) \
- ___ret = __net_get_random_once(buf, \
- nbytes, \
- &___done, \
- &___done_key); \
- ___ret; \
-})
-#endif
-
-#ifndef HAVE_SOCK_CREATE_KERN_NET
-int ovs_sock_create_kern(struct net *net, int family, int type, int protocol, struct socket **res);
-void ovs_sock_release(struct socket *sock);
-#define sock_create_kern ovs_sock_create_kern
-#define sock_release ovs_sock_release
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/netdev_features.h b/datapath/linux/compat/include/linux/netdev_features.h
deleted file mode 100644
index 411f2949b..000000000
--- a/datapath/linux/compat/include/linux/netdev_features.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef __LINUX_NETDEV_FEATURES_WRAPPER_H
-#define __LINUX_NETDEV_FEATURES_WRAPPER_H
-
-#include_next <linux/netdev_features.h>
-
-#ifndef NETIF_F_GSO_GRE
-#define NETIF_F_GSO_GRE 0
-#endif
-
-#ifndef NETIF_F_GSO_GRE_CSUM
-#define NETIF_F_GSO_GRE_CSUM 0
-#else
-#define HAVE_NETIF_F_GSO_GRE_CSUM
-#endif
-
-#ifndef NETIF_F_GSO_IPIP
-#define NETIF_F_GSO_IPIP 0
-#endif
-
-#ifndef NETIF_F_GSO_SIT
-#define NETIF_F_GSO_SIT 0
-#endif
-
-#ifndef NETIF_F_CSUM_MASK
-#define NETIF_F_CSUM_MASK 0
-#endif
-
-#ifndef NETIF_F_GSO_UDP_TUNNEL
-#define NETIF_F_GSO_UDP_TUNNEL 0
-#else
-#define HAVE_NETIF_F_GSO_UDP_TUNNEL 0
-#endif
-
-#ifndef NETIF_F_GSO_UDP_TUNNEL_CSUM
-#define NETIF_F_GSO_UDP_TUNNEL_CSUM 0
-#define SKB_GSO_UDP_TUNNEL_CSUM 0
-#endif
-
-#ifndef NETIF_F_GSO_MPLS
-#define NETIF_F_GSO_MPLS 0
-#endif
-
-#ifndef NETIF_F_HW_VLAN_STAG_TX
-#define NETIF_F_HW_VLAN_STAG_TX 0
-#endif
-
-#ifndef NETIF_F_GSO_TUNNEL_REMCSUM
-#define NETIF_F_GSO_TUNNEL_REMCSUM 0
-#define SKB_GSO_TUNNEL_REMCSUM 0
-#else
-/* support for REM_CSUM is added in 3.19 but API are not defined
- * till 4.0, so turn on REMSUM support on kernel 4.0 onwards.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
-#define HAVE_NETIF_F_GSO_TUNNEL_REMCSUM
-#endif
-#endif
-
-#ifndef NETIF_F_RXCSUM
-#define NETIF_F_RXCSUM 0
-#endif
-
-#ifndef NETIF_F_GSO_ENCAP_ALL
-#define NETIF_F_GSO_ENCAP_ALL (NETIF_F_GSO_GRE | \
- NETIF_F_GSO_GRE_CSUM | \
- NETIF_F_GSO_IPIP | \
- NETIF_F_GSO_SIT | \
- NETIF_F_GSO_UDP_TUNNEL | \
- NETIF_F_GSO_UDP_TUNNEL_CSUM | \
- NETIF_F_GSO_MPLS)
-#endif
-
-#ifndef HAVE_NETIF_F_GSO_GRE_CSUM
-#define SKB_GSO_GRE_CSUM 0
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h
deleted file mode 100644
index 126ff23cf..000000000
--- a/datapath/linux/compat/include/linux/netdevice.h
+++ /dev/null
@@ -1,336 +0,0 @@
-#ifndef __LINUX_NETDEVICE_WRAPPER_H
-#define __LINUX_NETDEVICE_WRAPPER_H 1
-
-#include_next <linux/netdevice.h>
-#include <linux/if_bridge.h>
-
-struct net;
-
-#include <linux/version.h>
-
-#ifndef IFF_TX_SKB_SHARING
-#define IFF_TX_SKB_SHARING 0
-#endif
-
-#ifndef IFF_OVS_DATAPATH
-#define IFF_OVS_DATAPATH 0
-#else
-#define HAVE_OVS_DATAPATH
-#endif
-
-#ifndef IFF_LIVE_ADDR_CHANGE
-#define IFF_LIVE_ADDR_CHANGE 0
-#endif
-
-#ifndef IFF_OPENVSWITCH
-#define IFF_OPENVSWITCH 0
-#endif
-
-#ifndef to_net_dev
-#define to_net_dev(class) container_of(class, struct net_device, NETDEV_DEV_MEMBER)
-#endif
-
-#ifndef HAVE_NET_NAME_UNKNOWN
-#undef alloc_netdev
-#define NET_NAME_UNKNOWN 0
-#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
- alloc_netdev_mq(sizeof_priv, name, setup, 1)
-#endif
-
-#ifndef HAVE_DEV_DISABLE_LRO
-extern void dev_disable_lro(struct net_device *dev);
-#endif
-
-#ifndef HAVE_DEV_GET_BY_INDEX_RCU
-static inline struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)
-{
- struct net_device *dev;
-
- read_lock(&dev_base_lock);
- dev = __dev_get_by_index(net, ifindex);
- read_unlock(&dev_base_lock);
-
- return dev;
-}
-#endif
-
-#ifndef NETIF_F_FSO
-#define NETIF_F_FSO 0
-#endif
-
-#ifndef HAVE_NETDEV_FEATURES_T
-typedef u32 netdev_features_t;
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
-#define OVS_USE_COMPAT_GSO_SEGMENTATION
-#endif
-
-#ifdef OVS_USE_COMPAT_GSO_SEGMENTATION
-/* define compat version to handle MPLS segmentation offload. */
-#define __skb_gso_segment rpl__skb_gso_segment
-struct sk_buff *rpl__skb_gso_segment(struct sk_buff *skb,
- netdev_features_t features,
- bool tx_path);
-
-#define skb_gso_segment rpl_skb_gso_segment
-static inline
-struct sk_buff *rpl_skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
-{
- return rpl__skb_gso_segment(skb, features, true);
-}
-#endif
-
-#ifdef HAVE_NETIF_NEEDS_GSO_NETDEV
-#define netif_needs_gso rpl_netif_needs_gso
-static inline bool netif_needs_gso(struct sk_buff *skb,
- netdev_features_t features)
-{
- return skb_is_gso(skb) && (!skb_gso_ok(skb, features) ||
- unlikely((skb->ip_summed != CHECKSUM_PARTIAL) &&
- (skb->ip_summed != CHECKSUM_UNNECESSARY)));
-}
-#endif
-
-#ifndef HAVE_NETDEV_MASTER_UPPER_DEV_LINK_PRIV
-#ifndef HAVE_NETDEV_MASTER_UPPER_DEV_LINK_RH
-static inline int rpl_netdev_master_upper_dev_link(struct net_device *dev,
- struct net_device *upper_dev,
- void *upper_priv,
- void *upper_info, void *extack)
-{
- return netdev_master_upper_dev_link(dev, upper_dev);
-}
-#define netdev_master_upper_dev_link rpl_netdev_master_upper_dev_link
-#else /* #ifndef HAVE_NETDEV_MASTER_UPPER_DEV_LINK_RH */
-static inline int rpl_netdev_master_upper_dev_link(struct net_device *dev,
- struct net_device *upper_dev,
- void *upper_priv,
- void *upper_info, void *extack)
-{
- return netdev_master_upper_dev_link(dev, upper_dev,
- upper_priv, upper_info);
-}
-#undef netdev_master_upper_dev_link
-#define netdev_master_upper_dev_link rpl_netdev_master_upper_dev_link
-#endif /* #else HAVE_NETDEV_MASTER_UPPER_DEV_LINK_RH */
-#else /* #ifndef HAVE_NETDEV_MASTER_UPPER_DEV_LINK_PRIV */
-#ifndef HAVE_UPPER_DEV_LINK_EXTACK
-static inline int rpl_netdev_master_upper_dev_link(struct net_device *dev,
- struct net_device *upper_dev,
- void *upper_priv,
- void *upper_info, void *extack)
-{
- return netdev_master_upper_dev_link(dev, upper_dev, upper_priv,
- upper_info);
-}
-#define netdev_master_upper_dev_link rpl_netdev_master_upper_dev_link
-#endif /* #ifndef HAVE_UPPER_DEV_LINK_EXTACK */
-#endif /* #else HAVE_NETDEV_MASTER_UPPER_DEV_LINK_PRIV */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
-#define dev_queue_xmit rpl_dev_queue_xmit
-int rpl_dev_queue_xmit(struct sk_buff *skb);
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
-static inline struct net_device *rpl_netdev_notifier_info_to_dev(void *info)
-{
- return info;
-}
-#define netdev_notifier_info_to_dev rpl_netdev_notifier_info_to_dev
-#endif
-
-#ifndef HAVE_PCPU_SW_NETSTATS
-#define pcpu_sw_netstats pcpu_tstats
-#endif
-
-#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0)
-/* Use compat version for all redhas releases */
-#undef netdev_alloc_pcpu_stats
-#endif
-
-#ifndef netdev_alloc_pcpu_stats
-#define netdev_alloc_pcpu_stats(type) \
-({ \
- typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \
- if (pcpu_stats) { \
- int ____i; \
- for_each_possible_cpu(____i) { \
- typeof(type) *stat; \
- stat = per_cpu_ptr(pcpu_stats, ____i); \
- u64_stats_init(&stat->syncp); \
- } \
- } \
- pcpu_stats; \
-})
-#endif
-
-#ifndef HAVE_DEV_RECURSION_LEVEL
-static inline bool dev_recursion_level(void) { return false; }
-#endif
-
-#ifndef NET_NAME_USER
-#define NET_NAME_USER 3
-#endif
-
-#ifndef HAVE_GRO_REMCSUM
-struct gro_remcsum {
-};
-
-#define skb_gro_remcsum_init(grc)
-#define skb_gro_remcsum_cleanup(a1, a2)
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0)
-
-#define skb_gro_remcsum_process rpl_skb_gro_remcsum_process
-static inline void *skb_gro_remcsum_process(struct sk_buff *skb, void *ptr,
- unsigned int off, size_t hdrlen,
- int start, int offset,
- struct gro_remcsum *grc,
- bool nopartial)
-{
- __wsum delta;
- size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start);
-
- BUG_ON(!NAPI_GRO_CB(skb)->csum_valid);
-
- if (!nopartial) {
- NAPI_GRO_CB(skb)->gro_remcsum_start = off + hdrlen + start;
- return ptr;
- }
-
- ptr = skb_gro_header_fast(skb, off);
- if (skb_gro_header_hard(skb, off + plen)) {
- ptr = skb_gro_header_slow(skb, off + plen, off);
- if (!ptr)
- return NULL;
- }
-
- delta = remcsum_adjust(ptr + hdrlen, NAPI_GRO_CB(skb)->csum,
- start, offset);
-
- /* Adjust skb->csum since we changed the packet */
- NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta);
-
- grc->offset = off + hdrlen + offset;
- grc->delta = delta;
-
- return ptr;
-}
-#endif
-#endif
-
-#ifndef HAVE_RTNL_LINK_STATS64
-#define dev_get_stats rpl_dev_get_stats
-struct rtnl_link_stats64 *rpl_dev_get_stats(struct net_device *dev,
- struct rtnl_link_stats64 *storage);
-#endif
-
-#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)
-/* Only required on RHEL 6. */
-#define dev_get_stats dev_get_stats64
-#endif
-
-#ifndef netdev_dbg
-#define netdev_dbg(__dev, format, args...) \
-do { \
- printk(KERN_DEBUG "%s ", __dev->name); \
- printk(KERN_DEBUG format, ##args); \
-} while (0)
-#endif
-
-#ifndef netdev_info
-#define netdev_info(__dev, format, args...) \
-do { \
- printk(KERN_INFO "%s ", __dev->name); \
- printk(KERN_INFO format, ##args); \
-} while (0)
-
-#endif
-
-#ifndef USE_UPSTREAM_TUNNEL
-#define dev_fill_metadata_dst ovs_dev_fill_metadata_dst
-int ovs_dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-#endif
-
-#ifndef NETDEV_OFFLOAD_PUSH_VXLAN
-#define NETDEV_OFFLOAD_PUSH_VXLAN 0x001C
-#endif
-
-#ifndef NETDEV_OFFLOAD_PUSH_GENEVE
-#define NETDEV_OFFLOAD_PUSH_GENEVE 0x001D
-#endif
-
-#ifndef HAVE_IFF_PHONY_HEADROOM
-
-#define IFF_PHONY_HEADROOM 0
-static inline unsigned netdev_get_fwd_headroom(struct net_device *dev)
-{
- return 0;
-}
-
-static inline void netdev_set_rx_headroom(struct net_device *dev, int new_hr)
-{
-}
-
-/* set the device rx headroom to the dev's default */
-static inline void netdev_reset_rx_headroom(struct net_device *dev)
-{
-}
-
-#endif
-
-#ifdef IFF_NO_QUEUE
-#define HAVE_IFF_NO_QUEUE
-#else
-#define IFF_NO_QUEUE 0
-#endif
-
-#ifndef HAVE_SKB_CSUM_HWOFFLOAD_HELP
-static inline int skb_csum_hwoffload_help(struct sk_buff *skb,
- const netdev_features_t features)
-{
- /* It's less accurate to approximate to this for older kernels, but
- * it was sufficient for a long time. If you care about ensuring that
- * upstream commit 7529390d08f0 has the same effect on older kernels,
- * consider backporting the following commits:
- * b72b5bf6a8fc ("net: introduce skb_crc32c_csum_help")
- * 43c26a1a4593 ("net: more accurate checksumming in validate_xmit_skb()")
- */
- return skb_checksum_help(skb);
-}
-#endif
-
-#ifndef HAVE_SKB_GSO_ERROR_UNWIND
-static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol,
- int pulled_hlen, u16 mac_offset,
- int mac_len)
-{
- skb->protocol = protocol;
- skb->encapsulation = 1;
- skb_push(skb, pulled_hlen);
- skb_reset_transport_header(skb);
- skb->mac_header = mac_offset;
- skb->network_header = skb->mac_header + mac_len;
- skb->mac_len = mac_len;
-}
-#endif
-
-#ifndef HAVE_NETIF_KEEP_DST
-static inline void netif_keep_dst(struct net_device *dev)
-{
-}
-#endif
-
-#ifndef HAVE_DEV_CHANGE_FLAGS_TAKES_EXTACK
-static inline int rpl_dev_change_flags(struct net_device *dev,
- unsigned int flags,
- struct netlink_ext_ack *extack)
-{
- return dev_change_flags(dev, flags);
-}
-#define dev_change_flags rpl_dev_change_flags
-#endif
-
-#endif /* __LINUX_NETDEVICE_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/netfilter.h b/datapath/linux/compat/include/linux/netfilter.h
deleted file mode 100644
index a6ed6172d..000000000
--- a/datapath/linux/compat/include/linux/netfilter.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __NETFILTER_WRAPPER_H
-#define __NETFILTER_WRAPPER_H
-
-#include_next <linux/netfilter.h>
-
-#if !defined(HAVE_NF_HOOK_STATE) || !defined(HAVE_NF_HOOK_STATE_NET)
-struct rpl_nf_hook_state {
- unsigned int hook;
- u_int8_t pf;
- struct net_device *in;
- struct net_device *out;
- struct sock *sk;
- struct net *net;
- int (*okfn)(struct net *, struct sock *, struct sk_buff *);
-};
-#define nf_hook_state rpl_nf_hook_state
-#endif
-
-#endif /* __NETFILTER_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/netfilter_ipv6.h b/datapath/linux/compat/include/linux/netfilter_ipv6.h
deleted file mode 100644
index 8d896fbc5..000000000
--- a/datapath/linux/compat/include/linux/netfilter_ipv6.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __NETFILTER_IPV6_WRAPPER_H
-#define __NETFILTER_IPV6_WRAPPER_H 1
-
-#include_next <linux/netfilter_ipv6.h>
-
-#include <linux/version.h>
-#include <net/ip.h> /* For OVS_VPORT_OUTPUT_PARAMS */
-#include <net/ip6_route.h>
-
-#ifndef HAVE_NF_IPV6_OPS_FRAGMENT
-/* Try to minimise changes required to the actions.c code for calling IPv6
- * fragmentation. We can keep the fragment() API mostly the same, except that
- * the callback parameter needs to be in the form that older kernels accept.
- * We don't backport the other ipv6_ops as they're currently unused by OVS. */
-struct ovs_nf_ipv6_ops {
- int (*fragment)(struct sock *sk, struct sk_buff *skb,
- int (*output)(OVS_VPORT_OUTPUT_PARAMS));
-};
-#define nf_ipv6_ops ovs_nf_ipv6_ops
-
-static struct ovs_nf_ipv6_ops ovs_ipv6_ops = {
- .fragment = ip6_fragment,
-};
-
-static inline struct ovs_nf_ipv6_ops *ovs_nf_get_ipv6_ops(void)
-{
- return &ovs_ipv6_ops;
-}
-#define nf_get_ipv6_ops ovs_nf_get_ipv6_ops
-
-#endif /* HAVE_NF_IPV6_OPS_FRAGMENT */
-#endif /* __NETFILTER_IPV6_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/netlink.h b/datapath/linux/compat/include/linux/netlink.h
deleted file mode 100644
index a64de4ff8..000000000
--- a/datapath/linux/compat/include/linux/netlink.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __LINUX_NETLINK_WRAPPER_H
-#define __LINUX_NETLINK_WRAPPER_H 1
-
-#include <linux/skbuff.h>
-#include_next <linux/netlink.h>
-
-#ifndef NLA_TYPE_MASK
-#define NLA_F_NESTED (1 << 15)
-#define NLA_F_NET_BYTEORDER (1 << 14)
-#define NLA_TYPE_MASK (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER))
-#endif
-
-#include <net/netlink.h>
-
-#ifndef NLMSG_DEFAULT_SIZE
-#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
deleted file mode 100644
index 8bb5abdc8..000000000
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ /dev/null
@@ -1,1176 +0,0 @@
-/*
- * Copyright (c) 2007-2017 Nicira, Inc.
- *
- * This file is offered under your choice of two licenses: Apache 2.0 or GNU
- * GPL 2.0 or later. The permission statements for each of these licenses is
- * given below. You may license your modifications to this file under either
- * of these licenses or both. If you wish to license your modifications under
- * only one of these licenses, delete the permission text for the other
- * license.
- *
- * ----------------------------------------------------------------------
- * 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.
- * ----------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * ----------------------------------------------------------------------
- */
-
-#ifndef _LINUX_OPENVSWITCH_H
-#define _LINUX_OPENVSWITCH_H 1
-
-#include <linux/types.h>
-#include <linux/if_ether.h>
-
-/**
- * struct ovs_header - header for OVS Generic Netlink messages.
- * @dp_ifindex: ifindex of local port for datapath (0 to make a request not
- * specific to a datapath).
- *
- * Attributes following the header are specific to a particular OVS Generic
- * Netlink family, but all of the OVS families use this header.
- */
-
-struct ovs_header {
- int dp_ifindex;
-};
-
-/* Datapaths. */
-
-#define OVS_DATAPATH_FAMILY "ovs_datapath"
-#define OVS_DATAPATH_MCGROUP "ovs_datapath"
-
-/* V2:
- * - API users are expected to provide OVS_DP_ATTR_USER_FEATURES
- * when creating the datapath.
- */
-#define OVS_DATAPATH_VERSION 2
-
-/* First OVS datapath version to support features */
-#define OVS_DP_VER_FEATURES 2
-
-enum ovs_datapath_cmd {
- OVS_DP_CMD_UNSPEC,
- OVS_DP_CMD_NEW,
- OVS_DP_CMD_DEL,
- OVS_DP_CMD_GET,
- OVS_DP_CMD_SET
-};
-
-/**
- * enum ovs_datapath_attr - attributes for %OVS_DP_* commands.
- * @OVS_DP_ATTR_NAME: Name of the network device that serves as the "local
- * port". This is the name of the network device whose dp_ifindex is given in
- * the &struct ovs_header. Always present in notifications. Required in
- * %OVS_DP_NEW requests. May be used as an alternative to specifying
- * dp_ifindex in other requests (with a dp_ifindex of 0).
- * @OVS_DP_ATTR_UPCALL_PID: The Netlink socket in userspace that is initially
- * set on the datapath port (for OVS_ACTION_ATTR_MISS). Only valid on
- * %OVS_DP_CMD_NEW requests. A value of zero indicates that upcalls should
- * not be sent.
- * @OVS_DP_ATTR_PER_CPU_PIDS: Per-cpu array of PIDs for upcalls when
- * OVS_DP_F_DISPATCH_UPCALL_PER_CPU feature is set.
- * @OVS_DP_ATTR_STATS: Statistics about packets that have passed through the
- * datapath. Always present in notifications.
- * @OVS_DP_ATTR_MEGAFLOW_STATS: Statistics about mega flow masks usage for the
- * datapath. Always present in notifications.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_DP_* commands.
- */
-enum ovs_datapath_attr {
- OVS_DP_ATTR_UNSPEC,
- OVS_DP_ATTR_NAME, /* name of dp_ifindex netdev */
- OVS_DP_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls */
- OVS_DP_ATTR_STATS, /* struct ovs_dp_stats */
- OVS_DP_ATTR_MEGAFLOW_STATS, /* struct ovs_dp_megaflow_stats */
- OVS_DP_ATTR_USER_FEATURES, /* OVS_DP_F_* */
- OVS_DP_ATTR_PAD,
- OVS_DP_ATTR_MASKS_CACHE_SIZE,
- OVS_DP_ATTR_PER_CPU_PIDS, /* Netlink PIDS to receive upcalls */
- __OVS_DP_ATTR_MAX
-};
-
-#define OVS_DP_ATTR_MAX (__OVS_DP_ATTR_MAX - 1)
-
-/* All 64-bit integers within Netlink messages are 4-byte aligned only. */
-struct ovs_dp_stats {
- __u64 n_hit; /* Number of flow table matches. */
- __u64 n_missed; /* Number of flow table misses. */
- __u64 n_lost; /* Number of misses not sent to userspace. */
- __u64 n_flows; /* Number of flows present */
-};
-
-struct ovs_dp_megaflow_stats {
- __u64 n_mask_hit; /* Number of masks used for flow lookups. */
- __u32 n_masks; /* Number of masks for the datapath. */
- __u32 pad0; /* Pad for future expension. */
- __u64 n_cache_hit; /* Number of cache matches for flow lookups. */
- __u64 pad1; /* Pad for future expension. */
-};
-
-struct ovs_vport_stats {
- __u64 rx_packets; /* total packets received */
- __u64 tx_packets; /* total packets transmitted */
- __u64 rx_bytes; /* total bytes received */
- __u64 tx_bytes; /* total bytes transmitted */
- __u64 rx_errors; /* bad packets received */
- __u64 tx_errors; /* packet transmit problems */
- __u64 rx_dropped; /* no space in linux buffers */
- __u64 tx_dropped; /* no space available in linux */
-};
-
-/* Allow last Netlink attribute to be unaligned */
-#define OVS_DP_F_UNALIGNED (1 << 0)
-
-/* Allow datapath to associate multiple Netlink PIDs to each vport */
-#define OVS_DP_F_VPORT_PIDS (1 << 1)
-
-/* Allow tc offload recirc sharing */
-#define OVS_DP_F_TC_RECIRC_SHARING (1 << 2)
-
-/* Allow per-cpu dispatch of upcalls */
-#define OVS_DP_F_DISPATCH_UPCALL_PER_CPU (1 << 3)
-
-/* Fixed logical ports. */
-#define OVSP_LOCAL ((__u32)0)
-
-/* Packet transfer. */
-
-#define OVS_PACKET_FAMILY "ovs_packet"
-#define OVS_PACKET_VERSION 0x1
-
-enum ovs_packet_cmd {
- OVS_PACKET_CMD_UNSPEC,
-
- /* Kernel-to-user notifications. */
- OVS_PACKET_CMD_MISS, /* Flow table miss. */
- OVS_PACKET_CMD_ACTION, /* OVS_ACTION_ATTR_USERSPACE action. */
-
- /* Userspace commands. */
- OVS_PACKET_CMD_EXECUTE /* Apply actions to a packet. */
-};
-
-/**
- * enum ovs_packet_attr - attributes for %OVS_PACKET_* commands.
- * @OVS_PACKET_ATTR_PACKET: Present for all notifications. Contains the entire
- * packet as received, from the start of the Ethernet header onward. For
- * %OVS_PACKET_CMD_ACTION, %OVS_PACKET_ATTR_PACKET reflects changes made by
- * actions preceding %OVS_ACTION_ATTR_USERSPACE, but %OVS_PACKET_ATTR_KEY is
- * the flow key extracted from the packet as originally received.
- * @OVS_PACKET_ATTR_KEY: Present for all notifications. Contains the flow key
- * extracted from the packet as nested %OVS_KEY_ATTR_* attributes. This allows
- * userspace to adapt its flow setup strategy by comparing its notion of the
- * flow key against the kernel's. When used with %OVS_PACKET_CMD_EXECUTE, only
- * metadata key fields (e.g. priority, skb mark) are honored. All the packet
- * header fields are parsed from the packet instead.
- * @OVS_PACKET_ATTR_ACTIONS: Contains actions for the packet. Used
- * for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes.
- * Also used in upcall when %OVS_ACTION_ATTR_USERSPACE has optional
- * %OVS_USERSPACE_ATTR_ACTIONS attribute.
- * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
- * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
- * %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
- * specified there.
- * @OVS_PACKET_ATTR_EGRESS_TUN_KEY: Present for an %OVS_PACKET_CMD_ACTION
- * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
- * %OVS_USERSPACE_ATTR_EGRESS_TUN_PORT attribute, which is sent only if the
- * output port is actually a tunnel port. Contains the output tunnel key
- * extracted from the packet as nested %OVS_TUNNEL_KEY_ATTR_* attributes.
- * @OVS_PACKET_ATTR_MRU: Present for an %OVS_PACKET_CMD_ACTION and
- * @OVS_PACKET_ATTR_LEN: Packet size before truncation.
- * %OVS_PACKET_ATTR_USERSPACE action specify the Maximum received fragment
- * size.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_PACKET_* commands.
- */
-enum ovs_packet_attr {
- OVS_PACKET_ATTR_UNSPEC,
- OVS_PACKET_ATTR_PACKET, /* Packet data. */
- OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */
- OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
- OVS_PACKET_ATTR_USERDATA, /* OVS_ACTION_ATTR_USERSPACE arg. */
- OVS_PACKET_ATTR_EGRESS_TUN_KEY, /* Nested OVS_TUNNEL_KEY_ATTR_*
- attributes. */
- OVS_PACKET_ATTR_UNUSED1,
- OVS_PACKET_ATTR_UNUSED2,
- OVS_PACKET_ATTR_PROBE, /* Packet operation is a feature probe,
- error logging should be suppressed. */
- OVS_PACKET_ATTR_MRU, /* Maximum received IP fragment size. */
- OVS_PACKET_ATTR_LEN, /* Packet size before truncation. */
- OVS_PACKET_ATTR_HASH, /* Packet hash. */
- __OVS_PACKET_ATTR_MAX
-};
-
-#define OVS_PACKET_ATTR_MAX (__OVS_PACKET_ATTR_MAX - 1)
-
-/* Virtual ports. */
-
-#define OVS_VPORT_FAMILY "ovs_vport"
-#define OVS_VPORT_MCGROUP "ovs_vport"
-#define OVS_VPORT_VERSION 0x1
-
-enum ovs_vport_cmd {
- OVS_VPORT_CMD_UNSPEC,
- OVS_VPORT_CMD_NEW,
- OVS_VPORT_CMD_DEL,
- OVS_VPORT_CMD_GET,
- OVS_VPORT_CMD_SET
-};
-
-enum ovs_vport_type {
- OVS_VPORT_TYPE_UNSPEC,
- OVS_VPORT_TYPE_NETDEV, /* network device */
- OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
- OVS_VPORT_TYPE_GRE, /* GRE tunnel. */
- OVS_VPORT_TYPE_VXLAN, /* VXLAN tunnel. */
- OVS_VPORT_TYPE_GENEVE, /* Geneve tunnel. */
- OVS_VPORT_TYPE_LISP = 105, /* LISP tunnel */
- OVS_VPORT_TYPE_STT = 106, /* STT tunnel */
- OVS_VPORT_TYPE_ERSPAN = 107, /* ERSPAN tunnel. */
- OVS_VPORT_TYPE_IP6ERSPAN = 108, /* ERSPAN tunnel. */
- OVS_VPORT_TYPE_IP6GRE = 109,
- OVS_VPORT_TYPE_GTPU = 110,
- OVS_VPORT_TYPE_BAREUDP = 111, /* Bareudp tunnel. */
- __OVS_VPORT_TYPE_MAX
-};
-
-#define OVS_VPORT_TYPE_MAX (__OVS_VPORT_TYPE_MAX - 1)
-
-/**
- * enum ovs_vport_attr - attributes for %OVS_VPORT_* commands.
- * @OVS_VPORT_ATTR_PORT_NO: 32-bit port number within datapath.
- * @OVS_VPORT_ATTR_TYPE: 32-bit %OVS_VPORT_TYPE_* constant describing the type
- * of vport.
- * @OVS_VPORT_ATTR_NAME: Name of vport. For a vport based on a network device
- * this is the name of the network device. Maximum length %IFNAMSIZ-1 bytes
- * plus a null terminator.
- * @OVS_VPORT_ATTR_OPTIONS: Vport-specific configuration information.
- * @OVS_VPORT_ATTR_UPCALL_PID: The array of Netlink socket pids in userspace
- * among which OVS_PACKET_CMD_MISS upcalls will be distributed for packets
- * received on this port. If this is a single-element array of value 0,
- * upcalls should not be sent.
- * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for
- * packets sent or received through the vport.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_VPORT_* commands.
- *
- * For %OVS_VPORT_CMD_NEW requests, the %OVS_VPORT_ATTR_TYPE and
- * %OVS_VPORT_ATTR_NAME attributes are required. %OVS_VPORT_ATTR_PORT_NO is
- * optional; if not specified a free port number is automatically selected.
- * Whether %OVS_VPORT_ATTR_OPTIONS is required or optional depends on the type
- * of vport. %OVS_VPORT_ATTR_STATS is optional and other attributes are
- * ignored.
- *
- * For other requests, if %OVS_VPORT_ATTR_NAME is specified then it is used to
- * look up the vport to operate on; otherwise dp_idx from the &struct
- * ovs_header plus %OVS_VPORT_ATTR_PORT_NO determine the vport.
- */
-enum ovs_vport_attr {
- OVS_VPORT_ATTR_UNSPEC,
- OVS_VPORT_ATTR_PORT_NO, /* u32 port number within datapath */
- OVS_VPORT_ATTR_TYPE, /* u32 OVS_VPORT_TYPE_* constant. */
- OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */
- OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */
- OVS_VPORT_ATTR_UPCALL_PID, /* array of u32 Netlink socket PIDs for */
- /* receiving upcalls */
- OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */
- OVS_VPORT_ATTR_PAD,
- OVS_VPORT_ATTR_IFINDEX,
- OVS_VPORT_ATTR_NETNSID,
- __OVS_VPORT_ATTR_MAX
-};
-
-#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
-
-enum {
- OVS_VXLAN_EXT_UNSPEC,
- OVS_VXLAN_EXT_GBP,
- /* place new values here to fill gap. */
- OVS_VXLAN_EXT_GPE = 8,
- __OVS_VXLAN_EXT_MAX,
-};
-
-#define OVS_VXLAN_EXT_MAX (__OVS_VXLAN_EXT_MAX - 1)
-
-enum {
- OVS_BAREUDP_EXT_UNSPEC,
- OVS_BAREUDP_EXT_MULTIPROTO_MODE,
- __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_MAX
-};
-
-#define OVS_TUNNEL_ATTR_MAX (__OVS_TUNNEL_ATTR_MAX - 1)
-
-/* Flows. */
-
-#define OVS_FLOW_FAMILY "ovs_flow"
-#define OVS_FLOW_MCGROUP "ovs_flow"
-#define OVS_FLOW_VERSION 0x1
-
-enum ovs_flow_cmd {
- OVS_FLOW_CMD_UNSPEC,
- OVS_FLOW_CMD_NEW,
- OVS_FLOW_CMD_DEL,
- OVS_FLOW_CMD_GET,
- OVS_FLOW_CMD_SET
-};
-
-struct ovs_flow_stats {
- __u64 n_packets; /* Number of matched packets. */
- __u64 n_bytes; /* Number of matched bytes. */
-};
-
-enum ovs_key_attr {
- OVS_KEY_ATTR_UNSPEC,
- OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */
- OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */
- OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */
- OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */
- OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */
- OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */
- OVS_KEY_ATTR_IPV4, /* struct ovs_key_ipv4 */
- OVS_KEY_ATTR_IPV6, /* struct ovs_key_ipv6 */
- OVS_KEY_ATTR_TCP, /* struct ovs_key_tcp */
- OVS_KEY_ATTR_UDP, /* struct ovs_key_udp */
- OVS_KEY_ATTR_ICMP, /* struct ovs_key_icmp */
- OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */
- OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */
- OVS_KEY_ATTR_ND, /* struct ovs_key_nd */
- OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */
- OVS_KEY_ATTR_TUNNEL, /* Nested set of ovs_tunnel attributes */
- OVS_KEY_ATTR_SCTP, /* struct ovs_key_sctp */
- OVS_KEY_ATTR_TCP_FLAGS, /* be16 TCP flags. */
- OVS_KEY_ATTR_DP_HASH, /* u32 hash value. Value 0 indicates the hash
- is not computed by the datapath. */
- OVS_KEY_ATTR_RECIRC_ID, /* u32 recirc id */
- OVS_KEY_ATTR_MPLS, /* array of struct ovs_key_mpls.
- * The implementation may restrict
- * the accepted length of the array. */
- OVS_KEY_ATTR_CT_STATE, /* u32 bitmask of OVS_CS_F_* */
- OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */
- OVS_KEY_ATTR_CT_MARK, /* u32 connection tracking mark */
- OVS_KEY_ATTR_CT_LABELS, /* 16-octet connection tracking labels */
- OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4, /* struct ovs_key_ct_tuple_ipv4 */
- OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6, /* struct ovs_key_ct_tuple_ipv6 */
- OVS_KEY_ATTR_NSH, /* Nested set of ovs_nsh_key_* */
-
- /* User space decided to squat on types 29 and 30. They are defined
- * below, but should not be sent to the kernel.
- *
- * WARNING: No new types should be added unless they are defined
- * for both kernel and user space (no 'ifdef's). It's hard
- * to keep compatibility otherwise.
- */
- OVS_KEY_ATTR_PACKET_TYPE, /* be32 packet type */
- OVS_KEY_ATTR_ND_EXTENSIONS, /* struct ovs_key_nd_extensions */
-
- OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info.
- * For in-kernel use only.
- */
- __OVS_KEY_ATTR_MAX
-};
-
-#define OVS_KEY_ATTR_MAX (__OVS_KEY_ATTR_MAX - 1)
-
-enum ovs_tunnel_key_attr {
- OVS_TUNNEL_KEY_ATTR_ID, /* be64 Tunnel ID */
- OVS_TUNNEL_KEY_ATTR_IPV4_SRC, /* be32 src IP address. */
- OVS_TUNNEL_KEY_ATTR_IPV4_DST, /* be32 dst IP address. */
- OVS_TUNNEL_KEY_ATTR_TOS, /* u8 Tunnel IP ToS. */
- OVS_TUNNEL_KEY_ATTR_TTL, /* u8 Tunnel IP TTL. */
- OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT, /* No argument, set DF. */
- OVS_TUNNEL_KEY_ATTR_CSUM, /* No argument. CSUM packet. */
- OVS_TUNNEL_KEY_ATTR_OAM, /* No argument. OAM frame. */
- OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */
- OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
- OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
- OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */
- OVS_TUNNEL_KEY_ATTR_IPV6_SRC, /* struct in6_addr src IPv6 address. */
- OVS_TUNNEL_KEY_ATTR_IPV6_DST, /* struct in6_addr dst IPv6 address. */
- OVS_TUNNEL_KEY_ATTR_PAD,
- OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, /* struct erspan_metadata */
-#ifndef __KERNEL__
- /* Only used within userspace data path. */
- OVS_TUNNEL_KEY_ATTR_GTPU_OPTS, /* struct gtpu_metadata */
-#endif
- __OVS_TUNNEL_KEY_ATTR_MAX
-};
-
-#define OVS_TUNNEL_KEY_ATTR_MAX (__OVS_TUNNEL_KEY_ATTR_MAX - 1)
-
-/**
- * enum xlate_error - Different types of error during translation
- */
-
-#ifndef __KERNEL__
-enum xlate_error {
- XLATE_OK = 0,
- XLATE_BRIDGE_NOT_FOUND,
- XLATE_RECURSION_TOO_DEEP,
- XLATE_TOO_MANY_RESUBMITS,
- XLATE_STACK_TOO_DEEP,
- XLATE_NO_RECIRCULATION_CONTEXT,
- XLATE_RECIRCULATION_CONFLICT,
- XLATE_TOO_MANY_MPLS_LABELS,
- XLATE_INVALID_TUNNEL_METADATA,
- XLATE_UNSUPPORTED_PACKET_TYPE,
- XLATE_CONGESTION_DROP,
- XLATE_FORWARDING_DISABLED,
- XLATE_MAX,
-};
-#endif
-
-/**
- * enum ovs_frag_type - IPv4 and IPv6 fragment type
- * @OVS_FRAG_TYPE_NONE: Packet is not a fragment.
- * @OVS_FRAG_TYPE_FIRST: Packet is a fragment with offset 0.
- * @OVS_FRAG_TYPE_LATER: Packet is a fragment with nonzero offset.
- *
- * Used as the @ipv4_frag in &struct ovs_key_ipv4 and as @ipv6_frag &struct
- * ovs_key_ipv6.
- */
-enum ovs_frag_type {
- OVS_FRAG_TYPE_NONE,
- OVS_FRAG_TYPE_FIRST,
- OVS_FRAG_TYPE_LATER,
- __OVS_FRAG_TYPE_MAX
-};
-
-#define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1)
-
-struct ovs_key_ethernet {
- __u8 eth_src[ETH_ALEN];
- __u8 eth_dst[ETH_ALEN];
-};
-
-struct ovs_key_mpls {
- __be32 mpls_lse;
-};
-
-struct ovs_key_ipv4 {
- __be32 ipv4_src;
- __be32 ipv4_dst;
- __u8 ipv4_proto;
- __u8 ipv4_tos;
- __u8 ipv4_ttl;
- __u8 ipv4_frag; /* One of OVS_FRAG_TYPE_*. */
-};
-
-struct ovs_key_ipv6 {
- __be32 ipv6_src[4];
- __be32 ipv6_dst[4];
- __be32 ipv6_label; /* 20-bits in least-significant bits. */
- __u8 ipv6_proto;
- __u8 ipv6_tclass;
- __u8 ipv6_hlimit;
- __u8 ipv6_frag; /* One of OVS_FRAG_TYPE_*. */
-};
-
-struct ovs_key_tcp {
- __be16 tcp_src;
- __be16 tcp_dst;
-};
-
-struct ovs_key_udp {
- __be16 udp_src;
- __be16 udp_dst;
-};
-
-struct ovs_key_sctp {
- __be16 sctp_src;
- __be16 sctp_dst;
-};
-
-struct ovs_key_icmp {
- __u8 icmp_type;
- __u8 icmp_code;
-};
-
-struct ovs_key_icmpv6 {
- __u8 icmpv6_type;
- __u8 icmpv6_code;
-};
-
-struct ovs_key_arp {
- __be32 arp_sip;
- __be32 arp_tip;
- __be16 arp_op;
- __u8 arp_sha[ETH_ALEN];
- __u8 arp_tha[ETH_ALEN];
-};
-
-struct ovs_key_nd {
- __be32 nd_target[4];
- __u8 nd_sll[ETH_ALEN];
- __u8 nd_tll[ETH_ALEN];
-};
-
-#ifndef __KERNEL__
-struct ovs_key_nd_extensions {
- __be32 nd_reserved;
- __u8 nd_options_type;
-};
-#endif
-
-#define OVS_CT_LABELS_LEN_32 4
-#define OVS_CT_LABELS_LEN (OVS_CT_LABELS_LEN_32 * sizeof(__u32))
-struct ovs_key_ct_labels {
- union {
- __u8 ct_labels[OVS_CT_LABELS_LEN];
- __u32 ct_labels_32[OVS_CT_LABELS_LEN_32];
- };
-};
-
-enum ovs_nsh_key_attr {
- OVS_NSH_KEY_ATTR_UNSPEC,
- OVS_NSH_KEY_ATTR_BASE, /* struct ovs_nsh_key_base. */
- OVS_NSH_KEY_ATTR_MD1, /* struct ovs_nsh_key_md1. */
- OVS_NSH_KEY_ATTR_MD2, /* variable-length octets. */
- __OVS_NSH_KEY_ATTR_MAX
-};
-
-#define OVS_NSH_KEY_ATTR_MAX (__OVS_NSH_KEY_ATTR_MAX - 1)
-
-struct ovs_nsh_key_base {
- __u8 flags;
- __u8 ttl;
- __u8 mdtype;
- __u8 np;
- __be32 path_hdr;
-};
-
-#define NSH_MD1_CONTEXT_SIZE 4
-
-struct ovs_nsh_key_md1 {
- __be32 context[NSH_MD1_CONTEXT_SIZE];
-};
-
-/* OVS_KEY_ATTR_CT_STATE flags */
-#define OVS_CS_F_NEW 0x01 /* Beginning of a new connection. */
-#define OVS_CS_F_ESTABLISHED 0x02 /* Part of an existing connection. */
-#define OVS_CS_F_RELATED 0x04 /* Related to an established
- * connection. */
-#define OVS_CS_F_REPLY_DIR 0x08 /* Flow is in the reply direction. */
-#define OVS_CS_F_INVALID 0x10 /* Could not track connection. */
-#define OVS_CS_F_TRACKED 0x20 /* Conntrack has occurred. */
-#define OVS_CS_F_SRC_NAT 0x40 /* Packet's source address/port was
- mangled by NAT. */
-#define OVS_CS_F_DST_NAT 0x80 /* Packet's destination address/port
- was mangled by NAT. */
-
-#define OVS_CS_F_NAT_MASK (OVS_CS_F_SRC_NAT | OVS_CS_F_DST_NAT)
-
-struct ovs_key_ct_tuple_ipv4 {
- __be32 ipv4_src;
- __be32 ipv4_dst;
- __be16 src_port;
- __be16 dst_port;
- __u8 ipv4_proto;
-};
-
-struct ovs_key_ct_tuple_ipv6 {
- __be32 ipv6_src[4];
- __be32 ipv6_dst[4];
- __be16 src_port;
- __be16 dst_port;
- __u8 ipv6_proto;
-};
-
-/**
- * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
- * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
- * key. Always present in notifications. Required for all requests (except
- * dumps).
- * @OVS_FLOW_ATTR_ACTIONS: Nested %OVS_ACTION_ATTR_* attributes specifying
- * the actions to take for packets that match the key. Always present in
- * notifications. Required for %OVS_FLOW_CMD_NEW requests, optional for
- * %OVS_FLOW_CMD_SET requests. An %OVS_FLOW_CMD_SET without
- * %OVS_FLOW_ATTR_ACTIONS will not modify the actions. To clear the actions,
- * an %OVS_FLOW_ATTR_ACTIONS without any nested attributes must be given.
- * @OVS_FLOW_ATTR_STATS: &struct ovs_flow_stats giving statistics for this
- * flow. Present in notifications if the stats would be nonzero. Ignored in
- * requests.
- * @OVS_FLOW_ATTR_TCP_FLAGS: An 8-bit value giving the OR'd value of all of the
- * TCP flags seen on packets in this flow. Only present in notifications for
- * TCP flows, and only if it would be nonzero. Ignored in requests.
- * @OVS_FLOW_ATTR_USED: A 64-bit integer giving the time, in milliseconds on
- * the system monotonic clock, at which a packet was last processed for this
- * flow. Only present in notifications if a packet has been processed for this
- * flow. Ignored in requests.
- * @OVS_FLOW_ATTR_CLEAR: If present in a %OVS_FLOW_CMD_SET request, clears the
- * last-used time, accumulated TCP flags, and statistics for this flow.
- * Otherwise ignored in requests. Never present in notifications.
- * @OVS_FLOW_ATTR_MASK: Nested %OVS_KEY_ATTR_* attributes specifying the
- * mask bits for wildcarded flow match. Mask bit value '1' specifies exact
- * match with corresponding flow key bit, while mask bit value '0' specifies
- * a wildcarded match. Omitting attribute is treated as wildcarding all
- * corresponding fields. Optional for all requests. If not present,
- * all flow key bits are exact match bits.
- * @OVS_FLOW_ATTR_UFID: A value between 1-16 octets specifying a unique
- * identifier for the flow. Causes the flow to be indexed by this value rather
- * than the value of the %OVS_FLOW_ATTR_KEY attribute. Optional for all
- * requests. Present in notifications if the flow was created with this
- * attribute.
- * @OVS_FLOW_ATTR_UFID_FLAGS: A 32-bit value of OR'd %OVS_UFID_F_*
- * flags that provide alternative semantics for flow installation and
- * retrieval. Optional for all requests.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_FLOW_* commands.
- */
-enum ovs_flow_attr {
- OVS_FLOW_ATTR_UNSPEC,
- OVS_FLOW_ATTR_KEY, /* Sequence of OVS_KEY_ATTR_* attributes. */
- OVS_FLOW_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
- OVS_FLOW_ATTR_STATS, /* struct ovs_flow_stats. */
- OVS_FLOW_ATTR_TCP_FLAGS, /* 8-bit OR'd TCP flags. */
- OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */
- OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */
- OVS_FLOW_ATTR_MASK, /* Sequence of OVS_KEY_ATTR_* attributes. */
- OVS_FLOW_ATTR_PROBE, /* Flow operation is a feature probe, error
- * logging should be suppressed. */
- OVS_FLOW_ATTR_UFID, /* Variable length unique flow identifier. */
- OVS_FLOW_ATTR_UFID_FLAGS,/* u32 of OVS_UFID_F_*. */
- OVS_FLOW_ATTR_PAD,
- __OVS_FLOW_ATTR_MAX
-};
-
-#define OVS_FLOW_ATTR_MAX (__OVS_FLOW_ATTR_MAX - 1)
-
-/**
- * Omit attributes for notifications.
- *
- * If a datapath request contains an OVS_UFID_F_OMIT_* flag, then the datapath
- * may omit the corresponding 'ovs_flow_attr' from the response.
- */
-#define OVS_UFID_F_OMIT_KEY (1 << 0)
-#define OVS_UFID_F_OMIT_MASK (1 << 1)
-#define OVS_UFID_F_OMIT_ACTIONS (1 << 2)
-
-/**
- * enum ovs_sample_attr - Attributes for %OVS_ACTION_ATTR_SAMPLE action.
- * @OVS_SAMPLE_ATTR_PROBABILITY: 32-bit fraction of packets to sample with
- * @OVS_ACTION_ATTR_SAMPLE. A value of 0 samples no packets, a value of
- * %UINT32_MAX samples all packets and intermediate values sample intermediate
- * fractions of packets.
- * @OVS_SAMPLE_ATTR_ACTIONS: Set of actions to execute in sampling event.
- * Actions are passed as nested attributes.
- *
- * Executes the specified actions with the given probability on a per-packet
- * basis.
- */
-enum ovs_sample_attr {
- OVS_SAMPLE_ATTR_UNSPEC,
- OVS_SAMPLE_ATTR_PROBABILITY, /* u32 number */
- OVS_SAMPLE_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
- __OVS_SAMPLE_ATTR_MAX,
-
-#ifdef __KERNEL__
- OVS_SAMPLE_ATTR_ARG /* struct sample_arg */
-#endif
-};
-
-#define OVS_SAMPLE_ATTR_MAX (__OVS_SAMPLE_ATTR_MAX - 1)
-
-#ifdef __KERNEL__
-struct sample_arg {
- bool exec; /* When true, actions in sample will not
- * change flow keys. False otherwise.
- */
- u32 probability; /* Same value as
- * 'OVS_SAMPLE_ATTR_PROBABILITY'.
- */
-};
-#endif
-
-/**
- * enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
- * @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
- * message should be sent. Required.
- * @OVS_USERSPACE_ATTR_USERDATA: If present, its variable-length argument is
- * copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
- * @OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: If present, u32 output port to get
- * tunnel info.
- * @OVS_USERSPACE_ATTR_ACTIONS: If present, send actions with upcall.
- */
-enum ovs_userspace_attr {
- OVS_USERSPACE_ATTR_UNSPEC,
- OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */
- OVS_USERSPACE_ATTR_USERDATA, /* Optional user-specified cookie. */
- OVS_USERSPACE_ATTR_EGRESS_TUN_PORT, /* Optional, u32 output port
- * to get tunnel info. */
- OVS_USERSPACE_ATTR_ACTIONS, /* Optional flag to get actions. */
- __OVS_USERSPACE_ATTR_MAX
-};
-
-#define OVS_USERSPACE_ATTR_MAX (__OVS_USERSPACE_ATTR_MAX - 1)
-
-struct ovs_action_trunc {
- uint32_t max_len; /* Max packet size in bytes. */
-};
-
-/**
- * struct ovs_action_push_mpls - %OVS_ACTION_ATTR_PUSH_MPLS action argument.
- * @mpls_lse: MPLS label stack entry to push.
- * @mpls_ethertype: Ethertype to set in the encapsulating ethernet frame.
- *
- * The only values @mpls_ethertype should ever be given are %ETH_P_MPLS_UC and
- * %ETH_P_MPLS_MC, indicating MPLS unicast or multicast. Other are rejected.
- */
-struct ovs_action_push_mpls {
- __be32 mpls_lse;
- __be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */
-};
-
-/**
- * struct ovs_action_add_mpls - %OVS_ACTION_ATTR_ADD_MPLS action
- * argument.
- * @mpls_lse: MPLS label stack entry to push.
- * @mpls_ethertype: Ethertype to set in the encapsulating ethernet frame.
- * @tun_flags: MPLS tunnel attributes.
- *
- * The only values @mpls_ethertype should ever be given are %ETH_P_MPLS_UC and
- * %ETH_P_MPLS_MC, indicating MPLS unicast or multicast. Other are rejected.
- */
-struct ovs_action_add_mpls {
- __be32 mpls_lse;
- __be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */
- __u16 tun_flags;
-};
-
-#define OVS_MPLS_L3_TUNNEL_FLAG_MASK (1 << 0) /* Flag to specify the place of
- * insertion of MPLS header.
- * When false, the MPLS header
- * will be inserted at the start
- * of the packet.
- * When true, the MPLS header
- * will be inserted at the start
- * of the l3 header.
- */
-
-/**
- * struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.
- * @vlan_tpid: Tag protocol identifier (TPID) to push.
- * @vlan_tci: Tag control identifier (TCI) to push. The CFI bit must be set
- * (but it will not be set in the 802.1Q header that is pushed).
- *
- * The @vlan_tpid value is typically %ETH_P_8021Q or %ETH_P_8021AD.
- * The only acceptable TPID values are those that the kernel module also parses
- * as 802.1Q or 802.1AD headers, to prevent %OVS_ACTION_ATTR_PUSH_VLAN followed
- * by %OVS_ACTION_ATTR_POP_VLAN from having surprising results.
- */
-struct ovs_action_push_vlan {
- __be16 vlan_tpid; /* 802.1Q or 802.1ad TPID. */
- __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
-};
-
-/* Data path hash algorithm for computing Datapath hash.
- *
- * The algorithm type only specifies the fields in a flow
- * will be used as part of the hash. Each datapath is free
- * to use its own hash algorithm. The hash value will be
- * opaque to the user space daemon.
- */
-enum ovs_hash_alg {
- OVS_HASH_ALG_L4,
-#ifndef __KERNEL__
- OVS_HASH_ALG_SYM_L4,
-#endif
- __OVS_HASH_MAX
-};
-
-/*
- * struct ovs_action_hash - %OVS_ACTION_ATTR_HASH action argument.
- * @hash_alg: Algorithm used to compute hash prior to recirculation.
- * @hash_basis: basis used for computing hash.
- */
-struct ovs_action_hash {
- uint32_t hash_alg; /* One of ovs_hash_alg. */
- uint32_t hash_basis;
-};
-
-#ifndef __KERNEL__
-#define TNL_PUSH_HEADER_SIZE 512
-
-/*
- * struct ovs_action_push_tnl - %OVS_ACTION_ATTR_TUNNEL_PUSH
- * @tnl_port: To identify tunnel port to pass header info.
- * @out_port: Physical port to send encapsulated packet.
- * @header_len: Length of the header to be pushed.
- * @tnl_type: This is only required to format this header. Otherwise
- * ODP layer can not parse %header.
- * @header: Partial header for the tunnel. Tunnel push action can use
- * this header to build final header according to actual packet parameters.
- */
-struct ovs_action_push_tnl {
- odp_port_t tnl_port;
- odp_port_t out_port;
- uint32_t header_len;
- uint32_t tnl_type; /* For logging. */
- uint32_t header[TNL_PUSH_HEADER_SIZE / 4];
-};
-#endif
-
-/**
- * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action.
- * @OVS_CT_ATTR_COMMIT: If present, commits the connection to the conntrack
- * table. This allows future packets for the same connection to be identified
- * as 'established' or 'related'. The flow key for the current packet will
- * retain the pre-commit connection state.
- * @OVS_CT_ATTR_ZONE: u16 connection tracking zone.
- * @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the
- * mask, the corresponding bit in the value is copied to the connection
- * tracking mark field in the connection.
- * @OVS_CT_ATTR_LABELS: %OVS_CT_LABELS_LEN value followed by %OVS_CT_LABELS_LEN
- * mask. For each bit set in the mask, the corresponding bit in the value is
- * copied to the connection tracking label field in the connection.
- * @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG.
- * @OVS_CT_ATTR_NAT: Nested OVS_NAT_ATTR_* for performing L3 network address
- * translation (NAT) on the packet.
- * @OVS_CT_ATTR_FORCE_COMMIT: Like %OVS_CT_ATTR_COMMIT, but instead of doing
- * nothing if the connection is already committed will check that the current
- * packet is in conntrack entry's original direction. If directionality does
- * not match, will delete the existing conntrack entry and create a new one.
- * @OVS_CT_ATTR_EVENTMASK: Mask of bits indicating which conntrack event types
- * (enum ip_conntrack_events IPCT_*) should be reported. For any bit set to
- * zero, the corresponding event type is not generated. Default behavior
- * depends on system configuration, but typically all event types are
- * generated, hence listening on NFNLGRP_CONNTRACK_UPDATE events may get a lot
- * of events. Explicitly passing this attribute allows limiting the updates
- * received to the events of interest. The bit 1 << IPCT_NEW, 1 <<
- * IPCT_RELATED, and 1 << IPCT_DESTROY must be set to ones for those events to
- * be received on NFNLGRP_CONNTRACK_NEW and NFNLGRP_CONNTRACK_DESTROY groups,
- * respectively. Remaining bits control the changes for which an event is
- * delivered on the NFNLGRP_CONNTRACK_UPDATE group.
- * @OVS_CT_ATTR_TIMEOUT: Variable length string defining conntrack timeout.
- */
-enum ovs_ct_attr {
- OVS_CT_ATTR_UNSPEC,
- OVS_CT_ATTR_COMMIT, /* No argument, commits connection. */
- OVS_CT_ATTR_ZONE, /* u16 zone id. */
- OVS_CT_ATTR_MARK, /* mark to associate with this connection. */
- OVS_CT_ATTR_LABELS, /* label to associate with this connection. */
- OVS_CT_ATTR_HELPER, /* netlink helper to assist detection of
- related connections. */
- OVS_CT_ATTR_NAT, /* Nested OVS_NAT_ATTR_* */
- OVS_CT_ATTR_FORCE_COMMIT, /* No argument */
- OVS_CT_ATTR_EVENTMASK, /* u32 mask of IPCT_* events. */
- OVS_CT_ATTR_TIMEOUT, /* Associate timeout with this connection for
- * fine-grain timeout tuning. */
-
- __OVS_CT_ATTR_MAX
-};
-
-#define OVS_CT_ATTR_MAX (__OVS_CT_ATTR_MAX - 1)
-
-/*
- * struct ovs_action_push_eth - %OVS_ACTION_ATTR_PUSH_ETH action argument.
- * @addresses: Source and destination MAC addresses.
- */
-struct ovs_action_push_eth {
- struct ovs_key_ethernet addresses;
-};
-
-/**
- * enum ovs_nat_attr - Attributes for %OVS_CT_ATTR_NAT.
- *
- * @OVS_NAT_ATTR_SRC: Flag for Source NAT (mangle source address/port).
- * @OVS_NAT_ATTR_DST: Flag for Destination NAT (mangle destination
- * address/port). Only one of (@OVS_NAT_ATTR_SRC, @OVS_NAT_ATTR_DST) may be
- * specified. Effective only for packets for ct_state NEW connections.
- * Committed connections are mangled by the NAT action according to the
- * committed NAT type regardless of the flags specified. As a corollary, a NAT
- * action without a NAT type flag will only mangle packets of committed
- * connections. The following NAT attributes only apply for NEW connections,
- * and they may be included only when the CT action has the @OVS_CT_ATTR_COMMIT
- * flag and either @OVS_NAT_ATTR_SRC, @OVS_NAT_ATTR_DST is also included.
- * @OVS_NAT_ATTR_IP_MIN: struct in_addr or struct in6_addr
- * @OVS_NAT_ATTR_IP_MAX: struct in_addr or struct in6_addr
- * @OVS_NAT_ATTR_PROTO_MIN: u16 L4 protocol specific lower boundary (port)
- * @OVS_NAT_ATTR_PROTO_MAX: u16 L4 protocol specific upper boundary (port)
- * @OVS_NAT_ATTR_PERSISTENT: Flag for persistent IP mapping across reboots
- * @OVS_NAT_ATTR_PROTO_HASH: Flag for pseudo random L4 port mapping (MD5)
- * @OVS_NAT_ATTR_PROTO_RANDOM: Flag for fully randomized L4 port mapping
- */
-enum ovs_nat_attr {
- OVS_NAT_ATTR_UNSPEC,
- OVS_NAT_ATTR_SRC,
- OVS_NAT_ATTR_DST,
- OVS_NAT_ATTR_IP_MIN,
- OVS_NAT_ATTR_IP_MAX,
- OVS_NAT_ATTR_PROTO_MIN,
- OVS_NAT_ATTR_PROTO_MAX,
- OVS_NAT_ATTR_PERSISTENT,
- OVS_NAT_ATTR_PROTO_HASH,
- OVS_NAT_ATTR_PROTO_RANDOM,
- __OVS_NAT_ATTR_MAX,
-};
-
-#define OVS_NAT_ATTR_MAX (__OVS_NAT_ATTR_MAX - 1)
-
-/*
- * enum ovs_check_pkt_len_attr - Attributes for %OVS_ACTION_ATTR_CHECK_PKT_LEN.
- *
- * @OVS_CHECK_PKT_LEN_ATTR_PKT_LEN: u16 Packet length to check for.
- * @OVS_CHECK_PKT_LEN_ATTR_USERSPACE_COND: u8 comparison condition to send
- * the packet to userspace. One of OVS_CHECK_PKT_LEN_COND_*.
- * @OVS_CHECK_PKT_LEN_ATTR_USERPACE - Nested OVS_USERSPACE_ATTR_* actions.
- */
-enum ovs_check_pkt_len_attr {
- OVS_CHECK_PKT_LEN_ATTR_UNSPEC,
- OVS_CHECK_PKT_LEN_ATTR_PKT_LEN,
- OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER,
- OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL,
- __OVS_CHECK_PKT_LEN_ATTR_MAX,
-
-#ifdef __KERNEL__
- OVS_CHECK_PKT_LEN_ATTR_ARG /* struct check_pkt_len_arg */
-#endif
-};
-
-#define OVS_CHECK_PKT_LEN_ATTR_MAX (__OVS_CHECK_PKT_LEN_ATTR_MAX - 1)
-
-#ifdef __KERNEL__
-struct check_pkt_len_arg {
- u16 pkt_len; /* Same value as OVS_CHECK_PKT_LEN_ATTR_PKT_LEN'. */
- bool exec_for_greater; /* When true, actions in IF_GREATE will
- * not change flow keys. False otherwise.
- */
- bool exec_for_lesser_equal; /* When true, actions in IF_LESS_EQUAL
- * will not change flow keys. False
- * otherwise.
- */
-};
-#endif
-
-/**
- * enum ovs_action_attr - Action types.
- *
- * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
- * @OVS_ACTION_ATTR_TRUNC: Output packet to port with truncated packet size.
- * @OVS_ACTION_ATTR_USERSPACE: Send packet to userspace according to nested
- * %OVS_USERSPACE_ATTR_* attributes.
- * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q or 802.1ad header
- * onto the packet.
- * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q or 802.1ad header
- * from the packet.
- * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
- * the nested %OVS_SAMPLE_ATTR_* attributes.
- * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header. The
- * single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
- * value.
- * @OVS_ACTION_ATTR_SET_MASKED: Replaces the contents of an existing header. A
- * nested %OVS_KEY_ATTR_* attribute specifies a header to modify, its value,
- * and a mask. For every bit set in the mask, the corresponding bit value
- * is copied from the value to the packet header field, rest of the bits are
- * left unchanged. The non-masked value bits must be passed in as zeroes.
- * Masking is not supported for the %OVS_KEY_ATTR_TUNNEL attribute.
- * @OVS_ACTION_ATTR_RECIRC: Recirculate within the data path.
- * @OVS_ACTION_ATTR_HASH: Compute and set flow hash value.
- * @OVS_ACTION_ATTR_PUSH_MPLS: Push a new MPLS label stack entry onto the
- * top of the packets MPLS label stack. Set the ethertype of the
- * encapsulating frame to either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC to
- * indicate the new packet contents.
- * @OVS_ACTION_ATTR_POP_MPLS: Pop an MPLS label stack entry off of the
- * packet's MPLS label stack. Set the encapsulating frame's ethertype to
- * indicate the new packet contents. This could potentially still be
- * %ETH_P_MPLS if the resulting MPLS label stack is not empty. If there
- * is no MPLS label stack, as determined by ethertype, no action is taken.
- * @OVS_ACTION_ATTR_CT: Track the connection. Populate the conntrack-related
- * entries in the flow key.
- * @OVS_ACTION_ATTR_PUSH_ETH: Push a new outermost Ethernet header onto the
- * packet.
- * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the packet.
- * @OVS_ACTION_ATTR_CT_CLEAR: Clear conntrack state from the packet.
- * @OVS_ACTION_ATTR_PUSH_NSH: push NSH header to the packet.
- * @OVS_ACTION_ATTR_POP_NSH: pop the outermost NSH header off the packet.
- *
- * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
- * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
- * type may not be changed.
- *
- * @OVS_ACTION_ATTR_SET_TO_MASKED: Kernel internal masked set action translated
- * from the @OVS_ACTION_ATTR_SET.
- * @OVS_ACTION_ATTR_TUNNEL_PUSH: Push tunnel header described by struct
- * ovs_action_push_tnl.
- * @OVS_ACTION_ATTR_TUNNEL_POP: Lookup tunnel port by port-no passed and pop
- * tunnel header.
- * @OVS_ACTION_ATTR_METER: Run packet through a meter, which may drop the
- * packet, or modify the packet (e.g., change the DSCP field).
- * @OVS_ACTION_ATTR_CLONE: make a copy of the packet and execute a list of
- * actions without affecting the original packet and key.
- * @OVS_ACTION_ATTR_CHECK_PKT_LEN: Check the packet length and execute a set
- * of actions if greater than the specified packet length, else execute
- * another set of actions.
- * @OVS_ACTION_ATTR_ADD_MPLS: Push a new MPLS label stack entry at the
- * start of the packet or at the start of the l3 header depending on the value
- * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
- * argument.
- * @OVS_ACTION_ATTR_DROP: Explicit drop action.
- */
-
-enum ovs_action_attr {
- OVS_ACTION_ATTR_UNSPEC,
- OVS_ACTION_ATTR_OUTPUT, /* u32 port number. */
- OVS_ACTION_ATTR_USERSPACE, /* Nested OVS_USERSPACE_ATTR_*. */
- OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */
- OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */
- OVS_ACTION_ATTR_POP_VLAN, /* No argument. */
- OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */
- OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */
- OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */
- OVS_ACTION_ATTR_PUSH_MPLS, /* struct ovs_action_push_mpls. */
- OVS_ACTION_ATTR_POP_MPLS, /* __be16 ethertype. */
- OVS_ACTION_ATTR_SET_MASKED, /* One nested OVS_KEY_ATTR_* including
- * data immediately followed by a mask.
- * The data must be zero for the unmasked
- * bits. */
- OVS_ACTION_ATTR_CT, /* Nested OVS_CT_ATTR_* . */
- OVS_ACTION_ATTR_TRUNC, /* u32 struct ovs_action_trunc. */
- OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */
- OVS_ACTION_ATTR_POP_ETH, /* No argument. */
- OVS_ACTION_ATTR_CT_CLEAR, /* No argument. */
- OVS_ACTION_ATTR_PUSH_NSH, /* Nested OVS_NSH_KEY_ATTR_*. */
- OVS_ACTION_ATTR_POP_NSH, /* No argument. */
- OVS_ACTION_ATTR_METER, /* u32 meter number. */
- OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */
- OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */
- OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
-
-#ifndef __KERNEL__
- OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/
- OVS_ACTION_ATTR_TUNNEL_POP, /* u32 port number. */
- OVS_ACTION_ATTR_DROP, /* u32 xlate_error. */
- OVS_ACTION_ATTR_LB_OUTPUT, /* u32 bond-id. */
-#endif
- __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
- * from userspace. */
-
-#ifdef __KERNEL__
- OVS_ACTION_ATTR_SET_TO_MASKED, /* Kernel module internal masked
- * set action converted from
- * OVS_ACTION_ATTR_SET. */
-#endif
-};
-
-#define OVS_ACTION_ATTR_MAX (__OVS_ACTION_ATTR_MAX - 1)
-
-/* Meters. */
-#define OVS_METER_FAMILY "ovs_meter"
-#define OVS_METER_MCGROUP "ovs_meter"
-#define OVS_METER_VERSION 0x1
-
-enum ovs_meter_cmd {
- OVS_METER_CMD_UNSPEC,
- OVS_METER_CMD_FEATURES, /* Get features supported by the datapath. */
- OVS_METER_CMD_SET, /* Add or modify a meter. */
- OVS_METER_CMD_DEL, /* Delete a meter. */
- OVS_METER_CMD_GET /* Get meter stats. */
-};
-
-enum ovs_meter_attr {
- OVS_METER_ATTR_UNSPEC,
- OVS_METER_ATTR_ID, /* u32 meter ID within datapath. */
- OVS_METER_ATTR_KBPS, /* No argument. If set, units in kilobits
- * per second. Otherwise, units in
- * packets per second.
- */
- OVS_METER_ATTR_STATS, /* struct ovs_flow_stats for the meter. */
- OVS_METER_ATTR_BANDS, /* Nested attributes for meter bands. */
- OVS_METER_ATTR_USED, /* u64 msecs last used in monotonic time. */
- OVS_METER_ATTR_CLEAR, /* Flag to clear stats, used. */
- OVS_METER_ATTR_MAX_METERS, /* u32 number of meters supported. */
- OVS_METER_ATTR_MAX_BANDS, /* u32 max number of bands per meter. */
- OVS_METER_ATTR_PAD,
- __OVS_METER_ATTR_MAX
-};
-
-#define OVS_METER_ATTR_MAX (__OVS_METER_ATTR_MAX - 1)
-
-enum ovs_band_attr {
- OVS_BAND_ATTR_UNSPEC,
- OVS_BAND_ATTR_TYPE, /* u32 OVS_METER_BAND_TYPE_* constant. */
- OVS_BAND_ATTR_RATE, /* u32 band rate in meter units (see above). */
- OVS_BAND_ATTR_BURST, /* u32 burst size in meter units. */
- OVS_BAND_ATTR_STATS, /* struct ovs_flow_stats for the band. */
- __OVS_BAND_ATTR_MAX
-};
-
-#define OVS_BAND_ATTR_MAX (__OVS_BAND_ATTR_MAX - 1)
-
-enum ovs_meter_band_type {
- OVS_METER_BAND_TYPE_UNSPEC,
- OVS_METER_BAND_TYPE_DROP, /* Drop exceeding packets. */
- __OVS_METER_BAND_TYPE_MAX
-};
-
-#define OVS_METER_BAND_TYPE_MAX (__OVS_METER_BAND_TYPE_MAX - 1)
-
-/* Conntrack limit */
-#define OVS_CT_LIMIT_FAMILY "ovs_ct_limit"
-#define OVS_CT_LIMIT_MCGROUP "ovs_ct_limit"
-#define OVS_CT_LIMIT_VERSION 0x1
-
-enum ovs_ct_limit_cmd {
- OVS_CT_LIMIT_CMD_UNSPEC,
- OVS_CT_LIMIT_CMD_SET, /* Add or modify ct limit. */
- OVS_CT_LIMIT_CMD_DEL, /* Delete ct limit. */
- OVS_CT_LIMIT_CMD_GET /* Get ct limit. */
-};
-
-enum ovs_ct_limit_attr {
- OVS_CT_LIMIT_ATTR_UNSPEC,
- OVS_CT_LIMIT_ATTR_ZONE_LIMIT, /* Nested struct ovs_zone_limit. */
- __OVS_CT_LIMIT_ATTR_MAX
-};
-
-#define OVS_CT_LIMIT_ATTR_MAX (__OVS_CT_LIMIT_ATTR_MAX - 1)
-
-#define OVS_ZONE_LIMIT_DEFAULT_ZONE -1
-
-struct ovs_zone_limit {
- int zone_id;
- __u32 limit;
- __u32 count;
-};
-
-#define OVS_CLONE_ATTR_EXEC 0 /* Specify an u32 value. When nonzero,
- * actions in clone will not change flow
- * keys. False otherwise.
- */
-
-#endif /* _LINUX_OPENVSWITCH_H */
diff --git a/datapath/linux/compat/include/linux/overflow.h b/datapath/linux/compat/include/linux/overflow.h
deleted file mode 100644
index 13ae6cf6a..000000000
--- a/datapath/linux/compat/include/linux/overflow.h
+++ /dev/null
@@ -1,313 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR MIT */
-#if defined(HAVE_OVERFLOW_H) && defined(HAVE_STRUCT_SIZE)
-#include_next <linux/overflow.h>
-#else
-#ifndef __LINUX_OVERFLOW_H
-#define __LINUX_OVERFLOW_H
-
-#include <linux/compiler.h>
-
-/*
- * In the fallback code below, we need to compute the minimum and
- * maximum values representable in a given type. These macros may also
- * be useful elsewhere, so we provide them outside the
- * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block.
- *
- * It would seem more obvious to do something like
- *
- * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
- * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
- *
- * Unfortunately, the middle expressions, strictly speaking, have
- * undefined behaviour, and at least some versions of gcc warn about
- * the type_max expression (but not if -fsanitize=undefined is in
- * effect; in that case, the warning is deferred to runtime...).
- *
- * The slightly excessive casting in type_min is to make sure the
- * macros also produce sensible values for the exotic type _Bool. [The
- * overflow checkers only almost work for _Bool, but that's
- * a-feature-not-a-bug, since people shouldn't be doing arithmetic on
- * _Bools. Besides, the gcc builtins don't allow _Bool* as third
- * argument.]
- *
- * Idea stolen from
- * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
- * credit to Christian Biere.
- */
-#define is_signed_type(type) (((type)(-1)) < (type)1)
-#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
-#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
-#define type_min(T) ((T)((T)-type_max(T)-(T)1))
-
-
-#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
-/*
- * For simplicity and code hygiene, the fallback code below insists on
- * a, b and *d having the same type (similar to the min() and max()
- * macros), whereas gcc's type-generic overflow checkers accept
- * different types. Hence we don't just make check_add_overflow an
- * alias for __builtin_add_overflow, but add type checks similar to
- * below.
- */
-#define check_add_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- __builtin_add_overflow(__a, __b, __d); \
-})
-
-#define check_sub_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- __builtin_sub_overflow(__a, __b, __d); \
-})
-
-#define check_mul_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- __builtin_mul_overflow(__a, __b, __d); \
-})
-
-#else
-
-
-/* Checking for unsigned overflow is relatively easy without causing UB. */
-#define __unsigned_add_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- *__d = __a + __b; \
- *__d < __a; \
-})
-#define __unsigned_sub_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- *__d = __a - __b; \
- __a < __b; \
-})
-/*
- * If one of a or b is a compile-time constant, this avoids a division.
- */
-#define __unsigned_mul_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- *__d = __a * __b; \
- __builtin_constant_p(__b) ? \
- __b > 0 && __a > type_max(typeof(__a)) / __b : \
- __a > 0 && __b > type_max(typeof(__b)) / __a; \
-})
-
-/*
- * For signed types, detecting overflow is much harder, especially if
- * we want to avoid UB. But the interface of these macros is such that
- * we must provide a result in *d, and in fact we must produce the
- * result promised by gcc's builtins, which is simply the possibly
- * wrapped-around value. Fortunately, we can just formally do the
- * operations in the widest relevant unsigned type (u64) and then
- * truncate the result - gcc is smart enough to generate the same code
- * with and without the (u64) casts.
- */
-
-/*
- * Adding two signed integers can overflow only if they have the same
- * sign, and overflow has happened iff the result has the opposite
- * sign.
- */
-#define __signed_add_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- *__d = (u64)__a + (u64)__b; \
- (((~(__a ^ __b)) & (*__d ^ __a)) \
- & type_min(typeof(__a))) != 0; \
-})
-
-/*
- * Subtraction is similar, except that overflow can now happen only
- * when the signs are opposite. In this case, overflow has happened if
- * the result has the opposite sign of a.
- */
-#define __signed_sub_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- *__d = (u64)__a - (u64)__b; \
- ((((__a ^ __b)) & (*__d ^ __a)) \
- & type_min(typeof(__a))) != 0; \
-})
-
-/*
- * Signed multiplication is rather hard. gcc always follows C99, so
- * division is truncated towards 0. This means that we can write the
- * overflow check like this:
- *
- * (a > 0 && (b > MAX/a || b < MIN/a)) ||
- * (a < -1 && (b > MIN/a || b < MAX/a) ||
- * (a == -1 && b == MIN)
- *
- * The redundant casts of -1 are to silence an annoying -Wtype-limits
- * (included in -Wextra) warning: When the type is u8 or u16, the
- * __b_c_e in check_mul_overflow obviously selects
- * __unsigned_mul_overflow, but unfortunately gcc still parses this
- * code and warns about the limited range of __b.
- */
-
-#define __signed_mul_overflow(a, b, d) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- typeof(d) __d = (d); \
- typeof(a) __tmax = type_max(typeof(a)); \
- typeof(a) __tmin = type_min(typeof(a)); \
- (void) (&__a == &__b); \
- (void) (&__a == __d); \
- *__d = (u64)__a * (u64)__b; \
- (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \
- (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \
- (__b == (typeof(__b))-1 && __a == __tmin); \
-})
-
-
-#define check_add_overflow(a, b, d) \
- __builtin_choose_expr(is_signed_type(typeof(a)), \
- __signed_add_overflow(a, b, d), \
- __unsigned_add_overflow(a, b, d))
-
-#define check_sub_overflow(a, b, d) \
- __builtin_choose_expr(is_signed_type(typeof(a)), \
- __signed_sub_overflow(a, b, d), \
- __unsigned_sub_overflow(a, b, d))
-
-#define check_mul_overflow(a, b, d) \
- __builtin_choose_expr(is_signed_type(typeof(a)), \
- __signed_mul_overflow(a, b, d), \
- __unsigned_mul_overflow(a, b, d))
-
-
-#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
-
-/** check_shl_overflow() - Calculate a left-shifted value and check overflow
- *
- * @a: Value to be shifted
- * @s: How many bits left to shift
- * @d: Pointer to where to store the result
- *
- * Computes *@d = (@a << @s)
- *
- * Returns true if '*d' cannot hold the result or when 'a << s' doesn't
- * make sense. Example conditions:
- * - 'a << s' causes bits to be lost when stored in *d.
- * - 's' is garbage (e.g. negative) or so large that the result of
- * 'a << s' is guaranteed to be 0.
- * - 'a' is negative.
- * - 'a << s' sets the sign bit, if any, in '*d'.
- *
- * '*d' will hold the results of the attempted shift, but is not
- * considered "safe for use" if false is returned.
- */
-#define check_shl_overflow(a, s, d) ({ \
- typeof(a) _a = a; \
- typeof(s) _s = s; \
- typeof(d) _d = d; \
- u64 _a_full = _a; \
- unsigned int _to_shift = \
- _s >= 0 && _s < 8 * sizeof(*d) ? _s : 0; \
- *_d = (_a_full << _to_shift); \
- (_to_shift != _s || *_d < 0 || _a < 0 || \
- (*_d >> _to_shift) != _a); \
-})
-
-/**
- * array_size() - Calculate size of 2-dimensional array.
- *
- * @a: dimension one
- * @b: dimension two
- *
- * Calculates size of 2-dimensional array: @a * @b.
- *
- * Returns: number of bytes needed to represent the array or SIZE_MAX on
- * overflow.
- */
-static inline __must_check size_t array_size(size_t a, size_t b)
-{
- size_t bytes;
-
- if (check_mul_overflow(a, b, &bytes))
- return SIZE_MAX;
-
- return bytes;
-}
-
-/**
- * array3_size() - Calculate size of 3-dimensional array.
- *
- * @a: dimension one
- * @b: dimension two
- * @c: dimension three
- *
- * Calculates size of 3-dimensional array: @a * @b * @c.
- *
- * Returns: number of bytes needed to represent the array or SIZE_MAX on
- * overflow.
- */
-static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
-{
- size_t bytes;
-
- if (check_mul_overflow(a, b, &bytes))
- return SIZE_MAX;
- if (check_mul_overflow(bytes, c, &bytes))
- return SIZE_MAX;
-
- return bytes;
-}
-
-static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
-{
- size_t bytes;
-
- if (check_mul_overflow(n, size, &bytes))
- return SIZE_MAX;
- if (check_add_overflow(bytes, c, &bytes))
- return SIZE_MAX;
-
- return bytes;
-}
-
-/**
- * struct_size() - Calculate size of structure with trailing array.
- * @p: Pointer to the structure.
- * @member: Name of the array member.
- * @n: Number of elements in the array.
- *
- * Calculates size of memory needed for structure @p followed by an
- * array of @n @member elements.
- *
- * Return: number of bytes needed or SIZE_MAX on overflow.
- */
-#define struct_size(p, member, n) \
- __ab_c_size(n, \
- sizeof(*(p)->member) + __must_be_array((p)->member),\
- sizeof(*(p)))
-
-#endif /* __LINUX_OVERFLOW_H */
-#endif /* defined(HAVE_OVERFLOW_H) && defined(HAVE_STRUCT_SIZE) */
diff --git a/datapath/linux/compat/include/linux/percpu.h b/datapath/linux/compat/include/linux/percpu.h
deleted file mode 100644
index a039142e2..000000000
--- a/datapath/linux/compat/include/linux/percpu.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __LINUX_PERCPU_WRAPPER_H
-#define __LINUX_PERCPU_WRAPPER_H 1
-
-#include_next <linux/percpu.h>
-
-#if !defined this_cpu_ptr
-#define this_cpu_ptr(ptr) per_cpu_ptr(ptr, smp_processor_id())
-#endif
-
-#if !defined this_cpu_read
-#define this_cpu_read(ptr) percpu_read(ptr)
-#endif
-
-#if !defined this_cpu_inc
-#define this_cpu_inc(ptr) percpu_add(ptr, 1)
-#endif
-
-#if !defined this_cpu_dec
-#define this_cpu_dec(ptr) percpu_sub(ptr, 1)
-#endif
-
-#ifndef alloc_percpu_gfp
-#define NEED_ALLOC_PERCPU_GFP
-
-void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp);
-
-#define alloc_percpu_gfp(type, gfp) \
- (typeof(type) __percpu *)__alloc_percpu_gfp(sizeof(type), \
- __alignof__(type), gfp)
-#endif
-
-
-#endif
diff --git a/datapath/linux/compat/include/linux/random.h b/datapath/linux/compat/include/linux/random.h
deleted file mode 100644
index 5c088a2d8..000000000
--- a/datapath/linux/compat/include/linux/random.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __LINUX_RANDOM_WRAPPER_H
-#define __LINUX_RANDOM_WRAPPER_H 1
-
-#include_next <linux/random.h>
-
-#ifndef HAVE_PRANDOM_U32
-#define prandom_u32() random32()
-#endif
-
-#ifndef HAVE_PRANDOM_U32_MAX
-static inline u32 prandom_u32_max(u32 ep_ro)
-{
- return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
-}
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/rbtree.h b/datapath/linux/compat/include/linux/rbtree.h
deleted file mode 100644
index dbf20ff0e..000000000
--- a/datapath/linux/compat/include/linux/rbtree.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __LINUX_RBTREE_WRAPPER_H
-#define __LINUX_RBTREE_WRAPPER_H 1
-
-#include_next <linux/rbtree.h>
-
-#ifndef HAVE_RBTREE_RB_LINK_NODE_RCU
-#include <linux/rcupdate.h>
-
-static inline void rb_link_node_rcu(struct rb_node *node, struct rb_node *parent,
- struct rb_node **rb_link)
-{
- node->__rb_parent_color = (unsigned long)parent;
- node->rb_left = node->rb_right = NULL;
-
- rcu_assign_pointer(*rb_link, node);
-}
-#endif
-
-#endif /* __LINUX_RBTREE_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/rculist.h b/datapath/linux/compat/include/linux/rculist.h
deleted file mode 100644
index 40fd5e171..000000000
--- a/datapath/linux/compat/include/linux/rculist.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __LINUX_RCULIST_WRAPPER_H
-#define __LINUX_RCULIST_WRAPPER_H
-
-#include_next <linux/rculist.h>
-
-#ifndef hlist_first_rcu
-#define hlist_first_rcu(head) (*((struct hlist_node __rcu **)(&(head)->first)))
-#define hlist_next_rcu(node) (*((struct hlist_node __rcu **)(&(node)->next)))
-#define hlist_pprev_rcu(node) (*((struct hlist_node __rcu **)((node)->pprev)))
-#endif
-
-/*
- * Check during list traversal that we are within an RCU reader
- */
-
-#define check_arg_count_one(dummy)
-
-#ifdef CONFIG_PROVE_RCU_LIST
-#define __list_check_rcu(dummy, cond, extra...) \
- ({ \
- check_arg_count_one(extra); \
- RCU_LOCKDEP_WARN(!cond && !rcu_read_lock_any_held(), \
- "RCU-list traversed in non-reader section!"); \
- })
-#else
-#define __list_check_rcu(dummy, cond, extra...) \
- ({ check_arg_count_one(extra); })
-#endif
-
-#undef hlist_for_each_entry_rcu
-#define hlist_for_each_entry_rcu(pos, head, member, cond...) \
- for (__list_check_rcu(dummy, ## cond, 0), \
- pos = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(head)),\
- typeof(*(pos)), member); \
- pos; \
- pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
- &(pos)->member)), typeof(*(pos)), member))
-
-#endif
diff --git a/datapath/linux/compat/include/linux/rcupdate.h b/datapath/linux/compat/include/linux/rcupdate.h
deleted file mode 100644
index 85e3c3b76..000000000
--- a/datapath/linux/compat/include/linux/rcupdate.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __RCUPDATE_WRAPPER_H
-#define __RCUPDATE_WRAPPER_H 1
-
-#include_next <linux/rcupdate.h>
-
-#ifndef rcu_dereference_check
-#define rcu_dereference_check(p, c) rcu_dereference(p)
-#endif
-
-#ifndef rcu_dereference_protected
-#define rcu_dereference_protected(p, c) (p)
-#endif
-
-#ifndef rcu_dereference_raw
-#define rcu_dereference_raw(p) rcu_dereference_check(p, 1)
-#endif
-
-#ifndef rcu_access_pointer
-#define rcu_access_pointer(p) rcu_dereference(p)
-#endif
-
-#ifndef HAVE_RCU_READ_LOCK_HELD
-static inline int rcu_read_lock_held(void)
-{
- return 1;
-}
-#endif
-
-#ifndef RCU_INITIALIZER
-#define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v)
-#endif
-
-#ifndef RCU_INIT_POINTER
-#define RCU_INIT_POINTER(p, v) \
- do { \
- p = RCU_INITIALIZER(v); \
- } while (0)
-
-#endif
-
-#endif /* linux/rcupdate.h wrapper */
diff --git a/datapath/linux/compat/include/linux/reciprocal_div.h b/datapath/linux/compat/include/linux/reciprocal_div.h
deleted file mode 100644
index f50d8e4ee..000000000
--- a/datapath/linux/compat/include/linux/reciprocal_div.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _LINUX_RECIPROCAL_DIV_WRAPPER_H
-#define _LINUX_RECIPROCAL_DIV_WRAPPER_H 1
-
-#include <linux/types.h>
-
-/*
- * This algorithm is based on the paper "Division by Invariant
- * Integers Using Multiplication" by Torbjörn Granlund and Peter
- * L. Montgomery.
- *
- * The assembler implementation from Agner Fog, which this code is
- * based on, can be found here:
- * http://www.agner.org/optimize/asmlib.zip
- *
- * This optimization for A/B is helpful if the divisor B is mostly
- * runtime invariant. The reciprocal of B is calculated in the
- * slow-path with reciprocal_value(). The fast-path can then just use
- * a much faster multiplication operation with a variable dividend A
- * to calculate the division A/B.
- */
-
-#define reciprocal_value rpl_reciprocal_value
-struct reciprocal_value {
- u32 m;
- u8 sh1, sh2;
-};
-
-struct reciprocal_value rpl_reciprocal_value(u32 d);
-
-#define reciprocal_divide rpl_reciprocal_divide
-static inline u32 rpl_reciprocal_divide(u32 a, struct reciprocal_value R)
-{
- u32 t = (u32)(((u64)a * R.m) >> 32);
- return (t + ((a - t) >> R.sh1)) >> R.sh2;
-}
-
-#endif /* _LINUX_RECIPROCAL_DIV_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/rtnetlink.h b/datapath/linux/compat/include/linux/rtnetlink.h
deleted file mode 100644
index cd1e1a0c0..000000000
--- a/datapath/linux/compat/include/linux/rtnetlink.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __RTNETLINK_WRAPPER_H
-#define __RTNETLINK_WRAPPER_H 1
-
-#include_next <linux/rtnetlink.h>
-
-#ifndef HAVE_LOCKDEP_RTNL_IS_HELD
-#ifdef CONFIG_PROVE_LOCKING
-static inline int lockdep_rtnl_is_held(void)
-{
- return 1;
-}
-#endif
-#endif
-
-#ifndef rcu_dereference_rtnl
-/**
- * rcu_dereference_rtnl - rcu_dereference with debug checking
- * @p: The pointer to read, prior to dereferencing
- *
- * Do an rcu_dereference(p), but check caller either holds rcu_read_lock()
- * or RTNL. Note : Please prefer rtnl_dereference() or rcu_dereference()
- */
-#define rcu_dereference_rtnl(p) \
- rcu_dereference_check(p, rcu_read_lock_held() || \
- lockdep_rtnl_is_held())
-#endif
-
-#ifndef rtnl_dereference
-/**
- * rtnl_dereference - fetch RCU pointer when updates are prevented by RTNL
- * @p: The pointer to read, prior to dereferencing
- *
- * Return the value of the specified RCU-protected pointer, but omit
- * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
- * caller holds RTNL.
- */
-#define rtnl_dereference(p) \
- rcu_dereference_protected(p, lockdep_rtnl_is_held())
-#endif
-
-#endif /* linux/rtnetlink.h wrapper */
diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
deleted file mode 100644
index 396a5e406..000000000
--- a/datapath/linux/compat/include/linux/skbuff.h
+++ /dev/null
@@ -1,491 +0,0 @@
-#ifndef __LINUX_SKBUFF_WRAPPER_H
-#define __LINUX_SKBUFF_WRAPPER_H 1
-
-#include <linux/version.h>
-#include <linux/types.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
-/* This should be before skbuff.h to make sure that we rewrite
- * the calls there. */
-struct sk_buff;
-
-int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
- gfp_t gfp_mask);
-#define pskb_expand_head rpl_pskb_expand_head
-#endif
-
-#include_next <linux/skbuff.h>
-#include <linux/jhash.h>
-
-#ifndef HAVE_IGNORE_DF_RENAME
-#define ignore_df local_df
-#endif
-
-
-#ifndef HAVE_NULL_COMPUTE_PSEUDO
-static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto)
-{
- return 0;
-}
-#endif
-
-#ifndef HAVE_SKB_CHECKSUM_CONVERT
-static inline bool __skb_checksum_convert_check(struct sk_buff *skb)
-{
-#ifdef HAVE_SKBUFF_CSUM_VALID
- return (skb->ip_summed == CHECKSUM_NONE && skb->csum_valid);
-#else
- return skb->ip_summed == CHECKSUM_NONE;
-#endif
-}
-
-static inline void __skb_checksum_convert(struct sk_buff *skb,
- __sum16 check, __wsum pseudo)
-{
- skb->csum = ~pseudo;
- skb->ip_summed = CHECKSUM_COMPLETE;
-}
-
-#define skb_checksum_try_convert(skb, proto, check, compute_pseudo) \
-do { \
- if (__skb_checksum_convert_check(skb)) \
- __skb_checksum_convert(skb, check, \
- compute_pseudo(skb, proto)); \
-} while (0)
-
-#endif
-
-#ifndef SKB_CHECKSUM_SIMPLE_VALIDATE
-
-#ifndef __skb_checksum_validate
-#define __skb_checksum_validate(skb, proto, complete, \
- zero_okay, check, compute_pseudo) \
-({ \
- __sum16 __ret = 0; \
- __ret; \
-})
-#endif
-
-#define skb_checksum_simple_validate(skb) \
- __skb_checksum_validate(skb, 0, true, false, 0, null_compute_pseudo)
-#endif
-
-#ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET
-static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb,
- const int offset, void *to,
- const unsigned int len)
-{
- memcpy(to, skb->data + offset, len);
-}
-
-static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
- const int offset,
- const void *from,
- const unsigned int len)
-{
- memcpy(skb->data + offset, from, len);
-}
-
-#endif /* !HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET */
-
-#ifndef HAVE_SKB_INNER_TRANSPORT_OFFSET
-static inline int skb_inner_transport_offset(const struct sk_buff *skb)
-{
- return skb_inner_transport_header(skb) - skb->data;
-}
-#endif
-
-#ifndef HAVE_SKB_RESET_TAIL_POINTER
-static inline void skb_reset_tail_pointer(struct sk_buff *skb)
-{
- skb->tail = skb->data;
-}
-#endif
-/*
- * The networking layer reserves some headroom in skb data (via
- * dev_alloc_skb). This is used to avoid having to reallocate skb data when
- * the header has to grow. In the default case, if the header has to grow
- * 16 bytes or less we avoid the reallocation.
- *
- * Unfortunately this headroom changes the DMA alignment of the resulting
- * network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive
- * on some architectures. An architecture can override this value,
- * perhaps setting it to a cacheline in size (since that will maintain
- * cacheline alignment of the DMA). It must be a power of 2.
- *
- * Various parts of the networking layer expect at least 16 bytes of
- * headroom, you should not reduce this.
- */
-#ifndef NET_SKB_PAD
-#define NET_SKB_PAD 16
-#endif
-
-#ifndef HAVE_SKB_COW_HEAD
-static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
- int cloned)
-{
- int delta = 0;
-
- if (headroom < NET_SKB_PAD)
- headroom = NET_SKB_PAD;
- if (headroom > skb_headroom(skb))
- delta = headroom - skb_headroom(skb);
-
- if (delta || cloned)
- return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0,
- GFP_ATOMIC);
- return 0;
-}
-
-static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
-{
- return __skb_cow(skb, headroom, skb_header_cloned(skb));
-}
-#endif /* !HAVE_SKB_COW_HEAD */
-
-#ifndef HAVE_SKB_DST_ACCESSOR_FUNCS
-static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
-{
- return (struct dst_entry *)skb->dst;
-}
-
-static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
-{
- skb->dst = dst;
-}
-
-static inline struct rtable *skb_rtable(const struct sk_buff *skb)
-{
- return (struct rtable *)skb->dst;
-}
-#endif
-
-#ifndef CHECKSUM_PARTIAL
-#define CHECKSUM_PARTIAL CHECKSUM_HW
-#endif
-#ifndef CHECKSUM_COMPLETE
-#define CHECKSUM_COMPLETE CHECKSUM_HW
-#endif
-
-#ifndef HAVE_SKB_WARN_LRO
-#ifndef NETIF_F_LRO
-static inline bool skb_warn_if_lro(const struct sk_buff *skb)
-{
- return false;
-}
-#else
-extern void __skb_warn_lro_forwarding(const struct sk_buff *skb);
-
-static inline bool skb_warn_if_lro(const struct sk_buff *skb)
-{
- /* LRO sets gso_size but not gso_type, whereas if GSO is really
- * wanted then gso_type will be set. */
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- if (shinfo->gso_size != 0 && unlikely(shinfo->gso_type == 0)) {
- __skb_warn_lro_forwarding(skb);
- return true;
- }
- return false;
-}
-#endif /* NETIF_F_LRO */
-#endif /* HAVE_SKB_WARN_LRO */
-
-#ifndef HAVE_CONSUME_SKB
-#define consume_skb kfree_skb
-#endif
-
-#ifndef HAVE_SKB_FRAG_PAGE
-#include <linux/mm.h>
-
-static inline struct page *skb_frag_page(const skb_frag_t *frag)
-{
- return frag->page;
-}
-
-static inline void __skb_frag_set_page(skb_frag_t *frag, struct page *page)
-{
- frag->page = page;
-}
-static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size)
-{
- frag->size = size;
-}
-static inline void __skb_frag_ref(skb_frag_t *frag)
-{
- get_page(skb_frag_page(frag));
-}
-static inline void __skb_frag_unref(skb_frag_t *frag)
-{
- put_page(skb_frag_page(frag));
-}
-
-static inline void skb_frag_ref(struct sk_buff *skb, int f)
-{
- __skb_frag_ref(&skb_shinfo(skb)->frags[f]);
-}
-
-static inline void skb_frag_unref(struct sk_buff *skb, int f)
-{
- __skb_frag_unref(&skb_shinfo(skb)->frags[f]);
-}
-
-#endif
-
-#ifndef HAVE_SKB_RESET_MAC_LEN
-static inline void skb_reset_mac_len(struct sk_buff *skb)
-{
- skb->mac_len = skb->network_header - skb->mac_header;
-}
-#endif
-
-#ifndef HAVE_SKB_UNCLONE
-static inline int skb_unclone(struct sk_buff *skb, gfp_t pri)
-{
- might_sleep_if(pri & __GFP_WAIT);
-
- if (skb_cloned(skb))
- return pskb_expand_head(skb, 0, 0, pri);
-
- return 0;
-}
-#endif
-
-#ifndef HAVE_SKB_ORPHAN_FRAGS
-static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask)
-{
- return 0;
-}
-#endif
-
-#ifndef HAVE_SKB_GET_HASH
-#define skb_get_hash skb_get_rxhash
-#endif /* HAVE_SKB_GET_HASH */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
-#define skb_zerocopy_headlen rpl_skb_zerocopy_headlen
-unsigned int rpl_skb_zerocopy_headlen(const struct sk_buff *from);
-#endif
-
-#ifndef HAVE_SKB_ZEROCOPY
-#define skb_zerocopy rpl_skb_zerocopy
-int rpl_skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len,
- int hlen);
-#endif
-
-#ifndef HAVE_SKB_CLEAR_HASH
-static inline void skb_clear_hash(struct sk_buff *skb)
-{
-#ifdef HAVE_RXHASH
- skb->rxhash = 0;
-#endif
- skb->l4_hash = 0;
-}
-#endif
-
-#ifndef HAVE_SKB_HAS_FRAG_LIST
-#define skb_has_frag_list skb_has_frags
-#endif
-
-#ifndef HAVE___SKB_FILL_PAGE_DESC
-static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
- struct page *page, int off, int size)
-{
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
- __skb_frag_set_page(frag, page);
- frag->page_offset = off;
- skb_frag_size_set(frag, size);
-}
-#endif
-
-#ifndef HAVE_SKB_ENSURE_WRITABLE
-#define skb_ensure_writable rpl_skb_ensure_writable
-int rpl_skb_ensure_writable(struct sk_buff *skb, int write_len);
-#endif
-
-#ifndef HAVE___SKB_VLAN_POP
-#define __skb_vlan_pop rpl___skb_vlan_pop
-int rpl___skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci);
-#endif
-
-#ifndef HAVE_SKB_VLAN_POP
-#define skb_vlan_pop rpl_skb_vlan_pop
-int rpl_skb_vlan_pop(struct sk_buff *skb);
-#endif
-
-#ifndef HAVE_SKB_VLAN_PUSH
-#define skb_vlan_push rpl_skb_vlan_push
-int rpl_skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
-#endif
-
-#ifndef HAVE_KFREE_SKB_LIST
-void rpl_kfree_skb_list(struct sk_buff *segs);
-#define kfree_skb_list rpl_kfree_skb_list
-#endif
-
-#ifndef HAVE_SKB_CHECKSUM_START_OFFSET
-static inline int skb_checksum_start_offset(const struct sk_buff *skb)
-{
- return skb->csum_start - skb_headroom(skb);
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0)
-#define skb_postpull_rcsum rpl_skb_postpull_rcsum
-static inline void skb_postpull_rcsum(struct sk_buff *skb,
- const void *start, unsigned int len)
-{
- if (skb->ip_summed == CHECKSUM_COMPLETE)
- skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0));
- else if (skb->ip_summed == CHECKSUM_PARTIAL &&
- skb_checksum_start_offset(skb) < 0)
- skb->ip_summed = CHECKSUM_NONE;
-}
-
-#define skb_pull_rcsum rpl_skb_pull_rcsum
-static inline unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
-{
- unsigned char *data = skb->data;
-
- BUG_ON(len > skb->len);
- __skb_pull(skb, len);
- skb_postpull_rcsum(skb, data, len);
- return skb->data;
-}
-
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
-#define skb_scrub_packet rpl_skb_scrub_packet
-void rpl_skb_scrub_packet(struct sk_buff *skb, bool xnet);
-#endif
-
-#define skb_pop_mac_header rpl_skb_pop_mac_header
-static inline void skb_pop_mac_header(struct sk_buff *skb)
-{
- skb->mac_header = skb->network_header;
-}
-
-#ifndef HAVE_SKB_CLEAR_HASH_IF_NOT_L4
-static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
-{
- if (!skb->l4_hash)
- skb_clear_hash(skb);
-}
-#endif
-
-#ifndef HAVE_SKB_POSTPUSH_RCSUM
-static inline void skb_postpush_rcsum(struct sk_buff *skb,
- const void *start, unsigned int len)
-{
- /* For performing the reverse operation to skb_postpull_rcsum(),
- * we can instead of ...
- *
- * skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
- *
- * ... just use this equivalent version here to save a few
- * instructions. Feeding csum of 0 in csum_partial() and later
- * on adding skb->csum is equivalent to feed skb->csum in the
- * first place.
- */
- if (skb->ip_summed == CHECKSUM_COMPLETE)
- skb->csum = csum_partial(start, len, skb->csum);
-}
-#endif
-
-#define skb_checksum_start rpl_skb_checksum_start
-static inline unsigned char *skb_checksum_start(const struct sk_buff *skb)
-{
- return skb->head + skb->csum_start;
-}
-
-#ifndef HAVE_LCO_CSUM
-static inline __wsum lco_csum(struct sk_buff *skb)
-{
- unsigned char *csum_start = skb_checksum_start(skb);
- unsigned char *l4_hdr = skb_transport_header(skb);
- __wsum partial;
-
- /* Start with complement of inner checksum adjustment */
- partial = ~csum_unfold(*(__force __sum16 *)(csum_start +
- skb->csum_offset));
-
- /* Add in checksum of our headers (incl. outer checksum
- * adjustment filled in by caller) and return result.
- */
- return csum_partial(l4_hdr, csum_start - l4_hdr, partial);
-}
-#endif
-
-#ifndef HAVE_SKB_NFCT
-static inline struct nf_conntrack *skb_nfct(const struct sk_buff *skb)
-{
-#if IS_ENABLED(CONFIG_NF_CONNTRACK)
- return skb->nfct;
-#else
- return NULL;
-#endif
-}
-#endif
-
-#ifndef HAVE_SKB_PUT_ZERO
-static inline void *skb_put_zero(struct sk_buff *skb, unsigned int len)
-{
- void *tmp = skb_put(skb, len);
-
- memset(tmp, 0, len);
-
- return tmp;
-}
-#endif
-
-#ifndef HAVE_SKB_GSO_IPXIP6
-#define SKB_GSO_IPXIP6 (1 << 10)
-#endif
-
-#ifndef HAVE_SKB_SET_INNER_IPPROTO
-static inline void skb_set_inner_ipproto(struct sk_buff *skb,
- __u8 ipproto)
-{
-}
-#endif
-
-#ifndef HAVE_NF_RESET_CT
-#define nf_reset_ct nf_reset
-#endif
-
-#ifndef HAVE___SKB_SET_HASH
-static inline void
-__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4)
-{
-#ifdef HAVE_RXHASH
- skb->rxhash = hash;
-#else
- skb->hash = hash;
-#endif
- skb->l4_hash = is_l4;
-#ifdef HAVE_SW_HASH
- skb->sw_hash = is_sw;
-#endif
-}
-#endif
-
-#ifndef HAVE_SKB_GET_HASH_RAW
-static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
-{
-#ifdef HAVE_RXHASH
- return skb->rxhash;
-#else
- return skb->hash;
-#endif
-}
-#endif
-
-#ifndef skb_list_walk_safe
-/* Iterate through singly-linked GSO fragments of an skb. */
-#define skb_list_walk_safe(first, skb, next_skb) \
- for ((skb) = (first), (next_skb) = (skb) ? (skb)->next : NULL; (skb); \
- (skb) = (next_skb), (next_skb) = (skb) ? (skb)->next : NULL)
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/static_key.h b/datapath/linux/compat/include/linux/static_key.h
deleted file mode 100644
index 432feccb9..000000000
--- a/datapath/linux/compat/include/linux/static_key.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef _STATIC_KEY_WRAPPER_H
-#define _STATIC_KEY_WRAPPER_H
-
-#include <linux/atomic.h>
-#include_next <linux/static_key.h>
-#ifndef HAVE_UPSTREAM_STATIC_KEY
-/*
- * This backport is based on upstream net-next commit 11276d5306b8
- * ("locking/static_keys: Add a new static_key interface").
- *
- * For kernel that does not support the new static key interface,
- * we do not backport the jump label support but the fall back version
- * of static key that is simply a conditional branch.
- */
-
-struct static_key_true {
- struct static_key key;
-};
-
-struct static_key_false {
- struct static_key key;
-};
-
-#define rpl_STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) }
-#define rpl_STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) }
-
-#define rpl_STATIC_KEY_TRUE_INIT \
- (struct static_key_true) { .key = rpl_STATIC_KEY_INIT_TRUE, }
-#define rpl_STATIC_KEY_FALSE_INIT \
- (struct static_key_false){ .key = rpl_STATIC_KEY_INIT_FALSE, }
-
-#define rpl_DEFINE_STATIC_KEY_TRUE(name) \
- struct static_key_true name = rpl_STATIC_KEY_TRUE_INIT
-
-#define rpl_DEFINE_STATIC_KEY_FALSE(name) \
- struct static_key_false name = rpl_STATIC_KEY_FALSE_INIT
-
-static inline int rpl_static_key_count(struct static_key *key)
-{
- return atomic_read(&key->enabled);
-}
-
-static inline void rpl_static_key_enable(struct static_key *key)
-{
- int count = rpl_static_key_count(key);
-
- WARN_ON_ONCE(count < 0 || count > 1);
-
- if (!count)
- static_key_slow_inc(key);
-}
-
-static inline void rpl_static_key_disable(struct static_key *key)
-{
- int count = rpl_static_key_count(key);
-
- WARN_ON_ONCE(count < 0 || count > 1);
-
- if (count)
- static_key_slow_dec(key);
-}
-
-#ifdef HAVE_DEFINE_STATIC_KEY
-#undef DEFINE_STATIC_KEY_TRUE
-#undef DEFINE_STATIC_KEY_FALSE
-#endif
-
-#define DEFINE_STATIC_KEY_TRUE rpl_DEFINE_STATIC_KEY_TRUE
-#define DEFINE_STATIC_KEY_FALSE rpl_DEFINE_STATIC_KEY_FALSE
-
-#define static_branch_likely(x) likely(static_key_enabled(&(x)->key))
-#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key))
-
-#define static_branch_enable(x) rpl_static_key_enable(&(x)->key)
-#define static_branch_disable(x) rpl_static_key_disable(&(x)->key)
-
-#ifndef HAVE_DECLARE_STATIC_KEY
-#define DECLARE_STATIC_KEY_TRUE(name) \
- extern struct static_key_true name
-#define DECLARE_STATIC_KEY_FALSE(name) \
- extern struct static_key_false name
-#endif
-
-#endif /* HAVE_UPSTREAM_STATIC_KEY */
-
-#endif /* _STATIC_KEY_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/stddef.h b/datapath/linux/compat/include/linux/stddef.h
deleted file mode 100644
index 5b44c0dee..000000000
--- a/datapath/linux/compat/include/linux/stddef.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __LINUX_STDDEF_WRAPPER_H
-#define __LINUX_STDDEF_WRAPPER_H 1
-
-#include_next <linux/stddef.h>
-
-#ifdef __KERNEL__
-
-#ifndef offsetofend
-#define offsetofend(TYPE, MEMBER) \
- (offsetof(TYPE, MEMBER) + sizeof(((TYPE *)0)->MEMBER))
-#endif
-
-#endif /* __KERNEL__ */
-
-#endif
diff --git a/datapath/linux/compat/include/linux/timekeeping.h b/datapath/linux/compat/include/linux/timekeeping.h
deleted file mode 100644
index 3a3b18331..000000000
--- a/datapath/linux/compat/include/linux/timekeeping.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _LINUX_TIMEKEEPING_WRAPPER_H
-#define _LINUX_TIMEKEEPING_WRAPPER_H
-
-#ifndef HAVE_KTIME_GET_TS64
-#define ktime_get_ts64 ktime_get_ts
-#define timespec64 timespec
-#else
-#include_next <linux/timekeeping.h>
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/types.h b/datapath/linux/compat/include/linux/types.h
deleted file mode 100644
index a58623e70..000000000
--- a/datapath/linux/compat/include/linux/types.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __LINUX_TYPES_WRAPPER_H
-#define __LINUX_TYPES_WRAPPER_H 1
-
-#include_next <linux/types.h>
-
-#ifndef HAVE_CSUM_TYPES
-typedef __u16 __bitwise __sum16;
-typedef __u32 __bitwise __wsum;
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/u64_stats_sync.h b/datapath/linux/compat/include/linux/u64_stats_sync.h
deleted file mode 100644
index 9342f73d0..000000000
--- a/datapath/linux/compat/include/linux/u64_stats_sync.h
+++ /dev/null
@@ -1,155 +0,0 @@
-#ifndef _LINUX_U64_STATS_SYNC_WRAPPER_H
-#define _LINUX_U64_STATS_SYNC_WRAPPER_H
-
-#include <linux/version.h>
-
-#if defined(HAVE_U64_STATS_FETCH_BEGIN_IRQ) && \
- LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
-#include_next <linux/u64_stats_sync.h>
-#else
-
-/*
- * To properly implement 64bits network statistics on 32bit and 64bit hosts,
- * we provide a synchronization point, that is a noop on 64bit or UP kernels.
- *
- * Key points :
- * 1) Use a seqcount on SMP 32bits, with low overhead.
- * 2) Whole thing is a noop on 64bit arches or UP kernels.
- * 3) Write side must ensure mutual exclusion or one seqcount update could
- * be lost, thus blocking readers forever.
- * If this synchronization point is not a mutex, but a spinlock or
- * spinlock_bh() or disable_bh() :
- * 3.1) Write side should not sleep.
- * 3.2) Write side should not allow preemption.
- * 3.3) If applicable, interrupts should be disabled.
- *
- * 4) If reader fetches several counters, there is no guarantee the whole values
- * are consistent (remember point 1) : this is a noop on 64bit arches anyway)
- *
- * 5) readers are allowed to sleep or be preempted/interrupted : They perform
- * pure reads. But if they have to fetch many values, it's better to not allow
- * preemptions/interruptions to avoid many retries.
- *
- * 6) If counter might be written by an interrupt, readers should block interrupts.
- * (On UP, there is no seqcount_t protection, a reader allowing interrupts could
- * read partial values)
- *
- * 7) For irq or softirq uses, readers can use u64_stats_fetch_begin_irq() and
- * u64_stats_fetch_retry_irq() helpers
- *
- * Usage :
- *
- * Stats producer (writer) should use following template granted it already got
- * an exclusive access to counters (a lock is already taken, or per cpu
- * data is used [in a non preemptable context])
- *
- * spin_lock_bh(...) or other synchronization to get exclusive access
- * ...
- * u64_stats_update_begin(&stats->syncp);
- * stats->bytes64 += len; // non atomic operation
- * stats->packets64++; // non atomic operation
- * u64_stats_update_end(&stats->syncp);
- *
- * While a consumer (reader) should use following template to get consistent
- * snapshot for each variable (but no guarantee on several ones)
- *
- * u64 tbytes, tpackets;
- * unsigned int start;
- *
- * do {
- * start = u64_stats_fetch_begin(&stats->syncp);
- * tbytes = stats->bytes64; // non atomic operation
- * tpackets = stats->packets64; // non atomic operation
- * } while (u64_stats_fetch_retry(&stats->syncp, start));
- *
- *
- * Example of use in drivers/net/loopback.c, using per_cpu containers,
- * in BH disabled context.
- */
-#include <linux/seqlock.h>
-
-struct u64_stats_sync {
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- seqcount_t seq;
-#endif
-};
-
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-# define u64_stats_init(syncp) seqcount_init(syncp.seq)
-#else
-# define u64_stats_init(syncp) do { } while (0)
-#endif
-
-static inline void u64_stats_update_begin(struct u64_stats_sync *syncp)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- write_seqcount_begin(&syncp->seq);
-#endif
-}
-
-static inline void u64_stats_update_end(struct u64_stats_sync *syncp)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- write_seqcount_end(&syncp->seq);
-#endif
-}
-
-static inline unsigned int u64_stats_fetch_begin(const struct u64_stats_sync *syncp)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- return read_seqcount_begin(&syncp->seq);
-#else
-#if BITS_PER_LONG==32
- preempt_disable();
-#endif
- return 0;
-#endif
-}
-
-static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
- unsigned int start)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- return read_seqcount_retry(&syncp->seq, start);
-#else
-#if BITS_PER_LONG==32
- preempt_enable();
-#endif
- return false;
-#endif
-}
-
-/*
- * In case irq handlers can update u64 counters, readers can use following helpers
- * - SMP 32bit arches use seqcount protection, irq safe.
- * - UP 32bit must disable irqs.
- * - 64bit have no problem atomically reading u64 values, irq safe.
- */
-static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- return read_seqcount_begin(&syncp->seq);
-#else
-#if BITS_PER_LONG==32
- local_irq_disable();
-#endif
- return 0;
-#endif
-}
-
-static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp,
- unsigned int start)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- return read_seqcount_retry(&syncp->seq, start);
-#else
-#if BITS_PER_LONG==32
- local_irq_enable();
-#endif
- return false;
-#endif
-}
-
-#endif /* !HAVE_U64_STATS_FETCH_BEGIN_IRQ || kernel < 3.13 */
-
-#endif /* _LINUX_U64_STATS_SYNC_WRAPPER_H */
diff --git a/datapath/linux/compat/include/linux/udp.h b/datapath/linux/compat/include/linux/udp.h
deleted file mode 100644
index 22e57d4c0..000000000
--- a/datapath/linux/compat/include/linux/udp.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __LINUX_UDP_WRAPPER_H
-#define __LINUX_UDP_WRAPPER_H 1
-
-#include_next <linux/udp.h>
-#include <linux/ipv6.h>
-
-#ifndef HAVE_NO_CHECK6_TX
-static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
-{
-#ifdef HAVE_SK_NO_CHECK_TX
- sk->sk_no_check_tx = val;
-#endif
-}
-
-static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
-{
-#ifdef HAVE_SK_NO_CHECK_TX
- sk->sk_no_check_rx = val;
-#else
- /* since netwroking stack is not checking for zero UDP checksum
- * check it in OVS module. */
- #define OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
-#endif
-}
-#endif
-
-#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
-#define udp6_csum_zero_error rpl_udp6_csum_zero_error
-
-void rpl_udp6_csum_zero_error(struct sk_buff *skb);
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/workqueue.h b/datapath/linux/compat/include/linux/workqueue.h
deleted file mode 100644
index ed573c226..000000000
--- a/datapath/linux/compat/include/linux/workqueue.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __LINUX_WORKQUEUE_WRAPPER_H
-#define __LINUX_WORKQUEUE_WRAPPER_H 1
-
-#include_next <linux/workqueue.h>
-
-#endif
diff --git a/datapath/linux/compat/include/net/checksum.h b/datapath/linux/compat/include/net/checksum.h
deleted file mode 100644
index d1f1125d1..000000000
--- a/datapath/linux/compat/include/net/checksum.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __NET_CHECKSUM_WRAPPER_H
-#define __NET_CHECKSUM_WRAPPER_H 1
-
-#include_next <net/checksum.h>
-
-#ifndef HAVE_CSUM_UNFOLD
-static inline __wsum csum_unfold(__sum16 n)
-{
- return (__force __wsum)n;
-}
-#endif /* !HAVE_CSUM_UNFOLD */
-
-/* Workaround for debugging included in certain versions of XenServer. It only
- * applies to 32-bit x86.
- */
-#if defined(HAVE_CSUM_COPY_DBG) && defined(CONFIG_X86_32)
-#define csum_and_copy_to_user(src, dst, len, sum, err_ptr) \
- csum_and_copy_to_user(src, dst, len, sum, NULL, err_ptr)
-#endif
-
-#ifndef HAVE_CSUM_REPLACE4
-static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
-{
- __be32 diff[] = { ~from, to };
-
- *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
-}
-
-static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
-{
- csum_replace4(sum, (__force __be32)from, (__force __be32)to);
-}
-#endif
-
-#ifndef CSUM_MANGLED_0
-#define CSUM_MANGLED_0 ((__force __sum16)0xffff)
-#endif
-
-#endif /* checksum.h */
diff --git a/datapath/linux/compat/include/net/dst.h b/datapath/linux/compat/include/net/dst.h
deleted file mode 100644
index af78a6ca6..000000000
--- a/datapath/linux/compat/include/net/dst.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef __NET_DST_WRAPPER_H
-#define __NET_DST_WRAPPER_H 1
-
-#include <linux/version.h>
-#include_next <net/dst.h>
-
-#ifndef HAVE_SKB_DST_ACCESSOR_FUNCS
-
-static inline void skb_dst_drop(struct sk_buff *skb)
-{
- if (skb->dst)
- dst_release(skb_dst(skb));
- skb->dst = NULL;
-}
-
-#endif
-
-#ifndef DST_OBSOLETE_NONE
-#define DST_OBSOLETE_NONE 0
-#endif
-
-#ifndef DST_NOCOUNT
-#define DST_NOCOUNT 0
-#endif
-
-#if !defined(HAVE___SKB_DST_COPY)
-static inline void __skb_dst_copy(struct sk_buff *nskb, unsigned long refdst)
-{
- nskb->_skb_refdst = refdst;
- if (!(nskb->_skb_refdst & SKB_DST_NOREF))
- dst_clone(skb_dst(nskb));
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0)
-static const u32 rpl_dst_default_metrics[RTAX_MAX + 1] = {
- /* This initializer is needed to force linker to place this variable
- * into const section. Otherwise it might end into bss section.
- * We really want to avoid false sharing on this variable, and catch
- * any writes on it.
- */
- [RTAX_MAX] = 0xdeadbeef,
-};
-#define dst_default_metrics rpl_dst_default_metrics
-
-static inline void rpl_dst_init(struct dst_entry *dst, struct dst_ops *ops,
- struct net_device *dev, int initial_ref,
- int initial_obsolete, unsigned short flags)
-{
- /* XXX: It's easier to handle compatibility by zeroing, as we can
- * refer to fewer fields. Do that here.
- */
- memset(dst, 0, sizeof *dst);
-
- dst->dev = dev;
- if (dev)
- dev_hold(dev);
- dst->ops = ops;
- dst_init_metrics(dst, dst_default_metrics, true);
- dst->path = dst;
- dst->input = dst_discard;
-#ifndef HAVE_DST_DISCARD_SK
- dst->output = dst_discard;
-#else
- dst->output = dst_discard_sk;
-#endif
- dst->obsolete = initial_obsolete;
- atomic_set(&dst->__refcnt, initial_ref);
- dst->lastuse = jiffies;
- dst->flags = flags;
- if (!(flags & DST_NOCOUNT))
- dst_entries_add(ops, 1);
-}
-#define dst_init rpl_dst_init
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/net/dst_cache.h b/datapath/linux/compat/include/net/dst_cache.h
deleted file mode 100644
index 6084d4eea..000000000
--- a/datapath/linux/compat/include/net/dst_cache.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef _NET_DST_CACHE_WRAPPER_H
-#define _NET_DST_CACHE_WRAPPER_H
-
-#ifdef USE_BUILTIN_DST_CACHE
-#include_next <net/dst_cache.h>
-#else
-
-#include <linux/jiffies.h>
-#include <net/dst.h>
-#if IS_ENABLED(CONFIG_IPV6)
-#include <net/ip6_fib.h>
-#endif
-
-#ifdef USE_UPSTREAM_TUNNEL
-#include_next <net/dst_cache.h>
-
-#else
-struct dst_cache {
- struct dst_cache_pcpu __percpu *cache;
- unsigned long reset_ts;
-};
-
-/**
- * dst_cache_get - perform cache lookup
- * @dst_cache: the cache
- *
- * The caller should use dst_cache_get_ip4() if it need to retrieve the
- * source address to be used when xmitting to the cached dst.
- * local BH must be disabled.
- */
-#define rpl_dst_cache_get dst_cache_get
-struct dst_entry *rpl_dst_cache_get(struct dst_cache *dst_cache);
-
-/**
- * dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address
- * @dst_cache: the cache
- * @saddr: return value for the retrieved source address
- *
- * local BH must be disabled.
- */
-#define rpl_dst_cache_get_ip4 dst_cache_get_ip4
-struct rtable *rpl_dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr);
-
-/**
- * dst_cache_set_ip4 - store the ipv4 dst into the cache
- * @dst_cache: the cache
- * @dst: the entry to be cached
- * @saddr: the source address to be stored inside the cache
- *
- * local BH must be disabled.
- */
-#define rpl_dst_cache_set_ip4 dst_cache_set_ip4
-void rpl_dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
- __be32 saddr);
-
-#if IS_ENABLED(CONFIG_IPV6)
-
-/**
- * dst_cache_set_ip6 - store the ipv6 dst into the cache
- * @dst_cache: the cache
- * @dst: the entry to be cached
- * @saddr: the source address to be stored inside the cache
- *
- * local BH must be disabled.
- */
-#define rpl_dst_cache_set_ip6 dst_cache_set_ip6
-void rpl_dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
- const struct in6_addr *addr);
-
-/**
- * dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address
- * @dst_cache: the cache
- * @saddr: return value for the retrieved source address
- *
- * local BH must be disabled.
- */
-#define rpl_dst_cache_get_ip6 dst_cache_get_ip6
-struct dst_entry *rpl_dst_cache_get_ip6(struct dst_cache *dst_cache,
- struct in6_addr *saddr);
-#endif
-
-/**
- * dst_cache_reset - invalidate the cache contents
- * @dst_cache: the cache
- *
- * This do not free the cached dst to avoid races and contentions.
- * the dst will be freed on later cache lookup.
- */
-static inline void dst_cache_reset(struct dst_cache *dst_cache)
-{
- dst_cache->reset_ts = jiffies;
-}
-
-/**
- * dst_cache_init - initialize the cache, allocating the required storage
- * @dst_cache: the cache
- * @gfp: allocation flags
- */
-#define rpl_dst_cache_init dst_cache_init
-int rpl_dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp);
-
-/**
- * dst_cache_destroy - empty the cache and free the allocated storage
- * @dst_cache: the cache
- *
- * No synchronization is enforced: it must be called only when the cache
- * is unsed.
- */
-#define rpl_dst_cache_destroy dst_cache_destroy
-void rpl_dst_cache_destroy(struct dst_cache *dst_cache);
-
-#endif /* USE_UPSTREAM_TUNNEL */
-#endif /* USE_BUILTIN_DST_CACHE */
-#endif
diff --git a/datapath/linux/compat/include/net/dst_metadata.h b/datapath/linux/compat/include/net/dst_metadata.h
deleted file mode 100644
index 4ffafccce..000000000
--- a/datapath/linux/compat/include/net/dst_metadata.h
+++ /dev/null
@@ -1,269 +0,0 @@
-#ifndef __NET_DST_METADATA_WRAPPER_H
-#define __NET_DST_METADATA_WRAPPER_H 1
-
-#ifdef USE_UPSTREAM_TUNNEL
-#include_next <net/dst_metadata.h>
-#else
-#include <linux/skbuff.h>
-
-#include <net/dsfield.h>
-#include <net/dst.h>
-#include <net/ipv6.h>
-#include <net/ip_tunnels.h>
-
-enum metadata_type {
- METADATA_IP_TUNNEL,
- METADATA_HW_PORT_MUX,
-};
-
-struct hw_port_info {
- struct net_device *lower_dev;
- u32 port_id;
-};
-
-struct metadata_dst {
- struct dst_entry dst;
- enum metadata_type type;
- union {
- struct ip_tunnel_info tun_info;
- struct hw_port_info port_info;
- } u;
-};
-
-#ifndef DST_METADATA
-#define DST_METADATA 0x0080
-#endif
-
-extern struct dst_ops md_dst_ops;
-
-static void rpl__metadata_dst_init(struct metadata_dst *md_dst,
- enum metadata_type type, u8 optslen)
-
-{
- struct dst_entry *dst;
-
- dst = &md_dst->dst;
- dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE,
- DST_METADATA | DST_NOCOUNT);
-
-#if 0
- /* unused in OVS */
- dst->input = dst_md_discard;
- dst->output = dst_md_discard_out;
-#endif
- memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst));
- md_dst->type = type;
-}
-
-static struct
-metadata_dst *__rpl_metadata_dst_alloc(u8 optslen,
- enum metadata_type type,
- gfp_t flags)
-{
- struct metadata_dst *md_dst;
-
- md_dst = kmalloc(sizeof(*md_dst) + optslen, flags);
- if (!md_dst)
- return NULL;
-
- rpl__metadata_dst_init(md_dst, type, optslen);
-
- return md_dst;
-}
-static inline struct metadata_dst *rpl_tun_rx_dst(int md_size)
-{
- struct metadata_dst *tun_dst;
-
- tun_dst = __rpl_metadata_dst_alloc(md_size, METADATA_IP_TUNNEL,
- GFP_ATOMIC);
- if (!tun_dst)
- return NULL;
-
- tun_dst->u.tun_info.options_len = 0;
- tun_dst->u.tun_info.mode = 0;
- return tun_dst;
-}
-static inline struct metadata_dst *rpl__ip_tun_set_dst(__be32 saddr,
- __be32 daddr,
- __u8 tos, __u8 ttl,
- __be16 tp_dst,
- __be16 flags,
- __be64 tunnel_id,
- int md_size)
-{
- struct metadata_dst *tun_dst;
-
- tun_dst = rpl_tun_rx_dst(md_size);
- if (!tun_dst)
- return NULL;
-
- ip_tunnel_key_init(&tun_dst->u.tun_info.key,
- saddr, daddr, tos, ttl,
- 0, 0, tp_dst, tunnel_id, flags);
- return tun_dst;
-}
-
-static inline struct metadata_dst *rpl_ip_tun_rx_dst(struct sk_buff *skb,
- __be16 flags,
- __be64 tunnel_id,
- int md_size)
-{
- const struct iphdr *iph = ip_hdr(skb);
-
- return rpl__ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl,
- 0, flags, tunnel_id, md_size);
-}
-
-static inline
-struct metadata_dst *rpl__ipv6_tun_set_dst(const struct in6_addr *saddr,
- const struct in6_addr *daddr,
- __u8 tos, __u8 ttl,
- __be16 tp_dst,
- __be32 label,
- __be16 flags,
- __be64 tunnel_id,
- int md_size)
-{
- struct metadata_dst *tun_dst;
- struct ip_tunnel_info *info;
-
- tun_dst = rpl_tun_rx_dst(md_size);
- if (!tun_dst)
- return NULL;
-
- info = &tun_dst->u.tun_info;
- info->mode = IP_TUNNEL_INFO_IPV6;
- info->key.tun_flags = flags;
- info->key.tun_id = tunnel_id;
- info->key.tp_src = 0;
- info->key.tp_dst = tp_dst;
-
- info->key.u.ipv6.src = *saddr;
- info->key.u.ipv6.dst = *daddr;
-
- info->key.tos = tos;
- info->key.ttl = ttl;
- info->key.label = label;
-
- return tun_dst;
-}
-
-static inline struct metadata_dst *rpl_ipv6_tun_rx_dst(struct sk_buff *skb,
- __be16 flags,
- __be64 tunnel_id,
- int md_size)
-{
- const struct ipv6hdr *ip6h = ipv6_hdr(skb);
-
- return rpl__ipv6_tun_set_dst(&ip6h->saddr, &ip6h->daddr,
- ipv6_get_dsfield(ip6h), ip6h->hop_limit,
- 0, ip6_flowlabel(ip6h), flags, tunnel_id,
- md_size);
-}
-
-static void __metadata_dst_init(struct metadata_dst *md_dst, u8 optslen)
-{
- struct dst_entry *dst;
-
- dst = &md_dst->dst;
-
-#if 0
- dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE,
- DST_METADATA | DST_NOCACHE | DST_NOCOUNT);
-
- dst->input = dst_md_discard;
- dst->output = dst_md_discard_out;
-#endif
-
- memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst));
-}
-
-static inline struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags)
-{
- struct metadata_dst *md_dst;
-
- md_dst = kmalloc(sizeof(*md_dst) + optslen, flags);
- if (!md_dst)
- return NULL;
-
- __metadata_dst_init(md_dst, optslen);
- return md_dst;
-}
-
-#define skb_tunnel_info ovs_skb_tunnel_info
-
-static inline void ovs_tun_rx_dst(struct metadata_dst *md_dst, int optslen)
-{
- /* No need to allocate for OVS backport case. */
-#if 0
- struct metadata_dst *tun_dst;
- struct ip_tunnel_info *info;
-
- tun_dst = metadata_dst_alloc(md_size, GFP_ATOMIC);
- if (!tun_dst)
- return NULL;
-#endif
- __metadata_dst_init(md_dst, optslen);
-}
-
-static inline void ovs_ip_tun_rx_dst(struct metadata_dst *md_dst,
- struct sk_buff *skb, __be16 flags,
- __be64 tunnel_id, int md_size)
-{
- const struct iphdr *iph = ip_hdr(skb);
-
- ovs_tun_rx_dst(md_dst, md_size);
- ip_tunnel_key_init(&md_dst->u.tun_info.key,
- iph->saddr, iph->daddr, iph->tos, iph->ttl, 0,
- 0, 0, tunnel_id, flags);
-}
-
-static inline void ovs_ipv6_tun_rx_dst(struct metadata_dst *md_dst,
- struct sk_buff *skb,
- __be16 flags,
- __be64 tunnel_id,
- int md_size)
-{
- struct ip_tunnel_info *info = &md_dst->u.tun_info;
- const struct ipv6hdr *ip6h = ipv6_hdr(skb);
-
- ovs_tun_rx_dst(md_dst, md_size);
- info->mode = IP_TUNNEL_INFO_IPV6;
- info->key.tun_flags = flags;
- info->key.tun_id = tunnel_id;
- info->key.tp_src = 0;
- info->key.tp_dst = 0;
-
- info->key.u.ipv6.src = ip6h->saddr;
- info->key.u.ipv6.dst = ip6h->daddr;
-
- info->key.tos = ipv6_get_dsfield(ip6h);
- info->key.ttl = ip6h->hop_limit;
- info->key.label = ip6_flowlabel(ip6h);
-}
-
-#endif /* USE_UPSTREAM_TUNNEL */
-
-void ovs_ip_tunnel_rcv(struct net_device *dev, struct sk_buff *skb,
- struct metadata_dst *tun_dst);
-
-static inline struct metadata_dst *
-rpl_metadata_dst_alloc(u8 optslen, enum metadata_type type, gfp_t flags)
-{
-#if defined(HAVE_METADATA_DST_ALLOC_WITH_METADATA_TYPE) && defined(USE_UPSTREAM_TUNNEL)
- return metadata_dst_alloc(optslen, type, flags);
-#else
- return metadata_dst_alloc(optslen, flags);
-#endif
-}
-#define metadata_dst_alloc rpl_metadata_dst_alloc
-
-static inline bool rpl_skb_valid_dst(const struct sk_buff *skb)
-{
- struct dst_entry *dst = skb_dst(skb);
-
- return dst && !(dst->flags & DST_METADATA);
-}
-#define skb_valid_dst rpl_skb_valid_dst
-
-#endif /* __NET_DST_METADATA_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/erspan.h b/datapath/linux/compat/include/net/erspan.h
deleted file mode 100644
index 4a6a8f240..000000000
--- a/datapath/linux/compat/include/net/erspan.h
+++ /dev/null
@@ -1,342 +0,0 @@
-#ifndef USE_UPSTREAM_TUNNEL
-#ifndef __LINUX_ERSPAN_H
-#define __LINUX_ERSPAN_H
-
-/*
- * GRE header for ERSPAN encapsulation (8 octets [34:41]) -- 8 bytes
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |0|0|0|1|0|00000|000000000|00000| Protocol Type for ERSPAN |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Sequence Number (increments per packet per session) |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Note that in the above GRE header [RFC1701] out of the C, R, K, S,
- * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The
- * other fields are set to zero, so only a sequence number follows.
- *
- * ERSPAN Version 1 (Type II) header (8 octets [42:49])
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Ver | VLAN | COS | En|T| Session ID |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Reserved | Index |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- *
- * ERSPAN Version 2 (Type III) header (12 octets [42:49])
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Ver | VLAN | COS |BSO|T| Session ID |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Timestamp |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | SGT |P| FT | Hw ID |D|Gra|O|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Platform Specific SubHeader (8 octets, optional)
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Platf ID | Platform Specific Info |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Platform Specific Info |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB
- */
-
-/* #include <uapi/linux/erspan.h> */
-/* Just insert uapi/linux/erspan.h here since
- * we don't pull in uapi to compat
- */
-/* ERSPAN version 2 metadata header */
-struct erspan_md2 {
- __be32 timestamp;
- __be16 sgt; /* security group tag */
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 hwid_upper:2,
- ft:5,
- p:1;
- __u8 o:1,
- gra:2,
- dir:1,
- hwid:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u8 p:1,
- ft:5,
- hwid_upper:2;
- __u8 hwid:4,
- dir:1,
- gra:2,
- o:1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-};
-
-struct erspan_metadata {
- int version;
- union {
- __be32 index; /* Version 1 (type II)*/
- struct erspan_md2 md2; /* Version 2 (type III) */
- } u;
-};
-
-#define ERSPAN_VERSION 0x1 /* ERSPAN type II */
-#define VER_MASK 0xf000
-#define VLAN_MASK 0x0fff
-#define COS_MASK 0xe000
-#define EN_MASK 0x1800
-#define T_MASK 0x0400
-#define ID_MASK 0x03ff
-#define INDEX_MASK 0xfffff
-
-#define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/
-#define BSO_MASK EN_MASK
-#define SGT_MASK 0xffff0000
-#define P_MASK 0x8000
-#define FT_MASK 0x7c00
-#define HWID_MASK 0x03f0
-#define DIR_MASK 0x0008
-#define GRA_MASK 0x0006
-#define O_MASK 0x0001
-
-#define HWID_OFFSET 4
-#define DIR_OFFSET 3
-
-enum erspan_encap_type {
- ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */
- ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */
- ERSPAN_ENCAP_8021Q = 0x2, /* originally 802.1Q encapsulated */
- ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */
-};
-
-#define ERSPAN_V1_MDSIZE 4
-#define ERSPAN_V2_MDSIZE 8
-
-struct erspan_base_hdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 vlan_upper:4,
- ver:4;
- __u8 vlan:8;
- __u8 session_id_upper:2,
- t:1,
- en:2,
- cos:3;
- __u8 session_id:8;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u8 ver: 4,
- vlan_upper:4;
- __u8 vlan:8;
- __u8 cos:3,
- en:2,
- t:1,
- session_id_upper:2;
- __u8 session_id:8;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-};
-
-static inline void set_session_id(struct erspan_base_hdr *ershdr, u16 id)
-{
- ershdr->session_id = id & 0xff;
- ershdr->session_id_upper = (id >> 8) & 0x3;
-}
-
-static inline u16 get_session_id(const struct erspan_base_hdr *ershdr)
-{
- return (ershdr->session_id_upper << 8) + ershdr->session_id;
-}
-
-static inline void set_vlan(struct erspan_base_hdr *ershdr, u16 vlan)
-{
- ershdr->vlan = vlan & 0xff;
- ershdr->vlan_upper = (vlan >> 8) & 0xf;
-}
-
-static inline u16 get_vlan(const struct erspan_base_hdr *ershdr)
-{
- return (ershdr->vlan_upper << 8) + ershdr->vlan;
-}
-
-static inline void set_hwid(struct erspan_md2 *md2, u8 hwid)
-{
- md2->hwid = hwid & 0xf;
- md2->hwid_upper = (hwid >> 4) & 0x3;
-}
-
-static inline u8 get_hwid(const struct erspan_md2 *md2)
-{
- return (md2->hwid_upper << 4) + md2->hwid;
-}
-
-static inline int erspan_hdr_len(int version)
-{
- return sizeof(struct erspan_base_hdr) +
- (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE);
-}
-
-static inline u8 tos_to_cos(u8 tos)
-{
- u8 dscp, cos;
-
- dscp = tos >> 2;
- cos = dscp >> 3;
- return cos;
-}
-
-static inline void erspan_build_header(struct sk_buff *skb,
- u32 id, u32 index,
- bool truncate, bool is_ipv4)
-{
- struct ethhdr *eth = (struct ethhdr *)skb->data;
- enum erspan_encap_type enc_type;
- struct erspan_base_hdr *ershdr;
- struct qtag_prefix {
- __be16 eth_type;
- __be16 tci;
- } *qp;
- u16 vlan_tci = 0;
- u8 tos;
- __be32 *idx;
-
- tos = is_ipv4 ? ip_hdr(skb)->tos :
- (ipv6_hdr(skb)->priority << 4) +
- (ipv6_hdr(skb)->flow_lbl[0] >> 4);
-
- enc_type = ERSPAN_ENCAP_NOVLAN;
-
- /* If mirrored packet has vlan tag, extract tci and
- * perserve vlan header in the mirrored frame.
- */
- if (eth->h_proto == htons(ETH_P_8021Q)) {
- qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
- vlan_tci = ntohs(qp->tci);
- enc_type = ERSPAN_ENCAP_INFRAME;
- }
-
- skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
- ershdr = (struct erspan_base_hdr *)skb->data;
- memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE);
-
- /* Build base header */
- ershdr->ver = ERSPAN_VERSION;
- ershdr->cos = tos_to_cos(tos);
- ershdr->en = enc_type;
- ershdr->t = truncate;
- set_vlan(ershdr, vlan_tci);
- set_session_id(ershdr, id);
-
- /* Build metadata */
- idx = (__be32 *)(ershdr + 1);
- *idx = htonl(index & INDEX_MASK);
-}
-
-/* ERSPAN GRA: timestamp granularity
- * 00b --> granularity = 100 microseconds
- * 01b --> granularity = 100 nanoseconds
- * 10b --> granularity = IEEE 1588
- * Here we only support 100 microseconds.
- */
-static inline __be32 erspan_get_timestamp(void)
-{
- u64 h_usecs;
- ktime_t kt;
-
- kt = ktime_get_real();
- h_usecs = ktime_divns(kt, 100 * NSEC_PER_USEC);
-
- /* ERSPAN base header only has 32-bit,
- * so it wraps around 4 days.
- */
- return htonl((u32)h_usecs);
-}
-
-/* ERSPAN BSO (Bad/Short/Oversized), see RFC1757
- * 00b --> Good frame with no error, or unknown integrity
- * 01b --> Payload is a Short Frame
- * 10b --> Payload is an Oversized Frame
- * 11b --> Payload is a Bad Frame with CRC or Alignment Error
- */
-enum erspan_bso {
- BSO_NOERROR = 0x0,
- BSO_SHORT = 0x1,
- BSO_OVERSIZED = 0x2,
- BSO_BAD = 0x3,
-};
-
-static inline u8 erspan_detect_bso(struct sk_buff *skb)
-{
- /* BSO_BAD is not handled because the frame CRC
- * or alignment error information is in FCS.
- */
- if (skb->len < ETH_ZLEN)
- return BSO_SHORT;
-
- if (skb->len > ETH_FRAME_LEN)
- return BSO_OVERSIZED;
-
- return BSO_NOERROR;
-}
-
-static inline void erspan_build_header_v2(struct sk_buff *skb,
- u32 id, u8 direction, u16 hwid,
- bool truncate, bool is_ipv4)
-{
- struct ethhdr *eth = (struct ethhdr *)skb->data;
- struct erspan_base_hdr *ershdr;
- struct erspan_md2 *md2;
- struct qtag_prefix {
- __be16 eth_type;
- __be16 tci;
- } *qp;
- u16 vlan_tci = 0;
- u8 gra = 0; /* 100 usec */
- u8 bso = truncate; /* Bad/Short/Oversized */
- u8 sgt = 0;
- u8 tos;
-
- tos = is_ipv4 ? ip_hdr(skb)->tos :
- (ipv6_hdr(skb)->priority << 4) +
- (ipv6_hdr(skb)->flow_lbl[0] >> 4);
-
- /* Unlike v1, v2 does not have En field,
- * so only extract vlan tci field.
- */
- if (eth->h_proto == htons(ETH_P_8021Q)) {
- qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
- vlan_tci = ntohs(qp->tci);
- }
-
- bso = erspan_detect_bso(skb);
- skb_push(skb, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
- ershdr = (struct erspan_base_hdr *)skb->data;
- memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE);
-
- /* Build base header */
- ershdr->ver = ERSPAN_VERSION2;
- ershdr->cos = tos_to_cos(tos);
- ershdr->en = bso;
- ershdr->t = truncate;
- set_vlan(ershdr, vlan_tci);
- set_session_id(ershdr, id);
-
- /* Build metadata */
- md2 = (struct erspan_md2 *)(ershdr + 1);
- md2->timestamp = erspan_get_timestamp();
- md2->sgt = htons(sgt);
- md2->p = 1;
- md2->ft = 0;
- md2->dir = direction;
- md2->gra = gra;
- md2->o = 0;
- set_hwid(md2, hwid);
-}
-
-#endif
-#else
-#include_next <net/erspan.h>
-#endif
diff --git a/datapath/linux/compat/include/net/genetlink.h b/datapath/linux/compat/include/net/genetlink.h
deleted file mode 100644
index 602ce38d3..000000000
--- a/datapath/linux/compat/include/net/genetlink.h
+++ /dev/null
@@ -1,136 +0,0 @@
-#ifndef __NET_GENERIC_NETLINK_WRAPPER_H
-#define __NET_GENERIC_NETLINK_WRAPPER_H 1
-
-#include <linux/version.h>
-#include <linux/netlink.h>
-#include <net/net_namespace.h>
-#include_next <net/genetlink.h>
-
-#ifndef HAVE_GENL_NOTIFY_TAKES_FAMILY
-struct rpl_genl_family {
- struct genl_family compat_family;
- unsigned int id;
- unsigned int hdrsize;
- char name[GENL_NAMSIZ];
- unsigned int version;
- unsigned int maxattr;
- bool netnsok;
- bool parallel_ops;
- int (*pre_doit)(const struct genl_ops *ops,
- struct sk_buff *skb,
- struct genl_info *info);
- void (*post_doit)(const struct genl_ops *ops,
- struct sk_buff *skb,
- struct genl_info *info);
- struct nlattr ** attrbuf; /* private */
- const struct genl_ops * ops; /* private */
- const struct genl_multicast_group *mcgrps; /* private */
- unsigned int n_ops; /* private */
- unsigned int n_mcgrps; /* private */
- unsigned int mcgrp_offset; /* private */
- struct list_head family_list; /* private */
- struct module *module;
-};
-
-#define genl_family rpl_genl_family
-static inline void *rpl_genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
- struct genl_family *family, int flags, u8 cmd)
-{
- return genlmsg_put(skb, portid, seq, &family->compat_family, flags, cmd);
-}
-
-#define genlmsg_put rpl_genlmsg_put
-
-static inline int rpl_genl_unregister_family(struct genl_family *family)
-{
- return genl_unregister_family(&family->compat_family);
-}
-#define genl_unregister_family rpl_genl_unregister_family
-
-#define genl_set_err rpl_genl_set_err
-static inline int genl_set_err(struct genl_family *family, struct net *net,
- u32 portid, u32 group, int code)
-{
-#ifdef HAVE_VOID_NETLINK_SET_ERR
- netlink_set_err(net->genl_sock, portid, group, code);
- return 0;
-#else
- return netlink_set_err(net->genl_sock, portid, group, code);
-#endif
-}
-
-#define genlmsg_multicast_netns rpl_genlmsg_multicast_netns
-static inline int genlmsg_multicast_netns(struct genl_family *family,
- struct net *net, struct sk_buff *skb,
- u32 portid, unsigned int group, gfp_t flags)
-{
- return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
-}
-
-
-#define __genl_register_family rpl___genl_register_family
-int rpl___genl_register_family(struct genl_family *family);
-
-#define genl_register_family rpl_genl_register_family
-static inline int rpl_genl_register_family(struct genl_family *family)
-{
- family->module = THIS_MODULE;
- return rpl___genl_register_family(family);
-}
-#endif
-
-#ifdef HAVE_GENL_NOTIFY_TAKES_NET
-#define genl_notify rpl_genl_notify
-void rpl_genl_notify(struct genl_family *family, struct sk_buff *skb,
- struct genl_info *info , u32 group, gfp_t flags);
-#endif
-
-#ifndef HAVE_GENL_HAS_LISTENERS
-static inline int genl_has_listeners(struct genl_family *family,
- struct net *net, unsigned int group)
-{
-#ifdef HAVE_MCGRP_OFFSET
- if (WARN_ON_ONCE(group >= family->n_mcgrps))
- return -EINVAL;
- group = family->mcgrp_offset + group;
-#endif
- return netlink_has_listeners(net->genl_sock, group);
-}
-#else
-
-#ifndef HAVE_GENL_HAS_LISTENERS_TAKES_NET
-static inline int rpl_genl_has_listeners(struct genl_family *family,
- struct net *net, unsigned int group)
-{
-#ifdef HAVE_GENL_NOTIFY_TAKES_FAMILY
- return genl_has_listeners(family, net->genl_sock, group);
-#else
- return genl_has_listeners(&family->compat_family, net->genl_sock, group);
-#endif
-}
-
-#define genl_has_listeners rpl_genl_has_listeners
-#endif
-
-#endif /* HAVE_GENL_HAS_LISTENERS */
-
-#ifndef HAVE_NETLINK_EXT_ACK
-struct netlink_ext_ack;
-
-static inline int rpl_genlmsg_parse(const struct nlmsghdr *nlh,
- const struct genl_family *family,
- struct nlattr *tb[], int maxtype,
- const struct nla_policy *policy,
- struct netlink_ext_ack *extack)
-{
-#ifdef HAVE_GENLMSG_PARSE
- return genlmsg_parse(nlh, family, tb, maxtype, policy);
-#else
- return nlmsg_parse(nlh, family->hdrsize + GENL_HDRLEN, tb, maxtype,
- policy);
-#endif
-}
-#define genlmsg_parse rpl_genlmsg_parse
-#endif
-
-#endif /* genetlink.h */
diff --git a/datapath/linux/compat/include/net/geneve.h b/datapath/linux/compat/include/net/geneve.h
deleted file mode 100644
index d9c9f0bf7..000000000
--- a/datapath/linux/compat/include/net/geneve.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef __NET_GENEVE_WRAPPER_H
-#define __NET_GENEVE_WRAPPER_H 1
-
-#ifdef CONFIG_INET
-#include <net/udp_tunnel.h>
-#endif
-
-
-#ifdef USE_UPSTREAM_TUNNEL
-#include_next <net/geneve.h>
-
-static inline int rpl_geneve_init_module(void)
-{
- return 0;
-}
-static inline void rpl_geneve_cleanup_module(void)
-{}
-
-#define geneve_xmit dev_queue_xmit
-
-#ifdef CONFIG_INET
-#ifndef HAVE_NAME_ASSIGN_TYPE
-static inline struct net_device *rpl_geneve_dev_create_fb(
- struct net *net, const char *name, u8 name_assign_type, u16 dst_port) {
- return geneve_dev_create_fb(net, name, dst_port);
-}
-#define geneve_dev_create_fb rpl_geneve_dev_create_fb
-#endif
-#endif
-
-#else
-/* Geneve Header:
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Virtual Network Identifier (VNI) | Reserved |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Variable Length Options |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Option Header:
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Option Class | Type |R|R|R| Length |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Variable Option Data |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
-
-struct geneve_opt {
- __be16 opt_class;
- u8 type;
-#ifdef __LITTLE_ENDIAN_BITFIELD
- u8 length:5;
- u8 r3:1;
- u8 r2:1;
- u8 r1:1;
-#else
- u8 r1:1;
- u8 r2:1;
- u8 r3:1;
- u8 length:5;
-#endif
- u8 opt_data[];
-};
-
-#define GENEVE_CRIT_OPT_TYPE (1 << 7)
-
-struct genevehdr {
-#ifdef __LITTLE_ENDIAN_BITFIELD
- u8 opt_len:6;
- u8 ver:2;
- u8 rsvd1:6;
- u8 critical:1;
- u8 oam:1;
-#else
- u8 ver:2;
- u8 opt_len:6;
- u8 oam:1;
- u8 critical:1;
- u8 rsvd1:6;
-#endif
- __be16 proto_type;
- u8 vni[3];
- u8 rsvd2;
- struct geneve_opt options[];
-};
-
-#ifdef CONFIG_INET
-#define geneve_dev_create_fb rpl_geneve_dev_create_fb
-struct net_device *rpl_geneve_dev_create_fb(struct net *net, const char *name,
- u8 name_assign_type, u16 dst_port);
-#endif /*ifdef CONFIG_INET */
-
-int rpl_geneve_init_module(void);
-void rpl_geneve_cleanup_module(void);
-
-#define geneve_xmit rpl_geneve_xmit
-netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb);
-
-#endif
-#define geneve_init_module rpl_geneve_init_module
-#define geneve_cleanup_module rpl_geneve_cleanup_module
-
-#define geneve_fill_metadata_dst ovs_geneve_fill_metadata_dst
-int ovs_geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-
-#endif /*ifdef__NET_GENEVE_H */
diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h
deleted file mode 100644
index 57293b6c2..000000000
--- a/datapath/linux/compat/include/net/gre.h
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef __LINUX_GRE_WRAPPER_H
-#define __LINUX_GRE_WRAPPER_H
-
-#include <linux/version.h>
-#include <linux/skbuff.h>
-#include <net/ip_tunnels.h>
-
-#ifdef USE_UPSTREAM_TUNNEL
-#include_next <net/gre.h>
-
-static inline int rpl_ipgre_init(void)
-{
- return 0;
-}
-static inline void rpl_ipgre_fini(void)
-{}
-
-static inline int rpl_ip6gre_init(void)
-{
- return 0;
-}
-
-static inline void rpl_ip6gre_fini(void)
-{}
-
-static inline int rpl_ip6_tunnel_init(void)
-{
- return 0;
-}
-
-static inline void rpl_ip6_tunnel_cleanup(void)
-{
-}
-
-static inline int rpl_gre_init(void)
-{
- return 0;
-}
-
-static inline void rpl_gre_exit(void)
-{
-}
-
-#define gre_fb_xmit dev_queue_xmit
-
-#ifdef CONFIG_INET
-#ifndef HAVE_NAME_ASSIGN_TYPE
-static inline struct net_device *rpl_gretap_fb_dev_create(
- struct net *net, const char *name, u8 name_assign_type) {
- return gretap_fb_dev_create(net, name);
-}
-#define gretap_fb_dev_create rpl_gretap_fb_dev_create
-#endif
-#endif
-
-#else
-#include_next <net/gre.h>
-
-#ifndef HAVE_GRE_CALC_HLEN
-static inline int gre_calc_hlen(__be16 o_flags)
-{
- int addend = 4;
-
- if (o_flags & TUNNEL_CSUM)
- addend += 4;
- if (o_flags & TUNNEL_KEY)
- addend += 4;
- if (o_flags & TUNNEL_SEQ)
- addend += 4;
- return addend;
-}
-
-#define ip_gre_calc_hlen gre_calc_hlen
-#else
-#ifdef HAVE_IP_GRE_CALC_HLEN
-#define gre_calc_hlen ip_gre_calc_hlen
-#endif
-#endif
-
-#define tnl_flags_to_gre_flags rpl_tnl_flags_to_gre_flags
-static inline __be16 rpl_tnl_flags_to_gre_flags(__be16 tflags)
-{
- __be16 flags = 0;
-
- if (tflags & TUNNEL_CSUM)
- flags |= GRE_CSUM;
- if (tflags & TUNNEL_ROUTING)
- flags |= GRE_ROUTING;
- if (tflags & TUNNEL_KEY)
- flags |= GRE_KEY;
- if (tflags & TUNNEL_SEQ)
- flags |= GRE_SEQ;
- if (tflags & TUNNEL_STRICT)
- flags |= GRE_STRICT;
- if (tflags & TUNNEL_REC)
- flags |= GRE_REC;
- if (tflags & TUNNEL_VERSION)
- flags |= GRE_VERSION;
-
- return flags;
-}
-
-#define gre_flags_to_tnl_flags rpl_gre_flags_to_tnl_flags
-static inline __be16 rpl_gre_flags_to_tnl_flags(__be16 flags)
-{
- __be16 tflags = 0;
-
- if (flags & GRE_CSUM)
- tflags |= TUNNEL_CSUM;
- if (flags & GRE_ROUTING)
- tflags |= TUNNEL_ROUTING;
- if (flags & GRE_KEY)
- tflags |= TUNNEL_KEY;
- if (flags & GRE_SEQ)
- tflags |= TUNNEL_SEQ;
- if (flags & GRE_STRICT)
- tflags |= TUNNEL_STRICT;
- if (flags & GRE_REC)
- tflags |= TUNNEL_REC;
- if (flags & GRE_VERSION)
- tflags |= TUNNEL_VERSION;
-
- return tflags;
-}
-#define gre_tnl_flags_to_gre_flags rpl_gre_tnl_flags_to_gre_flags
-static inline __be16 rpl_gre_tnl_flags_to_gre_flags(__be16 tflags)
-{
- __be16 flags = 0;
-
- if (tflags & TUNNEL_CSUM)
- flags |= GRE_CSUM;
- if (tflags & TUNNEL_ROUTING)
- flags |= GRE_ROUTING;
- if (tflags & TUNNEL_KEY)
- flags |= GRE_KEY;
- if (tflags & TUNNEL_SEQ)
- flags |= GRE_SEQ;
- if (tflags & TUNNEL_STRICT)
- flags |= GRE_STRICT;
- if (tflags & TUNNEL_REC)
- flags |= GRE_REC;
- if (tflags & TUNNEL_VERSION)
- flags |= GRE_VERSION;
-
- return flags;
-}
-
-#define gre_build_header rpl_gre_build_header
-void rpl_gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
- int hdr_len);
-
-int rpl_ipgre_init(void);
-void rpl_ipgre_fini(void);
-int rpl_ip6gre_init(void);
-void rpl_ip6gre_fini(void);
-int rpl_ip6_tunnel_init(void);
-void rpl_ip6_tunnel_cleanup(void);
-int rpl_gre_init(void);
-void rpl_gre_exit(void);
-
-#define gretap_fb_dev_create rpl_gretap_fb_dev_create
-struct net_device *rpl_gretap_fb_dev_create(struct net *net, const char *name,
- u8 name_assign_type);
-
-#define gre_parse_header rpl_gre_parse_header
-int rpl_gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
- bool *csum_err, __be16 proto, int nhs);
-
-#define gre_fb_xmit rpl_gre_fb_xmit
-netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb);
-
-#define gre_add_protocol rpl_gre_add_protocol
-int rpl_gre_add_protocol(const struct gre_protocol *proto, u8 version);
-#define gre_del_protocol rpl_gre_del_protocol
-int rpl_gre_del_protocol(const struct gre_protocol *proto, u8 version);
-#endif /* USE_UPSTREAM_TUNNEL */
-
-#define ipgre_init rpl_ipgre_init
-#define ipgre_fini rpl_ipgre_fini
-#define ip6gre_init rpl_ip6gre_init
-#define ip6gre_fini rpl_ip6gre_fini
-#define ip6_tunnel_init rpl_ip6_tunnel_init
-#define ip6_tunnel_cleanup rpl_ip6_tunnel_cleanup
-#define gre_init rpl_gre_init
-#define gre_exit rpl_gre_exit
-
-#define gre_fill_metadata_dst ovs_gre_fill_metadata_dst
-int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-
-
-#endif
diff --git a/datapath/linux/compat/include/net/inet_ecn.h b/datapath/linux/compat/include/net/inet_ecn.h
deleted file mode 100644
index f0591b322..000000000
--- a/datapath/linux/compat/include/net/inet_ecn.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef _INET_ECN_WRAPPER_H_
-#define _INET_ECN_WRAPPER_H_
-
-#include_next <net/inet_ecn.h>
-
-#define INET_ECN_decapsulate rpl_INET_ECN_decapsulate
-static inline int INET_ECN_decapsulate(struct sk_buff *skb,
- __u8 outer, __u8 inner)
-{
- if (INET_ECN_is_not_ect(inner)) {
- switch (outer & INET_ECN_MASK) {
- case INET_ECN_NOT_ECT:
- return 0;
- case INET_ECN_ECT_0:
- case INET_ECN_ECT_1:
- return 1;
- case INET_ECN_CE:
- return 2;
- }
- }
-
- if (INET_ECN_is_ce(outer))
- INET_ECN_set_ce(skb);
-
- return 0;
-}
-
-#define IP_ECN_decapsulate rpl_IP_ECN_decapsulate
-static inline int IP_ECN_decapsulate(const struct iphdr *oiph,
- struct sk_buff *skb)
-{
- __u8 inner;
-
- if (skb->protocol == htons(ETH_P_IP))
- inner = ip_hdr(skb)->tos;
- else if (skb->protocol == htons(ETH_P_IPV6))
- inner = ipv6_get_dsfield(ipv6_hdr(skb));
- else
- return 0;
-
- return INET_ECN_decapsulate(skb, oiph->tos, inner);
-}
-
-#define IP6_ECN_decapsulate rpl_IP6_ECN_decapsulate
-static inline int IP6_ECN_decapsulate(const struct ipv6hdr *oipv6h,
- struct sk_buff *skb)
-{
- __u8 inner;
-
- if (skb->protocol == htons(ETH_P_IP))
- inner = ip_hdr(skb)->tos;
- else if (skb->protocol == htons(ETH_P_IPV6))
- inner = ipv6_get_dsfield(ipv6_hdr(skb));
- else
- return 0;
-
- return INET_ECN_decapsulate(skb, ipv6_get_dsfield(oipv6h), inner);
-}
-#endif
diff --git a/datapath/linux/compat/include/net/inet_frag.h b/datapath/linux/compat/include/net/inet_frag.h
deleted file mode 100644
index 00784da2b..000000000
--- a/datapath/linux/compat/include/net/inet_frag.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __NET_INET_FRAG_WRAPPER_H
-#define __NET_INET_FRAG_WRAPPER_H 1
-
-#include <linux/version.h>
-#include_next <net/inet_frag.h>
-
-#ifdef HAVE_INET_FRAGS_LAST_IN
-#define q_flags(q) (q->last_in)
-#define qp_flags(qp) (qp->q.last_in)
-#else
-#define q_flags(q) (q->flags)
-#define qp_flags(qp) (qp->q.flags)
-#endif
-
-#ifndef HAVE_CORRECT_MRU_HANDLING
-#ifndef HAVE_INET_FRAG_EVICTING
-static inline bool inet_frag_evicting(struct inet_frag_queue *q)
-{
-#ifdef HAVE_INET_FRAG_QUEUE_WITH_LIST_EVICTOR
- return !hlist_unhashed(&q->list_evictor);
-#else
- return (q_flags(q) & INET_FRAG_FIRST_IN) && q->fragments != NULL;
-#endif /* HAVE_INET_FRAG_QUEUE_WITH_LIST_EVICTOR */
-}
-#endif /* HAVE_INET_FRAG_EVICTING */
-#endif /* HAVE_CORRECT_MRU_HANDLING */
-
-/* Upstream commit 3fd588eb90bf ("inet: frag: remove lru list") dropped this
- * function, but we call it from our compat code. Provide a noop version. */
-#ifndef HAVE_INET_FRAG_LRU_MOVE
-#define inet_frag_lru_move(q)
-#endif
-
-#ifdef HAVE_INET_FRAG_FQDIR
-#define netns_frags fqdir
-#endif
-
-#ifndef HAVE_SUB_FRAG_MEM_LIMIT_ARG_STRUCT_NETNS_FRAGS
-#ifdef HAVE_FRAG_PERCPU_COUNTER_BATCH
-static inline void rpl_sub_frag_mem_limit(struct netns_frags *nf, int i)
-{
- __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch);
-}
-#define sub_frag_mem_limit rpl_sub_frag_mem_limit
-
-static inline void rpl_add_frag_mem_limit(struct netns_frags *nf, int i)
-{
- __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch);
-}
-#define add_frag_mem_limit rpl_add_frag_mem_limit
-#else /* !frag_percpu_counter_batch */
-static inline void rpl_sub_frag_mem_limit(struct netns_frags *nf, int i)
-{
-#ifdef HAVE_INET_FRAG_FQDIR
- atomic_long_sub(i, &nf->mem);
-#else
- atomic_sub(i, &nf->mem);
-#endif
-}
-#define sub_frag_mem_limit rpl_sub_frag_mem_limit
-
-static inline void rpl_add_frag_mem_limit(struct netns_frags *nf, int i)
-{
-#ifdef HAVE_INET_FRAG_FQDIR
- atomic_long_add(i, &nf->mem);
-#else
- atomic_add(i, &nf->mem);
-#endif
-}
-#define add_frag_mem_limit rpl_add_frag_mem_limit
-#endif /* frag_percpu_counter_batch */
-#endif
-
-#ifdef HAVE_VOID_INET_FRAGS_INIT
-static inline int rpl_inet_frags_init(struct inet_frags *frags)
-{
- inet_frags_init(frags);
- return 0;
-}
-#define inet_frags_init rpl_inet_frags_init
-#endif
-
-#endif /* inet_frag.h */
diff --git a/datapath/linux/compat/include/net/inetpeer.h b/datapath/linux/compat/include/net/inetpeer.h
deleted file mode 100644
index c5f5eb12b..000000000
--- a/datapath/linux/compat/include/net/inetpeer.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _NET_INETPEER_WRAPPER_H
-#define _NET_INETPEER_WRAPPER_H
-
-#include_next <net/inetpeer.h>
-
-#ifndef HAVE_INETPEER_VIF_SUPPORT
-static inline struct inet_peer *rpl_inet_getpeer_v4(struct inet_peer_base *base,
- __be32 v4daddr, int vif,
- int create)
-{
- return inet_getpeer_v4(base, v4daddr, create);
-}
-#define inet_getpeer_v4 rpl_inet_getpeer_v4
-#endif /* HAVE_INETPEER_VIF_SUPPORT */
-
-#endif /* _NET_INETPEER_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/ip.h b/datapath/linux/compat/include/net/ip.h
deleted file mode 100644
index ad5ac33ee..000000000
--- a/datapath/linux/compat/include/net/ip.h
+++ /dev/null
@@ -1,143 +0,0 @@
-#ifndef __NET_IP_WRAPPER_H
-#define __NET_IP_WRAPPER_H 1
-
-#include_next <net/ip.h>
-
-#include <net/route.h>
-#include <linux/version.h>
-
-#ifndef HAVE_INET_GET_LOCAL_PORT_RANGE_USING_NET
-static inline void rpl_inet_get_local_port_range(struct net *net, int *low,
- int *high)
-{
- inet_get_local_port_range(low, high);
-}
-#define inet_get_local_port_range rpl_inet_get_local_port_range
-
-#endif
-
-#ifndef IPSKB_FRAG_PMTU
-#define IPSKB_FRAG_PMTU BIT(6)
-#endif
-
-/* IPv4 datagram length is stored into 16bit field (tot_len) */
-#ifndef IP_MAX_MTU
-#define IP_MAX_MTU 0xFFFFU
-#endif
-
-#ifndef HAVE_IP_SKB_DST_MTU
-static inline bool rpl_ip_sk_use_pmtu(const struct sock *sk)
-{
- return inet_sk(sk)->pmtudisc < IP_PMTUDISC_PROBE;
-}
-#define ip_sk_use_pmtu rpl_ip_sk_use_pmtu
-
-static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
- bool forwarding)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
- struct net *net = dev_net(dst->dev);
-
- if (net->ipv4.sysctl_ip_fwd_use_pmtu ||
- dst_metric_locked(dst, RTAX_MTU) ||
- !forwarding)
- return dst_mtu(dst);
-#endif
-
- return min(dst->dev->mtu, IP_MAX_MTU);
-}
-
-static inline unsigned int rpl_ip_skb_dst_mtu(const struct sk_buff *skb)
-{
- if (!skb->sk || ip_sk_use_pmtu(skb->sk)) {
- bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED;
- return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding);
- } else {
- return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU);
- }
-}
-#define ip_skb_dst_mtu rpl_ip_skb_dst_mtu
-#endif /* HAVE_IP_SKB_DST_MTU */
-
-#ifdef HAVE_IP_FRAGMENT_TAKES_SOCK
-#ifdef HAVE_IP_LOCAL_OUT_TAKES_NET
-#define OVS_VPORT_OUTPUT_PARAMS struct net *net, struct sock *sock, struct sk_buff *skb
-#else
-#define OVS_VPORT_OUTPUT_PARAMS struct sock *sock, struct sk_buff *skb
-#endif
-#else
-#define OVS_VPORT_OUTPUT_PARAMS struct sk_buff *skb
-#endif
-
-/* Prior to upstream commit d6b915e29f4a ("ip_fragment: don't forward
- * defragmented DF packet"), IPCB(skb)->frag_max_size was not always populated
- * correctly, which would lead to reassembled packets not being refragmented.
- * So, we backport all of ip_defrag() in these cases.
- */
-#ifndef HAVE_CORRECT_MRU_HANDLING
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
-static inline bool ip_defrag_user_in_between(u32 user,
- enum ip_defrag_users lower_bond,
- enum ip_defrag_users upper_bond)
-{
- return user >= lower_bond && user <= upper_bond;
-}
-#endif /* < v4.2 */
-
-int rpl_ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
- int (*output)(OVS_VPORT_OUTPUT_PARAMS));
-#define ip_do_fragment rpl_ip_do_fragment
-
-/* If backporting IP defrag, then init/exit functions need to be called from
- * compat_{in,ex}it() to prepare the backported fragmentation cache. In this
- * case we declare the functions which are defined in
- * datapath/linux/compat/ip_fragment.c. */
-int rpl_ip_defrag(struct net *net, struct sk_buff *skb, u32 user);
-#define ip_defrag rpl_ip_defrag
-int __init rpl_ipfrag_init(void);
-void rpl_ipfrag_fini(void);
-void ovs_netns_frags_init(struct net *net);
-void ovs_netns_frags_exit(struct net *net);
-
-#else /* HAVE_CORRECT_MRU_HANDLING */
-
-#ifndef HAVE_IP_DO_FRAGMENT_TAKES_NET
-static inline int rpl_ip_do_fragment(struct net *net, struct sock *sk,
- struct sk_buff *skb,
- int (*output)(OVS_VPORT_OUTPUT_PARAMS))
-{
- return ip_do_fragment(sk, skb, output);
-}
-#define ip_do_fragment rpl_ip_do_fragment
-#endif /* IP_DO_FRAGMENT_TAKES_NET */
-
-/* We have no good way to detect the presence of upstream commit 8282f27449bf
- * ("inet: frag: Always orphan skbs inside ip_defrag()"), but it should be
- * always included in kernels 4.5+. */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
-static inline int rpl_ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
-{
- skb_orphan(skb);
-#ifndef HAVE_IP_DEFRAG_TAKES_NET
- return ip_defrag(skb, user);
-#else
- return ip_defrag(net, skb, user);
-#endif
-}
-#define ip_defrag rpl_ip_defrag
-#endif
-
-/* If we can use upstream defrag then we can rely on the upstream
- * defrag module to init/exit correctly. In this case the calls in
- * compat_{in,ex}it() can be no-ops. */
-static inline int rpl_ipfrag_init(void) { return 0; }
-static inline void rpl_ipfrag_fini(void) { }
-static inline void ovs_netns_frags_init(struct net *net) { }
-static inline void ovs_netns_frags_exit(struct net *net) { }
-#endif /* HAVE_CORRECT_MRU_HANDLING */
-
-#define ipfrag_init rpl_ipfrag_init
-#define ipfrag_fini rpl_ipfrag_fini
-
-#endif
diff --git a/datapath/linux/compat/include/net/ip6_fib.h b/datapath/linux/compat/include/net/ip6_fib.h
deleted file mode 100644
index 0cc435813..000000000
--- a/datapath/linux/compat/include/net/ip6_fib.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Linux INET6 implementation
- *
- * Authors:
- * Pedro Roque <roque@di.fc.ul.pt>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _IP6_FIB_WRAPPER_H
-#define _IP6_FIB_WRAPPER_H
-
-#include_next <net/ip6_fib.h>
-
-#ifndef HAVE_RT6_GET_COOKIE
-
-#ifndef RTF_PCPU
-#define RTF_PCPU 0x40000000
-#endif
-
-#ifndef RTF_LOCAL
-#define RTF_LOCAL 0x80000000
-#endif
-
-#define rt6_get_cookie rpl_rt6_get_cookie
-static inline u32 rt6_get_cookie(const struct rt6_info *rt)
-{
- if (rt->rt6i_flags & RTF_PCPU ||
-#ifdef HAVE_DST_NOCACHE
- (unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from))
-#else
- (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from))
-#endif
- rt = (struct rt6_info *)(rt->dst.from);
-
- return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
-}
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/net/ip6_route.h b/datapath/linux/compat/include/net/ip6_route.h
deleted file mode 100644
index 7c78fd5c6..000000000
--- a/datapath/linux/compat/include/net/ip6_route.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __NET_IP6_ROUTE_WRAPPER
-#define __NET_IP6_ROUTE_WRAPPER
-
-#include <net/route.h>
-#include <net/ip.h> /* For OVS_VPORT_OUTPUT_PARAMS */
-#include <net/ipv6.h>
-
-#include_next<net/ip6_route.h>
-
-#ifndef HAVE_NF_IPV6_OPS_FRAGMENT
-int rpl_ip6_fragment(struct sock *sk, struct sk_buff *skb,
- int (*output)(OVS_VPORT_OUTPUT_PARAMS));
-#define ip6_fragment rpl_ip6_fragment
-#endif /* HAVE_NF_IPV6_OPS_FRAGMENT */
-
-#endif /* _NET_IP6_ROUTE_WRAPPER */
diff --git a/datapath/linux/compat/include/net/ip6_tunnel.h b/datapath/linux/compat/include/net/ip6_tunnel.h
deleted file mode 100644
index e0a33a646..000000000
--- a/datapath/linux/compat/include/net/ip6_tunnel.h
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef NET_IP6_TUNNEL_WRAPPER_H
-#define NET_IP6_TUNNEL_WRAPPER_H 1
-
-#ifdef HAVE_IP6_TNL_PARM_ERSPAN_VER
-#include_next <net/ip6_tunnel.h>
-#else
-
-#include <linux/ipv6.h>
-#include <linux/netdevice.h>
-#include <linux/if_tunnel.h>
-#include <linux/ip6_tunnel.h>
-#include <net/ip_tunnels.h>
-#include <net/dst_cache.h>
-#include <net/dst_metadata.h>
-#include "gso.h"
-
-#define IP6TUNNEL_ERR_TIMEO (30*HZ)
-
-/* capable of sending packets */
-#define IP6_TNL_F_CAP_XMIT 0x10000
-/* capable of receiving packets */
-#define IP6_TNL_F_CAP_RCV 0x20000
-/* determine capability on a per-packet basis */
-#define IP6_TNL_F_CAP_PER_PACKET 0x40000
-
-#ifndef IP6_TNL_F_ALLOW_LOCAL_REMOTE
-#define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0
-#endif
-
-struct rpl__ip6_tnl_parm {
- char name[IFNAMSIZ]; /* name of tunnel device */
- int link; /* ifindex of underlying L2 interface */
- __u8 proto; /* tunnel protocol */
- __u8 encap_limit; /* encapsulation limit for tunnel */
- __u8 hop_limit; /* hop limit for tunnel */
- bool collect_md;
- __be32 flowinfo; /* traffic class and flowlabel for tunnel */
- __u32 flags; /* tunnel flags */
- struct in6_addr laddr; /* local tunnel end-point address */
- struct in6_addr raddr; /* remote tunnel end-point address */
-
- __be16 i_flags;
- __be16 o_flags;
- __be32 i_key;
- __be32 o_key;
-
- __u32 fwmark;
- __u32 index; /* ERSPAN type II index */
- __u8 erspan_ver; /* ERSPAN version */
- __u8 dir; /* direction */
- __u16 hwid; /* hwid */
-};
-
-#define __ip6_tnl_parm rpl__ip6_tnl_parm
-
-/* IPv6 tunnel */
-struct rpl_ip6_tnl {
- struct rpl_ip6_tnl __rcu *next; /* next tunnel in list */
- struct net_device *dev; /* virtual device associated with tunnel */
- struct net *net; /* netns for packet i/o */
- struct __ip6_tnl_parm parms; /* tunnel configuration parameters */
- struct flowi fl; /* flowi template for xmit */
- struct dst_cache dst_cache; /* cached dst */
- struct gro_cells gro_cells;
-
- int err_count;
- unsigned long err_time;
-
- /* These fields used only by GRE */
- __u32 i_seqno; /* The last seen seqno */
- __u32 o_seqno; /* The last output seqno */
- int hlen; /* tun_hlen + encap_hlen */
- int tun_hlen; /* Precalculated header length */
- int encap_hlen; /* Encap header length (FOU,GUE) */
- struct ip_tunnel_encap encap;
- int mlink;
-};
-
-#define ip6_tnl rpl_ip6_tnl
-
-struct rpl_ip6_tnl_encap_ops {
- size_t (*encap_hlen)(struct ip_tunnel_encap *e);
- int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e,
- u8 *protocol, struct flowi6 *fl6);
-};
-
-#define ip6_tnl_encap_ops rpl_ip6_tnl_encap_ops
-
-#ifdef CONFIG_INET
-
-#ifndef MAX_IPTUN_ENCAP_OPS
-#define MAX_IPTUN_ENCAP_OPS 8
-#endif
-
-extern const struct ip6_tnl_encap_ops __rcu *
- rpl_ip6tun_encaps[MAX_IPTUN_ENCAP_OPS];
-
-int rpl_ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops,
- unsigned int num);
-#define ip6_tnl_encap_add_ops rpl_ip6_tnl_encap_add_ops
-int rpl_ip6_tnl_encap_del_ops(const struct ip6_tnl_encap_ops *ops,
- unsigned int num);
-#define ip6_tnl_encap_del_ops rpl_ip6_tnl_encap_del_ops
-int rpl_ip6_tnl_encap_setup(struct ip6_tnl *t,
- struct ip_tunnel_encap *ipencap);
-#define ip6_tnl_encap_setup rpl_ip6_tnl_encap_setup
-
-#ifndef HAVE_TUNNEL_ENCAP_TYPES
-enum tunnel_encap_types {
- TUNNEL_ENCAP_NONE,
- TUNNEL_ENCAP_FOU,
- TUNNEL_ENCAP_GUE,
-};
-
-#endif
-static inline int ip6_encap_hlen(struct ip_tunnel_encap *e)
-{
- const struct ip6_tnl_encap_ops *ops;
- int hlen = -EINVAL;
-
- if (e->type == TUNNEL_ENCAP_NONE)
- return 0;
-
- if (e->type >= MAX_IPTUN_ENCAP_OPS)
- return -EINVAL;
-
- rcu_read_lock();
- ops = rcu_dereference(rpl_ip6tun_encaps[e->type]);
- if (likely(ops && ops->encap_hlen))
- hlen = ops->encap_hlen(e);
- rcu_read_unlock();
-
- return hlen;
-}
-
-static inline int ip6_tnl_encap(struct sk_buff *skb, struct ip6_tnl *t,
- u8 *protocol, struct flowi6 *fl6)
-{
- const struct ip6_tnl_encap_ops *ops;
- int ret = -EINVAL;
-
- if (t->encap.type == TUNNEL_ENCAP_NONE)
- return 0;
-
- if (t->encap.type >= MAX_IPTUN_ENCAP_OPS)
- return -EINVAL;
-
- rcu_read_lock();
- ops = rcu_dereference(rpl_ip6tun_encaps[t->encap.type]);
- if (likely(ops && ops->build_header))
- ret = ops->build_header(skb, &t->encap, protocol, fl6);
- rcu_read_unlock();
-
- return ret;
-}
-
-/* Tunnel encapsulation limit destination sub-option */
-
-struct ipv6_tlv_tnl_enc_lim {
- __u8 type; /* type-code for option */
- __u8 length; /* option length */
- __u8 encap_limit; /* tunnel encapsulation limit */
-} __packed;
-
-int rpl_ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
- const struct in6_addr *raddr);
-#define ip6_tnl_rcv_ctl rpl_ip6_tnl_rcv_ctl
-int rpl_ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
- const struct tnl_ptk_info *tpi,
- struct metadata_dst *tun_dst,
- bool log_ecn_error);
-#define ip6_tnl_rcv rpl_ip6_tnl_rcv
-int rpl_ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
- const struct in6_addr *raddr);
-#define ip6_tnl_xmit_ctl rpl_ip6_tnl_xmit_ctl
-int rpl_ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
- struct flowi6 *fl6, int encap_limit, __u32 *pmtu,
- __u8 proto);
-#define ip6_tnl_xmit rpl_ip6_tnl_xmit
-__u16 rpl_ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
-#define ip6_tnl_parse_tlv_enc_lim rpl_ip6_tnl_parse_tlv_enc_lim
-__u32 rpl_ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
- const struct in6_addr *raddr);
-#define ip6_tnl_get_cap rpl_ip6_tnl_get_cap
-struct net *rpl_ip6_tnl_get_link_net(const struct net_device *dev);
-#define ip6_tnl_get_link_net rpl_ip6_tnl_get_link_net
-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
-
-static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
- struct net_device *dev)
-{
- int pkt_len, err;
-
- memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
- pkt_len = skb->len - skb_inner_network_offset(skb);
- err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
- if (unlikely(net_xmit_eval(err)))
- pkt_len = -1;
- iptunnel_xmit_stats(dev, pkt_len);
-}
-#endif
-
-#endif /* HAVE_IP6_TNL_PARM_ERSPAN_VER */
-
-#endif
diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h
deleted file mode 100644
index 617a753c7..000000000
--- a/datapath/linux/compat/include/net/ip_tunnels.h
+++ /dev/null
@@ -1,513 +0,0 @@
-#ifndef __NET_IP_TUNNELS_WRAPPER_H
-#define __NET_IP_TUNNELS_WRAPPER_H 1
-
-#include <linux/version.h>
-
-#ifdef USE_UPSTREAM_TUNNEL
-/* Block all ip_tunnel functions.
- * Only function that do not depend on ip_tunnel structure can
- * be used. Those needs to be explicitly defined in this header file. */
-#include_next <net/ip_tunnels.h>
-
-#ifndef TUNNEL_ERSPAN_OPT
-#define TUNNEL_ERSPAN_OPT __cpu_to_be16(0x4000)
-#endif
-#define ovs_ip_tunnel_encap ip_tunnel_encap
-
-#ifndef HAVE_IP_TUNNEL_INFO_OPTS_SET_FLAGS
-static inline void rpl_ip_tunnel_info_opts_set(struct ip_tunnel_info *info,
- const void *from, int len,
- __be16 flags)
-{
- memcpy(ip_tunnel_info_opts(info), from, len);
- info->options_len = len;
- info->key.tun_flags |= flags;
-}
-
-#define ip_tunnel_info_opts_set rpl_ip_tunnel_info_opts_set
-#endif
-
-#else /* USE_UPSTREAM_TUNNEL */
-
-#include <linux/if_tunnel.h>
-#include <linux/types.h>
-#include <net/dsfield.h>
-#include <net/dst_cache.h>
-#include <net/flow.h>
-#include <net/inet_ecn.h>
-#include <net/ip.h>
-#include <net/rtnetlink.h>
-#include <net/gro_cells.h>
-
-#ifndef MAX_IPTUN_ENCAP_OPS
-#define MAX_IPTUN_ENCAP_OPS 8
-#endif
-
-#ifndef HAVE_TUNNEL_ENCAP_TYPES
-enum tunnel_encap_types {
- TUNNEL_ENCAP_NONE,
- TUNNEL_ENCAP_FOU,
- TUNNEL_ENCAP_GUE,
-};
-
-#define HAVE_TUNNEL_ENCAP_TYPES 1
-#endif
-
-#define __iptunnel_pull_header rpl___iptunnel_pull_header
-int rpl___iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
- __be16 inner_proto, bool raw_proto, bool xnet);
-
-#define iptunnel_pull_header rpl_iptunnel_pull_header
-static inline int rpl_iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
- __be16 inner_proto, bool xnet)
-{
- return rpl___iptunnel_pull_header(skb, hdr_len, inner_proto, false, xnet);
-}
-
-int ovs_iptunnel_handle_offloads(struct sk_buff *skb,
- int gso_type_mask,
- void (*fix_segment)(struct sk_buff *));
-
-/* This is required to compile upstream gre.h. gre_handle_offloads()
- * is defined in gre.h and needs iptunnel_handle_offloads(). This provides
- * default signature for this function.
- * rpl prefix is to make OVS build happy.
- */
-#define iptunnel_handle_offloads rpl_iptunnel_handle_offloads
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
-struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb,
- bool csum_help,
- int gso_type_mask);
-#else
-int rpl_iptunnel_handle_offloads(struct sk_buff *skb,
- bool csum_help,
- int gso_type_mask);
-#endif
-
-#define iptunnel_xmit rpl_iptunnel_xmit
-void rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
- __be32 src, __be32 dst, __u8 proto, __u8 tos, __u8 ttl,
- __be16 df, bool xnet);
-#define ip_tunnel_xmit rpl_ip_tunnel_xmit
-void rpl_ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
- const struct iphdr *tnl_params, const u8 protocol);
-
-
-#ifndef TUNNEL_CSUM
-#define TUNNEL_CSUM __cpu_to_be16(0x01)
-#define TUNNEL_ROUTING __cpu_to_be16(0x02)
-#define TUNNEL_KEY __cpu_to_be16(0x04)
-#define TUNNEL_SEQ __cpu_to_be16(0x08)
-#define TUNNEL_STRICT __cpu_to_be16(0x10)
-#define TUNNEL_REC __cpu_to_be16(0x20)
-#define TUNNEL_VERSION __cpu_to_be16(0x40)
-#define TUNNEL_NO_KEY __cpu_to_be16(0x80)
-#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100)
-#define TUNNEL_OAM __cpu_to_be16(0x0200)
-#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400)
-#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800)
-#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000)
-#define TUNNEL_NOCACHE __cpu_to_be16(0x2000)
-#define TUNNEL_ERSPAN_OPT __cpu_to_be16(0x4000)
-
-#undef TUNNEL_OPTIONS_PRESENT
-#define TUNNEL_OPTIONS_PRESENT \
- (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT)
-
-struct tnl_ptk_info {
- __be16 flags;
- __be16 proto;
- __be32 key;
- __be32 seq;
- int hdr_len;
-};
-
-#define PACKET_RCVD 0
-#define PACKET_REJECT 1
-#define PACKET_NEXT 2
-#endif
-
-#define IP_TNL_HASH_BITS 7
-#define IP_TNL_HASH_SIZE (1 << IP_TNL_HASH_BITS)
-
-/* Keep error state on tunnel for 30 sec */
-#define IPTUNNEL_ERR_TIMEO (30*HZ)
-
-/* Used to memset ip_tunnel padding. */
-#define IP_TUNNEL_KEY_SIZE offsetofend(struct ip_tunnel_key, tp_dst)
-
-/* Used to memset ipv4 address padding. */
-#define IP_TUNNEL_KEY_IPV4_PAD offsetofend(struct ip_tunnel_key, u.ipv4.dst)
-#define IP_TUNNEL_KEY_IPV4_PAD_LEN \
- (sizeof_field(struct ip_tunnel_key, u) - \
- sizeof_field(struct ip_tunnel_key, u.ipv4))
-
-struct ip_tunnel_key {
- __be64 tun_id;
- union {
- struct {
- __be32 src;
- __be32 dst;
- } ipv4;
- struct {
- struct in6_addr src;
- struct in6_addr dst;
- } ipv6;
- } u;
- __be16 tun_flags;
- u8 tos; /* TOS for IPv4, TC for IPv6 */
- u8 ttl; /* TTL for IPv4, HL for IPv6 */
- __be32 label; /* Flow Label for IPv6 */
- __be16 tp_src;
- __be16 tp_dst;
-};
-
-/* Flags for ip_tunnel_info mode. */
-#define IP_TUNNEL_INFO_TX 0x01 /* represents tx tunnel parameters */
-#define IP_TUNNEL_INFO_IPV6 0x02 /* key contains IPv6 addresses */
-
-struct ip_tunnel_info {
- struct ip_tunnel_key key;
- struct dst_cache dst_cache;
- u8 options_len;
- u8 mode;
-};
-
-/* 6rd prefix/relay information */
-#ifdef CONFIG_IPV6_SIT_6RD
-struct ip_tunnel_6rd_parm {
- struct in6_addr prefix;
- __be32 relay_prefix;
- u16 prefixlen;
- u16 relay_prefixlen;
-};
-#endif
-
-struct ip_tunnel_encap {
- u16 type;
- u16 flags;
- __be16 sport;
- __be16 dport;
-};
-
-struct ip_tunnel_prl_entry {
- struct ip_tunnel_prl_entry __rcu *next;
- __be32 addr;
- u16 flags;
- struct rcu_head rcu_head;
-};
-
-static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info *tun_info)
-{
- return tun_info->mode & IP_TUNNEL_INFO_IPV6 ? AF_INET6 : AF_INET;
-}
-
-static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info)
-{
- return info + 1;
-}
-
-static inline void ip_tunnel_info_opts_get(void *to,
- const struct ip_tunnel_info *info)
-{
- memcpy(to, info + 1, info->options_len);
-}
-
-static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info,
- const void *from, int len,
- __be16 flags)
-{
- memcpy(ip_tunnel_info_opts(info), from, len);
- info->options_len = len;
- info->key.tun_flags |= flags;
-}
-
-static inline void ip_tunnel_key_init(struct ip_tunnel_key *key,
- __be32 saddr, __be32 daddr,
- u8 tos, u8 ttl, __be32 label,
- __be16 tp_src, __be16 tp_dst,
- __be64 tun_id, __be16 tun_flags)
-{
- key->tun_id = tun_id;
- key->u.ipv4.src = saddr;
- key->u.ipv4.dst = daddr;
- memset((unsigned char *)key + IP_TUNNEL_KEY_IPV4_PAD,
- 0, IP_TUNNEL_KEY_IPV4_PAD_LEN);
- key->tos = tos;
- key->ttl = ttl;
- key->label = label;
- key->tun_flags = tun_flags;
-
- /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of
- * the upper tunnel are used.
- * E.g: GRE over IPSEC, the tp_src and tp_port are zero.
- */
- key->tp_src = tp_src;
- key->tp_dst = tp_dst;
-
- /* Clear struct padding. */
- if (sizeof(*key) != IP_TUNNEL_KEY_SIZE)
- memset((unsigned char *)key + IP_TUNNEL_KEY_SIZE,
- 0, sizeof(*key) - IP_TUNNEL_KEY_SIZE);
-}
-
-#define ip_tunnel_collect_metadata() true
-
-#undef TUNNEL_NOCACHE
-#define TUNNEL_NOCACHE 0
-
-static inline bool
-ip_tunnel_dst_cache_usable(const struct sk_buff *skb,
- const struct ip_tunnel_info *info)
-{
- if (skb->mark)
- return false;
- if (!info)
- return true;
- if (info->key.tun_flags & TUNNEL_NOCACHE)
- return false;
-
- return true;
-}
-
-#define ip_tunnel_dst rpl_ip_tunnel_dst
-struct rpl_ip_tunnel_dst {
- struct dst_entry __rcu *dst;
- __be32 saddr;
-};
-
-#define ip_tunnel rpl_ip_tunnel
-struct rpl_ip_tunnel {
- struct ip_tunnel __rcu *next;
- struct hlist_node hash_node;
- struct net_device *dev;
- struct net *net; /* netns for packet i/o */
-
- unsigned long err_time; /* Time when the last ICMP error
- * arrived */
- int err_count; /* Number of arrived ICMP errors */
-
- /* These four fields used only by GRE */
- u32 i_seqno; /* The last seen seqno */
- u32 o_seqno; /* The last output seqno */
- int tun_hlen; /* Precalculated header length */
-
- /* These four fields used only by ERSPAN */
- u32 index; /* ERSPAN type II index */
- u8 erspan_ver; /* ERSPAN version */
- u8 dir; /* ERSPAN direction */
- u16 hwid; /* ERSPAN hardware ID */
-
- struct dst_cache dst_cache;
-
- struct ip_tunnel_parm parms;
-
- int mlink;
- int encap_hlen; /* Encap header length (FOU,GUE) */
- int hlen; /* tun_hlen + encap_hlen */
- struct ip_tunnel_encap encap;
-
- /* for SIT */
-#ifdef CONFIG_IPV6_SIT_6RD
- struct ip_tunnel_6rd_parm ip6rd;
-#endif
- struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */
- unsigned int prl_count; /* # of entries in PRL */
- unsigned int ip_tnl_net_id;
- struct gro_cells gro_cells;
- __u32 fwmark;
- bool collect_md;
- bool ignore_df;
-};
-
-#define ip_tunnel_net rpl_ip_tunnel_net
-struct rpl_ip_tunnel_net {
- struct net_device *fb_tunnel_dev;
- struct hlist_head tunnels[IP_TNL_HASH_SIZE];
- struct ip_tunnel __rcu *collect_md_tun;
-};
-
-
-struct ip_tunnel_encap_ops {
- size_t (*encap_hlen)(struct ip_tunnel_encap *e);
- int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e,
- const u8 *protocol, struct flowi4 *fl4);
-};
-
-extern const struct ip_tunnel_encap_ops __rcu *
- rpl_iptun_encaps[MAX_IPTUN_ENCAP_OPS];
-
-#define ip_encap_hlen rpl_ip_encap_hlen
-static inline int rpl_ip_encap_hlen(struct ip_tunnel_encap *e)
-{
- const struct ip_tunnel_encap_ops *ops;
- int hlen = -EINVAL;
-
- if (e->type == TUNNEL_ENCAP_NONE)
- return 0;
-
- if (e->type >= MAX_IPTUN_ENCAP_OPS)
- return -EINVAL;
-
- rcu_read_lock();
- ops = rcu_dereference(rpl_iptun_encaps[e->type]);
- if (likely(ops && ops->encap_hlen))
- hlen = ops->encap_hlen(e);
- rcu_read_unlock();
-
- return hlen;
-}
-
-static inline int ovs_ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
- const u8 *protocol, struct flowi4 *fl4)
-{
- const struct ip_tunnel_encap_ops *ops;
- int ret = -EINVAL;
-
- if (t->encap.type == TUNNEL_ENCAP_NONE)
- return 0;
-
- if (t->encap.type >= MAX_IPTUN_ENCAP_OPS)
- return -EINVAL;
-
- rcu_read_lock();
- ops = rcu_dereference(rpl_iptun_encaps[t->encap.type]);
- if (likely(ops && ops->build_header))
- ret = ops->build_header(skb, &t->encap, protocol, fl4);
- rcu_read_unlock();
-
- return ret;
-}
-
-#define ip_tunnel_get_stats64 rpl_ip_tunnel_get_stats64
-#if !defined(HAVE_VOID_NDO_GET_STATS64) && !defined(HAVE_RHEL7_MAX_MTU)
-struct rtnl_link_stats64 *rpl_ip_tunnel_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot);
-#else
-void rpl_ip_tunnel_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot);
-#endif
-#define ip_tunnel_get_dsfield rpl_ip_tunnel_get_dsfield
-static inline u8 rpl_ip_tunnel_get_dsfield(const struct iphdr *iph,
- const struct sk_buff *skb)
-{
- if (skb->protocol == htons(ETH_P_IP))
- return iph->tos;
- else if (skb->protocol == htons(ETH_P_IPV6))
- return ipv6_get_dsfield((const struct ipv6hdr *)iph);
- else
- return 0;
-}
-
-#define ip_tunnel_ecn_encap rpl_ip_tunnel_ecn_encap
-static inline u8 rpl_ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
- const struct sk_buff *skb)
-{
- u8 inner = ip_tunnel_get_dsfield(iph, skb);
-
- return INET_ECN_encapsulate(tos, inner);
-}
-
-static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len)
-{
- if (pkt_len > 0) {
- struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats);
-
- u64_stats_update_begin(&tstats->syncp);
- tstats->tx_bytes += pkt_len;
- tstats->tx_packets++;
- u64_stats_update_end(&tstats->syncp);
- put_cpu_ptr(tstats);
- } else {
- struct net_device_stats *err_stats = &dev->stats;
-
- if (pkt_len < 0) {
- err_stats->tx_errors++;
- err_stats->tx_aborted_errors++;
- } else {
- err_stats->tx_dropped++;
- }
- }
-}
-
-static inline __be64 key32_to_tunnel_id(__be32 key)
-{
-#ifdef __BIG_ENDIAN
- return (__force __be64)key;
-#else
- return (__force __be64)((__force u64)key << 32);
-#endif
-}
-
-/* Returns the least-significant 32 bits of a __be64. */
-static inline __be32 tunnel_id_to_key32(__be64 tun_id)
-{
-#ifdef __BIG_ENDIAN
- return (__force __be32)tun_id;
-#else
- return (__force __be32)((__force u64)tun_id >> 32);
-#endif
-}
-
-#define ip_tunnel_init rpl_ip_tunnel_init
-int rpl_ip_tunnel_init(struct net_device *dev);
-
-#define ip_tunnel_uninit rpl_ip_tunnel_uninit
-void rpl_ip_tunnel_uninit(struct net_device *dev);
-
-#define ip_tunnel_change_mtu rpl_ip_tunnel_change_mtu
-int rpl_ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);
-
-#define ip_tunnel_newlink rpl_ip_tunnel_newlink
-int rpl_ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
- struct ip_tunnel_parm *p);
-
-#define ip_tunnel_dellink rpl_ip_tunnel_dellink
-void rpl_ip_tunnel_dellink(struct net_device *dev, struct list_head *head);
-
-#define ip_tunnel_init_net rpl_ip_tunnel_init_net
-int rpl_ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
- struct rtnl_link_ops *ops, char *devname);
-
-#define ip_tunnel_delete_net rpl_ip_tunnel_delete_net
-void rpl_ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops);
-
-#define ip_tunnel_setup rpl_ip_tunnel_setup
-void rpl_ip_tunnel_setup(struct net_device *dev, int net_id);
-
-#define ip_tunnel_get_iflink rpl_ip_tunnel_get_iflink
-int rpl_ip_tunnel_get_iflink(const struct net_device *dev);
-
-#define ip_tunnel_get_link_net rpl_ip_tunnel_get_link_net
-struct net *rpl_ip_tunnel_get_link_net(const struct net_device *dev);
-
-#define __ip_tunnel_change_mtu rpl___ip_tunnel_change_mtu
-int rpl___ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict);
-
-#define ip_tunnel_lookup rpl_ip_tunnel_lookup
-struct ip_tunnel *rpl_ip_tunnel_lookup(struct ip_tunnel_net *itn,
- int link, __be16 flags,
- __be32 remote, __be32 local,
- __be32 key);
-
-static inline int iptunnel_pull_offloads(struct sk_buff *skb)
-{
- if (skb_is_gso(skb)) {
- int err;
-
- err = skb_unclone(skb, GFP_ATOMIC);
- if (unlikely(err))
- return err;
- skb_shinfo(skb)->gso_type &= ~(NETIF_F_GSO_ENCAP_ALL >>
- NETIF_F_GSO_SHIFT);
- }
-
- skb->encapsulation = 0;
- return 0;
-}
-#endif /* USE_UPSTREAM_TUNNEL */
-
-#define skb_is_encapsulated ovs_skb_is_encapsulated
-bool ovs_skb_is_encapsulated(struct sk_buff *skb);
-
-#endif /* __NET_IP_TUNNELS_H */
diff --git a/datapath/linux/compat/include/net/ipv6.h b/datapath/linux/compat/include/net/ipv6.h
deleted file mode 100644
index 6379457e8..000000000
--- a/datapath/linux/compat/include/net/ipv6.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef __NET_IPV6_WRAPPER_H
-#define __NET_IPV6_WRAPPER_H 1
-
-#include <linux/version.h>
-
-#include_next <net/ipv6.h>
-
-#ifndef NEXTHDR_SCTP
-#define NEXTHDR_SCTP 132 /* Stream Control Transport Protocol */
-#endif
-
-#ifndef HAVE_IP6_FH_F_SKIP_RH
-
-enum {
- IP6_FH_F_FRAG = (1 << 0),
- IP6_FH_F_AUTH = (1 << 1),
- IP6_FH_F_SKIP_RH = (1 << 2),
-};
-
-/* This function is upstream, but not the version which skips routing
- * headers with 0 segments_left. We fixed it when we introduced
- * IP6_FH_F_SKIP_RH.
- */
-#define ipv6_find_hdr rpl_ipv6_find_hdr
-extern int rpl_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
- int target, unsigned short *fragoff, int *fragflg);
-#endif
-
-#ifndef HAVE___IPV6_ADDR_JHASH
-static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 unused)
-{
- return ipv6_addr_jhash(a);
-}
-#endif
-
-#define ip6_flowlabel rpl_ip6_flowlabel
-static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
-{
- return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
-}
-
-#ifndef HAVE_IP6_MAKE_FLOWLABEL_FL6
-#define ip6_make_flowlabel rpl_ip6_make_flowlabel
-static inline __be32 rpl_ip6_make_flowlabel(struct net *net,
- struct sk_buff *skb,
- __be32 flowlabel, bool autolabel,
- struct flowi6 *fl6)
-{
-#ifndef HAVE_NETNS_SYSCTL_IPV6_AUTO_FLOWLABELS
- if (!flowlabel && autolabel) {
-#else
- if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) {
-#endif
- u32 hash;
-
- hash = skb_get_hash(skb);
-
- /* Since this is being sent on the wire obfuscate hash a bit
- * to minimize possbility that any useful information to an
- * attacker is leaked. Only lower 20 bits are relevant.
- */
- hash ^= hash >> 12;
-
- flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
- }
-
- return flowlabel;
-}
-#endif
-
-#ifndef IPV6_TCLASS_SHIFT
-#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
-#define IPV6_TCLASS_SHIFT 20
-#endif
-
-#define ip6_tclass rpl_ip6_tclass
-static inline u8 ip6_tclass(__be32 flowinfo)
-{
- return ntohl(flowinfo & IPV6_TCLASS_MASK) >> IPV6_TCLASS_SHIFT;
-}
-
-#define ip6_make_flowinfo rpl_ip6_make_flowinfo
-static inline __be32 ip6_make_flowinfo(unsigned int tclass, __be32 flowlabel)
-{
- return htonl(tclass << IPV6_TCLASS_SHIFT) | flowlabel;
-}
-
-#endif
diff --git a/datapath/linux/compat/include/net/ipv6_frag.h b/datapath/linux/compat/include/net/ipv6_frag.h
deleted file mode 100644
index 5d1cc901b..000000000
--- a/datapath/linux/compat/include/net/ipv6_frag.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __NET_IPV6_FRAG_WRAPPER_H
-#define __NET_IPV6_FRAG_WRAPPER_H
-
-#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) && defined(HAVE_IPV6_FRAG_H)
-#include_next <net/ipv6_frag.h>
-#endif
-
-#endif /* __NET_IPV6_FRAG_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/lisp.h b/datapath/linux/compat/include/net/lisp.h
deleted file mode 100644
index 6b43c77e2..000000000
--- a/datapath/linux/compat/include/net/lisp.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __NET_LISP_WRAPPER_H
-#define __NET_LISP_WRAPPER_H 1
-
-#ifdef CONFIG_INET
-#include <net/udp_tunnel.h>
-#endif
-
-
-#ifdef CONFIG_INET
-#define lisp_dev_create_fb rpl_lisp_dev_create_fb
-struct net_device *rpl_lisp_dev_create_fb(struct net *net, const char *name,
- u8 name_assign_type, u16 dst_port);
-#endif /*ifdef CONFIG_INET */
-
-#define lisp_init_module rpl_lisp_init_module
-int rpl_lisp_init_module(void);
-
-#define lisp_cleanup_module rpl_lisp_cleanup_module
-void rpl_lisp_cleanup_module(void);
-
-#define lisp_xmit rpl_lisp_xmit
-netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb);
-
-#define lisp_fill_metadata_dst ovs_lisp_fill_metadata_dst
-int ovs_lisp_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-
-#endif /*ifdef__NET_LISP_H */
diff --git a/datapath/linux/compat/include/net/mpls.h b/datapath/linux/compat/include/net/mpls.h
deleted file mode 100644
index 9359a2369..000000000
--- a/datapath/linux/compat/include/net/mpls.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#ifndef _NET_MPLS_WRAPPER_H
-#define _NET_MPLS_WRAPPER_H 1
-
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-
-#define MPLS_HLEN 4
-
-struct mpls_shim_hdr {
- __be32 label_stack_entry;
-};
-
-static inline bool eth_p_mpls(__be16 eth_type)
-{
- return eth_type == htons(ETH_P_MPLS_UC) ||
- eth_type == htons(ETH_P_MPLS_MC);
-}
-
-/* Starting from kernel 4.9, commit 48d2ab609b6b ("net: mpls: Fixups for GSO")
- * and commit 85de4a2101ac ("openvswitch: use mpls_hdr") introduced
- * behavioural changes to mpls_gso kernel module. It now assumes that
- * skb_network_header() points to the mpls header and
- * skb_inner_network_header() points to the L3 header. However, the old
- * mpls_gso kernel module assumes that the skb_network_header() points
- * to the L3 header. We shall backport the following function to ensure
- * MPLS GSO works properly for kernels older than the one which contains
- * these commits.
- */
-#ifdef MPLS_HEADER_IS_L3
-static inline struct mpls_shim_hdr *mpls_hdr(const struct sk_buff *skb)
-{
- return (struct mpls_shim_hdr *)skb_network_header(skb);
-}
-#else
-#define mpls_hdr rpl_mpls_hdr
-/*
- * For non-MPLS skbs this will correspond to the network header.
- * For MPLS skbs it will be before the network_header as the MPLS
- * label stack lies between the end of the mac header and the network
- * header. That is, for MPLS skbs the end of the mac header
- * is the top of the MPLS label stack.
- */
-static inline struct mpls_shim_hdr *rpl_mpls_hdr(const struct sk_buff *skb)
-{
- return (struct mpls_shim_hdr *) (skb_mac_header(skb) + skb->mac_len);
-}
-#endif
-
-#endif /* _NET_MPLS_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/net_namespace.h b/datapath/linux/compat/include/net/net_namespace.h
deleted file mode 100644
index 427072249..000000000
--- a/datapath/linux/compat/include/net/net_namespace.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __NET_NET_NAMESPACE_WRAPPER_H
-#define __NET_NET_NAMESPACE_WRAPPER_H 1
-
-#include_next <net/net_namespace.h>
-
-#ifndef HAVE_POSSIBLE_NET_T
-typedef struct {
-#ifdef CONFIG_NET_NS
- struct net *net;
-#endif
-} possible_net_t;
-
-static inline void rpl_write_pnet(possible_net_t *pnet, struct net *net)
-{
-#ifdef CONFIG_NET_NS
- pnet->net = net;
-#endif
-}
-
-static inline struct net *rpl_read_pnet(const possible_net_t *pnet)
-{
-#ifdef CONFIG_NET_NS
- return pnet->net;
-#else
- return &init_net;
-#endif
-}
-#else /* Linux >= 4.1 */
-#define rpl_read_pnet read_pnet
-#define rpl_write_pnet write_pnet
-#endif /* Linux >= 4.1 */
-
-#endif /* net/net_namespace.h wrapper */
diff --git a/datapath/linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/datapath/linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h
deleted file mode 100644
index c4c0f79ab..000000000
--- a/datapath/linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _NF_DEFRAG_IPV6_WRAPPER_H
-#define _NF_DEFRAG_IPV6_WRAPPER_H
-
-#include <linux/kconfig.h>
-#include_next <net/netfilter/ipv6/nf_defrag_ipv6.h>
-
-/* Upstream commit 029f7f3b8701 ("netfilter: ipv6: nf_defrag: avoid/free clone
- * operations") changed the semantics of nf_ct_frag6_gather(), so we need
- * to backport for all prior kernels, i.e. kernel < 4.5.0.
- *
- * Upstream commit 48cac18ecf1d ("ipv6: orphan skbs in reassembly unit") fixes
- * a bug that requires all kernels prior to this fix, i.e. kernel < 4.11.0
- * to be backported.
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
-#define OVS_NF_DEFRAG6_BACKPORT 1
-int rpl_nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user);
-#define nf_ct_frag6_gather rpl_nf_ct_frag6_gather
-
-/* If backporting IPv6 defrag, then init/exit functions need to be called from
- * compat_{in,ex}it() to prepare the backported fragmentation cache. In this
- * case we declare the functions which are defined in
- * datapath/linux/compat/nf_conntrack_reasm.c.
- *
- * Otherwise, if we can use upstream defrag then we can rely on the upstream
- * nf_defrag_ipv6 module to init/exit correctly. In this case the calls in
- * compat_{in,ex}it() can be no-ops.
- */
-int __init rpl_nf_ct_frag6_init(void);
-void rpl_nf_ct_frag6_cleanup(void);
-void ovs_netns_frags6_init(struct net *net);
-void ovs_netns_frags6_exit(struct net *net);
-#else /* !OVS_NF_DEFRAG6_BACKPORT */
-static inline int __init rpl_nf_ct_frag6_init(void) { return 0; }
-static inline void rpl_nf_ct_frag6_cleanup(void) { }
-static inline void ovs_netns_frags6_init(struct net *net) { }
-static inline void ovs_netns_frags6_exit(struct net *net) { }
-#endif /* OVS_NF_DEFRAG6_BACKPORT */
-#define nf_ct_frag6_init rpl_nf_ct_frag6_init
-#define nf_ct_frag6_cleanup rpl_nf_ct_frag6_cleanup
-
-#endif /* __NF_DEFRAG_IPV6_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack.h
deleted file mode 100644
index 50db914a3..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef _NF_CONNTRACK_WRAPPER_H
-#define _NF_CONNTRACK_WRAPPER_H
-
-#include_next <net/netfilter/nf_conntrack.h>
-
-#ifndef HAVE_NF_CT_GET_TUPLEPR_TAKES_STRUCT_NET
-static inline bool rpl_nf_ct_get_tuplepr(const struct sk_buff *skb,
- unsigned int nhoff,
- u_int16_t l3num, struct net *net,
- struct nf_conntrack_tuple *tuple)
-{
- return nf_ct_get_tuplepr(skb, nhoff, l3num, tuple);
-}
-#define nf_ct_get_tuplepr rpl_nf_ct_get_tuplepr
-#endif
-
-#ifndef HAVE_NF_CT_SET
-static inline void
-nf_ct_set(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info info)
-{
- skb->nfct = &ct->ct_general;
- skb->nfctinfo = info;
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)
-int rpl_nf_ct_netns_get(struct net *net, u8 nfproto);
-void rpl_nf_ct_netns_put(struct net *net, u8 nfproto);
-#define nf_ct_netns_get rpl_nf_ct_netns_get
-#define nf_ct_netns_put rpl_nf_ct_netns_put
-#endif
-
-#endif /* _NF_CONNTRACK_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h
deleted file mode 100644
index bc18c56b8..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h
+++ /dev/null
@@ -1,137 +0,0 @@
-#ifndef _NF_CONNTRACK_CORE_WRAPPER_H
-#define _NF_CONNTRACK_CORE_WRAPPER_H
-
-#include_next <net/netfilter/nf_conntrack_core.h>
-
-#ifndef HAVE_NF_CT_TMPL_ALLOC_TAKES_STRUCT_ZONE
-
-#include <net/netfilter/nf_conntrack_zones.h>
-
-/* Released via destroy_conntrack() */
-static inline struct nf_conn *
-rpl_nf_ct_tmpl_alloc(struct net *net, const struct nf_conntrack_zone *zone,
- gfp_t flags)
-{
- struct nf_conn *tmpl;
-
- tmpl = kzalloc(sizeof(*tmpl), flags);
- if (tmpl == NULL)
- return NULL;
-
- tmpl->status = IPS_TEMPLATE;
- write_pnet(&tmpl->ct_net, net);
-
- if (nf_ct_zone_add(tmpl, flags, zone) < 0)
- goto out_free;
-
- atomic_set(&tmpl->ct_general.use, 0);
-
- return tmpl;
-out_free:
- kfree(tmpl);
- return NULL;
-}
-#define nf_ct_tmpl_alloc rpl_nf_ct_tmpl_alloc
-
-static inline void rpl_nf_ct_tmpl_free(struct nf_conn *tmpl)
-{
- nf_ct_ext_destroy(tmpl);
- nf_ct_ext_free(tmpl);
- kfree(tmpl);
-}
-#define nf_ct_tmpl_free rpl_nf_ct_tmpl_free
-
-static inline struct nf_conntrack_tuple_hash *
-rpl_nf_conntrack_find_get(struct net *net,
- const struct nf_conntrack_zone *zone,
- const struct nf_conntrack_tuple *tuple)
-{
- return nf_conntrack_find_get(net, zone->id, tuple);
-}
-#define nf_conntrack_find_get rpl_nf_conntrack_find_get
-#endif /* HAVE_NF_CT_TMPL_ALLOC_TAKES_STRUCT_ZONE */
-
-#ifndef HAVE_NF_CT_GET_TUPLEPR_TAKES_STRUCT_NET
-static inline bool rpl_nf_ct_get_tuple(const struct sk_buff *skb,
- unsigned int nhoff,
- unsigned int dataoff, u_int16_t l3num,
- u_int8_t protonum,
- struct net *net,
- struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_l3proto *l3proto,
- const struct nf_conntrack_l4proto *l4proto)
-{
- return nf_ct_get_tuple(skb, nhoff, dataoff, l3num, protonum, tuple,
- l3proto, l4proto);
-}
-#define nf_ct_get_tuple rpl_nf_ct_get_tuple
-#endif /* HAVE_NF_CT_GET_TUPLEPR_TAKES_STRUCT_NET */
-
-#ifdef HAVE_NF_CONN_TIMER
-
-#ifndef HAVE_NF_CT_DELETE
-#include <net/netfilter/nf_conntrack_timestamp.h>
-#endif
-
-static inline bool rpl_nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
-{
- if (del_timer(&ct->timeout))
-#ifdef HAVE_NF_CT_DELETE
- return nf_ct_delete(ct, portid, report);
-#else
- {
- struct nf_conn_tstamp *tstamp;
-
- tstamp = nf_conn_tstamp_find(ct);
- if (tstamp && tstamp->stop == 0)
- tstamp->stop = ktime_to_ns(ktime_get_real());
-
- if (!test_bit(IPS_DYING_BIT, &ct->status) &&
- unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) {
- /* destroy event was not delivered */
- nf_ct_delete_from_lists(ct);
- nf_ct_dying_timeout(ct);
- return false;
- }
- set_bit(IPS_DYING_BIT, &ct->status);
- nf_ct_delete_from_lists(ct);
- nf_ct_put(ct);
- return true;
- }
-#endif
- return false;
-}
-#define nf_ct_delete rpl_nf_ct_delete
-#endif /* HAVE_NF_CONN_TIMER */
-
-#ifndef HAVE_NF_CONNTRACK_IN_TAKES_NF_HOOK_STATE
-static inline unsigned int
-rpl_nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state)
-{
- int err;
-
- /* Repeat if requested, see nf_iterate(). */
- do {
- err = nf_conntrack_in(state->net, state->pf, state->hook, skb);
- } while (err == NF_REPEAT);
-
- return err;
-}
-#define nf_conntrack_in rpl_nf_conntrack_in
-#endif /* HAVE_NF_CONNTRACK_IN_TAKES_NF_HOOK_STATE */
-
-#ifdef HAVE_NF_CT_INVERT_TUPLEPR
-static inline bool rpl_nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
- const struct nf_conntrack_tuple *orig)
-{
- return nf_ct_invert_tuplepr(inverse, orig);
-}
-#else
-static inline bool rpl_nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
- const struct nf_conntrack_tuple *orig)
-{
- return nf_ct_invert_tuple(inverse, orig);
-}
-#endif /* HAVE_NF_CT_INVERT_TUPLEPR */
-
-#endif /* _NF_CONNTRACK_CORE_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h
deleted file mode 100644
index 2143136aa..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _NF_CONNTRACK_COUNT_WRAPPER_H
-#define _NF_CONNTRACK_COUNT_WRAPPER_H
-
-#include <linux/list.h>
-#include <net/netfilter/nf_conntrack_tuple.h>
-#include <net/netfilter/nf_conntrack_zones.h>
-
-#ifdef HAVE_UPSTREAM_NF_CONNCOUNT
-#include_next <net/netfilter/nf_conntrack_count.h>
-
-static inline int rpl_nf_conncount_modinit(void)
-{
- return 0;
-}
-
-static inline void rpl_nf_conncount_modexit(void)
-{
-}
-
-#else
-#define CONFIG_NETFILTER_CONNCOUNT 1
-struct nf_conncount_data;
-
-struct nf_conncount_list {
- spinlock_t list_lock;
- struct list_head head; /* connections with the same filtering key */
- unsigned int count; /* length of list */
-};
-
-struct nf_conncount_data
-*rpl_nf_conncount_init(struct net *net, unsigned int family,
- unsigned int keylen);
-
-void rpl_nf_conncount_destroy(struct net *net, unsigned int family,
- struct nf_conncount_data *data);
-
-unsigned int rpl_nf_conncount_count(struct net *net,
- struct nf_conncount_data *data,
- const u32 *key,
- const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_zone *zone);
-
-#define nf_conncount_init rpl_nf_conncount_init
-#define nf_conncount_destroy rpl_nf_conncount_destroy
-#define nf_conncount_count rpl_nf_conncount_count
-
-int rpl_nf_conncount_modinit(void);
-void rpl_nf_conncount_modexit(void);
-#endif /* HAVE_UPSTREAM_NF_CONNCOUNT */
-
-#define nf_conncount_mod_init rpl_nf_conncount_modinit
-#define nf_conncount_modexit rpl_nf_conncount_modexit
-
-#endif /* _NF_CONNTRACK_COUNT_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_expect.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_expect.h
deleted file mode 100644
index a13f0ce60..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_expect.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _NF_CONNTRACK_EXPECT_WRAPPER_H
-#define _NF_CONNTRACK_EXPECT_WRAPPER_H
-
-#include_next <net/netfilter/nf_conntrack_expect.h>
-
-#ifndef HAVE_NF_CT_ZONE_INIT
-
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_zones.h>
-
-static inline struct nf_conntrack_expect *
-rpl___nf_ct_expect_find(struct net *net,
- const struct nf_conntrack_zone *zone,
- const struct nf_conntrack_tuple *tuple)
-{
- return __nf_ct_expect_find(net, zone->id, tuple);
-}
-#define __nf_ct_expect_find rpl___nf_ct_expect_find
-
-#endif /* HAVE_NF_CT_ZONE_INIT */
-#endif /* _NF_CONNTRACK_EXPECT_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_helper.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_helper.h
deleted file mode 100644
index 78f97375b..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_helper.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _NF_CONNTRACK_HELPER_WRAPPER_H
-#define _NF_CONNTRACK_HELPER_WRAPPER_H
-
-#include_next <net/netfilter/nf_conntrack_helper.h>
-
-#ifndef HAVE_NF_CONNTRACK_HELPER_PUT
-static inline void nf_conntrack_helper_put(struct nf_conntrack_helper *helper) {
- module_put(helper->me);
-}
-#endif
-
-#ifndef HAVE_NF_CT_HELPER_EXT_ADD_TAKES_HELPER
-static inline struct nf_conn_help *
-rpl_nf_ct_helper_ext_add(struct nf_conn *ct,
- struct nf_conntrack_helper *helper, gfp_t gfp)
-{
- return nf_ct_helper_ext_add(ct, gfp);
-}
-#define nf_ct_helper_ext_add rpl_nf_ct_helper_ext_add
-#endif /* HAVE_NF_CT_HELPER_EXT_ADD_TAKES_HELPER */
-
-#ifndef HAVE_NF_NAT_HELPER_TRY_MODULE_GET
-static inline int rpl_nf_nat_helper_try_module_get(const char *name, u16 l3num,
- u8 protonum)
-{
- request_module("ip_nat_%s", name);
- return 0;
-}
-#define nf_nat_helper_try_module_get rpl_nf_nat_helper_try_module_get
-#endif /* HAVE_NF_NAT_HELPER_TRY_MODULE_GET */
-
-#ifndef HAVE_NF_NAT_HELPER_PUT
-void rpl_nf_nat_helper_put(struct nf_conntrack_helper *helper)
-{
-}
-#define nf_nat_helper_put rpl_nf_nat_helper_put
-#endif /* HAVE_NF_NAT_HELPER_PUT */
-
-#endif /* _NF_CONNTRACK_HELPER_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_labels.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_labels.h
deleted file mode 100644
index 14cb35716..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_labels.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef _NF_CONNTRACK_LABELS_WRAPPER_H
-#define _NF_CONNTRACK_LABELS_WRAPPER_H
-
-#include <linux/kconfig.h>
-#include <linux/version.h>
-#include_next <net/netfilter/nf_conntrack_labels.h>
-
-#ifndef NF_CT_LABELS_MAX_SIZE
-#define NF_CT_LABELS_MAX_SIZE ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
-#endif
-
-#ifndef HAVE_NF_CONNLABELS_GET_TAKES_BIT
-#if IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS)
-
-/* XXX: This doesn't lock others out from doing the same configuration
- * simultaneously. */
-static inline int rpl_nf_connlabels_get(struct net *net, unsigned int bits)
-{
-#ifndef HAVE_NF_CONNLABELS_GET
- size_t words;
-
- words = BIT_WORD(bits) + 1;
- if (words > NF_CT_LABELS_MAX_SIZE / sizeof(long))
- return -ERANGE;
-
- net->ct.labels_used++;
- if (words > net->ct.label_words)
- net->ct.label_words = words;
-
- return 0;
-#else
- return nf_connlabels_get(net, bits + 1);
-#endif /* HAVE_NF_CONNLABELS_GET */
-}
-#define nf_connlabels_get rpl_nf_connlabels_get
-
-static inline void rpl_nf_connlabels_put(struct net *net)
-{
-#ifndef HAVE_NF_CONNLABELS_GET
- net->ct.labels_used--;
- if (net->ct.labels_used == 0)
- net->ct.label_words = 0;
-#else
- nf_connlabels_put(net);
-#endif /* HAVE_NF_CONNLABELS_GET */
-}
-#define nf_connlabels_put rpl_nf_connlabels_put
-
-#else /* CONFIG_NF_CONNTRACK_LABELS */
-#define nf_connlabels_get rpl_nf_connlabels_get
-static inline int nf_connlabels_get(struct net *net, unsigned int bits)
-{
- return -ERANGE;
-}
-
-#define nf_connlabels_put rpl_nf_connlabels_put
-static inline void nf_connlabels_put(struct net *net) { }
-#endif /* CONFIG_NF_CONNTRACK_LABELS */
-#endif /* HAVE_NF_CONNLABELS_GET_TAKES_BIT */
-
-/* Upstream commit 5a8145f7b222 ("netfilter: labels: don't emit ct event if
- * labels were not changed"), released in Linux 4.7, introduced a functional
- * change to trigger conntrack event for a label change only when the labels
- * actually changed. There is no way we can detect this from the headers, so
- * provide replacements that work the same for OVS (where labels size is 128
- * bits == 16 bytes == 4 4-byte words). */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
-static int replace_u32(u32 *address, u32 mask, u32 new)
-{
- u32 old, tmp;
-
- do {
- old = *address;
- tmp = (old & mask) ^ new;
- if (old == tmp)
- return 0;
- } while (cmpxchg(address, old, tmp) != old);
-
- return 1;
-}
-
-static int rpl_nf_connlabels_replace(struct nf_conn *ct,
- const u32 *data,
- const u32 *mask, unsigned int words32)
-{
- struct nf_conn_labels *labels;
- unsigned int i;
- int changed = 0;
- u32 *dst;
-
- labels = nf_ct_labels_find(ct);
- if (!labels)
- return -ENOSPC;
-
- dst = (u32 *) labels->bits;
- for (i = 0; i < words32; i++)
- changed |= replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
-
- if (changed)
- nf_conntrack_event_cache(IPCT_LABEL, ct);
-
- return 0;
-}
-#define nf_connlabels_replace rpl_nf_connlabels_replace
-#endif
-
-#endif /* _NF_CONNTRACK_LABELS_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h
deleted file mode 100644
index b11d1a578..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _NF_CONNTRACK_SEQADJ_WRAPPER_H
-#define _NF_CONNTRACK_SEQADJ_WRAPPER_H
-
-#ifdef HAVE_NF_CT_SEQ_ADJUST
-#include_next <net/netfilter/nf_conntrack_seqadj.h>
-#else
-
-#include <net/netfilter/nf_nat_helper.h>
-
-/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
-static inline int
-nf_ct_seq_adjust(struct sk_buff *skb,
- struct nf_conn *ct, enum ip_conntrack_info ctinfo,
- unsigned int protoff)
-{
- typeof(nf_nat_seq_adjust_hook) seq_adjust;
-
- seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
- if (!seq_adjust ||
- !seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
- NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
- return 0;
- }
-
- return 1;
-}
-
-#endif /* HAVE_NF_CT_SEQ_ADJUST */
-
-#endif /* _NF_CONNTRACK_SEQADJ_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_timeout.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_timeout.h
deleted file mode 100644
index 134e72b83..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_timeout.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _NF_CONNTRACK_TIMEOUT_WRAPPER_H
-#define _NF_CONNTRACK_TIMEOUT_WRAPPER_H
-
-#include_next <net/netfilter/nf_conntrack_timeout.h>
-
-#ifndef HAVE_NF_CT_SET_TIMEOUT
-
-#ifndef HAVE_NF_CT_TIMEOUT
-#define nf_ct_timeout ctnl_timeout
-#endif
-
-#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
-int rpl_nf_ct_set_timeout(struct net *net, struct nf_conn *ct, u8 l3num, u8 l4num,
- const char *timeout_name);
-void rpl_nf_ct_destroy_timeout(struct nf_conn *ct);
-#else
-static inline int rpl_nf_ct_set_timeout(struct net *net, struct nf_conn *ct,
- u8 l3num, u8 l4num,
- const char *timeout_name)
-{
- return -EOPNOTSUPP;
-}
-
-static inline void rpl_nf_ct_destroy_timeout(struct nf_conn *ct)
-{
- return;
-}
-#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
-
-#define nf_ct_set_timeout rpl_nf_ct_set_timeout
-#define nf_ct_destroy_timeout rpl_nf_ct_destroy_timeout
-
-#endif /* HAVE_NF_CT_SET_TIMEOUT */
-#endif /* _NF_CONNTRACK_TIMEOUT_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h
deleted file mode 100644
index d46c098c7..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef _NF_CONNTRACK_ZONES_WRAPPER_H
-#define _NF_CONNTRACK_ZONES_WRAPPER_H
-
-#include <linux/version.h>
-
-#include_next <net/netfilter/nf_conntrack_zones.h>
-
-#ifndef HAVE_NF_CT_ZONE_INIT
-
-#include <linux/kconfig.h>
-#include <linux/types.h>
-#include <linux/netfilter/nf_conntrack_tuple_common.h>
-
-#define NF_CT_DEFAULT_ZONE_ID 0
-
-#define NF_CT_ZONE_DIR_ORIG (1 << IP_CT_DIR_ORIGINAL)
-#define NF_CT_ZONE_DIR_REPL (1 << IP_CT_DIR_REPLY)
-
-#define NF_CT_DEFAULT_ZONE_DIR (NF_CT_ZONE_DIR_ORIG | NF_CT_ZONE_DIR_REPL)
-
-#define NF_CT_FLAG_MARK 1
-
-struct rpl_nf_conntrack_zone {
- u16 id;
- u8 flags;
- u8 dir;
-};
-#define nf_conntrack_zone rpl_nf_conntrack_zone
-
-extern const struct nf_conntrack_zone nf_ct_zone_dflt;
-
-#if IS_ENABLED(CONFIG_NF_CONNTRACK)
-#include <net/netfilter/nf_conntrack_extend.h>
-
-static inline const struct nf_conntrack_zone *
-rpl_nf_ct_zone(const struct nf_conn *ct)
-{
- const struct nf_conntrack_zone *nf_ct_zone = NULL;
-
-#ifdef CONFIG_NF_CONNTRACK_ZONES
- nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE);
-#endif
- return nf_ct_zone ? nf_ct_zone : &nf_ct_zone_dflt;
-}
-#define nf_ct_zone rpl_nf_ct_zone
-
-static inline const struct nf_conntrack_zone *
-nf_ct_zone_init(struct nf_conntrack_zone *zone, u16 id, u8 dir, u8 flags)
-{
- zone->id = id;
- zone->flags = flags;
- zone->dir = dir;
-
- return zone;
-}
-
-static inline int nf_ct_zone_add(struct nf_conn *ct, gfp_t flags,
- const struct nf_conntrack_zone *info)
-{
-#ifdef CONFIG_NF_CONNTRACK_ZONES
- struct nf_conntrack_zone *nf_ct_zone;
-
- nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, flags);
- if (!nf_ct_zone)
- return -ENOMEM;
-
- nf_ct_zone_init(nf_ct_zone, info->id, info->dir,
- info->flags);
-#endif
- return 0;
-}
-
-static inline bool nf_ct_zone_matches_dir(const struct nf_conntrack_zone *zone,
- enum ip_conntrack_dir dir)
-{
- return zone->dir & (1 << dir);
-}
-
-static inline u16 nf_ct_zone_id(const struct nf_conntrack_zone *zone,
- enum ip_conntrack_dir dir)
-{
- return nf_ct_zone_matches_dir(zone, dir) ?
- zone->id : NF_CT_DEFAULT_ZONE_ID;
-}
-
-static inline bool nf_ct_zone_equal(const struct nf_conn *a,
- const struct nf_conntrack_zone *b,
- enum ip_conntrack_dir dir)
-{
- return nf_ct_zone_id(nf_ct_zone(a), dir) ==
- nf_ct_zone_id(b, dir);
-}
-
-static inline bool nf_ct_zone_equal_any(const struct nf_conn *a,
- const struct nf_conntrack_zone *b)
-{
- return nf_ct_zone(a)->id == b->id;
-}
-#endif /* IS_ENABLED(CONFIG_NF_CONNTRACK) */
-#endif /* HAVE_NF_CT_ZONE_INIT */
-#endif /* _NF_CONNTRACK_ZONES_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netfilter/nf_nat.h b/datapath/linux/compat/include/net/netfilter/nf_nat.h
deleted file mode 100644
index 773e569cb..000000000
--- a/datapath/linux/compat/include/net/netfilter/nf_nat.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _NF_NAT_WRAPPER_H
-#define _NF_NAT_WRAPPER_H
-
-#include_next <net/netfilter/nf_nat.h>
-
-#ifndef HAVE_NF_CT_NAT_EXT_ADD
-
-static inline struct nf_conn_nat *
-nf_ct_nat_ext_add(struct nf_conn *ct)
-{
- struct nf_conn_nat *nat = nfct_nat(ct);
- if (nat)
- return nat;
-
- if (!nf_ct_is_confirmed(ct))
- nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
-
- return nat;
-}
-#endif /* HAVE_NF_CT_NAT_EXT_ADD */
-
-#ifndef HAVE_NF_NAT_ALLOC_NULL_BINDING
-static inline unsigned int
-nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
-{
- /* Force range to this IP; let proto decide mapping for
- * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
- * Use reply in case it's already been mangled (eg local packet).
- */
- union nf_inet_addr ip =
- (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
- struct nf_nat_range range = {
- .flags = NF_NAT_RANGE_MAP_IPS,
- .min_addr = ip,
- .max_addr = ip,
- };
- return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
-}
-
-#endif /* HAVE_NF_NAT_ALLOC_NULL_BINDING */
-
-#endif /* _NF_NAT_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/netlink.h b/datapath/linux/compat/include/net/netlink.h
deleted file mode 100644
index 84e073974..000000000
--- a/datapath/linux/compat/include/net/netlink.h
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef __NET_NETLINK_WRAPPER_H
-#define __NET_NETLINK_WRAPPER_H 1
-
-#include <linux/version.h>
-#include_next <net/netlink.h>
-#include_next <linux/in6.h>
-
-#ifndef HAVE_NLA_GET_BE16
-/**
- * nla_get_be16 - return payload of __be16 attribute
- * @nla: __be16 netlink attribute
- */
-static inline __be16 nla_get_be16(const struct nlattr *nla)
-{
- return *(__be16 *) nla_data(nla);
-}
-#endif /* !HAVE_NLA_GET_BE16 */
-
-#ifndef HAVE_NLA_PUT_BE16
-static inline int nla_put_be16(struct sk_buff *skb, int attrtype, __be16 value)
-{
- return nla_put(skb, attrtype, sizeof(__be16), &value);
-}
-#endif
-
-#ifndef HAVE_NLA_PUT_BE32
-static inline int nla_put_be32(struct sk_buff *skb, int attrtype, __be32 value)
-{
- return nla_put(skb, attrtype, sizeof(__be32), &value);
-}
-#endif
-
-#ifndef HAVE_NLA_PUT_BE64
-static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value)
-{
- return nla_put(skb, attrtype, sizeof(__be64), &value);
-}
-#endif
-
-#ifndef nla_for_each_nested
-#define nla_for_each_nested(pos, nla, rem) \
- nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem)
-#endif
-
-#ifndef HAVE_NLA_FIND_NESTED
-static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype)
-{
- return nla_find(nla_data(nla), nla_len(nla), attrtype);
-}
-#endif
-
-#ifndef HAVE_NLA_IS_LAST
-static inline bool nla_is_last(const struct nlattr *nla, int rem)
-{
- return nla->nla_len == rem;
-}
-#endif
-
-#ifndef HAVE_NLA_PUT_IN_ADDR
-static inline int nla_put_in_addr(struct sk_buff *skb, int attrtype,
- __be32 addr)
-{
- return nla_put_be32(skb, attrtype, addr);
-}
-
-static inline int nla_put_in6_addr(struct sk_buff *skb, int attrtype,
- const struct in6_addr *addr)
-{
- return nla_put(skb, attrtype, sizeof(*addr), addr);
-}
-
-static inline __be32 nla_get_in_addr(const struct nlattr *nla)
-{
- return *(__be32 *) nla_data(nla);
-}
-
-static inline struct in6_addr nla_get_in6_addr(const struct nlattr *nla)
-{
- struct in6_addr tmp;
-
- nla_memcpy(&tmp, nla, sizeof(tmp));
- return tmp;
-}
-#endif
-
-#ifndef HAVE_NLA_PUT_64BIT
-static inline bool nla_need_padding_for_64bit(struct sk_buff *skb)
-{
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- /* The nlattr header is 4 bytes in size, that's why we test
- * if the skb->data _is_ aligned. A NOP attribute, plus
- * nlattr header for next attribute, will make nla_data()
- * 8-byte aligned.
- */
- if (IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8))
- return true;
-#endif
- return false;
-}
-
-static inline int nla_align_64bit(struct sk_buff *skb, int padattr)
-{
- if (nla_need_padding_for_64bit(skb) &&
- !nla_reserve(skb, padattr, 0))
- return -EMSGSIZE;
-
- return 0;
-}
-
-static inline int nla_total_size_64bit(int payload)
-{
- return NLA_ALIGN(nla_attr_size(payload))
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- + NLA_ALIGN(nla_attr_size(0))
-#endif
- ;
-}
-
-#define nla_put_64bit rpl_nla_put_64bit
-int rpl_nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
- const void *data, int padattr);
-
-#define __nla_put_64bit rpl___nla_put_64bit
-void rpl___nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
- const void *data, int padattr);
-
-#define __nla_reserve_64bit rpl___nla_reserve_64bit
-struct nlattr *rpl___nla_reserve_64bit(struct sk_buff *skb, int attrtype,
- int attrlen, int padattr);
-
-static inline int nla_put_u64_64bit(struct sk_buff *skb, int attrtype,
- u64 value, int padattr)
-{
- return nla_put_64bit(skb, attrtype, sizeof(u64), &value, padattr);
-}
-
-#define nla_put_be64 rpl_nla_put_be64
-static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value,
- int padattr)
-{
- return nla_put_64bit(skb, attrtype, sizeof(__be64), &value, padattr);
-}
-
-#endif
-
-#ifndef HAVE_NLA_PARSE_DEPRECATED_STRICT
-#define nla_parse_nested_deprecated nla_parse_nested
-#define nla_parse_deprecated_strict nla_parse
-#define genlmsg_parse_deprecated genlmsg_parse
-
-#ifndef HAVE_NETLINK_EXT_ACK
-struct netlink_ext_ack;
-
-static inline int rpl_nla_parse_nested(struct nlattr *tb[], int maxtype,
- const struct nlattr *nla,
- const struct nla_policy *policy,
- struct netlink_ext_ack *extack)
-{
- return nla_parse_nested(tb, maxtype, nla, policy);
-}
-#undef nla_parse_nested_deprecated
-#define nla_parse_nested_deprecated rpl_nla_parse_nested
-
-static inline int rpl_nla_parse(struct nlattr **tb, int maxtype,
- const struct nlattr *head, int len,
- const struct nla_policy *policy,
- struct netlink_ext_ack *extack)
-{
- return nla_parse(tb, maxtype, head, len, policy);
-}
-#undef nla_parse_deprecated_strict
-#define nla_parse_deprecated_strict rpl_nla_parse
-#endif
-#endif /* HAVE_NLA_PARSE_DEPRECATED_STRICT */
-
-#ifndef HAVE_NLA_NEST_START_NOFLAG
-static inline struct nlattr *rpl_nla_nest_start_noflag(struct sk_buff *skb,
- int attrtype)
-{
- return nla_nest_start(skb, attrtype);
-}
-#define nla_nest_start_noflag rpl_nla_nest_start_noflag
-#endif
-
-#endif /* net/netlink.h */
diff --git a/datapath/linux/compat/include/net/nsh.h b/datapath/linux/compat/include/net/nsh.h
deleted file mode 100644
index 76894910c..000000000
--- a/datapath/linux/compat/include/net/nsh.h
+++ /dev/null
@@ -1,313 +0,0 @@
-#ifndef __NET_NSH_H
-#define __NET_NSH_H 1
-
-#include <linux/skbuff.h>
-
-/*
- * Network Service Header:
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |Ver|O|U| TTL | Length |U|U|U|U|MD Type| Next Protocol |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Service Path Identifier (SPI) | Service Index |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | |
- * ~ Mandatory/Optional Context Headers ~
- * | |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Version: The version field is used to ensure backward compatibility
- * going forward with future NSH specification updates. It MUST be set
- * to 0x0 by the sender, in this first revision of NSH. Given the
- * widespread implementation of existing hardware that uses the first
- * nibble after an MPLS label stack for ECMP decision processing, this
- * document reserves version 01b and this value MUST NOT be used in
- * future versions of the protocol. Please see [RFC7325] for further
- * discussion of MPLS-related forwarding requirements.
- *
- * O bit: Setting this bit indicates an Operations, Administration, and
- * Maintenance (OAM) packet. The actual format and processing of SFC
- * OAM packets is outside the scope of this specification (see for
- * example [I-D.ietf-sfc-oam-framework] for one approach).
- *
- * The O bit MUST be set for OAM packets and MUST NOT be set for non-OAM
- * packets. The O bit MUST NOT be modified along the SFP.
- *
- * SF/SFF/SFC Proxy/Classifier implementations that do not support SFC
- * OAM procedures SHOULD discard packets with O bit set, but MAY support
- * a configurable parameter to enable forwarding received SFC OAM
- * packets unmodified to the next element in the chain. Forwarding OAM
- * packets unmodified by SFC elements that do not support SFC OAM
- * procedures may be acceptable for a subset of OAM functions, but can
- * result in unexpected outcomes for others, thus it is recommended to
- * analyze the impact of forwarding an OAM packet for all OAM functions
- * prior to enabling this behavior. The configurable parameter MUST be
- * disabled by default.
- *
- * TTL: Indicates the maximum SFF hops for an SFP. This field is used
- * for service plane loop detection. The initial TTL value SHOULD be
- * configurable via the control plane; the configured initial value can
- * be specific to one or more SFPs. If no initial value is explicitly
- * provided, the default initial TTL value of 63 MUST be used. Each SFF
- * involved in forwarding an NSH packet MUST decrement the TTL value by
- * 1 prior to NSH forwarding lookup. Decrementing by 1 from an incoming
- * value of 0 shall result in a TTL value of 63. The packet MUST NOT be
- * forwarded if TTL is, after decrement, 0.
- *
- * All other flag fields, marked U, are unassigned and available for
- * future use, see Section 11.2.1. Unassigned bits MUST be set to zero
- * upon origination, and MUST be ignored and preserved unmodified by
- * other NSH supporting elements. Elements which do not understand the
- * meaning of any of these bits MUST NOT modify their actions based on
- * those unknown bits.
- *
- * Length: The total length, in 4-byte words, of NSH including the Base
- * Header, the Service Path Header, the Fixed Length Context Header or
- * Variable Length Context Header(s). The length MUST be 0x6 for MD
- * Type equal to 0x1, and MUST be 0x2 or greater for MD Type equal to
- * 0x2. The length of the NSH header MUST be an integer multiple of 4
- * bytes, thus variable length metadata is always padded out to a
- * multiple of 4 bytes.
- *
- * MD Type: Indicates the format of NSH beyond the mandatory Base Header
- * and the Service Path Header. MD Type defines the format of the
- * metadata being carried.
- *
- * 0x0 - This is a reserved value. Implementations SHOULD silently
- * discard packets with MD Type 0x0.
- *
- * 0x1 - This indicates that the format of the header includes a fixed
- * length Context Header (see Figure 4 below).
- *
- * 0x2 - This does not mandate any headers beyond the Base Header and
- * Service Path Header, but may contain optional variable length Context
- * Header(s). The semantics of the variable length Context Header(s)
- * are not defined in this document. The format of the optional
- * variable length Context Headers is provided in Section 2.5.1.
- *
- * 0xF - This value is reserved for experimentation and testing, as per
- * [RFC3692]. Implementations not explicitly configured to be part of
- * an experiment SHOULD silently discard packets with MD Type 0xF.
- *
- * Next Protocol: indicates the protocol type of the encapsulated data.
- * NSH does not alter the inner payload, and the semantics on the inner
- * protocol remain unchanged due to NSH service function chaining.
- * Please see the IANA Considerations section below, Section 11.2.5.
- *
- * This document defines the following Next Protocol values:
- *
- * 0x1: IPv4
- * 0x2: IPv6
- * 0x3: Ethernet
- * 0x4: NSH
- * 0x5: MPLS
- * 0xFE: Experiment 1
- * 0xFF: Experiment 2
- *
- * Packets with Next Protocol values not supported SHOULD be silently
- * dropped by default, although an implementation MAY provide a
- * configuration parameter to forward them. Additionally, an
- * implementation not explicitly configured for a specific experiment
- * [RFC3692] SHOULD silently drop packets with Next Protocol values 0xFE
- * and 0xFF.
- *
- * Service Path Identifier (SPI): Identifies a service path.
- * Participating nodes MUST use this identifier for Service Function
- * Path selection. The initial classifier MUST set the appropriate SPI
- * for a given classification result.
- *
- * Service Index (SI): Provides location within the SFP. The initial
- * classifier for a given SFP SHOULD set the SI to 255, however the
- * control plane MAY configure the initial value of SI as appropriate
- * (i.e., taking into account the length of the service function path).
- * The Service Index MUST be decremented by a value of 1 by Service
- * Functions or by SFC Proxy nodes after performing required services
- * and the new decremented SI value MUST be used in the egress packet's
- * NSH. The initial Classifier MUST send the packet to the first SFF in
- * the identified SFP for forwarding along an SFP. If re-classification
- * occurs, and that re-classification results in a new SPI, the
- * (re)classifier is, in effect, the initial classifier for the
- * resultant SPI.
- *
- * The SI is used in conjunction the with Service Path Identifier for
- * Service Function Path Selection and for determining the next SFF/SF
- * in the path. The SI is also valuable when troubleshooting or
- * reporting service paths. Additionally, while the TTL field is the
- * main mechanism for service plane loop detection, the SI can also be
- * used for detecting service plane loops.
- *
- * When the Base Header specifies MD Type = 0x1, a Fixed Length Context
- * Header (16-bytes) MUST be present immediately following the Service
- * Path Header. The value of a Fixed Length Context
- * Header that carries no metadata MUST be set to zero.
- *
- * When the base header specifies MD Type = 0x2, zero or more Variable
- * Length Context Headers MAY be added, immediately following the
- * Service Path Header (see Figure 5). Therefore, Length = 0x2,
- * indicates that only the Base Header followed by the Service Path
- * Header are present. The optional Variable Length Context Headers
- * MUST be of an integer number of 4-bytes. The base header Length
- * field MUST be used to determine the offset to locate the original
- * packet or frame for SFC nodes that require access to that
- * information.
- *
- * The format of the optional variable length Context Headers
- *
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Metadata Class | Type |U| Length |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Variable Metadata |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Metadata Class (MD Class): Defines the scope of the 'Type' field to
- * provide a hierarchical namespace. The IANA Considerations
- * Section 11.2.4 defines how the MD Class values can be allocated to
- * standards bodies, vendors, and others.
- *
- * Type: Indicates the explicit type of metadata being carried. The
- * definition of the Type is the responsibility of the MD Class owner.
- *
- * Unassigned bit: One unassigned bit is available for future use. This
- * bit MUST NOT be set, and MUST be ignored on receipt.
- *
- * Length: Indicates the length of the variable metadata, in bytes. In
- * case the metadata length is not an integer number of 4-byte words,
- * the sender MUST add pad bytes immediately following the last metadata
- * byte to extend the metadata to an integer number of 4-byte words.
- * The receiver MUST round up the length field to the nearest 4-byte
- * word boundary, to locate and process the next field in the packet.
- * The receiver MUST access only those bytes in the metadata indicated
- * by the length field (i.e., actual number of bytes) and MUST ignore
- * the remaining bytes up to the nearest 4-byte word boundary. The
- * Length may be 0 or greater.
- *
- * A value of 0 denotes a Context Header without a Variable Metadata
- * field.
- *
- * [0] https://datatracker.ietf.org/doc/draft-ietf-sfc-nsh/
- */
-
-/**
- * struct nsh_md1_ctx - Keeps track of NSH context data
- * @nshc<1-4>: NSH Contexts.
- */
-struct nsh_md1_ctx {
- __be32 context[4];
-};
-
-struct nsh_md2_tlv {
- __be16 md_class;
- u8 type;
- u8 length;
- u8 md_value[];
-};
-
-struct nshhdr {
- __be16 ver_flags_ttl_len;
- u8 mdtype;
- u8 np;
- __be32 path_hdr;
- union {
- struct nsh_md1_ctx md1;
- struct nsh_md2_tlv md2;
- };
-};
-
-/* Masking NSH header fields. */
-#define NSH_VER_MASK 0xc000
-#define NSH_VER_SHIFT 14
-#define NSH_FLAGS_MASK 0x3000
-#define NSH_FLAGS_SHIFT 12
-#define NSH_TTL_MASK 0x0fc0
-#define NSH_TTL_SHIFT 6
-#define NSH_LEN_MASK 0x003f
-#define NSH_LEN_SHIFT 0
-
-#define NSH_MDTYPE_MASK 0x0f
-#define NSH_MDTYPE_SHIFT 0
-
-#define NSH_SPI_MASK 0xffffff00
-#define NSH_SPI_SHIFT 8
-#define NSH_SI_MASK 0x000000ff
-#define NSH_SI_SHIFT 0
-
-/* MD Type Registry. */
-#define NSH_M_TYPE1 0x01
-#define NSH_M_TYPE2 0x02
-#define NSH_M_EXP1 0xFE
-#define NSH_M_EXP2 0xFF
-
-/* NSH Base Header Length */
-#define NSH_BASE_HDR_LEN 8
-
-/* NSH MD Type 1 header Length. */
-#define NSH_M_TYPE1_LEN 24
-
-/* NSH header maximum Length. */
-#define NSH_HDR_MAX_LEN 252
-
-/* NSH context headers maximum Length. */
-#define NSH_CTX_HDRS_MAX_LEN 244
-
-static inline struct nshhdr *nsh_hdr(struct sk_buff *skb)
-{
- return (struct nshhdr *)skb_network_header(skb);
-}
-
-static inline u16 nsh_hdr_len(const struct nshhdr *nsh)
-{
- return ((ntohs(nsh->ver_flags_ttl_len) & NSH_LEN_MASK)
- >> NSH_LEN_SHIFT) << 2;
-}
-
-static inline u8 nsh_get_ver(const struct nshhdr *nsh)
-{
- return (ntohs(nsh->ver_flags_ttl_len) & NSH_VER_MASK)
- >> NSH_VER_SHIFT;
-}
-
-static inline u8 nsh_get_flags(const struct nshhdr *nsh)
-{
- return (ntohs(nsh->ver_flags_ttl_len) & NSH_FLAGS_MASK)
- >> NSH_FLAGS_SHIFT;
-}
-
-static inline u8 nsh_get_ttl(const struct nshhdr *nsh)
-{
- return (ntohs(nsh->ver_flags_ttl_len) & NSH_TTL_MASK)
- >> NSH_TTL_SHIFT;
-}
-
-static inline void __nsh_set_xflag(struct nshhdr *nsh, u16 xflag, u16 xmask)
-{
- nsh->ver_flags_ttl_len
- = (nsh->ver_flags_ttl_len & ~htons(xmask)) | htons(xflag);
-}
-
-static inline void nsh_set_flags_and_ttl(struct nshhdr *nsh, u8 flags, u8 ttl)
-{
- __nsh_set_xflag(nsh, ((flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK) |
- ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK),
- NSH_FLAGS_MASK | NSH_TTL_MASK);
-}
-
-static inline void nsh_set_flags_ttl_len(struct nshhdr *nsh, u8 flags,
- u8 ttl, u8 len)
-{
- len = len >> 2;
- __nsh_set_xflag(nsh, ((flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK) |
- ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK) |
- ((len << NSH_LEN_SHIFT) & NSH_LEN_MASK),
- NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK);
-}
-
-int ovs_nsh_init(void);
-void ovs_nsh_cleanup(void);
-
-int ovs_nsh_push(struct sk_buff *skb, const struct nshhdr *pushed_nh);
-int ovs_nsh_pop(struct sk_buff *skb);
-
-#endif /* __NET_NSH_H */
diff --git a/datapath/linux/compat/include/net/protocol.h b/datapath/linux/compat/include/net/protocol.h
deleted file mode 100644
index 0247a26c7..000000000
--- a/datapath/linux/compat/include/net/protocol.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _NET_PROTOCOL_WRAPPER_H
-#define _NET_PROTOCOL_WRAPPER_H
-
-#include_next <net/protocol.h>
-
-#ifdef HAVE_UDP_OFFLOAD
-
-#ifndef HAVE_UDP_ADD_OFFLOAD_TAKES_NET
-#define udp_add_offload(net, prot) udp_add_offload(prot)
-#endif
-
-#else
-
-#define udp_add_offload(net, prot) 0
-#define udp_del_offload(prot) do {} while(0)
-
-#endif /* HAVE_UDP_OFFLOAD */
-
-#endif /* _NET_PROTOCOL_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/route.h b/datapath/linux/compat/include/net/route.h
deleted file mode 100644
index 9e4a1f18a..000000000
--- a/datapath/linux/compat/include/net/route.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __NET_ROUTE_H_WRAPPER
-#define __NET_ROUTE_H_WRAPPER
-
-#include_next <net/route.h>
-
-#endif
diff --git a/datapath/linux/compat/include/net/rtnetlink.h b/datapath/linux/compat/include/net/rtnetlink.h
deleted file mode 100644
index e026cab95..000000000
--- a/datapath/linux/compat/include/net/rtnetlink.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __NET_RTNETLINK_WRAPPER_H
-#define __NET_RTNETLINK_WRAPPER_H
-#include_next <net/rtnetlink.h>
-
-#define rtnl_delete_link rpl_rtnl_delete_link
-int rpl_rtnl_delete_link(struct net_device *dev);
-
-#ifndef HAVE_NAME_ASSIGN_TYPE
-#ifdef HAVE_RTNL_CREATE_LINK_SRC_NET
-static inline struct net_device *rpl_rtnl_create_link(struct net *net, const char *ifname,
- unsigned char name_assign_type,
- const struct rtnl_link_ops *ops,
- struct nlattr *tb[])
-{
- return rtnl_create_link(net, net, (char *)ifname, ops, tb);
-}
-
-#else
-static inline struct net_device *rpl_rtnl_create_link(struct net *net, const char *ifname,
- unsigned char name_assign_type,
- const struct rtnl_link_ops *ops,
- struct nlattr *tb[])
-{
- return rtnl_create_link(net, (char *)ifname, ops, tb);
-}
-#endif
-#else
-/* This function is only defined to avoid warning related to ifname. Some backported
- * function did not changed the name to const type. */
-static inline struct net_device *rpl_rtnl_create_link(struct net *net, const char *ifname,
- unsigned char name_assign_type,
- const struct rtnl_link_ops *ops,
- struct nlattr *tb[])
-{
-#ifdef HAVE_RTNL_CREATE_LINK_TAKES_EXTACK
- return rtnl_create_link(net, (char *) ifname, name_assign_type, ops, tb, NULL);
-#else
- return rtnl_create_link(net, (char *) ifname, name_assign_type, ops, tb);
-#endif
-}
-#endif
-
-#define rtnl_create_link rpl_rtnl_create_link
-#endif
diff --git a/datapath/linux/compat/include/net/sctp/checksum.h b/datapath/linux/compat/include/net/sctp/checksum.h
deleted file mode 100644
index 7832abce0..000000000
--- a/datapath/linux/compat/include/net/sctp/checksum.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __SCTP_CHECKSUM_WRAPPER_H
-#define __SCTP_CHECKSUM_WRAPPER_H 1
-
-#include_next <net/sctp/checksum.h>
-
-#ifndef HAVE_SCTP_COMPUTE_CKSUM
-static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
- unsigned int offset)
-{
- const struct sk_buff *iter;
-
- __u32 crc32 = sctp_start_cksum(skb->data + offset,
- skb_headlen(skb) - offset);
- skb_walk_frags(skb, iter)
- crc32 = sctp_update_cksum((__u8 *) iter->data,
- skb_headlen(iter), crc32);
-
- /* Open-code sctp_end_cksum() to avoid a sparse warning due to a bug in
- * sparse annotations in Linux fixed in 3.10 in commit eee1d5a14 (sctp:
- * Correct type and usage of sctp_end_cksum()). */
- return cpu_to_le32(~crc32);
-}
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/net/sock.h b/datapath/linux/compat/include/net/sock.h
deleted file mode 100644
index 2900704ec..000000000
--- a/datapath/linux/compat/include/net/sock.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __NET_SOCK_WRAPPER_H
-#define __NET_SOCK_WRAPPER_H 1
-
-#include_next <net/sock.h>
-
-#ifndef __sk_user_data
-#define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data)))
-
-#define rcu_dereference_sk_user_data(sk) rcu_dereference(__sk_user_data((sk)))
-#define rcu_assign_sk_user_data(sk, ptr) rcu_assign_pointer(__sk_user_data((sk)), ptr)
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/net/stt.h b/datapath/linux/compat/include/net/stt.h
deleted file mode 100644
index d2e63d163..000000000
--- a/datapath/linux/compat/include/net/stt.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef __NET_STT_H
-#define __NET_STT_H 1
-
-#include <linux/kconfig.h>
-#include <linux/errno.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) && IS_ENABLED(CONFIG_NETFILTER)
-#include <net/ip_tunnels.h>
-#define OVS_STT
-
-struct stthdr {
- __u8 version;
- __u8 flags;
- __u8 l4_offset;
- __u8 reserved;
- __be16 mss;
- __be16 vlan_tci;
- __be64 key;
-};
-
-/* Padding after the end of the tunnel headers to provide alignment
- * for inner packet IP header after 14 byte Ethernet header.
- */
-#define STT_ETH_PAD 2
-
-#define STT_BASE_HLEN (sizeof(struct stthdr) + STT_ETH_PAD)
-#define STT_HEADER_LEN (sizeof(struct tcphdr) + STT_BASE_HLEN)
-
-static inline struct stthdr *stt_hdr(const struct sk_buff *skb)
-{
- return (struct stthdr *)(skb_transport_header(skb) +
- sizeof(struct tcphdr));
-}
-
-struct net_device *ovs_stt_dev_create_fb(struct net *net, const char *name,
- u8 name_assign_type, u16 dst_port);
-
-netdev_tx_t ovs_stt_xmit(struct sk_buff *skb);
-
-int ovs_stt_init_module(void);
-
-void ovs_stt_cleanup_module(void);
-#else
-static inline int ovs_stt_init_module(void)
-{
- return 0;
-}
-
-static inline void ovs_stt_cleanup_module(void)
-{}
-
-static inline struct net_device *ovs_stt_dev_create_fb(struct net *net, const char *name,
- u8 name_assign_type, u16 dst_port)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-static inline netdev_tx_t ovs_stt_xmit(struct sk_buff *skb)
-{
- BUG();
- return NETDEV_TX_OK;
-}
-#endif
-
-#define stt_dev_create_fb ovs_stt_dev_create_fb
-#define stt_init_module ovs_stt_init_module
-#define stt_cleanup_module ovs_stt_cleanup_module
-
-#define stt_fill_metadata_dst ovs_stt_fill_metadata_dst
-int ovs_stt_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-
-#endif /*ifdef__NET_STT_H */
diff --git a/datapath/linux/compat/include/net/tun_proto.h b/datapath/linux/compat/include/net/tun_proto.h
deleted file mode 100644
index 2ea3deba4..000000000
--- a/datapath/linux/compat/include/net/tun_proto.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef __NET_TUN_PROTO_H
-#define __NET_TUN_PROTO_H
-
-#include <linux/kernel.h>
-
-/* One byte protocol values as defined by VXLAN-GPE and NSH. These will
- * hopefully get a shared IANA registry.
- */
-#define TUN_P_IPV4 0x01
-#define TUN_P_IPV6 0x02
-#define TUN_P_ETHERNET 0x03
-#define TUN_P_NSH 0x04
-#define TUN_P_MPLS_UC 0x05
-
-static inline __be16 tun_p_to_eth_p(u8 proto)
-{
- switch (proto) {
- case TUN_P_IPV4:
- return htons(ETH_P_IP);
- case TUN_P_IPV6:
- return htons(ETH_P_IPV6);
- case TUN_P_ETHERNET:
- return htons(ETH_P_TEB);
- case TUN_P_NSH:
- return htons(ETH_P_NSH);
- case TUN_P_MPLS_UC:
- return htons(ETH_P_MPLS_UC);
- }
- return 0;
-}
-
-static inline u8 tun_p_from_eth_p(__be16 proto)
-{
- switch (proto) {
- case htons(ETH_P_IP):
- return TUN_P_IPV4;
- case htons(ETH_P_IPV6):
- return TUN_P_IPV6;
- case htons(ETH_P_TEB):
- return TUN_P_ETHERNET;
- case htons(ETH_P_NSH):
- return TUN_P_NSH;
- case htons(ETH_P_MPLS_UC):
- return TUN_P_MPLS_UC;
- }
- return 0;
-}
-
-#endif
diff --git a/datapath/linux/compat/include/net/udp.h b/datapath/linux/compat/include/net/udp.h
deleted file mode 100644
index 447999218..000000000
--- a/datapath/linux/compat/include/net/udp.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __NET_UDP_WRAPPER_H
-#define __NET_UDP_WRAPPER_H 1
-
-#include <net/ip.h>
-
-#ifdef inet_get_local_port_range
-/* Earlier RHEL7 kernels backport udp_flow_src_port() using an older version of
- * inet_get_local_port_range(). */
-#undef inet_get_local_port_range
-#include_next <net/udp.h>
-#define inet_get_local_port_range rpl_inet_get_local_port_range
-#else
-#include_next <net/udp.h>
-#endif
-
-#ifndef HAVE_UDP_FLOW_SRC_PORT
-static inline __be16 rpl_udp_flow_src_port(struct net *net, struct sk_buff *skb,
- int min, int max, bool use_eth)
-{
- u32 hash;
-
- if (min >= max) {
- /* Use default range */
- inet_get_local_port_range(net, &min, &max);
- }
-
- hash = skb_get_hash(skb);
- if (unlikely(!hash) && use_eth) {
- /* Can't find a normal hash, caller has indicated an Ethernet
- * packet so use that to compute a hash.
- */
- hash = jhash(skb->data, 2 * ETH_ALEN,
- (__force u32) skb->protocol);
- }
-
- /* Since this is being sent on the wire obfuscate hash a bit
- * to minimize possbility that any useful information to an
- * attacker is leaked. Only upper 16 bits are relevant in the
- * computation for 16 bit port value.
- */
- hash ^= hash << 16;
-
- return htons((((u64) hash * (max - min)) >> 32) + min);
-}
-
-#define udp_flow_src_port rpl_udp_flow_src_port
-#endif
-
-#ifndef HAVE_UDP_V4_CHECK
-static inline __sum16 udp_v4_check(int len, __be32 saddr,
- __be32 daddr, __wsum base)
-{
- return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base);
-}
-#endif
-
-#ifndef USE_UPSTREAM_TUNNEL
-#define udp_set_csum rpl_udp_set_csum
-void rpl_udp_set_csum(bool nocheck, struct sk_buff *skb,
- __be32 saddr, __be32 daddr, int len);
-#endif
-#endif
diff --git a/datapath/linux/compat/include/net/udp_tunnel.h b/datapath/linux/compat/include/net/udp_tunnel.h
deleted file mode 100644
index 6e4063359..000000000
--- a/datapath/linux/compat/include/net/udp_tunnel.h
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef __NET_UDP_TUNNEL_WRAPPER_H
-#define __NET_UDP_TUNNEL_WRAPPER_H
-
-#include <linux/version.h>
-#include <linux/kconfig.h>
-
-#include <net/addrconf.h>
-#include <net/dst_metadata.h>
-#include <linux/netdev_features.h>
-
-#ifdef USE_UPSTREAM_TUNNEL
-#include_next <net/udp_tunnel.h>
-
-#else
-
-#include <net/addrconf.h>
-#include <net/ip_tunnels.h>
-#include <net/udp.h>
-
-struct udp_port_cfg {
- u8 family;
-
- /* Used only for kernel-created sockets */
- union {
- struct in_addr local_ip;
-#if IS_ENABLED(CONFIG_IPV6)
- struct in6_addr local_ip6;
-#endif
- };
-
- union {
- struct in_addr peer_ip;
-#if IS_ENABLED(CONFIG_IPV6)
- struct in6_addr peer_ip6;
-#endif
- };
-
- __be16 local_udp_port;
- __be16 peer_udp_port;
- unsigned int use_udp_checksums:1,
- use_udp6_tx_checksums:1,
- use_udp6_rx_checksums:1,
- ipv6_v6only:1;
-};
-
-#ifdef HAVE_NDO_UDP_TUNNEL_ADD
-enum udp_parsable_tunnel_type {
- UDP_TUNNEL_TYPE_VXLAN, /* RFC 7348 */
- UDP_TUNNEL_TYPE_GENEVE, /* draft-ietf-nvo3-geneve */
- UDP_TUNNEL_TYPE_VXLAN_GPE, /* draft-ietf-nvo3-vxlan-gpe */
-};
-
-struct udp_tunnel_info {
- unsigned short type;
- sa_family_t sa_family;
- __be16 port;
-};
-#endif
-
-#define udp_sock_create4 rpl_udp_sock_create4
-int rpl_udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
- struct socket **sockp);
-
-#define udp_sock_create6 rpl_udp_sock_create6
-#if IS_ENABLED(CONFIG_IPV6)
-int rpl_udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
- struct socket **sockp);
-#else
-static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
- struct socket **sockp)
-{
- return -EPFNOSUPPORT;
-}
-#endif
-
-#define udp_sock_create rpl_udp_sock_create
-static inline int udp_sock_create(struct net *net,
- struct udp_port_cfg *cfg,
- struct socket **sockp)
-{
- if (cfg->family == AF_INET)
- return udp_sock_create4(net, cfg, sockp);
-
- if (cfg->family == AF_INET6)
- return udp_sock_create6(net, cfg, sockp);
-
- return -EPFNOSUPPORT;
-}
-
-typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb);
-typedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk);
-typedef struct sk_buff **(*udp_tunnel_gro_receive_t)(struct sock *sk,
- struct sk_buff **head,
- struct sk_buff *skb);
-typedef int (*udp_tunnel_gro_complete_t)(struct sock *sk, struct sk_buff *skb,
- int nhoff);
-
-struct udp_tunnel_sock_cfg {
- void *sk_user_data; /* user data used by encap_rcv call back */
- /* Used for setting up udp_sock fields, see udp.h for details */
- __u8 encap_type;
- udp_tunnel_encap_rcv_t encap_rcv;
- udp_tunnel_encap_destroy_t encap_destroy;
-#ifdef HAVE_UDP_TUNNEL_SOCK_CFG_GRO_RECEIVE
- udp_tunnel_gro_receive_t gro_receive;
- udp_tunnel_gro_complete_t gro_complete;
-#endif
-};
-
-/* Setup the given (UDP) sock to receive UDP encapsulated packets */
-#define setup_udp_tunnel_sock rpl_setup_udp_tunnel_sock
-void rpl_setup_udp_tunnel_sock(struct net *net, struct socket *sock,
- struct udp_tunnel_sock_cfg *sock_cfg);
-
-/* Transmit the skb using UDP encapsulation. */
-#define udp_tunnel_xmit_skb rpl_udp_tunnel_xmit_skb
-void rpl_udp_tunnel_xmit_skb(struct rtable *rt,
- struct sock *sk, struct sk_buff *skb,
- __be32 src, __be32 dst, __u8 tos, __u8 ttl,
- __be16 df, __be16 src_port, __be16 dst_port,
- bool xnet, bool nocheck);
-
-
-#define udp_tunnel_sock_release rpl_udp_tunnel_sock_release
-void rpl_udp_tunnel_sock_release(struct socket *sock);
-
-#define udp_tunnel_encap_enable rpl_udp_tunnel_encap_enable
-static inline void udp_tunnel_encap_enable(struct socket *sock)
-{
-#if IS_ENABLED(CONFIG_IPV6)
- if (sock->sk->sk_family == PF_INET6)
-#ifdef HAVE_IPV6_STUB
- ipv6_stub->udpv6_encap_enable();
-#else
- udpv6_encap_enable();
-#endif
- else
-#endif
- udp_encap_enable();
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-#define udp_tunnel6_xmit_skb rpl_udp_tunnel6_xmit_skb
-int rpl_udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb,
- struct net_device *dev, struct in6_addr *saddr,
- struct in6_addr *daddr,
- __u8 prio, __u8 ttl, __be32 label, __be16 src_port,
- __be16 dst_port, bool nocheck);
-#endif
-
-static inline void udp_tunnel_gro_complete(struct sk_buff *skb, int nhoff)
-{
- struct udphdr *uh;
-
- uh = (struct udphdr *)(skb->data + nhoff - sizeof(struct udphdr));
- skb_shinfo(skb)->gso_type |= uh->check ?
- SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
-}
-
-void ovs_udp_gso(struct sk_buff *skb);
-void ovs_udp_csum_gso(struct sk_buff *skb);
-
-static inline int rpl_udp_tunnel_handle_offloads(struct sk_buff *skb,
- bool udp_csum)
-{
- void (*fix_segment)(struct sk_buff *);
- int type = 0;
-
- type |= udp_csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
-#ifndef USE_UPSTREAM_TUNNEL_GSO
- if (!udp_csum)
- fix_segment = ovs_udp_gso;
- else
- fix_segment = ovs_udp_csum_gso;
- /* This functuin is not used by vxlan lan tunnel. On older
- * udp offload only supports vxlan, therefore fallback to software
- * segmentation.
- */
- type = 0;
-#else
- fix_segment = NULL;
-#endif
-
- return ovs_iptunnel_handle_offloads(skb, type, fix_segment);
-}
-
-#define udp_tunnel_handle_offloads rpl_udp_tunnel_handle_offloads
-static inline void ovs_udp_tun_rx_dst(struct metadata_dst *md_dst,
- struct sk_buff *skb,
- unsigned short family,
- __be16 flags, __be64 tunnel_id, int md_size)
-{
- struct ip_tunnel_info *info = &md_dst->u.tun_info;
-
- if (family == AF_INET)
- ovs_ip_tun_rx_dst(md_dst, skb, flags, tunnel_id, md_size);
- else
- ovs_ipv6_tun_rx_dst(md_dst, skb, flags, tunnel_id, md_size);
-
- info->key.tp_src = udp_hdr(skb)->source;
- info->key.tp_dst = udp_hdr(skb)->dest;
- if (udp_hdr(skb)->check)
- info->key.tun_flags |= TUNNEL_CSUM;
-}
-#endif /* USE_UPSTREAM_TUNNEL */
-
-#endif
diff --git a/datapath/linux/compat/include/net/vrf.h b/datapath/linux/compat/include/net/vrf.h
deleted file mode 100644
index f5b6e8900..000000000
--- a/datapath/linux/compat/include/net/vrf.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * include/net/net_vrf.h - adds vrf dev structure definitions
- * Copyright (c) 2015 Cumulus Networks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __LINUX_NET_VRF_WRAPPER_H
-#define __LINUX_NET_VRF_WRAPPER_H
-
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)
-#include_next <net/vrf.h>
-#else
-
-static inline int vrf_master_ifindex_rcu(const struct net_device *dev)
-{
- return 0;
-}
-#endif
-
-#endif /* __LINUX_NET_VRF_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
deleted file mode 100644
index 18f5474d9..000000000
--- a/datapath/linux/compat/include/net/vxlan.h
+++ /dev/null
@@ -1,444 +0,0 @@
-#ifndef __NET_VXLAN_WRAPPER_H
-#define __NET_VXLAN_WRAPPER_H 1
-
-#ifdef CONFIG_INET
-#include <net/udp_tunnel.h>
-#endif
-
-#ifdef USE_UPSTREAM_TUNNEL
-#include_next <net/vxlan.h>
-
-static inline int rpl_vxlan_init_module(void)
-{
- return 0;
-}
-static inline void rpl_vxlan_cleanup_module(void)
-{}
-
-#define vxlan_xmit dev_queue_xmit
-
-#ifdef CONFIG_INET
-#ifndef HAVE_NAME_ASSIGN_TYPE
-static inline struct net_device *rpl_vxlan_dev_create(
- struct net *net, const char *name, u8 name_assign_type,
- struct vxlan_config *conf) {
- return vxlan_dev_create(net, name, conf);
-}
-#define vxlan_dev_create rpl_vxlan_dev_create
-#endif
-#endif
-
-#else /* USE_UPSTREAM_TUNNEL */
-
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_vlan.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/udp.h>
-#include <net/dst_cache.h>
-#include <net/dst_metadata.h>
-
-#include "compat.h"
-#include "gso.h"
-
-/* VXLAN protocol (RFC 7348) header:
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |R|R|R|R|I|R|R|R| Reserved |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | VXLAN Network Identifier (VNI) | Reserved |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * I = VXLAN Network Identifier (VNI) present.
- */
-struct vxlanhdr {
- __be32 vx_flags;
- __be32 vx_vni;
-};
-
-/* VXLAN header flags. */
-#define VXLAN_HF_VNI cpu_to_be32(BIT(27))
-
-#define VXLAN_N_VID (1u << 24)
-#define VXLAN_VID_MASK (VXLAN_N_VID - 1)
-#define VXLAN_VNI_MASK cpu_to_be32(VXLAN_VID_MASK << 8)
-#define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
-
-#define VNI_HASH_BITS 10
-#define VNI_HASH_SIZE (1<<VNI_HASH_BITS)
-#define FDB_HASH_BITS 8
-#define FDB_HASH_SIZE (1<<FDB_HASH_BITS)
-
-/* Remote checksum offload for VXLAN (VXLAN_F_REMCSUM_[RT]X):
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |R|R|R|R|I|R|R|R|R|R|C| Reserved |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | VXLAN Network Identifier (VNI) |O| Csum start |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * C = Remote checksum offload bit. When set indicates that the
- * remote checksum offload data is present.
- *
- * O = Offset bit. Indicates the checksum offset relative to
- * checksum start.
- *
- * Csum start = Checksum start divided by two.
- *
- * http://tools.ietf.org/html/draft-herbert-vxlan-rco
- */
-
-/* VXLAN-RCO header flags. */
-#define VXLAN_HF_RCO cpu_to_be32(BIT(21))
-
-/* Remote checksum offload header option */
-#define VXLAN_RCO_MASK cpu_to_be32(0x7f) /* Last byte of vni field */
-#define VXLAN_RCO_UDP cpu_to_be32(0x80) /* Indicate UDP RCO (TCP when not set *) */
-#define VXLAN_RCO_SHIFT 1 /* Left shift of start */
-#define VXLAN_RCO_SHIFT_MASK ((1 << VXLAN_RCO_SHIFT) - 1)
-#define VXLAN_MAX_REMCSUM_START (0x7f << VXLAN_RCO_SHIFT)
-
-/*
- * VXLAN Group Based Policy Extension (VXLAN_F_GBP):
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |G|R|R|R|I|R|R|R|R|D|R|R|A|R|R|R| Group Policy ID |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | VXLAN Network Identifier (VNI) | Reserved |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * G = Group Policy ID present.
- *
- * D = Don't Learn bit. When set, this bit indicates that the egress
- * VTEP MUST NOT learn the source address of the encapsulated frame.
- *
- * A = Indicates that the group policy has already been applied to
- * this packet. Policies MUST NOT be applied by devices when the
- * A bit is set.
- *
- * https://tools.ietf.org/html/draft-smith-vxlan-group-policy
- */
-struct vxlanhdr_gbp {
- u8 vx_flags;
-#ifdef __LITTLE_ENDIAN_BITFIELD
- u8 reserved_flags1:3,
- policy_applied:1,
- reserved_flags2:2,
- dont_learn:1,
- reserved_flags3:1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- u8 reserved_flags1:1,
- dont_learn:1,
- reserved_flags2:2,
- policy_applied:1,
- reserved_flags3:3;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- __be16 policy_id;
- __be32 vx_vni;
-};
-
-/* VXLAN-GBP header flags. */
-#define VXLAN_HF_GBP cpu_to_be32(BIT(31))
-
-#define VXLAN_GBP_USED_BITS (VXLAN_HF_GBP | cpu_to_be32(0xFFFFFF))
-
-/* skb->mark mapping
- *
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |R|R|R|R|R|R|R|R|R|D|R|R|A|R|R|R| Group Policy ID |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
-#define VXLAN_GBP_DONT_LEARN (BIT(6) << 16)
-#define VXLAN_GBP_POLICY_APPLIED (BIT(3) << 16)
-#define VXLAN_GBP_ID_MASK (0xFFFF)
-
-/*
- * VXLAN Generic Protocol Extension (VXLAN_F_GPE):
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |R|R|Ver|I|P|R|O| Reserved |Next Protocol |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | VXLAN Network Identifier (VNI) | Reserved |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Ver = Version. Indicates VXLAN GPE protocol version.
- *
- * P = Next Protocol Bit. The P bit is set to indicate that the
- * Next Protocol field is present.
- *
- * O = OAM Flag Bit. The O bit is set to indicate that the packet
- * is an OAM packet.
- *
- * Next Protocol = This 8 bit field indicates the protocol header
- * immediately following the VXLAN GPE header.
- *
- * https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe-01
- */
-
-struct vxlanhdr_gpe {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- u8 oam_flag:1,
- reserved_flags1:1,
- np_applied:1,
- instance_applied:1,
- version:2,
-reserved_flags2:2;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- u8 reserved_flags2:2,
- version:2,
- instance_applied:1,
- np_applied:1,
- reserved_flags1:1,
- oam_flag:1;
-#endif
- u8 reserved_flags3;
- u8 reserved_flags4;
- u8 next_protocol;
- __be32 vx_vni;
-};
-
-/* VXLAN-GPE header flags. */
-#define VXLAN_HF_VER cpu_to_be32(BIT(29) | BIT(28))
-#define VXLAN_HF_NP cpu_to_be32(BIT(26))
-#define VXLAN_HF_OAM cpu_to_be32(BIT(24))
-
-#define VXLAN_GPE_USED_BITS (VXLAN_HF_VER | VXLAN_HF_NP | VXLAN_HF_OAM | \
- cpu_to_be32(0xff))
-
-struct vxlan_metadata {
- u32 gbp;
-};
-
-/* per UDP socket information */
-struct vxlan_sock {
- struct hlist_node hlist;
- struct socket *sock;
- struct hlist_head vni_list[VNI_HASH_SIZE];
- atomic_t refcnt;
- u32 flags;
-#ifdef HAVE_UDP_OFFLOAD
- struct udp_offload udp_offloads;
-#endif
-};
-
-union vxlan_addr {
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
- struct sockaddr sa;
-};
-
-struct vxlan_rdst {
- union vxlan_addr remote_ip;
- __be16 remote_port;
- __be32 remote_vni;
- u32 remote_ifindex;
- struct list_head list;
- struct rcu_head rcu;
- struct dst_cache dst_cache;
-};
-
-struct vxlan_config {
- union vxlan_addr remote_ip;
- union vxlan_addr saddr;
- __be32 vni;
- int remote_ifindex;
- int mtu;
- __be16 dst_port;
- u16 port_min;
- u16 port_max;
- u8 tos;
- u8 ttl;
- __be32 label;
- u32 flags;
- unsigned long age_interval;
- unsigned int addrmax;
- bool no_share;
-};
-
-/* Pseudo network device */
-struct vxlan_dev {
- struct hlist_node hlist; /* vni hash table */
- struct list_head next; /* vxlan's per namespace list */
- struct vxlan_sock __rcu *vn4_sock; /* listening socket for IPv4 */
-#if IS_ENABLED(CONFIG_IPV6)
- struct vxlan_sock __rcu *vn6_sock; /* listening socket for IPv6 */
-#endif
- struct net_device *dev;
- struct net *net; /* netns for packet i/o */
- struct vxlan_rdst default_dst; /* default destination */
- u32 flags; /* VXLAN_F_* in vxlan.h */
-
- struct timer_list age_timer;
- spinlock_t hash_lock;
- unsigned int addrcnt;
-
- struct vxlan_config cfg;
-
- struct hlist_head fdb_head[FDB_HASH_SIZE];
-};
-
-#define VXLAN_F_LEARN 0x01
-#define VXLAN_F_PROXY 0x02
-#define VXLAN_F_RSC 0x04
-#define VXLAN_F_L2MISS 0x08
-#define VXLAN_F_L3MISS 0x10
-#define VXLAN_F_IPV6 0x20
-#define VXLAN_F_UDP_ZERO_CSUM_TX 0x40
-#define VXLAN_F_UDP_ZERO_CSUM6_TX 0x80
-#define VXLAN_F_UDP_ZERO_CSUM6_RX 0x100
-#define VXLAN_F_REMCSUM_TX 0x200
-#define VXLAN_F_REMCSUM_RX 0x400
-#define VXLAN_F_GBP 0x800
-#define VXLAN_F_REMCSUM_NOPARTIAL 0x1000
-#define VXLAN_F_COLLECT_METADATA 0x2000
-#define VXLAN_F_GPE 0x4000
-
-/* Flags that are used in the receive path. These flags must match in
- * order for a socket to be shareable
- */
-#define VXLAN_F_RCV_FLAGS (VXLAN_F_GBP | \
- VXLAN_F_GPE | \
- VXLAN_F_UDP_ZERO_CSUM6_RX | \
- VXLAN_F_REMCSUM_RX | \
- VXLAN_F_REMCSUM_NOPARTIAL | \
- VXLAN_F_COLLECT_METADATA)
-
-/* Flags that can be set together with VXLAN_F_GPE. */
-#define VXLAN_F_ALLOWED_GPE (VXLAN_F_GPE | \
- VXLAN_F_IPV6 | \
- VXLAN_F_UDP_ZERO_CSUM_TX | \
- VXLAN_F_UDP_ZERO_CSUM6_TX | \
- VXLAN_F_UDP_ZERO_CSUM6_RX | \
- VXLAN_F_COLLECT_METADATA)
-
-#define vxlan_dev_create rpl_vxlan_dev_create
-struct net_device *rpl_vxlan_dev_create(struct net *net, const char *name,
- u8 name_assign_type, struct vxlan_config *conf);
-
-static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
- netdev_features_t features)
-{
- u8 l4_hdr = 0;
-
- if (!skb->encapsulation)
- return features;
-
- switch (vlan_get_protocol(skb)) {
- case htons(ETH_P_IP):
- l4_hdr = ip_hdr(skb)->protocol;
- break;
- case htons(ETH_P_IPV6):
- l4_hdr = ipv6_hdr(skb)->nexthdr;
- break;
- default:
- return features;;
- }
-
- if ((l4_hdr == IPPROTO_UDP) && (
-#ifdef HAVE_INNER_PROTOCOL_TYPE
- skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
-#endif
-#ifdef HAVE_INNER_PROTOCOL
- skb->inner_protocol != htons(ETH_P_TEB) ||
-#endif
- (skb_inner_mac_header(skb) - skb_transport_header(skb) !=
- sizeof(struct udphdr) + sizeof(struct vxlanhdr)) ||
- (skb->ip_summed != CHECKSUM_NONE &&
- !can_checksum_protocol(features, inner_eth_hdr(skb)->h_proto))))
- return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
-
- return features;
-}
-
-/* IP header + UDP + VXLAN + Ethernet header */
-#define VXLAN_HEADROOM (20 + 8 + 8 + 14)
-/* IPv6 header + UDP + VXLAN + Ethernet header */
-#define VXLAN6_HEADROOM (40 + 8 + 8 + 14)
-
-static inline struct vxlanhdr *vxlan_hdr(struct sk_buff *skb)
-{
- return (struct vxlanhdr *)(udp_hdr(skb) + 1);
-}
-
-static inline __be32 vxlan_vni(__be32 vni_field)
-{
-#if defined(__BIG_ENDIAN)
- return (__force __be32)((__force u32)vni_field >> 8);
-#else
- return (__force __be32)((__force u32)(vni_field & VXLAN_VNI_MASK) << 8);
-#endif
-}
-
-static inline __be32 vxlan_vni_field(__be32 vni)
-{
-#if defined(__BIG_ENDIAN)
- return (__force __be32)((__force u32)vni << 8);
-#else
- return (__force __be32)((__force u32)vni >> 8);
-#endif
-}
-
-static inline __be32 vxlan_tun_id_to_vni(__be64 tun_id)
-{
-#if defined(__BIG_ENDIAN)
- return (__force __be32)tun_id;
-#else
- return (__force __be32)((__force u64)tun_id >> 32);
-#endif
-}
-
-static inline __be64 vxlan_vni_to_tun_id(__be32 vni)
-{
-#if defined(__BIG_ENDIAN)
- return (__force __be64)vni;
-#else
- return (__force __be64)((u64)(__force u32)vni << 32);
-#endif
-}
-
-static inline size_t vxlan_rco_start(__be32 vni_field)
-{
- return be32_to_cpu(vni_field & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
-}
-
-static inline size_t vxlan_rco_offset(__be32 vni_field)
-{
- return (vni_field & VXLAN_RCO_UDP) ?
- offsetof(struct udphdr, check) :
- offsetof(struct tcphdr, check);
-}
-
-static inline __be32 vxlan_compute_rco(unsigned int start, unsigned int offset)
-{
- __be32 vni_field = cpu_to_be32(start >> VXLAN_RCO_SHIFT);
-
- if (offset == offsetof(struct udphdr, check))
- vni_field |= VXLAN_RCO_UDP;
- return vni_field;
-}
-
-static inline void vxlan_get_rx_port(struct net_device *netdev)
-{
- ASSERT_RTNL();
- call_netdevice_notifiers(NETDEV_OFFLOAD_PUSH_VXLAN, netdev);
-}
-
-static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs)
-{
- return vs->sock->sk->sk_family;
-}
-
-int rpl_vxlan_init_module(void);
-void rpl_vxlan_cleanup_module(void);
-
-#define vxlan_fill_metadata_dst ovs_vxlan_fill_metadata_dst
-int ovs_vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-
-#define vxlan_xmit rpl_vxlan_xmit
-netdev_tx_t rpl_vxlan_xmit(struct sk_buff *skb);
-
-#endif /* USE_UPSTREAM_TUNNEL */
-
-#define vxlan_init_module rpl_vxlan_init_module
-#define vxlan_cleanup_module rpl_vxlan_cleanup_module
-
-#endif
diff --git a/datapath/linux/compat/include/uapi/linux/netfilter.h b/datapath/linux/compat/include/uapi/linux/netfilter.h
deleted file mode 100644
index 56895b17b..000000000
--- a/datapath/linux/compat/include/uapi/linux/netfilter.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _NETFILTER_WRAPPER_H
-#define _NETFILTER_WRAPPER_H
-
-#include_next <uapi/linux/netfilter.h>
-
-/*
- * NFPROTO_INET was introduced in net-next commit 1d49144c0aaa
- * ("netfilter: nf_tables: add "inet" table for IPv4/IPv6") in v3.14.
- * Define this symbol to support back to v3.10 kernel. */
-#ifndef HAVE_NFPROTO_INET
-#define NFPROTO_INET 1
-#endif
-
-#endif /* _NETFILTER_WRAPPER_H */
diff --git a/datapath/linux/compat/inet_fragment.c b/datapath/linux/compat/inet_fragment.c
deleted file mode 100644
index 21736e61a..000000000
--- a/datapath/linux/compat/inet_fragment.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * inet fragments management
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Authors: Pavel Emelyanov <xemul@openvz.org>
- * Started as consolidation of ipv4/ip_fragment.c,
- * ipv6/reassembly. and ipv6 nf conntrack reassembly
- */
-
-#ifndef HAVE_CORRECT_MRU_HANDLING
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-#include <net/inet_frag.h>
-#include <net/inet_ecn.h>
-
-
-#endif /* !HAVE_CORRECT_MRU_HANDLING */
diff --git a/datapath/linux/compat/ip6_gre.c b/datapath/linux/compat/ip6_gre.c
deleted file mode 100644
index 3aa9844b3..000000000
--- a/datapath/linux/compat/ip6_gre.c
+++ /dev/null
@@ -1,2746 +0,0 @@
-/*
- * GRE over IPv6 protocol decoder.
- *
- * Authors: Dmitry Kozlov (xeb@mail.ru)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#ifndef USE_UPSTREAM_TUNNEL
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include <linux/if_arp.h>
-#include <linux/init.h>
-#include <linux/in6.h>
-#include <linux/inetdevice.h>
-#include <linux/igmp.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/hash.h>
-#include <linux/if_tunnel.h>
-#include <linux/ip6_tunnel.h>
-
-#include <net/sock.h>
-#include <net/ip.h>
-#include <net/ip_tunnels.h>
-#include <net/icmp.h>
-#include <net/protocol.h>
-#include <net/addrconf.h>
-#include <net/arp.h>
-#include <net/checksum.h>
-#include <net/dsfield.h>
-#include <net/inet_ecn.h>
-#include <net/xfrm.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/rtnetlink.h>
-
-#include <net/ipv6.h>
-#include <net/ip6_fib.h>
-#include <net/ip6_route.h>
-#include <net/ip6_tunnel.h>
-#include <net/gre.h>
-#include <net/erspan.h>
-#include <net/dst_metadata.h>
-
-#include "vport-netdev.h"
-
-#define IP6_GRE_HASH_SIZE_SHIFT 5
-#define IP6_GRE_HASH_SIZE (1 << IP6_GRE_HASH_SIZE_SHIFT)
-
-static unsigned int ip6gre_net_id __read_mostly;
-static bool ip6_gre_loaded = false;
-struct ip6gre_net {
- struct ip6_tnl __rcu *tunnels[4][IP6_GRE_HASH_SIZE];
-
- struct ip6_tnl __rcu *collect_md_tun;
- struct ip6_tnl __rcu *collect_md_tun_erspan;
- struct net_device *fb_tunnel_dev;
-};
-
-static struct rtnl_link_ops ip6gre_link_ops __read_mostly;
-static struct rtnl_link_ops ip6gre_tap_ops __read_mostly;
-static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly;
-static int ip6gre_tunnel_init(struct net_device *dev);
-static void ip6gre_tunnel_setup(struct net_device *dev);
-static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t);
-static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu);
-static void ip6erspan_tnl_link_config(struct ip6_tnl *t, int set_mtu);
-
-/* Tunnel hash table */
-
-/*
- 4 hash tables:
-
- 3: (remote,local)
- 2: (remote,*)
- 1: (*,local)
- 0: (*,*)
-
- We require exact key match i.e. if a key is present in packet
- it will match only tunnel with the same key; if it is not present,
- it will match only keyless tunnel.
-
- All keysless packets, if not matched configured keyless tunnels
- will match fallback tunnel.
- */
-
-#define HASH_KEY(key) (((__force u32)key^((__force u32)key>>4))&(IP6_GRE_HASH_SIZE - 1))
-static u32 HASH_ADDR(const struct in6_addr *addr)
-{
- u32 hash = ipv6_addr_hash(addr);
-
- return hash_32(hash, IP6_GRE_HASH_SIZE_SHIFT);
-}
-
-#define tunnels_r_l tunnels[3]
-#define tunnels_r tunnels[2]
-#define tunnels_l tunnels[1]
-#define tunnels_wc tunnels[0]
-
-/* Given src, dst and key, find appropriate for input tunnel. */
-
-static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
- const struct in6_addr *remote, const struct in6_addr *local,
- __be32 key, __be16 gre_proto)
-{
- struct net *net = dev_net(dev);
- int link = dev->ifindex;
- unsigned int h0 = HASH_ADDR(remote);
- unsigned int h1 = HASH_KEY(key);
- struct ip6_tnl *t, *cand = NULL;
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
- int dev_type = (gre_proto == htons(ETH_P_TEB) ||
- gre_proto == htons(ETH_P_ERSPAN) ||
- gre_proto == htons(ETH_P_ERSPAN2)) ?
- ARPHRD_ETHER : ARPHRD_IP6GRE;
- int score, cand_score = 4;
-
- for_each_ip_tunnel_rcu(t, ign->tunnels_r_l[h0 ^ h1]) {
- if (!ipv6_addr_equal(local, &t->parms.laddr) ||
- !ipv6_addr_equal(remote, &t->parms.raddr) ||
- key != t->parms.i_key ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (t->dev->type != ARPHRD_IP6GRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
-
- for_each_ip_tunnel_rcu(t, ign->tunnels_r[h0 ^ h1]) {
- if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
- key != t->parms.i_key ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (t->dev->type != ARPHRD_IP6GRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
-
- for_each_ip_tunnel_rcu(t, ign->tunnels_l[h1]) {
- if ((!ipv6_addr_equal(local, &t->parms.laddr) &&
- (!ipv6_addr_equal(local, &t->parms.raddr) ||
- !ipv6_addr_is_multicast(local))) ||
- key != t->parms.i_key ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (t->dev->type != ARPHRD_IP6GRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
-
- for_each_ip_tunnel_rcu(t, ign->tunnels_wc[h1]) {
- if (t->parms.i_key != key ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (t->dev->type != ARPHRD_IP6GRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
-
- if (cand)
- return cand;
-
- if (gre_proto == htons(ETH_P_ERSPAN) ||
- gre_proto == htons(ETH_P_ERSPAN2))
- t = rcu_dereference(ign->collect_md_tun_erspan);
- else
- t = rcu_dereference(ign->collect_md_tun);
-
- if (t && t->dev->flags & IFF_UP)
- return t;
-
- dev = ign->fb_tunnel_dev;
- if (dev->flags & IFF_UP)
- return netdev_priv(dev);
-
- return NULL;
-}
-
-static struct ip6_tnl __rcu **__ip6gre_bucket(struct ip6gre_net *ign,
- const struct __ip6_tnl_parm *p)
-{
- const struct in6_addr *remote = &p->raddr;
- const struct in6_addr *local = &p->laddr;
- unsigned int h = HASH_KEY(p->i_key);
- int prio = 0;
-
- if (!ipv6_addr_any(local))
- prio |= 1;
- if (!ipv6_addr_any(remote) && !ipv6_addr_is_multicast(remote)) {
- prio |= 2;
- h ^= HASH_ADDR(remote);
- }
-
- return &ign->tunnels[prio][h];
-}
-
-static void ip6gre_tunnel_link_md(struct ip6gre_net *ign, struct ip6_tnl *t)
-{
- if (t->parms.collect_md)
- rcu_assign_pointer(ign->collect_md_tun, t);
-}
-
-static void ip6erspan_tunnel_link_md(struct ip6gre_net *ign, struct ip6_tnl *t)
-{
- if (t->parms.collect_md)
- rcu_assign_pointer(ign->collect_md_tun_erspan, t);
-}
-
-static void ip6gre_tunnel_unlink_md(struct ip6gre_net *ign, struct ip6_tnl *t)
-{
- if (t->parms.collect_md)
- rcu_assign_pointer(ign->collect_md_tun, NULL);
-}
-
-static void ip6erspan_tunnel_unlink_md(struct ip6gre_net *ign,
- struct ip6_tnl *t)
-{
- if (t->parms.collect_md)
- rcu_assign_pointer(ign->collect_md_tun_erspan, NULL);
-}
-
-static inline struct ip6_tnl __rcu **ip6gre_bucket(struct ip6gre_net *ign,
- const struct ip6_tnl *t)
-{
- return __ip6gre_bucket(ign, &t->parms);
-}
-
-static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t)
-{
- struct ip6_tnl __rcu **tp = ip6gre_bucket(ign, t);
-
- rcu_assign_pointer(t->next, rtnl_dereference(*tp));
- rcu_assign_pointer(*tp, t);
-}
-
-static void ip6gre_tunnel_unlink(struct ip6gre_net *ign, struct ip6_tnl *t)
-{
- struct ip6_tnl __rcu **tp;
- struct ip6_tnl *iter;
-
- for (tp = ip6gre_bucket(ign, t);
- (iter = rtnl_dereference(*tp)) != NULL;
- tp = &iter->next) {
- if (t == iter) {
- rcu_assign_pointer(*tp, t->next);
- break;
- }
- }
-}
-
-static struct ip6_tnl *ip6gre_tunnel_find(struct net *net,
- const struct __ip6_tnl_parm *parms,
- int type)
-{
- const struct in6_addr *remote = &parms->raddr;
- const struct in6_addr *local = &parms->laddr;
- __be32 key = parms->i_key;
- int link = parms->link;
- struct ip6_tnl *t;
- struct ip6_tnl __rcu **tp;
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
-
- for (tp = __ip6gre_bucket(ign, parms);
- (t = rtnl_dereference(*tp)) != NULL;
- tp = &t->next)
- if (ipv6_addr_equal(local, &t->parms.laddr) &&
- ipv6_addr_equal(remote, &t->parms.raddr) &&
- key == t->parms.i_key &&
- link == t->parms.link &&
- type == t->dev->type)
- break;
-
- return t;
-}
-
-static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net,
- const struct __ip6_tnl_parm *parms, int create)
-{
- struct ip6_tnl *t, *nt;
- struct net_device *dev;
- char name[IFNAMSIZ];
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
-
- t = ip6gre_tunnel_find(net, parms, ARPHRD_IP6GRE);
- if (t && create)
- return NULL;
- if (t || !create)
- return t;
-
- if (parms->name[0])
- strlcpy(name, parms->name, IFNAMSIZ);
- else
- strlcpy(name, "ovs-ip6gre%d", IFNAMSIZ);
-
- dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
- ip6gre_tunnel_setup);
- if (!dev)
- return NULL;
-
- dev_net_set(dev, net);
-
- nt = netdev_priv(dev);
- nt->parms = *parms;
- dev->rtnl_link_ops = &ip6gre_link_ops;
-
- nt->dev = dev;
- nt->net = dev_net(dev);
-
- if (register_netdevice(dev) < 0)
- goto failed_free;
-
- ip6gre_tnl_link_config(nt, 1);
-
- /* Can use a lockless transmit, unless we generate output sequences */
- if (!(nt->parms.o_flags & TUNNEL_SEQ))
- dev->features |= NETIF_F_LLTX;
-
- dev_hold(dev);
- ip6gre_tunnel_link(ign, nt);
- return nt;
-
-failed_free:
- free_netdev(dev);
- return NULL;
-}
-
-static void ip6erspan_tunnel_uninit(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
-
- ip6erspan_tunnel_unlink_md(ign, t);
- ip6gre_tunnel_unlink(ign, t);
- dst_cache_reset(&t->dst_cache);
- dev_put(dev);
-}
-
-static void ip6gre_tunnel_uninit(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
-
- ip6gre_tunnel_unlink_md(ign, t);
- ip6gre_tunnel_unlink(ign, t);
- dst_cache_reset(&t->dst_cache);
- dev_put(dev);
-}
-
-
-static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
- u8 type, u8 code, int offset, __be32 info)
-{
-#if 0
- struct net *net = dev_net(skb->dev);
- const struct gre_base_hdr *greh;
- const struct ipv6hdr *ipv6h;
- int grehlen = sizeof(*greh);
- struct ip6_tnl *t;
- int key_off = 0;
- __be16 flags;
- __be32 key;
-
- if (!pskb_may_pull(skb, offset + grehlen))
- return;
- greh = (const struct gre_base_hdr *)(skb->data + offset);
- flags = greh->flags;
- if (flags & (GRE_VERSION | GRE_ROUTING))
- return;
- if (flags & GRE_CSUM)
- grehlen += 4;
- if (flags & GRE_KEY) {
- key_off = grehlen + offset;
- grehlen += 4;
- }
-
- if (!pskb_may_pull(skb, offset + grehlen))
- return;
- ipv6h = (const struct ipv6hdr *)skb->data;
- greh = (const struct gre_base_hdr *)(skb->data + offset);
- key = key_off ? *(__be32 *)(skb->data + key_off) : 0;
-
- t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
- key, greh->protocol);
- if (!t)
- return;
-
- switch (type) {
- struct ipv6_tlv_tnl_enc_lim *tel;
- __u32 teli;
- case ICMPV6_DEST_UNREACH:
- net_dbg_ratelimited("%s: Path to destination invalid or inactive!\n",
- t->parms.name);
- if (code != ICMPV6_PORT_UNREACH)
- break;
- return;
- case ICMPV6_TIME_EXCEED:
- if (code == ICMPV6_EXC_HOPLIMIT) {
- net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n",
- t->parms.name);
- break;
- }
- return;
- case ICMPV6_PARAMPROB:
- teli = 0;
- if (code == ICMPV6_HDR_FIELD)
- teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
-
- if (teli && teli == be32_to_cpu(info) - 2) {
- tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
- if (tel->encap_limit == 0) {
- net_dbg_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n",
- t->parms.name);
- }
- } else {
- net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!\n",
- t->parms.name);
- }
- return;
- case ICMPV6_PKT_TOOBIG:
- ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
- return;
- case NDISC_REDIRECT:
- ip6_redirect(skb, net, skb->dev->ifindex, 0,
- sock_net_uid(net, NULL));
- return;
- }
-
- if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO))
- t->err_count++;
- else
- t->err_count = 1;
- t->err_time = jiffies;
-#endif
-}
-
-static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
-{
- const struct ipv6hdr *ipv6h;
- struct ip6_tnl *tunnel;
-
- ipv6h = ipv6_hdr(skb);
- tunnel = ip6gre_tunnel_lookup(skb->dev,
- &ipv6h->saddr, &ipv6h->daddr, tpi->key,
- tpi->proto);
- if (tunnel) {
- struct metadata_dst *tun_dst = NULL;
- if (tunnel->parms.collect_md) {
- __be64 tun_id;
- __be16 flags;
-
- flags = tpi->flags;
- tun_id = key32_to_tunnel_id(tpi->key);
-
- tun_dst = rpl_ipv6_tun_rx_dst(skb, flags, tun_id, 0);
- if (!tun_dst)
- return PACKET_REJECT;
-
- }
-
- ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, false);
- kfree(tun_dst);
- return PACKET_RCVD;
- }
-
- return PACKET_RCVD;
-}
-
-static int ip6erspan_rcv(struct sk_buff *skb,
- struct tnl_ptk_info *tpi,
- int gre_hdr_len)
-{
- struct erspan_base_hdr *ershdr;
- const struct ipv6hdr *ipv6h;
- struct erspan_md2 *md2;
- struct ip6_tnl *tunnel;
- u8 ver;
-
- if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr))))
- return PACKET_REJECT;
-
- ipv6h = ipv6_hdr(skb);
- ershdr = (struct erspan_base_hdr *)skb->data;
- ver = ershdr->ver;
- tpi->key = cpu_to_be32(get_session_id(ershdr));
-
- tunnel = ip6gre_tunnel_lookup(skb->dev,
- &ipv6h->saddr, &ipv6h->daddr, 0,
- tpi->proto);
- if (tunnel) {
- struct metadata_dst *tun_dst = NULL;
- int len = erspan_hdr_len(ver);
-
- if (unlikely(!pskb_may_pull(skb, len)))
- return PACKET_REJECT;
-
- if (__iptunnel_pull_header(skb, len,
- htons(ETH_P_TEB),
- false, false) < 0)
- return PACKET_REJECT;
-
- if (tunnel->parms.collect_md) {
- struct erspan_metadata *pkt_md, *md;
- struct ip_tunnel_info *info;
- unsigned char *gh;
- __be64 tun_id;
- __be16 flags;
-
- tpi->flags |= TUNNEL_KEY;
- flags = tpi->flags;
- tun_id = key32_to_tunnel_id(tpi->key);
-
- tun_dst = rpl_ipv6_tun_rx_dst(skb, flags, tun_id,
- sizeof(*md));
- if (!tun_dst)
- return PACKET_REJECT;
-
- /* skb can be uncloned in __iptunnel_pull_header, so
- * old pkt_md is no longer valid and we need to reset
- * it
- */
- gh = skb_network_header(skb) +
- skb_network_header_len(skb);
- pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
- sizeof(*ershdr));
- info = &tun_dst->u.tun_info;
- md = ip_tunnel_info_opts(info);
- md->version = ver;
- md2 = &md->u.md2;
- memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
- ERSPAN_V2_MDSIZE);
- info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
- info->options_len = sizeof(*md);
- }
-
- ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, false);
- kfree(tun_dst);
- return PACKET_RCVD;
- }
-
- kfree(skb);
- return PACKET_RCVD;
-}
-
-static int gre_rcv(struct sk_buff *skb)
-{
- struct tnl_ptk_info tpi;
- bool csum_err = false;
- int hdr_len;
-
- hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IPV6), 0);
- if (hdr_len < 0)
- goto drop;
-
- if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
- goto drop;
-
- if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
- tpi.proto == htons(ETH_P_ERSPAN2))) {
- if (ip6erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
- return 0;
- goto out;
- }
-
- if (ip6gre_rcv(skb, &tpi) == PACKET_RCVD)
- return 0;
-
-out:
- icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
-drop:
- kfree_skb(skb);
- return 0;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
-#include "gso.h"
-/* gre_handle_offloads() has different return type on older kernsl. */
-static void gre_nop_fix(struct sk_buff *skb) { }
-
-static void gre_csum_fix(struct sk_buff *skb)
-{
- struct gre_base_hdr *greh;
- __be32 *options;
- int gre_offset = skb_transport_offset(skb);
-
- greh = (struct gre_base_hdr *)skb_transport_header(skb);
- options = ((__be32 *)greh + 1);
-
- *options = 0;
- *(__sum16 *)options = csum_fold(skb_checksum(skb, gre_offset,
- skb->len - gre_offset, 0));
-}
-
-#define gre_handle_offloads rpl_gre_handle_offloads
-static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
-{
- int type = gre_csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE;
- gso_fix_segment_t fix_segment;
-
- if (gre_csum)
- fix_segment = gre_csum_fix;
- else
- fix_segment = gre_nop_fix;
-
- return ovs_iptunnel_handle_offloads(skb, type, fix_segment);
-}
-#else
-static int gre_handle_offloads(struct sk_buff *skb, bool csum)
-{
- return iptunnel_handle_offloads(skb, csum,
- csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
-}
-#endif
-
-static void prepare_ip6gre_xmit_ipv4(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi6 *fl6, __u8 *dsfield,
- int *encap_limit)
-{
- const struct iphdr *iph = ip_hdr(skb);
- struct ip6_tnl *t = netdev_priv(dev);
-
- if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- *encap_limit = t->parms.encap_limit;
-
- memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6));
-
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- *dsfield = ipv4_get_dsfield(iph);
- else
- *dsfield = ip6_tclass(t->parms.flowinfo);
-
-#ifndef IP6_TNL_F_USE_ORIG_FWMARK
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
- fl6->flowi6_mark = skb->mark;
- else
- fl6->flowi6_mark = t->parms.fwmark;
-
- fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
-#endif
-}
-
-static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi6 *fl6, __u8 *dsfield,
- int *encap_limit)
-{
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- struct ip6_tnl *t = netdev_priv(dev);
- __u16 offset;
-
- offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
- /* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
-
- if (offset > 0) {
- struct ipv6_tlv_tnl_enc_lim *tel;
-
- tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
- if (tel->encap_limit == 0) {
- icmpv6_send(skb, ICMPV6_PARAMPROB,
- ICMPV6_HDR_FIELD, offset + 2);
- return -1;
- }
- *encap_limit = tel->encap_limit - 1;
- } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
- *encap_limit = t->parms.encap_limit;
- }
-
- memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6));
-
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- *dsfield = ipv6_get_dsfield(ipv6h);
- else
- *dsfield = ip6_tclass(t->parms.flowinfo);
-
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
- fl6->flowlabel |= ip6_flowlabel(ipv6h);
-
-#ifndef IP6_TNL_F_USE_ORIG_FWMARK
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
- fl6->flowi6_mark = skb->mark;
- else
- fl6->flowi6_mark = t->parms.fwmark;
-
- fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
-#endif
-
- return 0;
-}
-
-static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
- struct net_device *dev, __u8 dsfield,
- struct flowi6 *fl6, int encap_limit,
- __u32 *pmtu, __be16 proto)
-{
- struct ip6_tnl *tunnel = netdev_priv(dev);
- struct tnl_ptk_info tpi;
- __be16 protocol;
-
- if (dev->header_ops && dev->type == ARPHRD_IP6GRE)
- fl6->daddr = ((struct ipv6hdr *)skb->data)->daddr;
- else
- fl6->daddr = tunnel->parms.raddr;
-
- if (tunnel->parms.o_flags & TUNNEL_SEQ)
- tunnel->o_seqno++;
-
- if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen))
- return -ENOMEM;
-
- /* Push GRE header. */
- protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
-
- if (tunnel->parms.collect_md) {
- struct ip_tunnel_info *tun_info;
- const struct ip_tunnel_key *key;
- __be16 flags;
-
- tun_info = skb_tunnel_info(skb);
- if (unlikely(!tun_info ||
- !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
- ip_tunnel_info_af(tun_info) != AF_INET6))
- return -EINVAL;
-
- key = &tun_info->key;
- memset(fl6, 0, sizeof(*fl6));
- fl6->flowi6_proto = IPPROTO_GRE;
- fl6->daddr = key->u.ipv6.dst;
- fl6->flowlabel = key->label;
-// FIX ME!
-// fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
-
- dsfield = key->tos;
- flags = key->tun_flags & (TUNNEL_CSUM | TUNNEL_KEY);
- tunnel->tun_hlen = gre_calc_hlen(flags);
-
- tpi.flags = flags;
- tpi.proto = protocol;
- tpi.key = tunnel_id_to_key32(key->tun_id);
- tpi.seq = htonl(tunnel->o_seqno++);
- tpi.hdr_len = tunnel->tun_hlen;
-
- gre_build_header(skb, &tpi, 8);
- } else {
- tpi.flags = tunnel->parms.o_flags;
- tpi.proto = protocol;
- tpi.key = tunnel->parms.o_key;
- tpi.seq = htonl(tunnel->o_seqno++);
- tpi.hdr_len = tunnel->tun_hlen;
-
- gre_build_header(skb, &tpi, 8);
- }
-
- return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu,
- NEXTHDR_GRE);
-}
-
-static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- int encap_limit = -1;
- struct flowi6 fl6;
- __u8 dsfield = 0;
- __u32 mtu;
- int err;
-
- memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
-
- if (!t->parms.collect_md)
- prepare_ip6gre_xmit_ipv4(skb, dev, &fl6,
- &dsfield, &encap_limit);
-
- err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
- if (err)
- return -1;
-
- err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
- skb->protocol);
- if (err != 0) {
- /* XXX: send ICMP error even if DF is not set. */
- if (err == -EMSGSIZE)
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
- htonl(mtu));
- return -1;
- }
-
- return 0;
-}
-
-static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- int encap_limit = -1;
- struct flowi6 fl6;
- __u8 dsfield = 0;
- __u32 mtu;
- int err;
-
- if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr))
- return -1;
-
- if (!t->parms.collect_md &&
- prepare_ip6gre_xmit_ipv6(skb, dev, &fl6, &dsfield, &encap_limit))
- return -1;
-
- if (gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)))
- return -1;
-
- err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit,
- &mtu, skb->protocol);
- if (err != 0) {
- if (err == -EMSGSIZE)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
- * @t: the outgoing tunnel device
- * @hdr: IPv6 header from the incoming packet
- *
- * Description:
- * Avoid trivial tunneling loop by checking that tunnel exit-point
- * doesn't match source of incoming packet.
- *
- * Return:
- * 1 if conflict,
- * 0 else
- **/
-
-static inline bool ip6gre_tnl_addr_conflict(const struct ip6_tnl *t,
- const struct ipv6hdr *hdr)
-{
- return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
-}
-
-static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- int encap_limit = -1;
- struct flowi6 fl6;
- __u32 mtu;
- int err;
-
- if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- encap_limit = t->parms.encap_limit;
-
- if (!t->parms.collect_md)
- memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
-
- err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
- if (err)
- return err;
-
- err = __gre6_xmit(skb, dev, 0, &fl6, encap_limit, &mtu, skb->protocol);
-
- return err;
-}
-
-static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct net_device_stats *stats = &t->dev->stats;
- int ret;
-
- if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
- goto tx_err;
-
- switch (skb->protocol) {
- case htons(ETH_P_IP):
- ret = ip6gre_xmit_ipv4(skb, dev);
- break;
- case htons(ETH_P_IPV6):
- ret = ip6gre_xmit_ipv6(skb, dev);
- break;
- default:
- ret = ip6gre_xmit_other(skb, dev);
- break;
- }
-
- if (ret < 0)
- goto tx_err;
-
- return NETDEV_TX_OK;
-
-tx_err:
- stats->tx_errors++;
- stats->tx_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static netdev_tx_t __ip6gre_tunnel_xmit(struct sk_buff *skb)
-{
- return ip6gre_tunnel_xmit(skb, skb->dev);
-}
-
-static bool erspan_skb_would_panic(struct sk_buff *skb, int erspan_md_size)
-{
- /* check if there is enough headroom in packet, if not
- * drop it. Checking for 8 bytes of gre header space +
- * erspan base hdr and erspan type specific header.
- */
- if (skb_headroom(skb) < (8 + sizeof(struct erspan_base_hdr) +
- erspan_md_size))
- return true;
-
- return false;
-}
-
-static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct dst_entry *dst = skb_dst(skb);
- struct ip_tunnel_info *tun_info;
- const struct ip_tunnel_key *key;
- struct net_device_stats *stats;
- struct erspan_metadata *md;
- struct tnl_ptk_info tpi;
- bool truncate = false;
- int encap_limit = -1;
- __u8 dsfield = false;
- struct flowi6 fl6;
- int err = -EINVAL;
- __be32 tun_id;
- __u32 mtu;
- int nhoff;
- int thoff;
-
-
- /* OVS doesn't support native mode ip6 tunnel traffic so
- * take an early exit in that case. */
- if (!t->parms.collect_md)
- goto tx_err;
-
- if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
- goto tx_err;
-
- if (gre_handle_offloads(skb, false))
- goto tx_err;
-
- if (skb->len > dev->mtu + dev->hard_header_len) {
- pskb_trim(skb, dev->mtu + dev->hard_header_len);
- truncate = true;
- }
-
- nhoff = skb_network_header(skb) - skb_mac_header(skb);
- if (skb->protocol == htons(ETH_P_IP) &&
- (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
- truncate = true;
-
- thoff = skb_transport_header(skb) - skb_mac_header(skb);
- if (skb->protocol == htons(ETH_P_IPV6) &&
- (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff))
- truncate = true;
-
- if (skb_cow_head(skb, dev->needed_headroom ? : t->hlen))
- goto tx_err;
-
- t->parms.o_flags &= ~TUNNEL_KEY;
-
- tun_info = ovs_skb_tunnel_info(skb);
- if (unlikely(!tun_info ||
- !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
- ip_tunnel_info_af(tun_info) != AF_INET6))
- return -EINVAL;
-
- key = &tun_info->key;
- memset(&fl6, 0, sizeof(fl6));
- fl6.flowi6_proto = IPPROTO_GRE;
- fl6.daddr = key->u.ipv6.dst;
- fl6.flowlabel = key->label;
- // fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
-
- dsfield = key->tos;
- md = ip_tunnel_info_opts(tun_info);
- if (!md)
- goto tx_err;
-
- if (erspan_skb_would_panic(skb,
- md->version == 1 ?
- ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE))
- goto tx_err;
-
- tun_id = tunnel_id_to_key32(key->tun_id);
- if (md->version == 1) {
- erspan_build_header(skb,
- ntohl(tun_id),
- ntohl(md->u.index), truncate,
- false);
- tpi.hdr_len = ERSPAN_V1_MDSIZE;
- tpi.proto = htons(ETH_P_ERSPAN);
- } else if (md->version == 2) {
- erspan_build_header_v2(skb,
- ntohl(tun_id),
- md->u.md2.dir,
- get_hwid(&md->u.md2),
- truncate, false);
- tpi.hdr_len = ERSPAN_V2_MDSIZE;
- tpi.proto = htons(ETH_P_ERSPAN2);
- } else {
- goto tx_err;
- }
-
- tpi.flags = TUNNEL_SEQ;
- tpi.key = 0;
- tpi.seq = htonl(t->o_seqno++);
-
- /* Push GRE header. */
- gre_build_header(skb, &tpi, 8);
-
- /* TooBig packet may have updated dst->dev's mtu */
- if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu)
-#ifndef HAVE_DST_OPS_CONFIRM_NEIGH
- dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu);
-#else
- dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu, false);
-#endif
-
- err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
- NEXTHDR_GRE);
- if (err != 0)
- goto tx_err;
-
- return NETDEV_TX_OK;
-
-tx_err:
- stats = &t->dev->stats;
- stats->tx_errors++;
- stats->tx_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static netdev_tx_t __ip6erspan_tunnel_xmit(struct sk_buff *skb)
-{
- return ip6erspan_tunnel_xmit(skb, skb->dev);
-}
-
-static void ip6gre_tnl_link_config_common(struct ip6_tnl *t)
-{
- struct net_device *dev = t->dev;
- struct __ip6_tnl_parm *p = &t->parms;
- struct flowi6 *fl6 = &t->fl.u.ip6;
-
- if (dev->type != ARPHRD_ETHER) {
- memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
- memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
- }
-
- /* Set up flowi template */
- fl6->saddr = p->laddr;
- fl6->daddr = p->raddr;
- fl6->flowi6_oif = p->link;
- fl6->flowlabel = 0;
- fl6->flowi6_proto = IPPROTO_GRE;
-
- if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
- fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo;
- if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
- fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
-
- p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
- p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
-
- if (p->flags&IP6_TNL_F_CAP_XMIT &&
- p->flags&IP6_TNL_F_CAP_RCV && dev->type != ARPHRD_ETHER)
- dev->flags |= IFF_POINTOPOINT;
- else
- dev->flags &= ~IFF_POINTOPOINT;
-}
-
-static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu,
- int t_hlen)
-{
- const struct __ip6_tnl_parm *p = &t->parms;
- struct net_device *dev = t->dev;
-
- if (p->flags & IP6_TNL_F_CAP_XMIT) {
- int strict = (ipv6_addr_type(&p->raddr) &
- (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
-
- struct rt6_info *rt = rt6_lookup(t->net,
- &p->raddr, &p->laddr,
- p->link, strict);
-
- if (!rt)
- return;
-
- if (rt->dst.dev) {
- dev->hard_header_len = rt->dst.dev->hard_header_len +
- t_hlen;
-
- if (set_mtu) {
- dev->mtu = rt->dst.dev->mtu - t_hlen;
- if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- dev->mtu -= 8;
- if (dev->type == ARPHRD_ETHER)
- dev->mtu -= ETH_HLEN;
-
- if (dev->mtu < IPV6_MIN_MTU)
- dev->mtu = IPV6_MIN_MTU;
- }
- }
- ip6_rt_put(rt);
- }
-}
-
-static int ip6gre_calc_hlen(struct ip6_tnl *tunnel)
-{
- int t_hlen;
-
- tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
- tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
-
- t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
- tunnel->dev->hard_header_len = LL_MAX_HEADER + t_hlen;
- return t_hlen;
-}
-
-static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
-{
- ip6gre_tnl_link_config_common(t);
- ip6gre_tnl_link_config_route(t, set_mtu, ip6gre_calc_hlen(t));
-}
-
-static void ip6gre_tnl_copy_tnl_parm(struct ip6_tnl *t,
- const struct __ip6_tnl_parm *p)
-{
- t->parms.laddr = p->laddr;
- t->parms.raddr = p->raddr;
- t->parms.flags = p->flags;
- t->parms.hop_limit = p->hop_limit;
- t->parms.encap_limit = p->encap_limit;
- t->parms.flowinfo = p->flowinfo;
- t->parms.link = p->link;
- t->parms.proto = p->proto;
- t->parms.i_key = p->i_key;
- t->parms.o_key = p->o_key;
- t->parms.i_flags = p->i_flags;
- t->parms.o_flags = p->o_flags;
- t->parms.fwmark = p->fwmark;
- dst_cache_reset(&t->dst_cache);
-}
-
-static int ip6gre_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
- int set_mtu)
-{
- ip6gre_tnl_copy_tnl_parm(t, p);
- ip6gre_tnl_link_config(t, set_mtu);
- return 0;
-}
-
-static void ip6gre_tnl_parm_from_user(struct __ip6_tnl_parm *p,
- const struct ip6_tnl_parm2 *u)
-{
- p->laddr = u->laddr;
- p->raddr = u->raddr;
- p->flags = u->flags;
- p->hop_limit = u->hop_limit;
- p->encap_limit = u->encap_limit;
- p->flowinfo = u->flowinfo;
- p->link = u->link;
- p->i_key = u->i_key;
- p->o_key = u->o_key;
- p->i_flags = gre_flags_to_tnl_flags(u->i_flags);
- p->o_flags = gre_flags_to_tnl_flags(u->o_flags);
- memcpy(p->name, u->name, sizeof(u->name));
-}
-
-static void ip6gre_tnl_parm_to_user(struct ip6_tnl_parm2 *u,
- const struct __ip6_tnl_parm *p)
-{
- u->proto = IPPROTO_GRE;
- u->laddr = p->laddr;
- u->raddr = p->raddr;
- u->flags = p->flags;
- u->hop_limit = p->hop_limit;
- u->encap_limit = p->encap_limit;
- u->flowinfo = p->flowinfo;
- u->link = p->link;
- u->i_key = p->i_key;
- u->o_key = p->o_key;
- u->i_flags = gre_tnl_flags_to_gre_flags(p->i_flags);
- u->o_flags = gre_tnl_flags_to_gre_flags(p->o_flags);
- memcpy(u->name, p->name, sizeof(u->name));
-}
-
-static int ip6gre_tunnel_ioctl(struct net_device *dev,
- struct ifreq *ifr, int cmd)
-{
- int err = 0;
- struct ip6_tnl_parm2 p;
- struct __ip6_tnl_parm p1;
- struct ip6_tnl *t = netdev_priv(dev);
- struct net *net = t->net;
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
-
- memset(&p1, 0, sizeof(p1));
-
- switch (cmd) {
- case SIOCGETTUNNEL:
- if (dev == ign->fb_tunnel_dev) {
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
- err = -EFAULT;
- break;
- }
- ip6gre_tnl_parm_from_user(&p1, &p);
- t = ip6gre_tunnel_locate(net, &p1, 0);
- if (!t)
- t = netdev_priv(dev);
- }
- memset(&p, 0, sizeof(p));
- ip6gre_tnl_parm_to_user(&p, &t->parms);
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- err = -EFAULT;
- break;
-
- case SIOCADDTUNNEL:
- case SIOCCHGTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
-
- err = -EINVAL;
- if ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))
- goto done;
-
- if (!(p.i_flags&GRE_KEY))
- p.i_key = 0;
- if (!(p.o_flags&GRE_KEY))
- p.o_key = 0;
-
- ip6gre_tnl_parm_from_user(&p1, &p);
- t = ip6gre_tunnel_locate(net, &p1, cmd == SIOCADDTUNNEL);
-
- if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
- if (t) {
- if (t->dev != dev) {
- err = -EEXIST;
- break;
- }
- } else {
- t = netdev_priv(dev);
-
- ip6gre_tunnel_unlink(ign, t);
- synchronize_net();
- ip6gre_tnl_change(t, &p1, 1);
- ip6gre_tunnel_link(ign, t);
- netdev_state_change(dev);
- }
- }
-
- if (t) {
- err = 0;
-
- memset(&p, 0, sizeof(p));
- ip6gre_tnl_parm_to_user(&p, &t->parms);
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- err = -EFAULT;
- } else
- err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
- break;
-
- case SIOCDELTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- if (dev == ign->fb_tunnel_dev) {
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
- err = -ENOENT;
- ip6gre_tnl_parm_from_user(&p1, &p);
- t = ip6gre_tunnel_locate(net, &p1, 0);
- if (!t)
- goto done;
- err = -EPERM;
- if (t == netdev_priv(ign->fb_tunnel_dev))
- goto done;
- dev = t->dev;
- }
- unregister_netdevice(dev);
- err = 0;
- break;
-
- default:
- err = -EINVAL;
- }
-
-done:
- return err;
-}
-
-static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned int len)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct ipv6hdr *ipv6h;
- __be16 *p;
-
- ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen + sizeof(*ipv6h));
- ip6_flow_hdr(ipv6h, 0, ip6_make_flowlabel(dev_net(dev), skb,
- t->fl.u.ip6.flowlabel,
- true, &t->fl.u.ip6));
- ipv6h->hop_limit = t->parms.hop_limit;
- ipv6h->nexthdr = NEXTHDR_GRE;
- ipv6h->saddr = t->parms.laddr;
- ipv6h->daddr = t->parms.raddr;
-
- p = (__be16 *)(ipv6h + 1);
- p[0] = t->parms.o_flags;
- p[1] = htons(type);
-
- /*
- * Set the source hardware address.
- */
-
- if (saddr)
- memcpy(&ipv6h->saddr, saddr, sizeof(struct in6_addr));
- if (daddr)
- memcpy(&ipv6h->daddr, daddr, sizeof(struct in6_addr));
- if (!ipv6_addr_any(&ipv6h->daddr))
- return t->hlen;
-
- return -t->hlen;
-}
-
-static const struct header_ops ip6gre_header_ops = {
- .create = ip6gre_header,
-};
-
-static const struct net_device_ops ip6gre_netdev_ops = {
- .ndo_init = ip6gre_tunnel_init,
- .ndo_uninit = ip6gre_tunnel_uninit,
- .ndo_start_xmit = ip6gre_tunnel_xmit,
- .ndo_do_ioctl = ip6gre_tunnel_ioctl,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = ip6_tnl_change_mtu,
-#else
- .ndo_change_mtu = ip6_tnl_change_mtu,
-#endif
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_NDO_GET_IFLINK
- .ndo_get_iflink = ip6_tnl_get_iflink,
-#endif
-};
-
-#ifdef HAVE_NEEDS_FREE_NETDEV
-static void ip6gre_dev_free(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
-
- dst_cache_destroy(&t->dst_cache);
- free_percpu(dev->tstats);
-}
-
-#endif
-static void ip6gre_tunnel_setup(struct net_device *dev)
-{
- dev->netdev_ops = &ip6gre_netdev_ops;
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
- dev->priv_destructor = ip6gre_dev_free;
-#endif
-
- dev->type = ARPHRD_IP6GRE;
-
- dev->flags |= IFF_NOARP;
- dev->addr_len = sizeof(struct in6_addr);
- netif_keep_dst(dev);
- /* This perm addr will be used as interface identifier by IPv6 */
- dev->addr_assign_type = NET_ADDR_RANDOM;
- eth_random_addr(dev->perm_addr);
-}
-
-#define GRE6_FEATURES (NETIF_F_SG | \
- NETIF_F_FRAGLIST | \
- NETIF_F_HIGHDMA | \
- NETIF_F_HW_CSUM)
-
-static void ip6gre_tnl_init_features(struct net_device *dev)
-{
- struct ip6_tnl *nt = netdev_priv(dev);
-
- dev->features |= GRE6_FEATURES;
- dev->hw_features |= GRE6_FEATURES;
-
- if (!(nt->parms.o_flags & TUNNEL_SEQ)) {
- /* TCP offload with GRE SEQ is not supported, nor
- * can we support 2 levels of outer headers requiring
- * an update.
- */
- if (!(nt->parms.o_flags & TUNNEL_CSUM) ||
- nt->encap.type == TUNNEL_ENCAP_NONE) {
- dev->features |= NETIF_F_GSO_SOFTWARE;
- dev->hw_features |= NETIF_F_GSO_SOFTWARE;
- }
-
- /* Can use a lockless transmit, unless we generate
- * output sequences
- */
- dev->features |= NETIF_F_LLTX;
- }
-}
-
-static int ip6gre_tunnel_init_common(struct net_device *dev)
-{
- struct ip6_tnl *tunnel;
- int ret;
- int t_hlen;
-
- tunnel = netdev_priv(dev);
-
- tunnel->dev = dev;
- tunnel->net = dev_net(dev);
- strcpy(tunnel->parms.name, dev->name);
-
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
- if (ret) {
- free_percpu(dev->tstats);
- dev->tstats = NULL;
- return ret;
- }
-
- t_hlen = ip6gre_calc_hlen(tunnel);
- dev->mtu = ETH_DATA_LEN - t_hlen;
- if (dev->type == ARPHRD_ETHER)
- dev->mtu -= ETH_HLEN;
- if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- dev->mtu -= 8;
-
- if (tunnel->parms.collect_md) {
- dev->features |= NETIF_F_NETNS_LOCAL;
- netif_keep_dst(dev);
- }
- ip6gre_tnl_init_features(dev);
-
- return 0;
-}
-
-static int ip6gre_tunnel_init(struct net_device *dev)
-{
- struct ip6_tnl *tunnel;
- int ret;
-
- ret = ip6gre_tunnel_init_common(dev);
- if (ret)
- return ret;
-
- tunnel = netdev_priv(dev);
-
- if (tunnel->parms.collect_md)
- return 0;
-
- memcpy(dev->dev_addr, &tunnel->parms.laddr, sizeof(struct in6_addr));
- memcpy(dev->broadcast, &tunnel->parms.raddr, sizeof(struct in6_addr));
-
- if (ipv6_addr_any(&tunnel->parms.raddr))
- dev->header_ops = &ip6gre_header_ops;
-
- return 0;
-}
-
-static void ip6gre_fb_tunnel_init(struct net_device *dev)
-{
- struct ip6_tnl *tunnel = netdev_priv(dev);
-
- tunnel->dev = dev;
- tunnel->net = dev_net(dev);
- strcpy(tunnel->parms.name, dev->name);
-
- tunnel->hlen = sizeof(struct ipv6hdr) + 4;
-
- dev_hold(dev);
-}
-
-static struct inet6_protocol ip6gre_protocol __read_mostly = {
- .handler = gre_rcv,
- .err_handler = ip6gre_err,
- .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
-};
-
-static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head)
-{
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
- struct net_device *dev, *aux;
- int prio;
-
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == &ip6gre_link_ops ||
- dev->rtnl_link_ops == &ip6gre_tap_ops ||
- dev->rtnl_link_ops == &ip6erspan_tap_ops)
- unregister_netdevice_queue(dev, head);
-
- for (prio = 0; prio < 4; prio++) {
- int h;
- for (h = 0; h < IP6_GRE_HASH_SIZE; h++) {
- struct ip6_tnl *t;
-
- t = rtnl_dereference(ign->tunnels[prio][h]);
-
- while (t) {
- /* If dev is in the same netns, it has already
- * been added to the list by the previous loop.
- */
- if (!net_eq(dev_net(t->dev), net))
- unregister_netdevice_queue(t->dev,
- head);
- t = rtnl_dereference(t->next);
- }
- }
- }
-}
-
-static int __net_init ip6gre_init_net(struct net *net)
-{
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
- int err;
-
- ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl),
- "ovs-ip6gre0",
- NET_NAME_UNKNOWN,
- ip6gre_tunnel_setup);
- if (!ign->fb_tunnel_dev) {
- err = -ENOMEM;
- goto err_alloc_dev;
- }
- dev_net_set(ign->fb_tunnel_dev, net);
- /* FB netdevice is special: we have one, and only one per netns.
- * Allowing to move it to another netns is clearly unsafe.
- */
- ign->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
-
-
- ip6gre_fb_tunnel_init(ign->fb_tunnel_dev);
- ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops;
-
- err = register_netdev(ign->fb_tunnel_dev);
- if (err)
- goto err_reg_dev;
-
- rcu_assign_pointer(ign->tunnels_wc[0],
- netdev_priv(ign->fb_tunnel_dev));
- return 0;
-
-err_reg_dev:
- free_netdev(ign->fb_tunnel_dev);
-err_alloc_dev:
- return err;
-}
-
-static void __net_exit ip6gre_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)
- ip6gre_destroy_tunnels(net, &list);
- unregister_netdevice_many(&list);
- rtnl_unlock();
-}
-
-enum {
-#ifndef HAVE_IFLA_GRE_ENCAP_DPORT
- IFLA_GRE_ENCAP_TYPE = IFLA_GRE_FLAGS + 1,
- IFLA_GRE_ENCAP_FLAGS,
- IFLA_GRE_ENCAP_SPORT,
- IFLA_GRE_ENCAP_DPORT,
-#endif
-#ifndef HAVE_IFLA_GRE_COLLECT_METADATA
- IFLA_GRE_COLLECT_METADATA = IFLA_GRE_ENCAP_DPORT + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_IGNORE_DF
- IFLA_GRE_IGNORE_DF = IFLA_GRE_COLLECT_METADATA + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_FWMARK
- IFLA_GRE_FWMARK = IFLA_GRE_IGNORE_DF + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_ERSPAN_INDEX
- IFLA_GRE_ERSPAN_INDEX = IFLA_GRE_FWMARK + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_ERSPAN_HWID
- IFLA_GRE_ERSPAN_VER = IFLA_GRE_ERSPAN_INDEX + 1,
- IFLA_GRE_ERSPAN_DIR,
- IFLA_GRE_ERSPAN_HWID,
-#endif
-};
-
-#define RPL_IFLA_GRE_MAX (IFLA_GRE_ERSPAN_HWID + 1)
-
-static struct pernet_operations ip6gre_net_ops = {
- .init = ip6gre_init_net,
- .exit_batch = ip6gre_exit_batch_net,
- .id = &ip6gre_net_id,
- .size = sizeof(struct ip6gre_net),
-};
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int rpl_ip6gre_tunnel_validate(struct nlattr *tb[],
- struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6gre_tunnel_validate(struct nlattr *tb[],
- struct nlattr *data[])
-#endif
-{
- __be16 flags;
-
- if (!data)
- return 0;
-
- flags = 0;
- if (data[IFLA_GRE_IFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
- if (data[IFLA_GRE_OFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
- if (flags & (GRE_VERSION|GRE_ROUTING))
- return -EINVAL;
-
- return 0;
-}
-#define ip6gre_tunnel_validate rpl_ip6gre_tunnel_validate
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int rpl_ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- struct in6_addr daddr;
-
- if (tb[IFLA_ADDRESS]) {
- if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
- return -EINVAL;
- if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
- return -EADDRNOTAVAIL;
- }
-
- if (!data)
- goto out;
-
- if (data[IFLA_GRE_REMOTE]) {
- daddr = nla_get_in6_addr(data[IFLA_GRE_REMOTE]);
- if (ipv6_addr_any(&daddr))
- return -EINVAL;
- }
-
-out:
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
- return ip6gre_tunnel_validate(tb, data, extack);
-#else
- return ip6gre_tunnel_validate(tb, data);
-#endif
-}
-#define ip6gre_tap_validate rpl_ip6gre_tap_validate
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int rpl_ip6erspan_tap_validate(struct nlattr *tb[],
- struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6erspan_tap_validate(struct nlattr *tb[],
- struct nlattr *data[])
-#endif
-{
- __be16 flags = 0;
- int ret, ver = 0;
-
- if (!data)
- return 0;
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
- ret = ip6gre_tap_validate(tb, data, extack);
-#else
- ret = ip6gre_tap_validate(tb, data);
-#endif
- if (ret)
- return ret;
-
- /* ERSPAN should only have GRE sequence and key flag */
- if (data[IFLA_GRE_OFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
- if (data[IFLA_GRE_IFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
- if (!data[IFLA_GRE_COLLECT_METADATA] &&
- flags != (GRE_SEQ | GRE_KEY))
- return -EINVAL;
-
- /* ERSPAN Session ID only has 10-bit. Since we reuse
- * 32-bit key field as ID, check it's range.
- */
- if (data[IFLA_GRE_IKEY] &&
- (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK))
- return -EINVAL;
-
- if (data[IFLA_GRE_OKEY] &&
- (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
- return -EINVAL;
-
- if (data[IFLA_GRE_ERSPAN_VER]) {
- ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
- if (ver != 1 && ver != 2)
- return -EINVAL;
- }
-
- if (ver == 1) {
- if (data[IFLA_GRE_ERSPAN_INDEX]) {
- u32 index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
-
- if (index & ~INDEX_MASK)
- return -EINVAL;
- }
- } else if (ver == 2) {
- if (data[IFLA_GRE_ERSPAN_DIR]) {
- u16 dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
-
- if (dir & ~(DIR_MASK >> DIR_OFFSET))
- return -EINVAL;
- }
-
- if (data[IFLA_GRE_ERSPAN_HWID]) {
- u16 hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
-
- if (hwid & ~(HWID_MASK >> HWID_OFFSET))
- return -EINVAL;
- }
- }
-
- return 0;
-}
-#define ip6erspan_tap_validate rpl_ip6erspan_tap_validate
-
-static void ip6gre_netlink_parms(struct nlattr *data[],
- struct __ip6_tnl_parm *parms)
-{
-#if 0
- /* Do not use in case of OVS - our vport needs to set a parm
- * directly and this erases it
- */
- memset(parms, 0, sizeof(*parms));
-
-#endif
- if (!data)
- return;
-
- if (data[IFLA_GRE_LINK])
- parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
-
- if (data[IFLA_GRE_IFLAGS])
- parms->i_flags = gre_flags_to_tnl_flags(
- nla_get_be16(data[IFLA_GRE_IFLAGS]));
-
- if (data[IFLA_GRE_OFLAGS])
- parms->o_flags = gre_flags_to_tnl_flags(
- nla_get_be16(data[IFLA_GRE_OFLAGS]));
-
- if (data[IFLA_GRE_IKEY])
- parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
-
- if (data[IFLA_GRE_OKEY])
- parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
-
- if (data[IFLA_GRE_LOCAL])
- parms->laddr = nla_get_in6_addr(data[IFLA_GRE_LOCAL]);
-
- if (data[IFLA_GRE_REMOTE])
- parms->raddr = nla_get_in6_addr(data[IFLA_GRE_REMOTE]);
-
- if (data[IFLA_GRE_TTL])
- parms->hop_limit = nla_get_u8(data[IFLA_GRE_TTL]);
-
- if (data[IFLA_GRE_ENCAP_LIMIT])
- parms->encap_limit = nla_get_u8(data[IFLA_GRE_ENCAP_LIMIT]);
-
- if (data[IFLA_GRE_FLOWINFO])
- parms->flowinfo = nla_get_be32(data[IFLA_GRE_FLOWINFO]);
-
- if (data[IFLA_GRE_FLAGS])
- parms->flags = nla_get_u32(data[IFLA_GRE_FLAGS]);
-
- if (data[IFLA_GRE_FWMARK])
- parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
-
- if (data[IFLA_GRE_COLLECT_METADATA])
- parms->collect_md = true;
-
- parms->erspan_ver = 1;
- if (data[IFLA_GRE_ERSPAN_VER])
- parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
-
- if (parms->erspan_ver == 1) {
- if (data[IFLA_GRE_ERSPAN_INDEX])
- parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
- } else if (parms->erspan_ver == 2) {
- if (data[IFLA_GRE_ERSPAN_DIR])
- parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
- if (data[IFLA_GRE_ERSPAN_HWID])
- parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
- }
-}
-
-static int ip6gre_tap_init(struct net_device *dev)
-{
- int ret;
-
- ret = ip6gre_tunnel_init_common(dev);
- if (ret)
- return ret;
-
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
-
- return 0;
-}
-
-static const struct net_device_ops ip6gre_tap_netdev_ops = {
- .ndo_init = ip6gre_tap_init,
- .ndo_uninit = ip6gre_tunnel_uninit,
- .ndo_start_xmit = ip6gre_tunnel_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = ip6_tnl_change_mtu,
-#else
- .ndo_change_mtu = ip6_tnl_change_mtu,
-#endif
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_NDO_GET_IFLINK
- .ndo_get_iflink = ip6_tnl_get_iflink,
-#endif
-};
-
-static int ip6erspan_calc_hlen(struct ip6_tnl *tunnel)
-{
- int t_hlen;
-
- tunnel->tun_hlen = 8;
- tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
- erspan_hdr_len(tunnel->parms.erspan_ver);
-
- t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
- tunnel->dev->hard_header_len = LL_MAX_HEADER + t_hlen;
- return t_hlen;
-}
-
-static int ip6erspan_tap_init(struct net_device *dev)
-{
- struct ip6_tnl *tunnel;
- int t_hlen;
- int ret;
-
- tunnel = netdev_priv(dev);
-
- tunnel->dev = dev;
- tunnel->net = dev_net(dev);
- strcpy(tunnel->parms.name, dev->name);
-
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
- if (ret) {
- free_percpu(dev->tstats);
- dev->tstats = NULL;
- return ret;
- }
-
- t_hlen = ip6erspan_calc_hlen(tunnel);
- dev->mtu = ETH_DATA_LEN - t_hlen;
- if (dev->type == ARPHRD_ETHER)
- dev->mtu -= ETH_HLEN;
- if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- dev->mtu -= 8;
-
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
- tunnel = netdev_priv(dev);
- ip6erspan_tnl_link_config(tunnel, 1);
-
- return 0;
-}
-
-static const struct net_device_ops ip6erspan_netdev_ops = {
- .ndo_init = ip6erspan_tap_init,
- .ndo_uninit = ip6erspan_tunnel_uninit,
- .ndo_start_xmit = ip6erspan_tunnel_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = ip6_tnl_change_mtu,
-#else
- .ndo_change_mtu = ip6_tnl_change_mtu,
-#endif
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_NDO_GET_IFLINK
- .ndo_get_iflink = ip6_tnl_get_iflink,
-#endif
-};
-
-static void ip6gre_tap_setup(struct net_device *dev)
-{
-
- ether_setup(dev);
-#ifdef HAVE_NET_DEVICE_MAX_MTU
- dev->max_mtu = 0;
-#endif
- dev->netdev_ops = &ip6gre_tap_netdev_ops;
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
- dev->priv_destructor = ip6gre_dev_free;
-#endif
-
- dev->features |= NETIF_F_NETNS_LOCAL;
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
- netif_keep_dst(dev);
-}
-
-static bool ip6gre_netlink_encap_parms(struct nlattr *data[],
- struct ip_tunnel_encap *ipencap)
-{
- bool ret = false;
-
- memset(ipencap, 0, sizeof(*ipencap));
-
- if (!data)
- return ret;
-
- if (data[IFLA_GRE_ENCAP_TYPE]) {
- ret = true;
- ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
- }
-
- if (data[IFLA_GRE_ENCAP_FLAGS]) {
- ret = true;
- ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
- }
-
- if (data[IFLA_GRE_ENCAP_SPORT]) {
- ret = true;
- ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
- }
-
- if (data[IFLA_GRE_ENCAP_DPORT]) {
- ret = true;
- ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
- }
-
- return ret;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int rpl_ip6gre_newlink_common(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6gre_newlink_common(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- struct ip6_tnl *nt;
- struct ip_tunnel_encap ipencap;
- int err;
-
- nt = netdev_priv(dev);
-
- if (ip6gre_netlink_encap_parms(data, &ipencap)) {
- int err = ip6_tnl_encap_setup(nt, &ipencap);
-
- if (err < 0)
- return err;
- }
-
- if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
- eth_hw_addr_random(dev);
-
- nt->dev = dev;
- nt->net = dev_net(dev);
-
- err = register_netdevice(dev);
- if (err)
- goto out;
-
- if (tb[IFLA_MTU])
- ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
-
- dev_hold(dev);
-
-out:
- return err;
-}
-#define ip6gre_newlink_common rpl_ip6gre_newlink_common
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int rpl_ip6gre_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6gre_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- struct ip6_tnl *nt = netdev_priv(dev);
- struct net *net = dev_net(dev);
- struct ip6gre_net *ign;
- int err;
-
- ip6gre_netlink_parms(data, &nt->parms);
- ign = net_generic(net, ip6gre_net_id);
-
- if (nt->parms.collect_md) {
- if (rtnl_dereference(ign->collect_md_tun))
- return -EEXIST;
- } else {
- if (ip6gre_tunnel_find(net, &nt->parms, dev->type))
- return -EEXIST;
- }
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
-#else
- err = ip6gre_newlink_common(src_net, dev, tb, data);
-#endif
- if (!err) {
- ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
- ip6gre_tunnel_link_md(ign, nt);
- ip6gre_tunnel_link(net_generic(net, ip6gre_net_id), nt);
- }
- return err;
-}
-
-#define ip6gre_newlink rpl_ip6gre_newlink
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static struct ip6_tnl *
-rpl_ip6gre_changelink_common(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[], struct __ip6_tnl_parm *p_p,
- struct netlink_ext_ack *extack)
-#else
-static struct ip6_tnl *
-rpl_ip6gre_changelink_common(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[], struct __ip6_tnl_parm *p_p)
-#endif
-{
- struct ip6_tnl *t, *nt = netdev_priv(dev);
- struct net *net = nt->net;
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
- struct ip_tunnel_encap ipencap;
-
- if (dev == ign->fb_tunnel_dev)
- return ERR_PTR(-EINVAL);
-
- if (ip6gre_netlink_encap_parms(data, &ipencap)) {
- int err = ip6_tnl_encap_setup(nt, &ipencap);
-
- if (err < 0)
- return ERR_PTR(err);
- }
-
- ip6gre_netlink_parms(data, p_p);
-
- t = ip6gre_tunnel_locate(net, p_p, 0);
-
- if (t) {
- if (t->dev != dev)
- return ERR_PTR(-EEXIST);
- } else {
- t = nt;
- }
-
- return t;
-}
-#define ip6gre_changelink_common rpl_ip6gre_changelink_common
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int rpl_ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[])
-#endif
-{
- struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
- struct __ip6_tnl_parm p;
- struct ip6_tnl *t;
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- t = ip6gre_changelink_common(dev, tb, data, &p, extack);
-#else
- t = ip6gre_changelink_common(dev, tb, data, &p);
-#endif
- if (IS_ERR(t))
- return PTR_ERR(t);
-
- ip6gre_tunnel_unlink_md(ign, t);
- ip6gre_tunnel_unlink(ign, t);
- ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
- ip6gre_tunnel_link_md(ign, t);
- ip6gre_tunnel_link(ign, t);
- return 0;
-}
-#define ip6gre_changelink rpl_ip6gre_changelink
-
-static void ip6gre_dellink(struct net_device *dev, struct list_head *head)
-{
- struct net *net = dev_net(dev);
- struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
-
- if (dev != ign->fb_tunnel_dev)
- unregister_netdevice_queue(dev, head);
-}
-
-static size_t ip6gre_get_size(const struct net_device *dev)
-{
- return
- /* IFLA_GRE_LINK */
- nla_total_size(4) +
- /* IFLA_GRE_IFLAGS */
- nla_total_size(2) +
- /* IFLA_GRE_OFLAGS */
- nla_total_size(2) +
- /* IFLA_GRE_IKEY */
- nla_total_size(4) +
- /* IFLA_GRE_OKEY */
- nla_total_size(4) +
- /* IFLA_GRE_LOCAL */
- nla_total_size(sizeof(struct in6_addr)) +
- /* IFLA_GRE_REMOTE */
- nla_total_size(sizeof(struct in6_addr)) +
- /* IFLA_GRE_TTL */
- nla_total_size(1) +
- /* IFLA_GRE_ENCAP_LIMIT */
- nla_total_size(1) +
- /* IFLA_GRE_FLOWINFO */
- nla_total_size(4) +
- /* IFLA_GRE_FLAGS */
- nla_total_size(4) +
- /* IFLA_GRE_ENCAP_TYPE */
- nla_total_size(2) +
- /* IFLA_GRE_ENCAP_FLAGS */
- nla_total_size(2) +
- /* IFLA_GRE_ENCAP_SPORT */
- nla_total_size(2) +
- /* IFLA_GRE_ENCAP_DPORT */
- nla_total_size(2) +
- /* IFLA_GRE_COLLECT_METADATA */
- nla_total_size(0) +
- /* IFLA_GRE_FWMARK */
- nla_total_size(4) +
- /* IFLA_GRE_ERSPAN_INDEX */
- nla_total_size(4) +
- 0;
-}
-
-static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct __ip6_tnl_parm *p = &t->parms;
-
- if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
- nla_put_be16(skb, IFLA_GRE_IFLAGS,
- gre_tnl_flags_to_gre_flags(p->i_flags)) ||
- nla_put_be16(skb, IFLA_GRE_OFLAGS,
- gre_tnl_flags_to_gre_flags(p->o_flags)) ||
- nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
- nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
- nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) ||
- nla_put_in6_addr(skb, IFLA_GRE_REMOTE, &p->raddr) ||
- nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) ||
- nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) ||
- nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) ||
- nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) ||
- nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark) ||
- nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index))
- goto nla_put_failure;
-
- if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
- t->encap.type) ||
- nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
- t->encap.sport) ||
- nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
- t->encap.dport) ||
- nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
- t->encap.flags))
- goto nla_put_failure;
-
- if (p->collect_md) {
- if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
- goto nla_put_failure;
- }
-
- if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver))
- goto nla_put_failure;
-
- if (p->erspan_ver == 1) {
- if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index))
- goto nla_put_failure;
- } else if (p->erspan_ver == 2) {
- if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir))
- goto nla_put_failure;
- if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid))
- goto nla_put_failure;
- }
-
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-static const struct nla_policy ip6gre_policy[RPL_IFLA_GRE_MAX + 1] = {
- [IFLA_GRE_LINK] = { .type = NLA_U32 },
- [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
- [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
- [IFLA_GRE_IKEY] = { .type = NLA_U32 },
- [IFLA_GRE_OKEY] = { .type = NLA_U32 },
- [IFLA_GRE_LOCAL] = { .len = sizeof_field(struct ipv6hdr, saddr) },
- [IFLA_GRE_REMOTE] = { .len = sizeof_field(struct ipv6hdr, daddr) },
- [IFLA_GRE_TTL] = { .type = NLA_U8 },
- [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 },
- [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 },
- [IFLA_GRE_FLAGS] = { .type = NLA_U32 },
- [IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 },
- [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 },
- [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 },
- [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
- [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
- [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
- [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
- [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 },
- [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 },
- [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 },
-};
-
-static void ip6erspan_tap_setup(struct net_device *dev)
-{
- ether_setup(dev);
-
- dev->netdev_ops = &ip6erspan_netdev_ops;
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
- dev->priv_destructor = ip6gre_dev_free;
-#endif
-
- dev->features |= NETIF_F_NETNS_LOCAL;
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
- netif_keep_dst(dev);
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int rpl_ip6erspan_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6erspan_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- struct ip6_tnl *nt = netdev_priv(dev);
- struct net *net = dev_net(dev);
- struct ip6gre_net *ign;
- int err;
-
- ip6gre_netlink_parms(data, &nt->parms);
- ign = net_generic(net, ip6gre_net_id);
-
- if (nt->parms.collect_md) {
- if (rtnl_dereference(ign->collect_md_tun_erspan))
- return -EEXIST;
- } else {
- if (ip6gre_tunnel_find(net, &nt->parms, dev->type))
- return -EEXIST;
- }
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
-#else
- err = ip6gre_newlink_common(src_net, dev, tb, data);
-#endif
- if (!err) {
- ip6erspan_tnl_link_config(nt, !tb[IFLA_MTU]);
- ip6erspan_tunnel_link_md(ign, nt);
- ip6gre_tunnel_link(net_generic(net, ip6gre_net_id), nt);
- }
- return err;
-}
-#define ip6erspan_newlink rpl_ip6erspan_newlink
-
-static void ip6erspan_tnl_link_config(struct ip6_tnl *t, int set_mtu)
-{
- ip6gre_tnl_link_config_common(t);
- ip6gre_tnl_link_config_route(t, set_mtu, ip6erspan_calc_hlen(t));
-}
-
-static int ip6erspan_tnl_change(struct ip6_tnl *t,
- const struct __ip6_tnl_parm *p, int set_mtu)
-{
- ip6gre_tnl_copy_tnl_parm(t, p);
- ip6erspan_tnl_link_config(t, set_mtu);
- return 0;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int rpl_ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[])
-#endif
-{
- struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
- struct __ip6_tnl_parm p;
- struct ip6_tnl *t;
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- t = ip6gre_changelink_common(dev, tb, data, &p, extack);
-#else
- t = ip6gre_changelink_common(dev, tb, data, &p);
-#endif
- if (IS_ERR(t))
- return PTR_ERR(t);
-
- ip6gre_tunnel_unlink_md(ign, t);
- ip6gre_tunnel_unlink(ign, t);
- ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]);
- ip6erspan_tunnel_link_md(ign, t);
- ip6gre_tunnel_link(ign, t);
- return 0;
-}
-#define ip6erspan_changelink rpl_ip6erspan_changelink
-
-static struct rtnl_link_ops ip6gre_link_ops __read_mostly = {
- .kind = "ip6gre",
- .maxtype = RPL_IFLA_GRE_MAX,
- .policy = ip6gre_policy,
- .priv_size = sizeof(struct ip6_tnl),
- .setup = ip6gre_tunnel_setup,
- .validate = ip6gre_tunnel_validate,
- .newlink = ip6gre_newlink,
- .changelink = ip6gre_changelink,
- .dellink = ip6gre_dellink,
- .get_size = ip6gre_get_size,
- .fill_info = ip6gre_fill_info,
-#ifdef HAVE_GET_LINK_NET
- .get_link_net = ip6_tnl_get_link_net,
-#endif
-};
-
-static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = {
- .kind = "ip6gretap",
- .maxtype = RPL_IFLA_GRE_MAX,
- .policy = ip6gre_policy,
- .priv_size = sizeof(struct ip6_tnl),
- .setup = ip6gre_tap_setup,
- .validate = ip6gre_tap_validate,
- .newlink = ip6gre_newlink,
- .changelink = ip6gre_changelink,
- .dellink = ip6gre_dellink,
- .get_size = ip6gre_get_size,
- .fill_info = ip6gre_fill_info,
-#ifdef HAVE_GET_LINK_NET
- .get_link_net = ip6_tnl_get_link_net,
-#endif
-};
-
-static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly = {
- .kind = "ip6erspan",
- .maxtype = RPL_IFLA_GRE_MAX,
- .policy = ip6gre_policy,
- .priv_size = sizeof(struct ip6_tnl),
- .setup = ip6erspan_tap_setup,
- .validate = ip6erspan_tap_validate,
- .newlink = ip6erspan_newlink,
- .changelink = ip6erspan_changelink,
- .dellink = ip6gre_dellink,
- .get_size = ip6gre_get_size,
- .fill_info = ip6gre_fill_info,
-#ifdef HAVE_GET_LINK_NET
- .get_link_net = ip6_tnl_get_link_net,
-#endif
-};
-
-struct net_device *ip6erspan_fb_dev_create(struct net *net, const char *name,
- u8 name_assign_type)
-{
- struct nlattr *tb[IFLA_MAX + 1];
- struct net_device *dev;
- LIST_HEAD(list_kill);
- struct ip6_tnl *t;
- int err;
-
- memset(&tb, 0, sizeof(tb));
-
- dev = rtnl_create_link(net, (char *)name, name_assign_type,
- &ip6erspan_tap_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- t = netdev_priv(dev);
- t->parms.collect_md = true;
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- err = ip6erspan_newlink(net, dev, tb, NULL, NULL);
-#else
- err = ip6erspan_newlink(net, dev, tb, NULL);
-#endif
- if (err < 0) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
- /* openvswitch users expect packet sizes to be unrestricted,
- * so set the largest MTU we can.
- */
- err = ip6_tnl_change_mtu(dev, 64000);
- if (err)
- goto out;
-
- return dev;
-out:
- ip6gre_dellink(dev, &list_kill);
- unregister_netdevice_many(&list_kill);
- return ERR_PTR(err);
-}
-
-static struct vport_ops ovs_erspan6_vport_ops;
-
-static struct vport *erspan6_tnl_create(const struct vport_parms *parms)
-{
- struct net *net = ovs_dp_get_net(parms->dp);
- struct net_device *dev;
- struct vport *vport;
- int err;
-
- vport = ovs_vport_alloc(0, &ovs_erspan6_vport_ops, parms);
- if (IS_ERR(vport))
- return vport;
-
- rtnl_lock();
- dev = ip6erspan_fb_dev_create(net, parms->name, NET_NAME_USER);
- 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);
- return ERR_PTR(err);
- }
-
- rtnl_unlock();
- return vport;
-}
-
-static struct vport *erspan6_create(const struct vport_parms *parms)
-{
- struct vport *vport;
-
- vport = erspan6_tnl_create(parms);
- if (IS_ERR(vport))
- return vport;
-
- return ovs_netdev_link(vport, parms->name);
-}
-
-#ifndef OVS_VPORT_TYPE_IP6ERSPAN
-/* Just until integration */
-#define OVS_VPORT_TYPE_IP6ERSPAN 108
-#endif
-static struct vport_ops ovs_erspan6_vport_ops = {
- .type = OVS_VPORT_TYPE_IP6ERSPAN,
- .create = erspan6_create,
- .send = __ip6erspan_tunnel_xmit,
-#ifndef USE_UPSTREAM_TUNNEL
- .fill_metadata_dst = gre_fill_metadata_dst,
-#endif
- .destroy = ovs_netdev_tunnel_destroy,
-};
-
-struct net_device *ip6gre_fb_dev_create(struct net *net, const char *name,
- u8 name_assign_type)
-{
- struct nlattr *tb[IFLA_MAX + 1];
- struct net_device *dev;
- LIST_HEAD(list_kill);
- struct ip6_tnl *t;
- int err;
-
- memset(&tb, 0, sizeof(tb));
-
- dev = rtnl_create_link(net, (char *)name, name_assign_type,
- &ip6gre_tap_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- t = netdev_priv(dev);
- t->parms.collect_md = true;
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- err = ip6gre_newlink(net, dev, tb, NULL, NULL);
-#else
- err = ip6gre_newlink(net, dev, tb, NULL);
-#endif
- if (err < 0) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
- /* openvswitch users expect packet sizes to be unrestricted,
- * so set the largest MTU we can.
- */
- err = ip6_tnl_change_mtu(dev, 64000);
- if (err)
- goto out;
-
- return dev;
-out:
- ip6gre_dellink(dev, &list_kill);
- unregister_netdevice_many(&list_kill);
- return ERR_PTR(err);
-}
-
-static struct vport_ops ovs_ip6gre_vport_ops;
-
-static struct vport *ip6gre_tnl_create(const struct vport_parms *parms)
-{
- struct net *net = ovs_dp_get_net(parms->dp);
- struct net_device *dev;
- struct vport *vport;
- int err;
-
- vport = ovs_vport_alloc(0, &ovs_ip6gre_vport_ops, parms);
- if (IS_ERR(vport))
- return vport;
-
- rtnl_lock();
- dev = ip6gre_fb_dev_create(net, parms->name, NET_NAME_USER);
- 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);
- return ERR_PTR(err);
- }
-
- rtnl_unlock();
- return vport;
-}
-
-static struct vport *ip6gre_create(const struct vport_parms *parms)
-{
- struct vport *vport;
-
- vport = ip6gre_tnl_create(parms);
- if (IS_ERR(vport))
- return vport;
-
- return ovs_netdev_link(vport, parms->name);
-}
-
-static struct vport_ops ovs_ip6gre_vport_ops = {
- .type = OVS_VPORT_TYPE_IP6GRE,
- .create = ip6gre_create,
- .send = __ip6gre_tunnel_xmit,
-#ifndef USE_UPSTREAM_TUNNEL
- .fill_metadata_dst = gre_fill_metadata_dst,
-#endif
- .destroy = ovs_netdev_tunnel_destroy,
-};
-
-
-/*
- * And now the modules code and kernel interface.
- */
-
-int rpl_ip6gre_init(void)
-{
- int err;
-
- err = register_pernet_device(&ip6gre_net_ops);
- if (err < 0) {
- if (err == -EEXIST)
- goto ip6_gre_loaded;
- else
- goto out;
- }
-
- err = inet6_add_protocol(&ip6gre_protocol, IPPROTO_GRE);
- if (err < 0) {
- pr_info("%s: can't add protocol\n", __func__);
- unregister_pernet_device(&ip6gre_net_ops);
- /*
- * inet6_add_protocol will return a -1 if it fails
- * to grab the pointer but the vport initialization
- * expects a return value of -EEXIST. Set err to
- * -EEXIST here to ensure proper handling.
- */
- err = -EEXIST;
- goto ip6_gre_loaded;
- }
-
- pr_info("GRE over IPv6 tunneling driver\n");
- ovs_vport_ops_register(&ovs_ip6gre_vport_ops);
- ovs_vport_ops_register(&ovs_erspan6_vport_ops);
- return err;
-
-ip6_gre_loaded:
- /* Since IPv6 GRE only allows single receiver to be registerd,
- * we skip here so only transmit works, see:
- *
- * commit f9242b6b28d61295f2bf7e8adfb1060b382e5381
- * Author: David S. Miller <davem@davemloft.net>
- * Date: Tue Jun 19 18:56:21 2012 -0700
- *
- * inet: Sanitize inet{,6} protocol demux.
- *
- * OVS GRE receive part is disabled.
- */
- pr_info("GRE TX only over IPv6 tunneling driver\n");
- ip6_gre_loaded = true;
- ovs_vport_ops_register(&ovs_ip6gre_vport_ops);
- ovs_vport_ops_register(&ovs_erspan6_vport_ops);
-out:
- return err;
-}
-
-void rpl_ip6gre_fini(void)
-{
- ovs_vport_ops_unregister(&ovs_erspan6_vport_ops);
- ovs_vport_ops_unregister(&ovs_ip6gre_vport_ops);
- if (!ip6_gre_loaded) {
- inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE);
- unregister_pernet_device(&ip6gre_net_ops);
- }
-}
-#endif /* USE_UPSTREAM_TUNNEL */
diff --git a/datapath/linux/compat/ip6_output.c b/datapath/linux/compat/ip6_output.c
deleted file mode 100644
index 688884275..000000000
--- a/datapath/linux/compat/ip6_output.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Backported from upstream commit 9ef2e965e554
- * ("ipv6: drop frames with attached skb->sk in forwarding")
- *
- * IPv6 output functions
- * Linux INET6 implementation
- *
- * Authors:
- * Pedro Roque <roque@di.fc.ul.pt>
- *
- * Based on linux/net/ipv4/ip_output.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Changes:
- * A.N.Kuznetsov : airthmetics in fragmentation.
- * extension headers are implemented.
- * route changes now work.
- * ip6_forward does not confuse sniffers.
- * etc.
- *
- * H. von Brand : Added missing #include <linux/string.h>
- * Imran Patel : frag id should be in NBO
- * Kazunori MIYAZAWA @USAGI
- * : add ip6_append_data and related functions
- * for datagram xmit
- */
-
-#include <linux/version.h>
-
-#ifndef HAVE_NF_IPV6_OPS_FRAGMENT
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/tcp.h>
-#include <linux/random.h>
-#include <linux/route.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv6.h>
-
-#include <net/sock.h>
-#include <net/snmp.h>
-
-#include <net/ipv6.h>
-#include <net/ndisc.h>
-#include <net/protocol.h>
-#include <net/ip6_route.h>
-#include <net/addrconf.h>
-#include <net/rawv6.h>
-#include <net/icmp.h>
-#include <net/xfrm.h>
-#include <net/checksum.h>
-#include <linux/mroute6.h>
-
-#define IP_IDENTS_SZ 2048u
-
-static atomic_t *ip_idents __read_mostly;
-static u32 *ip_tstamps __read_mostly;
-
-int __init ip6_output_init(void);
-void ip6_output_exit(void);
-
-/* In order to protect privacy, we add a perturbation to identifiers
- * if one generator is seldom used. This makes hard for an attacker
- * to infer how many packets were sent between two points in time.
- */
-static u32 rpl_ip_idents_reserve(u32 hash, int segs)
-{
- u32 *p_tstamp = ip_tstamps + hash % IP_IDENTS_SZ;
- atomic_t *p_id = ip_idents + hash % IP_IDENTS_SZ;
- u32 old = ACCESS_ONCE(*p_tstamp);
- u32 now = (u32)jiffies;
- u32 delta = 0;
-
- if (old != now && cmpxchg(p_tstamp, old, now) == old)
- delta = prandom_u32_max(now - old);
-
- return atomic_add_return(segs + delta, p_id) - segs;
-}
-
-static u32 rpl___ipv6_select_ident(struct net *net, u32 hashrnd,
- const struct in6_addr *dst,
- const struct in6_addr *src)
-{
- u32 hash, id;
-
- hash = __ipv6_addr_jhash(dst, hashrnd);
- hash = __ipv6_addr_jhash(src, hash);
- hash ^= net_hash_mix(net);
-
- /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve,
- * set the hight order instead thus minimizing possible future
- * collisions.
- */
- id = rpl_ip_idents_reserve(hash, 1);
- if (unlikely(!id))
- id = 1 << 31;
-
- return id;
-}
-
-static __be32 rpl_ipv6_select_ident(struct net *net,
- const struct in6_addr *daddr,
- const struct in6_addr *saddr)
-{
- static u32 ip6_idents_hashrnd __read_mostly;
- u32 id;
-
- net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
-
- id = rpl___ipv6_select_ident(net, ip6_idents_hashrnd, daddr, saddr);
- return htonl(id);
-}
-
-static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
-{
- to->pkt_type = from->pkt_type;
- to->priority = from->priority;
- to->protocol = from->protocol;
- skb_dst_drop(to);
- skb_dst_set(to, dst_clone(skb_dst(from)));
- to->dev = from->dev;
- to->mark = from->mark;
-
-#ifdef CONFIG_NET_SCHED
- to->tc_index = from->tc_index;
-#endif
- nf_copy(to, from);
- skb_copy_secmark(to, from);
-}
-
-#ifdef HAVE_IP_FRAGMENT_TAKES_SOCK
-#define OUTPUT(skb) output(skb->sk, skb)
-#else
-#define OUTPUT(skb) output(skb)
-#endif
-
-int ip6_fragment(struct sock *sk, struct sk_buff *skb,
- int (*output)(OVS_VPORT_OUTPUT_PARAMS))
-{
- struct sk_buff *frag;
- struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
- struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
- inet6_sk(skb->sk) : NULL;
- struct ipv6hdr *tmp_hdr;
- struct frag_hdr *fh;
- unsigned int mtu, hlen, left, len;
- int hroom, troom;
- __be32 frag_id;
- int ptr, offset = 0, err = 0;
- u8 *prevhdr, nexthdr = 0;
- struct net *net = dev_net(skb_dst(skb)->dev);
-
- hlen = ip6_find_1stfragopt(skb, &prevhdr);
- nexthdr = *prevhdr;
-
- mtu = ip6_skb_dst_mtu(skb);
-
- /* We must not fragment if the socket is set to force MTU discovery
- * or if the skb it not generated by a local socket.
- */
- if (unlikely(!skb->ignore_df && skb->len > mtu))
- goto fail_toobig;
-
- if (IP6CB(skb)->frag_max_size) {
- if (IP6CB(skb)->frag_max_size > mtu)
- goto fail_toobig;
-
- /* don't send fragments larger than what we received */
- mtu = IP6CB(skb)->frag_max_size;
- if (mtu < IPV6_MIN_MTU)
- mtu = IPV6_MIN_MTU;
- }
-
- if (np && np->frag_size < mtu) {
- if (np->frag_size)
- mtu = np->frag_size;
- }
- mtu -= hlen + sizeof(struct frag_hdr);
-
- frag_id = rpl_ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
- &ipv6_hdr(skb)->saddr);
-
- hroom = LL_RESERVED_SPACE(rt->dst.dev);
- if (skb_has_frag_list(skb)) {
- int first_len = skb_pagelen(skb);
- struct sk_buff *frag2;
-
- if (first_len - hlen > mtu ||
- ((first_len - hlen) & 7) ||
- skb_cloned(skb) ||
- skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
- goto slow_path;
-
- skb_walk_frags(skb, frag) {
- /* Correct geometry. */
- if (frag->len > mtu ||
- ((frag->len & 7) && frag->next) ||
- skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
- goto slow_path_clean;
-
- /* Partially cloned skb? */
- if (skb_shared(frag))
- goto slow_path_clean;
-
- BUG_ON(frag->sk);
- if (skb->sk) {
- frag->sk = skb->sk;
- frag->destructor = sock_wfree;
- }
- skb->truesize -= frag->truesize;
- }
-
- err = 0;
- offset = 0;
- /* BUILD HEADER */
-
- *prevhdr = NEXTHDR_FRAGMENT;
- tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
- if (!tmp_hdr) {
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGFAILS);
- err = -ENOMEM;
- goto fail;
- }
- frag = skb_shinfo(skb)->frag_list;
- skb_frag_list_init(skb);
-
- __skb_pull(skb, hlen);
- fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
- __skb_push(skb, hlen);
- skb_reset_network_header(skb);
- memcpy(skb_network_header(skb), tmp_hdr, hlen);
-
- fh->nexthdr = nexthdr;
- fh->reserved = 0;
- fh->frag_off = htons(IP6_MF);
- fh->identification = frag_id;
-
- first_len = skb_pagelen(skb);
- skb->data_len = first_len - skb_headlen(skb);
- skb->len = first_len;
- ipv6_hdr(skb)->payload_len = htons(first_len -
- sizeof(struct ipv6hdr));
-
- dst_hold(&rt->dst);
-
- for (;;) {
- /* Prepare header of the next frame,
- * before previous one went down. */
- if (frag) {
- frag->ip_summed = CHECKSUM_NONE;
- skb_reset_transport_header(frag);
- fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr));
- __skb_push(frag, hlen);
- skb_reset_network_header(frag);
- memcpy(skb_network_header(frag), tmp_hdr,
- hlen);
- offset += skb->len - hlen - sizeof(struct frag_hdr);
- fh->nexthdr = nexthdr;
- fh->reserved = 0;
- fh->frag_off = htons(offset);
- if (frag->next)
- fh->frag_off |= htons(IP6_MF);
- fh->identification = frag_id;
- ipv6_hdr(frag)->payload_len =
- htons(frag->len -
- sizeof(struct ipv6hdr));
- ip6_copy_metadata(frag, skb);
- }
-
- err = OUTPUT(skb);
- if (!err)
- IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
- IPSTATS_MIB_FRAGCREATES);
-
- if (err || !frag)
- break;
-
- skb = frag;
- frag = skb->next;
- skb->next = NULL;
- }
-
- kfree(tmp_hdr);
-
- if (err == 0) {
- IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
- IPSTATS_MIB_FRAGOKS);
- ip6_rt_put(rt);
- return 0;
- }
-
- kfree_skb_list(frag);
-
- IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
- IPSTATS_MIB_FRAGFAILS);
- ip6_rt_put(rt);
- return err;
-
-slow_path_clean:
- skb_walk_frags(skb, frag2) {
- if (frag2 == frag)
- break;
- frag2->sk = NULL;
- frag2->destructor = NULL;
- skb->truesize += frag2->truesize;
- }
- }
-
-slow_path:
- if ((skb->ip_summed == CHECKSUM_PARTIAL) &&
- skb_checksum_help(skb))
- goto fail;
-
- left = skb->len - hlen; /* Space per frame */
- ptr = hlen; /* Where to start from */
-
- /*
- * Fragment the datagram.
- */
-
- *prevhdr = NEXTHDR_FRAGMENT;
- troom = rt->dst.dev->needed_tailroom;
-
- /*
- * Keep copying data until we run out.
- */
- while (left > 0) {
- len = left;
- /* IF: it doesn't fit, use 'mtu' - the data space left */
- if (len > mtu)
- len = mtu;
- /* IF: we are not sending up to and including the packet end
- then align the next start on an eight byte boundary */
- if (len < left) {
- len &= ~7;
- }
-
- /* Allocate buffer */
- frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
- hroom + troom, GFP_ATOMIC);
- if (!frag) {
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGFAILS);
- err = -ENOMEM;
- goto fail;
- }
-
- /*
- * Set up data on packet
- */
-
- ip6_copy_metadata(frag, skb);
- skb_reserve(frag, hroom);
- skb_put(frag, len + hlen + sizeof(struct frag_hdr));
- skb_reset_network_header(frag);
- fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
- frag->transport_header = (frag->network_header + hlen +
- sizeof(struct frag_hdr));
-
- /*
- * Charge the memory for the fragment to any owner
- * it might possess
- */
- if (skb->sk)
- skb_set_owner_w(frag, skb->sk);
-
- /*
- * Copy the packet header into the new buffer.
- */
- skb_copy_from_linear_data(skb, skb_network_header(frag), hlen);
-
- /*
- * Build fragment header.
- */
- fh->nexthdr = nexthdr;
- fh->reserved = 0;
- fh->identification = frag_id;
-
- /*
- * Copy a block of the IP datagram.
- */
- BUG_ON(skb_copy_bits(skb, ptr, skb_transport_header(frag),
- len));
- left -= len;
-
- fh->frag_off = htons(offset);
- if (left > 0)
- fh->frag_off |= htons(IP6_MF);
- ipv6_hdr(frag)->payload_len = htons(frag->len -
- sizeof(struct ipv6hdr));
-
- ptr += len;
- offset += len;
-
- /*
- * Put this fragment into the sending queue.
- */
- err = OUTPUT(frag);
- if (err)
- goto fail;
-
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGCREATES);
- }
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGOKS);
- consume_skb(skb);
- return err;
-
-fail_toobig:
- if (skb->sk && dst_allfrag(skb_dst(skb)))
- sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
-
- skb->dev = skb_dst(skb)->dev;
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- err = -EMSGSIZE;
-
-fail:
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGFAILS);
- kfree_skb(skb);
- return err;
-}
-#undef OUTPUT
-
-int __init ip6_output_init(void)
-{
- ip_idents = kmalloc(IP_IDENTS_SZ * sizeof(*ip_idents), GFP_KERNEL);
- if (!ip_idents) {
- pr_warn("IP: failed to allocate ip_idents\n");
- goto error;
- }
-
- prandom_bytes(ip_idents, IP_IDENTS_SZ * sizeof(*ip_idents));
-
- ip_tstamps = kcalloc(IP_IDENTS_SZ, sizeof(*ip_tstamps), GFP_KERNEL);
- if (!ip_tstamps) {
- pr_warn("IP: failed to allocate ip_tstamps\n");
- goto error_ip_idents_free;
- }
-
- return 0;
-
-error_ip_idents_free:
- kfree(ip_idents);
-error:
- return -ENOMEM;
-}
-
-void ip6_output_exit(void)
-{
- kfree(ip_tstamps);
- kfree(ip_idents);
-}
-
-#endif /* !HAVE_NF_IPV6_OPS_FRAGMENT */
diff --git a/datapath/linux/compat/ip6_tunnel.c b/datapath/linux/compat/ip6_tunnel.c
deleted file mode 100644
index 984a51bfb..000000000
--- a/datapath/linux/compat/ip6_tunnel.c
+++ /dev/null
@@ -1,2213 +0,0 @@
-/*
- * IPv6 tunneling device
- * Linux INET6 implementation
- *
- * Authors:
- * Ville Nuorvala <vnuorval@tcs.hut.fi>
- * Yasuyuki Kozakai <kozakai@linux-ipv6.org>
- *
- * Based on:
- * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
- *
- * RFC 2473
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#ifndef USE_UPSTREAM_TUNNEL
-#include <linux/module.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/sockios.h>
-#include <linux/icmp.h>
-#include <linux/if.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/net.h>
-#include <linux/in6.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/icmpv6.h>
-#include <linux/init.h>
-#include <linux/route.h>
-#include <linux/rtnetlink.h>
-#include <linux/netfilter_ipv6.h>
-#include <linux/slab.h>
-#include <linux/hash.h>
-#include <linux/etherdevice.h>
-
-#include <linux/uaccess.h>
-#include <linux/atomic.h>
-
-#include <net/icmp.h>
-#include <net/ip.h>
-#include <net/ip_tunnels.h>
-#include <net/ipv6.h>
-#include <net/ip6_route.h>
-#include <net/addrconf.h>
-#include <net/ip6_tunnel.h>
-#include <net/xfrm.h>
-#include <net/dsfield.h>
-#include <net/inet_ecn.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include "gso.h"
-#include <net/dst_metadata.h>
-
-#include "vport-netdev.h"
-
-#define IP6_TUNNEL_HASH_SIZE_SHIFT 5
-#define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT)
-
-enum {
-#ifndef HAVE_IFLA_IPTUN_ENCAP_TYPE
- IFLA_IPTUN_ENCAP_TYPE = IFLA_IPTUN_6RD_RELAY_PREFIXLEN + 1,
- IFLA_IPTUN_ENCAP_FLAGS,
- IFLA_IPTUN_ENCAP_SPORT,
- IFLA_IPTUN_ENCAP_DPORT,
-#endif
-#ifndef HAVE_IFLA_IPTUN_COLLECT_METADATA
- IFLA_IPTUN_COLLECT_METADATA = IFLA_IPTUN_ENCAP_DPORT + 1,
-#endif
-#ifndef HAVE_IFLA_IPTUN_FWMARK
- IFLA_IPTUN_FWMARK = IFLA_IPTUN_COLLECT_METADATA + 1,
-#endif
- RPL__IFLA_IPTUN_MAX = IFLA_IPTUN_FWMARK + 1,
-};
-
-#define RPL_IFLA_IPTUN_MAX RPL__IFLA_IPTUN_MAX
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
-/* Undef the one from ip_tunnels.h - we need a different one here */
-/* At least I think... */
-#undef iptunnel_handle_offloads
-/* gre_handle_offloads() has different return type on older kernsl. */
-static void gre_nop_fix(struct sk_buff *skb) { }
-
-static void gre_csum_fix(struct sk_buff *skb)
-{
- struct gre_base_hdr *greh;
- __be32 *options;
- int gre_offset = skb_transport_offset(skb);
-
- greh = (struct gre_base_hdr *)skb_transport_header(skb);
- options = ((__be32 *)greh + 1);
-
- *options = 0;
- *(__sum16 *)options = csum_fold(skb_checksum(skb, gre_offset,
- skb->len - gre_offset, 0));
-}
-
-#define iptunnel_handle_offloads rpl__iptunnel_handle_offloads
-static int rpl__iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum,
- int __always_unused ignored)
-{
- int type = gre_csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE;
- gso_fix_segment_t fix_segment;
-
- if (gre_csum)
- fix_segment = gre_csum_fix;
- else
- fix_segment = gre_nop_fix;
-
- return ovs_iptunnel_handle_offloads(skb, type, fix_segment);
-}
-
-#endif
-static bool log_ecn_error = true;
-
-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
-{
- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
-
- return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
-}
-
-static int ip6_tnl_dev_init(struct net_device *dev);
-static void ip6_tnl_dev_setup(struct net_device *dev);
-static struct rtnl_link_ops ip6_link_ops __read_mostly;
-
-static unsigned int ip6_tnl_net_id __read_mostly;
-struct ip6_tnl_net {
- /* the IPv6 tunnel fallback device */
- struct net_device *fb_tnl_dev;
- /* lists for storing tunnels in use */
- struct ip6_tnl __rcu *tnls_r_l[IP6_TUNNEL_HASH_SIZE];
- struct ip6_tnl __rcu *tnls_wc[1];
- struct ip6_tnl __rcu **tnls[2];
- struct ip6_tnl __rcu *collect_md_tun;
-};
-
-static struct net_device_stats *ip6_get_stats(struct net_device *dev)
-{
- struct pcpu_sw_netstats tmp, sum = { 0 };
- int i;
-
- for_each_possible_cpu(i) {
- unsigned int start;
- const struct pcpu_sw_netstats *tstats =
- per_cpu_ptr(dev->tstats, i);
-
- do {
- start = u64_stats_fetch_begin_irq(&tstats->syncp);
- tmp.rx_packets = tstats->rx_packets;
- tmp.rx_bytes = tstats->rx_bytes;
- tmp.tx_packets = tstats->tx_packets;
- tmp.tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
-
- sum.rx_packets += tmp.rx_packets;
- sum.rx_bytes += tmp.rx_bytes;
- sum.tx_packets += tmp.tx_packets;
- sum.tx_bytes += tmp.tx_bytes;
- }
- dev->stats.rx_packets = sum.rx_packets;
- dev->stats.rx_bytes = sum.rx_bytes;
- dev->stats.tx_packets = sum.tx_packets;
- dev->stats.tx_bytes = sum.tx_bytes;
- return &dev->stats;
-}
-
-/**
- * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
- * @remote: the address of the tunnel exit-point
- * @local: the address of the tunnel entry-point
- *
- * Return:
- * tunnel matching given end-points if found,
- * else fallback tunnel if its device is up,
- * else %NULL
- **/
-
-#define for_each_ip6_tunnel_rcu(start) \
- for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
-
-static struct ip6_tnl *
-ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
-{
- unsigned int hash = HASH(remote, local);
- struct ip6_tnl *t;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- struct in6_addr any;
-
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
- if (ipv6_addr_equal(local, &t->parms.laddr) &&
- ipv6_addr_equal(remote, &t->parms.raddr) &&
- (t->dev->flags & IFF_UP))
- return t;
- }
-
- memset(&any, 0, sizeof(any));
- hash = HASH(&any, local);
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
- if (ipv6_addr_equal(local, &t->parms.laddr) &&
- ipv6_addr_any(&t->parms.raddr) &&
- (t->dev->flags & IFF_UP))
- return t;
- }
-
- hash = HASH(remote, &any);
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
- if (ipv6_addr_equal(remote, &t->parms.raddr) &&
- ipv6_addr_any(&t->parms.laddr) &&
- (t->dev->flags & IFF_UP))
- return t;
- }
-
- t = rcu_dereference(ip6n->collect_md_tun);
- if (t && t->dev->flags & IFF_UP)
- return t;
-
- t = rcu_dereference(ip6n->tnls_wc[0]);
- if (t && (t->dev->flags & IFF_UP))
- return t;
-
- return NULL;
-}
-
-/**
- * ip6_tnl_bucket - get head of list matching given tunnel parameters
- * @p: parameters containing tunnel end-points
- *
- * Description:
- * ip6_tnl_bucket() returns the head of the list matching the
- * &struct in6_addr entries laddr and raddr in @p.
- *
- * Return: head of IPv6 tunnel list
- **/
-
-static struct ip6_tnl __rcu **
-ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p)
-{
- const struct in6_addr *remote = &p->raddr;
- const struct in6_addr *local = &p->laddr;
- unsigned int h = 0;
- int prio = 0;
-
- if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
- prio = 1;
- h = HASH(remote, local);
- }
- return &ip6n->tnls[prio][h];
-}
-
-/**
- * ip6_tnl_link - add tunnel to hash table
- * @t: tunnel to be added
- **/
-
-static void
-ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
-{
- struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
-
- if (t->parms.collect_md)
- rcu_assign_pointer(ip6n->collect_md_tun, t);
- rcu_assign_pointer(t->next , rtnl_dereference(*tp));
- rcu_assign_pointer(*tp, t);
-}
-
-/**
- * ip6_tnl_unlink - remove tunnel from hash table
- * @t: tunnel to be removed
- **/
-
-static void
-ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
-{
- struct ip6_tnl __rcu **tp;
- struct ip6_tnl *iter;
-
- if (t->parms.collect_md)
- rcu_assign_pointer(ip6n->collect_md_tun, NULL);
-
- for (tp = ip6_tnl_bucket(ip6n, &t->parms);
- (iter = rtnl_dereference(*tp)) != NULL;
- tp = &iter->next) {
- if (t == iter) {
- rcu_assign_pointer(*tp, t->next);
- break;
- }
- }
-}
-
-#ifdef HAVE_NEEDS_FREE_NETDEV
-static void ip6_dev_free(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
-
- gro_cells_destroy(&t->gro_cells);
- dst_cache_destroy(&t->dst_cache);
- free_percpu(dev->tstats);
-}
-
-#endif
-static int ip6_tnl_create2(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct net *net = dev_net(dev);
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- int err;
-
- t = netdev_priv(dev);
-
- dev->rtnl_link_ops = &ip6_link_ops;
- err = register_netdevice(dev);
- if (err < 0)
- goto out;
-
- strcpy(t->parms.name, dev->name);
-
- dev_hold(dev);
- ip6_tnl_link(ip6n, t);
- return 0;
-
-out:
- return err;
-}
-
-/**
- * ip6_tnl_create - create a new tunnel
- * @p: tunnel parameters
- * @pt: pointer to new tunnel
- *
- * Description:
- * Create tunnel matching given parameters.
- *
- * Return:
- * created tunnel or error pointer
- **/
-
-static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
-{
- struct net_device *dev;
- struct ip6_tnl *t;
- char name[IFNAMSIZ];
- int err = -ENOMEM;
-
- if (p->name[0])
- strlcpy(name, p->name, IFNAMSIZ);
- else
- strlcpy(name, "ovs-ip6tnl%d", IFNAMSIZ);
-
- dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
- ip6_tnl_dev_setup);
- if (!dev)
- goto failed;
-
- dev_net_set(dev, net);
-
- t = netdev_priv(dev);
- t->parms = *p;
- t->net = dev_net(dev);
- err = ip6_tnl_create2(dev);
- if (err < 0)
- goto failed_free;
-
- return t;
-
-failed_free:
- free_netdev(dev);
-failed:
- return ERR_PTR(err);
-}
-
-/**
- * ip6_tnl_locate - find or create tunnel matching given parameters
- * @p: tunnel parameters
- * @create: != 0 if allowed to create new tunnel if no match found
- *
- * Description:
- * ip6_tnl_locate() first tries to locate an existing tunnel
- * based on @parms. If this is unsuccessful, but @create is set a new
- * tunnel device is created and registered for use.
- *
- * Return:
- * matching tunnel or error pointer
- **/
-
-static struct ip6_tnl *ip6_tnl_locate(struct net *net,
- struct __ip6_tnl_parm *p, int create)
-{
- const struct in6_addr *remote = &p->raddr;
- const struct in6_addr *local = &p->laddr;
- struct ip6_tnl __rcu **tp;
- struct ip6_tnl *t;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-
- for (tp = ip6_tnl_bucket(ip6n, p);
- (t = rtnl_dereference(*tp)) != NULL;
- tp = &t->next) {
- if (ipv6_addr_equal(local, &t->parms.laddr) &&
- ipv6_addr_equal(remote, &t->parms.raddr)) {
- if (create)
- return ERR_PTR(-EEXIST);
-
- return t;
- }
- }
- if (!create)
- return ERR_PTR(-ENODEV);
- return ip6_tnl_create(net, p);
-}
-
-/**
- * ip6_tnl_dev_uninit - tunnel device uninitializer
- * @dev: the device to be destroyed
- *
- * Description:
- * ip6_tnl_dev_uninit() removes tunnel from its list
- **/
-
-static void
-ip6_tnl_dev_uninit(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct net *net = t->net;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-
- if (dev == ip6n->fb_tnl_dev)
- RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
- else
- ip6_tnl_unlink(ip6n, t);
- dst_cache_reset(&t->dst_cache);
- dev_put(dev);
-}
-
-/**
- * parse_tvl_tnl_enc_lim - handle encapsulation limit option
- * @skb: received socket buffer
- *
- * Return:
- * 0 if none was found,
- * else index to encapsulation limit
- **/
-
-__u16 rpl_ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
-{
- const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
- unsigned int nhoff = raw - skb->data;
- unsigned int off = nhoff + sizeof(*ipv6h);
- u8 next, nexthdr = ipv6h->nexthdr;
-
- while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
- struct ipv6_opt_hdr *hdr;
- u16 optlen;
-
- if (!pskb_may_pull(skb, off + sizeof(*hdr)))
- break;
-
- hdr = (struct ipv6_opt_hdr *)(skb->data + off);
- if (nexthdr == NEXTHDR_FRAGMENT) {
- struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
- if (frag_hdr->frag_off)
- break;
- optlen = 8;
- } else if (nexthdr == NEXTHDR_AUTH) {
- optlen = (hdr->hdrlen + 2) << 2;
- } else {
- optlen = ipv6_optlen(hdr);
- }
- /* cache hdr->nexthdr, since pskb_may_pull() might
- * invalidate hdr
- */
- next = hdr->nexthdr;
- if (nexthdr == NEXTHDR_DEST) {
- u16 i = 2;
-
- /* Remember : hdr is no longer valid at this point. */
- if (!pskb_may_pull(skb, off + optlen))
- break;
-
- while (1) {
- struct ipv6_tlv_tnl_enc_lim *tel;
-
- /* No more room for encapsulation limit */
- if (i + sizeof(*tel) > optlen)
- break;
-
- tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i);
- /* return index of option if found and valid */
- if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
- tel->length == 1)
- return i + off - nhoff;
- /* else jump to next option */
- if (tel->type)
- i += tel->length + 2;
- else
- i++;
- }
- }
- nexthdr = next;
- off += optlen;
- }
- return 0;
-}
-
-static int
-ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
- u8 type, u8 code, int offset, __be32 info)
-{
- return PACKET_REJECT;
-}
-
-static int
-ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
- u8 type, u8 code, int offset, __be32 info)
-{
- return PACKET_REJECT;
-}
-
-static int ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
- const struct ipv6hdr *ipv6h,
- struct sk_buff *skb)
-{
- __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
-
- if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
- ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
-
- return IP6_ECN_decapsulate(ipv6h, skb);
-}
-
-static int ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
- const struct ipv6hdr *ipv6h,
- struct sk_buff *skb)
-{
- if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
- ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb));
-
- return IP6_ECN_decapsulate(ipv6h, skb);
-}
-
-__u32 rpl_ip6_tnl_get_cap(struct ip6_tnl *t,
- const struct in6_addr *laddr,
- const struct in6_addr *raddr)
-{
- struct __ip6_tnl_parm *p = &t->parms;
- int ltype = ipv6_addr_type(laddr);
- int rtype = ipv6_addr_type(raddr);
- __u32 flags = 0;
-
- if (ltype == IPV6_ADDR_ANY || rtype == IPV6_ADDR_ANY) {
- flags = IP6_TNL_F_CAP_PER_PACKET;
- } else if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
- rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
- !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
- (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) {
- if (ltype&IPV6_ADDR_UNICAST)
- flags |= IP6_TNL_F_CAP_XMIT;
- if (rtype&IPV6_ADDR_UNICAST)
- flags |= IP6_TNL_F_CAP_RCV;
- }
- return flags;
-}
-
-/* called with rcu_read_lock() */
-int rpl_ip6_tnl_rcv_ctl(struct ip6_tnl *t,
- const struct in6_addr *laddr,
- const struct in6_addr *raddr)
-{
- struct __ip6_tnl_parm *p = &t->parms;
- int ret = 0;
- struct net *net = t->net;
-
- if ((p->flags & IP6_TNL_F_CAP_RCV) ||
- ((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
- (rpl_ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_RCV))) {
- struct net_device *ldev = NULL;
-
- if (p->link)
- ldev = dev_get_by_index_rcu(net, p->link);
-
- if ((ipv6_addr_is_multicast(laddr) ||
- likely(ipv6_chk_addr(net, laddr, ldev, 0))) &&
- ((p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) ||
- likely(!ipv6_chk_addr(net, raddr, NULL, 0))))
- ret = 1;
- }
- return ret;
-}
-
-static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
- const struct tnl_ptk_info *tpi,
- struct metadata_dst *tun_dst,
- int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
- const struct ipv6hdr *ipv6h,
- struct sk_buff *skb),
- bool log_ecn_err)
-{
- struct pcpu_sw_netstats *tstats;
-
- if ((!(tpi->flags & TUNNEL_CSUM) &&
- (tunnel->parms.i_flags & TUNNEL_CSUM)) ||
- ((tpi->flags & TUNNEL_CSUM) &&
- !(tunnel->parms.i_flags & TUNNEL_CSUM))) {
- tunnel->dev->stats.rx_crc_errors++;
- tunnel->dev->stats.rx_errors++;
- goto drop;
- }
-
- if (tunnel->parms.i_flags & TUNNEL_SEQ) {
- if (!(tpi->flags & TUNNEL_SEQ) ||
- (tunnel->i_seqno &&
- (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {
- tunnel->dev->stats.rx_fifo_errors++;
- tunnel->dev->stats.rx_errors++;
- goto drop;
- }
- tunnel->i_seqno = ntohl(tpi->seq) + 1;
- }
-
-#if 0
- /* Warning: All skb pointers will be invalidated! */
- if (tunnel->dev->type == ARPHRD_ETHER) {
- if (!pskb_may_pull(skb, ETH_HLEN)) {
- tunnel->dev->stats.rx_length_errors++;
- tunnel->dev->stats.rx_errors++;
- goto drop;
- }
-
- ipv6h = ipv6_hdr(skb);
- skb->protocol = eth_type_trans(skb, tunnel->dev);
- skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
- } else {
- skb->dev = tunnel->dev;
- }
-
- skb_reset_network_header(skb);
- memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
-
- __skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
-
- err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
- if (unlikely(err)) {
- if (log_ecn_err)
- net_info_ratelimited("non-ECT from %pI6 with DS=%#x\n",
- &ipv6h->saddr,
- ipv6_get_dsfield(ipv6h));
- if (err > 1) {
- ++tunnel->dev->stats.rx_frame_errors;
- ++tunnel->dev->stats.rx_errors;
- goto drop;
- }
- }
-
-#endif
- tstats = this_cpu_ptr(tunnel->dev->tstats);
- u64_stats_update_begin(&tstats->syncp);
- tstats->rx_packets++;
- tstats->rx_bytes += skb->len;
- u64_stats_update_end(&tstats->syncp);
-
- skb_reset_mac_header(skb);
- skb_scrub_packet(skb, false);
- skb->protocol = eth_type_trans(skb, tunnel->dev);
- skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
-
- ovs_skb_dst_set(skb, (struct dst_entry *)tun_dst);
- netdev_port_receive(skb, &tun_dst->u.tun_info);
- return 0;
-
-drop:
- /* In OVS case caller will free tun_dst and skb */
-#if 0
- if (tun_dst)
- dst_release((struct dst_entry *)tun_dst);
- kfree_skb(skb);
-#endif
- return 0;
-}
-
-int rpl_ip6_tnl_rcv(struct ip6_tnl *t, struct sk_buff *skb,
- const struct tnl_ptk_info *tpi,
- struct metadata_dst *tun_dst,
- bool log_ecn_err)
-{
- return __ip6_tnl_rcv(t, skb, tpi, tun_dst, ip6ip6_dscp_ecn_decapsulate,
- log_ecn_err);
-}
-
-static const struct tnl_ptk_info tpi_v6 = {
- /* no tunnel info required for ipxip6. */
- .proto = htons(ETH_P_IPV6),
-};
-
-static const struct tnl_ptk_info tpi_v4 = {
- /* no tunnel info required for ipxip6. */
- .proto = htons(ETH_P_IP),
-};
-
-static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
- const struct tnl_ptk_info *tpi,
- int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
- const struct ipv6hdr *ipv6h,
- struct sk_buff *skb))
-{
- struct ip6_tnl *t;
- const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- struct metadata_dst *tun_dst = NULL;
- int ret = -1;
-
- rcu_read_lock();
- t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
-
- if (t) {
- u8 tproto = READ_ONCE(t->parms.proto);
-
- if (tproto != ipproto && tproto != 0)
- goto drop;
- if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
- goto drop;
- if (!rpl_ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr))
- goto drop;
- if (iptunnel_pull_header(skb, 0, tpi->proto, false))
- goto drop;
- if (t->parms.collect_md) {
- ovs_ipv6_tun_rx_dst(tun_dst, skb, 0, 0, 0);
- if (!tun_dst)
- goto drop;
- }
- ret = __ip6_tnl_rcv(t, skb, tpi, tun_dst, dscp_ecn_decapsulate,
- log_ecn_error);
- }
-
- rcu_read_unlock();
-
- return ret;
-
-drop:
- rcu_read_unlock();
- kfree_skb(skb);
- return 0;
-}
-
-static int ip4ip6_rcv(struct sk_buff *skb)
-{
- return ipxip6_rcv(skb, IPPROTO_IPIP, &tpi_v4,
- ip4ip6_dscp_ecn_decapsulate);
-}
-
-static int ip6ip6_rcv(struct sk_buff *skb)
-{
- return ipxip6_rcv(skb, IPPROTO_IPV6, &tpi_v6,
- ip6ip6_dscp_ecn_decapsulate);
-}
-
-struct ipv6_tel_txoption {
- struct ipv6_txoptions ops;
- __u8 dst_opt[8];
-};
-
-static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
-{
- memset(opt, 0, sizeof(struct ipv6_tel_txoption));
-
- opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT;
- opt->dst_opt[3] = 1;
- opt->dst_opt[4] = encap_limit;
- opt->dst_opt[5] = IPV6_TLV_PADN;
- opt->dst_opt[6] = 1;
-
- opt->ops.dst1opt = (struct ipv6_opt_hdr *) opt->dst_opt;
- opt->ops.opt_nflen = 8;
-}
-
-/**
- * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
- * @t: the outgoing tunnel device
- * @hdr: IPv6 header from the incoming packet
- *
- * Description:
- * Avoid trivial tunneling loop by checking that tunnel exit-point
- * doesn't match source of incoming packet.
- *
- * Return:
- * 1 if conflict,
- * 0 else
- **/
-
-static inline bool
-ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
-{
- return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
-}
-
-int rpl_ip6_tnl_xmit_ctl(struct ip6_tnl *t,
- const struct in6_addr *laddr,
- const struct in6_addr *raddr)
-{
- struct __ip6_tnl_parm *p = &t->parms;
- int ret = 0;
- struct net *net = t->net;
-
- if (t->parms.collect_md)
- return 1;
-
- if ((p->flags & IP6_TNL_F_CAP_XMIT) ||
- ((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
- (rpl_ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_XMIT))) {
- struct net_device *ldev = NULL;
-
- rcu_read_lock();
- if (p->link)
- ldev = dev_get_by_index_rcu(net, p->link);
-
- if (unlikely(!ipv6_chk_addr(net, laddr, ldev, 0)))
- pr_warn("%s xmit: Local address not yet configured!\n",
- p->name);
- else if (!(p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) &&
- !ipv6_addr_is_multicast(raddr) &&
- unlikely(ipv6_chk_addr(net, raddr, NULL, 0)))
- pr_warn("%s xmit: Routing loop! Remote address found on this node!\n",
- p->name);
- else
- ret = 1;
- rcu_read_unlock();
- }
- return ret;
-}
-
-static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto,
- u8 type, struct ipv6_opt_hdr *opt)
-{
- struct ipv6_opt_hdr *h =
- (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
-
- memcpy(h, opt, ipv6_optlen(opt));
- h->nexthdr = *proto;
- *proto = type;
-}
-
-void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
- u8 *proto)
-{
- if (opt->dst1opt)
- ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
-}
-
-/**
- * ip6_tnl_xmit - encapsulate packet and send
- * @skb: the outgoing socket buffer
- * @dev: the outgoing tunnel device
- * @dsfield: dscp code for outer header
- * @fl6: flow of tunneled packet
- * @encap_limit: encapsulation limit
- * @pmtu: Path MTU is stored if packet is too big
- * @proto: next header value
- *
- * Description:
- * Build new header and do some sanity checks on the packet before sending
- * it.
- *
- * Return:
- * 0 on success
- * -1 fail
- * %-EMSGSIZE message too big. return mtu in this case.
- **/
-
-int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
- struct flowi6 *fl6, int encap_limit, __u32 *pmtu,
- __u8 proto)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct net *net = t->net;
- struct net_device_stats *stats = &t->dev->stats;
- struct ipv6hdr *ipv6h;
- struct ipv6_tel_txoption opt;
- struct dst_entry *dst = NULL, *ndst = NULL;
- struct net_device *tdev;
- int mtu;
- unsigned int eth_hlen = t->dev->type == ARPHRD_ETHER ? ETH_HLEN : 0;
- unsigned int psh_hlen = sizeof(struct ipv6hdr) + t->encap_hlen;
- unsigned int max_headroom = psh_hlen;
- bool use_cache = false;
- u8 hop_limit;
- int err = -1;
-
- if (t->parms.collect_md) {
- hop_limit = skb_tunnel_info(skb)->key.ttl;
- goto route_lookup;
- } else {
- hop_limit = t->parms.hop_limit;
- }
-
- /* NBMA tunnel */
- if (ipv6_addr_any(&t->parms.raddr)) {
- if (skb->protocol == htons(ETH_P_IPV6)) {
- struct in6_addr *addr6;
- struct neighbour *neigh;
- int addr_type;
-
- if (!skb_dst(skb))
- goto tx_err_link_failure;
-
- neigh = dst_neigh_lookup(skb_dst(skb),
- &ipv6_hdr(skb)->daddr);
- if (!neigh)
- goto tx_err_link_failure;
-
- addr6 = (struct in6_addr *)&neigh->primary_key;
- addr_type = ipv6_addr_type(addr6);
-
- if (addr_type == IPV6_ADDR_ANY)
- addr6 = &ipv6_hdr(skb)->daddr;
-
- memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
- neigh_release(neigh);
- }
- } else if (t->parms.proto != 0 && !(t->parms.flags &
- (IP6_TNL_F_USE_ORIG_TCLASS |
- IP6_TNL_F_USE_ORIG_FWMARK))) {
- /* enable the cache only if neither the outer protocol nor the
- * routing decision depends on the current inner header value
- */
- use_cache = true;
- }
-
- if (use_cache)
- dst = dst_cache_get(&t->dst_cache);
-
- if (!rpl_ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
- goto tx_err_link_failure;
-
- if (!dst) {
-route_lookup:
- /* add dsfield to flowlabel for route lookup */
- fl6->flowlabel = ip6_make_flowinfo(dsfield, fl6->flowlabel);
-
- dst = ip6_route_output(net, NULL, fl6);
-
- if (dst->error)
- goto tx_err_link_failure;
- dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
- if (IS_ERR(dst)) {
- err = PTR_ERR(dst);
- dst = NULL;
- goto tx_err_link_failure;
- }
- if (t->parms.collect_md &&
- ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev,
- &fl6->daddr, 0, &fl6->saddr))
- goto tx_err_link_failure;
- ndst = dst;
- }
-
- tdev = dst->dev;
-
- if (tdev == dev) {
- stats->collisions++;
- net_warn_ratelimited("%s: Local routing loop detected!\n",
- t->parms.name);
- goto tx_err_dst_release;
- }
- mtu = dst_mtu(dst) - eth_hlen - psh_hlen - t->tun_hlen;
- if (encap_limit >= 0) {
- max_headroom += 8;
- mtu -= 8;
- }
- if (skb->protocol == htons(ETH_P_IPV6)) {
- if (mtu < IPV6_MIN_MTU)
- mtu = IPV6_MIN_MTU;
- } else if (mtu < 576) {
- mtu = 576;
- }
-
-// FIX ME
-// skb_dst_update_pmtu(skb, mtu);
- if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) {
- *pmtu = mtu;
- err = -EMSGSIZE;
- goto tx_err_dst_release;
- }
-
- if (t->err_count > 0) {
- if (time_before(jiffies,
- t->err_time + IP6TUNNEL_ERR_TIMEO)) {
- t->err_count--;
-
- dst_link_failure(skb);
- } else {
- t->err_count = 0;
- }
- }
-
- skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
-
- /*
- * Okay, now see if we can stuff it in the buffer as-is.
- */
- max_headroom += LL_RESERVED_SPACE(tdev);
-
- if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
- (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
- struct sk_buff *new_skb;
-
- new_skb = skb_realloc_headroom(skb, max_headroom);
- if (!new_skb)
- goto tx_err_dst_release;
-
- if (skb->sk)
- skb_set_owner_w(new_skb, skb->sk);
- consume_skb(skb);
- skb = new_skb;
- }
-
- if (t->parms.collect_md) {
- if (t->encap.type != TUNNEL_ENCAP_NONE)
- goto tx_err_dst_release;
- } else {
- if (use_cache && ndst)
- dst_cache_set_ip6(&t->dst_cache, ndst, &fl6->saddr);
- }
- skb_dst_set(skb, dst);
-
- if (encap_limit >= 0) {
- init_tel_txopt(&opt, encap_limit);
- ipv6_push_frag_opts(skb, &opt.ops, &proto);
- }
- hop_limit = hop_limit ? : ip6_dst_hoplimit(dst);
-
- /* Calculate max headroom for all the headers and adjust
- * needed_headroom if necessary.
- */
- max_headroom = LL_RESERVED_SPACE(dst->dev) + sizeof(struct ipv6hdr)
- + dst->header_len + t->hlen;
- if (max_headroom > dev->needed_headroom)
- dev->needed_headroom = max_headroom;
-
- err = ip6_tnl_encap(skb, t, &proto, fl6);
- if (err)
- return err;
-
- skb_push(skb, sizeof(struct ipv6hdr));
- skb_reset_network_header(skb);
- ipv6h = ipv6_hdr(skb);
- ip6_flow_hdr(ipv6h, dsfield,
- ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
- ipv6h->hop_limit = hop_limit;
- ipv6h->nexthdr = proto;
- ipv6h->saddr = fl6->saddr;
- ipv6h->daddr = fl6->daddr;
- ip6tunnel_xmit(NULL, skb, dev);
- return 0;
-tx_err_link_failure:
- stats->tx_carrier_errors++;
- dst_link_failure(skb);
-tx_err_dst_release:
- dst_release(dst);
- return err;
-}
-EXPORT_SYMBOL(ip6_tnl_xmit);
-
-static inline int
-ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- const struct iphdr *iph = ip_hdr(skb);
- int encap_limit = -1;
- struct flowi6 fl6;
- __u8 dsfield;
- __u32 mtu;
- u8 tproto;
- int err;
-
- memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
-
- tproto = READ_ONCE(t->parms.proto);
- if (tproto != IPPROTO_IPIP && tproto != 0)
- return -1;
-
- if (t->parms.collect_md) {
- struct ip_tunnel_info *tun_info;
- const struct ip_tunnel_key *key;
-
- tun_info = skb_tunnel_info(skb);
- if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
- ip_tunnel_info_af(tun_info) != AF_INET6))
- return -1;
- key = &tun_info->key;
- memset(&fl6, 0, sizeof(fl6));
- fl6.flowi6_proto = IPPROTO_IPIP;
- fl6.daddr = key->u.ipv6.dst;
- fl6.flowlabel = key->label;
- dsfield = key->tos;
- } else {
- if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- encap_limit = t->parms.encap_limit;
-
- memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
- fl6.flowi6_proto = IPPROTO_IPIP;
-
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- dsfield = ipv4_get_dsfield(iph);
- else
- dsfield = ip6_tclass(t->parms.flowinfo);
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
- fl6.flowi6_mark = skb->mark;
- else
- fl6.flowi6_mark = t->parms.fwmark;
- }
-
-// FIX ME
-// fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
-
- if (iptunnel_handle_offloads(skb, true, SKB_GSO_IPXIP6))
- return -1;
-
- dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph));
-
- skb_set_inner_ipproto(skb, IPPROTO_IPIP);
-
- err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
- IPPROTO_IPIP);
- if (err != 0) {
- /* XXX: send ICMP error even if DF is not set. */
- if (err == -EMSGSIZE)
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
- htonl(mtu));
- return -1;
- }
-
- return 0;
-}
-
-static inline int
-ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- int encap_limit = -1;
- __u16 offset;
- struct flowi6 fl6;
- __u8 dsfield;
- __u32 mtu;
- u8 tproto;
- int err;
-
- tproto = READ_ONCE(t->parms.proto);
- if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
- ip6_tnl_addr_conflict(t, ipv6h))
- return -1;
-
- if (t->parms.collect_md) {
- struct ip_tunnel_info *tun_info;
- const struct ip_tunnel_key *key;
-
- tun_info = skb_tunnel_info(skb);
- if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
- ip_tunnel_info_af(tun_info) != AF_INET6))
- return -1;
- key = &tun_info->key;
- memset(&fl6, 0, sizeof(fl6));
- fl6.flowi6_proto = IPPROTO_IPV6;
- fl6.daddr = key->u.ipv6.dst;
- fl6.flowlabel = key->label;
- dsfield = key->tos;
- } else {
- offset = rpl_ip6_tnl_parse_tlv_enc_lim(skb,
- skb_network_header(skb));
- /*
- * ip6_tnl_parse_tlv_enc_lim() might
- * have reallocated skb->head
- */
- ipv6h = ipv6_hdr(skb);
- if (offset > 0) {
- struct ipv6_tlv_tnl_enc_lim *tel;
-
- tel = (void *)&skb_network_header(skb)[offset];
- if (tel->encap_limit == 0) {
- icmpv6_send(skb, ICMPV6_PARAMPROB,
- ICMPV6_HDR_FIELD, offset + 2);
- return -1;
- }
- encap_limit = tel->encap_limit - 1;
- } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
- encap_limit = t->parms.encap_limit;
- }
-
- memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
- fl6.flowi6_proto = IPPROTO_IPV6;
-
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- dsfield = ipv6_get_dsfield(ipv6h);
- else
- dsfield = ip6_tclass(t->parms.flowinfo);
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
- fl6.flowlabel |= ip6_flowlabel(ipv6h);
- if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
- fl6.flowi6_mark = skb->mark;
- else
- fl6.flowi6_mark = t->parms.fwmark;
- }
-
-// FIX ME
-// fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
-
- if (iptunnel_handle_offloads(skb, true, SKB_GSO_IPXIP6))
- return -1;
-
- dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
-
- skb_set_inner_ipproto(skb, IPPROTO_IPV6);
-
- err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
- IPPROTO_IPV6);
- if (err != 0) {
- if (err == -EMSGSIZE)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- return -1;
- }
-
- return 0;
-}
-
-static netdev_tx_t
-ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct net_device_stats *stats = &t->dev->stats;
- int ret;
-
- switch (skb->protocol) {
- case htons(ETH_P_IP):
- ret = ip4ip6_tnl_xmit(skb, dev);
- break;
- case htons(ETH_P_IPV6):
- ret = ip6ip6_tnl_xmit(skb, dev);
- break;
- default:
- goto tx_err;
- }
-
- if (ret < 0)
- goto tx_err;
-
- return NETDEV_TX_OK;
-
-tx_err:
- stats->tx_errors++;
- stats->tx_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static void ip6_tnl_link_config(struct ip6_tnl *t)
-{
- struct net_device *dev = t->dev;
- struct __ip6_tnl_parm *p = &t->parms;
- struct flowi6 *fl6 = &t->fl.u.ip6;
- int t_hlen;
-
- memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
- memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
-
- /* Set up flowi template */
- fl6->saddr = p->laddr;
- fl6->daddr = p->raddr;
- fl6->flowi6_oif = p->link;
- fl6->flowlabel = 0;
-
- if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
- fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo;
- if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
- fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
-
- p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
- p->flags |= rpl_ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
-
- if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
- dev->flags |= IFF_POINTOPOINT;
- else
- dev->flags &= ~IFF_POINTOPOINT;
-
- t->tun_hlen = 0;
- t->hlen = t->encap_hlen + t->tun_hlen;
- t_hlen = t->hlen + sizeof(struct ipv6hdr);
-
- if (p->flags & IP6_TNL_F_CAP_XMIT) {
- int strict = (ipv6_addr_type(&p->raddr) &
- (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
-
- struct rt6_info *rt = rt6_lookup(t->net,
- &p->raddr, &p->laddr,
- p->link, strict);
-
- if (!rt)
- return;
-
- if (rt->dst.dev) {
- dev->hard_header_len = rt->dst.dev->hard_header_len +
- t_hlen;
-
- dev->mtu = rt->dst.dev->mtu - t_hlen;
- if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- dev->mtu -= 8;
-
- if (dev->mtu < IPV6_MIN_MTU)
- dev->mtu = IPV6_MIN_MTU;
- }
- ip6_rt_put(rt);
- }
-}
-
-/**
- * ip6_tnl_change - update the tunnel parameters
- * @t: tunnel to be changed
- * @p: tunnel configuration parameters
- *
- * Description:
- * ip6_tnl_change() updates the tunnel parameters
- **/
-
-static int
-ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
-{
- t->parms.laddr = p->laddr;
- t->parms.raddr = p->raddr;
- t->parms.flags = p->flags;
- t->parms.hop_limit = p->hop_limit;
- t->parms.encap_limit = p->encap_limit;
- t->parms.flowinfo = p->flowinfo;
- t->parms.link = p->link;
- t->parms.proto = p->proto;
- t->parms.fwmark = p->fwmark;
- dst_cache_reset(&t->dst_cache);
- ip6_tnl_link_config(t);
- return 0;
-}
-
-static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
-{
- struct net *net = t->net;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- int err;
-
- ip6_tnl_unlink(ip6n, t);
- synchronize_net();
- err = ip6_tnl_change(t, p);
- ip6_tnl_link(ip6n, t);
- netdev_state_change(t->dev);
- return err;
-}
-
-static int ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
-{
- /* for default tnl0 device allow to change only the proto */
- t->parms.proto = p->proto;
- netdev_state_change(t->dev);
- return 0;
-}
-
-static void
-ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
-{
- p->laddr = u->laddr;
- p->raddr = u->raddr;
- p->flags = u->flags;
- p->hop_limit = u->hop_limit;
- p->encap_limit = u->encap_limit;
- p->flowinfo = u->flowinfo;
- p->link = u->link;
- p->proto = u->proto;
- memcpy(p->name, u->name, sizeof(u->name));
-}
-
-static void
-ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p)
-{
- u->laddr = p->laddr;
- u->raddr = p->raddr;
- u->flags = p->flags;
- u->hop_limit = p->hop_limit;
- u->encap_limit = p->encap_limit;
- u->flowinfo = p->flowinfo;
- u->link = p->link;
- u->proto = p->proto;
- memcpy(u->name, p->name, sizeof(u->name));
-}
-
-/**
- * ip6_tnl_ioctl - configure ipv6 tunnels from userspace
- * @dev: virtual device associated with tunnel
- * @ifr: parameters passed from userspace
- * @cmd: command to be performed
- *
- * Description:
- * ip6_tnl_ioctl() is used for managing IPv6 tunnels
- * from userspace.
- *
- * The possible commands are the following:
- * %SIOCGETTUNNEL: get tunnel parameters for device
- * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
- * %SIOCCHGTUNNEL: change tunnel parameters to those given
- * %SIOCDELTUNNEL: delete tunnel
- *
- * The fallback device "ovs-ip6tnl0", created during module
- * initialization, can be used for creating other tunnel devices.
- *
- * Return:
- * 0 on success,
- * %-EFAULT if unable to copy data to or from userspace,
- * %-EPERM if current process hasn't %CAP_NET_ADMIN set
- * %-EINVAL if passed tunnel parameters are invalid,
- * %-EEXIST if changing a tunnel's parameters would cause a conflict
- * %-ENODEV if attempting to change or delete a nonexisting device
- **/
-
-static int
-ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- int err = 0;
- struct ip6_tnl_parm p;
- struct __ip6_tnl_parm p1;
- struct ip6_tnl *t = netdev_priv(dev);
- struct net *net = t->net;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-
- memset(&p1, 0, sizeof(p1));
-
- switch (cmd) {
- case SIOCGETTUNNEL:
- if (dev == ip6n->fb_tnl_dev) {
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
- err = -EFAULT;
- break;
- }
- ip6_tnl_parm_from_user(&p1, &p);
- t = ip6_tnl_locate(net, &p1, 0);
- if (IS_ERR(t))
- t = netdev_priv(dev);
- } else {
- memset(&p, 0, sizeof(p));
- }
- ip6_tnl_parm_to_user(&p, &t->parms);
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) {
- err = -EFAULT;
- }
- break;
- case SIOCADDTUNNEL:
- case SIOCCHGTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- break;
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- break;
- err = -EINVAL;
- if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
- p.proto != 0)
- break;
- ip6_tnl_parm_from_user(&p1, &p);
- t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
- if (cmd == SIOCCHGTUNNEL) {
- if (!IS_ERR(t)) {
- if (t->dev != dev) {
- err = -EEXIST;
- break;
- }
- } else
- t = netdev_priv(dev);
- if (dev == ip6n->fb_tnl_dev)
- err = ip6_tnl0_update(t, &p1);
- else
- err = ip6_tnl_update(t, &p1);
- }
- if (!IS_ERR(t)) {
- err = 0;
- ip6_tnl_parm_to_user(&p, &t->parms);
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- err = -EFAULT;
-
- } else {
- err = PTR_ERR(t);
- }
- break;
- case SIOCDELTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- break;
-
- if (dev == ip6n->fb_tnl_dev) {
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- break;
- err = -ENOENT;
- ip6_tnl_parm_from_user(&p1, &p);
- t = ip6_tnl_locate(net, &p1, 0);
- if (IS_ERR(t))
- break;
- err = -EPERM;
- if (t->dev == ip6n->fb_tnl_dev)
- break;
- dev = t->dev;
- }
- err = 0;
- unregister_netdevice(dev);
- break;
- default:
- err = -EINVAL;
- }
- return err;
-}
-
-/**
- * ip6_tnl_change_mtu - change mtu manually for tunnel device
- * @dev: virtual device associated with tunnel
- * @new_mtu: the new mtu
- *
- * Return:
- * 0 on success,
- * %-EINVAL if mtu too small
- **/
-
-int rpl_ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
-{
- struct ip6_tnl *tnl = netdev_priv(dev);
-
- if (tnl->parms.proto == IPPROTO_IPV6) {
- if (new_mtu < IPV6_MIN_MTU)
- return -EINVAL;
- } else {
- if (new_mtu < ETH_MIN_MTU)
- return -EINVAL;
- }
- if (new_mtu > 0xFFF8 - dev->hard_header_len)
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
-}
-
-#ifdef HAVE_NDO_GET_IFLINK
-int rpl_ip6_tnl_get_iflink(const struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
-
- return t->parms.link;
-}
-
-#endif
-const struct ip6_tnl_encap_ops __rcu *
- rpl_ip6tun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly;
-
-int rpl_ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops,
- unsigned int num)
-{
- if (num >= MAX_IPTUN_ENCAP_OPS)
- return -ERANGE;
-
- return !cmpxchg((const struct ip6_tnl_encap_ops **)
- &rpl_ip6tun_encaps[num],
- NULL, ops) ? 0 : -1;
-}
-
-int rpl_ip6_tnl_encap_del_ops(const struct ip6_tnl_encap_ops *ops,
- unsigned int num)
-{
- int ret;
-
- if (num >= MAX_IPTUN_ENCAP_OPS)
- return -ERANGE;
-
- ret = (cmpxchg((const struct ip6_tnl_encap_ops **)
- &rpl_ip6tun_encaps[num],
- ops, NULL) == ops) ? 0 : -1;
-
- synchronize_net();
-
- return ret;
-}
-
-int rpl_ip6_tnl_encap_setup(struct ip6_tnl *t,
- struct ip_tunnel_encap *ipencap)
-{
- int hlen;
-
- memset(&t->encap, 0, sizeof(t->encap));
-
- hlen = ip6_encap_hlen(ipencap);
- if (hlen < 0)
- return hlen;
-
- t->encap.type = ipencap->type;
- t->encap.sport = ipencap->sport;
- t->encap.dport = ipencap->dport;
- t->encap.flags = ipencap->flags;
-
- t->encap_hlen = hlen;
- t->hlen = t->encap_hlen + t->tun_hlen;
-
- return 0;
-}
-
-static const struct net_device_ops ip6_tnl_netdev_ops = {
- .ndo_init = ip6_tnl_dev_init,
- .ndo_uninit = ip6_tnl_dev_uninit,
- .ndo_start_xmit = ip6_tnl_start_xmit,
- .ndo_do_ioctl = ip6_tnl_ioctl,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = ip6_tnl_change_mtu,
-#else
- .ndo_change_mtu = ip6_tnl_change_mtu,
-#endif
- .ndo_get_stats = ip6_get_stats,
-#ifdef HAVE_NDO_GET_IFLINK
- .ndo_get_iflink = ip6_tnl_get_iflink,
-#endif
-};
-
-#define IPXIPX_FEATURES (NETIF_F_SG | \
- NETIF_F_FRAGLIST | \
- NETIF_F_HIGHDMA | \
- NETIF_F_GSO_SOFTWARE | \
- NETIF_F_HW_CSUM)
-
-/**
- * ip6_tnl_dev_setup - setup virtual tunnel device
- * @dev: virtual device associated with tunnel
- *
- * Description:
- * Initialize function pointers and device parameters
- **/
-
-static void ip6_tnl_dev_setup(struct net_device *dev)
-{
- dev->netdev_ops = &ip6_tnl_netdev_ops;
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
- dev->priv_destructor = ip6_dev_free;
-#endif
-
- dev->type = ARPHRD_TUNNEL6;
- dev->flags |= IFF_NOARP;
- dev->addr_len = sizeof(struct in6_addr);
- dev->features |= NETIF_F_LLTX;
- netif_keep_dst(dev);
-
- dev->features |= IPXIPX_FEATURES;
- dev->hw_features |= IPXIPX_FEATURES;
-
- /* This perm addr will be used as interface identifier by IPv6 */
- dev->addr_assign_type = NET_ADDR_RANDOM;
- eth_random_addr(dev->perm_addr);
-}
-
-
-/**
- * ip6_tnl_dev_init_gen - general initializer for all tunnel devices
- * @dev: virtual device associated with tunnel
- **/
-
-static inline int
-ip6_tnl_dev_init_gen(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- int ret;
- int t_hlen;
-
- t->dev = dev;
- t->net = dev_net(dev);
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- ret = dst_cache_init(&t->dst_cache, GFP_KERNEL);
- if (ret)
- goto free_stats;
-
- ret = gro_cells_init(&t->gro_cells, dev);
- if (ret)
- goto destroy_dst;
-
- t->tun_hlen = 0;
- t->hlen = t->encap_hlen + t->tun_hlen;
- t_hlen = t->hlen + sizeof(struct ipv6hdr);
-
- dev->type = ARPHRD_TUNNEL6;
- dev->hard_header_len = LL_MAX_HEADER + t_hlen;
- dev->mtu = ETH_DATA_LEN - t_hlen;
- if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
- dev->mtu -= 8;
-#ifdef HAVE_NET_DEVICE_MAX_MTU
- dev->min_mtu = ETH_MIN_MTU;
- dev->max_mtu = 0xFFF8 - dev->hard_header_len;
-#endif
-
- return 0;
-
-destroy_dst:
- dst_cache_destroy(&t->dst_cache);
-free_stats:
- free_percpu(dev->tstats);
- dev->tstats = NULL;
-
- return ret;
-}
-
-/**
- * ip6_tnl_dev_init - initializer for all non fallback tunnel devices
- * @dev: virtual device associated with tunnel
- **/
-
-static int ip6_tnl_dev_init(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- int err = ip6_tnl_dev_init_gen(dev);
-
- if (err)
- return err;
- ip6_tnl_link_config(t);
- if (t->parms.collect_md) {
- dev->features |= NETIF_F_NETNS_LOCAL;
- netif_keep_dst(dev);
- }
- return 0;
-}
-
-/**
- * ip6_fb_tnl_dev_init - initializer for fallback tunnel device
- * @dev: fallback device
- *
- * Return: 0
- **/
-
-static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct net *net = dev_net(dev);
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-
- t->parms.proto = IPPROTO_IPV6;
- dev_hold(dev);
-
- rcu_assign_pointer(ip6n->tnls_wc[0], t);
- return 0;
-}
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int rpl_ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- u8 proto;
-
- if (!data || !data[IFLA_IPTUN_PROTO])
- return 0;
-
- proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
- if (proto != IPPROTO_IPV6 &&
- proto != IPPROTO_IPIP &&
- proto != 0)
- return -EINVAL;
-
- return 0;
-}
-#define ip6_tnl_validate rpl_ip6_tnl_validate
-
-static void ip6_tnl_netlink_parms(struct nlattr *data[],
- struct __ip6_tnl_parm *parms)
-{
- memset(parms, 0, sizeof(*parms));
-
- if (!data)
- return;
-
- if (data[IFLA_IPTUN_LINK])
- parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
-
- if (data[IFLA_IPTUN_LOCAL])
- parms->laddr = nla_get_in6_addr(data[IFLA_IPTUN_LOCAL]);
-
- if (data[IFLA_IPTUN_REMOTE])
- parms->raddr = nla_get_in6_addr(data[IFLA_IPTUN_REMOTE]);
-
- if (data[IFLA_IPTUN_TTL])
- parms->hop_limit = nla_get_u8(data[IFLA_IPTUN_TTL]);
-
- if (data[IFLA_IPTUN_ENCAP_LIMIT])
- parms->encap_limit = nla_get_u8(data[IFLA_IPTUN_ENCAP_LIMIT]);
-
- if (data[IFLA_IPTUN_FLOWINFO])
- parms->flowinfo = nla_get_be32(data[IFLA_IPTUN_FLOWINFO]);
-
- if (data[IFLA_IPTUN_FLAGS])
- parms->flags = nla_get_u32(data[IFLA_IPTUN_FLAGS]);
-
- if (data[IFLA_IPTUN_PROTO])
- parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
-
- if (data[IFLA_IPTUN_COLLECT_METADATA])
- parms->collect_md = true;
-
- if (data[IFLA_IPTUN_FWMARK])
- parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
-}
-
-static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[],
- struct ip_tunnel_encap *ipencap)
-{
- bool ret = false;
-
- memset(ipencap, 0, sizeof(*ipencap));
-
- if (!data)
- return ret;
-
- if (data[IFLA_IPTUN_ENCAP_TYPE]) {
- ret = true;
- ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
- }
-
- if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
- ret = true;
- ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
- }
-
- if (data[IFLA_IPTUN_ENCAP_SPORT]) {
- ret = true;
- ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]);
- }
-
- if (data[IFLA_IPTUN_ENCAP_DPORT]) {
- ret = true;
- ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]);
- }
-
- return ret;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int rpl_ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- struct net *net = dev_net(dev);
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- struct ip_tunnel_encap ipencap;
- struct ip6_tnl *nt, *t;
- int err;
-
- nt = netdev_priv(dev);
-
- if (ip6_tnl_netlink_encap_parms(data, &ipencap)) {
- err = ip6_tnl_encap_setup(nt, &ipencap);
- if (err < 0)
- return err;
- }
-
- ip6_tnl_netlink_parms(data, &nt->parms);
-
- if (nt->parms.collect_md) {
- if (rtnl_dereference(ip6n->collect_md_tun))
- return -EEXIST;
- } else {
- t = ip6_tnl_locate(net, &nt->parms, 0);
- if (!IS_ERR(t))
- return -EEXIST;
- }
-
- err = ip6_tnl_create2(dev);
- if (!err && tb[IFLA_MTU])
- ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
-
- return err;
-}
-#define ip6_tnl_newlink rpl_ip6_tnl_newlink
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int rpl_ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int rpl_ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[])
-#endif
-{
- struct ip6_tnl *t = netdev_priv(dev);
- struct __ip6_tnl_parm p;
- struct net *net = t->net;
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- struct ip_tunnel_encap ipencap;
-
- if (dev == ip6n->fb_tnl_dev)
- return -EINVAL;
-
- if (ip6_tnl_netlink_encap_parms(data, &ipencap)) {
- int err = ip6_tnl_encap_setup(t, &ipencap);
-
- if (err < 0)
- return err;
- }
- ip6_tnl_netlink_parms(data, &p);
- if (p.collect_md)
- return -EINVAL;
-
- t = ip6_tnl_locate(net, &p, 0);
- if (!IS_ERR(t)) {
- if (t->dev != dev)
- return -EEXIST;
- } else
- t = netdev_priv(dev);
-
- return ip6_tnl_update(t, &p);
-}
-#define ip6_tnl_changelink rpl_ip6_tnl_changelink
-
-static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head)
-{
- struct net *net = dev_net(dev);
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-
- if (dev != ip6n->fb_tnl_dev)
- unregister_netdevice_queue(dev, head);
-}
-
-static size_t ip6_tnl_get_size(const struct net_device *dev)
-{
- return
- /* IFLA_IPTUN_LINK */
- nla_total_size(4) +
- /* IFLA_IPTUN_LOCAL */
- nla_total_size(sizeof(struct in6_addr)) +
- /* IFLA_IPTUN_REMOTE */
- nla_total_size(sizeof(struct in6_addr)) +
- /* IFLA_IPTUN_TTL */
- nla_total_size(1) +
- /* IFLA_IPTUN_ENCAP_LIMIT */
- nla_total_size(1) +
- /* IFLA_IPTUN_FLOWINFO */
- nla_total_size(4) +
- /* IFLA_IPTUN_FLAGS */
- nla_total_size(4) +
- /* IFLA_IPTUN_PROTO */
- nla_total_size(1) +
- /* IFLA_IPTUN_ENCAP_TYPE */
- nla_total_size(2) +
- /* IFLA_IPTUN_ENCAP_FLAGS */
- nla_total_size(2) +
- /* IFLA_IPTUN_ENCAP_SPORT */
- nla_total_size(2) +
- /* IFLA_IPTUN_ENCAP_DPORT */
- nla_total_size(2) +
- /* IFLA_IPTUN_COLLECT_METADATA */
- nla_total_size(0) +
- /* IFLA_IPTUN_FWMARK */
- nla_total_size(4) +
- 0;
-}
-
-static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- struct ip6_tnl *tunnel = netdev_priv(dev);
- struct __ip6_tnl_parm *parm = &tunnel->parms;
-
- if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
- nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
- nla_put_in6_addr(skb, IFLA_IPTUN_REMOTE, &parm->raddr) ||
- nla_put_u8(skb, IFLA_IPTUN_TTL, parm->hop_limit) ||
- nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
- nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
- nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
- nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
- nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark))
- goto nla_put_failure;
-
- if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) ||
- nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) ||
- nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) ||
- nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, tunnel->encap.flags))
- goto nla_put_failure;
-
- if (parm->collect_md)
- if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-#ifdef HAVE_GET_LINK_NET
-struct net *rpl_ip6_tnl_get_link_net(const struct net_device *dev)
-{
- struct ip6_tnl *tunnel = netdev_priv(dev);
-
- return tunnel->net;
-}
-
-#endif
-static const struct nla_policy ip6_tnl_policy[RPL_IFLA_IPTUN_MAX + 1] = {
- [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
- [IFLA_IPTUN_LOCAL] = { .len = sizeof(struct in6_addr) },
- [IFLA_IPTUN_REMOTE] = { .len = sizeof(struct in6_addr) },
- [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
- [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 },
- [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 },
- [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 },
- [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
- [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 },
- [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 },
- [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 },
- [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
- [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
- [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
-};
-
-static struct rtnl_link_ops ip6_link_ops __read_mostly = {
- .kind = "ip6tnl",
- .maxtype = RPL_IFLA_IPTUN_MAX,
- .policy = ip6_tnl_policy,
- .priv_size = sizeof(struct ip6_tnl),
- .setup = ip6_tnl_dev_setup,
- .validate = ip6_tnl_validate,
- .newlink = ip6_tnl_newlink,
- .changelink = ip6_tnl_changelink,
- .dellink = ip6_tnl_dellink,
- .get_size = ip6_tnl_get_size,
- .fill_info = ip6_tnl_fill_info,
-#ifdef HAVE_GET_LINK_NET
- .get_link_net = ip6_tnl_get_link_net,
-#endif
-};
-
-static struct xfrm6_tunnel ip4ip6_handler __read_mostly = {
- .handler = ip4ip6_rcv,
- .err_handler = ip4ip6_err,
- .priority = 1,
-};
-
-static struct xfrm6_tunnel ip6ip6_handler __read_mostly = {
- .handler = ip6ip6_rcv,
- .err_handler = ip6ip6_err,
- .priority = 1,
-};
-
-static void __net_exit ip6_tnl_destroy_tunnels(struct net *net, struct list_head *list)
-{
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- struct net_device *dev, *aux;
- int h;
- struct ip6_tnl *t;
-
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == &ip6_link_ops)
- unregister_netdevice_queue(dev, list);
-
- for (h = 0; h < IP6_TUNNEL_HASH_SIZE; h++) {
- t = rtnl_dereference(ip6n->tnls_r_l[h]);
- while (t) {
- /* If dev is in the same netns, it has already
- * been added to the list by the previous loop.
- */
- if (!net_eq(dev_net(t->dev), net))
- unregister_netdevice_queue(t->dev, list);
- t = rtnl_dereference(t->next);
- }
- }
-}
-
-static int __net_init ip6_tnl_init_net(struct net *net)
-{
- struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- struct ip6_tnl *t = NULL;
- int err;
-
- ip6n->tnls[0] = ip6n->tnls_wc;
- ip6n->tnls[1] = ip6n->tnls_r_l;
-
- err = -ENOMEM;
- ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ovs-ip6tnl0",
- NET_NAME_UNKNOWN, ip6_tnl_dev_setup);
-
- if (!ip6n->fb_tnl_dev)
- goto err_alloc_dev;
- dev_net_set(ip6n->fb_tnl_dev, net);
- ip6n->fb_tnl_dev->rtnl_link_ops = &ip6_link_ops;
- /* FB netdevice is special: we have one, and only one per netns.
- * Allowing to move it to another netns is clearly unsafe.
- */
- ip6n->fb_tnl_dev->features |= NETIF_F_NETNS_LOCAL;
-
- err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
- if (err < 0)
- goto err_register;
-
- err = register_netdev(ip6n->fb_tnl_dev);
- if (err < 0)
- goto err_register;
-
- t = netdev_priv(ip6n->fb_tnl_dev);
-
- strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
- return 0;
-
-err_register:
- free_netdev(ip6n->fb_tnl_dev);
-err_alloc_dev:
- return err;
-}
-
-static void __net_exit ip6_tnl_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)
- ip6_tnl_destroy_tunnels(net, &list);
- unregister_netdevice_many(&list);
- rtnl_unlock();
-}
-
-static struct pernet_operations ip6_tnl_net_ops = {
- .init = ip6_tnl_init_net,
- .exit_batch = ip6_tnl_exit_batch_net,
- .id = &ip6_tnl_net_id,
- .size = sizeof(struct ip6_tnl_net),
-};
-
-/**
- * ip6_tunnel_init - register protocol and reserve needed resources
- *
- * Return: 0 on success
- **/
-
-int rpl_ip6_tunnel_init(void)
-{
- int err;
-
-#if 0
- if (!ipv6_mod_enabled())
- return -EOPNOTSUPP;
-#endif
- err = register_pernet_device(&ip6_tnl_net_ops);
- if (err < 0) {
- pr_err("%s: can't register ip6_tnl pernet device\n",
- __func__);
- goto out_pernet;
- }
-
- err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET);
- if (err < 0) {
- pr_err("%s: can't register ip4ip6\n", __func__);
- goto out_ip4ip6;
- }
-
- err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6);
- if (err < 0) {
- pr_err("%s: can't register ip6ip6\n", __func__);
- goto out_ip6ip6;
- }
-
- err = rtnl_link_register(&ip6_link_ops);
- if (err < 0) {
- pr_err("%s: can't register ip6_lin_ops\n",
- __func__);
- goto rtnl_link_failed;
- }
- return 0;
-
-rtnl_link_failed:
- xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
-out_ip6ip6:
- xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
-out_ip4ip6:
- unregister_pernet_device(&ip6_tnl_net_ops);
-out_pernet:
- return err;
-}
-
-/**
- * ip6_tunnel_cleanup - free resources and unregister protocol
- **/
-
-void rpl_ip6_tunnel_cleanup(void)
-{
- rtnl_link_unregister(&ip6_link_ops);
- if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET))
- pr_info("%s: can't deregister ip4ip6\n", __func__);
-
- if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
- pr_info("%s: can't deregister ip6ip6\n", __func__);
-
- unregister_pernet_device(&ip6_tnl_net_ops);
-}
-
-#endif /* USE_UPSTREAM_TUNNEL */
diff --git a/datapath/linux/compat/ip_fragment.c b/datapath/linux/compat/ip_fragment.c
deleted file mode 100644
index f910b99b4..000000000
--- a/datapath/linux/compat/ip_fragment.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- * IP fragmentation backport, heavily based on linux/net/ipv4/ip_fragment.c,
- * copied from Linux 192132b9a034 net: Add support for VRFs to inetpeer cache
- *
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * The IP fragmentation functionality.
- *
- * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * Fixes:
- * Alan Cox : Split from ip.c , see ip_input.c for history.
- * David S. Miller : Begin massive cleanup...
- * Andi Kleen : Add sysctls.
- * xxxx : Overlapfrag bug.
- * Ultima : ip_expire() kernel panic.
- * Bill Hawes : Frag accounting and evictor fixes.
- * John McDonald : 0 length frag bug.
- * Alexey Kuznetsov: SMP races, threading, cleanup.
- * Patrick McHardy : LRU queue of frag heads for evictor.
- */
-
-#include <linux/version.h>
-
-#ifndef HAVE_CORRECT_MRU_HANDLING
-
-#define pr_fmt(fmt) "IPv4: " fmt
-
-#include <linux/compiler.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/jiffies.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/ip.h>
-#include <linux/icmp.h>
-#include <linux/netdevice.h>
-#include <linux/jhash.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <net/route.h>
-#include <net/dst.h>
-#include <net/sock.h>
-#include <net/ip.h>
-#include <net/icmp.h>
-#include <net/checksum.h>
-#include <net/inetpeer.h>
-#include <net/inet_frag.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include <linux/inet.h>
-#include <linux/netfilter_ipv4.h>
-#include <net/inet_ecn.h>
-#include <net/vrf.h>
-#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
-#include <net/netns/generic.h>
-#include "datapath.h"
-
-/* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6
- * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c
- * as well. Or notify me, at least. --ANK
- */
-
-static int sysctl_ipfrag_max_dist __read_mostly = 64;
-static const char ip_frag_cache_name[] = "ovs-frag4";
-
-struct ipfrag_skb_cb
-{
- struct inet_skb_parm h;
- int offset;
-};
-
-#define FRAG_CB(skb) ((struct ipfrag_skb_cb *)((skb)->cb))
-
-/* Describe an entry in the "incomplete datagrams" queue. */
-struct ipq {
- struct inet_frag_queue q;
-
- u32 user;
- __be32 saddr;
- __be32 daddr;
- __be16 id;
- u8 protocol;
- u8 ecn; /* RFC3168 support */
- u16 max_df_size; /* largest frag with DF set seen */
- int iif;
- int vif; /* VRF device index */
- unsigned int rid;
- struct inet_peer *peer;
-};
-
-static u8 ip4_frag_ecn(u8 tos)
-{
- return 1 << (tos & INET_ECN_MASK);
-}
-
-static struct inet_frags ip4_frags;
-
-static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
- struct net_device *dev);
-
-struct ip4_create_arg {
- struct iphdr *iph;
- u32 user;
- int vif;
-};
-
-static struct netns_frags *get_netns_frags_from_net(struct net *net)
-{
-#ifdef HAVE_INET_FRAG_LRU_MOVE
- struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
- return &(ovs_net->ipv4_frags);
-#else
- return &(net->ipv4.frags);
-#endif
-}
-
-static struct net *get_net_from_netns_frags(struct netns_frags *frags)
-{
- struct net *net;
-#ifdef HAVE_INET_FRAG_LRU_MOVE
- struct ovs_net *ovs_net;
-
- ovs_net = container_of(frags, struct ovs_net, ipv4_frags);
- net = ovs_net->net;
-#else
- net = container_of(frags, struct net, ipv4.frags);
-#endif
- return net;
-}
-
-void ovs_netns_frags_init(struct net *net)
-{
-#ifdef HAVE_INET_FRAG_LRU_MOVE
- struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
-
- ovs_net->ipv4_frags.high_thresh = 4 * 1024 * 1024;
- ovs_net->ipv4_frags.low_thresh = 3 * 1024 * 1024;
- ovs_net->ipv4_frags.timeout = IP_FRAG_TIME;
- inet_frags_init_net(&(ovs_net->ipv4_frags));
- ovs_net->net = net;
-#endif
-}
-
-void ovs_netns_frags_exit(struct net *net)
-{
- struct netns_frags *frags;
-
- frags = get_netns_frags_from_net(net);
- inet_frags_exit_net(frags, &ip4_frags);
-}
-
-static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
-{
- net_get_random_once(&ip4_frags.rnd, sizeof(ip4_frags.rnd));
- return jhash_3words((__force u32)id << 16 | prot,
- (__force u32)saddr, (__force u32)daddr,
- ip4_frags.rnd);
-}
-/* fb3cfe6e75b9 ("inet: frag: remove hash size assumptions from callers")
- * shifted this logic into inet_fragment, but prior kernels still need this.
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
-#define ipqhashfn(a, b, c, d) (ipqhashfn(a, b, c, d) & (INETFRAGS_HASHSZ - 1))
-#endif
-
-#ifdef HAVE_INET_FRAGS_CONST
-static unsigned int ip4_hashfn(const struct inet_frag_queue *q)
-#else
-static unsigned int ip4_hashfn(struct inet_frag_queue *q)
-#endif
-{
- const struct ipq *ipq;
-
- ipq = container_of(q, struct ipq, q);
- return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol);
-}
-
-#ifdef HAVE_INET_FRAGS_CONST
-static bool ip4_frag_match(const struct inet_frag_queue *q, const void *a)
-#else
-static bool ip4_frag_match(struct inet_frag_queue *q, void *a)
-#endif
-{
- const struct ipq *qp;
- const struct ip4_create_arg *arg = a;
-
- qp = container_of(q, struct ipq, q);
- return qp->id == arg->iph->id &&
- qp->saddr == arg->iph->saddr &&
- qp->daddr == arg->iph->daddr &&
- qp->protocol == arg->iph->protocol &&
- qp->user == arg->user &&
- qp->vif == arg->vif;
-}
-
-#ifdef HAVE_INET_FRAGS_CONST
-static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
-#else
-static void ip4_frag_init(struct inet_frag_queue *q, void *a)
-#endif
-{
- struct ipq *qp = container_of(q, struct ipq, q);
- struct net *net = get_net_from_netns_frags(q->net);
-
- const struct ip4_create_arg *arg = a;
-
- qp->protocol = arg->iph->protocol;
- qp->id = arg->iph->id;
- qp->ecn = ip4_frag_ecn(arg->iph->tos);
- qp->saddr = arg->iph->saddr;
- qp->daddr = arg->iph->daddr;
- qp->vif = arg->vif;
- qp->user = arg->user;
- qp->peer = sysctl_ipfrag_max_dist ?
- inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, arg->vif, 1) :
- NULL;
-}
-
-static void ip4_frag_free(struct inet_frag_queue *q)
-{
- struct ipq *qp;
-
- qp = container_of(q, struct ipq, q);
- if (qp->peer)
- inet_putpeer(qp->peer);
-}
-
-
-/* Destruction primitives. */
-
-static void ipq_put(struct ipq *ipq)
-{
- inet_frag_put(&ipq->q, &ip4_frags);
-}
-
-/* Kill ipq entry. It is not destroyed immediately,
- * because caller (and someone more) holds reference count.
- */
-static void ipq_kill(struct ipq *ipq)
-{
- inet_frag_kill(&ipq->q, &ip4_frags);
-}
-
-static bool frag_expire_skip_icmp(u32 user)
-{
- return user == IP_DEFRAG_AF_PACKET ||
- ip_defrag_user_in_between(user, IP_DEFRAG_CONNTRACK_IN,
- __IP_DEFRAG_CONNTRACK_IN_END) ||
- ip_defrag_user_in_between(user, IP_DEFRAG_CONNTRACK_BRIDGE_IN,
- __IP_DEFRAG_CONNTRACK_BRIDGE_IN);
-}
-
-/*
- * Oops, a fragment queue timed out. Kill it and send an ICMP reply.
- */
-static void ip_expire(unsigned long arg)
-{
- struct ipq *qp;
- struct net *net;
-
- qp = container_of((struct inet_frag_queue *) arg, struct ipq, q);
- net = get_net_from_netns_frags(qp->q.net);
-
- spin_lock(&qp->q.lock);
-
- if (qp_flags(qp) & INET_FRAG_COMPLETE)
- goto out;
-
- ipq_kill(qp);
- IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
-
- if (!inet_frag_evicting(&qp->q)) {
- struct sk_buff *head = qp->q.fragments;
- const struct iphdr *iph;
- int err;
-
- IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT);
-
- if (!(qp_flags(qp) & INET_FRAG_FIRST_IN) || !qp->q.fragments)
- goto out;
-
- rcu_read_lock();
- head->dev = dev_get_by_index_rcu(net, qp->iif);
- if (!head->dev)
- goto out_rcu_unlock;
-
- /* skb has no dst, perform route lookup again */
- iph = ip_hdr(head);
- err = ip_route_input_noref(head, iph->daddr, iph->saddr,
- iph->tos, head->dev);
- if (err)
- goto out_rcu_unlock;
-
- /* Only an end host needs to send an ICMP
- * "Fragment Reassembly Timeout" message, per RFC792.
- */
- if (frag_expire_skip_icmp(qp->user) &&
- (skb_rtable(head)->rt_type != RTN_LOCAL))
- goto out_rcu_unlock;
-
- /* Send an ICMP "Fragment Reassembly Timeout" message. */
- icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
-out_rcu_unlock:
- rcu_read_unlock();
- }
-out:
- spin_unlock(&qp->q.lock);
- ipq_put(qp);
-}
-
-#ifdef HAVE_INET_FRAG_EVICTOR
-/* Memory limiting on fragments. Evictor trashes the oldest
- * fragment queue until we are back under the threshold.
- *
- * Necessary for kernels earlier than v3.17. Replaced in commit
- * b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue").
- */
-static void ip_evictor(struct net *net)
-{
- int evicted;
- struct netns_frags *frags;
-
- frags = get_netns_frags_from_net(net);
- evicted = inet_frag_evictor(frags, &ip4_frags, false);
- if (evicted)
- IP_ADD_STATS_BH(net, IPSTATS_MIB_REASMFAILS, evicted);
-}
-#endif
-
-/* Find the correct entry in the "incomplete datagrams" queue for
- * this IP datagram, and create new one, if nothing is found.
- */
-static struct ipq *ip_find(struct net *net, struct iphdr *iph,
- u32 user, int vif)
-{
- struct inet_frag_queue *q;
- struct ip4_create_arg arg;
- unsigned int hash;
- struct netns_frags *frags;
-
- arg.iph = iph;
- arg.user = user;
- arg.vif = vif;
-
-#ifdef HAVE_INET_FRAGS_WITH_RWLOCK
- read_lock(&ip4_frags.lock);
-#endif
- hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
-
- frags = get_netns_frags_from_net(net);
- q = inet_frag_find(frags, &ip4_frags, &arg, hash);
- if (IS_ERR_OR_NULL(q)) {
- inet_frag_maybe_warn_overflow(q, pr_fmt());
- return NULL;
- }
- return container_of(q, struct ipq, q);
-}
-
-/* Is the fragment too far ahead to be part of ipq? */
-static int ip_frag_too_far(struct ipq *qp)
-{
- struct inet_peer *peer = qp->peer;
- unsigned int max = sysctl_ipfrag_max_dist;
- unsigned int start, end;
-
- int rc;
-
- if (!peer || !max)
- return 0;
-
- start = qp->rid;
- end = atomic_inc_return(&peer->rid);
- qp->rid = end;
-
- rc = qp->q.fragments && (end - start) > max;
-
- if (rc) {
- struct net *net;
-
- net = get_net_from_netns_frags(qp->q.net);
- IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
- }
-
- return rc;
-}
-
-static int ip_frag_reinit(struct ipq *qp)
-{
- struct sk_buff *fp;
- unsigned int sum_truesize = 0;
-
- if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) {
- atomic_inc(&qp->q.refcnt);
- return -ETIMEDOUT;
- }
-
- fp = qp->q.fragments;
- do {
- struct sk_buff *xp = fp->next;
-
- sum_truesize += fp->truesize;
- kfree_skb(fp);
- fp = xp;
- } while (fp);
- sub_frag_mem_limit(qp->q.net, sum_truesize);
-
- qp_flags(qp) = 0;
- qp->q.len = 0;
- qp->q.meat = 0;
- qp->q.fragments = NULL;
- qp->q.fragments_tail = NULL;
- qp->iif = 0;
- qp->ecn = 0;
-
- return 0;
-}
-
-/* Add new segment to existing queue. */
-static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
-{
- struct sk_buff *prev, *next;
- struct net_device *dev;
- unsigned int fragsize;
- int flags, offset;
- int ihl, end;
- int err = -ENOENT;
- u8 ecn;
-
- if (qp_flags(qp) & INET_FRAG_COMPLETE)
- goto err;
-
- if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
- unlikely(ip_frag_too_far(qp)) &&
- unlikely(err = ip_frag_reinit(qp))) {
- ipq_kill(qp);
- goto err;
- }
-
- ecn = ip4_frag_ecn(ip_hdr(skb)->tos);
- offset = ntohs(ip_hdr(skb)->frag_off);
- flags = offset & ~IP_OFFSET;
- offset &= IP_OFFSET;
- offset <<= 3; /* offset is in 8-byte chunks */
- ihl = ip_hdrlen(skb);
-
- /* Determine the position of this fragment. */
- end = offset + skb->len - skb_network_offset(skb) - ihl;
- err = -EINVAL;
-
- /* Is this the final fragment? */
- if ((flags & IP_MF) == 0) {
- /* If we already have some bits beyond end
- * or have different end, the segment is corrupted.
- */
- if (end < qp->q.len ||
- ((qp_flags(qp) & INET_FRAG_LAST_IN) && end != qp->q.len))
- goto err;
- qp_flags(qp) |= INET_FRAG_LAST_IN;
- qp->q.len = end;
- } else {
- if (end&7) {
- end &= ~7;
- if (skb->ip_summed != CHECKSUM_UNNECESSARY)
- skb->ip_summed = CHECKSUM_NONE;
- }
- if (end > qp->q.len) {
- /* Some bits beyond end -> corruption. */
- if (qp_flags(qp) & INET_FRAG_LAST_IN)
- goto err;
- qp->q.len = end;
- }
- }
- if (end == offset)
- goto err;
-
- err = -ENOMEM;
- if (!pskb_pull(skb, skb_network_offset(skb) + ihl))
- goto err;
-
- err = pskb_trim_rcsum(skb, end - offset);
- if (err)
- goto err;
-
- /* Find out which fragments are in front and at the back of us
- * in the chain of fragments so far. We must know where to put
- * this fragment, right?
- */
- prev = qp->q.fragments_tail;
- if (!prev || FRAG_CB(prev)->offset < offset) {
- next = NULL;
- goto found;
- }
- prev = NULL;
- for (next = qp->q.fragments; next != NULL; next = next->next) {
- if (FRAG_CB(next)->offset >= offset)
- break; /* bingo! */
- prev = next;
- }
-
-found:
- /* We found where to put this one. Check for overlap with
- * preceding fragment, and, if needed, align things so that
- * any overlaps are eliminated.
- */
- if (prev) {
- int i = (FRAG_CB(prev)->offset + prev->len) - offset;
-
- if (i > 0) {
- offset += i;
- err = -EINVAL;
- if (end <= offset)
- goto err;
- err = -ENOMEM;
- if (!pskb_pull(skb, i))
- goto err;
- if (skb->ip_summed != CHECKSUM_UNNECESSARY)
- skb->ip_summed = CHECKSUM_NONE;
- }
- }
-
- err = -ENOMEM;
-
- while (next && FRAG_CB(next)->offset < end) {
- int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */
-
- if (i < next->len) {
- /* Eat head of the next overlapped fragment
- * and leave the loop. The next ones cannot overlap.
- */
- if (!pskb_pull(next, i))
- goto err;
- FRAG_CB(next)->offset += i;
- qp->q.meat -= i;
- if (next->ip_summed != CHECKSUM_UNNECESSARY)
- next->ip_summed = CHECKSUM_NONE;
- break;
- } else {
- struct sk_buff *free_it = next;
-
- /* Old fragment is completely overridden with
- * new one drop it.
- */
- next = next->next;
-
- if (prev)
- prev->next = next;
- else
- qp->q.fragments = next;
-
- qp->q.meat -= free_it->len;
- sub_frag_mem_limit(qp->q.net, free_it->truesize);
- kfree_skb(free_it);
- }
- }
-
- FRAG_CB(skb)->offset = offset;
-
- /* Insert this fragment in the chain of fragments. */
- skb->next = next;
- if (!next)
- qp->q.fragments_tail = skb;
- if (prev)
- prev->next = skb;
- else
- qp->q.fragments = skb;
-
- dev = skb->dev;
- if (dev) {
- qp->iif = dev->ifindex;
- skb->dev = NULL;
- }
- qp->q.stamp = skb->tstamp;
- qp->q.meat += skb->len;
- qp->ecn |= ecn;
- add_frag_mem_limit(qp->q.net, skb->truesize);
- if (offset == 0)
- qp_flags(qp) |= INET_FRAG_FIRST_IN;
-
- fragsize = skb->len + ihl;
-
- if (fragsize > qp->q.max_size)
- qp->q.max_size = fragsize;
-
- if (ip_hdr(skb)->frag_off & htons(IP_DF) &&
- fragsize > qp->max_df_size)
- qp->max_df_size = fragsize;
-
- if (qp_flags(qp) == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
- qp->q.meat == qp->q.len) {
- unsigned long orefdst = skb->_skb_refdst;
-
- skb->_skb_refdst = 0UL;
- err = ip_frag_reasm(qp, prev, dev);
- skb->_skb_refdst = orefdst;
- return err;
- }
-
- skb_dst_drop(skb);
- inet_frag_lru_move(&qp->q);
- return -EINPROGRESS;
-
-err:
- kfree_skb(skb);
- return err;
-}
-
-
-/* Build a new IP datagram from all its fragments. */
-
-static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
- struct net_device *dev)
-{
- struct net *net = get_net_from_netns_frags(qp->q.net);
- struct iphdr *iph;
- struct sk_buff *fp, *head = qp->q.fragments;
- int len;
- int ihlen;
- int err;
- u8 ecn;
-
- ipq_kill(qp);
-
- ecn = ip_frag_ecn_table[qp->ecn];
- if (unlikely(ecn == 0xff)) {
- err = -EINVAL;
- goto out_fail;
- }
- /* Make the one we just received the head. */
- if (prev) {
- head = prev->next;
- fp = skb_clone(head, GFP_ATOMIC);
- if (!fp)
- goto out_nomem;
-
- fp->next = head->next;
- if (!fp->next)
- qp->q.fragments_tail = fp;
- prev->next = fp;
-
- skb_morph(head, qp->q.fragments);
- head->next = qp->q.fragments->next;
-
- consume_skb(qp->q.fragments);
- qp->q.fragments = head;
- }
-
- WARN_ON(!head);
- WARN_ON(FRAG_CB(head)->offset != 0);
-
- /* Allocate a new buffer for the datagram. */
- ihlen = ip_hdrlen(head);
- len = ihlen + qp->q.len;
-
- err = -E2BIG;
- if (len > 65535)
- goto out_oversize;
-
- /* Head of list must not be cloned. */
- if (skb_unclone(head, GFP_ATOMIC))
- goto out_nomem;
-
- /* If the first fragment is fragmented itself, we split
- * it to two chunks: the first with data and paged part
- * and the second, holding only fragments. */
- if (skb_has_frag_list(head)) {
- struct sk_buff *clone;
- int i, plen = 0;
-
- clone = alloc_skb(0, GFP_ATOMIC);
- if (!clone)
- goto out_nomem;
- clone->next = head->next;
- head->next = clone;
- skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
- skb_frag_list_init(head);
- for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
- plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
- clone->len = clone->data_len = head->data_len - plen;
- head->data_len -= clone->len;
- head->len -= clone->len;
- clone->csum = 0;
- clone->ip_summed = head->ip_summed;
- add_frag_mem_limit(qp->q.net, clone->truesize);
- }
-
- skb_shinfo(head)->frag_list = head->next;
- skb_push(head, head->data - skb_network_header(head));
-
- for (fp=head->next; fp; fp = fp->next) {
- head->data_len += fp->len;
- head->len += fp->len;
- if (head->ip_summed != fp->ip_summed)
- head->ip_summed = CHECKSUM_NONE;
- else if (head->ip_summed == CHECKSUM_COMPLETE)
- head->csum = csum_add(head->csum, fp->csum);
- head->truesize += fp->truesize;
- }
- sub_frag_mem_limit(qp->q.net, head->truesize);
-
- head->next = NULL;
- head->dev = dev;
- head->tstamp = qp->q.stamp;
- IPCB(head)->frag_max_size = max(qp->max_df_size, qp->q.max_size);
-
- iph = ip_hdr(head);
- iph->tot_len = htons(len);
- iph->tos |= ecn;
-
- /* When we set IP_DF on a refragmented skb we must also force a
- * call to ip_fragment to avoid forwarding a DF-skb of size s while
- * original sender only sent fragments of size f (where f < s).
- *
- * We only set DF/IPSKB_FRAG_PMTU if such DF fragment was the largest
- * frag seen to avoid sending tiny DF-fragments in case skb was built
- * from one very small df-fragment and one large non-df frag.
- */
- if (qp->max_df_size == qp->q.max_size) {
- IPCB(head)->flags |= IPSKB_FRAG_PMTU;
- iph->frag_off = htons(IP_DF);
- } else {
- iph->frag_off = 0;
- }
-
- ip_send_check(iph);
-
- IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
- qp->q.fragments = NULL;
- qp->q.fragments_tail = NULL;
- return 0;
-
-out_nomem:
- net_dbg_ratelimited("queue_glue: no memory for gluing queue %p\n", qp);
- err = -ENOMEM;
- goto out_fail;
-out_oversize:
- net_info_ratelimited("Oversized IP packet from %pI4\n", &qp->saddr);
-out_fail:
- IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
- return err;
-}
-
-/* Process an incoming IP datagram fragment. */
-int rpl_ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
-{
- struct net_device *dev = skb->dev ? : skb_dst(skb)->dev;
- int vif = vrf_master_ifindex_rcu(dev);
- struct ipq *qp;
-
- IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);
- skb_orphan(skb);
-
-#ifdef HAVE_INET_FRAG_EVICTOR
- /* Start by cleaning up the memory. */
- ip_evictor(net);
-#endif
-
- /* Lookup (or create) queue header */
- qp = ip_find(net, ip_hdr(skb), user, vif);
- if (qp) {
- int ret;
-
- spin_lock(&qp->q.lock);
-
- ret = ip_frag_queue(qp, skb);
-
- spin_unlock(&qp->q.lock);
- ipq_put(qp);
- return ret;
- }
-
- IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
- kfree_skb(skb);
- return -ENOMEM;
-}
-
-#ifdef HAVE_DEFRAG_ENABLE_TAKES_NET
-static int __net_init ipv4_frags_init_net(struct net *net)
-{
- return nf_defrag_ipv4_enable(net);
-}
-#endif
-
-static void __net_exit ipv4_frags_exit_net(struct net *net)
-{
-}
-
-static struct pernet_operations ip4_frags_ops = {
-#ifdef HAVE_DEFRAG_ENABLE_TAKES_NET
- .init = ipv4_frags_init_net,
-#endif
- .exit = ipv4_frags_exit_net,
-};
-
-int __init rpl_ipfrag_init(void)
-{
-#ifndef HAVE_DEFRAG_ENABLE_TAKES_NET
- nf_defrag_ipv4_enable();
-#endif
- register_pernet_subsys(&ip4_frags_ops);
- ip4_frags.hashfn = ip4_hashfn;
- ip4_frags.constructor = ip4_frag_init;
- ip4_frags.destructor = ip4_frag_free;
- ip4_frags.skb_free = NULL;
- ip4_frags.qsize = sizeof(struct ipq);
- ip4_frags.match = ip4_frag_match;
- ip4_frags.frag_expire = ip_expire;
-#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK
- ip4_frags.frags_cache_name = ip_frag_cache_name;
-#endif
-#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0)
- ip4_frags.secret_interval = 10 * 60 * HZ;
-#endif
- if (inet_frags_init(&ip4_frags)) {
- pr_warn("IP: failed to allocate ip4_frags cache\n");
- return -ENOMEM;
- }
- return 0;
-}
-
-void rpl_ipfrag_fini(void)
-{
- inet_frags_fini(&ip4_frags);
- unregister_pernet_subsys(&ip4_frags_ops);
-}
-
-#endif /* !HAVE_CORRECT_MRU_HANDLING */
diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c
deleted file mode 100644
index c194ffe00..000000000
--- a/datapath/linux/compat/ip_gre.c
+++ /dev/null
@@ -1,1450 +0,0 @@
-/*
- * Linux NET3: GRE over IP protocol decoder.
- *
- * Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#ifndef USE_UPSTREAM_TUNNEL
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/kconfig.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/netdev_features.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include <linux/if_arp.h>
-#include <linux/mroute.h>
-#include <linux/if_vlan.h>
-#include <linux/init.h>
-#include <linux/in6.h>
-#include <linux/inetdevice.h>
-#include <linux/igmp.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-
-#include <net/sock.h>
-#include <net/ip.h>
-#include <net/icmp.h>
-#include <net/protocol.h>
-#include <net/ip_tunnels.h>
-#include <net/arp.h>
-#include <net/checksum.h>
-#include <net/dsfield.h>
-#include <net/inet_ecn.h>
-#include <net/xfrm.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/rtnetlink.h>
-#include <net/gre.h>
-#include <net/dst_metadata.h>
-#include <net/erspan.h>
-
-#if IS_ENABLED(CONFIG_IPV6)
-#include <net/ipv6.h>
-#include <net/ip6_fib.h>
-#include <net/ip6_route.h>
-#endif
-
-#include "gso.h"
-#include "vport-netdev.h"
-
-static int gre_tap_net_id __read_mostly;
-static unsigned int erspan_net_id __read_mostly;
-static void erspan_build_header(struct sk_buff *skb,
- __be32 id, u32 index,
- bool truncate, bool is_ipv4);
-
-static bool ip_gre_loaded = false;
-
-/* Normally in net/core/dst.c but move it here */
-struct dst_ops md_dst_ops = {
- .family = AF_UNSPEC,
-};
-
-#ifndef ip_gre_calc_hlen
-#define ip_gre_calc_hlen gre_calc_hlen
-#endif
-
-static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
- int gre_hdr_len)
-{
- struct net *net = dev_net(skb->dev);
- struct metadata_dst *tun_dst = NULL;
- struct erspan_base_hdr *ershdr;
- struct erspan_metadata *pkt_md;
- struct ip_tunnel_net *itn;
- struct ip_tunnel *tunnel;
- const struct iphdr *iph;
- struct erspan_md2 *md2;
- int ver;
- int len;
-
- itn = net_generic(net, erspan_net_id);
- len = gre_hdr_len + sizeof(*ershdr);
-
- /* Check based hdr len */
- if (unlikely(!pskb_may_pull(skb, len)))
- return PACKET_REJECT;
-
- iph = ip_hdr(skb);
- ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
- ver = ershdr->ver;
-
- /* The original GRE header does not have key field,
- * Use ERSPAN 10-bit session ID as key.
- */
- tpi->key = cpu_to_be32(get_session_id(ershdr));
- tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
- tpi->flags,
- iph->saddr, iph->daddr, tpi->key);
-
- if (tunnel) {
- len = gre_hdr_len + erspan_hdr_len(ver);
- if (unlikely(!pskb_may_pull(skb, len)))
- return PACKET_REJECT;
-
- ershdr = (struct erspan_base_hdr *)skb->data;
- pkt_md = (struct erspan_metadata *)(ershdr + 1);
-
- if (__iptunnel_pull_header(skb,
- len,
- htons(ETH_P_TEB),
- false, false) < 0)
- goto drop;
-
- if (tunnel->collect_md) {
- struct ip_tunnel_info *info;
- struct erspan_metadata *md;
- __be64 tun_id;
- __be16 flags;
-
- tpi->flags |= TUNNEL_KEY;
- flags = tpi->flags;
- tun_id = key32_to_tunnel_id(tpi->key);
-
- tun_dst = rpl_ip_tun_rx_dst(skb, flags, tun_id, sizeof(*md));
- if (!tun_dst)
- return PACKET_REJECT;
-
- md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
- md->version = ver;
- md2 = &md->u.md2;
- memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
- ERSPAN_V2_MDSIZE);
-
- info = &tun_dst->u.tun_info;
- info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
- info->options_len = sizeof(*md);
- }
-
- skb_reset_mac_header(skb);
- ovs_ip_tunnel_rcv(tunnel->dev, skb, tun_dst);
- kfree(tun_dst);
- return PACKET_RCVD;
- }
-drop:
- kfree_skb(skb);
- return PACKET_RCVD;
-}
-
-
-static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
- struct ip_tunnel_net *itn, int hdr_len, bool raw_proto)
-{
- struct metadata_dst tun_dst;
- const struct iphdr *iph;
- struct ip_tunnel *tunnel;
-
- iph = ip_hdr(skb);
- tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
- iph->saddr, iph->daddr, tpi->key);
-
- if (tunnel) {
- if (__iptunnel_pull_header(skb, hdr_len, tpi->proto,
- raw_proto, false) < 0)
- goto drop;
-
- if (tunnel->dev->type != ARPHRD_NONE)
- skb_pop_mac_header(skb);
- else
- skb_reset_mac_header(skb);
- if (tunnel->collect_md) {
- __be16 flags;
- __be64 tun_id;
-
- flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY);
- tun_id = key32_to_tunnel_id(tpi->key);
- ovs_ip_tun_rx_dst(&tun_dst, skb, flags, tun_id, 0);
- }
-
- ovs_ip_tunnel_rcv(tunnel->dev, skb, &tun_dst);
- return PACKET_RCVD;
- }
- return PACKET_NEXT;
-
-drop:
- kfree_skb(skb);
- return PACKET_RCVD;
-}
-
-
-static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
- int hdr_len)
-{
- struct net *net = dev_net(skb->dev);
- struct ip_tunnel_net *itn;
- int res;
-
- if (tpi->proto == htons(ETH_P_TEB))
- itn = net_generic(net, gre_tap_net_id);
- else if (tpi->proto == htons(ETH_P_ERSPAN) ||
- tpi->proto == htons(ETH_P_ERSPAN2))
- itn = net_generic(net, erspan_net_id);
- else
- return PACKET_RCVD;
-
- res = __ipgre_rcv(skb, tpi, itn, hdr_len, false);
-
- return res;
-}
-
-static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
- const struct iphdr *tnl_params,
- __be16 proto)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- struct tnl_ptk_info tpi;
-
- tpi.flags = tunnel->parms.o_flags;
- tpi.proto = proto;
- tpi.key = tunnel->parms.o_key;
- if (tunnel->parms.o_flags & TUNNEL_SEQ)
- tunnel->o_seqno++;
- tpi.seq = htonl(tunnel->o_seqno);
-
- /* Push GRE header. */
- gre_build_header(skb, &tpi, tunnel->hlen);
-
- ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
-}
-
-static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *unused_tpi)
-{
- struct tnl_ptk_info tpi;
- bool csum_err = false;
- int hdr_len;
-
- hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0);
- if (hdr_len < 0)
- goto drop;
-
- if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
- tpi.proto == htons(ETH_P_ERSPAN2))) {
- if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
- return 0;
- goto drop;
- }
-
- if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
- return 0;
-drop:
-
- kfree_skb(skb);
- return 0;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
-#include "gso.h"
-/* gre_handle_offloads() has different return type on older kernsl. */
-static void gre_nop_fix(struct sk_buff *skb) { }
-
-static void gre_csum_fix(struct sk_buff *skb)
-{
- struct gre_base_hdr *greh;
- __be32 *options;
- int gre_offset = skb_transport_offset(skb);
-
- greh = (struct gre_base_hdr *)skb_transport_header(skb);
- options = ((__be32 *)greh + 1);
-
- *options = 0;
- *(__sum16 *)options = csum_fold(skb_checksum(skb, gre_offset,
- skb->len - gre_offset, 0));
-}
-
-#define gre_handle_offloads rpl_gre_handle_offloads
-static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
-{
- int type = gre_csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE;
- gso_fix_segment_t fix_segment;
-
- if (gre_csum)
- fix_segment = gre_csum_fix;
- else
- fix_segment = gre_nop_fix;
-
- return ovs_iptunnel_handle_offloads(skb, type, fix_segment);
-}
-#else
-static int gre_handle_offloads(struct sk_buff *skb, bool csum)
-{
- return iptunnel_handle_offloads(skb, csum,
- csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
-}
-#endif
-
-static bool is_gre_gso(struct sk_buff *skb)
-{
- return skb_shinfo(skb)->gso_type &
- (SKB_GSO_GRE | SKB_GSO_GRE_CSUM);
-}
-
-static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
- __be16 proto, __be32 key, __be32 seq)
-{
- struct gre_base_hdr *greh;
-
- skb_push(skb, hdr_len);
-
- skb_reset_transport_header(skb);
- greh = (struct gre_base_hdr *)skb->data;
- greh->flags = tnl_flags_to_gre_flags(flags);
- greh->protocol = proto;
-
- if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
- __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
-
- if (flags & TUNNEL_SEQ) {
- *ptr = seq;
- ptr--;
- }
- if (flags & TUNNEL_KEY) {
- *ptr = key;
- ptr--;
- }
- if (flags & TUNNEL_CSUM && !is_gre_gso(skb)) {
- *ptr = 0;
- *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
- skb->len, 0));
- }
- }
- ovs_skb_set_inner_protocol(skb, proto);
-}
-
-static struct rtable *gre_get_rt(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi4 *fl,
- const struct ip_tunnel_key *key)
-{
- struct net *net = dev_net(dev);
-
- memset(fl, 0, sizeof(*fl));
- fl->daddr = key->u.ipv4.dst;
- fl->saddr = key->u.ipv4.src;
- fl->flowi4_tos = RT_TOS(key->tos);
- fl->flowi4_mark = skb->mark;
- fl->flowi4_proto = IPPROTO_GRE;
-
- return ip_route_output_key(net, fl);
-}
-
-static struct rtable *prepare_fb_xmit(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi4 *fl,
- int tunnel_hlen)
-{
- struct ip_tunnel_info *tun_info;
- const struct ip_tunnel_key *key;
- struct rtable *rt = NULL;
- int min_headroom;
- bool use_cache;
- int err;
-
- tun_info = skb_tunnel_info(skb);
- key = &tun_info->key;
- use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
-
- if (use_cache)
- rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl->saddr);
- if (!rt) {
- rt = gre_get_rt(skb, dev, fl, key);
- if (IS_ERR(rt))
- goto err_free_skb;
- if (use_cache)
- dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
- fl->saddr);
- }
-
- min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
- + tunnel_hlen + sizeof(struct iphdr);
- if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
- int head_delta = SKB_DATA_ALIGN(min_headroom -
- skb_headroom(skb) +
- 16);
- err = pskb_expand_head(skb, max_t(int, head_delta, 0),
- 0, GFP_ATOMIC);
- if (unlikely(err))
- goto err_free_rt;
- }
- return rt;
-
-err_free_rt:
- ip_rt_put(rt);
-err_free_skb:
- kfree_skb(skb);
- dev->stats.tx_dropped++;
- return NULL;
-}
-
-netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- struct ip_tunnel_info *tun_info;
- const struct ip_tunnel_key *key;
- struct flowi4 fl;
- struct rtable *rt;
- int min_headroom;
- int tunnel_hlen;
- __be16 df, flags;
- int err;
-
- tun_info = skb_tunnel_info(skb);
- if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
- ip_tunnel_info_af(tun_info) != AF_INET))
- goto err_free_skb;
-
- key = &tun_info->key;
-
- rt = gre_get_rt(skb, dev, &fl, key);
- if (IS_ERR(rt))
- goto err_free_skb;
-
- tunnel_hlen = ip_gre_calc_hlen(key->tun_flags);
-
- min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
- + tunnel_hlen + sizeof(struct iphdr)
- + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
- if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
- int head_delta = SKB_DATA_ALIGN(min_headroom -
- skb_headroom(skb) +
- 16);
- err = pskb_expand_head(skb, max_t(int, head_delta, 0),
- 0, GFP_ATOMIC);
- if (unlikely(err))
- goto err_free_rt;
- }
-
- if (skb_vlan_tag_present(skb)) {
- skb = __vlan_hwaccel_push_inside(skb);
- if (unlikely(!skb)) {
- err = -ENOMEM;
- goto err_free_rt;
- }
- }
-
- /* Push Tunnel header. */
- err = gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM));
- if (err)
- goto err_free_rt;
-
- flags = tun_info->key.tun_flags & (TUNNEL_CSUM | TUNNEL_KEY);
- build_header(skb, tunnel_hlen, flags, htons(ETH_P_TEB),
- tunnel_id_to_key32(tun_info->key.tun_id), 0);
-
- df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
- iptunnel_xmit(skb->sk, rt, skb, fl.saddr, key->u.ipv4.dst, IPPROTO_GRE,
- key->tos, key->ttl, df, false);
- return NETDEV_TX_OK;
-
-err_free_rt:
- ip_rt_put(rt);
-err_free_skb:
- kfree_skb(skb);
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
-}
-EXPORT_SYMBOL(rpl_gre_fb_xmit);
-
-static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
- __be16 proto)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- struct ip_tunnel_info *tun_info;
- const struct ip_tunnel_key *key;
- struct erspan_metadata *md;
- struct rtable *rt = NULL;
- struct tnl_ptk_info tpi;
- bool truncate = false;
- struct flowi4 fl;
- int tunnel_hlen;
- int version;
- __be16 df;
- int nhoff;
- int thoff;
-
- tun_info = skb_tunnel_info(skb);
- if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
- ip_tunnel_info_af(tun_info) != AF_INET))
- goto err_free_skb;
-
- key = &tun_info->key;
- if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
- goto err_free_rt;
- md = ip_tunnel_info_opts(tun_info);
- if (!md)
- goto err_free_rt;
-
- /* ERSPAN has fixed 8 byte GRE header */
- version = md->version;
- tunnel_hlen = 8 + erspan_hdr_len(version);
-
- rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen);
- if (!rt)
- return;
-
- if (gre_handle_offloads(skb, false))
- goto err_free_rt;
-
- if (skb->len > dev->mtu + dev->hard_header_len) {
- pskb_trim(skb, dev->mtu + dev->hard_header_len);
- truncate = true;
- }
-
- nhoff = skb_network_header(skb) - skb_mac_header(skb);
- if (skb->protocol == htons(ETH_P_IP) &&
- (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
- truncate = true;
-
- thoff = skb_transport_header(skb) - skb_mac_header(skb);
- if (skb->protocol == htons(ETH_P_IPV6) &&
- (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff))
- truncate = true;
-
- if (version == 1) {
- erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)),
- ntohl(md->u.index), truncate, true);
- tpi.hdr_len = ERSPAN_V1_MDSIZE;
- tpi.proto = htons(ETH_P_ERSPAN);
- } else if (version == 2) {
- erspan_build_header_v2(skb,
- ntohl(tunnel_id_to_key32(key->tun_id)),
- md->u.md2.dir,
- get_hwid(&md->u.md2),
- truncate, true);
- tpi.hdr_len = ERSPAN_V2_MDSIZE;
- tpi.proto = htons(ETH_P_ERSPAN2);
- } else {
- goto err_free_rt;
- }
-
- tpi.flags = TUNNEL_SEQ;
- tpi.key = tunnel_id_to_key32(key->tun_id);
- tpi.seq = htonl(tunnel->o_seqno++);
-
- gre_build_header(skb, &tpi, 8);
-
- df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
-
- iptunnel_xmit(skb->sk, rt, skb, fl.saddr, key->u.ipv4.dst, IPPROTO_GRE,
- key->tos, key->ttl, df, false);
- return;
-
-err_free_rt:
- ip_rt_put(rt);
-err_free_skb:
- kfree_skb(skb);
- dev->stats.tx_dropped++;
-}
-
-#define GRE_FEATURES (NETIF_F_SG | \
- NETIF_F_FRAGLIST | \
- NETIF_F_HIGHDMA | \
- NETIF_F_HW_CSUM | \
- NETIF_F_NETNS_LOCAL)
-
-static void __gre_tunnel_init(struct net_device *dev)
-{
- struct ip_tunnel *tunnel;
-
- tunnel = netdev_priv(dev);
- tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
- tunnel->parms.iph.protocol = IPPROTO_GRE;
-
- tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
-
- dev->features |= GRE_FEATURES;
- dev->hw_features |= GRE_FEATURES;
-
- if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
- /* TCP offload with GRE SEQ is not supported, nor
- * can we support 2 levels of outer headers requiring
- * an update.
- */
- if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
- (tunnel->encap.type == TUNNEL_ENCAP_NONE)) {
- dev->features |= NETIF_F_GSO_SOFTWARE;
- dev->hw_features |= NETIF_F_GSO_SOFTWARE;
- }
-
- /* Can use a lockless transmit, unless we generate
- * output sequences
- */
- dev->features |= NETIF_F_LLTX;
- }
-}
-
-static int __gre_rcv(struct sk_buff *skb)
-{
- return gre_rcv(skb, NULL);
-}
-
-void __gre_err(struct sk_buff *skb, u32 info)
-{
- pr_warn("%s: GRE receive error\n", __func__);
-}
-
-static const struct gre_protocol ipgre_protocol = {
- .handler = __gre_rcv,
- .err_handler = __gre_err,
-};
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- __be16 flags;
-
- if (!data)
- return 0;
-
- flags = 0;
- if (data[IFLA_GRE_IFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
- if (data[IFLA_GRE_OFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
- if (flags & (GRE_VERSION|GRE_ROUTING))
- return -EINVAL;
-
- return 0;
-}
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- __be32 daddr;
-
- if (tb[IFLA_ADDRESS]) {
- if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
- return -EINVAL;
- if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
- return -EADDRNOTAVAIL;
- }
-
- if (!data)
- goto out;
-
- if (data[IFLA_GRE_REMOTE]) {
- memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
- if (!daddr)
- return -EINVAL;
- }
-
-out:
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
- return ipgre_tunnel_validate(tb, data, NULL);
-#else
- return ipgre_tunnel_validate(tb, data);
-#endif
-}
-
-enum {
-#ifndef HAVE_IFLA_GRE_ENCAP_DPORT
- IFLA_GRE_ENCAP_TYPE = IFLA_GRE_FLAGS + 1,
- IFLA_GRE_ENCAP_FLAGS,
- IFLA_GRE_ENCAP_SPORT,
- IFLA_GRE_ENCAP_DPORT,
-#endif
-#ifndef HAVE_IFLA_GRE_COLLECT_METADATA
- IFLA_GRE_COLLECT_METADATA = IFLA_GRE_ENCAP_DPORT + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_IGNORE_DF
- IFLA_GRE_IGNORE_DF = IFLA_GRE_COLLECT_METADATA + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_FWMARK
- IFLA_GRE_FWMARK = IFLA_GRE_IGNORE_DF + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_ERSPAN_INDEX
- IFLA_GRE_ERSPAN_INDEX = IFLA_GRE_FWMARK + 1,
-#endif
-#ifndef HAVE_IFLA_GRE_ERSPAN_HWID
- IFLA_GRE_ERSPAN_VER = IFLA_GRE_ERSPAN_INDEX + 1,
- IFLA_GRE_ERSPAN_DIR,
- IFLA_GRE_ERSPAN_HWID,
-#endif
-};
-
-#define RPL_IFLA_GRE_MAX (IFLA_GRE_ERSPAN_HWID + 1)
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int erspan_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- __be16 flags = 0;
- int ret;
-
- if (!data)
- return 0;
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
- ret = ipgre_tap_validate(tb, data, NULL);
-#else
- ret = ipgre_tap_validate(tb, data);
-#endif
- if (ret)
- return ret;
-
- /* ERSPAN should only have GRE sequence and key flag */
- if (data[IFLA_GRE_OFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
- if (data[IFLA_GRE_IFLAGS])
- flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
- if (!data[IFLA_GRE_COLLECT_METADATA] &&
- flags != (GRE_SEQ | GRE_KEY))
- return -EINVAL;
-
- /* ERSPAN Session ID only has 10-bit. Since we reuse
- * 32-bit key field as ID, check it's range.
- */
- if (data[IFLA_GRE_OKEY] &&
- (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
- return -EINVAL;
-
- return 0;
-}
-
-static int ipgre_netlink_parms(struct net_device *dev,
- struct nlattr *data[],
- struct nlattr *tb[],
- struct ip_tunnel_parm *parms)
-{
- struct ip_tunnel *t = netdev_priv(dev);
-
- memset(parms, 0, sizeof(*parms));
-
- parms->iph.protocol = IPPROTO_GRE;
-
- if (!data)
- return 0;
-
- if (data[IFLA_GRE_LINK])
- parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
-
- if (data[IFLA_GRE_IFLAGS])
- parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
-
- if (data[IFLA_GRE_OFLAGS])
- parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
-
- if (data[IFLA_GRE_IKEY])
- parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
-
- if (data[IFLA_GRE_OKEY])
- parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
-
- if (data[IFLA_GRE_LOCAL])
- parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]);
-
- if (data[IFLA_GRE_REMOTE])
- parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]);
-
- if (data[IFLA_GRE_TTL])
- parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
-
- if (data[IFLA_GRE_TOS])
- parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
-
- if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) {
- if (t->ignore_df)
- return -EINVAL;
- parms->iph.frag_off = htons(IP_DF);
- }
-
- if (data[IFLA_GRE_COLLECT_METADATA]) {
- t->collect_md = true;
- if (dev->type == ARPHRD_IPGRE)
- dev->type = ARPHRD_NONE;
- }
-
- if (data[IFLA_GRE_IGNORE_DF]) {
- if (nla_get_u8(data[IFLA_GRE_IGNORE_DF])
- && (parms->iph.frag_off & htons(IP_DF)))
- return -EINVAL;
- t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
- }
-
- if (data[IFLA_GRE_ERSPAN_INDEX]) {
- t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
-
- if (t->index & ~INDEX_MASK)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int gre_tap_init(struct net_device *dev)
-{
- __gre_tunnel_init(dev);
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
-
- return ip_tunnel_init(dev);
-}
-
-static netdev_tx_t gre_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;
-}
-
-static netdev_tx_t erspan_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- bool truncate = false;
-
- if (tunnel->collect_md) {
- erspan_fb_xmit(skb, dev, skb->protocol);
- return NETDEV_TX_OK;
- }
-
- if (gre_handle_offloads(skb, false))
- goto free_skb;
-
- if (skb_cow_head(skb, dev->needed_headroom))
- goto free_skb;
-
- if (skb->len > dev->mtu + dev->hard_header_len) {
- pskb_trim(skb, dev->mtu + dev->hard_header_len);
- truncate = true;
- }
-
- /* Push ERSPAN header */
- if (tunnel->erspan_ver == 1)
- erspan_build_header(skb, ntohl(tunnel->parms.o_key),
- tunnel->index,
- truncate, true);
- else if (tunnel->erspan_ver == 2)
- erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key),
- tunnel->dir, tunnel->hwid,
- truncate, true);
- else
- goto free_skb;
-
- tunnel->parms.o_flags &= ~TUNNEL_KEY;
- __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN));
- return NETDEV_TX_OK;
-
-free_skb:
- kfree_skb(skb);
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
-}
-
-static netdev_tx_t __erspan_fb_xmit(struct sk_buff *skb)
-{
- erspan_fb_xmit(skb, skb->dev, skb->protocol);
- return NETDEV_TX_OK;
-}
-
-int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
-{
- struct ip_tunnel_info *info = skb_tunnel_info(skb);
- struct rtable *rt;
- struct flowi4 fl4;
-
- if (ip_tunnel_info_af(info) != AF_INET)
- return -EINVAL;
-
- rt = gre_get_rt(skb, dev, &fl4, &info->key);
- if (IS_ERR(rt))
- return PTR_ERR(rt);
-
- ip_rt_put(rt);
- info->key.u.ipv4.src = fl4.saddr;
- return 0;
-}
-EXPORT_SYMBOL_GPL(ovs_gre_fill_metadata_dst);
-
-static int erspan_tunnel_init(struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
-
- tunnel->tun_hlen = 8;
- tunnel->parms.iph.protocol = IPPROTO_GRE;
- tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
- erspan_hdr_len(tunnel->erspan_ver);
-
- dev->features |= GRE_FEATURES;
- dev->hw_features |= GRE_FEATURES;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
- netif_keep_dst(dev);
-
- return ip_tunnel_init(dev);
-}
-
-static const struct net_device_ops gre_tap_netdev_ops = {
- .ndo_init = gre_tap_init,
- .ndo_uninit = rpl_ip_tunnel_uninit,
- .ndo_start_xmit = gre_dev_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = ip_tunnel_change_mtu,
-#else
- .ndo_change_mtu = ip_tunnel_change_mtu,
-#endif
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_NDO_GET_IFLINK
- .ndo_get_iflink = rpl_ip_tunnel_get_iflink,
-#endif
-#ifdef HAVE_NDO_FILL_METADATA_DST
- .ndo_fill_metadata_dst = gre_fill_metadata_dst,
-#endif
-};
-
-static const struct net_device_ops erspan_netdev_ops = {
- .ndo_init = erspan_tunnel_init,
- .ndo_uninit = rpl_ip_tunnel_uninit,
- .ndo_start_xmit = erspan_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = ip_tunnel_change_mtu,
-#else
- .ndo_change_mtu = ip_tunnel_change_mtu,
-#endif
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_NDO_GET_IFLINK
- .ndo_get_iflink = rpl_ip_tunnel_get_iflink,
-#endif
-#ifdef HAVE_NDO_FILL_METADATA_DST
- .ndo_fill_metadata_dst = gre_fill_metadata_dst,
-#endif
-};
-
-static void ipgre_tap_setup(struct net_device *dev)
-{
- ether_setup(dev);
-#ifdef HAVE_NET_DEVICE_MAX_MTU
- dev->max_mtu = 0;
-#endif
- dev->netdev_ops = &gre_tap_netdev_ops;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
- ip_tunnel_setup(dev, gre_tap_net_id);
-}
-
-static void erspan_setup(struct net_device *dev)
-{
- struct ip_tunnel *t = netdev_priv(dev);
-
- eth_hw_addr_random(dev);
- ether_setup(dev);
-#ifdef HAVE_NET_DEVICE_MAX_MTU
- dev->max_mtu = 0;
-#endif
- dev->netdev_ops = &erspan_netdev_ops;
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
- ip_tunnel_setup(dev, erspan_net_id);
- t->erspan_ver = 1;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int ipgre_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int ipgre_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- struct ip_tunnel_parm p;
- int err;
-
- ipgre_netlink_parms(dev, data, tb, &p);
- err = ip_tunnel_newlink(dev, tb, &p);
- return err;
-
-}
-
-static size_t ipgre_get_size(const struct net_device *dev)
-{
- return
- /* IFLA_GRE_LINK */
- nla_total_size(4) +
- /* IFLA_GRE_IFLAGS */
- nla_total_size(2) +
- /* IFLA_GRE_OFLAGS */
- nla_total_size(2) +
- /* IFLA_GRE_IKEY */
- nla_total_size(4) +
- /* IFLA_GRE_OKEY */
- nla_total_size(4) +
- /* IFLA_GRE_LOCAL */
- nla_total_size(4) +
- /* IFLA_GRE_REMOTE */
- nla_total_size(4) +
- /* IFLA_GRE_TTL */
- nla_total_size(1) +
- /* IFLA_GRE_TOS */
- nla_total_size(1) +
- /* IFLA_GRE_PMTUDISC */
- nla_total_size(1) +
- /* IFLA_GRE_ENCAP_TYPE */
- nla_total_size(2) +
- /* IFLA_GRE_ENCAP_FLAGS */
- nla_total_size(2) +
- /* IFLA_GRE_ENCAP_SPORT */
- nla_total_size(2) +
- /* IFLA_GRE_ENCAP_DPORT */
- nla_total_size(2) +
- /* IFLA_GRE_COLLECT_METADATA */
- nla_total_size(0) +
- /* IFLA_GRE_ERSPAN_INDEX */
- nla_total_size(4) +
- /* IFLA_GRE_ERSPAN_VER */
- nla_total_size(1) +
- /* IFLA_GRE_ERSPAN_DIR */
- nla_total_size(1) +
- /* IFLA_GRE_ERSPAN_HWID */
- nla_total_size(2) +
- 0;
-}
-
-static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- struct ip_tunnel *t = netdev_priv(dev);
- struct ip_tunnel_parm *p = &t->parms;
-
- if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
- nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) ||
- nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) ||
- nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
- nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
- nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
- nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
- nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
- nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
- nla_put_u8(skb, IFLA_GRE_PMTUDISC,
- !!(p->iph.frag_off & htons(IP_DF))))
- goto nla_put_failure;
-
- if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
- goto nla_put_failure;
-
- if (t->erspan_ver == 1) {
- if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
- goto nla_put_failure;
- } else if (t->erspan_ver == 2) {
- if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
- goto nla_put_failure;
- if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
- goto nla_put_failure;
- }
-
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-static const struct nla_policy ipgre_policy[RPL_IFLA_GRE_MAX + 1] = {
- [IFLA_GRE_LINK] = { .type = NLA_U32 },
- [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
- [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
- [IFLA_GRE_IKEY] = { .type = NLA_U32 },
- [IFLA_GRE_OKEY] = { .type = NLA_U32 },
- [IFLA_GRE_LOCAL] = { .len = sizeof_field(struct iphdr, saddr) },
- [IFLA_GRE_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) },
- [IFLA_GRE_TTL] = { .type = NLA_U8 },
- [IFLA_GRE_TOS] = { .type = NLA_U8 },
- [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
- [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
- [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 },
- [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 },
- [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 },
-};
-
-static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
- .kind = "ovs_gretap",
- .maxtype = RPL_IFLA_GRE_MAX,
- .policy = ipgre_policy,
- .priv_size = sizeof(struct ip_tunnel),
- .setup = ipgre_tap_setup,
- .validate = ipgre_tap_validate,
- .newlink = ipgre_newlink,
- .dellink = ip_tunnel_dellink,
- .get_size = ipgre_get_size,
- .fill_info = ipgre_fill_info,
-#ifdef HAVE_GET_LINK_NET
- .get_link_net = ip_tunnel_get_link_net,
-#endif
-};
-
-static struct rtnl_link_ops erspan_link_ops __read_mostly = {
- .kind = "erspan",
- .maxtype = RPL_IFLA_GRE_MAX,
- .policy = ipgre_policy,
- .priv_size = sizeof(struct ip_tunnel),
- .setup = erspan_setup,
- .validate = erspan_validate,
- .newlink = ipgre_newlink,
- .dellink = ip_tunnel_dellink,
- .get_size = ipgre_get_size,
- .fill_info = ipgre_fill_info,
-#ifdef HAVE_GET_LINK_NET
- .get_link_net = ip_tunnel_get_link_net,
-#endif
-};
-
-struct net_device *rpl_gretap_fb_dev_create(struct net *net, const char *name,
- u8 name_assign_type)
-{
- struct nlattr *tb[IFLA_MAX + 1];
- struct net_device *dev;
- LIST_HEAD(list_kill);
- struct ip_tunnel *t;
- int err;
-
- memset(&tb, 0, sizeof(tb));
-
- dev = rtnl_create_link(net, (char *)name, name_assign_type,
- &ipgre_tap_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- t = netdev_priv(dev);
- t->collect_md = true;
- /* Configure flow based GRE device. */
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- err = ipgre_newlink(net, dev, tb, NULL, NULL);
-#else
- err = ipgre_newlink(net, dev, tb, NULL);
-#endif
- if (err < 0) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
- /* openvswitch users expect packet sizes to be unrestricted,
- * so set the largest MTU we can.
- */
- err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
- if (err)
- goto out;
-
- return dev;
-out:
- ip_tunnel_dellink(dev, &list_kill);
- unregister_netdevice_many(&list_kill);
- return ERR_PTR(err);
-}
-EXPORT_SYMBOL_GPL(rpl_gretap_fb_dev_create);
-
-static int __net_init erspan_init_net(struct net *net)
-{
- return ip_tunnel_init_net(net, erspan_net_id,
- &erspan_link_ops, NULL);
-}
-
-static void __net_exit erspan_exit_net(struct net *net)
-{
- struct ip_tunnel_net *itn = net_generic(net, erspan_net_id);
-
- ip_tunnel_delete_net(itn, &erspan_link_ops);
-}
-
-static struct pernet_operations erspan_net_ops = {
- .init = erspan_init_net,
- .exit = erspan_exit_net,
- .id = &erspan_net_id,
- .size = sizeof(struct ip_tunnel_net),
-};
-
-static int __net_init ipgre_tap_init_net(struct net *net)
-{
- return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "ovs-gretap0");
-}
-
-static void __net_exit ipgre_tap_exit_net(struct net *net)
-{
- struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id);
-
- ip_tunnel_delete_net(itn, &ipgre_tap_ops);
-}
-
-static struct pernet_operations ipgre_tap_net_ops = {
- .init = ipgre_tap_init_net,
- .exit = ipgre_tap_exit_net,
- .id = &gre_tap_net_id,
- .size = sizeof(struct ip_tunnel_net),
-};
-
-static struct net_device *erspan_fb_dev_create(struct net *net,
- const char *name,
- u8 name_assign_type)
-{
- struct nlattr *tb[IFLA_MAX + 1];
- struct net_device *dev;
- LIST_HEAD(list_kill);
- struct ip_tunnel *t;
- int err;
-
- memset(&tb, 0, sizeof(tb));
-
- dev = rtnl_create_link(net, (char *)name, name_assign_type,
- &erspan_link_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- t = netdev_priv(dev);
- t->collect_md = true;
- /* Configure flow based GRE device. */
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
- err = ipgre_newlink(net, dev, tb, NULL, NULL);
-#else
- err = ipgre_newlink(net, dev, tb, NULL);
-#endif
- if (err < 0) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
- /* openvswitch users expect packet sizes to be unrestricted,
- * so set the largest MTU we can.
- */
- err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
- if (err)
- goto out;
-
- return dev;
-out:
- ip_tunnel_dellink(dev, &list_kill);
- unregister_netdevice_many(&list_kill);
- return ERR_PTR(err);
-}
-
-static struct vport_ops ovs_erspan_vport_ops;
-
-static struct vport *erspan_tnl_create(const struct vport_parms *parms)
-{
- struct net *net = ovs_dp_get_net(parms->dp);
- struct net_device *dev;
- struct vport *vport;
- int err;
-
- vport = ovs_vport_alloc(0, &ovs_erspan_vport_ops, parms);
- if (IS_ERR(vport))
- return vport;
-
- rtnl_lock();
- dev = erspan_fb_dev_create(net, parms->name, NET_NAME_USER);
- 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);
- return ERR_PTR(err);
- }
-
- rtnl_unlock();
- return vport;
-}
-
-static struct vport *erspan_create(const struct vport_parms *parms)
-{
- struct vport *vport;
-
- vport = erspan_tnl_create(parms);
- if (IS_ERR(vport))
- return vport;
-
- return ovs_netdev_link(vport, parms->name);
-}
-
-static struct vport_ops ovs_erspan_vport_ops = {
- .type = OVS_VPORT_TYPE_ERSPAN,
- .create = erspan_create,
- .send = __erspan_fb_xmit,
-#ifndef USE_UPSTREAM_TUNNEL
- .fill_metadata_dst = gre_fill_metadata_dst,
-#endif
- .destroy = ovs_netdev_tunnel_destroy,
-};
-
-static struct vport_ops ovs_ipgre_vport_ops;
-
-static struct vport *ipgre_tnl_create(const struct vport_parms *parms)
-{
- struct net *net = ovs_dp_get_net(parms->dp);
- struct net_device *dev;
- struct vport *vport;
- int err;
-
- vport = ovs_vport_alloc(0, &ovs_ipgre_vport_ops, parms);
- if (IS_ERR(vport))
- return vport;
-
- rtnl_lock();
- dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER);
- 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);
- return ERR_PTR(err);
- }
-
- rtnl_unlock();
- return vport;
-}
-
-static struct vport *ipgre_create(const struct vport_parms *parms)
-{
- struct vport *vport;
-
- vport = ipgre_tnl_create(parms);
- if (IS_ERR(vport))
- return vport;
-
- return ovs_netdev_link(vport, parms->name);
-}
-
-static struct vport_ops ovs_ipgre_vport_ops = {
- .type = OVS_VPORT_TYPE_GRE,
- .create = ipgre_create,
- .send = gre_fb_xmit,
-#ifndef USE_UPSTREAM_TUNNEL
- .fill_metadata_dst = gre_fill_metadata_dst,
-#endif
- .destroy = ovs_netdev_tunnel_destroy,
-};
-
-int rpl_ipgre_init(void)
-{
- int err;
-
- err = register_pernet_device(&ipgre_tap_net_ops);
- if (err < 0) {
- if (err == -EEXIST)
- goto ip_gre_loaded;
- else
- goto pnet_tap_failed;
- }
-
- err = register_pernet_device(&erspan_net_ops);
- if (err < 0) {
- if (err == -EEXIST)
- goto ip_gre_loaded;
- else
- goto pnet_erspan_failed;
- }
-
- err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
- if (err < 0) {
- pr_info("%s: can't add protocol\n", __func__);
- if (err == -EBUSY) {
- goto ip_gre_loaded;
- } else {
- goto add_proto_failed;
- }
- }
-
- pr_info("GRE over IPv4 tunneling driver\n");
- ovs_vport_ops_register(&ovs_ipgre_vport_ops);
- ovs_vport_ops_register(&ovs_erspan_vport_ops);
- return 0;
-
-ip_gre_loaded:
- /* Since GRE only allows single receiver to be registerd,
- * we skip here so only gre transmit works, see:
- *
- * commit 9f57c67c379d88a10e8ad676426fee5ae7341b14
- * Author: Pravin B Shelar <pshelar@nicira.com>
- * Date: Fri Aug 7 23:51:52 2015 -0700
- * gre: Remove support for sharing GRE protocol hook
- *
- * OVS GRE receive part is disabled.
- */
- pr_info("GRE TX only over IPv4 tunneling driver\n");
- ip_gre_loaded = true;
- ovs_vport_ops_register(&ovs_ipgre_vport_ops);
- ovs_vport_ops_register(&ovs_erspan_vport_ops);
- return 0;
-
-add_proto_failed:
- unregister_pernet_device(&erspan_net_ops);
-pnet_erspan_failed:
- unregister_pernet_device(&ipgre_tap_net_ops);
-pnet_tap_failed:
- pr_err("Error while initializing GRE %d\n", err);
- return err;
-}
-
-void rpl_ipgre_fini(void)
-{
- ovs_vport_ops_unregister(&ovs_erspan_vport_ops);
- ovs_vport_ops_unregister(&ovs_ipgre_vport_ops);
-
- if (!ip_gre_loaded) {
- gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
- unregister_pernet_device(&erspan_net_ops);
- unregister_pernet_device(&ipgre_tap_net_ops);
- }
-}
-
-#endif
diff --git a/datapath/linux/compat/ip_output.c b/datapath/linux/compat/ip_output.c
deleted file mode 100644
index e2f869f9a..000000000
--- a/datapath/linux/compat/ip_output.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * IP fragmentation backport, heavily based on linux/net/ipv4/ip_output.c,
- * copied from Linux ae7ef81ef000 ("skbuff: introduce skb_gso_validate_mtu")
- *
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * The Internet Protocol (IP) output module.
- *
- * Authors: Ross Biro
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Donald Becker, <becker@super.org>
- * Alan Cox, <Alan.Cox@linux.org>
- * Richard Underwood
- * Stefan Becker, <stefanb@yello.ping.de>
- * Jorge Cwik, <jorge@laser.satlink.net>
- * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- * Hirokazu Takahashi, <taka@valinux.co.jp>
- *
- * See ip_input.c for original log
- *
- * Fixes:
- * Alan Cox : Missing nonblock feature in ip_build_xmit.
- * Mike Kilburn : htons() missing in ip_build_xmit.
- * Bradford Johnson: Fix faulty handling of some frames when
- * no route is found.
- * Alexander Demenshin: Missing sk/skb free in ip_queue_xmit
- * (in case if packet not accepted by
- * output firewall rules)
- * Mike McLagan : Routing by source
- * Alexey Kuznetsov: use new route cache
- * Andi Kleen: Fix broken PMTU recovery and remove
- * some redundant tests.
- * Vitaly E. Lavrov : Transparent proxy revived after year coma.
- * Andi Kleen : Replace ip_reply with ip_send_reply.
- * Andi Kleen : Split fast and slow ip_build_xmit path
- * for decreased register pressure on x86
- * and more readibility.
- * Marc Boucher : When call_out_firewall returns FW_QUEUE,
- * silently drop skb instead of failing with -EPERM.
- * Detlev Wengorz : Copy protocol for fragments.
- * Hirokazu Takahashi: HW checksumming for outgoing UDP
- * datagrams.
- * Hirokazu Takahashi: sendfile() on UDP works now.
- */
-
-#ifndef HAVE_CORRECT_MRU_HANDLING
-#include <asm/uaccess.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-
-#include <net/snmp.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <net/xfrm.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/arp.h>
-#include <net/icmp.h>
-#include <net/checksum.h>
-#include <net/inetpeer.h>
-#include <linux/igmp.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_bridge.h>
-#include <linux/netlink.h>
-#include <linux/tcp.h>
-
-static inline void rpl_ip_options_fragment(struct sk_buff *skb)
-{
- unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr);
- struct ip_options *opt = &(IPCB(skb)->opt);
- int l = opt->optlen;
- int optlen;
-
- while (l > 0) {
- switch (*optptr) {
- case IPOPT_END:
- return;
- case IPOPT_NOOP:
- l--;
- optptr++;
- continue;
- }
- optlen = optptr[1];
- if (optlen < 2 || optlen > l)
- return;
- if (!IPOPT_COPIED(*optptr))
- memset(optptr, IPOPT_NOOP, optlen);
- l -= optlen;
- optptr += optlen;
- }
- opt->ts = 0;
- opt->rr = 0;
- opt->rr_needaddr = 0;
- opt->ts_needaddr = 0;
- opt->ts_needtime = 0;
-}
-#define ip_options_fragment rpl_ip_options_fragment
-
-static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
-{
- to->pkt_type = from->pkt_type;
- to->priority = from->priority;
- to->protocol = from->protocol;
- skb_dst_drop(to);
- skb_dst_copy(to, from);
- to->dev = from->dev;
- to->mark = from->mark;
-
- /* Copy the flags to each fragment. */
- IPCB(to)->flags = IPCB(from)->flags;
-
-#ifdef CONFIG_NET_SCHED
- to->tc_index = from->tc_index;
-#endif
- nf_copy(to, from);
-#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
- to->ipvs_property = from->ipvs_property;
-#endif
- skb_copy_secmark(to, from);
-}
-
-#ifdef HAVE_IP_DO_FRAGMENT_USING_NET
-#define OUTPUT(net, sk, skb) output(net, sk, skb)
-#elif defined(HAVE_IP_FRAGMENT_TAKES_SOCK)
-#define OUTPUT(net, sk, skb) output(sk, skb)
-#else
-#define OUTPUT(net, sk, skb) output(skb)
-#endif
-
-/*
- * This IP datagram is too large to be sent in one piece. Break it up into
- * smaller pieces (each of size equal to IP header plus
- * a block of the data of the original IP data part) that will yet fit in a
- * single device frame, and queue such a frame for sending.
- */
-
-int rpl_ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
- int (*output)(OVS_VPORT_OUTPUT_PARAMS))
-{
- struct iphdr *iph;
- int ptr;
- struct net_device *dev;
- struct sk_buff *skb2;
- unsigned int mtu, hlen, left, len, ll_rs;
- int offset;
- __be16 not_last_frag;
- struct rtable *rt = skb_rtable(skb);
- int err = 0;
-
- dev = rt->dst.dev;
-
- /* for offloaded checksums cleanup checksum before fragmentation */
- if (skb->ip_summed == CHECKSUM_PARTIAL &&
- (err = skb_checksum_help(skb)))
- goto fail;
-
- /*
- * Point into the IP datagram header.
- */
-
- iph = ip_hdr(skb);
-
- mtu = ip_skb_dst_mtu(skb);
- if (IPCB(skb)->frag_max_size && IPCB(skb)->frag_max_size < mtu)
- mtu = IPCB(skb)->frag_max_size;
-
- /*
- * Setup starting values.
- */
-
- hlen = iph->ihl * 4;
- mtu = mtu - hlen; /* Size of data space */
- IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
-
- /* When frag_list is given, use it. First, check its validity:
- * some transformers could create wrong frag_list or break existing
- * one, it is not prohibited. In this case fall back to copying.
- *
- * LATER: this step can be merged to real generation of fragments,
- * we can switch to copy when see the first bad fragment.
- */
- if (skb_has_frag_list(skb)) {
- struct sk_buff *frag, *frag2;
- int first_len = skb_pagelen(skb);
-
- if (first_len - hlen > mtu ||
- ((first_len - hlen) & 7) ||
- ip_is_fragment(iph) ||
- skb_cloned(skb))
- goto slow_path;
-
- skb_walk_frags(skb, frag) {
- /* Correct geometry. */
- if (frag->len > mtu ||
- ((frag->len & 7) && frag->next) ||
- skb_headroom(frag) < hlen)
- goto slow_path_clean;
-
- /* Partially cloned skb? */
- if (skb_shared(frag))
- goto slow_path_clean;
-
- BUG_ON(frag->sk);
- if (skb->sk) {
- frag->sk = skb->sk;
- frag->destructor = sock_wfree;
- }
- skb->truesize -= frag->truesize;
- }
-
- /* Everything is OK. Generate! */
-
- err = 0;
- offset = 0;
- frag = skb_shinfo(skb)->frag_list;
- skb_frag_list_init(skb);
- skb->data_len = first_len - skb_headlen(skb);
- skb->len = first_len;
- iph->tot_len = htons(first_len);
- iph->frag_off = htons(IP_MF);
- ip_send_check(iph);
-
- for (;;) {
- /* Prepare header of the next frame,
- * before previous one went down. */
- if (frag) {
- frag->ip_summed = CHECKSUM_NONE;
- skb_reset_transport_header(frag);
- __skb_push(frag, hlen);
- skb_reset_network_header(frag);
- memcpy(skb_network_header(frag), iph, hlen);
- iph = ip_hdr(frag);
- iph->tot_len = htons(frag->len);
- ip_copy_metadata(frag, skb);
- if (offset == 0)
- ip_options_fragment(frag);
- offset += skb->len - hlen;
- iph->frag_off = htons(offset>>3);
- if (frag->next)
- iph->frag_off |= htons(IP_MF);
- /* Ready, complete checksum */
- ip_send_check(iph);
- }
-
- err = OUTPUT(net, sk, skb);
-
- if (!err)
- IP_INC_STATS(net, IPSTATS_MIB_FRAGCREATES);
- if (err || !frag)
- break;
-
- skb = frag;
- frag = skb->next;
- skb->next = NULL;
- }
-
- if (err == 0) {
- IP_INC_STATS(net, IPSTATS_MIB_FRAGOKS);
- return 0;
- }
-
- while (frag) {
- skb = frag->next;
- kfree_skb(frag);
- frag = skb;
- }
- IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
- return err;
-
-slow_path_clean:
- skb_walk_frags(skb, frag2) {
- if (frag2 == frag)
- break;
- frag2->sk = NULL;
- frag2->destructor = NULL;
- skb->truesize += frag2->truesize;
- }
- }
-
-slow_path:
- iph = ip_hdr(skb);
-
- left = skb->len - hlen; /* Space per frame */
- ptr = hlen; /* Where to start from */
-
- ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
-
- /*
- * Fragment the datagram.
- */
-
- offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3;
- not_last_frag = iph->frag_off & htons(IP_MF);
-
- /*
- * Keep copying data until we run out.
- */
-
- while (left > 0) {
- len = left;
- /* IF: it doesn't fit, use 'mtu' - the data space left */
- if (len > mtu)
- len = mtu;
- /* IF: we are not sending up to and including the packet end
- then align the next start on an eight byte boundary */
- if (len < left) {
- len &= ~7;
- }
-
- /* Allocate buffer */
- skb2 = alloc_skb(len + hlen + ll_rs, GFP_ATOMIC);
- if (!skb2) {
- err = -ENOMEM;
- goto fail;
- }
-
- /*
- * Set up data on packet
- */
-
- ip_copy_metadata(skb2, skb);
- skb_reserve(skb2, ll_rs);
- skb_put(skb2, len + hlen);
- skb_reset_network_header(skb2);
- skb2->transport_header = skb2->network_header + hlen;
-
- /*
- * Charge the memory for the fragment to any owner
- * it might possess
- */
-
- if (skb->sk)
- skb_set_owner_w(skb2, skb->sk);
-
- /*
- * Copy the packet header into the new buffer.
- */
-
- skb_copy_from_linear_data(skb, skb_network_header(skb2), hlen);
-
- /*
- * Copy a block of the IP datagram.
- */
- if (skb_copy_bits(skb, ptr, skb_transport_header(skb2), len))
- BUG();
- left -= len;
-
- /*
- * Fill in the new header fields.
- */
- iph = ip_hdr(skb2);
- iph->frag_off = htons((offset >> 3));
-
- if (IPCB(skb)->flags & IPSKB_FRAG_PMTU)
- iph->frag_off |= htons(IP_DF);
-
- /* ANK: dirty, but effective trick. Upgrade options only if
- * the segment to be fragmented was THE FIRST (otherwise,
- * options are already fixed) and make it ONCE
- * on the initial skb, so that all the following fragments
- * will inherit fixed options.
- */
- if (offset == 0)
- ip_options_fragment(skb);
-
- /*
- * Added AC : If we are fragmenting a fragment that's not the
- * last fragment then keep MF on each bit
- */
- if (left > 0 || not_last_frag)
- iph->frag_off |= htons(IP_MF);
- ptr += len;
- offset += len;
-
- /*
- * Put this fragment into the sending queue.
- */
- iph->tot_len = htons(len + hlen);
-
- ip_send_check(iph);
-
- err = OUTPUT(net, sk, skb2);
- if (err)
- goto fail;
-
- IP_INC_STATS(net, IPSTATS_MIB_FRAGCREATES);
- }
- consume_skb(skb);
- IP_INC_STATS(net, IPSTATS_MIB_FRAGOKS);
- return err;
-
-fail:
- kfree_skb(skb);
- IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
- return err;
-}
-EXPORT_SYMBOL(rpl_ip_do_fragment);
-
-#endif /* HAVE_CORRECT_MRU_HANDLING */
diff --git a/datapath/linux/compat/ip_tunnel.c b/datapath/linux/compat/ip_tunnel.c
deleted file mode 100644
index e7a039358..000000000
--- a/datapath/linux/compat/ip_tunnel.c
+++ /dev/null
@@ -1,776 +0,0 @@
-/*
- * Copyright (c) 2013,2018 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include <linux/if_arp.h>
-#include <linux/mroute.h>
-#include <linux/init.h>
-#include <linux/in6.h>
-#include <linux/inetdevice.h>
-#include <linux/igmp.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/if_vlan.h>
-#include <linux/rculist.h>
-#include <linux/err.h>
-
-#include <net/sock.h>
-#include <net/ip.h>
-#include <net/icmp.h>
-#include <net/protocol.h>
-#include <net/ip_tunnels.h>
-#include <net/arp.h>
-#include <net/checksum.h>
-#include <net/dsfield.h>
-#include <net/inet_ecn.h>
-#include <net/xfrm.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/rtnetlink.h>
-#include <net/dst_metadata.h>
-
-#if IS_ENABLED(CONFIG_IPV6)
-#include <net/ipv6.h>
-#include <net/ip6_fib.h>
-#include <net/ip6_route.h>
-#endif
-
-#include "compat.h"
-
-#ifndef USE_UPSTREAM_TUNNEL
-const struct ip_tunnel_encap_ops __rcu *
- rpl_iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly;
-
-static unsigned int rpl_ip_tunnel_hash(__be32 key, __be32 remote)
-{
- return hash_32((__force u32)key ^ (__force u32)remote,
- IP_TNL_HASH_BITS);
-}
-
-static bool rpl_ip_tunnel_key_match(const struct ip_tunnel_parm *p,
- __be16 flags, __be32 key)
-{
- if (p->i_flags & TUNNEL_KEY) {
- if (flags & TUNNEL_KEY)
- return key == p->i_key;
- else
- /* key expected, none present */
- return false;
- } else
- return !(flags & TUNNEL_KEY);
-}
-
-static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn,
- struct ip_tunnel_parm *parms)
-{
- unsigned int h;
- __be32 remote;
- __be32 i_key = parms->i_key;
-
- if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr))
- remote = parms->iph.daddr;
- else
- remote = 0;
-
- if (!(parms->i_flags & TUNNEL_KEY) && (parms->i_flags & VTI_ISVTI))
- i_key = 0;
-
- h = rpl_ip_tunnel_hash(i_key, remote);
- return &itn->tunnels[h];
-}
-
-static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t)
-{
- struct hlist_head *head = ip_bucket(itn, &t->parms);
-
- if (t->collect_md)
- rcu_assign_pointer(itn->collect_md_tun, t);
- hlist_add_head_rcu(&t->hash_node, head);
-}
-
-static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t)
-{
- if (t->collect_md)
- rcu_assign_pointer(itn->collect_md_tun, NULL);
- hlist_del_init_rcu(&t->hash_node);
-}
-
-static struct net_device *__ip_tunnel_create(struct net *net,
- const struct rtnl_link_ops *ops,
- struct ip_tunnel_parm *parms)
-{
- int err;
- struct ip_tunnel *tunnel;
- struct net_device *dev;
- char name[IFNAMSIZ];
-
- if (parms->name[0])
- strlcpy(name, parms->name, IFNAMSIZ);
- else {
- if (strlen(ops->kind) > (IFNAMSIZ - 3)) {
- err = -E2BIG;
- goto failed;
- }
- strlcpy(name, ops->kind, IFNAMSIZ);
- strncat(name, "%d", 2);
- }
-
- ASSERT_RTNL();
- dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup);
- if (!dev) {
- err = -ENOMEM;
- goto failed;
- }
- dev_net_set(dev, net);
-
- dev->rtnl_link_ops = ops;
-
- tunnel = netdev_priv(dev);
- tunnel->parms = *parms;
- tunnel->net = net;
-
- err = register_netdevice(dev);
- if (err)
- goto failed_free;
-
- return dev;
-
-failed_free:
- free_netdev(dev);
-failed:
- return ERR_PTR(err);
-}
-
-static inline void init_tunnel_flow(struct flowi4 *fl4,
- int proto,
- __be32 daddr, __be32 saddr,
- __be32 key, __u8 tos, int oif)
-{
- memset(fl4, 0, sizeof(*fl4));
- fl4->flowi4_oif = oif;
- fl4->daddr = daddr;
- fl4->saddr = saddr;
- fl4->flowi4_tos = tos;
- fl4->flowi4_proto = proto;
- fl4->fl4_gre_key = key;
-}
-
-static int ip_tunnel_bind_dev(struct net_device *dev)
-{
- struct net_device *tdev = NULL;
- struct ip_tunnel *tunnel = netdev_priv(dev);
- const struct iphdr *iph;
- int hlen = LL_MAX_HEADER;
- int mtu = ETH_DATA_LEN;
- int t_hlen = tunnel->hlen + sizeof(struct iphdr);
-
- iph = &tunnel->parms.iph;
-
- /* Guess output device to choose reasonable mtu and needed_headroom */
- if (iph->daddr) {
- struct flowi4 fl4;
- struct rtable *rt;
-
- init_tunnel_flow(&fl4, iph->protocol, iph->daddr,
- iph->saddr, tunnel->parms.o_key,
- RT_TOS(iph->tos), tunnel->parms.link);
- rt = ip_route_output_key(tunnel->net, &fl4);
-
- if (!IS_ERR(rt)) {
- tdev = rt->dst.dev;
- ip_rt_put(rt);
- }
- if (dev->type != ARPHRD_ETHER)
- dev->flags |= IFF_POINTOPOINT;
-
- dst_cache_reset(&tunnel->dst_cache);
- }
-
- if (!tdev && tunnel->parms.link)
- tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link);
-
- if (tdev) {
- hlen = tdev->hard_header_len + tdev->needed_headroom;
- mtu = tdev->mtu;
- }
-
- dev->needed_headroom = t_hlen + hlen;
- mtu -= (dev->hard_header_len + t_hlen);
-
- if (mtu < 68)
- mtu = 68;
-
- return mtu;
-}
-
-int rpl___ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- int t_hlen = tunnel->hlen + sizeof(struct iphdr);
- int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;
-
- if (new_mtu < 68)
- return -EINVAL;
-
- if (new_mtu > max_mtu) {
- if (strict)
- return -EINVAL;
-
- new_mtu = max_mtu;
- }
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-int rpl_ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
-{
- return rpl___ip_tunnel_change_mtu(dev, new_mtu, true);
-}
-
-static int rpl_tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
- struct rtable *rt, __be16 df,
- const struct iphdr *inner_iph)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len;
- int mtu;
-
- if (df)
- mtu = dst_mtu(&rt->dst) - dev->hard_header_len
- - sizeof(struct iphdr) - tunnel->hlen;
- else
- mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
-
- if (skb_valid_dst(skb))
-#ifndef HAVE_DST_OPS_CONFIRM_NEIGH
- skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
-#else
- skb_dst(skb)->ops->update_pmtu(skb_dst(skb),
- NULL, skb, mtu, false);
-#endif
-
- if (skb->protocol == htons(ETH_P_IP)) {
- if (!skb_is_gso(skb) &&
- (inner_iph->frag_off & htons(IP_DF)) &&
- mtu < pkt_size) {
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
- return -E2BIG;
- }
- }
-#if IS_ENABLED(CONFIG_IPV6)
- else if (skb->protocol == htons(ETH_P_IPV6)) {
- struct rt6_info *rt6;
-
- rt6 = skb_valid_dst(skb) ? (struct rt6_info *)skb_dst(skb) :
- NULL;
-
- if (rt6 && mtu < dst_mtu(skb_dst(skb)) &&
- mtu >= IPV6_MIN_MTU) {
- if ((tunnel->parms.iph.daddr &&
- !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
- rt6->rt6i_dst.plen == 128) {
- rt6->rt6i_flags |= RTF_MODIFIED;
- dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
- }
- }
-
- if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU &&
- mtu < pkt_size) {
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- return -E2BIG;
- }
- }
-#endif
- return 0;
-}
-
-void rpl_ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
- const struct iphdr *tnl_params, const u8 protocol)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- const struct iphdr *inner_iph;
- struct flowi4 fl4;
- u8 tos, ttl;
- __be16 df;
- struct rtable *rt; /* Route to the other host */
- unsigned int max_headroom; /* The extra header space needed */
- __be32 dst;
- bool connected;
-
- inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
- connected = (tunnel->parms.iph.daddr != 0);
-
- dst = tnl_params->daddr;
- if (dst == 0) {
- /* NBMA tunnel */
-
- if (skb_dst(skb) == NULL) {
- dev->stats.tx_fifo_errors++;
- goto tx_error;
- }
-
- if (skb->protocol == htons(ETH_P_IP)) {
- rt = skb_rtable(skb);
- dst = rt_nexthop(rt, inner_iph->daddr);
- }
-#if IS_ENABLED(CONFIG_IPV6)
- else if (skb->protocol == htons(ETH_P_IPV6)) {
- const struct in6_addr *addr6;
- struct neighbour *neigh;
- bool do_tx_error_icmp;
- int addr_type;
-
- neigh = dst_neigh_lookup(skb_dst(skb),
- &ipv6_hdr(skb)->daddr);
- if (neigh == NULL)
- goto tx_error;
-
- addr6 = (const struct in6_addr *)&neigh->primary_key;
- addr_type = ipv6_addr_type(addr6);
-
- if (addr_type == IPV6_ADDR_ANY) {
- addr6 = &ipv6_hdr(skb)->daddr;
- addr_type = ipv6_addr_type(addr6);
- }
-
- if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
- do_tx_error_icmp = true;
- else {
- do_tx_error_icmp = false;
- dst = addr6->s6_addr32[3];
- }
- neigh_release(neigh);
- if (do_tx_error_icmp)
- goto tx_error_icmp;
- }
-#endif
- else
- goto tx_error;
-
- connected = false;
- }
-
- tos = tnl_params->tos;
- if (tos & 0x1) {
- tos &= ~0x1;
- if (skb->protocol == htons(ETH_P_IP)) {
- tos = inner_iph->tos;
- connected = false;
- } else if (skb->protocol == htons(ETH_P_IPV6)) {
- tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
- connected = false;
- }
- }
-
- init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
- tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link);
-
- if (ovs_ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
- goto tx_error;
-
- rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) :
- NULL;
-
- if (!rt) {
- rt = ip_route_output_key(tunnel->net, &fl4);
-
- if (IS_ERR(rt)) {
- dev->stats.tx_carrier_errors++;
- goto tx_error;
- }
- if (connected)
- dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
- fl4.saddr);
- }
-
- if (rt->dst.dev == dev) {
- ip_rt_put(rt);
- dev->stats.collisions++;
- goto tx_error;
- }
-
- if (rpl_tnl_update_pmtu(dev, skb, rt,
- tnl_params->frag_off, inner_iph)) {
- ip_rt_put(rt);
- goto tx_error;
- }
-
- if (tunnel->err_count > 0) {
- if (time_before(jiffies,
- tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
- tunnel->err_count--;
-
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
- dst_link_failure(skb);
- } else
- tunnel->err_count = 0;
- }
-
- tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
- ttl = tnl_params->ttl;
- if (ttl == 0) {
- if (skb->protocol == htons(ETH_P_IP))
- ttl = inner_iph->ttl;
-#if IS_ENABLED(CONFIG_IPV6)
- else if (skb->protocol == htons(ETH_P_IPV6))
- ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
-#endif
- else
- ttl = ip4_dst_hoplimit(&rt->dst);
- }
-
- df = tnl_params->frag_off;
- if (skb->protocol == htons(ETH_P_IP))
- df |= (inner_iph->frag_off&htons(IP_DF));
-
- max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
- + rt->dst.header_len;
- if (max_headroom > dev->needed_headroom)
- dev->needed_headroom = max_headroom;
-
- if (skb_cow_head(skb, dev->needed_headroom)) {
- ip_rt_put(rt);
- dev->stats.tx_dropped++;
- kfree_skb(skb);
- return;
- }
-
- iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, protocol,
- tos, ttl, df, !net_eq(tunnel->net, dev_net(dev)));
-
- return;
-
-#if IS_ENABLED(CONFIG_IPV6)
-tx_error_icmp:
- dst_link_failure(skb);
-#endif
-tx_error:
- dev->stats.tx_errors++;
- kfree_skb(skb);
-}
-EXPORT_SYMBOL_GPL(rpl_ip_tunnel_xmit);
-
-static void ip_tunnel_dev_free(struct net_device *dev)
-{
- free_percpu(dev->tstats);
-#ifndef HAVE_NEEDS_FREE_NETDEV
- free_netdev(dev);
-#endif
-}
-
-void rpl_ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- struct ip_tunnel_net *itn;
-
- itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id);
-
- if (itn->fb_tunnel_dev != dev) {
- ip_tunnel_del(itn, netdev_priv(dev));
- unregister_netdevice_queue(dev, head);
- }
-}
-
-int rpl_ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
- struct rtnl_link_ops *ops, char *devname)
-{
- struct ip_tunnel_net *itn = net_generic(net, ip_tnl_net_id);
- struct ip_tunnel_parm parms;
- unsigned int i;
-
- for (i = 0; i < IP_TNL_HASH_SIZE; i++)
- INIT_HLIST_HEAD(&itn->tunnels[i]);
-
- if (!ops) {
- itn->fb_tunnel_dev = NULL;
- return 0;
- }
-
- memset(&parms, 0, sizeof(parms));
- if (devname)
- strlcpy(parms.name, devname, IFNAMSIZ);
-
- rtnl_lock();
- itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms);
- /* FB netdevice is special: we have one, and only one per netns.
- * * Allowing to move it to another netns is clearly unsafe.
- * */
- if (!IS_ERR(itn->fb_tunnel_dev)) {
- itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
- itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev);
- ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
- }
- rtnl_unlock();
-
- return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev);
-}
-
-static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head,
- struct rtnl_link_ops *ops)
-{
- struct net *net = dev_net(itn->fb_tunnel_dev);
- struct net_device *dev, *aux;
- int h;
-
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == ops)
- unregister_netdevice_queue(dev, head);
-
- for (h = 0; h < IP_TNL_HASH_SIZE; h++) {
- struct ip_tunnel *t;
- struct hlist_node *n;
- struct hlist_head *thead = &itn->tunnels[h];
-
- hlist_for_each_entry_safe(t, n, thead, hash_node)
- /* If dev is in the same netns, it has already
- * been added to the list by the previous loop.
- */
- if (!net_eq(dev_net(t->dev), net))
- unregister_netdevice_queue(t->dev, head);
- }
-}
-
-void rpl_ip_tunnel_delete_net(struct ip_tunnel_net *itn,
- struct rtnl_link_ops *ops)
-{
- LIST_HEAD(list);
-
- rtnl_lock();
- ip_tunnel_destroy(itn, &list, ops);
- unregister_netdevice_many(&list);
- rtnl_unlock();
-}
-
-int rpl_ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
- struct ip_tunnel_parm *p)
-{
- struct ip_tunnel *nt;
- struct net *net = dev_net(dev);
- struct ip_tunnel_net *itn;
- int mtu;
- int err;
-
- nt = netdev_priv(dev);
- itn = net_generic(net, nt->ip_tnl_net_id);
-
- if (nt->collect_md) {
- if (rtnl_dereference(itn->collect_md_tun))
- return -EEXIST;
- } else {
- return -EOPNOTSUPP;
- }
-
- nt->net = net;
- nt->parms = *p;
- err = register_netdevice(dev);
- if (err)
- goto out;
-
- if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
- eth_hw_addr_random(dev);
-
- mtu = ip_tunnel_bind_dev(dev);
- if (!tb[IFLA_MTU])
- dev->mtu = mtu;
-
- ip_tunnel_add(itn, nt);
-out:
- return err;
-}
-
-int rpl_ip_tunnel_init(struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- struct iphdr *iph = &tunnel->parms.iph;
- int err;
-
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = ip_tunnel_dev_free;
-#else
- dev->needs_free_netdev = true;
- dev->priv_destructor = ip_tunnel_dev_free;
-#endif
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
- if (err) {
- free_percpu(dev->tstats);
- return err;
- }
-
- err = gro_cells_init(&tunnel->gro_cells, dev);
- if (err) {
- dst_cache_destroy(&tunnel->dst_cache);
- free_percpu(dev->tstats);
- return err;
- }
-
- tunnel->dev = dev;
- tunnel->net = dev_net(dev);
- strcpy(tunnel->parms.name, dev->name);
- iph->version = 4;
- iph->ihl = 5;
-
- if (tunnel->collect_md) {
- dev->features |= NETIF_F_NETNS_LOCAL;
- netif_keep_dst(dev);
- }
- return 0;
-}
-
-void rpl_ip_tunnel_uninit(struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net *net = tunnel->net;
- struct ip_tunnel_net *itn;
-
- itn = net_generic(net, tunnel->ip_tnl_net_id);
- if (itn->fb_tunnel_dev != dev)
- ip_tunnel_del(itn, netdev_priv(dev));
-}
-
-/* Do least required initialization, rest of init is done in tunnel_init call */
-void rpl_ip_tunnel_setup(struct net_device *dev, int net_id)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
-
- tunnel->ip_tnl_net_id = net_id;
-}
-
-int rpl_ip_tunnel_get_iflink(const struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
-
- return tunnel->parms.link;
-}
-
-struct net *rpl_ip_tunnel_get_link_net(const struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
-
- return tunnel->net;
-}
-
-struct ip_tunnel *rpl_ip_tunnel_lookup(struct ip_tunnel_net *itn,
- int link, __be16 flags,
- __be32 remote, __be32 local,
- __be32 key)
-{
- unsigned int hash;
- struct ip_tunnel *t, *cand = NULL;
- struct hlist_head *head;
-
- hash = rpl_ip_tunnel_hash(key, remote);
- head = &itn->tunnels[hash];
-
- hlist_for_each_entry_rcu(t, head, hash_node) {
- if (local != t->parms.iph.saddr ||
- remote != t->parms.iph.daddr ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (!rpl_ip_tunnel_key_match(&t->parms, flags, key))
- continue;
-
- if (t->parms.link == link)
- return t;
- else
- cand = t;
- }
-
- hlist_for_each_entry_rcu(t, head, hash_node) {
- if (remote != t->parms.iph.daddr ||
- t->parms.iph.saddr != 0 ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (!rpl_ip_tunnel_key_match(&t->parms, flags, key))
- continue;
-
- if (t->parms.link == link)
- return t;
- else if (!cand)
- cand = t;
- }
-
- hash = rpl_ip_tunnel_hash(key, 0);
- head = &itn->tunnels[hash];
-
- hlist_for_each_entry_rcu(t, head, hash_node) {
- if ((local != t->parms.iph.saddr || t->parms.iph.daddr != 0) &&
- (local != t->parms.iph.daddr || !ipv4_is_multicast(local)))
- continue;
-
- if (!(t->dev->flags & IFF_UP))
- continue;
-
- if (!rpl_ip_tunnel_key_match(&t->parms, flags, key))
- continue;
-
- if (t->parms.link == link)
- return t;
- else if (!cand)
- cand = t;
- }
-
- if (flags & TUNNEL_NO_KEY)
- goto skip_key_lookup;
-
- hlist_for_each_entry_rcu(t, head, hash_node) {
- if (t->parms.i_key != key ||
- t->parms.iph.saddr != 0 ||
- t->parms.iph.daddr != 0 ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (t->parms.link == link)
- return t;
- else if (!cand)
- cand = t;
- }
-
-skip_key_lookup:
- if (cand)
- return cand;
-
- t = rcu_dereference(itn->collect_md_tun);
- if (t)
- return t;
-
- if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP)
- return netdev_priv(itn->fb_tunnel_dev);
-
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(rpl_ip_tunnel_lookup);
-
-#endif
diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c
deleted file mode 100644
index a3b1f7fc1..000000000
--- a/datapath/linux/compat/ip_tunnels_core.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (c) 2007-2013 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/if_vlan.h>
-#include <linux/in.h>
-#include <linux/in_route.h>
-#include <linux/inetdevice.h>
-#include <linux/jhash.h>
-#include <linux/list.h>
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/workqueue.h>
-#include <linux/rculist.h>
-#include <net/ip_tunnels.h>
-#include <net/ip6_tunnel.h>
-#include <net/route.h>
-#include <net/xfrm.h>
-
-#include "compat.h"
-#include "gso.h"
-#include "vport-netdev.h"
-
-#ifndef USE_UPSTREAM_TUNNEL
-void rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
- __be32 src, __be32 dst, __u8 proto, __u8 tos, __u8 ttl,
- __be16 df, bool xnet)
-{
- struct net_device *dev = skb->dev;
- int pkt_len = skb->len - skb_inner_network_offset(skb);
- struct iphdr *iph;
- int err;
-
- skb_scrub_packet(skb, xnet);
-
- skb_clear_hash(skb);
- skb_dst_set(skb, &rt->dst);
-
-#if 0
- /* Do not clear ovs_skb_cb. It will be done in gso code. */
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-#endif
-
- /* Push down and install the IP header. */
- __skb_push(skb, sizeof(struct iphdr));
- skb_reset_network_header(skb);
-
- iph = ip_hdr(skb);
-
- iph->version = 4;
- iph->ihl = sizeof(struct iphdr) >> 2;
- iph->frag_off = df;
- iph->protocol = proto;
- iph->tos = tos;
- iph->daddr = dst;
- iph->saddr = src;
- iph->ttl = ttl;
-
-#ifdef HAVE_IP_SELECT_IDENT_USING_DST_ENTRY
- __ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1);
-#elif defined(HAVE_IP_SELECT_IDENT_USING_NET)
- __ip_select_ident(dev_net(rt->dst.dev), iph,
- skb_shinfo(skb)->gso_segs ?: 1);
-#else
- __ip_select_ident(iph, skb_shinfo(skb)->gso_segs ?: 1);
-#endif
-
- err = ip_local_out(dev_net(rt->dst.dev), sk, skb);
- if (unlikely(net_xmit_eval(err)))
- pkt_len = 0;
- iptunnel_xmit_stats(dev, pkt_len);
-}
-EXPORT_SYMBOL_GPL(rpl_iptunnel_xmit);
-
-int ovs_iptunnel_handle_offloads(struct sk_buff *skb,
- int gso_type_mask,
- void (*fix_segment)(struct sk_buff *))
-{
- int err;
-
- if (likely(!skb_is_encapsulated(skb))) {
- skb_reset_inner_headers(skb);
- skb->encapsulation = 1;
- } else if (skb_is_gso(skb)) {
- err = -ENOSYS;
- goto error;
- }
-
- if (skb_is_gso(skb)) {
- err = skb_unclone(skb, GFP_ATOMIC);
- if (unlikely(err))
- goto error;
- skb_shinfo(skb)->gso_type |= gso_type_mask;
-
-#ifndef USE_UPSTREAM_TUNNEL_GSO
- if (gso_type_mask)
- fix_segment = NULL;
-
- OVS_GSO_CB(skb)->fix_segment = fix_segment;
-#endif
- return 0;
- }
-
- if (skb->ip_summed != CHECKSUM_PARTIAL) {
- skb->ip_summed = CHECKSUM_NONE;
- skb->encapsulation = 0;
- }
-
- return 0;
-error:
- return err;
-}
-EXPORT_SYMBOL_GPL(ovs_iptunnel_handle_offloads);
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
-struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb,
- bool csum_help,
- int gso_type_mask)
-#else
-int rpl_iptunnel_handle_offloads(struct sk_buff *skb,
- bool csum_help,
- int gso_type_mask)
-#endif
-{
- int err;
-
- if (likely(!skb->encapsulation)) {
- skb_reset_inner_headers(skb);
- skb->encapsulation = 1;
- }
-
- if (skb_is_gso(skb)) {
- err = skb_unclone(skb, GFP_ATOMIC);
- if (unlikely(err))
- goto error;
- skb_shinfo(skb)->gso_type |= gso_type_mask;
- goto out;
- }
-
- /* If packet is not gso and we are resolving any partial checksum,
- * clear encapsulation flag. This allows setting CHECKSUM_PARTIAL
- * on the outer header without confusing devices that implement
- * NETIF_F_IP_CSUM with encapsulation.
- */
- if (csum_help)
- skb->encapsulation = 0;
-
- if (skb->ip_summed == CHECKSUM_PARTIAL && csum_help) {
- err = skb_checksum_help(skb);
- if (unlikely(err))
- goto error;
- } else if (skb->ip_summed != CHECKSUM_PARTIAL)
- skb->ip_summed = CHECKSUM_NONE;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
-out:
- return skb;
-error:
- kfree_skb(skb);
- return ERR_PTR(err);
-#else
-out:
-error:
- return 0;
-#endif
-}
-EXPORT_SYMBOL_GPL(rpl_iptunnel_handle_offloads);
-
-int rpl___iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
- __be16 inner_proto, bool raw_proto, bool xnet)
-{
- if (unlikely(!pskb_may_pull(skb, hdr_len)))
- return -ENOMEM;
-
- skb_pull_rcsum(skb, hdr_len);
-
- if (!raw_proto && inner_proto == htons(ETH_P_TEB)) {
- struct ethhdr *eh;
-
- if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
- return -ENOMEM;
-
- eh = (struct ethhdr *)skb->data;
- if (likely(eth_proto_is_802_3(eh->h_proto)))
- skb->protocol = eh->h_proto;
- else
- skb->protocol = htons(ETH_P_802_2);
-
- } else {
- skb->protocol = inner_proto;
- }
-
- skb_clear_hash_if_not_l4(skb);
- skb->vlan_tci = 0;
- skb_set_queue_mapping(skb, 0);
- skb_scrub_packet(skb, xnet);
-
- return iptunnel_pull_offloads(skb);
-}
-EXPORT_SYMBOL_GPL(rpl___iptunnel_pull_header);
-#endif /* USE_UPSTREAM_TUNNEL */
-
-bool ovs_skb_is_encapsulated(struct sk_buff *skb)
-{
- /* checking for inner protocol should be sufficient on newer kernel, but
- * old kernel just set encapsulation bit.
- */
- return ovs_skb_get_inner_protocol(skb) || skb->encapsulation;
-}
-EXPORT_SYMBOL_GPL(ovs_skb_is_encapsulated);
-
-/* derived from ip_tunnel_rcv(). */
-void ovs_ip_tunnel_rcv(struct net_device *dev, struct sk_buff *skb,
- struct metadata_dst *tun_dst)
-{
- struct pcpu_sw_netstats *tstats;
-
- tstats = this_cpu_ptr((struct pcpu_sw_netstats __percpu *)dev->tstats);
- u64_stats_update_begin(&tstats->syncp);
- tstats->rx_packets++;
- tstats->rx_bytes += skb->len;
- u64_stats_update_end(&tstats->syncp);
-
- skb_reset_mac_header(skb);
- skb_scrub_packet(skb, false);
- skb->protocol = eth_type_trans(skb, dev);
- skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
-
- ovs_skb_dst_set(skb, (struct dst_entry *)tun_dst);
-
-#ifndef USE_UPSTREAM_TUNNEL
- netdev_port_receive(skb, &tun_dst->u.tun_info);
-#else
- netif_rx(skb);
-#endif
-}
-
-#ifndef HAVE_PCPU_SW_NETSTATS
-#define netdev_stats_to_stats64 rpl_netdev_stats_to_stats64
-static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
- const struct net_device_stats *netdev_stats)
-{
-#if BITS_PER_LONG == 64
- BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats));
- memcpy(stats64, netdev_stats, sizeof(*stats64));
-#else
- size_t i, n = sizeof(*stats64) / sizeof(u64);
- const unsigned long *src = (const unsigned long *)netdev_stats;
- u64 *dst = (u64 *)stats64;
-
- BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) !=
- sizeof(*stats64) / sizeof(u64));
- for (i = 0; i < n; i++)
- dst[i] = src[i];
-#endif
-}
-#endif
-
-#if !defined(HAVE_VOID_NDO_GET_STATS64) && !defined(HAVE_RHEL7_MAX_MTU)
-struct rtnl_link_stats64 *rpl_ip_tunnel_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-#else
-void rpl_ip_tunnel_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-#endif
-{
- int i;
-
- netdev_stats_to_stats64(tot, &dev->stats);
-
- for_each_possible_cpu(i) {
- const struct pcpu_sw_netstats *tstats =
- per_cpu_ptr((struct pcpu_sw_netstats __percpu *)dev->tstats, i);
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- unsigned int start;
-
- do {
- start = u64_stats_fetch_begin_irq(&tstats->syncp);
- rx_packets = tstats->rx_packets;
- tx_packets = tstats->tx_packets;
- rx_bytes = tstats->rx_bytes;
- tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
-
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
- }
-
-#if !defined(HAVE_VOID_NDO_GET_STATS64) && !defined(HAVE_RHEL7_MAX_MTU)
- return tot;
-#endif
-}
-
-void rpl_ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
- struct net_device *dev)
-{
- int pkt_len, err;
-
- pkt_len = skb->len - skb_inner_network_offset(skb);
-#ifdef HAVE_IP6_LOCAL_OUT_SK
- err = ip6_local_out_sk(sk, skb);
-#else
- err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
-#endif
- if (net_xmit_eval(err))
- pkt_len = -1;
-
- iptunnel_xmit_stats(dev, pkt_len);
-}
-EXPORT_SYMBOL_GPL(rpl_ip6tunnel_xmit);
diff --git a/datapath/linux/compat/lisp.c b/datapath/linux/compat/lisp.c
deleted file mode 100644
index 49c60f4ed..000000000
--- a/datapath/linux/compat/lisp.c
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * Copyright (c) 2015 Nicira, Inc.
- * Copyright (c) 2013 Cisco Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/version.h>
-
-#include <linux/etherdevice.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/net.h>
-#include <linux/module.h>
-#include <linux/rculist.h>
-#include <linux/udp.h>
-
-#include <net/icmp.h>
-#include <net/ip.h>
-#include <net/lisp.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/route.h>
-#include <net/udp.h>
-#include <net/udp_tunnel.h>
-#include <net/xfrm.h>
-
-#include "datapath.h"
-#include "gso.h"
-#include "vport.h"
-#include "vport-netdev.h"
-
-#define LISP_UDP_PORT 4341
-#define LISP_NETDEV_VER "0.1"
-static int lisp_net_id;
-
-/* Pseudo network device */
-struct lisp_dev {
- struct net *net; /* netns for packet i/o */
- struct net_device *dev; /* netdev for lisp tunnel */
- struct socket __rcu *sock;
- __be16 dst_port;
- struct list_head next;
-};
-
-/* per-network namespace private data for this module */
-struct lisp_net {
- struct list_head lisp_list;
-};
-
-/*
- * LISP encapsulation header:
- *
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |N|L|E|V|I|flags| Nonce/Map-Version |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Instance ID/Locator Status Bits |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- */
-
-/**
- * struct lisphdr - LISP header
- * @nonce_present: Flag indicating the presence of a 24 bit nonce value.
- * @locator_status_bits_present: Flag indicating the presence of Locator Status
- * Bits (LSB).
- * @solicit_echo_nonce: Flag indicating the use of the echo noncing mechanism.
- * @map_version_present: Flag indicating the use of mapping versioning.
- * @instance_id_present: Flag indicating the presence of a 24 bit Instance ID.
- * @reserved_flags: 3 bits reserved for future flags.
- * @nonce: 24 bit nonce value.
- * @map_version: 24 bit mapping version.
- * @locator_status_bits: Locator Status Bits: 32 bits when instance_id_present
- * is not set, 8 bits when it is.
- * @instance_id: 24 bit Instance ID
- */
-struct lisphdr {
-#ifdef __LITTLE_ENDIAN_BITFIELD
- __u8 reserved_flags:3;
- __u8 instance_id_present:1;
- __u8 map_version_present:1;
- __u8 solicit_echo_nonce:1;
- __u8 locator_status_bits_present:1;
- __u8 nonce_present:1;
-#else
- __u8 nonce_present:1;
- __u8 locator_status_bits_present:1;
- __u8 solicit_echo_nonce:1;
- __u8 map_version_present:1;
- __u8 instance_id_present:1;
- __u8 reserved_flags:3;
-#endif
- union {
- __u8 nonce[3];
- __u8 map_version[3];
- } u1;
- union {
- __be32 locator_status_bits;
- struct {
- __u8 instance_id[3];
- __u8 locator_status_bits;
- } word2;
- } u2;
-};
-
-#define LISP_HLEN (sizeof(struct udphdr) + sizeof(struct lisphdr))
-#define LISP_MAX_MTU (IP_MAX_MTU - LISP_HLEN - sizeof(struct iphdr))
-
-static inline struct lisphdr *lisp_hdr(const struct sk_buff *skb)
-{
- return (struct lisphdr *)(udp_hdr(skb) + 1);
-}
-
-/* Convert 64 bit tunnel ID to 24 bit Instance ID. */
-static void tunnel_id_to_instance_id(__be64 tun_id, __u8 *iid)
-{
-
-#ifdef __BIG_ENDIAN
- iid[0] = (__force __u8)(tun_id >> 16);
- iid[1] = (__force __u8)(tun_id >> 8);
- iid[2] = (__force __u8)tun_id;
-#else
- iid[0] = (__force __u8)((__force u64)tun_id >> 40);
- iid[1] = (__force __u8)((__force u64)tun_id >> 48);
- iid[2] = (__force __u8)((__force u64)tun_id >> 56);
-#endif
-}
-
-/* Convert 24 bit Instance ID to 64 bit tunnel ID. */
-static __be64 instance_id_to_tunnel_id(__u8 *iid)
-{
-#ifdef __BIG_ENDIAN
- return (iid[0] << 16) | (iid[1] << 8) | iid[2];
-#else
- return (__force __be64)(((__force u64)iid[0] << 40) |
- ((__force u64)iid[1] << 48) |
- ((__force u64)iid[2] << 56));
-#endif
-}
-
-/* Compute source UDP port for outgoing packet.
- * Currently we use the flow hash.
- */
-static u16 get_src_port(struct net *net, struct sk_buff *skb)
-{
- u32 hash = skb_get_hash(skb);
- unsigned int range;
- int high;
- int low;
-
- if (!hash) {
- if (skb->protocol == htons(ETH_P_IP)) {
- struct iphdr *iph;
- int size = (sizeof(iph->saddr) * 2) / sizeof(u32);
-
- iph = (struct iphdr *) skb_network_header(skb);
- hash = jhash2((const u32 *)&iph->saddr, size, 0);
- } else if (skb->protocol == htons(ETH_P_IPV6)) {
- struct ipv6hdr *ipv6hdr;
-
- ipv6hdr = (struct ipv6hdr *) skb_network_header(skb);
- hash = jhash2((const u32 *)&ipv6hdr->saddr,
- (sizeof(struct in6_addr) * 2) / sizeof(u32), 0);
- } else {
- pr_warn_once("LISP inner protocol is not IP when "
- "calculating hash.\n");
- }
- }
-
- inet_get_local_port_range(net, &low, &high);
- range = (high - low) + 1;
- return (((u64) hash * range) >> 32) + low;
-}
-
-static void lisp_build_header(struct sk_buff *skb,
- const struct ip_tunnel_key *tun_key)
-{
- struct lisphdr *lisph;
-
- lisph = (struct lisphdr *)__skb_push(skb, sizeof(struct lisphdr));
- lisph->nonce_present = 0; /* We don't support echo nonce algorithm */
- lisph->locator_status_bits_present = 1; /* Set LSB */
- lisph->solicit_echo_nonce = 0; /* No echo noncing */
- lisph->map_version_present = 0; /* No mapping versioning, nonce instead */
- lisph->instance_id_present = 1; /* Store the tun_id as Instance ID */
- lisph->reserved_flags = 0; /* Reserved flags, set to 0 */
-
- lisph->u1.nonce[0] = 0;
- lisph->u1.nonce[1] = 0;
- lisph->u1.nonce[2] = 0;
-
- tunnel_id_to_instance_id(tun_key->tun_id, &lisph->u2.word2.instance_id[0]);
- lisph->u2.word2.locator_status_bits = 1;
-}
-
-/* Called with rcu_read_lock and BH disabled. */
-static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
-{
- struct lisp_dev *lisp_dev;
- struct net_device *dev;
- struct lisphdr *lisph;
- struct iphdr *inner_iph;
- struct metadata_dst *tun_dst;
-#ifndef USE_UPSTREAM_TUNNEL
- struct metadata_dst temp;
-#endif
- __be64 key;
- struct ethhdr *ethh;
- __be16 protocol;
-
- dev = rcu_dereference_sk_user_data(sk);
- if (unlikely(!dev))
- goto error;
-
- lisp_dev = netdev_priv(dev);
- if (iptunnel_pull_header(skb, LISP_HLEN, 0,
- !net_eq(lisp_dev->net, dev_net(lisp_dev->dev))))
- goto error;
-
- lisph = lisp_hdr(skb);
-
- if (lisph->instance_id_present != 1)
- key = 0;
- else
- key = instance_id_to_tunnel_id(&lisph->u2.word2.instance_id[0]);
-
- /* Save outer tunnel values */
-#ifndef USE_UPSTREAM_TUNNEL
- tun_dst = &temp;
- ovs_udp_tun_rx_dst(tun_dst, skb, AF_INET, TUNNEL_KEY, key, 0);
-#else
- tun_dst = udp_tun_rx_dst(skb, AF_INET, TUNNEL_KEY, key, 0);
-#endif
- /* Drop non-IP inner packets */
- inner_iph = (struct iphdr *)(lisph + 1);
- switch (inner_iph->version) {
- case 4:
- protocol = htons(ETH_P_IP);
- break;
- case 6:
- protocol = htons(ETH_P_IPV6);
- break;
- default:
- goto error;
- }
- skb->protocol = protocol;
-
- /* Add Ethernet header */
- ethh = (struct ethhdr *)skb_push(skb, ETH_HLEN);
- memset(ethh, 0, ETH_HLEN);
- ethh->h_dest[0] = 0x02;
- ethh->h_source[0] = 0x02;
- ethh->h_proto = protocol;
-
- ovs_ip_tunnel_rcv(dev, skb, tun_dst);
- goto out;
-
-error:
- kfree_skb(skb);
-out:
- return 0;
-}
-
-static struct rtable *lisp_get_rt(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi4 *fl,
- const struct ip_tunnel_key *key)
-{
- struct net *net = dev_net(dev);
-
- /* Route lookup */
- memset(fl, 0, sizeof(*fl));
- fl->daddr = key->u.ipv4.dst;
- fl->saddr = key->u.ipv4.src;
- fl->flowi4_tos = RT_TOS(key->tos);
- fl->flowi4_mark = skb->mark;
- fl->flowi4_proto = IPPROTO_UDP;
-
- return ip_route_output_key(net, fl);
-}
-
-/* this is to handle the return type change in handle-offload
- * functions.
- */
-#if !defined(HAVE_UDP_TUNNEL_HANDLE_OFFLOAD_RET_SKB) || !defined(USE_UPSTREAM_TUNNEL)
-static struct sk_buff *
-__udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum)
-{
- int err;
-
- err = udp_tunnel_handle_offloads(skb, udp_csum);
- if (err) {
- kfree_skb(skb);
- return NULL;
- }
- return skb;
-}
-#else
-#define __udp_tunnel_handle_offloads udp_tunnel_handle_offloads
-#endif
-
-netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- struct lisp_dev *lisp_dev = netdev_priv(dev);
- struct net *net = lisp_dev->net;
- int network_offset = skb_network_offset(skb);
- struct ip_tunnel_info *info;
- struct ip_tunnel_key *tun_key;
- __be16 src_port, dst_port;
- struct rtable *rt;
- int min_headroom;
- struct socket *sock;
- struct flowi4 fl;
- __be16 df;
- int err;
-
- info = skb_tunnel_info(skb);
- if (unlikely(!info)) {
- err = -EINVAL;
- goto error;
- }
-
- sock = rcu_dereference(lisp_dev->sock);
- if (!sock) {
- err = -EIO;
- goto error;
- }
-
- if (skb->protocol != htons(ETH_P_IP) &&
- skb->protocol != htons(ETH_P_IPV6)) {
- err = 0;
- goto error;
- }
-
- tun_key = &info->key;
-
- rt = lisp_get_rt(skb, dev, &fl, tun_key);
- if (IS_ERR(rt)) {
- err = PTR_ERR(rt);
- goto error;
- }
-
- min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
- + sizeof(struct iphdr) + LISP_HLEN;
-
- if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
- int head_delta = SKB_DATA_ALIGN(min_headroom -
- skb_headroom(skb) +
- 16);
-
- err = pskb_expand_head(skb, max_t(int, head_delta, 0),
- 0, GFP_ATOMIC);
- if (unlikely(err))
- goto err_free_rt;
- }
-
- /* Reset l2 headers. */
- skb_pull(skb, network_offset);
- skb_reset_mac_header(skb);
- skb->vlan_tci = 0;
-
- if (skb_is_gso(skb) && skb_is_encapsulated(skb))
- goto err_free_rt;
-
- skb = __udp_tunnel_handle_offloads(skb, false);
- if (!skb)
- return NETDEV_TX_OK;
-
- src_port = htons(get_src_port(net, skb));
- dst_port = lisp_dev->dst_port;
-
- lisp_build_header(skb, tun_key);
-
- skb->ignore_df = 1;
-
- ovs_skb_set_inner_protocol(skb, skb->protocol);
-
- df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
- udp_tunnel_xmit_skb(rt, sock->sk, skb,
- fl.saddr, tun_key->u.ipv4.dst,
- tun_key->tos, tun_key->ttl,
- df, src_port, dst_port, false, true);
-
- return NETDEV_TX_OK;
-
-err_free_rt:
- ip_rt_put(rt);
-error:
- kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-EXPORT_SYMBOL(rpl_lisp_xmit);
-
-/* Setup stats when device is created */
-static int lisp_init(struct net_device *dev)
-{
- dev->tstats = (typeof(dev->tstats)) netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- return 0;
-}
-
-static void lisp_uninit(struct net_device *dev)
-{
- free_percpu(dev->tstats);
-}
-
-static struct socket *create_sock(struct net *net, bool ipv6,
- __be16 port)
-{
- struct socket *sock;
- struct udp_port_cfg udp_conf;
- int err;
-
- memset(&udp_conf, 0, sizeof(udp_conf));
-
- if (ipv6) {
- udp_conf.family = AF_INET6;
- } else {
- udp_conf.family = AF_INET;
- udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
- }
-
- 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;
-}
-
-static int lisp_open(struct net_device *dev)
-{
- struct lisp_dev *lisp = netdev_priv(dev);
- struct udp_tunnel_sock_cfg tunnel_cfg;
- struct net *net = lisp->net;
- struct socket *sock;
-
- sock = create_sock(net, false, lisp->dst_port);
- if (IS_ERR(sock))
- return PTR_ERR(sock);
-
- rcu_assign_pointer(lisp->sock, sock);
- /* Mark socket as an encapsulation socket */
- memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
- tunnel_cfg.sk_user_data = dev;
- tunnel_cfg.encap_type = 1;
- tunnel_cfg.encap_rcv = lisp_rcv;
- tunnel_cfg.encap_destroy = NULL;
- setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
- return 0;
-}
-
-static int lisp_stop(struct net_device *dev)
-{
- struct lisp_dev *lisp = netdev_priv(dev);
- struct socket *socket;
-
- socket = rtnl_dereference(lisp->sock);
- if (!socket)
- return 0;
-
- rcu_assign_pointer(lisp->sock, NULL);
-
- synchronize_net();
- udp_tunnel_sock_release(socket);
- return 0;
-}
-
-static netdev_tx_t lisp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-#ifdef USE_UPSTREAM_TUNNEL
- return rpl_lisp_xmit(skb);
-#else
- /* 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;
-#endif
-}
-
-static int lisp_change_mtu(struct net_device *dev, int new_mtu)
-{
- if (new_mtu < 68 || new_mtu > LISP_MAX_MTU)
- return -EINVAL;
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-static int egress_ipv4_tun_info(struct net_device *dev, struct sk_buff *skb,
- struct ip_tunnel_info *info,
- __be16 sport, __be16 dport)
-{
- struct rtable *rt;
- struct flowi4 fl4;
-
- rt = lisp_get_rt(skb, dev, &fl4, &info->key);
- if (IS_ERR(rt))
- return PTR_ERR(rt);
- ip_rt_put(rt);
-
- info->key.u.ipv4.src = fl4.saddr;
- info->key.tp_src = sport;
- info->key.tp_dst = dport;
- return 0;
-}
-
-int ovs_lisp_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
-{
- struct lisp_dev *lisp = netdev_priv(dev);
- struct net *net = lisp->net;
- struct ip_tunnel_info *info = skb_tunnel_info(skb);
- __be16 sport, dport;
-
- sport = htons(get_src_port(net, skb));
- dport = lisp->dst_port;
-
- if (ip_tunnel_info_af(info) == AF_INET)
- return egress_ipv4_tun_info(dev, skb, info, sport, dport);
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(ovs_lisp_fill_metadata_dst);
-
-static const struct net_device_ops lisp_netdev_ops = {
- .ndo_init = lisp_init,
- .ndo_uninit = lisp_uninit,
- .ndo_get_stats64 = ip_tunnel_get_stats64,
- .ndo_open = lisp_open,
- .ndo_stop = lisp_stop,
- .ndo_start_xmit = lisp_dev_xmit,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = lisp_change_mtu,
-#else
- .ndo_change_mtu = lisp_change_mtu,
-#endif
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
-#ifdef USE_UPSTREAM_TUNNEL
-#ifdef HAVE_NDO_FILL_METADATA_DST
- .ndo_fill_metadata_dst = lisp_fill_metadata_dst,
-#endif
-#endif
-};
-
-static void lisp_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- strlcpy(drvinfo->version, LISP_NETDEV_VER, sizeof(drvinfo->version));
- strlcpy(drvinfo->driver, "lisp", sizeof(drvinfo->driver));
-}
-
-static const struct ethtool_ops lisp_ethtool_ops = {
- .get_drvinfo = lisp_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-
-/* Info for udev, that this is a virtual tunnel endpoint */
-static struct device_type lisp_type = {
- .name = "lisp",
-};
-
-/* Initialize the device structure. */
-static void lisp_setup(struct net_device *dev)
-{
- ether_setup(dev);
-
- dev->netdev_ops = &lisp_netdev_ops;
- dev->ethtool_ops = &lisp_ethtool_ops;
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
-#endif
-
- SET_NETDEV_DEVTYPE(dev, &lisp_type);
-
- dev->features |= NETIF_F_LLTX | NETIF_F_NETNS_LOCAL;
- 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;
-#ifdef USE_UPSTREAM_TUNNEL
- netif_keep_dst(dev);
-#endif
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
- eth_hw_addr_random(dev);
-}
-
-static const struct nla_policy lisp_policy[IFLA_LISP_MAX + 1] = {
- [IFLA_LISP_PORT] = { .type = NLA_U16 },
-};
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int lisp_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack __always_unused *extack)
-#else
-static int lisp_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- if (tb[IFLA_ADDRESS]) {
- if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
- return -EINVAL;
-
- if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
- return -EADDRNOTAVAIL;
- }
-
- return 0;
-}
-
-static struct lisp_dev *find_dev(struct net *net, __be16 dst_port)
-{
- struct lisp_net *ln = net_generic(net, lisp_net_id);
- struct lisp_dev *dev;
-
- list_for_each_entry(dev, &ln->lisp_list, next) {
- if (dev->dst_port == dst_port)
- return dev;
- }
- return NULL;
-}
-
-static int lisp_configure(struct net *net, struct net_device *dev,
- __be16 dst_port)
-{
- struct lisp_net *ln = net_generic(net, lisp_net_id);
- struct lisp_dev *lisp = netdev_priv(dev);
- int err;
-
- lisp->net = net;
- lisp->dev = dev;
-
- lisp->dst_port = dst_port;
-
- if (find_dev(net, dst_port))
- return -EBUSY;
-
- err = lisp_change_mtu(dev, LISP_MAX_MTU);
- if (err)
- return err;
-
- err = register_netdevice(dev);
- if (err)
- return err;
-
- list_add(&lisp->next, &ln->lisp_list);
- return 0;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int lisp_newlink(struct net *net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack __always_unused *extack)
-#else
-static int lisp_newlink(struct net *net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- __be16 dst_port = htons(LISP_UDP_PORT);
-
- if (data[IFLA_LISP_PORT])
- dst_port = nla_get_be16(data[IFLA_LISP_PORT]);
-
- return lisp_configure(net, dev, dst_port);
-}
-
-static void lisp_dellink(struct net_device *dev, struct list_head *head)
-{
- struct lisp_dev *lisp = netdev_priv(dev);
-
- list_del(&lisp->next);
- unregister_netdevice_queue(dev, head);
-}
-
-static size_t lisp_get_size(const struct net_device *dev)
-{
- return nla_total_size(sizeof(__be32)); /* IFLA_LISP_PORT */
-}
-
-static int lisp_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- struct lisp_dev *lisp = netdev_priv(dev);
-
- if (nla_put_be16(skb, IFLA_LISP_PORT, lisp->dst_port))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-static struct rtnl_link_ops lisp_link_ops __read_mostly = {
- .kind = "lisp",
- .maxtype = IFLA_LISP_MAX,
- .policy = lisp_policy,
- .priv_size = sizeof(struct lisp_dev),
- .setup = lisp_setup,
- .validate = lisp_validate,
- .newlink = lisp_newlink,
- .dellink = lisp_dellink,
- .get_size = lisp_get_size,
- .fill_info = lisp_fill_info,
-};
-
-struct net_device *rpl_lisp_dev_create_fb(struct net *net, const char *name,
- u8 name_assign_type, u16 dst_port)
-{
- struct nlattr *tb[IFLA_MAX + 1];
- struct net_device *dev;
- int err;
-
- memset(tb, 0, sizeof(tb));
- dev = rtnl_create_link(net, (char *) name, name_assign_type,
- &lisp_link_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- err = lisp_configure(net, dev, htons(dst_port));
- if (err) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
- return dev;
-}
-EXPORT_SYMBOL_GPL(rpl_lisp_dev_create_fb);
-
-static int lisp_init_net(struct net *net)
-{
- struct lisp_net *ln = net_generic(net, lisp_net_id);
-
- INIT_LIST_HEAD(&ln->lisp_list);
- return 0;
-}
-
-static void lisp_exit_net(struct net *net)
-{
- struct lisp_net *ln = net_generic(net, lisp_net_id);
- struct lisp_dev *lisp, *next;
- struct net_device *dev, *aux;
- LIST_HEAD(list);
-
- rtnl_lock();
-
- /* gather any lisp devices that were moved into this ns */
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == &lisp_link_ops)
- unregister_netdevice_queue(dev, &list);
-
- list_for_each_entry_safe(lisp, next, &ln->lisp_list, next) {
- /* If lisp->dev is in the same netns, it was already added
- * to the lisp by the previous loop.
- */
- if (!net_eq(dev_net(lisp->dev), net))
- unregister_netdevice_queue(lisp->dev, &list);
- }
-
- /* unregister the devices gathered above */
- unregister_netdevice_many(&list);
- rtnl_unlock();
-}
-
-static struct pernet_operations lisp_net_ops = {
- .init = lisp_init_net,
- .exit = lisp_exit_net,
- .id = &lisp_net_id,
- .size = sizeof(struct lisp_net),
-};
-
-int rpl_lisp_init_module(void)
-{
- int rc;
-
- rc = register_pernet_subsys(&lisp_net_ops);
- if (rc)
- goto out1;
-
- rc = rtnl_link_register(&lisp_link_ops);
- if (rc)
- goto out2;
-
- pr_info("LISP tunneling driver\n");
- return 0;
-out2:
- unregister_pernet_subsys(&lisp_net_ops);
-out1:
- pr_err("Error while initializing LISP %d\n", rc);
- return rc;
-}
-
-void rpl_lisp_cleanup_module(void)
-{
- rtnl_link_unregister(&lisp_link_ops);
- unregister_pernet_subsys(&lisp_net_ops);
-}
diff --git a/datapath/linux/compat/netdevice.c b/datapath/linux/compat/netdevice.c
deleted file mode 100644
index c0ffbbd31..000000000
--- a/datapath/linux/compat/netdevice.c
+++ /dev/null
@@ -1,167 +0,0 @@
-#include <linux/netdevice.h>
-#include <linux/if_vlan.h>
-#include <net/mpls.h>
-
-#include "gso.h"
-
-#ifdef OVS_USE_COMPAT_GSO_SEGMENTATION
-struct sk_buff *rpl__skb_gso_segment(struct sk_buff *skb,
- netdev_features_t features,
- bool tx_path)
-{
- int vlan_depth = ETH_HLEN;
- __be16 type = skb->protocol;
- __be16 skb_proto;
- struct sk_buff *skb_gso;
-
- while (type == htons(ETH_P_8021Q)) {
- struct vlan_hdr *vh;
-
- if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
- return ERR_PTR(-EINVAL);
-
- vh = (struct vlan_hdr *)(skb->data + vlan_depth);
- type = vh->h_vlan_encapsulated_proto;
- vlan_depth += VLAN_HLEN;
- }
-
- if (eth_p_mpls(type))
- type = ovs_skb_get_inner_protocol(skb);
-
- /* this hack needed to get regular skb_gso_segment() */
- skb_proto = skb->protocol;
- skb->protocol = type;
-
-#ifdef HAVE___SKB_GSO_SEGMENT
-#undef __skb_gso_segment
- skb_gso = __skb_gso_segment(skb, features, tx_path);
-#else
-#undef skb_gso_segment
- skb_gso = skb_gso_segment(skb, features);
-#endif
-
- skb->protocol = skb_proto;
- return skb_gso;
-}
-EXPORT_SYMBOL_GPL(rpl__skb_gso_segment);
-
-#endif /* OVS_USE_COMPAT_GSO_SEGMENTATION */
-
-#ifdef HAVE_UDP_OFFLOAD
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0)
-struct sk_buff **rpl_eth_gro_receive(struct sk_buff **head,
- struct sk_buff *skb)
-{
- struct sk_buff *p, **pp = NULL;
- struct ethhdr *eh, *eh2;
- unsigned int hlen, off_eth;
- const struct packet_offload *ptype;
- __be16 type;
- int flush = 1;
-
- off_eth = skb_gro_offset(skb);
- hlen = off_eth + sizeof(*eh);
- eh = skb_gro_header_fast(skb, off_eth);
- if (skb_gro_header_hard(skb, hlen)) {
- eh = skb_gro_header_slow(skb, hlen, off_eth);
- if (unlikely(!eh))
- goto out;
- }
-
- flush = 0;
-
- for (p = *head; p; p = p->next) {
- if (!NAPI_GRO_CB(p)->same_flow)
- continue;
-
- eh2 = (struct ethhdr *)(p->data + off_eth);
- if (compare_ether_header(eh, eh2)) {
- NAPI_GRO_CB(p)->same_flow = 0;
- continue;
- }
- }
-
- type = eh->h_proto;
-
- rcu_read_lock();
- ptype = gro_find_receive_by_type(type);
- if (ptype == NULL) {
- flush = 1;
- goto out_unlock;
- }
-
- skb_gro_pull(skb, sizeof(*eh));
- skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
- pp = ptype->callbacks.gro_receive(head, skb);
-
-out_unlock:
- rcu_read_unlock();
-out:
- NAPI_GRO_CB(skb)->flush |= flush;
-
- return pp;
-}
-
-int rpl_eth_gro_complete(struct sk_buff *skb, int nhoff)
-{
- struct ethhdr *eh = (struct ethhdr *)(skb->data + nhoff);
- __be16 type = eh->h_proto;
- struct packet_offload *ptype;
- int err = -ENOSYS;
-
- if (skb->encapsulation)
- skb_set_inner_mac_header(skb, nhoff);
-
- rcu_read_lock();
- ptype = gro_find_complete_by_type(type);
- if (ptype != NULL)
- err = ptype->callbacks.gro_complete(skb, nhoff +
- sizeof(struct ethhdr));
-
- rcu_read_unlock();
- return err;
-}
-
-#endif
-#endif /* HAVE_UDP_OFFLOAD */
-
-#ifndef HAVE_RTNL_LINK_STATS64
-#undef dev_get_stats
-struct rtnl_link_stats64 *rpl_dev_get_stats(struct net_device *dev,
- struct rtnl_link_stats64 *storage)
-{
- const struct net_device_stats *stats = dev_get_stats(dev);
-
-#define copy(s) storage->s = stats->s
-
- copy(rx_packets);
- copy(tx_packets);
- copy(rx_bytes);
- copy(tx_bytes);
- copy(rx_errors);
- copy(tx_errors);
- copy(rx_dropped);
- copy(tx_dropped);
- copy(multicast);
- copy(collisions);
-
- copy(rx_length_errors);
- copy(rx_over_errors);
- copy(rx_crc_errors);
- copy(rx_frame_errors);
- copy(rx_fifo_errors);
- copy(rx_missed_errors);
-
- copy(tx_aborted_errors);
- copy(tx_carrier_errors);
- copy(tx_fifo_errors);
- copy(tx_heartbeat_errors);
- copy(tx_window_errors);
-
- copy(rx_compressed);
- copy(tx_compressed);
-
-#undef copy
- return storage;
-}
-#endif
diff --git a/datapath/linux/compat/nf_conncount.c b/datapath/linux/compat/nf_conncount.c
deleted file mode 100644
index 97bdfb933..000000000
--- a/datapath/linux/compat/nf_conncount.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Backported from upstream commit 5c789e131cbb ("netfilter:
- * nf_conncount: Add list lock and gc worker, and RCU for init tree search")
- *
- * count the number of connections matching an arbitrary key.
- *
- * (C) 2017 Red Hat GmbH
- * Author: Florian Westphal <fw@strlen.de>
- *
- * split from xt_connlimit.c:
- * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
- * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
- * only ignore TIME_WAIT or gone connections
- * (C) CC Computer Consultants GmbH, 2007
- */
-#ifndef HAVE_UPSTREAM_NF_CONNCOUNT
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/jhash.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/rbtree.h>
-#include <linux/module.h>
-#include <linux/random.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/netfilter/nf_conntrack_tcp.h>
-#include <linux/netfilter/x_tables.h>
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_count.h>
-#include <net/netfilter/nf_conntrack_core.h>
-#include <net/netfilter/nf_conntrack_tuple.h>
-#include <net/netfilter/nf_conntrack_zones.h>
-
-#define CONNCOUNT_SLOTS 256U
-
-#define CONNCOUNT_GC_MAX_NODES 8
-#define MAX_KEYLEN 5
-
-/* we will save the tuples of all connections we care about */
-struct nf_conncount_tuple {
- struct list_head node;
- struct nf_conntrack_tuple tuple;
- struct nf_conntrack_zone zone;
- int cpu;
- u32 jiffies32;
-};
-
-struct nf_conncount_rb {
- struct rb_node node;
- struct nf_conncount_list list;
- u32 key[MAX_KEYLEN];
- struct rcu_head rcu_head;
-};
-
-static spinlock_t nf_conncount_locks[CONNCOUNT_SLOTS] __cacheline_aligned_in_smp;
-
-struct nf_conncount_data {
- unsigned int keylen;
- struct rb_root root[CONNCOUNT_SLOTS];
- struct net *net;
- struct work_struct gc_work;
- unsigned long pending_trees[BITS_TO_LONGS(CONNCOUNT_SLOTS)];
- unsigned int gc_tree;
-};
-
-static u_int32_t conncount_rnd __read_mostly;
-static struct kmem_cache *conncount_rb_cachep __read_mostly;
-static struct kmem_cache *conncount_conn_cachep __read_mostly;
-
-static inline bool already_closed(const struct nf_conn *conn)
-{
- if (nf_ct_protonum(conn) == IPPROTO_TCP)
- return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT ||
- conn->proto.tcp.state == TCP_CONNTRACK_CLOSE;
- else
- return false;
-}
-
-static int key_diff(const u32 *a, const u32 *b, unsigned int klen)
-{
- return memcmp(a, b, klen * sizeof(u32));
-}
-
-static void conn_free(struct nf_conncount_list *list,
- struct nf_conncount_tuple *conn)
-{
- lockdep_assert_held(&list->list_lock);
-
- list->count--;
- list_del(&conn->node);
-
- kmem_cache_free(conncount_conn_cachep, conn);
-}
-
-static const struct nf_conntrack_tuple_hash *
-find_or_evict(struct net *net, struct nf_conncount_list *list,
- struct nf_conncount_tuple *conn)
-{
- const struct nf_conntrack_tuple_hash *found;
- unsigned long a, b;
- int cpu = raw_smp_processor_id();
- u32 age;
-
- found = nf_conntrack_find_get(net, &conn->zone, &conn->tuple);
- if (found)
- return found;
- b = conn->jiffies32;
- a = (u32)jiffies;
-
- /* conn might have been added just before by another cpu and
- * might still be unconfirmed. In this case, nf_conntrack_find()
- * returns no result. Thus only evict if this cpu added the
- * stale entry or if the entry is older than two jiffies.
- */
- age = a - b;
- if (conn->cpu == cpu || age >= 2) {
- conn_free(list, conn);
- return ERR_PTR(-ENOENT);
- }
-
- return ERR_PTR(-EAGAIN);
-}
-
-static int __nf_conncount_add(struct net *net,
- struct nf_conncount_list *list,
- const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_zone *zone)
-{
- const struct nf_conntrack_tuple_hash *found;
- struct nf_conncount_tuple *conn, *conn_n;
- struct nf_conn *found_ct;
- unsigned int collect = 0;
-
- /* check the saved connections */
- list_for_each_entry_safe(conn, conn_n, &list->head, node) {
- if (collect > CONNCOUNT_GC_MAX_NODES)
- break;
-
- found = find_or_evict(net, list, conn);
- if (IS_ERR(found)) {
- /* Not found, but might be about to be confirmed */
- if (PTR_ERR(found) == -EAGAIN) {
- if (nf_ct_tuple_equal(&conn->tuple, tuple) &&
- nf_ct_zone_id(&conn->zone, conn->zone.dir) ==
- nf_ct_zone_id(zone, zone->dir))
- return 0; /* already exists */
- } else {
- collect++;
- }
- continue;
- }
-
- found_ct = nf_ct_tuplehash_to_ctrack(found);
-
- if (nf_ct_tuple_equal(&conn->tuple, tuple) &&
- nf_ct_zone_equal(found_ct, zone, zone->dir)) {
- /*
- * We should not see tuples twice unless someone hooks
- * this into a table without "-p tcp --syn".
- *
- * Attempt to avoid a re-add in this case.
- */
- nf_ct_put(found_ct);
- return 0;
- } else if (already_closed(found_ct)) {
- /*
- * we do not care about connections which are
- * closed already -> ditch it
- */
- nf_ct_put(found_ct);
- conn_free(list, conn);
- collect++;
- continue;
- }
-
- nf_ct_put(found_ct);
- }
-
- if (WARN_ON_ONCE(list->count > INT_MAX))
- return -EOVERFLOW;
-
- conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC);
- if (conn == NULL)
- return -ENOMEM;
-
- conn->tuple = *tuple;
- conn->zone = *zone;
- conn->cpu = raw_smp_processor_id();
- conn->jiffies32 = (u32)jiffies;
- list_add_tail(&conn->node, &list->head);
- list->count++;
- return 0;
-}
-
-int nf_conncount_add(struct net *net,
- struct nf_conncount_list *list,
- const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_zone *zone)
-{
- int ret;
-
- /* check the saved connections */
- spin_lock_bh(&list->list_lock);
- ret = __nf_conncount_add(net, list, tuple, zone);
- spin_unlock_bh(&list->list_lock);
-
- return ret;
-}
-
-static void nf_conncount_list_init(struct nf_conncount_list *list)
-{
- spin_lock_init(&list->list_lock);
- INIT_LIST_HEAD(&list->head);
- list->count = 0;
-}
-
-/* Return true if the list is empty. Must be called with BH disabled. */
-static bool nf_conncount_gc_list(struct net *net,
- struct nf_conncount_list *list)
-{
- const struct nf_conntrack_tuple_hash *found;
- struct nf_conncount_tuple *conn, *conn_n;
- struct nf_conn *found_ct;
- unsigned int collected = 0;
- bool ret = false;
-
- /* don't bother if other cpu is already doing GC */
- if (!spin_trylock(&list->list_lock))
- return false;
-
- list_for_each_entry_safe(conn, conn_n, &list->head, node) {
- found = find_or_evict(net, list, conn);
- if (IS_ERR(found)) {
- if (PTR_ERR(found) == -ENOENT)
- collected++;
- continue;
- }
-
- found_ct = nf_ct_tuplehash_to_ctrack(found);
- if (already_closed(found_ct)) {
- /*
- * we do not care about connections which are
- * closed already -> ditch it
- */
- nf_ct_put(found_ct);
- conn_free(list, conn);
- collected++;
- continue;
- }
-
- nf_ct_put(found_ct);
- if (collected > CONNCOUNT_GC_MAX_NODES)
- break;
- }
-
- if (!list->count)
- ret = true;
- spin_unlock(&list->list_lock);
-
- return ret;
-}
-
-static void __tree_nodes_free(struct rcu_head *h)
-{
- struct nf_conncount_rb *rbconn;
-
- rbconn = container_of(h, struct nf_conncount_rb, rcu_head);
- kmem_cache_free(conncount_rb_cachep, rbconn);
-}
-
-/* caller must hold tree nf_conncount_locks[] lock */
-static void tree_nodes_free(struct rb_root *root,
- struct nf_conncount_rb *gc_nodes[],
- unsigned int gc_count)
-{
- struct nf_conncount_rb *rbconn;
-
- while (gc_count) {
- rbconn = gc_nodes[--gc_count];
- spin_lock(&rbconn->list.list_lock);
- if (!rbconn->list.count) {
- rb_erase(&rbconn->node, root);
- call_rcu(&rbconn->rcu_head, __tree_nodes_free);
- }
- spin_unlock(&rbconn->list.list_lock);
- }
-}
-
-static void schedule_gc_worker(struct nf_conncount_data *data, int tree)
-{
- set_bit(tree, data->pending_trees);
- schedule_work(&data->gc_work);
-}
-
-static unsigned int
-insert_tree(struct net *net,
- struct nf_conncount_data *data,
- struct rb_root *root,
- unsigned int hash,
- const u32 *key,
- const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_zone *zone)
-{
- struct nf_conncount_rb *gc_nodes[CONNCOUNT_GC_MAX_NODES];
- struct rb_node **rbnode, *parent;
- struct nf_conncount_rb *rbconn;
- struct nf_conncount_tuple *conn;
- unsigned int count = 0, gc_count = 0;
- u8 keylen = data->keylen;
- bool do_gc = true;
-
- spin_lock_bh(&nf_conncount_locks[hash]);
-restart:
- parent = NULL;
- rbnode = &(root->rb_node);
- while (*rbnode) {
- int diff;
- rbconn = rb_entry(*rbnode, struct nf_conncount_rb, node);
-
- parent = *rbnode;
- diff = key_diff(key, rbconn->key, keylen);
- if (diff < 0) {
- rbnode = &((*rbnode)->rb_left);
- } else if (diff > 0) {
- rbnode = &((*rbnode)->rb_right);
- } else {
- int ret;
-
- ret = nf_conncount_add(net, &rbconn->list, tuple, zone);
- if (ret)
- count = 0; /* hotdrop */
- else
- count = rbconn->list.count;
- tree_nodes_free(root, gc_nodes, gc_count);
- goto out_unlock;
- }
-
- if (gc_count >= ARRAY_SIZE(gc_nodes))
- continue;
-
- if (do_gc && nf_conncount_gc_list(net, &rbconn->list))
- gc_nodes[gc_count++] = rbconn;
- }
-
- if (gc_count) {
- tree_nodes_free(root, gc_nodes, gc_count);
- schedule_gc_worker(data, hash);
- gc_count = 0;
- do_gc = false;
- goto restart;
- }
-
- /* expected case: match, insert new node */
- rbconn = kmem_cache_alloc(conncount_rb_cachep, GFP_ATOMIC);
- if (rbconn == NULL)
- goto out_unlock;
-
- conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC);
- if (conn == NULL) {
- kmem_cache_free(conncount_rb_cachep, rbconn);
- goto out_unlock;
- }
-
- conn->tuple = *tuple;
- conn->zone = *zone;
- memcpy(rbconn->key, key, sizeof(u32) * keylen);
-
- nf_conncount_list_init(&rbconn->list);
- list_add(&conn->node, &rbconn->list.head);
- count = 1;
- rbconn->list.count = count;
-
- rb_link_node_rcu(&rbconn->node, parent, rbnode);
- rb_insert_color(&rbconn->node, root);
-out_unlock:
- spin_unlock_bh(&nf_conncount_locks[hash]);
- return count;
-}
-
-static unsigned int
-count_tree(struct net *net,
- struct nf_conncount_data *data,
- const u32 *key,
- const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_zone *zone)
-{
- struct rb_root *root;
- struct rb_node *parent;
- struct nf_conncount_rb *rbconn;
- unsigned int hash;
- u8 keylen = data->keylen;
-
- hash = jhash2(key, data->keylen, conncount_rnd) % CONNCOUNT_SLOTS;
- root = &data->root[hash];
-
- parent = rcu_dereference_raw(root->rb_node);
- while (parent) {
- int diff;
-
- rbconn = rb_entry(parent, struct nf_conncount_rb, node);
-
- diff = key_diff(key, rbconn->key, keylen);
- if (diff < 0) {
- parent = rcu_dereference_raw(parent->rb_left);
- } else if (diff > 0) {
- parent = rcu_dereference_raw(parent->rb_right);
- } else {
- int ret;
-
- if (!tuple) {
- nf_conncount_gc_list(net, &rbconn->list);
- return rbconn->list.count;
- }
-
- spin_lock_bh(&rbconn->list.list_lock);
- /* Node might be about to be free'd.
- * We need to defer to insert_tree() in this case.
- */
- if (rbconn->list.count == 0) {
- spin_unlock_bh(&rbconn->list.list_lock);
- break;
- }
-
- /* same source network -> be counted! */
- ret = __nf_conncount_add(net, &rbconn->list, tuple, zone);
- spin_unlock_bh(&rbconn->list.list_lock);
- if (ret)
- return 0; /* hotdrop */
- else
- return rbconn->list.count;
- }
- }
-
- if (!tuple)
- return 0;
-
- return insert_tree(net, data, root, hash, key, tuple, zone);
-}
-
-static void tree_gc_worker(struct work_struct *work)
-{
- struct nf_conncount_data *data = container_of(work, struct nf_conncount_data, gc_work);
- struct nf_conncount_rb *gc_nodes[CONNCOUNT_GC_MAX_NODES], *rbconn;
- struct rb_root *root;
- struct rb_node *node;
- unsigned int tree, next_tree, gc_count = 0;
-
- tree = data->gc_tree % CONNCOUNT_SLOTS;
- root = &data->root[tree];
-
- local_bh_disable();
- rcu_read_lock();
- for (node = rb_first(root); node != NULL; node = rb_next(node)) {
- rbconn = rb_entry(node, struct nf_conncount_rb, node);
- if (nf_conncount_gc_list(data->net, &rbconn->list))
- gc_count++;
- }
- rcu_read_unlock();
- local_bh_enable();
-
- cond_resched();
-
- spin_lock_bh(&nf_conncount_locks[tree]);
- if (gc_count < ARRAY_SIZE(gc_nodes))
- goto next; /* do not bother */
-
- gc_count = 0;
- node = rb_first(root);
- while (node != NULL) {
- rbconn = rb_entry(node, struct nf_conncount_rb, node);
- node = rb_next(node);
-
- if (rbconn->list.count > 0)
- continue;
-
- gc_nodes[gc_count++] = rbconn;
- if (gc_count >= ARRAY_SIZE(gc_nodes)) {
- tree_nodes_free(root, gc_nodes, gc_count);
- gc_count = 0;
- }
- }
-
- tree_nodes_free(root, gc_nodes, gc_count);
-next:
-
- clear_bit(tree, data->pending_trees);
-
- next_tree = (tree + 1) % CONNCOUNT_SLOTS;
- next_tree = find_next_bit(data->pending_trees, CONNCOUNT_SLOTS, next_tree);
-
- if (next_tree < CONNCOUNT_SLOTS) {
- data->gc_tree = next_tree;
- schedule_work(work);
- }
-
- spin_unlock_bh(&nf_conncount_locks[tree]);
-}
-
-/* Count and return number of conntrack entries in 'net' with particular 'key'.
- * If 'tuple' is not null, insert it into the accounting data structure.
- * Call with RCU read lock.
- */
-unsigned int rpl_nf_conncount_count(struct net *net,
- struct nf_conncount_data *data,
- const u32 *key,
- const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_zone *zone)
-{
- return count_tree(net, data, key, tuple, zone);
-}
-EXPORT_SYMBOL_GPL(rpl_nf_conncount_count);
-
-struct nf_conncount_data *rpl_nf_conncount_init(struct net *net, unsigned int family,
- unsigned int keylen)
-{
- struct nf_conncount_data *data;
- int ret, i;
-
- if (keylen % sizeof(u32) ||
- keylen / sizeof(u32) > MAX_KEYLEN ||
- keylen == 0)
- return ERR_PTR(-EINVAL);
-
- net_get_random_once(&conncount_rnd, sizeof(conncount_rnd));
-
- data = kmalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
- return ERR_PTR(-ENOMEM);
-
- ret = nf_ct_netns_get(net, family);
- if (ret < 0) {
- kfree(data);
- return ERR_PTR(ret);
- }
-
- for (i = 0; i < ARRAY_SIZE(data->root); ++i)
- data->root[i] = RB_ROOT;
-
- data->keylen = keylen / sizeof(u32);
- data->net = net;
- INIT_WORK(&data->gc_work, tree_gc_worker);
-
- return data;
-}
-EXPORT_SYMBOL_GPL(rpl_nf_conncount_init);
-
-static void nf_conncount_cache_free(struct nf_conncount_list *list)
-{
- struct nf_conncount_tuple *conn, *conn_n;
-
- list_for_each_entry_safe(conn, conn_n, &list->head, node)
- kmem_cache_free(conncount_conn_cachep, conn);
-}
-
-static void destroy_tree(struct rb_root *r)
-{
- struct nf_conncount_rb *rbconn;
- struct rb_node *node;
-
- while ((node = rb_first(r)) != NULL) {
- rbconn = rb_entry(node, struct nf_conncount_rb, node);
-
- rb_erase(node, r);
-
- nf_conncount_cache_free(&rbconn->list);
-
- kmem_cache_free(conncount_rb_cachep, rbconn);
- }
-}
-
-void rpl_nf_conncount_destroy(struct net *net, unsigned int family,
- struct nf_conncount_data *data)
-{
- unsigned int i;
-
- cancel_work_sync(&data->gc_work);
- nf_ct_netns_put(net, family);
-
- for (i = 0; i < ARRAY_SIZE(data->root); ++i)
- destroy_tree(&data->root[i]);
-
- kfree(data);
-}
-EXPORT_SYMBOL_GPL(rpl_nf_conncount_destroy);
-
-int rpl_nf_conncount_modinit(void)
-{
- int i;
-
- for (i = 0; i < CONNCOUNT_SLOTS; ++i)
- spin_lock_init(&nf_conncount_locks[i]);
-
- conncount_conn_cachep = kmem_cache_create("nf_conncount_tuple",
- sizeof(struct nf_conncount_tuple),
- 0, 0, NULL);
- if (!conncount_conn_cachep)
- return -ENOMEM;
-
- conncount_rb_cachep = kmem_cache_create("nf_conncount_rb",
- sizeof(struct nf_conncount_rb),
- 0, 0, NULL);
- if (!conncount_rb_cachep) {
- kmem_cache_destroy(conncount_conn_cachep);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void rpl_nf_conncount_modexit(void)
-{
- kmem_cache_destroy(conncount_conn_cachep);
- kmem_cache_destroy(conncount_rb_cachep);
-}
-
-#endif /* HAVE_UPSTREAM_NF_CONNCOUNT */
diff --git a/datapath/linux/compat/nf_conntrack_core.c b/datapath/linux/compat/nf_conntrack_core.c
deleted file mode 100644
index a7d3d4331..000000000
--- a/datapath/linux/compat/nf_conntrack_core.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <linux/version.h>
-
-#ifndef HAVE_NF_CT_ZONE_INIT
-
-#include <net/netfilter/nf_conntrack_zones.h>
-
-/* Built-in default zone used e.g. by modules. */
-const struct nf_conntrack_zone nf_ct_zone_dflt = {
- .id = NF_CT_DEFAULT_ZONE_ID,
- .dir = NF_CT_DEFAULT_ZONE_DIR,
-};
-
-#endif /* HAVE_NF_CT_ZONE_INIT */
diff --git a/datapath/linux/compat/nf_conntrack_proto.c b/datapath/linux/compat/nf_conntrack_proto.c
deleted file mode 100644
index fe291dbf2..000000000
--- a/datapath/linux/compat/nf_conntrack_proto.c
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <linux/types.h>
-
-#include <net/netfilter/nf_conntrack.h>
-#ifdef HAVE_NF_CONNTRACK_L3PROATO_H
-#include <net/netfilter/nf_conntrack_l3proto.h>
-#endif
-
-/*
- * Upstream net-next commmit 7e35ec0e8044
- * ("netfilter: conntrack: move nf_ct_netns_{get,put}() to core")
- * is introduced in v4.15, and it supports NFPROTO_INET in
- * nf_ct_netns_{get,put}() that OVS conntrack uses this feature.
- *
- * However, we only need this feature if the underlying nf_conntrack_l3proto
- * supports net_ns_get/put. Thus, we just mock the functions if
- * HAVE_NET_NS_GET is false.
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)
-#ifdef HAVE_NET_NS_GET
-static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
-{
- const struct nf_conntrack_l3proto *l3proto;
- int ret;
-
- might_sleep();
-
- ret = nf_ct_l3proto_try_module_get(nfproto);
- if (ret < 0)
- return ret;
-
- /* we already have a reference, can't fail */
- rcu_read_lock();
- l3proto = __nf_ct_l3proto_find(nfproto);
- rcu_read_unlock();
-
- if (!l3proto->net_ns_get)
- return 0;
-
- ret = l3proto->net_ns_get(net);
- if (ret < 0)
- nf_ct_l3proto_module_put(nfproto);
-
- return ret;
-}
-
-int rpl_nf_ct_netns_get(struct net *net, u8 nfproto)
-{
- int err;
-
- if (nfproto == NFPROTO_INET) {
- err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
- if (err < 0)
- goto err1;
- err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
- if (err < 0)
- goto err2;
- } else {
- err = nf_ct_netns_do_get(net, nfproto);
- if (err < 0)
- goto err1;
- }
- return 0;
-
-err2:
- nf_ct_netns_put(net, NFPROTO_IPV4);
-err1:
- return err;
-}
-EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_get);
-
-static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
-{
- const struct nf_conntrack_l3proto *l3proto;
-
- might_sleep();
-
- /* same as nf_conntrack_netns_get(), reference assumed */
- rcu_read_lock();
- l3proto = __nf_ct_l3proto_find(nfproto);
- rcu_read_unlock();
-
- if (WARN_ON(!l3proto))
- return;
-
- if (l3proto->net_ns_put)
- l3proto->net_ns_put(net);
-
- nf_ct_l3proto_module_put(nfproto);
-}
-
-void rpl_nf_ct_netns_put(struct net *net, uint8_t nfproto)
-{
- if (nfproto == NFPROTO_INET) {
- nf_ct_netns_do_put(net, NFPROTO_IPV4);
- nf_ct_netns_do_put(net, NFPROTO_IPV6);
- } else
- nf_ct_netns_do_put(net, nfproto);
-}
-EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_put);
-
-#else /* !HAVE_NET_NS_GET */
-void rpl_nf_ct_netns_put(struct net *net, uint8_t nfproto)
-{
-}
-EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_put);
-
-int rpl_nf_ct_netns_get(struct net *net, u8 nfproto)
-{
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_get);
-
-#endif /* HAVE_NET_NS_GET */
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) */
diff --git a/datapath/linux/compat/nf_conntrack_reasm.c b/datapath/linux/compat/nf_conntrack_reasm.c
deleted file mode 100644
index 77b4b2548..000000000
--- a/datapath/linux/compat/nf_conntrack_reasm.c
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Backported from upstream commit 5b490047240f
- * ("ipv6: Export nf_ct_frag6_gather()")
- *
- * IPv6 fragment reassembly for connection tracking
- *
- * Copyright (C)2004 USAGI/WIDE Project
- *
- * Author:
- * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *
- * Based on: net/ipv6/reassembly.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#define pr_fmt(fmt) "IPv6-nf: " fmt
-
-#include <linux/version.h>
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/jiffies.h>
-#include <linux/net.h>
-#include <linux/list.h>
-#include <linux/netdevice.h>
-#include <linux/in6.h>
-#include <linux/ipv6.h>
-#include <linux/icmpv6.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-#include <net/snmp.h>
-#include <net/inet_frag.h>
-
-#include <net/ipv6.h>
-#include <net/ipv6_frag.h>
-#include <net/protocol.h>
-#include <net/transp_v6.h>
-#include <net/rawv6.h>
-#include <net/ndisc.h>
-#include <net/addrconf.h>
-#include <net/inet_ecn.h>
-#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv6.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
-#include <net/netns/generic.h>
-#include "datapath.h"
-
-#if defined(HAVE_INET_FRAGS_WITH_FRAGS_WORK) || !defined(HAVE_INET_FRAGS_RND)
-
-static const char nf_frags_cache_name[] = "ovs-frag6";
-
-#endif
-
-#ifdef OVS_NF_DEFRAG6_BACKPORT
-struct nf_ct_frag6_skb_cb
-{
- struct inet6_skb_parm h;
- int offset;
-};
-
-#define NFCT_FRAG6_CB(skb) ((struct nf_ct_frag6_skb_cb*)((skb)->cb))
-
-static struct inet_frags nf_frags;
-
-static struct netns_frags *get_netns_frags6_from_net(struct net *net)
-{
-#ifdef HAVE_INET_FRAG_LRU_MOVE
- struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
- return &(ovs_net->nf_frags);
-#else
- return &(net->nf_frag.frags);
-#endif
-}
-
-static struct net *get_net_from_netns_frags6(struct netns_frags *frags)
-{
- struct net *net;
-#ifdef HAVE_INET_FRAG_LRU_MOVE
- struct ovs_net *ovs_net;
-
- ovs_net = container_of(frags, struct ovs_net, nf_frags);
- net = ovs_net->net;
-#else
- net = container_of(frags, struct net, nf_frag.frags);
-#endif
- return net;
-}
-
-static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
-{
- return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK);
-}
-
-#ifdef HAVE_INET_FRAGS_RND
-static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr,
- const struct in6_addr *daddr)
-{
- net_get_random_once(&nf_frags.rnd, sizeof(nf_frags.rnd));
- return jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr),
- (__force u32)id, nf_frags.rnd);
-}
-/* fb3cfe6e75b9 ("inet: frag: remove hash size assumptions from callers")
- * shifted this logic into inet_fragment, but prior kernels still need this.
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
-#define nf_hash_frag(a, b, c) (nf_hash_frag(a, b, c) & (INETFRAGS_HASHSZ - 1))
-#endif
-
-#ifdef HAVE_INET_FRAGS_CONST
-static unsigned int nf_hashfn(const struct inet_frag_queue *q)
-#else
-static unsigned int nf_hashfn(struct inet_frag_queue *q)
-#endif
-{
- const struct frag_queue *nq;
-
- nq = container_of(q, struct frag_queue, q);
- return nf_hash_frag(nq->id, &nq->saddr, &nq->daddr);
-}
-
-#endif /* HAVE_INET_FRAGS_RND */
-static void nf_ct_frag6_expire(unsigned long data)
-{
- struct frag_queue *fq;
- struct net *net;
-
- fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q);
- net = get_net_from_netns_frags6(fq->q.net);
-
-#ifdef HAVE_INET_FRAGS_RND
- ip6_expire_frag_queue(net, fq, &nf_frags);
-#else
-#ifdef HAVE_IPV6_FRAG_H
- ip6frag_expire_frag_queue(net, fq);
-#else
- ip6_expire_frag_queue(net, fq);
-#endif
-#endif
-}
-
-#ifdef HAVE_INET_FRAGS_RND
-/* Creation primitives. */
-static inline struct frag_queue *fq_find(struct net *net, __be32 id,
- u32 user, struct in6_addr *src,
- struct in6_addr *dst, u8 ecn)
-{
- struct inet_frag_queue *q;
- struct ip6_create_arg arg;
- unsigned int hash;
- struct netns_frags *frags;
-
- arg.id = id;
- arg.user = user;
- arg.src = src;
- arg.dst = dst;
- arg.ecn = ecn;
-
-#ifdef HAVE_INET_FRAGS_WITH_RWLOCK
- read_lock_bh(&nf_frags.lock);
-#else
- local_bh_disable();
-#endif
- hash = nf_hash_frag(id, src, dst);
-
- frags = get_netns_frags6_from_net(net);
- q = inet_frag_find(frags, &nf_frags, &arg, hash);
- local_bh_enable();
- if (IS_ERR_OR_NULL(q)) {
- inet_frag_maybe_warn_overflow(q, pr_fmt());
- return NULL;
- }
- return container_of(q, struct frag_queue, q);
-}
-#else
-static struct frag_queue *fq_find(struct net *net, __be32 id, u32 user,
- const struct ipv6hdr *hdr, int iif)
-{
- struct frag_v6_compare_key key = {
- .id = id,
- .saddr = hdr->saddr,
- .daddr = hdr->daddr,
- .user = user,
- .iif = iif,
- };
- struct inet_frag_queue *q;
-
- q = inet_frag_find(&net->nf_frag.frags, &key);
- if (!q)
- return NULL;
-
- return container_of(q, struct frag_queue, q);
-}
-
-#endif /* HAVE_INET_FRAGS_RND */
-
-static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
- const struct frag_hdr *fhdr, int nhoff)
-{
- struct sk_buff *prev, *next;
- unsigned int payload_len;
- int offset, end;
- u8 ecn;
-
- if (qp_flags(fq) & INET_FRAG_COMPLETE) {
- pr_debug("Already completed\n");
- goto err;
- }
-
- payload_len = ntohs(ipv6_hdr(skb)->payload_len);
-
- offset = ntohs(fhdr->frag_off) & ~0x7;
- end = offset + (payload_len -
- ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
-
- if ((unsigned int)end > IPV6_MAXPLEN) {
- pr_debug("offset is too large.\n");
- return -1;
- }
-
- ecn = ip6_frag_ecn(ipv6_hdr(skb));
-
- if (skb->ip_summed == CHECKSUM_COMPLETE) {
- const unsigned char *nh = skb_network_header(skb);
- skb->csum = csum_sub(skb->csum,
- csum_partial(nh, (u8 *)(fhdr + 1) - nh,
- 0));
- }
-
- /* Is this the final fragment? */
- if (!(fhdr->frag_off & htons(IP6_MF))) {
- /* If we already have some bits beyond end
- * or have different end, the segment is corrupted.
- */
- if (end < fq->q.len ||
- ((qp_flags(fq) & INET_FRAG_LAST_IN) && end != fq->q.len)) {
- pr_debug("already received last fragment\n");
- goto err;
- }
- qp_flags(fq) |= INET_FRAG_LAST_IN;
- fq->q.len = end;
- } else {
- /* Check if the fragment is rounded to 8 bytes.
- * Required by the RFC.
- */
- if (end & 0x7) {
- /* RFC2460 says always send parameter problem in
- * this case. -DaveM
- */
- pr_debug("end of fragment not rounded to 8 bytes.\n");
- return -1;
- }
- if (end > fq->q.len) {
- /* Some bits beyond end -> corruption. */
- if (qp_flags(fq) & INET_FRAG_LAST_IN) {
- pr_debug("last packet already reached.\n");
- goto err;
- }
- fq->q.len = end;
- }
- }
-
- if (end == offset)
- goto err;
-
- /* Point into the IP datagram 'data' part. */
- if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) {
- pr_debug("queue: message is too short.\n");
- goto err;
- }
- if (pskb_trim_rcsum(skb, end - offset)) {
- pr_debug("Can't trim\n");
- goto err;
- }
-
- /* Find out which fragments are in front and at the back of us
- * in the chain of fragments so far. We must know where to put
- * this fragment, right?
- */
- prev = fq->q.fragments_tail;
- if (!prev || NFCT_FRAG6_CB(prev)->offset < offset) {
- next = NULL;
- goto found;
- }
- prev = NULL;
- for (next = fq->q.fragments; next != NULL; next = next->next) {
- if (NFCT_FRAG6_CB(next)->offset >= offset)
- break; /* bingo! */
- prev = next;
- }
-
-found:
- /* RFC5722, Section 4:
- * When reassembling an IPv6 datagram, if
- * one or more its constituent fragments is determined to be an
- * overlapping fragment, the entire datagram (and any constituent
- * fragments, including those not yet received) MUST be silently
- * discarded.
- */
-
- /* Check for overlap with preceding fragment. */
- if (prev &&
- (NFCT_FRAG6_CB(prev)->offset + prev->len) > offset)
- goto discard_fq;
-
- /* Look for overlap with succeeding segment. */
- if (next && NFCT_FRAG6_CB(next)->offset < end)
- goto discard_fq;
-
- NFCT_FRAG6_CB(skb)->offset = offset;
-
- /* Insert this fragment in the chain of fragments. */
- skb->next = next;
- if (!next)
- fq->q.fragments_tail = skb;
- if (prev)
- prev->next = skb;
- else
- fq->q.fragments = skb;
-
- if (skb->dev) {
- fq->iif = skb->dev->ifindex;
- skb->dev = NULL;
- }
- fq->q.stamp = skb->tstamp;
- fq->q.meat += skb->len;
- fq->ecn |= ecn;
- if (payload_len > fq->q.max_size)
- fq->q.max_size = payload_len;
- add_frag_mem_limit(fq->q.net, skb->truesize);
-
- /* The first fragment.
- * nhoffset is obtained from the first fragment, of course.
- */
- if (offset == 0) {
- fq->nhoffset = nhoff;
- qp_flags(fq) |= INET_FRAG_FIRST_IN;
- }
-
- inet_frag_lru_move(&fq->q);
- return 0;
-
-discard_fq:
-#ifdef HAVE_INET_FRAGS_RND
- inet_frag_kill(&fq->q, &nf_frags);
-#else
- inet_frag_kill(&fq->q);
-#endif
-err:
- return -1;
-}
-
-/*
- * Check if this packet is complete.
- *
- * It is called with locked fq, and caller must check that
- * queue is eligible for reassembly i.e. it is not COMPLETE,
- * the last and the first frames arrived and all the bits are here.
- *
- * returns true if *prev skb has been transformed into the reassembled
- * skb, false otherwise.
- */
-static bool
-nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *prev, struct net_device *dev)
-{
- struct sk_buff *fp, *head = fq->q.fragments;
- int payload_len;
- u8 ecn;
-
-#ifdef HAVE_INET_FRAGS_RND
- inet_frag_kill(&fq->q, &nf_frags);
-#else
- inet_frag_kill(&fq->q);
-#endif
-
- WARN_ON(head == NULL);
- WARN_ON(NFCT_FRAG6_CB(head)->offset != 0);
-
- ecn = ip_frag_ecn_table[fq->ecn];
- if (unlikely(ecn == 0xff))
- return false;
-
- /* Unfragmented part is taken from the first segment. */
- payload_len = ((head->data - skb_network_header(head)) -
- sizeof(struct ipv6hdr) + fq->q.len -
- sizeof(struct frag_hdr));
- if (payload_len > IPV6_MAXPLEN) {
- net_dbg_ratelimited("nf_ct_frag6_reasm: payload len = %d\n",
- payload_len);
- return false;
- }
-
- /* Head of list must not be cloned. */
- if (skb_unclone(head, GFP_ATOMIC))
- return false;
-
- /* If the first fragment is fragmented itself, we split
- * it to two chunks: the first with data and paged part
- * and the second, holding only fragments. */
- if (skb_has_frag_list(head)) {
- struct sk_buff *clone;
- int i, plen = 0;
-
- clone = alloc_skb(0, GFP_ATOMIC);
- if (clone == NULL)
- return false;
-
- clone->next = head->next;
- head->next = clone;
- skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
- skb_frag_list_init(head);
- for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
- plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
- clone->len = clone->data_len = head->data_len - plen;
- head->data_len -= clone->len;
- head->len -= clone->len;
- clone->csum = 0;
- clone->ip_summed = head->ip_summed;
-
- add_frag_mem_limit(fq->q.net, clone->truesize);
- }
-
- /* morph head into last received skb: prev.
- *
- * This allows callers of ipv6 conntrack defrag to continue
- * to use the last skb(frag) passed into the reasm engine.
- * The last skb frag 'silently' turns into the full reassembled skb.
- *
- * Since prev is also part of q->fragments we have to clone it first.
- */
- if (head != prev) {
- struct sk_buff *iter;
-
- fp = skb_clone(prev, GFP_ATOMIC);
- if (!fp)
- return false;
-
- fp->next = prev->next;
-
- iter = head;
- while (iter) {
- if (iter->next == prev) {
- iter->next = fp;
- break;
- }
- iter = iter->next;
- }
-
- skb_morph(prev, head);
- prev->next = head->next;
- consume_skb(head);
- head = prev;
- }
-
- /* We have to remove fragment header from datagram and to relocate
- * header in order to calculate ICV correctly. */
- skb_network_header(head)[fq->nhoffset] = skb_transport_header(head)[0];
- memmove(head->head + sizeof(struct frag_hdr), head->head,
- (head->data - head->head) - sizeof(struct frag_hdr));
- head->mac_header += sizeof(struct frag_hdr);
- head->network_header += sizeof(struct frag_hdr);
-
- skb_shinfo(head)->frag_list = head->next;
- skb_reset_transport_header(head);
- skb_push(head, head->data - skb_network_header(head));
-
- for (fp=head->next; fp; fp = fp->next) {
- head->data_len += fp->len;
- head->len += fp->len;
- if (head->ip_summed != fp->ip_summed)
- head->ip_summed = CHECKSUM_NONE;
- else if (head->ip_summed == CHECKSUM_COMPLETE)
- head->csum = csum_add(head->csum, fp->csum);
- head->truesize += fp->truesize;
- }
- sub_frag_mem_limit(fq->q.net, head->truesize);
-
- head->ignore_df = 1;
- head->next = NULL;
- head->dev = dev;
- head->tstamp = fq->q.stamp;
- ipv6_hdr(head)->payload_len = htons(payload_len);
- ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn);
- IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size;
-
- /* Yes, and fold redundant checksum back. 8) */
- if (head->ip_summed == CHECKSUM_COMPLETE)
- head->csum = csum_partial(skb_network_header(head),
- skb_network_header_len(head),
- head->csum);
-
- fq->q.fragments = NULL;
- fq->q.fragments_tail = NULL;
-
- return true;
-}
-
-/*
- * find the header just before Fragment Header.
- *
- * if success return 0 and set ...
- * (*prevhdrp): the value of "Next Header Field" in the header
- * just before Fragment Header.
- * (*prevhoff): the offset of "Next Header Field" in the header
- * just before Fragment Header.
- * (*fhoff) : the offset of Fragment Header.
- *
- * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c
- *
- */
-static int
-find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
-{
- u8 nexthdr = ipv6_hdr(skb)->nexthdr;
- const int netoff = skb_network_offset(skb);
- u8 prev_nhoff = netoff + offsetof(struct ipv6hdr, nexthdr);
- int start = netoff + sizeof(struct ipv6hdr);
- int len = skb->len - start;
- u8 prevhdr = NEXTHDR_IPV6;
-
- while (nexthdr != NEXTHDR_FRAGMENT) {
- struct ipv6_opt_hdr hdr;
- int hdrlen;
-
- if (!ipv6_ext_hdr(nexthdr)) {
- return -1;
- }
- if (nexthdr == NEXTHDR_NONE) {
- pr_debug("next header is none\n");
- return -1;
- }
- if (len < (int)sizeof(struct ipv6_opt_hdr)) {
- pr_debug("too short\n");
- return -1;
- }
- if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
- BUG();
- if (nexthdr == NEXTHDR_AUTH)
- hdrlen = (hdr.hdrlen+2)<<2;
- else
- hdrlen = ipv6_optlen(&hdr);
-
- prevhdr = nexthdr;
- prev_nhoff = start;
-
- nexthdr = hdr.nexthdr;
- len -= hdrlen;
- start += hdrlen;
- }
-
- if (len < 0)
- return -1;
-
- *prevhdrp = prevhdr;
- *prevhoff = prev_nhoff;
- *fhoff = start;
-
- return 0;
-}
-
-int rpl_nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
-{
- struct net_device *dev = skb->dev;
- int fhoff, nhoff, ret;
- struct frag_hdr *fhdr;
- struct frag_queue *fq;
- struct ipv6hdr *hdr;
- u8 prevhdr;
- struct netns_frags *frags;
-
- /* Jumbo payload inhibits frag. header */
- if (ipv6_hdr(skb)->payload_len == 0) {
- pr_debug("payload len = 0\n");
- return -EINVAL;
- }
-
- if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0)
- return -EINVAL;
-
- if (!pskb_may_pull(skb, fhoff + sizeof(*fhdr)))
- return -ENOMEM;
-
- skb_set_transport_header(skb, fhoff);
- hdr = ipv6_hdr(skb);
- fhdr = (struct frag_hdr *)skb_transport_header(skb);
-
-/* See ip_evictor(). */
- frags = get_netns_frags6_from_net(net);
-#ifdef HAVE_INET_FRAG_EVICTOR
- local_bh_disable();
- inet_frag_evictor(frags, &nf_frags, false);
- local_bh_enable();
-#endif
-
- skb_orphan(skb);
-#ifdef HAVE_INET_FRAGS_RND
- fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
- ip6_frag_ecn(hdr));
-#else
- fq = fq_find(net, fhdr->identification, user, hdr,
- skb->dev ? skb->dev->ifindex : 0);
-#endif
- if (fq == NULL)
- return -ENOMEM;
-
- spin_lock_bh(&fq->q.lock);
-
- if (nf_ct_frag6_queue(fq, skb, fhdr, nhoff) < 0) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- /* after queue has assumed skb ownership, only 0 or -EINPROGRESS
- * must be returned.
- */
- ret = -EINPROGRESS;
- if (qp_flags(fq) == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
- fq->q.meat == fq->q.len &&
- nf_ct_frag6_reasm(fq, skb, dev))
- ret = 0;
-
-out_unlock:
- spin_unlock_bh(&fq->q.lock);
-#ifdef HAVE_INET_FRAGS_RND
- inet_frag_put(&fq->q, &nf_frags);
-#else
- inet_frag_put(&fq->q);
-#endif
- return ret;
-}
-
-#ifdef HAVE_DEFRAG_ENABLE_TAKES_NET
-static int nf_ct_net_init(struct net *net)
-{
- return nf_defrag_ipv6_enable(net);
-}
-#endif
-
-static void nf_ct_net_exit(struct net *net)
-{
-}
-
-void ovs_netns_frags6_init(struct net *net)
-{
-#ifdef HAVE_INET_FRAG_LRU_MOVE
- struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
-
- ovs_net->nf_frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
- ovs_net->nf_frags.low_thresh = IPV6_FRAG_LOW_THRESH;
- ovs_net->nf_frags.timeout = IPV6_FRAG_TIMEOUT;
-
- inet_frags_init_net(&(ovs_net->nf_frags));
-#endif
-}
-
-void ovs_netns_frags6_exit(struct net *net)
-{
-#ifdef HAVE_INET_FRAGS_RND
- struct netns_frags *frags;
-
- frags = get_netns_frags6_from_net(net);
- inet_frags_exit_net(frags, &nf_frags);
-#endif
-}
-
-static struct pernet_operations nf_ct_net_ops = {
-#ifdef HAVE_DEFRAG_ENABLE_TAKES_NET
- .init = nf_ct_net_init,
-#endif
- .exit = nf_ct_net_exit,
-};
-
-#ifdef HAVE_IPV6_FRAG_H
-static const struct rhashtable_params nfct_rhash_params = {
- .head_offset = offsetof(struct inet_frag_queue, node),
- .hashfn = ip6frag_key_hashfn,
- .obj_hashfn = ip6frag_obj_hashfn,
- .obj_cmpfn = ip6frag_obj_cmpfn,
- .automatic_shrinking = true,
-};
-#endif
-
-int rpl_nf_ct_frag6_init(void)
-{
- int ret = 0;
-
-#ifndef HAVE_DEFRAG_ENABLE_TAKES_NET
- nf_defrag_ipv6_enable();
-#endif
-#ifdef HAVE_INET_FRAGS_RND
- nf_frags.hashfn = nf_hashfn;
- nf_frags.match = ip6_frag_match;
- nf_frags.constructor = ip6_frag_init;
-#else
-#ifdef HAVE_IPV6_FRAG_H
- nf_frags.rhash_params = nfct_rhash_params;
- nf_frags.constructor = ip6frag_init;
-#else
- nf_frags.rhash_params = ip6_rhash_params;
- nf_frags.constructor = ip6_frag_init;
-#endif
-#endif /* HAVE_INET_FRAGS_RND */
- nf_frags.destructor = NULL;
- nf_frags.qsize = sizeof(struct frag_queue);
- nf_frags.frag_expire = nf_ct_frag6_expire;
-#if defined(HAVE_INET_FRAGS_WITH_FRAGS_WORK) || !defined(HAVE_INET_FRAGS_RND)
- nf_frags.frags_cache_name = nf_frags_cache_name;
-#endif
-#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0)
- nf_frags.secret_interval = 10 * 60 * HZ;
-#endif
- ret = inet_frags_init(&nf_frags);
- if (ret)
- goto out;
- ret = register_pernet_subsys(&nf_ct_net_ops);
- if (ret)
- inet_frags_fini(&nf_frags);
-
-out:
- return ret;
-}
-
-void rpl_nf_ct_frag6_cleanup(void)
-{
- unregister_pernet_subsys(&nf_ct_net_ops);
- inet_frags_fini(&nf_frags);
-}
-
-#endif /* OVS_NF_DEFRAG6_BACKPORT */
diff --git a/datapath/linux/compat/nf_conntrack_timeout.c b/datapath/linux/compat/nf_conntrack_timeout.c
deleted file mode 100644
index c02baff57..000000000
--- a/datapath/linux/compat/nf_conntrack_timeout.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_core.h>
-#include <net/netfilter/nf_conntrack_extend.h>
-#include <net/netfilter/nf_conntrack_timeout.h>
-
-#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
-#ifndef HAVE_NF_CT_SET_TIMEOUT
-static void rpl__nf_ct_timeout_put(struct nf_ct_timeout *timeout)
-{
- typeof(nf_ct_timeout_put_hook) timeout_put;
-
- timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
- if (timeout_put)
- timeout_put(timeout);
-}
-
-int rpl_nf_ct_set_timeout(struct net *net, struct nf_conn *ct,
- u8 l3num, u8 l4num, const char *timeout_name)
-{
- typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
- struct nf_ct_timeout *timeout;
- struct nf_conn_timeout *timeout_ext;
- const char *errmsg = NULL;
- int ret = 0;
-
- rcu_read_lock();
- timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
- if (!timeout_find_get) {
- ret = -ENOENT;
- errmsg = "Timeout policy base is empty";
- goto out;
- }
-
-#ifdef HAVE_NF_CT_TIMEOUT_FIND_GET_HOOK_NET
- timeout = timeout_find_get(net, timeout_name);
-#else
- timeout = timeout_find_get(timeout_name);
-#endif
- if (!timeout) {
- ret = -ENOENT;
- pr_info_ratelimited("No such timeout policy \"%s\"\n",
- timeout_name);
- goto out;
- }
-
- if (timeout->l3num != l3num) {
- ret = -EINVAL;
- pr_info_ratelimited("Timeout policy `%s' can only be used by "
- "L%d protocol number %d\n",
- timeout_name, 3, timeout->l3num);
- goto err_put_timeout;
- }
- /* Make sure the timeout policy matches any existing protocol tracker,
- * otherwise default to generic.
- */
- if (timeout->l4proto->l4proto != l4num) {
- ret = -EINVAL;
- pr_info_ratelimited("Timeout policy `%s' can only be used by "
- "L%d protocol number %d\n",
- timeout_name, 4, timeout->l4proto->l4proto);
- goto err_put_timeout;
- }
- timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
- if (!timeout_ext) {
- ret = -ENOMEM;
- goto err_put_timeout;
- }
-
- rcu_read_unlock();
- return ret;
-
-err_put_timeout:
- rpl__nf_ct_timeout_put(timeout);
-out:
- rcu_read_unlock();
- if (errmsg)
- pr_info_ratelimited("%s\n", errmsg);
- return ret;
-}
-EXPORT_SYMBOL_GPL(rpl_nf_ct_set_timeout);
-
-void rpl_nf_ct_destroy_timeout(struct nf_conn *ct)
-{
- struct nf_conn_timeout *timeout_ext;
- typeof(nf_ct_timeout_put_hook) timeout_put;
-
- rcu_read_lock();
- timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
-
- if (timeout_put) {
- timeout_ext = nf_ct_timeout_find(ct);
- if (timeout_ext) {
- timeout_put(timeout_ext->timeout);
- RCU_INIT_POINTER(timeout_ext->timeout, NULL);
- }
- }
- rcu_read_unlock();
-}
-EXPORT_SYMBOL_GPL(rpl_nf_ct_destroy_timeout);
-
-#endif /* HAVE_NF_CT_SET_TIMEOUT */
-#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
diff --git a/datapath/linux/compat/reciprocal_div.c b/datapath/linux/compat/reciprocal_div.c
deleted file mode 100644
index 818502a0f..000000000
--- a/datapath/linux/compat/reciprocal_div.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <linux/kernel.h>
-#include <asm/div64.h>
-#include <linux/module.h>
-#include <linux/reciprocal_div.h>
-
-/*
- * For a description of the algorithm please have a look at
- * include/linux/reciprocal_div.h
- */
-
-struct reciprocal_value rpl_reciprocal_value(u32 d)
-{
- struct reciprocal_value R;
- u64 m;
- int l;
-
- l = fls(d - 1);
- m = ((1ULL << 32) * ((1ULL << l) - d));
- do_div(m, d);
- ++m;
- R.m = (u32)m;
- R.sh1 = min(l, 1);
- R.sh2 = max(l - 1, 0);
-
- return R;
-}
-EXPORT_SYMBOL_GPL(rpl_reciprocal_value);
diff --git a/datapath/linux/compat/skbuff-openvswitch.c b/datapath/linux/compat/skbuff-openvswitch.c
deleted file mode 100644
index 4cdeedc58..000000000
--- a/datapath/linux/compat/skbuff-openvswitch.c
+++ /dev/null
@@ -1,310 +0,0 @@
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_vlan.h>
-#include <linux/kconfig.h>
-
-#include "gso.h"
-
-#if !defined(HAVE_SKB_WARN_LRO) && defined(NETIF_F_LRO)
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-void __skb_warn_lro_forwarding(const struct sk_buff *skb)
-{
- if (net_ratelimit())
- pr_warn("%s: received packets cannot be forwarded while LRO is enabled\n",
- skb->dev->name);
-}
-
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
-
-static inline bool head_frag(const struct sk_buff *skb)
-{
- return skb->head_frag;
-}
-
- /**
- * skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy()
- * @from: source buffer
- *
- * Calculates the amount of linear headroom needed in the 'to' skb passed
- * into skb_zerocopy().
- */
-unsigned int
-rpl_skb_zerocopy_headlen(const struct sk_buff *from)
-{
- unsigned int hlen = 0;
-
- if (!head_frag(from) ||
- skb_headlen(from) < L1_CACHE_BYTES ||
- skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
- hlen = skb_headlen(from);
-
- if (skb_has_frag_list(from))
- hlen = from->len;
-
- return hlen;
-}
-EXPORT_SYMBOL_GPL(rpl_skb_zerocopy_headlen);
-
-#ifndef HAVE_SKB_ZEROCOPY
-/**
- * skb_zerocopy - Zero copy skb to skb
- * @to: destination buffer
- * @source: source buffer
- * @len: number of bytes to copy from source buffer
- * @hlen: size of linear headroom in destination buffer
- *
- * Copies up to `len` bytes from `from` to `to` by creating references
- * to the frags in the source buffer.
- *
- * The `hlen` as calculated by skb_zerocopy_headlen() specifies the
- * headroom in the `to` buffer.
- *
- * Return value:
- * 0: everything is OK
- * -ENOMEM: couldn't orphan frags of @from due to lack of memory
- * -EFAULT: skb_copy_bits() found some problem with skb geometry
- */
-int
-rpl_skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
-{
- int i, j = 0;
- int plen = 0; /* length of skb->head fragment */
- int ret;
- struct page *page;
- unsigned int offset;
-
- BUG_ON(!head_frag(from) && !hlen);
-
- /* dont bother with small payloads */
- if (len <= skb_tailroom(to))
- return skb_copy_bits(from, 0, skb_put(to, len), len);
-
- if (hlen) {
- ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
- if (unlikely(ret))
- return ret;
- len -= hlen;
- } else {
- plen = min_t(int, skb_headlen(from), len);
- if (plen) {
- page = virt_to_head_page(from->head);
- offset = from->data - (unsigned char *)page_address(page);
- __skb_fill_page_desc(to, 0, page, offset, plen);
- get_page(page);
- j = 1;
- len -= plen;
- }
- }
-
- to->truesize += len + plen;
- to->len += len + plen;
- to->data_len += len + plen;
-
- if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
- skb_tx_error(from);
- return -ENOMEM;
- }
-
- for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
- if (!len)
- break;
- skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
- skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
- len -= skb_shinfo(to)->frags[j].size;
- skb_frag_ref(to, j);
- j++;
- }
- skb_shinfo(to)->nr_frags = j;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_skb_zerocopy);
-#endif
-#endif
-
-#ifndef HAVE_SKB_ENSURE_WRITABLE
-int rpl_skb_ensure_writable(struct sk_buff *skb, int write_len)
-{
- if (!pskb_may_pull(skb, write_len))
- return -ENOMEM;
-
- if (!skb_cloned(skb) || skb_clone_writable(skb, write_len))
- return 0;
-
- return pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-}
-EXPORT_SYMBOL_GPL(rpl_skb_ensure_writable);
-#endif
-
-#if !defined(HAVE___SKB_VLAN_POP) || !defined(HAVE_SKB_VLAN_POP)
-/* remove VLAN header from packet and update csum accordingly. */
-int rpl___skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci)
-{
- struct vlan_hdr *vhdr;
- unsigned int offset = skb->data - skb_mac_header(skb);
- int err;
-
- __skb_push(skb, offset);
- err = skb_ensure_writable(skb, VLAN_ETH_HLEN);
- if (unlikely(err))
- goto pull;
-
- skb_postpull_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN);
-
- vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
- *vlan_tci = ntohs(vhdr->h_vlan_TCI);
-
- memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN);
- __skb_pull(skb, VLAN_HLEN);
-
- vlan_set_encap_proto(skb, vhdr);
- skb->mac_header += VLAN_HLEN;
-
- if (skb_network_offset(skb) < ETH_HLEN)
- skb_set_network_header(skb, ETH_HLEN);
-
- skb_reset_mac_len(skb);
-pull:
- __skb_pull(skb, offset);
-
- return err;
-}
-#endif
-
-#ifndef HAVE_SKB_VLAN_POP
-int rpl_skb_vlan_pop(struct sk_buff *skb)
-{
- u16 vlan_tci;
- __be16 vlan_proto;
- int err;
-
- if (likely(skb_vlan_tag_present(skb))) {
- skb->vlan_tci = 0;
- } else {
- if (unlikely((skb->protocol != htons(ETH_P_8021Q) &&
- skb->protocol != htons(ETH_P_8021AD)) ||
- skb->len < VLAN_ETH_HLEN))
- return 0;
-
- err = rpl___skb_vlan_pop(skb, &vlan_tci);
- if (err)
- return err;
- }
- /* move next vlan tag to hw accel tag */
- if (likely((skb->protocol != htons(ETH_P_8021Q) &&
- skb->protocol != htons(ETH_P_8021AD)) ||
- skb->len < VLAN_ETH_HLEN))
- return 0;
-
- vlan_proto = htons(ETH_P_8021Q);
- err = __skb_vlan_pop(skb, &vlan_tci);
- if (unlikely(err))
- return err;
-
- __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_skb_vlan_pop);
-#endif
-
-#ifndef HAVE_SKB_VLAN_PUSH
-int rpl_skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
-{
- if (skb_vlan_tag_present(skb)) {
- unsigned int offset = skb->data - skb_mac_header(skb);
- int err;
-
- /* __vlan_insert_tag expect skb->data pointing to mac header.
- * So change skb->data before calling it and change back to
- * original position later
- */
- __skb_push(skb, offset);
- err = __vlan_insert_tag(skb, skb->vlan_proto,
- skb_vlan_tag_get(skb));
- if (err)
- return err;
- skb->mac_len += VLAN_HLEN;
- __skb_pull(skb, offset);
-
- if (skb->ip_summed == CHECKSUM_COMPLETE)
- skb->csum = csum_add(skb->csum, csum_partial(skb->data
- + (2 * ETH_ALEN), VLAN_HLEN, 0));
- }
- __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_skb_vlan_push);
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
-int rpl_pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
- gfp_t gfp_mask)
-{
- int err;
- int inner_mac_offset, inner_nw_offset, inner_transport_offset;
-
- inner_mac_offset = skb_inner_mac_offset(skb);
- inner_nw_offset = skb_inner_network_offset(skb);
- inner_transport_offset = skb_inner_transport_offset(skb);
-
-#undef pskb_expand_head
- err = pskb_expand_head(skb, nhead, ntail, gfp_mask);
- if (err)
- return err;
-
- skb_set_inner_mac_header(skb, inner_mac_offset);
- skb_set_inner_network_header(skb, inner_nw_offset);
- skb_set_inner_transport_header(skb, inner_transport_offset);
-
- return 0;
-}
-EXPORT_SYMBOL(rpl_pskb_expand_head);
-
-#endif
-
-#ifndef HAVE_KFREE_SKB_LIST
-void rpl_kfree_skb_list(struct sk_buff *segs)
-{
- while (segs) {
- struct sk_buff *next = segs->next;
-
- kfree_skb(segs);
- segs = next;
- }
-}
-EXPORT_SYMBOL(rpl_kfree_skb_list);
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
-
-#define nf_reset_trace rpl_nf_reset_trace
-static void nf_reset_trace(struct sk_buff *skb)
-{
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
- skb->nf_trace = 0;
-#endif
-}
-
-void rpl_skb_scrub_packet(struct sk_buff *skb, bool xnet)
-{
- skb->tstamp.tv64 = 0;
- skb->pkt_type = PACKET_HOST;
- skb->skb_iif = 0;
- skb->ignore_df = 0;
- skb_dst_drop(skb);
- secpath_reset(skb);
- nf_reset(skb);
- nf_reset_trace(skb);
-
- if (!xnet)
- return;
-
- skb_orphan(skb);
- skb->mark = 0;
-}
-#endif
diff --git a/datapath/linux/compat/socket.c b/datapath/linux/compat/socket.c
deleted file mode 100644
index 7f61e4456..000000000
--- a/datapath/linux/compat/socket.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/socket.h>
-#include <linux/udp.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <net/ip_tunnels.h>
-#include <net/udp.h>
-#include <net/udp_tunnel.h>
-#include <net/net_namespace.h>
-
-
-#ifndef HAVE_SOCK_CREATE_KERN_NET
-#undef sock_create_kern
-
-int ovs_sock_create_kern(struct net *net, int family, int type, int protocol, struct socket **res)
-{
- int err;
-
- err = sock_create_kern(family, type, protocol, res);
- if (err < 0)
- return err;
-
- sk_change_net((*res)->sk, net);
- return err;
-}
-#undef sk_release_kernel
-void ovs_sock_release(struct socket *sock)
-{
- sk_release_kernel(sock->sk);
-}
-#endif
diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c
deleted file mode 100644
index 39a294764..000000000
--- a/datapath/linux/compat/stt.c
+++ /dev/null
@@ -1,2129 +0,0 @@
-/*
- * Stateless TCP Tunnel (STT) vport.
- *
- * Copyright (c) 2015 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <asm/unaligned.h>
-
-#include <linux/delay.h>
-#include <linux/if.h>
-#include <linux/if_vlan.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/jhash.h>
-#include <linux/list.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-#include <linux/net.h>
-#include <linux/netfilter.h>
-#include <linux/percpu.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/workqueue.h>
-
-#include <net/dst_metadata.h>
-#include <net/icmp.h>
-#include <net/inet_ecn.h>
-#include <net/ip.h>
-#include <net/ip_tunnels.h>
-#include <net/ip6_checksum.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/sock.h>
-#include <net/stt.h>
-#include <net/tcp.h>
-#include <net/udp.h>
-
-#include "gso.h"
-#include "compat.h"
-
-#define STT_NETDEV_VER "0.1"
-#define STT_DST_PORT 7471
-
-#ifdef OVS_STT
-#ifdef CONFIG_SLUB
-/*
- * We saw better performance with skipping zero copy in case of SLUB.
- * So skip zero copy for SLUB case.
- */
-#define SKIP_ZERO_COPY
-#endif
-
-#define STT_VER 0
-
-/* @list: Per-net list of STT ports.
- * @rcv: The callback is called on STT packet recv, STT reassembly can generate
- * multiple packets, in this case first packet has tunnel outer header, rest
- * of the packets are inner packet segments with no stt header.
- * @rcv_data: user data.
- * @sock: Fake TCP socket for the STT port.
- */
-struct stt_dev {
- struct net_device *dev;
- struct net *net;
- struct list_head next;
- struct list_head up_next;
- struct socket *sock;
- __be16 dst_port;
-};
-
-#define STT_CSUM_VERIFIED BIT(0)
-#define STT_CSUM_PARTIAL BIT(1)
-#define STT_PROTO_IPV4 BIT(2)
-#define STT_PROTO_TCP BIT(3)
-#define STT_PROTO_TYPES (STT_PROTO_IPV4 | STT_PROTO_TCP)
-
-#ifdef HAVE_SKB_GSO_UDP
-#define SUPPORTED_GSO_TYPES (SKB_GSO_TCPV4 | SKB_GSO_UDP | SKB_GSO_DODGY | \
- SKB_GSO_TCPV6)
-#else
-#define SUPPORTED_GSO_TYPES (SKB_GSO_TCPV4 | SKB_GSO_DODGY | \
- SKB_GSO_TCPV6)
-#endif
-
-/* The length and offset of a fragment are encoded in the sequence number.
- * STT_SEQ_LEN_SHIFT is the left shift needed to store the length.
- * STT_SEQ_OFFSET_MASK is the mask to extract the offset.
- */
-#define STT_SEQ_LEN_SHIFT 16
-#define STT_SEQ_OFFSET_MASK (BIT(STT_SEQ_LEN_SHIFT) - 1)
-
-/* The maximum amount of memory used to store packets waiting to be reassembled
- * on a given CPU. Once this threshold is exceeded we will begin freeing the
- * least recently used fragments.
- */
-#define REASM_HI_THRESH (4 * 1024 * 1024)
-/* The target for the high memory evictor. Once we have exceeded
- * REASM_HI_THRESH, we will continue freeing fragments until we hit
- * this limit.
- */
-#define REASM_LO_THRESH (3 * 1024 * 1024)
-/* The length of time a given packet has to be reassembled from the time the
- * first fragment arrives. Once this limit is exceeded it becomes available
- * for cleaning.
- */
-#define FRAG_EXP_TIME (30 * HZ)
-/* Number of hash entries. Each entry has only a single slot to hold a packet
- * so if there are collisions, we will drop packets. This is allocated
- * per-cpu and each entry consists of struct pkt_frag.
- */
-#define FRAG_HASH_SHIFT 8
-#define FRAG_HASH_ENTRIES BIT(FRAG_HASH_SHIFT)
-#define FRAG_HASH_SEGS ((sizeof(u32) * 8) / FRAG_HASH_SHIFT)
-
-#define CLEAN_PERCPU_INTERVAL (30 * HZ)
-
-struct pkt_key {
- __be32 saddr;
- __be32 daddr;
- __be32 pkt_seq;
- u32 mark;
-};
-
-struct pkt_frag {
- struct sk_buff *skbs;
- unsigned long timestamp;
- struct list_head lru_node;
- struct pkt_key key;
-};
-
-struct stt_percpu {
- struct pkt_frag *frag_hash;
- struct list_head frag_lru;
- unsigned int frag_mem_used;
-
- /* Protect frags table. */
- spinlock_t lock;
-};
-
-struct first_frag {
- struct sk_buff *last_skb;
- unsigned int mem_used;
- u16 tot_len;
- u16 rcvd_len;
- bool set_ecn_ce;
-};
-
-struct frag_skb_cb {
- u16 offset;
-
- /* Only valid for the first skb in the chain. */
- struct first_frag first;
-};
-
-#define FRAG_CB(skb) ((struct frag_skb_cb *)(skb)->cb)
-
-/* per-network namespace private data for this module */
-struct stt_net {
- struct list_head stt_list;
- struct list_head stt_up_list; /* Devices which are in IFF_UP state. */
- int n_tunnels;
-#ifdef HAVE_NF_REGISTER_NET_HOOK
- bool nf_hook_reg_done;
-#endif
-};
-
-static int stt_net_id;
-
-static struct stt_percpu __percpu *stt_percpu_data __read_mostly;
-static u32 frag_hash_seed __read_mostly;
-
-/* Protects sock-hash and refcounts. */
-static DEFINE_MUTEX(stt_mutex);
-
-static int n_tunnels;
-static DEFINE_PER_CPU(u32, pkt_seq_counter);
-
-static void clean_percpu(struct work_struct *work);
-static DECLARE_DELAYED_WORK(clean_percpu_wq, clean_percpu);
-
-static struct stt_dev *stt_find_up_dev(struct net *net, __be16 port)
-{
- struct stt_net *sn = net_generic(net, stt_net_id);
- struct stt_dev *stt_dev;
-
- list_for_each_entry_rcu(stt_dev, &sn->stt_up_list, up_next) {
- if (stt_dev->dst_port == port)
- return stt_dev;
- }
- return NULL;
-}
-
-static __be32 ack_seq(void)
-{
-#if NR_CPUS <= 65536
- u32 pkt_seq, ack;
-
- pkt_seq = this_cpu_read(pkt_seq_counter);
- ack = pkt_seq << ilog2(NR_CPUS) | smp_processor_id();
- this_cpu_inc(pkt_seq_counter);
-
- return (__force __be32)ack;
-#else
-#error "Support for greater than 64k CPUs not implemented"
-#endif
-}
-
-static int clear_gso(struct sk_buff *skb)
-{
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- int err;
-
- if (shinfo->gso_type == 0 && shinfo->gso_size == 0 &&
- shinfo->gso_segs == 0)
- return 0;
-
- err = skb_unclone(skb, GFP_ATOMIC);
- if (unlikely(err))
- return err;
-
- shinfo = skb_shinfo(skb);
- shinfo->gso_type = 0;
- shinfo->gso_size = 0;
- shinfo->gso_segs = 0;
- return 0;
-}
-
-static void copy_skb_metadata(struct sk_buff *to, struct sk_buff *from)
-{
- to->protocol = from->protocol;
- to->tstamp = from->tstamp;
- to->priority = from->priority;
- to->mark = from->mark;
- to->vlan_tci = from->vlan_tci;
- to->vlan_proto = from->vlan_proto;
- skb_copy_secmark(to, from);
-}
-
-static void update_headers(struct sk_buff *skb, bool head,
- unsigned int l4_offset, unsigned int hdr_len,
- bool ipv4, u32 tcp_seq)
-{
- u16 old_len, new_len;
- __be32 delta;
- struct tcphdr *tcph;
- int gso_size;
-
- if (ipv4) {
- struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
-
- old_len = ntohs(iph->tot_len);
- new_len = skb->len - ETH_HLEN;
- iph->tot_len = htons(new_len);
-
- ip_send_check(iph);
- } else {
- struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + ETH_HLEN);
-
- old_len = ntohs(ip6h->payload_len);
- new_len = skb->len - ETH_HLEN - sizeof(struct ipv6hdr);
- ip6h->payload_len = htons(new_len);
- }
-
- tcph = (struct tcphdr *)(skb->data + l4_offset);
- if (!head) {
- tcph->seq = htonl(tcp_seq);
- tcph->cwr = 0;
- }
-
- if (skb->next) {
- tcph->fin = 0;
- tcph->psh = 0;
- }
-
- delta = htonl(~old_len + new_len);
- tcph->check = ~csum_fold((__force __wsum)((__force u32)tcph->check +
- (__force u32)delta));
-
- gso_size = skb_shinfo(skb)->gso_size;
- if (gso_size && skb->len - hdr_len <= gso_size)
- BUG_ON(clear_gso(skb));
-}
-
-static bool can_segment(struct sk_buff *head, bool ipv4, bool tcp, bool csum_partial)
-{
- /* If no offloading is in use then we don't have enough information
- * to process the headers.
- */
- if (!csum_partial)
- goto linearize;
-
- /* Handling UDP packets requires IP fragmentation, which means that
- * the L4 checksum can no longer be calculated by hardware (since the
- * fragments are in different packets. If we have to compute the
- * checksum it's faster just to linearize and large UDP packets are
- * pretty uncommon anyways, so it's not worth dealing with for now.
- */
- if (!tcp)
- goto linearize;
-
- if (ipv4) {
- struct iphdr *iph = (struct iphdr *)(head->data + ETH_HLEN);
-
- /* It's difficult to get the IP IDs exactly right here due to
- * varying segment sizes and potentially multiple layers of
- * segmentation. IP ID isn't important when DF is set and DF
- * is generally set for TCP packets, so just linearize if it's
- * not.
- */
- if (!(iph->frag_off & htons(IP_DF)))
- goto linearize;
- } else {
- struct ipv6hdr *ip6h = (struct ipv6hdr *)(head->data + ETH_HLEN);
-
- /* Jumbograms require more processing to update and we'll
- * probably never see them, so just linearize.
- */
- if (ip6h->payload_len == 0)
- goto linearize;
- }
- return true;
-
-linearize:
- return false;
-}
-
-static int copy_headers(struct sk_buff *head, struct sk_buff *frag,
- int hdr_len)
-{
- u16 csum_start;
-
- if (skb_cloned(frag) || skb_headroom(frag) < hdr_len) {
- int extra_head = hdr_len - skb_headroom(frag);
-
- extra_head = extra_head > 0 ? extra_head : 0;
- if (unlikely(pskb_expand_head(frag, extra_head, 0,
- GFP_ATOMIC)))
- return -ENOMEM;
- }
-
- memcpy(__skb_push(frag, hdr_len), head->data, hdr_len);
-
- csum_start = head->csum_start - skb_headroom(head);
- frag->csum_start = skb_headroom(frag) + csum_start;
- frag->csum_offset = head->csum_offset;
- frag->ip_summed = head->ip_summed;
-
- skb_shinfo(frag)->gso_size = skb_shinfo(head)->gso_size;
- skb_shinfo(frag)->gso_type = skb_shinfo(head)->gso_type;
- skb_shinfo(frag)->gso_segs = 0;
-
- copy_skb_metadata(frag, head);
- return 0;
-}
-
-static int skb_list_segment(struct sk_buff *head, bool ipv4, int l4_offset)
-{
- struct sk_buff *skb;
- struct tcphdr *tcph;
- int seg_len;
- int hdr_len;
- int tcp_len;
- u32 seq;
-
- if (unlikely(!pskb_may_pull(head, l4_offset + sizeof(*tcph))))
- return -ENOMEM;
-
- tcph = (struct tcphdr *)(head->data + l4_offset);
- tcp_len = tcph->doff * 4;
- hdr_len = l4_offset + tcp_len;
-
- if (unlikely((tcp_len < sizeof(struct tcphdr)) ||
- (head->len < hdr_len)))
- return -EINVAL;
-
- if (unlikely(!pskb_may_pull(head, hdr_len)))
- return -ENOMEM;
-
- tcph = (struct tcphdr *)(head->data + l4_offset);
- /* Update header of each segment. */
- seq = ntohl(tcph->seq);
- seg_len = skb_pagelen(head) - hdr_len;
-
- skb = skb_shinfo(head)->frag_list;
- skb_shinfo(head)->frag_list = NULL;
- head->next = skb;
- for (; skb; skb = skb->next) {
- int err;
-
- head->len -= skb->len;
- head->data_len -= skb->len;
- head->truesize -= skb->truesize;
-
- seq += seg_len;
- seg_len = skb->len;
- err = copy_headers(head, skb, hdr_len);
- if (err)
- return err;
- update_headers(skb, false, l4_offset, hdr_len, ipv4, seq);
- }
- update_headers(head, true, l4_offset, hdr_len, ipv4, 0);
- return 0;
-}
-
-#ifndef SKIP_ZERO_COPY
-static struct sk_buff *normalize_frag_list(struct sk_buff *head,
- struct sk_buff **skbp)
-{
- struct sk_buff *skb = *skbp;
- struct sk_buff *last;
-
- do {
- struct sk_buff *frags;
-
- if (skb_shared(skb)) {
- struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
-
- if (unlikely(!nskb))
- return ERR_PTR(-ENOMEM);
-
- nskb->next = skb->next;
- consume_skb(skb);
- skb = nskb;
- *skbp = skb;
- }
-
- if (head) {
- head->len -= skb->len;
- head->data_len -= skb->len;
- head->truesize -= skb->truesize;
- }
-
- frags = skb_shinfo(skb)->frag_list;
- if (frags) {
- int err;
-
- err = skb_unclone(skb, GFP_ATOMIC);
- if (unlikely(err))
- return ERR_PTR(err);
-
- last = normalize_frag_list(skb, &frags);
- if (IS_ERR(last))
- return last;
-
- skb_shinfo(skb)->frag_list = NULL;
- last->next = skb->next;
- skb->next = frags;
- } else {
- last = skb;
- }
-
- skbp = &skb->next;
- } while ((skb = skb->next));
-
- return last;
-}
-
-/* Takes a linked list of skbs, which potentially contain frag_list
- * (whose members in turn potentially contain frag_lists, etc.) and
- * converts them into a single linear linked list.
- */
-static int straighten_frag_list(struct sk_buff **skbp)
-{
- struct sk_buff *err_skb;
-
- err_skb = normalize_frag_list(NULL, skbp);
- if (IS_ERR(err_skb))
- return PTR_ERR(err_skb);
-
- return 0;
-}
-
-static int coalesce_skb(struct sk_buff **headp)
-{
- struct sk_buff *frag, *head, *prev;
- int err;
-
- err = straighten_frag_list(headp);
- if (unlikely(err))
- return err;
- head = *headp;
-
- /* Coalesce frag list. */
- prev = head;
- for (frag = head->next; frag; frag = frag->next) {
- bool headstolen;
- int delta;
-
- if (unlikely(skb_unclone(prev, GFP_ATOMIC)))
- return -ENOMEM;
-
- if (!skb_try_coalesce(prev, frag, &headstolen, &delta)) {
- prev = frag;
- continue;
- }
-
- prev->next = frag->next;
- frag->len = 0;
- frag->data_len = 0;
- frag->truesize -= delta;
- kfree_skb_partial(frag, headstolen);
- frag = prev;
- }
-
- if (!head->next)
- return 0;
-
- for (frag = head->next; frag; frag = frag->next) {
- head->len += frag->len;
- head->data_len += frag->len;
- head->truesize += frag->truesize;
- }
-
- skb_shinfo(head)->frag_list = head->next;
- head->next = NULL;
- return 0;
-}
-#else
-static int coalesce_skb(struct sk_buff **headp)
-{
- struct sk_buff *frag, *head = *headp, *next;
- int delta = FRAG_CB(head)->first.tot_len - skb_headlen(head);
- int err;
-
- if (unlikely(!head->next))
- return 0;
-
- err = pskb_expand_head(head, 0, delta, GFP_ATOMIC);
- if (unlikely(err))
- return err;
-
- if (unlikely(!__pskb_pull_tail(head, head->data_len)))
- BUG();
-
- for (frag = head->next; frag; frag = next) {
- skb_copy_bits(frag, 0, skb_put(head, frag->len), frag->len);
- next = frag->next;
- kfree_skb(frag);
- }
-
- head->next = NULL;
- head->truesize = SKB_TRUESIZE(head->len);
- return 0;
-}
-#endif
-
-static int __try_to_segment(struct sk_buff *skb, bool csum_partial,
- bool ipv4, bool tcp, int l4_offset)
-{
- if (can_segment(skb, ipv4, tcp, csum_partial))
- return skb_list_segment(skb, ipv4, l4_offset);
- else
- return skb_linearize(skb);
-}
-
-static int try_to_segment(struct sk_buff *skb)
-{
- struct stthdr *stth = stt_hdr(skb);
- bool csum_partial = !!(stth->flags & STT_CSUM_PARTIAL);
- bool ipv4 = !!(stth->flags & STT_PROTO_IPV4);
- bool tcp = !!(stth->flags & STT_PROTO_TCP);
- int l4_offset = stth->l4_offset;
-
- return __try_to_segment(skb, csum_partial, ipv4, tcp, l4_offset);
-}
-
-static int segment_skb(struct sk_buff **headp, bool csum_partial,
- bool ipv4, bool tcp, int l4_offset)
-{
-#ifndef SKIP_ZERO_COPY
- int err;
-
- err = coalesce_skb(headp);
- if (err)
- return err;
-#endif
-
- if (skb_shinfo(*headp)->frag_list)
- return __try_to_segment(*headp, csum_partial,
- ipv4, tcp, l4_offset);
- return 0;
-}
-
-static int __push_stt_header(struct sk_buff *skb, __be64 tun_id,
- __be16 s_port, __be16 d_port,
- __be32 saddr, __be32 dst,
- __be16 l3_proto, u8 l4_proto,
- int dst_mtu)
-{
- int data_len = skb->len + sizeof(struct stthdr) + STT_ETH_PAD;
- unsigned short encap_mss;
- struct tcphdr *tcph;
- struct stthdr *stth;
-
- skb_push(skb, STT_HEADER_LEN);
- skb_reset_transport_header(skb);
- tcph = tcp_hdr(skb);
- memset(tcph, 0, STT_HEADER_LEN);
- stth = stt_hdr(skb);
-
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- stth->flags |= STT_CSUM_PARTIAL;
-
- stth->l4_offset = skb->csum_start -
- (skb_headroom(skb) +
- STT_HEADER_LEN);
-
- if (l3_proto == htons(ETH_P_IP))
- stth->flags |= STT_PROTO_IPV4;
-
- if (l4_proto == IPPROTO_TCP)
- stth->flags |= STT_PROTO_TCP;
-
- stth->mss = htons(skb_shinfo(skb)->gso_size);
- } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
- stth->flags |= STT_CSUM_VERIFIED;
- }
-
- stth->vlan_tci = htons(skb->vlan_tci);
- skb->vlan_tci = 0;
- put_unaligned(tun_id, &stth->key);
-
- tcph->source = s_port;
- tcph->dest = d_port;
- tcph->doff = sizeof(struct tcphdr) / 4;
- tcph->ack = 1;
- tcph->psh = 1;
- tcph->window = htons(USHRT_MAX);
- tcph->seq = htonl(data_len << STT_SEQ_LEN_SHIFT);
- tcph->ack_seq = ack_seq();
- tcph->check = ~tcp_v4_check(skb->len, saddr, dst, 0);
-
- skb->csum_start = skb_transport_header(skb) - skb->head;
- skb->csum_offset = offsetof(struct tcphdr, check);
- skb->ip_summed = CHECKSUM_PARTIAL;
-
- encap_mss = dst_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
- if (data_len > encap_mss) {
- if (unlikely(skb_unclone(skb, GFP_ATOMIC)))
- return -EINVAL;
-
- skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
- skb_shinfo(skb)->gso_size = encap_mss;
- skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(data_len, encap_mss);
- } else {
- if (unlikely(clear_gso(skb)))
- return -EINVAL;
- }
- return 0;
-}
-
-static struct sk_buff *push_stt_header(struct sk_buff *head, __be64 tun_id,
- __be16 s_port, __be16 d_port,
- __be32 saddr, __be32 dst,
- __be16 l3_proto, u8 l4_proto,
- int dst_mtu)
-{
- struct sk_buff *skb;
-
- if (skb_shinfo(head)->frag_list) {
- bool ipv4 = (l3_proto == htons(ETH_P_IP));
- bool tcp = (l4_proto == IPPROTO_TCP);
- bool csum_partial = (head->ip_summed == CHECKSUM_PARTIAL);
- int l4_offset = skb_transport_offset(head);
-
- /* Need to call skb_orphan() to report currect true-size.
- * calling skb_orphan() in this layer is odd but SKB with
- * frag-list should not be associated with any socket, so
- * skb-orphan should be no-op. */
- skb_orphan(head);
- if (unlikely(segment_skb(&head, csum_partial,
- ipv4, tcp, l4_offset)))
- goto error;
- }
-
- for (skb = head; skb; skb = skb->next) {
- if (__push_stt_header(skb, tun_id, s_port, d_port, saddr, dst,
- l3_proto, l4_proto, dst_mtu))
- goto error;
- }
-
- return head;
-error:
- kfree_skb_list(head);
- return NULL;
-}
-
-static int stt_can_offload(struct sk_buff *skb, __be16 l3_proto, u8 l4_proto)
-{
- if (skb_is_gso(skb) && skb->ip_summed != CHECKSUM_PARTIAL) {
- int csum_offset;
- __sum16 *csum;
- int len;
-
- if (l4_proto == IPPROTO_TCP)
- csum_offset = offsetof(struct tcphdr, check);
- else if (l4_proto == IPPROTO_UDP)
- csum_offset = offsetof(struct udphdr, check);
- else
- return 0;
-
- len = skb->len - skb_transport_offset(skb);
- csum = (__sum16 *)(skb_transport_header(skb) + csum_offset);
-
- if (unlikely(!pskb_may_pull(skb, skb_transport_offset(skb) +
- csum_offset + sizeof(*csum))))
- return -EINVAL;
-
- if (l3_proto == htons(ETH_P_IP)) {
- struct iphdr *iph = ip_hdr(skb);
-
- *csum = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- len, l4_proto, 0);
- } else if (l3_proto == htons(ETH_P_IPV6)) {
- struct ipv6hdr *ip6h = ipv6_hdr(skb);
-
- *csum = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
- len, l4_proto, 0);
- } else {
- return 0;
- }
- skb->csum_start = skb_transport_header(skb) - skb->head;
- skb->csum_offset = csum_offset;
- skb->ip_summed = CHECKSUM_PARTIAL;
- }
-
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- /* Assume receiver can only offload TCP/UDP over IPv4/6,
- * and require 802.1Q VLANs to be accelerated.
- */
- if (l3_proto != htons(ETH_P_IP) &&
- l3_proto != htons(ETH_P_IPV6))
- return 0;
-
- if (l4_proto != IPPROTO_TCP && l4_proto != IPPROTO_UDP)
- return 0;
-
- /* L4 offset must fit in a 1-byte field. */
- if (skb->csum_start - skb_headroom(skb) > 255)
- return 0;
-
- if (skb_shinfo(skb)->gso_type & ~SUPPORTED_GSO_TYPES)
- return 0;
- }
- /* Total size of encapsulated packet must fit in 16 bits. */
- if (skb->len + STT_HEADER_LEN + sizeof(struct iphdr) > 65535)
- return 0;
-
- if (skb_vlan_tag_present(skb) && skb->vlan_proto != htons(ETH_P_8021Q))
- return 0;
- return 1;
-}
-
-static bool need_linearize(const struct sk_buff *skb)
-{
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- int i;
-
- if (unlikely(shinfo->frag_list))
- return true;
-
- /* Generally speaking we should linearize if there are paged frags.
- * However, if all of the refcounts are 1 we know nobody else can
- * change them from underneath us and we can skip the linearization.
- */
- for (i = 0; i < shinfo->nr_frags; i++)
- if (unlikely(page_count(skb_frag_page(&shinfo->frags[i])) > 1))
- return true;
-
- return false;
-}
-
-static struct sk_buff *handle_offloads(struct sk_buff *skb, int min_headroom)
-{
- int err;
-
- if (skb_vlan_tag_present(skb) && skb->vlan_proto != htons(ETH_P_8021Q)) {
-
- min_headroom += VLAN_HLEN;
- if (skb_headroom(skb) < min_headroom) {
- int head_delta = SKB_DATA_ALIGN(min_headroom -
- skb_headroom(skb) + 16);
-
- err = pskb_expand_head(skb, max_t(int, head_delta, 0),
- 0, GFP_ATOMIC);
- if (unlikely(err))
- goto error;
- }
-
- skb = __vlan_hwaccel_push_inside(skb);
- if (!skb) {
- err = -ENOMEM;
- goto error;
- }
- }
-
- if (skb_is_gso(skb)) {
- struct sk_buff *nskb;
- char cb[sizeof(skb->cb)];
-
- memcpy(cb, skb->cb, sizeof(cb));
-
- nskb = __skb_gso_segment(skb, 0, false);
- if (IS_ERR(nskb)) {
- err = PTR_ERR(nskb);
- goto error;
- }
-
- consume_skb(skb);
- skb = nskb;
- while (nskb) {
- memcpy(nskb->cb, cb, sizeof(cb));
- nskb = nskb->next;
- }
- } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- /* Pages aren't locked and could change at any time.
- * If this happens after we compute the checksum, the
- * checksum will be wrong. We linearize now to avoid
- * this problem.
- */
- if (unlikely(need_linearize(skb))) {
- err = __skb_linearize(skb);
- if (unlikely(err))
- goto error;
- }
-
- err = skb_checksum_help(skb);
- if (unlikely(err))
- goto error;
- }
- skb->ip_summed = CHECKSUM_NONE;
-
- return skb;
-error:
- kfree_skb(skb);
- return ERR_PTR(err);
-}
-
-static void skb_list_xmit(struct rtable *rt, struct sk_buff *skb, __be32 src,
- __be32 dst, __u8 tos, __u8 ttl, __be16 df)
-{
- while (skb) {
- struct sk_buff *next = skb->next;
-
- if (next)
- dst_clone(&rt->dst);
-
- skb->next = NULL;
- iptunnel_xmit(NULL, rt, skb, src, dst, IPPROTO_TCP,
- tos, ttl, df, false);
-
- skb = next;
- }
-}
-
-static u8 parse_ipv6_l4_proto(struct sk_buff *skb)
-{
- unsigned int nh_ofs = skb_network_offset(skb);
- int payload_ofs;
- struct ipv6hdr *nh;
- uint8_t nexthdr;
- __be16 frag_off;
-
- if (unlikely(!pskb_may_pull(skb, nh_ofs + sizeof(struct ipv6hdr))))
- return 0;
-
- nh = ipv6_hdr(skb);
- nexthdr = nh->nexthdr;
- payload_ofs = (u8 *)(nh + 1) - skb->data;
-
- payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off);
- if (unlikely(payload_ofs < 0))
- return 0;
-
- return nexthdr;
-}
-
-static u8 skb_get_l4_proto(struct sk_buff *skb, __be16 l3_proto)
-{
- if (l3_proto == htons(ETH_P_IP)) {
- unsigned int nh_ofs = skb_network_offset(skb);
-
- if (unlikely(!pskb_may_pull(skb, nh_ofs + sizeof(struct iphdr))))
- return 0;
-
- return ip_hdr(skb)->protocol;
- } else if (l3_proto == htons(ETH_P_IPV6)) {
- return parse_ipv6_l4_proto(skb);
- }
- return 0;
-}
-
-static int stt_xmit_skb(struct sk_buff *skb, struct rtable *rt,
- __be32 src, __be32 dst, __u8 tos,
- __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port,
- __be64 tun_id)
-{
- struct ethhdr *eh = eth_hdr(skb);
- int ret = 0, min_headroom;
- __be16 inner_l3_proto;
- u8 inner_l4_proto;
-
- inner_l3_proto = eh->h_proto;
- inner_l4_proto = skb_get_l4_proto(skb, inner_l3_proto);
-
- min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
- + STT_HEADER_LEN + sizeof(struct iphdr);
-
- if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
- int head_delta = SKB_DATA_ALIGN(min_headroom -
- skb_headroom(skb) +
- 16);
-
- ret = pskb_expand_head(skb, max_t(int, head_delta, 0),
- 0, GFP_ATOMIC);
- if (unlikely(ret))
- goto err_free_rt;
- }
-
- ret = stt_can_offload(skb, inner_l3_proto, inner_l4_proto);
- if (ret < 0)
- goto err_free_rt;
- if (!ret) {
- skb = handle_offloads(skb, min_headroom);
- if (IS_ERR(skb)) {
- ret = PTR_ERR(skb);
- skb = NULL;
- goto err_free_rt;
- }
- }
-
- ret = 0;
- while (skb) {
- struct sk_buff *next_skb = skb->next;
-
- skb->next = NULL;
-
- if (next_skb)
- dst_clone(&rt->dst);
-
- /* Push STT and TCP header. */
- skb = push_stt_header(skb, tun_id, src_port, dst_port, src,
- dst, inner_l3_proto, inner_l4_proto,
- dst_mtu(&rt->dst));
- if (unlikely(!skb)) {
- ip_rt_put(rt);
- goto next;
- }
-
- /* Push IP header. */
- skb_list_xmit(rt, skb, src, dst, tos, ttl, df);
-
-next:
- skb = next_skb;
- }
-
- return 0;
-
-err_free_rt:
- ip_rt_put(rt);
- kfree_skb(skb);
- return ret;
-}
-
-static struct rtable *stt_get_rt(struct sk_buff *skb,
- struct net_device *dev,
- struct flowi4 *fl,
- const struct ip_tunnel_key *key,
- __be16 dport, __be16 sport)
-{
- struct net *net = dev_net(dev);
-
- /* Route lookup */
- memset(fl, 0, sizeof(*fl));
- fl->daddr = key->u.ipv4.dst;
- fl->saddr = key->u.ipv4.src;
- fl->flowi4_tos = RT_TOS(key->tos);
- fl->flowi4_mark = skb->mark;
- fl->flowi4_proto = IPPROTO_TCP;
- fl->fl4_dport = dport;
- fl->fl4_sport = sport;
-
- return ip_route_output_key(net, fl);
-}
-
-netdev_tx_t ovs_stt_xmit(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- struct stt_dev *stt_dev = netdev_priv(dev);
- struct net *net = stt_dev->net;
- __be16 dport = stt_dev->dst_port;
- struct ip_tunnel_key *tun_key;
- struct ip_tunnel_info *tun_info;
- struct rtable *rt;
- struct flowi4 fl;
- __be16 sport;
- __be16 df;
- int err;
-
- tun_info = skb_tunnel_info(skb);
- if (unlikely(!tun_info)) {
- err = -EINVAL;
- goto error;
- }
-
- tun_key = &tun_info->key;
-
- sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);
- rt = stt_get_rt(skb, dev, &fl, tun_key, dport, sport);
- if (IS_ERR(rt)) {
- err = PTR_ERR(rt);
- goto error;
- }
-
- df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
- skb->ignore_df = 1;
-
- stt_xmit_skb(skb, rt, fl.saddr, tun_key->u.ipv4.dst,
- tun_key->tos, tun_key->ttl,
- df, sport, dport, tun_key->tun_id);
- return NETDEV_TX_OK;
-error:
- kfree_skb(skb);
- dev->stats.tx_errors++;
- return err;
-}
-EXPORT_SYMBOL(ovs_stt_xmit);
-
-static void free_frag(struct stt_percpu *stt_percpu,
- struct pkt_frag *frag)
-{
- stt_percpu->frag_mem_used -= FRAG_CB(frag->skbs)->first.mem_used;
- kfree_skb_list(frag->skbs);
- list_del(&frag->lru_node);
- frag->skbs = NULL;
-}
-
-static void evict_frags(struct stt_percpu *stt_percpu)
-{
- while (!list_empty(&stt_percpu->frag_lru) &&
- stt_percpu->frag_mem_used > REASM_LO_THRESH) {
- struct pkt_frag *frag;
-
- frag = list_first_entry(&stt_percpu->frag_lru,
- struct pkt_frag,
- lru_node);
- free_frag(stt_percpu, frag);
- }
-}
-
-static bool pkt_key_match(struct net *net,
- const struct pkt_frag *a, const struct pkt_key *b)
-{
- return a->key.saddr == b->saddr && a->key.daddr == b->daddr &&
- a->key.pkt_seq == b->pkt_seq && a->key.mark == b->mark &&
- net_eq(dev_net(a->skbs->dev), net);
-}
-
-static u32 pkt_key_hash(const struct net *net, const struct pkt_key *key)
-{
- u32 initval = frag_hash_seed ^ (u32)(unsigned long)net ^ key->mark;
-
- return jhash_3words((__force u32)key->saddr, (__force u32)key->daddr,
- (__force u32)key->pkt_seq, initval);
-}
-
-static struct pkt_frag *lookup_frag(struct net *net,
- struct stt_percpu *stt_percpu,
- const struct pkt_key *key, u32 hash)
-{
- struct pkt_frag *frag, *victim_frag = NULL;
- int i;
-
- for (i = 0; i < FRAG_HASH_SEGS; i++) {
- frag = &stt_percpu->frag_hash[hash & (FRAG_HASH_ENTRIES - 1)];
-
- if (frag->skbs &&
- time_before(jiffies, frag->timestamp + FRAG_EXP_TIME) &&
- pkt_key_match(net, frag, key))
- return frag;
-
- if (!victim_frag ||
- (victim_frag->skbs &&
- (!frag->skbs ||
- time_before(frag->timestamp, victim_frag->timestamp))))
- victim_frag = frag;
-
- hash >>= FRAG_HASH_SHIFT;
- }
-
- if (victim_frag->skbs)
- free_frag(stt_percpu, victim_frag);
-
- return victim_frag;
-}
-
-#ifdef SKIP_ZERO_COPY
-static int __copy_skb(struct sk_buff *to, struct sk_buff *from,
- int *delta, bool *headstolen)
-{
- int err;
-
- if (unlikely(to->next))
- return -EINVAL;
-
- if (unlikely(FRAG_CB(to)->offset))
- return -EINVAL;
-
- if (unlikely(skb_unclone(to, GFP_ATOMIC)))
- return -ENOMEM;
-
- if (skb_try_coalesce(to, from, headstolen, delta))
- return 0;
-
- *headstolen = false;
- err = pskb_expand_head(to, 0, to->data_len + from->len, GFP_ATOMIC);
- if (unlikely(err))
- return err;
-
- if (unlikely(!__pskb_pull_tail(to, to->data_len)))
- BUG();
-
- skb_copy_bits(from, 0, skb_put(to, from->len), from->len);
-
- *delta = from->len;
- to->truesize += from->len;
- return 0;
-}
-#else
-static int __copy_skb(struct sk_buff *to, struct sk_buff *from,
- int *delta, bool *headstolen)
-{
- *headstolen = false;
- return -EINVAL;
-}
-#endif
-
-static struct sk_buff *reassemble(struct sk_buff *skb)
-{
- struct iphdr *iph = ip_hdr(skb);
- struct tcphdr *tcph = tcp_hdr(skb);
- u32 seq = ntohl(tcph->seq);
- struct stt_percpu *stt_percpu;
- struct sk_buff *last_skb, *copied_skb = NULL;
- struct pkt_frag *frag;
- struct pkt_key key;
- int tot_len, delta = skb->truesize;
- bool headstolen;
- u32 hash;
-
- tot_len = seq >> STT_SEQ_LEN_SHIFT;
- FRAG_CB(skb)->offset = seq & STT_SEQ_OFFSET_MASK;
-
- if (unlikely(skb->len == 0))
- goto out_free;
-
- if (unlikely(FRAG_CB(skb)->offset + skb->len > tot_len))
- goto out_free;
-
- if (tot_len == skb->len)
- goto out;
-
- key.saddr = iph->saddr;
- key.daddr = iph->daddr;
- key.pkt_seq = tcph->ack_seq;
- key.mark = skb->mark;
- hash = pkt_key_hash(dev_net(skb->dev), &key);
-
- stt_percpu = per_cpu_ptr(stt_percpu_data, smp_processor_id());
-
- spin_lock(&stt_percpu->lock);
-
- if (unlikely(stt_percpu->frag_mem_used + skb->truesize > REASM_HI_THRESH))
- evict_frags(stt_percpu);
-
- frag = lookup_frag(dev_net(skb->dev), stt_percpu, &key, hash);
- if (!frag->skbs) {
- frag->skbs = skb;
- frag->key = key;
- frag->timestamp = jiffies;
- FRAG_CB(skb)->first.last_skb = skb;
- FRAG_CB(skb)->first.mem_used = skb->truesize;
- FRAG_CB(skb)->first.tot_len = tot_len;
- FRAG_CB(skb)->first.rcvd_len = skb->len;
- FRAG_CB(skb)->first.set_ecn_ce = false;
- list_add_tail(&frag->lru_node, &stt_percpu->frag_lru);
- stt_percpu->frag_mem_used += skb->truesize;
- skb = NULL;
- goto unlock;
- }
-
- /* Optimize for the common case where fragments are received in-order
- * and not overlapping.
- */
- last_skb = FRAG_CB(frag->skbs)->first.last_skb;
- if (likely(FRAG_CB(last_skb)->offset + last_skb->len ==
- FRAG_CB(skb)->offset)) {
-
- if (!__copy_skb(frag->skbs, skb, &delta, &headstolen)) {
- copied_skb = skb;
- } else {
- last_skb->next = skb;
- FRAG_CB(frag->skbs)->first.last_skb = skb;
- }
- } else {
- struct sk_buff *prev = NULL, *next;
-
- for (next = frag->skbs; next; next = next->next) {
- if (FRAG_CB(next)->offset >= FRAG_CB(skb)->offset)
- break;
- prev = next;
- }
-
- /* Overlapping fragments aren't allowed. We shouldn't start
- * before the end of the previous fragment.
- */
- if (prev &&
- FRAG_CB(prev)->offset + prev->len > FRAG_CB(skb)->offset)
- goto unlock_free;
-
- /* We also shouldn't end after the beginning of the next
- * fragment.
- */
- if (next &&
- FRAG_CB(skb)->offset + skb->len > FRAG_CB(next)->offset)
- goto unlock_free;
-
- if (prev) {
- prev->next = skb;
- } else {
- FRAG_CB(skb)->first = FRAG_CB(frag->skbs)->first;
- frag->skbs = skb;
- }
-
- if (next)
- skb->next = next;
- else
- FRAG_CB(frag->skbs)->first.last_skb = skb;
- }
-
- FRAG_CB(frag->skbs)->first.set_ecn_ce |= INET_ECN_is_ce(iph->tos);
- FRAG_CB(frag->skbs)->first.rcvd_len += skb->len;
- stt_percpu->frag_mem_used += delta;
- FRAG_CB(frag->skbs)->first.mem_used += delta;
-
- if (FRAG_CB(frag->skbs)->first.tot_len ==
- FRAG_CB(frag->skbs)->first.rcvd_len) {
- struct sk_buff *frag_head = frag->skbs;
-
- frag_head->tstamp = skb->tstamp;
- if (FRAG_CB(frag_head)->first.set_ecn_ce)
- INET_ECN_set_ce(frag_head);
-
- list_del(&frag->lru_node);
- stt_percpu->frag_mem_used -= FRAG_CB(frag_head)->first.mem_used;
- frag->skbs = NULL;
- skb = frag_head;
- } else {
- list_move_tail(&frag->lru_node, &stt_percpu->frag_lru);
- skb = NULL;
- }
-
- if (copied_skb)
- kfree_skb_partial(copied_skb, headstolen);
- goto unlock;
-
-unlock_free:
- kfree_skb(skb);
- skb = NULL;
-unlock:
- spin_unlock(&stt_percpu->lock);
- return skb;
-out_free:
- kfree_skb(skb);
- skb = NULL;
-out:
- return skb;
-}
-
-static bool validate_checksum(struct sk_buff *skb)
-{
- struct iphdr *iph = ip_hdr(skb);
-
- if (skb_csum_unnecessary(skb))
- return true;
-
- if (skb->ip_summed == CHECKSUM_COMPLETE &&
- !tcp_v4_check(skb->len, iph->saddr, iph->daddr, skb->csum))
- return true;
-
- skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, skb->len,
- IPPROTO_TCP, 0);
-
- return __skb_checksum_complete(skb) == 0;
-}
-
-static bool set_offloads(struct sk_buff *skb)
-{
- struct stthdr *stth = stt_hdr(skb);
- unsigned int gso_type = 0;
- int l3_header_size;
- int l4_header_size;
- u16 csum_offset;
- u8 proto_type;
-
- if (stth->vlan_tci)
- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
- ntohs(stth->vlan_tci));
-
- if (!(stth->flags & STT_CSUM_PARTIAL)) {
- if (stth->flags & STT_CSUM_VERIFIED)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
- skb->ip_summed = CHECKSUM_NONE;
-
- return clear_gso(skb) == 0;
- }
-
- proto_type = stth->flags & STT_PROTO_TYPES;
-
- switch (proto_type) {
- case (STT_PROTO_IPV4 | STT_PROTO_TCP):
- /* TCP/IPv4 */
- csum_offset = offsetof(struct tcphdr, check);
- gso_type = SKB_GSO_TCPV4;
- l3_header_size = sizeof(struct iphdr);
- l4_header_size = sizeof(struct tcphdr);
- skb->protocol = htons(ETH_P_IP);
- break;
- case STT_PROTO_TCP:
- /* TCP/IPv6 */
- csum_offset = offsetof(struct tcphdr, check);
- gso_type = SKB_GSO_TCPV6;
- l3_header_size = sizeof(struct ipv6hdr);
- l4_header_size = sizeof(struct tcphdr);
- skb->protocol = htons(ETH_P_IPV6);
- break;
- case STT_PROTO_IPV4:
- /* UDP/IPv4 */
- csum_offset = offsetof(struct udphdr, check);
-#ifdef HAVE_SKB_GSO_UDP
- gso_type = SKB_GSO_UDP;
-#endif
- l3_header_size = sizeof(struct iphdr);
- l4_header_size = sizeof(struct udphdr);
- skb->protocol = htons(ETH_P_IP);
- break;
- default:
- /* UDP/IPv6 */
- csum_offset = offsetof(struct udphdr, check);
-#ifdef HAVE_SKB_GSO_UDP
- gso_type = SKB_GSO_UDP;
-#endif
- l3_header_size = sizeof(struct ipv6hdr);
- l4_header_size = sizeof(struct udphdr);
- skb->protocol = htons(ETH_P_IPV6);
- }
-
- if (unlikely(stth->l4_offset < ETH_HLEN + l3_header_size))
- return false;
-
- if (unlikely(!pskb_may_pull(skb, stth->l4_offset + l4_header_size)))
- return false;
-
- stth = stt_hdr(skb);
-
- skb->csum_start = skb_headroom(skb) + stth->l4_offset;
- skb->csum_offset = csum_offset;
- skb->ip_summed = CHECKSUM_PARTIAL;
-
- if (stth->mss) {
- if (unlikely(skb_unclone(skb, GFP_ATOMIC)))
- return false;
-
- skb_shinfo(skb)->gso_type = gso_type | SKB_GSO_DODGY;
- skb_shinfo(skb)->gso_size = ntohs(stth->mss);
- skb_shinfo(skb)->gso_segs = 0;
- } else {
- if (unlikely(clear_gso(skb)))
- return false;
- }
-
- return true;
-}
-
-static void rcv_list(struct net_device *dev, struct sk_buff *skb,
- struct metadata_dst *tun_dst)
-{
- struct sk_buff *next;
-
- do {
- next = skb->next;
- skb->next = NULL;
- if (next) {
- ovs_dst_hold((struct dst_entry *)tun_dst);
- ovs_skb_dst_set(next, (struct dst_entry *)tun_dst);
- }
- ovs_ip_tunnel_rcv(dev, skb, tun_dst);
- } while ((skb = next));
-}
-
-#ifndef USE_UPSTREAM_TUNNEL
-static int __stt_rcv(struct stt_dev *stt_dev, struct sk_buff *skb)
-{
- struct metadata_dst tun_dst;
-
- ovs_ip_tun_rx_dst(&tun_dst, skb, TUNNEL_KEY | TUNNEL_CSUM,
- get_unaligned(&stt_hdr(skb)->key), 0);
- tun_dst.u.tun_info.key.tp_src = tcp_hdr(skb)->source;
- tun_dst.u.tun_info.key.tp_dst = tcp_hdr(skb)->dest;
-
- rcv_list(stt_dev->dev, skb, &tun_dst);
- return 0;
-}
-#else
-static int __stt_rcv(struct stt_dev *stt_dev, struct sk_buff *skb)
-{
- struct metadata_dst *tun_dst;
- __be16 flags;
- __be64 tun_id;
-
- flags = TUNNEL_KEY | TUNNEL_CSUM;
- tun_id = get_unaligned(&stt_hdr(skb)->key);
- tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0);
- if (!tun_dst)
- return -ENOMEM;
- tun_dst->u.tun_info.key.tp_src = tcp_hdr(skb)->source;
- tun_dst->u.tun_info.key.tp_dst = tcp_hdr(skb)->dest;
-
- rcv_list(stt_dev->dev, skb, tun_dst);
- return 0;
-}
-#endif
-
-static void stt_rcv(struct stt_dev *stt_dev, struct sk_buff *skb)
-{
- int err;
-
- if (unlikely(!validate_checksum(skb)))
- goto drop;
-
- __skb_pull(skb, sizeof(struct tcphdr));
- skb = reassemble(skb);
- if (!skb)
- return;
-
- if (skb->next && coalesce_skb(&skb))
- goto drop;
-
- err = iptunnel_pull_header(skb,
- sizeof(struct stthdr) + STT_ETH_PAD,
- htons(ETH_P_TEB),
- !net_eq(stt_dev->net, dev_net(stt_dev->dev)));
- if (unlikely(err))
- goto drop;
-
- if (unlikely(stt_hdr(skb)->version != 0))
- goto drop;
-
- if (unlikely(!set_offloads(skb)))
- goto drop;
-
- if (skb_shinfo(skb)->frag_list && try_to_segment(skb))
- goto drop;
-
- err = __stt_rcv(stt_dev, skb);
- if (err)
- goto drop;
- return;
-drop:
- /* Consume bad packet */
- kfree_skb_list(skb);
- stt_dev->dev->stats.rx_errors++;
-}
-
-static void tcp_sock_release(struct socket *sock)
-{
- kernel_sock_shutdown(sock, SHUT_RDWR);
- sock_release(sock);
-}
-
-static int tcp_sock_create4(struct net *net, __be16 port,
- struct socket **sockp)
-{
- struct sockaddr_in tcp_addr;
- struct socket *sock = NULL;
- int err;
-
- err = sock_create_kern(net, AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
- if (err < 0)
- goto error;
-
- memset(&tcp_addr, 0, sizeof(tcp_addr));
- tcp_addr.sin_family = AF_INET;
- tcp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- tcp_addr.sin_port = port;
- err = kernel_bind(sock, (struct sockaddr *)&tcp_addr,
- sizeof(tcp_addr));
- if (err < 0)
- goto error;
-
- *sockp = sock;
- return 0;
-
-error:
- if (sock)
- tcp_sock_release(sock);
- *sockp = NULL;
- return err;
-}
-
-static void schedule_clean_percpu(void)
-{
- schedule_delayed_work(&clean_percpu_wq, CLEAN_PERCPU_INTERVAL);
-}
-
-static void clean_percpu(struct work_struct *work)
-{
- int i;
-
- for_each_possible_cpu(i) {
- struct stt_percpu *stt_percpu = per_cpu_ptr(stt_percpu_data, i);
- int j;
-
- for (j = 0; j < FRAG_HASH_ENTRIES; j++) {
- struct pkt_frag *frag;
-
- frag = &stt_percpu->frag_hash[j];
- if (!frag->skbs ||
- time_before(jiffies, frag->timestamp + FRAG_EXP_TIME))
- continue;
-
- spin_lock_bh(&stt_percpu->lock);
-
- if (frag->skbs &&
- time_after(jiffies, frag->timestamp + FRAG_EXP_TIME))
- free_frag(stt_percpu, frag);
-
- spin_unlock_bh(&stt_percpu->lock);
- }
- }
- schedule_clean_percpu();
-}
-
-#ifdef HAVE_NF_HOOKFN_ARG_OPS
-#define FIRST_PARAM const struct nf_hook_ops *ops
-#else
-#ifdef HAVE_NF_HOOKFN_ARG_PRIV
-#define FIRST_PARAM void *priv
-#else
-#define FIRST_PARAM unsigned int hooknum
-#endif
-#endif
-
-#ifdef HAVE_NF_HOOK_STATE
-#if RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0)
-/* RHEL nfhook hacks. */
-#ifndef __GENKSYMS__
-#define LAST_PARAM const struct net_device *in, const struct net_device *out, \
- const struct nf_hook_state *state
-#else
-#define LAST_PARAM const struct net_device *in, const struct net_device *out, \
- int (*okfn)(struct sk_buff *)
-#endif
-#else
-#define LAST_PARAM const struct nf_hook_state *state
-#endif
-#else
-#define LAST_PARAM const struct net_device *in, const struct net_device *out, \
- int (*okfn)(struct sk_buff *)
-#endif
-
-static unsigned int nf_ip_hook(FIRST_PARAM, struct sk_buff *skb, LAST_PARAM)
-{
- struct stt_dev *stt_dev;
- int ip_hdr_len;
-
- if (ip_hdr(skb)->protocol != IPPROTO_TCP)
- return NF_ACCEPT;
-
- ip_hdr_len = ip_hdrlen(skb);
- if (unlikely(!pskb_may_pull(skb, ip_hdr_len + sizeof(struct tcphdr))))
- return NF_ACCEPT;
-
- skb_set_transport_header(skb, ip_hdr_len);
-
- stt_dev = stt_find_up_dev(dev_net(skb->dev), tcp_hdr(skb)->dest);
- if (!stt_dev)
- return NF_ACCEPT;
-
- __skb_pull(skb, ip_hdr_len);
- stt_rcv(stt_dev, skb);
- return NF_STOLEN;
-}
-
-static struct nf_hook_ops nf_hook_ops __read_mostly = {
- .hook = nf_ip_hook,
-#ifdef HAVE_NF_HOOKS_OPS_OWNER
- .owner = THIS_MODULE,
-#endif
- .pf = NFPROTO_IPV4,
- .hooknum = NF_INET_LOCAL_IN,
- .priority = INT_MAX,
-};
-
-static int stt_start(struct net *net)
-{
- struct stt_net *sn = net_generic(net, stt_net_id);
- int err;
- int i;
-
- if (n_tunnels) {
- n_tunnels++;
- return 0;
- }
- get_random_bytes(&frag_hash_seed, sizeof(u32));
-
- stt_percpu_data = alloc_percpu(struct stt_percpu);
- if (!stt_percpu_data) {
- err = -ENOMEM;
- goto error;
- }
-
- for_each_possible_cpu(i) {
- struct stt_percpu *stt_percpu = per_cpu_ptr(stt_percpu_data, i);
- struct pkt_frag *frag_hash;
-
- spin_lock_init(&stt_percpu->lock);
- INIT_LIST_HEAD(&stt_percpu->frag_lru);
- get_random_bytes(&per_cpu(pkt_seq_counter, i), sizeof(u32));
-
- frag_hash = kvmalloc_array(sizeof(struct pkt_frag),
- FRAG_HASH_ENTRIES,
- GFP_KERNEL | __GFP_ZERO);
- if (!frag_hash) {
- err = -ENOMEM;
- goto free_percpu;
- }
- stt_percpu->frag_hash = frag_hash;
- }
- schedule_clean_percpu();
- n_tunnels++;
-
- if (sn->n_tunnels) {
- sn->n_tunnels++;
- return 0;
- }
-#ifdef HAVE_NF_REGISTER_NET_HOOK
- /* On kernel which support per net nf-hook, nf_register_hook() takes
- * rtnl-lock, which results in dead lock in stt-dev-create. Therefore
- * use this new API.
- */
-
- if (sn->nf_hook_reg_done)
- goto out;
-
- err = nf_register_net_hook(net, &nf_hook_ops);
- if (!err)
- sn->nf_hook_reg_done = true;
-#else
- /* Register STT only on very first STT device addition. */
- if (!list_empty(&nf_hook_ops.list))
- goto out;
-
- err = nf_register_hook(&nf_hook_ops);
-#endif
- if (err)
- goto dec_n_tunnel;
-out:
- sn->n_tunnels++;
- return 0;
-
-dec_n_tunnel:
- n_tunnels--;
-free_percpu:
- for_each_possible_cpu(i) {
- struct stt_percpu *stt_percpu = per_cpu_ptr(stt_percpu_data, i);
-
- if (stt_percpu->frag_hash)
- kvfree(stt_percpu->frag_hash);
- }
-
- free_percpu(stt_percpu_data);
-
-error:
- return err;
-}
-
-static void stt_cleanup(struct net *net)
-{
- struct stt_net *sn = net_generic(net, stt_net_id);
- int i;
-
- sn->n_tunnels--;
- n_tunnels--;
- if (n_tunnels)
- return;
-
- cancel_delayed_work_sync(&clean_percpu_wq);
- for_each_possible_cpu(i) {
- struct stt_percpu *stt_percpu = per_cpu_ptr(stt_percpu_data, i);
- int j;
-
- for (j = 0; j < FRAG_HASH_ENTRIES; j++) {
- struct pkt_frag *frag;
-
- frag = &stt_percpu->frag_hash[j];
- kfree_skb_list(frag->skbs);
- }
-
- kvfree(stt_percpu->frag_hash);
- }
-
- free_percpu(stt_percpu_data);
-}
-
-static netdev_tx_t stt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-#ifdef USE_UPSTREAM_TUNNEL
- return ovs_stt_xmit(skb);
-#else
- /* 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;
-#endif
-}
-
-/* Setup stats when device is created */
-static int stt_init(struct net_device *dev)
-{
- dev->tstats = (typeof(dev->tstats)) netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- return 0;
-}
-
-static void stt_uninit(struct net_device *dev)
-{
- free_percpu(dev->tstats);
-}
-
-static int stt_open(struct net_device *dev)
-{
- struct stt_dev *stt = netdev_priv(dev);
- struct net *net = stt->net;
- struct stt_net *sn = net_generic(net, stt_net_id);
- int err;
-
- err = stt_start(net);
- if (err)
- return err;
-
- err = tcp_sock_create4(net, stt->dst_port, &stt->sock);
- if (err)
- return err;
- list_add_rcu(&stt->up_next, &sn->stt_up_list);
- return 0;
-}
-
-static int stt_stop(struct net_device *dev)
-{
- struct stt_dev *stt_dev = netdev_priv(dev);
- struct net *net = stt_dev->net;
-
- list_del_rcu(&stt_dev->up_next);
- synchronize_net();
- tcp_sock_release(stt_dev->sock);
- stt_dev->sock = NULL;
- stt_cleanup(net);
- return 0;
-}
-
-static int __stt_change_mtu(struct net_device *dev, int new_mtu, bool strict)
-{
- int max_mtu = IP_MAX_MTU - STT_HEADER_LEN - sizeof(struct iphdr)
- - dev->hard_header_len;
-
- if (new_mtu < 68)
- return -EINVAL;
-
- if (new_mtu > max_mtu) {
- if (strict)
- return -EINVAL;
-
- new_mtu = max_mtu;
- }
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-static int stt_change_mtu(struct net_device *dev, int new_mtu)
-{
- return __stt_change_mtu(dev, new_mtu, true);
-}
-
-int ovs_stt_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
-{
- struct ip_tunnel_info *info = skb_tunnel_info(skb);
- struct stt_dev *stt_dev = netdev_priv(dev);
- struct net *net = stt_dev->net;
- __be16 dport = stt_dev->dst_port;
- __be16 sport;
- struct flowi4 fl4;
- struct rtable *rt;
-
- if (ip_tunnel_info_af(info) != AF_INET)
- return -EINVAL;
-
- sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);
- rt = stt_get_rt(skb, dev, &fl4, &info->key, dport, sport);
- if (IS_ERR(rt))
- return PTR_ERR(rt);
-
- ip_rt_put(rt);
-
- info->key.u.ipv4.src = fl4.saddr;
- info->key.tp_src = sport;
- info->key.tp_dst = dport;
- return 0;
-}
-EXPORT_SYMBOL_GPL(ovs_stt_fill_metadata_dst);
-
-static const struct net_device_ops stt_netdev_ops = {
- .ndo_init = stt_init,
- .ndo_uninit = stt_uninit,
- .ndo_open = stt_open,
- .ndo_stop = stt_stop,
- .ndo_start_xmit = stt_dev_xmit,
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = stt_change_mtu,
-#else
- .ndo_change_mtu = stt_change_mtu,
-#endif
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
-#ifdef USE_UPSTREAM_TUNNEL
-#ifdef HAVE_NDO_FILL_METADATA_DST
- .ndo_fill_metadata_dst = stt_fill_metadata_dst,
-#endif
-#endif
-};
-
-static void stt_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- strlcpy(drvinfo->version, STT_NETDEV_VER, sizeof(drvinfo->version));
- strlcpy(drvinfo->driver, "stt", sizeof(drvinfo->driver));
-}
-
-static const struct ethtool_ops stt_ethtool_ops = {
- .get_drvinfo = stt_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-
-/* Info for udev, that this is a virtual tunnel endpoint */
-static struct device_type stt_type = {
- .name = "stt",
-};
-
-/* Initialize the device structure. */
-static void stt_setup(struct net_device *dev)
-{
- ether_setup(dev);
-
- dev->netdev_ops = &stt_netdev_ops;
- dev->ethtool_ops = &stt_ethtool_ops;
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
-#endif
-
- SET_NETDEV_DEVTYPE(dev, &stt_type);
-
- dev->features |= NETIF_F_LLTX | NETIF_F_NETNS_LOCAL;
- 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;
-
-#ifdef USE_UPSTREAM_TUNNEL
- netif_keep_dst(dev);
-#endif
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
- eth_hw_addr_random(dev);
-}
-
-static const struct nla_policy stt_policy[IFLA_STT_MAX + 1] = {
- [IFLA_STT_PORT] = { .type = NLA_U16 },
-};
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int stt_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack __always_unused *extack)
-#else
-static int stt_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- if (tb[IFLA_ADDRESS]) {
- if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
- return -EINVAL;
-
- if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
- return -EADDRNOTAVAIL;
- }
-
- return 0;
-}
-
-static struct stt_dev *find_dev(struct net *net, __be16 dst_port)
-{
- struct stt_net *sn = net_generic(net, stt_net_id);
- struct stt_dev *dev;
-
- list_for_each_entry(dev, &sn->stt_list, next) {
- if (dev->dst_port == dst_port)
- return dev;
- }
- return NULL;
-}
-
-static int stt_configure(struct net *net, struct net_device *dev,
- __be16 dst_port)
-{
- struct stt_net *sn = net_generic(net, stt_net_id);
- struct stt_dev *stt = netdev_priv(dev);
- int err;
-
- stt->net = net;
- stt->dev = dev;
-
- stt->dst_port = dst_port;
-
- if (find_dev(net, dst_port))
- return -EBUSY;
-
- err = __stt_change_mtu(dev, IP_MAX_MTU, false);
- if (err)
- return err;
-
- err = register_netdevice(dev);
- if (err)
- return err;
-
- list_add(&stt->next, &sn->stt_list);
- return 0;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int stt_newlink(struct net *net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack __always_unused *extack)
-#else
-static int stt_newlink(struct net *net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- __be16 dst_port = htons(STT_DST_PORT);
-
- if (data[IFLA_STT_PORT])
- dst_port = nla_get_be16(data[IFLA_STT_PORT]);
-
- return stt_configure(net, dev, dst_port);
-}
-
-static void stt_dellink(struct net_device *dev, struct list_head *head)
-{
- struct stt_dev *stt = netdev_priv(dev);
-
- list_del(&stt->next);
- unregister_netdevice_queue(dev, head);
-}
-
-static size_t stt_get_size(const struct net_device *dev)
-{
- return nla_total_size(sizeof(__be32)); /* IFLA_STT_PORT */
-}
-
-static int stt_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- struct stt_dev *stt = netdev_priv(dev);
-
- if (nla_put_be16(skb, IFLA_STT_PORT, stt->dst_port))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-static struct rtnl_link_ops stt_link_ops __read_mostly = {
- .kind = "stt",
- .maxtype = IFLA_STT_MAX,
- .policy = stt_policy,
- .priv_size = sizeof(struct stt_dev),
- .setup = stt_setup,
- .validate = stt_validate,
- .newlink = stt_newlink,
- .dellink = stt_dellink,
- .get_size = stt_get_size,
- .fill_info = stt_fill_info,
-};
-
-struct net_device *ovs_stt_dev_create_fb(struct net *net, const char *name,
- u8 name_assign_type, u16 dst_port)
-{
- struct nlattr *tb[IFLA_MAX + 1];
- struct net_device *dev;
- int err;
-
- memset(tb, 0, sizeof(tb));
- dev = rtnl_create_link(net, (char *) name, name_assign_type,
- &stt_link_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- err = stt_configure(net, dev, htons(dst_port));
- if (err) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
- return dev;
-}
-EXPORT_SYMBOL_GPL(ovs_stt_dev_create_fb);
-
-static int stt_init_net(struct net *net)
-{
- struct stt_net *sn = net_generic(net, stt_net_id);
-
- INIT_LIST_HEAD(&sn->stt_list);
- INIT_LIST_HEAD(&sn->stt_up_list);
-#ifdef HAVE_NF_REGISTER_NET_HOOK
- sn->nf_hook_reg_done = false;
-#endif
- return 0;
-}
-
-static void stt_exit_net(struct net *net)
-{
- struct stt_net *sn = net_generic(net, stt_net_id);
- struct stt_dev *stt, *next;
- struct net_device *dev, *aux;
- LIST_HEAD(list);
-
-#ifdef HAVE_NF_REGISTER_NET_HOOK
- /* Ideally this should be done from stt_stop(), But on some kernels
- * nf-unreg operation needs RTNL-lock, which can cause deallock.
- * So it is done from here. */
- if (sn->nf_hook_reg_done)
- nf_unregister_net_hook(net, &nf_hook_ops);
-#endif
-
- rtnl_lock();
-
- /* gather any stt devices that were moved into this ns */
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == &stt_link_ops)
- unregister_netdevice_queue(dev, &list);
-
- list_for_each_entry_safe(stt, next, &sn->stt_list, next) {
- /* If stt->dev is in the same netns, it was already added
- * to the stt by the previous loop.
- */
- if (!net_eq(dev_net(stt->dev), net))
- unregister_netdevice_queue(stt->dev, &list);
- }
-
- /* unregister the devices gathered above */
- unregister_netdevice_many(&list);
- rtnl_unlock();
-}
-
-static struct pernet_operations stt_net_ops = {
- .init = stt_init_net,
- .exit = stt_exit_net,
- .id = &stt_net_id,
- .size = sizeof(struct stt_net),
-};
-
-int stt_init_module(void)
-{
- int rc;
-
- rc = register_pernet_subsys(&stt_net_ops);
- if (rc)
- goto out1;
-
- rc = rtnl_link_register(&stt_link_ops);
- if (rc)
- goto out2;
-
-#ifdef HAVE_LIST_IN_NF_HOOK_OPS
- INIT_LIST_HEAD(&nf_hook_ops.list);
-#endif
- pr_info("STT tunneling driver\n");
- return 0;
-out2:
- unregister_pernet_subsys(&stt_net_ops);
-out1:
- pr_err("Error while initializing STT %d\n", rc);
- return rc;
-}
-
-void stt_cleanup_module(void)
-{
-#ifndef HAVE_NF_REGISTER_NET_HOOK
- if (!list_empty(&nf_hook_ops.list))
- nf_unregister_hook(&nf_hook_ops);
-#endif
- rtnl_link_unregister(&stt_link_ops);
- unregister_pernet_subsys(&stt_net_ops);
-}
-#endif
diff --git a/datapath/linux/compat/udp.c b/datapath/linux/compat/udp.c
deleted file mode 100644
index 38bf332db..000000000
--- a/datapath/linux/compat/udp.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <linux/version.h>
-
-#ifndef USE_UPSTREAM_TUNNEL
-
-#include <net/udp.h>
-
-/* Function to set UDP checksum for an IPv4 UDP packet. This is intended
- * for the simple case like when setting the checksum for a UDP tunnel.
- */
-void rpl_udp_set_csum(bool nocheck, struct sk_buff *skb,
- __be32 saddr, __be32 daddr, int len)
-{
- struct udphdr *uh = udp_hdr(skb);
-
-
- if (nocheck) {
- uh->check = 0;
- } else if (skb_is_gso(skb)) {
- uh->check = ~udp_v4_check(len, saddr, daddr, 0);
- } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- uh->check = 0;
- uh->check = udp_v4_check(len, saddr, daddr, lco_csum(skb));
- if (uh->check == 0)
- uh->check = CSUM_MANGLED_0;
- } else {
- skb->ip_summed = CHECKSUM_PARTIAL;
- skb->csum_start = skb_transport_header(skb) - skb->head;
- skb->csum_offset = offsetof(struct udphdr, check);
- uh->check = ~udp_v4_check(len, saddr, daddr, 0);
- }
-}
-EXPORT_SYMBOL_GPL(rpl_udp_set_csum);
-
-#endif /* Linux version < 3.16 */
-
-#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
-void rpl_udp6_csum_zero_error(struct sk_buff *skb)
-{
- /* RFC 2460 section 8.1 says that we SHOULD log
- * this error. Well, it is reasonable.
- */
- net_dbg_ratelimited("IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
- &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source),
- &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest));
-}
-#endif
diff --git a/datapath/linux/compat/udp_tunnel.c b/datapath/linux/compat/udp_tunnel.c
deleted file mode 100644
index 852069f62..000000000
--- a/datapath/linux/compat/udp_tunnel.c
+++ /dev/null
@@ -1,292 +0,0 @@
-#include <linux/version.h>
-
-#ifndef USE_UPSTREAM_TUNNEL
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/socket.h>
-#include <linux/udp.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <net/ip_tunnels.h>
-#include <net/udp.h>
-#include <net/udp_tunnel.h>
-#include <net/net_namespace.h>
-#include <net/ip6_checksum.h>
-#include <net/ip6_tunnel.h>
-
-#include "gso.h"
-
-int rpl_udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
- struct socket **sockp)
-{
- int err;
- struct socket *sock = NULL;
- struct sockaddr_in udp_addr;
-
- err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock);
- if (err < 0)
- goto error;
-
- udp_addr.sin_family = AF_INET;
- udp_addr.sin_addr = cfg->local_ip;
- udp_addr.sin_port = cfg->local_udp_port;
- err = kernel_bind(sock, (struct sockaddr *)&udp_addr,
- sizeof(udp_addr));
- if (err < 0)
- goto error;
-
- if (cfg->peer_udp_port) {
- udp_addr.sin_family = AF_INET;
- udp_addr.sin_addr = cfg->peer_ip;
- udp_addr.sin_port = cfg->peer_udp_port;
- err = kernel_connect(sock, (struct sockaddr *)&udp_addr,
- sizeof(udp_addr), 0);
- if (err < 0)
- goto error;
- }
-#ifdef HAVE_SK_NO_CHECK_TX
- sock->sk->sk_no_check_tx = !cfg->use_udp_checksums;
-#endif
- *sockp = sock;
- return 0;
-
-error:
- if (sock) {
- kernel_sock_shutdown(sock, SHUT_RDWR);
- sock_release(sock);
- }
- *sockp = NULL;
- return err;
-}
-EXPORT_SYMBOL(rpl_udp_sock_create4);
-
-int rpl_udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
- struct socket **sockp)
-{
- struct sockaddr_in6 udp6_addr;
- int err;
- struct socket *sock = NULL;
-
- err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock);
- if (err < 0)
- goto error;
-
- if (cfg->ipv6_v6only) {
- int val = 1;
-
- err = kernel_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
- (char *) &val, sizeof(val));
- if (err < 0)
- goto error;
- }
-
- udp6_addr.sin6_family = AF_INET6;
- memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6,
- sizeof(udp6_addr.sin6_addr));
- udp6_addr.sin6_port = cfg->local_udp_port;
- err = kernel_bind(sock, (struct sockaddr *)&udp6_addr,
- sizeof(udp6_addr));
- if (err < 0)
- goto error;
-
- if (cfg->peer_udp_port) {
- udp6_addr.sin6_family = AF_INET6;
- memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6,
- sizeof(udp6_addr.sin6_addr));
- udp6_addr.sin6_port = cfg->peer_udp_port;
- err = kernel_connect(sock,
- (struct sockaddr *)&udp6_addr,
- sizeof(udp6_addr), 0);
- }
- if (err < 0)
- goto error;
-
- udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums);
- udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums);
-
- *sockp = sock;
- return 0;
-
-error:
- if (sock) {
- kernel_sock_shutdown(sock, SHUT_RDWR);
- sock_release(sock);
- }
- *sockp = NULL;
- return err;
-}
-EXPORT_SYMBOL_GPL(rpl_udp_sock_create6);
-
-void rpl_setup_udp_tunnel_sock(struct net *net, struct socket *sock,
- struct udp_tunnel_sock_cfg *cfg)
-{
- struct sock *sk = sock->sk;
-
- /* Disable multicast loopback */
- inet_sk(sk)->mc_loop = 0;
-
- rcu_assign_sk_user_data(sk, cfg->sk_user_data);
-
- udp_sk(sk)->encap_type = cfg->encap_type;
- udp_sk(sk)->encap_rcv = cfg->encap_rcv;
- udp_sk(sk)->encap_destroy = cfg->encap_destroy;
-#ifdef HAVE_UDP_TUNNEL_SOCK_CFG_GRO_RECEIVE
- udp_sk(sk)->gro_receive = cfg->gro_receive;
- udp_sk(sk)->gro_complete = cfg->gro_complete;
-#endif
-
- udp_tunnel_encap_enable(sock);
-}
-EXPORT_SYMBOL_GPL(rpl_setup_udp_tunnel_sock);
-
-void rpl_udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk,
- struct sk_buff *skb, __be32 src, __be32 dst,
- __u8 tos, __u8 ttl, __be16 df, __be16 src_port,
- __be16 dst_port, bool xnet, bool nocheck)
-{
- struct udphdr *uh;
-
- __skb_push(skb, sizeof(*uh));
- skb_reset_transport_header(skb);
- uh = udp_hdr(skb);
-
- uh->dest = dst_port;
- uh->source = src_port;
- uh->len = htons(skb->len);
-
- udp_set_csum(nocheck, skb, src, dst, skb->len);
-
- iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet);
-}
-EXPORT_SYMBOL_GPL(rpl_udp_tunnel_xmit_skb);
-
-void rpl_udp_tunnel_sock_release(struct socket *sock)
-{
- rcu_assign_sk_user_data(sock->sk, NULL);
- kernel_sock_shutdown(sock, SHUT_RDWR);
- sock_release(sock);
-}
-EXPORT_SYMBOL_GPL(rpl_udp_tunnel_sock_release);
-
-#if IS_ENABLED(CONFIG_IPV6)
-
-#define udp_v6_check rpl_udp_v6_check
-static __sum16 udp_v6_check(int len,
- const struct in6_addr *saddr,
- const struct in6_addr *daddr,
- __wsum base)
-{
- return csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, base);
-}
-
-#define udp6_set_csum rpl_udp6_set_csum
-static void udp6_set_csum(bool nocheck, struct sk_buff *skb,
- const struct in6_addr *saddr,
- const struct in6_addr *daddr, int len)
-{
- struct udphdr *uh = udp_hdr(skb);
-
- if (nocheck)
- uh->check = 0;
- else if (skb_is_gso(skb))
- uh->check = ~udp_v6_check(len, saddr, daddr, 0);
- else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- uh->check = 0;
- uh->check = udp_v6_check(len, saddr, daddr, lco_csum(skb));
- if (uh->check == 0)
- uh->check = CSUM_MANGLED_0;
- } else {
- skb->ip_summed = CHECKSUM_PARTIAL;
- skb->csum_start = skb_transport_header(skb) - skb->head;
- skb->csum_offset = offsetof(struct udphdr, check);
- uh->check = ~udp_v6_check(len, saddr, daddr, 0);
- }
-}
-
-#define ip6_flow_hdr rpl_ip6_flow_hdr
-static inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass,
- __be32 flowlabel)
-{
- *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel;
-}
-
-int rpl_udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
- struct sk_buff *skb,
- struct net_device *dev, struct in6_addr *saddr,
- struct in6_addr *daddr,
- __u8 prio, __u8 ttl, __be32 label, __be16 src_port,
- __be16 dst_port, bool nocheck)
-{
- struct udphdr *uh;
- struct ipv6hdr *ip6h;
-
- __skb_push(skb, sizeof(*uh));
- skb_reset_transport_header(skb);
- uh = udp_hdr(skb);
-
- uh->dest = dst_port;
- uh->source = src_port;
-
- uh->len = htons(skb->len);
-
- memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
- | IPSKB_REROUTED);
- skb_dst_set(skb, dst);
-
- udp6_set_csum(nocheck, skb, saddr, daddr, skb->len);
-
- __skb_push(skb, sizeof(*ip6h));
- skb_reset_network_header(skb);
- ip6h = ipv6_hdr(skb);
- ip6_flow_hdr(ip6h, prio, label);
- ip6h->payload_len = htons(skb->len);
- ip6h->nexthdr = IPPROTO_UDP;
- ip6h->hop_limit = ttl;
- ip6h->daddr = *daddr;
- ip6h->saddr = *saddr;
-
- ip6tunnel_xmit(sk, skb, dev);
- return 0;
-}
-#endif
-
-#ifndef USE_UPSTREAM_TUNNEL_GSO
-void ovs_udp_gso(struct sk_buff *skb)
-{
- int udp_offset = skb_transport_offset(skb);
- struct udphdr *uh;
-
- uh = udp_hdr(skb);
- uh->len = htons(skb->len - udp_offset);
-}
-EXPORT_SYMBOL_GPL(ovs_udp_gso);
-
-void ovs_udp_csum_gso(struct sk_buff *skb)
-{
- int udp_offset = skb_transport_offset(skb);
-
- ovs_udp_gso(skb);
-
- if (!OVS_GSO_CB(skb)->ipv6) {
- struct iphdr *iph = ip_hdr(skb);
-
- /* csum segment if tunnel sets skb with csum. The cleanest way
- * to do this just to set it up from scratch. */
- udp_set_csum(false, skb, iph->saddr, iph->daddr,
- skb->len - udp_offset);
-#if IS_ENABLED(CONFIG_IPV6)
- } else {
- struct ipv6hdr *ip6h;
-
- ip6h = ipv6_hdr(skb);
- udp6_set_csum(false, skb, &ip6h->saddr, &ip6h->daddr,
- skb->len - udp_offset);
-#endif
- }
-}
-EXPORT_SYMBOL_GPL(ovs_udp_csum_gso);
-#endif /* USE_UPSTREAM_TUNNEL_GSO */
-
-#endif
diff --git a/datapath/linux/compat/utils.c b/datapath/linux/compat/utils.c
deleted file mode 100644
index a4a98ba65..000000000
--- a/datapath/linux/compat/utils.c
+++ /dev/null
@@ -1,112 +0,0 @@
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/ctype.h>
-#include <linux/inet.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <net/checksum.h>
-#include <net/ip.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/percpu.h>
-#include <linux/init.h>
-#include <linux/ratelimit.h>
-
-#include <net/sock.h>
-
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
-
-bool rpl___net_get_random_once(void *buf, int nbytes, bool *done,
- atomic_t *done_key)
-{
- static DEFINE_SPINLOCK(lock);
- unsigned long flags;
-
- spin_lock_irqsave(&lock, flags);
- if (*done) {
- spin_unlock_irqrestore(&lock, flags);
- return false;
- }
-
- get_random_bytes(buf, nbytes);
- *done = true;
- spin_unlock_irqrestore(&lock, flags);
-
- atomic_set(done_key, 1);
-
- return true;
-}
-EXPORT_SYMBOL_GPL(rpl___net_get_random_once);
-
-#endif
-
-#ifdef NEED_ALLOC_PERCPU_GFP
-void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp)
-{
- void __percpu *p;
- int i;
-
- /* older kernel do not allow all GFP flags, specifically atomic
- * allocation.
- */
- if (gfp & ~(GFP_KERNEL | __GFP_ZERO))
- return NULL;
- p = __alloc_percpu(size, align);
- if (!p)
- return p;
-
- if (!(gfp & __GFP_ZERO))
- return p;
-
- for_each_possible_cpu(i) {
- void *d;
-
- d = per_cpu_ptr(p, i);
- memset(d, 0, size);
- }
- return p;
-}
-#endif
-
-#ifndef HAVE_NLA_PUT_64BIT
-int rpl_nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
- const void *data, int padattr)
-{
- size_t len;
-
- if (nla_need_padding_for_64bit(skb))
- len = nla_total_size_64bit(attrlen);
- else
- len = nla_total_size(attrlen);
- if (unlikely(skb_tailroom(skb) < len))
- return -EMSGSIZE;
-
- __nla_put_64bit(skb, attrtype, attrlen, data, padattr);
- return 0;
-}
-EXPORT_SYMBOL_GPL(rpl_nla_put_64bit);
-
-void rpl___nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
- const void *data, int padattr)
-{
- struct nlattr *nla;
-
- nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
- memcpy(nla_data(nla), data, attrlen);
-}
-EXPORT_SYMBOL_GPL(rpl___nla_put_64bit);
-
-struct nlattr *rpl___nla_reserve_64bit(struct sk_buff *skb, int attrtype,
- int attrlen, int padattr)
-{
- if (nla_need_padding_for_64bit(skb))
- nla_align_64bit(skb, padattr);
-
- return __nla_reserve(skb, attrtype, attrlen);
-}
-EXPORT_SYMBOL_GPL(rpl___nla_reserve_64bit);
-#endif
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
deleted file mode 100644
index e65d955e9..000000000
--- a/datapath/linux/compat/vxlan.c
+++ /dev/null
@@ -1,2382 +0,0 @@
-/*
- * VXLAN: Virtual eXtensible Local Area Network
- *
- * Copyright (c) 2012-2013 Vyatta Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/rculist.h>
-#include <linux/netdevice.h>
-#include <linux/netdev_features.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/igmp.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/if_vlan.h>
-#include <linux/hash.h>
-#include <linux/ethtool.h>
-#include <net/arp.h>
-#include <net/dst_metadata.h>
-#include <net/ndisc.h>
-#include <net/ip.h>
-#include <net/ip_tunnels.h>
-#include <net/icmp.h>
-#include <net/udp.h>
-#include <net/udp_tunnel.h>
-#include <net/rtnetlink.h>
-#include <net/route.h>
-#include <net/dsfield.h>
-#include <net/inet_ecn.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/protocol.h>
-
-#if IS_ENABLED(CONFIG_IPV6)
-#include <net/ipv6.h>
-#include <net/addrconf.h>
-#include <net/ip6_tunnel.h>
-#include <net/ip6_checksum.h>
-#include <net/ip6_route.h>
-#endif
-
-#include <net/tun_proto.h>
-#include <net/vxlan.h>
-#include "gso.h"
-#include "vport-netdev.h"
-#include "compat.h"
-
-#ifndef USE_UPSTREAM_TUNNEL
-#define VXLAN_VERSION "0.1"
-
-#define PORT_HASH_BITS 8
-#define PORT_HASH_SIZE (1<<PORT_HASH_BITS)
-#define FDB_AGE_DEFAULT 300 /* 5 min */
-#define FDB_AGE_INTERVAL (10 * HZ) /* rescan interval */
-
-/* UDP port for VXLAN traffic.
- * The IANA assigned port is 4789, but the Linux default is 8472
- * for compatibility with early adopters.
- */
-static unsigned short vxlan_port __read_mostly = 8472;
-module_param_named(udp_port, vxlan_port, ushort, 0444);
-MODULE_PARM_DESC(udp_port, "Destination UDP port");
-
-static int vxlan_net_id;
-static struct rtnl_link_ops vxlan_link_ops;
-
-static const u8 all_zeros_mac[ETH_ALEN + 2];
-
-static int vxlan_sock_add(struct vxlan_dev *vxlan);
-
-/* per-network namespace private data for this module */
-struct vxlan_net {
- struct list_head vxlan_list;
- struct hlist_head sock_list[PORT_HASH_SIZE];
- spinlock_t sock_lock;
-};
-
-/* Forwarding table entry */
-struct vxlan_fdb {
- struct hlist_node hlist; /* linked list of entries */
- struct rcu_head rcu;
- unsigned long updated; /* jiffies */
- unsigned long used;
- struct list_head remotes;
- u8 eth_addr[ETH_ALEN];
- u16 state; /* see ndm_state */
- u8 flags; /* see ndm_flags */
-};
-
-/* salt for hash table */
-static u32 vxlan_salt __read_mostly;
-
-static inline bool vxlan_collect_metadata(struct vxlan_sock *vs)
-{
- return vs->flags & VXLAN_F_COLLECT_METADATA ||
- ip_tunnel_collect_metadata();
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static inline
-bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
-{
- if (a->sa.sa_family != b->sa.sa_family)
- return false;
- if (a->sa.sa_family == AF_INET6)
- return ipv6_addr_equal(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
- else
- return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
-}
-
-static inline bool vxlan_addr_any(const union vxlan_addr *ipa)
-{
- if (ipa->sa.sa_family == AF_INET6)
- return ipv6_addr_any(&ipa->sin6.sin6_addr);
- else
- return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
-}
-
-static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa)
-{
- if (ipa->sa.sa_family == AF_INET6)
- return ipv6_addr_is_multicast(&ipa->sin6.sin6_addr);
- else
- return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
-}
-
-#else /* !CONFIG_IPV6 */
-
-static inline
-bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
-{
- return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
-}
-
-static inline bool vxlan_addr_any(const union vxlan_addr *ipa)
-{
- return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
-}
-
-static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa)
-{
- return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
-}
-#endif
-
-/* Virtual Network hash table head */
-static inline struct hlist_head *vni_head(struct vxlan_sock *vs, __be32 vni)
-{
- return &vs->vni_list[hash_32((__force u32)vni, VNI_HASH_BITS)];
-}
-
-/* Socket hash table head */
-static inline struct hlist_head *vs_head(struct net *net, __be16 port)
-{
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
-
- return &vn->sock_list[hash_32(ntohs(port), PORT_HASH_BITS)];
-}
-
-/* Find VXLAN socket based on network namespace, address family and UDP port
- * and enabled unshareable flags.
- */
-static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,
- __be16 port, u32 flags)
-{
- struct vxlan_sock *vs;
-
- flags &= VXLAN_F_RCV_FLAGS;
-
- hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
- if (inet_sk(vs->sock->sk)->inet_sport == port &&
- vxlan_get_sk_family(vs) == family &&
- vs->flags == flags)
- return vs;
- }
- return NULL;
-}
-
-static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, __be32 vni)
-{
- struct vxlan_dev *vxlan;
-
- /* For flow based devices, map all packets to VNI 0 */
- if (vs->flags & VXLAN_F_COLLECT_METADATA)
- vni = 0;
-
- hlist_for_each_entry_rcu(vxlan, vni_head(vs, vni), hlist) {
- if (vxlan->default_dst.remote_vni == vni)
- return vxlan;
- }
-
- return NULL;
-}
-
-/* Look up VNI in a per net namespace table */
-static struct vxlan_dev *vxlan_find_vni(struct net *net, __be32 vni,
- sa_family_t family, __be16 port,
- u32 flags)
-{
- struct vxlan_sock *vs;
-
- vs = vxlan_find_sock(net, family, port, flags);
- if (!vs)
- return NULL;
-
- return vxlan_vs_find_vni(vs, vni);
-}
-
-static int vxlan_fdb_create(struct vxlan_dev *vxlan,
- const u8 *mac, union vxlan_addr *ip,
- __u16 state, __u16 flags,
- __be16 port, __be32 vni, __u32 ifindex,
- __u8 ndm_flags)
-{
- return -EINVAL;
-}
-
-static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
-{
-
-}
-
-static inline size_t vxlan_nlmsg_size(void)
-{
- return NLMSG_ALIGN(sizeof(struct ndmsg))
- + nla_total_size(ETH_ALEN) /* NDA_LLADDR */
- + nla_total_size(sizeof(struct in6_addr)) /* NDA_DST */
- + nla_total_size(sizeof(__be16)) /* NDA_PORT */
- + nla_total_size(sizeof(__be32)) /* NDA_VNI */
- + nla_total_size(sizeof(__u32)) /* NDA_IFINDEX */
- + nla_total_size(sizeof(__s32)) /* NDA_LINK_NETNSID */
- + nla_total_size(sizeof(struct nda_cacheinfo));
-}
-
-#ifdef HAVE_UDP_OFFLOAD
-#ifdef HAVE_NETIF_F_GSO_TUNNEL_REMCSUM
-
-static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
- unsigned int off,
- struct vxlanhdr *vh, size_t hdrlen,
- __be32 vni_field,
- struct gro_remcsum *grc,
- bool nopartial)
-{
- size_t start, offset;
-
- if (skb->remcsum_offload)
- return vh;
-
- if (!NAPI_GRO_CB(skb)->csum_valid)
- return NULL;
-
- start = vxlan_rco_start(vni_field);
- offset = start + vxlan_rco_offset(vni_field);
-
- vh = skb_gro_remcsum_process(skb, (void *)vh, off, hdrlen,
- start, offset, grc, nopartial);
-
- skb->remcsum_offload = 1;
-
- return vh;
-}
-#else
-static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
- unsigned int off,
- struct vxlanhdr *vh, size_t hdrlen,
- u32 data, struct gro_remcsum *grc,
- bool nopartial)
-{
- return NULL;
-}
-#endif
-
-#ifndef HAVE_UDP_OFFLOAD_ARG_UOFF
-static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
- struct sk_buff *skb)
-#else
-static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
- struct sk_buff *skb,
- struct udp_offload *uoff)
-#endif
-{
-#ifdef HAVE_UDP_OFFLOAD_ARG_UOFF
- struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock,
- udp_offloads);
-#else
- struct vxlan_sock *vs = NULL;
-#endif
- struct sk_buff *p, **pp = NULL;
- struct vxlanhdr *vh, *vh2;
- unsigned int hlen, off_vx;
- int flush = 1;
- __be32 flags;
- struct gro_remcsum grc;
-
- skb_gro_remcsum_init(&grc);
-
- off_vx = skb_gro_offset(skb);
- hlen = off_vx + sizeof(*vh);
- vh = skb_gro_header_fast(skb, off_vx);
- if (skb_gro_header_hard(skb, hlen)) {
- vh = skb_gro_header_slow(skb, hlen, off_vx);
- if (unlikely(!vh))
- goto out;
- }
-
- skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
-
- flags = vh->vx_flags;
-
- if ((flags & VXLAN_HF_RCO) && vs && (vs->flags & VXLAN_F_REMCSUM_RX)) {
- vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr),
- vh->vx_vni, &grc,
- !!(vs->flags &
- VXLAN_F_REMCSUM_NOPARTIAL));
-
- if (!vh)
- goto out;
- }
-
- skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
-
- for (p = *head; p; p = p->next) {
- if (!NAPI_GRO_CB(p)->same_flow)
- continue;
-
- vh2 = (struct vxlanhdr *)(p->data + off_vx);
- if (vh->vx_flags != vh2->vx_flags ||
- vh->vx_vni != vh2->vx_vni) {
- NAPI_GRO_CB(p)->same_flow = 0;
- continue;
- }
- }
-
- pp = eth_gro_receive(head, skb);
- flush = 0;
-
-out:
- skb_gro_remcsum_cleanup(skb, &grc);
- NAPI_GRO_CB(skb)->flush |= flush;
-
- return pp;
-}
-
-#ifndef HAVE_UDP_OFFLOAD_ARG_UOFF
-static int vxlan_gro_complete(struct sk_buff *skb, int nhoff)
-#else
-static int vxlan_gro_complete(struct sk_buff *skb, int nhoff,
- struct udp_offload *uoff)
-#endif
-{
- /* Sets 'skb->inner_mac_header' since we are always called with
- * 'skb->encapsulation' set.
- */
- udp_tunnel_gro_complete(skb, nhoff);
-
- return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
-}
-#endif
-
-/* Notify netdevs that UDP port started listening */
-static void vxlan_notify_add_rx_port(struct vxlan_sock *vs)
-{
- struct net_device *dev;
- struct sock *sk = vs->sock->sk;
- struct net *net = sock_net(sk);
- sa_family_t sa_family = vxlan_get_sk_family(vs);
-
-
- if (sa_family == AF_INET) {
- int err;
-
- err = udp_add_offload(net, &vs->udp_offloads);
- if (err)
- pr_warn("vxlan: udp_add_offload failed with status %d\n", err);
- }
-
- rcu_read_lock();
- for_each_netdev_rcu(net, dev) {
-#ifdef HAVE_NDO_ADD_VXLAN_PORT
- __be16 port = inet_sk(sk)->inet_sport;
-
- if (dev->netdev_ops->ndo_add_vxlan_port)
- dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
- port);
-#elif defined(HAVE_NDO_UDP_TUNNEL_ADD)
- struct udp_tunnel_info ti;
- if (vs->flags & VXLAN_F_GPE)
- ti.type = UDP_TUNNEL_TYPE_VXLAN_GPE;
- else
- ti.type = UDP_TUNNEL_TYPE_VXLAN;
- ti.sa_family = sa_family;
- ti.port = inet_sk(sk)->inet_sport;
-
- if (dev->netdev_ops->ndo_udp_tunnel_add)
- dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti);
-#endif
- }
- rcu_read_unlock();
-}
-
-/* Notify netdevs that UDP port is no more listening */
-static void vxlan_notify_del_rx_port(struct vxlan_sock *vs)
-{
- struct net_device *dev;
- struct sock *sk = vs->sock->sk;
- struct net *net = sock_net(sk);
- sa_family_t sa_family = vxlan_get_sk_family(vs);
-
- rcu_read_lock();
- for_each_netdev_rcu(net, dev) {
-#ifdef HAVE_NDO_ADD_VXLAN_PORT
- __be16 port = inet_sk(sk)->inet_sport;
-
- if (dev->netdev_ops->ndo_del_vxlan_port)
- dev->netdev_ops->ndo_del_vxlan_port(dev, sa_family,
- port);
-#elif defined(HAVE_NDO_UDP_TUNNEL_ADD)
- struct udp_tunnel_info ti;
- if (vs->flags & VXLAN_F_GPE)
- ti.type = UDP_TUNNEL_TYPE_VXLAN_GPE;
- else
- ti.type = UDP_TUNNEL_TYPE_VXLAN;
- ti.port = inet_sk(sk)->inet_sport;
- ti.sa_family = sa_family;
-
- if (dev->netdev_ops->ndo_udp_tunnel_del)
- dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti);
-#endif
- }
- rcu_read_unlock();
-
- if (sa_family == AF_INET) {
- udp_del_offload(&vs->udp_offloads);
- }
-}
-
-/* See if multicast group is already in use by other ID */
-static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev)
-{
- struct vxlan_dev *vxlan;
- struct vxlan_sock *sock4;
- struct vxlan_sock *sock6 = NULL;
- unsigned short family = dev->default_dst.remote_ip.sa.sa_family;
-
- sock4 = rtnl_dereference(dev->vn4_sock);
-
- /* The vxlan_sock is only used by dev, leaving group has
- * no effect on other vxlan devices.
- */
- if (family == AF_INET && sock4 && atomic_read(&sock4->refcnt) == 1)
- return false;
-#if IS_ENABLED(CONFIG_IPV6)
- sock6 = rtnl_dereference(dev->vn6_sock);
- if (family == AF_INET6 && sock6 && atomic_read(&sock6->refcnt) == 1)
- return false;
-#endif
-
- list_for_each_entry(vxlan, &vn->vxlan_list, next) {
- if (!netif_running(vxlan->dev) || vxlan == dev)
- continue;
-
- if (family == AF_INET &&
- rtnl_dereference(vxlan->vn4_sock) != sock4)
- continue;
-#if IS_ENABLED(CONFIG_IPV6)
- if (family == AF_INET6 &&
- rtnl_dereference(vxlan->vn6_sock) != sock6)
- continue;
-#endif
-
- if (!vxlan_addr_equal(&vxlan->default_dst.remote_ip,
- &dev->default_dst.remote_ip))
- continue;
-
- if (vxlan->default_dst.remote_ifindex !=
- dev->default_dst.remote_ifindex)
- continue;
-
- return true;
- }
-
- return false;
-}
-
-static bool __vxlan_sock_release_prep(struct vxlan_sock *vs)
-{
- struct vxlan_net *vn;
-
- if (!vs)
- return false;
- if (!atomic_dec_and_test(&vs->refcnt))
- return false;
-
- vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id);
- spin_lock(&vn->sock_lock);
- hlist_del_rcu(&vs->hlist);
- vxlan_notify_del_rx_port(vs);
- spin_unlock(&vn->sock_lock);
-
- return true;
-}
-
-static void vxlan_sock_release(struct vxlan_dev *vxlan)
-{
- struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
-#if IS_ENABLED(CONFIG_IPV6)
- struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
-
- rcu_assign_pointer(vxlan->vn6_sock, NULL);
-#endif
-
- rcu_assign_pointer(vxlan->vn4_sock, NULL);
- synchronize_net();
-
- if (__vxlan_sock_release_prep(sock4)) {
- udp_tunnel_sock_release(sock4->sock);
- kfree(sock4);
- }
-
-#if IS_ENABLED(CONFIG_IPV6)
- if (__vxlan_sock_release_prep(sock6)) {
- udp_tunnel_sock_release(sock6->sock);
- kfree(sock6);
- }
-#endif
-}
-
-/* Update multicast group membership when first VNI on
- * multicast address is brought up
- */
-static int vxlan_igmp_join(struct vxlan_dev *vxlan)
-{
- return -EINVAL;
-}
-
-/* Inverse of vxlan_igmp_join when last VNI is brought down */
-static int vxlan_igmp_leave(struct vxlan_dev *vxlan)
-{
- return -EINVAL;
-}
-
-static bool vxlan_remcsum(struct vxlanhdr *unparsed,
- struct sk_buff *skb, u32 vxflags)
-{
-#ifndef USE_UPSTREAM_TUNNEL
- return false;
-#else
- size_t start, offset;
-
- if (!(unparsed->vx_flags & VXLAN_HF_RCO) || skb->remcsum_offload)
- goto out;
-
- start = vxlan_rco_start(unparsed->vx_vni);
- offset = start + vxlan_rco_offset(unparsed->vx_vni);
-
- if (!pskb_may_pull(skb, offset + sizeof(u16)))
- return false;
-
- skb_remcsum_process(skb, (void *)(vxlan_hdr(skb) + 1), start, offset,
- !!(vxflags & VXLAN_F_REMCSUM_NOPARTIAL));
-out:
- unparsed->vx_flags &= ~VXLAN_HF_RCO;
- unparsed->vx_vni &= VXLAN_VNI_MASK;
- return true;
-#endif
-}
-
-static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed,
- struct sk_buff *skb, u32 vxflags,
- struct vxlan_metadata *md)
-{
- struct vxlanhdr_gbp *gbp = (struct vxlanhdr_gbp *)unparsed;
- struct metadata_dst *tun_dst;
-
- if (!(unparsed->vx_flags & VXLAN_HF_GBP))
- goto out;
-
- md->gbp = ntohs(gbp->policy_id);
-
- tun_dst = (struct metadata_dst *)skb_dst(skb);
- if (tun_dst) {
- tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
- tun_dst->u.tun_info.options_len = sizeof(*md);
- }
- if (gbp->dont_learn)
- md->gbp |= VXLAN_GBP_DONT_LEARN;
-
- if (gbp->policy_applied)
- md->gbp |= VXLAN_GBP_POLICY_APPLIED;
-
- /* In flow-based mode, GBP is carried in dst_metadata */
- if (!(vxflags & VXLAN_F_COLLECT_METADATA))
- skb->mark = md->gbp;
-out:
- unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS;
-}
-
-static bool vxlan_parse_gpe_hdr(struct vxlanhdr *unparsed,
- __be16 *protocol,
- struct sk_buff *skb, u32 vxflags)
-{
- struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)unparsed;
-
- /* Need to have Next Protocol set for interfaces in GPE mode. */
- if (!gpe->np_applied)
- return false;
- /* "The initial version is 0. If a receiver does not support the
- * version indicated it MUST drop the packet.
- */
- if (gpe->version != 0)
- return false;
- /* "When the O bit is set to 1, the packet is an OAM packet and OAM
- * processing MUST occur." However, we don't implement OAM
- * processing, thus drop the packet.
- */
- if (gpe->oam_flag)
- return false;
-
- *protocol = tun_p_to_eth_p(gpe->next_protocol);
- if (!*protocol)
- return false;
-
- unparsed->vx_flags &= ~VXLAN_GPE_USED_BITS;
- return true;
-}
-
-static bool vxlan_set_mac(struct vxlan_dev *vxlan,
- struct vxlan_sock *vs,
- struct sk_buff *skb)
-{
- return true;
-}
-
-static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph,
- struct sk_buff *skb)
-{
- int err = 0;
-
- if (vxlan_get_sk_family(vs) == AF_INET)
- err = IP_ECN_decapsulate(oiph, skb);
-#if IS_ENABLED(CONFIG_IPV6)
- else
- err = IP6_ECN_decapsulate(oiph, skb);
-#endif
- return err <= 1;
-}
-
-/* Callback from net/ipv4/udp.c to receive packets */
-static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
-{
- union {
- struct metadata_dst dst;
- char buf[sizeof(struct metadata_dst) + sizeof(struct vxlan_metadata)];
- } buf;
-
- struct pcpu_sw_netstats *stats;
- struct vxlan_dev *vxlan;
- struct vxlan_sock *vs;
- struct vxlanhdr unparsed;
- struct vxlan_metadata _md;
- struct vxlan_metadata *md = &_md;
- __be16 protocol = htons(ETH_P_TEB);
- bool raw_proto = false;
- void *oiph;
-
- /* Need UDP and VXLAN header to be present */
- if (!pskb_may_pull(skb, VXLAN_HLEN))
- goto drop;
-
- unparsed = *vxlan_hdr(skb);
- /* VNI flag always required to be set */
- if (!(unparsed.vx_flags & VXLAN_HF_VNI)) {
- netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
- ntohl(vxlan_hdr(skb)->vx_flags),
- ntohl(vxlan_hdr(skb)->vx_vni));
- /* Return non vxlan pkt */
- goto drop;
- }
-
- unparsed.vx_flags &= ~VXLAN_HF_VNI;
- unparsed.vx_vni &= ~VXLAN_VNI_MASK;
-
- vs = rcu_dereference_sk_user_data(sk);
- if (!vs)
- goto drop;
-
-#if IS_ENABLED(CONFIG_IPV6)
-#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
- if (vxlan_get_sk_family(vs) == AF_INET6 &&
- !udp_hdr(skb)->check &&
- !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
- udp6_csum_zero_error(skb);
- goto drop;
- }
-#endif
-#endif
- vxlan = vxlan_vs_find_vni(vs, vxlan_vni(vxlan_hdr(skb)->vx_vni));
- if (!vxlan)
- goto drop;
-
- /* For backwards compatibility, only allow reserved fields to be
- * used by VXLAN extensions if explicitly requested.
- */
- if (vs->flags & VXLAN_F_GPE) {
- if (!vxlan_parse_gpe_hdr(&unparsed, &protocol, skb, vs->flags))
- goto drop;
- raw_proto = true;
- }
-
- if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto,
- !net_eq(vxlan->net, dev_net(vxlan->dev))))
- goto drop;
-
- if (vxlan_collect_metadata(vs)) {
- __be32 vni = vxlan_vni(vxlan_hdr(skb)->vx_vni);
- struct metadata_dst *tun_dst;
-
- tun_dst = &buf.dst;
- ovs_udp_tun_rx_dst(tun_dst, skb,
- vxlan_get_sk_family(vs), TUNNEL_KEY,
- vxlan_vni_to_tun_id(vni), sizeof(*md));
-
- if (!tun_dst)
- goto drop;
-
- md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
-
- ovs_skb_dst_set(skb, (struct dst_entry *)tun_dst);
- } else {
- memset(md, 0, sizeof(*md));
- }
-
- if (vs->flags & VXLAN_F_REMCSUM_RX)
- if (!vxlan_remcsum(&unparsed, skb, vs->flags))
- goto drop;
-
- if (vs->flags & VXLAN_F_GBP)
- vxlan_parse_gbp_hdr(&unparsed, skb, vs->flags, md);
- /* Note that GBP and GPE can never be active together. This is
- * ensured in vxlan_dev_configure.
- */
-
- if (unparsed.vx_flags || unparsed.vx_vni) {
- /* If there are any unprocessed flags remaining treat
- * this as a malformed packet. This behavior diverges from
- * VXLAN RFC (RFC7348) which stipulates that bits in reserved
- * in reserved fields are to be ignored. The approach here
- * maintains compatibility with previous stack code, and also
- * is more robust and provides a little more security in
- * adding extensions to VXLAN.
- */
- goto drop;
- }
-
- if (!raw_proto) {
- if (!vxlan_set_mac(vxlan, vs, skb))
- goto drop;
- skb_reset_mac_header(skb);
- skb->protocol = eth_type_trans(skb, vxlan->dev);
- skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
- } else {
- skb_reset_mac_header(skb);
- skb->dev = vxlan->dev;
- skb->pkt_type = PACKET_HOST;
- }
-
- oiph = skb_network_header(skb);
- skb_reset_network_header(skb);
-
- if (!vxlan_ecn_decapsulate(vs, oiph, skb)) {
- ++vxlan->dev->stats.rx_frame_errors;
- ++vxlan->dev->stats.rx_errors;
- goto drop;
- }
-
- stats = this_cpu_ptr(vxlan->dev->tstats);
- u64_stats_update_begin(&stats->syncp);
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
- u64_stats_update_end(&stats->syncp);
-
- netdev_port_receive(skb, skb_tunnel_info(skb));
- return 0;
-
-drop:
- /* Consume bad packet */
- kfree_skb(skb);
- return 0;
-}
-
-static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
- struct vxlan_metadata *md)
-{
- struct vxlanhdr_gbp *gbp;
-
- if (!md->gbp)
- return;
-
- gbp = (struct vxlanhdr_gbp *)vxh;
- vxh->vx_flags |= VXLAN_HF_GBP;
-
- if (md->gbp & VXLAN_GBP_DONT_LEARN)
- gbp->dont_learn = 1;
-
- if (md->gbp & VXLAN_GBP_POLICY_APPLIED)
- gbp->policy_applied = 1;
-
- gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK);
-}
-
-static int vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags,
- __be16 protocol)
-{
- struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)vxh;
-
- gpe->np_applied = 1;
- gpe->next_protocol = tun_p_from_eth_p(protocol);
- if (!gpe->next_protocol)
- return -EPFNOSUPPORT;
- return 0;
-}
-
-static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
- int iphdr_len, __be32 vni,
- struct vxlan_metadata *md, u32 vxflags,
- bool udp_sum)
-{
- void (*fix_segment)(struct sk_buff *);
- struct vxlanhdr *vxh;
- int min_headroom;
- int err;
- int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
- __be16 inner_protocol = htons(ETH_P_TEB);
-
- if ((vxflags & VXLAN_F_REMCSUM_TX) &&
- skb->ip_summed == CHECKSUM_PARTIAL) {
- int csum_start = skb_checksum_start_offset(skb);
-
- if (csum_start <= VXLAN_MAX_REMCSUM_START &&
- !(csum_start & VXLAN_RCO_SHIFT_MASK) &&
- (skb->csum_offset == offsetof(struct udphdr, check) ||
- skb->csum_offset == offsetof(struct tcphdr, check)))
- type |= SKB_GSO_TUNNEL_REMCSUM;
- }
-
- min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len
- + VXLAN_HLEN + iphdr_len
- + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
-
- /* Need space for new headers (invalidates iph ptr) */
- err = skb_cow_head(skb, min_headroom);
- if (unlikely(err))
- goto out_free;
-
- if (skb_vlan_tag_present(skb))
- skb = __vlan_hwaccel_push_inside(skb);
- if (WARN_ON(!skb))
- return -ENOMEM;
-
- type |= udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
-#ifndef USE_UPSTREAM_TUNNEL_GSO
- fix_segment = !udp_sum ? ovs_udp_gso : ovs_udp_csum_gso;
-#else
- fix_segment = NULL;
-#endif
- err = ovs_iptunnel_handle_offloads(skb, type, fix_segment);
- if (err)
- goto out_free;
-
- vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
- vxh->vx_flags = VXLAN_HF_VNI;
- vxh->vx_vni = vxlan_vni_field(vni);
-
- if (type & SKB_GSO_TUNNEL_REMCSUM) {
- unsigned int start;
-
- start = skb_checksum_start_offset(skb) - sizeof(struct vxlanhdr);
- vxh->vx_vni |= vxlan_compute_rco(start, skb->csum_offset);
- vxh->vx_flags |= VXLAN_HF_RCO;
-
- if (!skb_is_gso(skb)) {
- skb->ip_summed = CHECKSUM_NONE;
- skb->encapsulation = 0;
- }
- }
-
- if (vxflags & VXLAN_F_GBP)
- vxlan_build_gbp_hdr(vxh, vxflags, md);
- if (vxflags & VXLAN_F_GPE) {
- err = vxlan_build_gpe_hdr(vxh, vxflags, skb->protocol);
- if (err < 0)
- goto out_free;
- inner_protocol = skb->protocol;
- }
-
- ovs_skb_set_inner_protocol(skb, inner_protocol);
- return 0;
-
-out_free:
- kfree_skb(skb);
- return err;
-}
-
-static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
- struct sk_buff *skb, int oif, u8 tos,
- __be32 daddr, __be32 *saddr,
- __be16 dport, __be16 sport,
- struct dst_cache *dst_cache,
- const struct ip_tunnel_info *info)
-{
- bool use_cache = (dst_cache && ip_tunnel_dst_cache_usable(skb, info));
- struct rtable *rt = NULL;
- struct flowi4 fl4;
-
- if (tos && !info)
- use_cache = false;
- if (use_cache) {
- rt = dst_cache_get_ip4(dst_cache, saddr);
- if (rt)
- return rt;
- }
-
- memset(&fl4, 0, sizeof(fl4));
- fl4.flowi4_oif = oif;
- fl4.flowi4_tos = RT_TOS(tos);
- fl4.flowi4_mark = skb->mark;
- fl4.flowi4_proto = IPPROTO_UDP;
- fl4.daddr = daddr;
- fl4.saddr = *saddr;
- fl4.fl4_dport = dport;
- fl4.fl4_sport = sport;
-
- rt = ip_route_output_key(vxlan->net, &fl4);
- if (!IS_ERR(rt)) {
- *saddr = fl4.saddr;
- if (use_cache)
- dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr);
- }
- return rt;
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
- struct sk_buff *skb, int oif, u8 tos,
- __be32 label,
- const struct in6_addr *daddr,
- struct in6_addr *saddr,
- __be16 dport, __be16 sport,
- struct dst_cache *dst_cache,
- const struct ip_tunnel_info *info)
-{
- struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
- bool use_cache = (dst_cache && ip_tunnel_dst_cache_usable(skb, info));
- struct dst_entry *ndst;
- struct flowi6 fl6;
-#if !defined(HAVE_IPV6_STUB_WITH_DST_ENTRY) || \
- !defined(HAVE_IPV6_DST_LOOKUP_FLOW)
- int err;
-#endif
-
- if (!sock6)
- return ERR_PTR(-EIO);
-
- if (tos && !info)
- use_cache = false;
- if (use_cache) {
- ndst = dst_cache_get_ip6(dst_cache, saddr);
- if (ndst)
- return ndst;
- }
-
- memset(&fl6, 0, sizeof(fl6));
- fl6.flowi6_oif = oif;
- fl6.daddr = *daddr;
- fl6.saddr = *saddr;
- fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tos), label);
- fl6.flowi6_mark = skb->mark;
- fl6.flowi6_proto = IPPROTO_UDP;
- fl6.fl6_dport = dport;
- fl6.fl6_sport = sport;
-
-#if defined(HAVE_IPV6_STUB_WITH_DST_ENTRY) && defined(HAVE_IPV6_DST_LOOKUP_FLOW)
-#ifdef HAVE_IPV6_DST_LOOKUP_FLOW_NET
- ndst = ipv6_stub->ipv6_dst_lookup_flow(vxlan->net, sock6->sock->sk,
- &fl6, NULL);
-#else
- ndst = ipv6_stub->ipv6_dst_lookup_flow(sock6->sock->sk, &fl6, NULL);
-#endif
- if (unlikely(IS_ERR(ndst))) {
-#elif defined(HAVE_IPV6_DST_LOOKUP_FLOW_NET)
- err = ipv6_stub->ipv6_dst_lookup_flow(vxlan->net, sock6->sock->sk,
- &ndst, &fl6);
-#elif defined(HAVE_IPV6_DST_LOOKUP_FLOW)
- err = ipv6_stub->ipv6_dst_lookup_flow(sock6->sock->sk, &ndst, &fl6);
-#elif defined(HAVE_IPV6_DST_LOOKUP_NET)
- err = ipv6_stub->ipv6_dst_lookup(vxlan->net, sock6->sock->sk,
- &ndst, &fl6);
-#elif defined(HAVE_IPV6_STUB)
- err = ipv6_stub->ipv6_dst_lookup(vxlan->vn6_sock->sock->sk,
- &ndst, &fl6);
-#else
- err = ip6_dst_lookup(vxlan->vn6_sock->sock->sk, &ndst, &fl6);
-#endif
-#if defined(HAVE_IPV6_STUB_WITH_DST_ENTRY) && defined(HAVE_IPV6_DST_LOOKUP_FLOW)
- return ERR_PTR(-ENETUNREACH);
- }
-#else
- if (err < 0)
- return ERR_PTR(err);
-#endif
-
- *saddr = fl6.saddr;
- if (use_cache)
- dst_cache_set_ip6(dst_cache, ndst, saddr);
- return ndst;
-}
-#endif
-
-/* Bypass encapsulation if the destination is local */
-static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
- struct vxlan_dev *dst_vxlan)
-{
- skb->dev->stats.rx_dropped++;
- kfree_skb(skb);
-}
-
-static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
- struct vxlan_rdst *rdst, bool did_rsc)
-{
- struct dst_cache *dst_cache;
- struct ip_tunnel_info *info;
- struct vxlan_dev *vxlan = netdev_priv(dev);
- struct sock *sk;
- struct rtable *rt = NULL;
- const struct iphdr *old_iph;
- union vxlan_addr *dst;
- union vxlan_addr remote_ip, local_ip;
- union vxlan_addr *src;
- struct vxlan_metadata _md;
- struct vxlan_metadata *md = &_md;
- __be16 src_port = 0, dst_port;
- __be32 vni, label;
- __be16 df = 0;
- __u8 tos, ttl;
- int err;
- u32 flags = vxlan->flags;
- bool udp_sum = false;
- bool xnet = !net_eq(vxlan->net, dev_net(vxlan->dev));
-
- info = skb_tunnel_info(skb);
-
- if (rdst) {
- dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;
- vni = rdst->remote_vni;
- dst = &rdst->remote_ip;
- src = &vxlan->cfg.saddr;
- dst_cache = &rdst->dst_cache;
- } else {
- if (!info) {
- WARN_ONCE(1, "%s: Missing encapsulation instructions\n",
- dev->name);
- goto drop;
- }
- dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port;
- vni = vxlan_tun_id_to_vni(info->key.tun_id);
- remote_ip.sa.sa_family = ip_tunnel_info_af(info);
- if (remote_ip.sa.sa_family == AF_INET) {
- remote_ip.sin.sin_addr.s_addr = info->key.u.ipv4.dst;
- local_ip.sin.sin_addr.s_addr = info->key.u.ipv4.src;
- } else {
- remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst;
- local_ip.sin6.sin6_addr = info->key.u.ipv6.src;
- }
- dst = &remote_ip;
- src = &local_ip;
- dst_cache = &info->dst_cache;
- }
-
- if (vxlan_addr_any(dst)) {
- if (did_rsc) {
- /* short-circuited back to local bridge */
- vxlan_encap_bypass(skb, vxlan, vxlan);
- return;
- }
- goto drop;
- }
-
- old_iph = ip_hdr(skb);
-
- ttl = vxlan->cfg.ttl;
- if (!ttl && vxlan_addr_multicast(dst))
- ttl = 1;
-
- tos = vxlan->cfg.tos;
- if (tos == 1)
- tos = ip_tunnel_get_dsfield(old_iph, skb);
-
- label = vxlan->cfg.label;
- src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min,
- vxlan->cfg.port_max, true);
-
- if (info) {
- ttl = info->key.ttl;
- tos = info->key.tos;
- label = info->key.label;
- udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
-
- if (info->options_len &&
- info->key.tun_flags & TUNNEL_VXLAN_OPT)
- md = ip_tunnel_info_opts(info);
- } else {
- md->gbp = skb->mark;
- }
-
- if (dst->sa.sa_family == AF_INET) {
- struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
-
- if (!sock4)
- goto drop;
- sk = sock4->sock->sk;
-
- rt = vxlan_get_route(vxlan, skb,
- rdst ? rdst->remote_ifindex : 0, tos,
- dst->sin.sin_addr.s_addr,
- &src->sin.sin_addr.s_addr,
- dst_port, src_port,
- dst_cache, info);
- if (IS_ERR(rt)) {
- netdev_dbg(dev, "no route to %pI4\n",
- &dst->sin.sin_addr.s_addr);
- dev->stats.tx_carrier_errors++;
- goto tx_error;
- }
-
- if (rt->dst.dev == dev) {
- netdev_dbg(dev, "circular route to %pI4\n",
- &dst->sin.sin_addr.s_addr);
- dev->stats.collisions++;
- goto rt_tx_error;
- }
-
- /* Bypass encapsulation if the destination is local */
- if (!info && rt->rt_flags & RTCF_LOCAL &&
- !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
- struct vxlan_dev *dst_vxlan;
-
- ip_rt_put(rt);
- dst_vxlan = vxlan_find_vni(vxlan->net, vni,
- dst->sa.sa_family, dst_port,
- vxlan->flags);
- if (!dst_vxlan)
- goto tx_error;
- vxlan_encap_bypass(skb, vxlan, dst_vxlan);
- return;
- }
-
- if (!info)
- udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM_TX);
- else if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)
- df = htons(IP_DF);
-
- tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
- ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
- err = vxlan_build_skb(skb, &rt->dst, sizeof(struct iphdr),
- vni, md, flags, udp_sum);
- if (err < 0)
- goto xmit_tx_error;
-
- udp_tunnel_xmit_skb(rt, sk, skb, src->sin.sin_addr.s_addr,
- dst->sin.sin_addr.s_addr, tos, ttl, df,
- src_port, dst_port, xnet, !udp_sum);
-#if IS_ENABLED(CONFIG_IPV6)
- } else {
- struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
- struct dst_entry *ndst;
- u32 rt6i_flags;
-
- if (!sock6)
- goto drop;
- sk = sock6->sock->sk;
-
- ndst = vxlan6_get_route(vxlan, skb,
- rdst ? rdst->remote_ifindex : 0, tos,
- label, &dst->sin6.sin6_addr,
- &src->sin6.sin6_addr,
- dst_port, src_port,
- dst_cache, info);
- if (IS_ERR(ndst)) {
- netdev_dbg(dev, "no route to %pI6\n",
- &dst->sin6.sin6_addr);
- dev->stats.tx_carrier_errors++;
- goto tx_error;
- }
-
- if (ndst->dev == dev) {
- netdev_dbg(dev, "circular route to %pI6\n",
- &dst->sin6.sin6_addr);
- dst_release(ndst);
- dev->stats.collisions++;
- goto tx_error;
- }
-
- /* Bypass encapsulation if the destination is local */
- rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags;
- if (!info && rt6i_flags & RTF_LOCAL &&
- !(rt6i_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
- struct vxlan_dev *dst_vxlan;
-
- dst_release(ndst);
- dst_vxlan = vxlan_find_vni(vxlan->net, vni,
- dst->sa.sa_family, dst_port,
- vxlan->flags);
- if (!dst_vxlan)
- goto tx_error;
- vxlan_encap_bypass(skb, vxlan, dst_vxlan);
- return;
- }
-
- if (!info)
- udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
-
- tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
- ttl = ttl ? : ip6_dst_hoplimit(ndst);
- skb_scrub_packet(skb, xnet);
- err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr),
- vni, md, flags, udp_sum);
- if (err < 0) {
- dst_release(ndst);
- return;
- }
- udp_tunnel6_xmit_skb(ndst, sk, skb, dev,
- &src->sin6.sin6_addr,
- &dst->sin6.sin6_addr, tos, ttl,
- label, src_port, dst_port, !udp_sum);
-#endif
- }
-
- return;
-
-drop:
- dev->stats.tx_dropped++;
- goto tx_free;
-
-xmit_tx_error:
- /* skb is already freed. */
- skb = NULL;
-rt_tx_error:
- ip_rt_put(rt);
-tx_error:
- dev->stats.tx_errors++;
-tx_free:
- dev_kfree_skb(skb);
-}
-
-/* Transmit local packets over Vxlan
- *
- * Outer IP header inherits ECN and DF from inner header.
- * Outer UDP destination is the VXLAN assigned port.
- * source port is based on hash of flow
- */
-netdev_tx_t rpl_vxlan_xmit(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- struct vxlan_dev *vxlan = netdev_priv(dev);
- const struct ip_tunnel_info *info;
-
- info = skb_tunnel_info(skb);
- skb_reset_mac_header(skb);
- if (vxlan->flags & VXLAN_F_COLLECT_METADATA) {
- if (info && info->mode & IP_TUNNEL_INFO_TX) {
- vxlan_xmit_one(skb, dev, NULL, false);
- return NETDEV_TX_OK;
- }
- }
-
- dev->stats.tx_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-EXPORT_SYMBOL_GPL(rpl_vxlan_xmit);
-
-/* Walk the forwarding table and purge stale entries */
-#ifdef HAVE_INIT_TIMER_DEFERRABLE
-static void vxlan_cleanup(unsigned long arg)
-{
- struct vxlan_dev *vxlan = (struct vxlan_dev *) arg;
-#else
-static void vxlan_cleanup(struct timer_list *t)
-{
- struct vxlan_dev *vxlan = from_timer(vxlan, t, age_timer);
-#endif
- unsigned long next_timer = jiffies + FDB_AGE_INTERVAL;
- unsigned int h;
-
- if (!netif_running(vxlan->dev))
- return;
-
- for (h = 0; h < FDB_HASH_SIZE; ++h) {
- struct hlist_node *p, *n;
-
- spin_lock_bh(&vxlan->hash_lock);
- hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
- struct vxlan_fdb *f
- = container_of(p, struct vxlan_fdb, hlist);
- unsigned long timeout;
-
- if (f->state & NUD_PERMANENT)
- continue;
-
- timeout = f->used + vxlan->cfg.age_interval * HZ;
- if (time_before_eq(timeout, jiffies)) {
- netdev_dbg(vxlan->dev,
- "garbage collect %pM\n",
- f->eth_addr);
- f->state = NUD_STALE;
- vxlan_fdb_destroy(vxlan, f);
- } else if (time_before(timeout, next_timer))
- next_timer = timeout;
- }
- spin_unlock_bh(&vxlan->hash_lock);
- }
-
- mod_timer(&vxlan->age_timer, next_timer);
-}
-
-static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
-{
- struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
- __be32 vni = vxlan->default_dst.remote_vni;
-
- spin_lock(&vn->sock_lock);
- hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni));
- spin_unlock(&vn->sock_lock);
-}
-
-/* Setup stats when device is created */
-static int vxlan_init(struct net_device *dev)
-{
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- return 0;
-}
-
-static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan)
-{
-}
-
-static void vxlan_uninit(struct net_device *dev)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
-
- vxlan_fdb_delete_default(vxlan);
-
- free_percpu(dev->tstats);
-}
-
-/* Start ageing timer and join group when device is brought up */
-static int vxlan_open(struct net_device *dev)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
- int ret;
-
- ret = vxlan_sock_add(vxlan);
- if (ret < 0)
- return ret;
-
- if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) {
- ret = vxlan_igmp_join(vxlan);
- if (ret == -EADDRINUSE)
- ret = 0;
- if (ret) {
- vxlan_sock_release(vxlan);
- return ret;
- }
- }
-
- if (vxlan->cfg.age_interval)
- mod_timer(&vxlan->age_timer, jiffies + FDB_AGE_INTERVAL);
-
- return ret;
-}
-
-/* Purge the forwarding table */
-static void vxlan_flush(struct vxlan_dev *vxlan)
-{
- unsigned int h;
-
- spin_lock_bh(&vxlan->hash_lock);
- for (h = 0; h < FDB_HASH_SIZE; ++h) {
- struct hlist_node *p, *n;
- hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
- struct vxlan_fdb *f
- = container_of(p, struct vxlan_fdb, hlist);
- /* the all_zeros_mac entry is deleted at vxlan_uninit */
- if (!is_zero_ether_addr(f->eth_addr))
- vxlan_fdb_destroy(vxlan, f);
- }
- }
- spin_unlock_bh(&vxlan->hash_lock);
-}
-
-/* Cleanup timer and forwarding table on shutdown */
-static int vxlan_stop(struct net_device *dev)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
- struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
- int ret = 0;
-
- if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip) &&
- !vxlan_group_used(vn, vxlan))
- ret = vxlan_igmp_leave(vxlan);
-
- del_timer_sync(&vxlan->age_timer);
-
- vxlan_flush(vxlan);
- vxlan_sock_release(vxlan);
-
- return ret;
-}
-
-/* Stub, nothing needs to be done. */
-static void vxlan_set_multicast_list(struct net_device *dev)
-{
-}
-
-static int __vxlan_change_mtu(struct net_device *dev,
- struct net_device *lowerdev,
- struct vxlan_rdst *dst, int new_mtu, bool strict)
-{
- int max_mtu = IP_MAX_MTU;
-
- if (lowerdev)
- max_mtu = lowerdev->mtu;
-
- if (dst->remote_ip.sa.sa_family == AF_INET6)
- max_mtu -= VXLAN6_HEADROOM;
- else
- max_mtu -= VXLAN_HEADROOM;
-
- if (new_mtu < 68)
- return -EINVAL;
-
- if (new_mtu > max_mtu) {
- if (strict)
- return -EINVAL;
-
- new_mtu = max_mtu;
- }
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
- struct vxlan_rdst *dst = &vxlan->default_dst;
- struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
- dst->remote_ifindex);
- return __vxlan_change_mtu(dev, lowerdev, dst, new_mtu, true);
-}
-
-int ovs_vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
- struct ip_tunnel_info *info = skb_tunnel_info(skb);
- __be16 sport, dport;
-
- sport = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min,
- vxlan->cfg.port_max, true);
- dport = info->key.tp_dst ? : vxlan->cfg.dst_port;
-
- if (ip_tunnel_info_af(info) == AF_INET) {
- struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
- struct rtable *rt;
-
- if (!sock4)
- return -EINVAL;
- rt = vxlan_get_route(vxlan, skb, 0, info->key.tos,
- info->key.u.ipv4.dst,
- &info->key.u.ipv4.src,
- dport, sport, NULL, info);
- if (IS_ERR(rt))
- return PTR_ERR(rt);
- ip_rt_put(rt);
- } else {
-#if IS_ENABLED(CONFIG_IPV6)
- struct dst_entry *ndst;
-
- ndst = vxlan6_get_route(vxlan, skb, 0, info->key.tos,
- info->key.label, &info->key.u.ipv6.dst,
- &info->key.u.ipv6.src,
- dport, sport, NULL, info);
- if (IS_ERR(ndst))
- return PTR_ERR(ndst);
- dst_release(ndst);
-#else /* !CONFIG_IPV6 */
- return -EPFNOSUPPORT;
-#endif
- }
- info->key.tp_src = sport;
- info->key.tp_dst = dport;
- return 0;
-}
-EXPORT_SYMBOL_GPL(ovs_vxlan_fill_metadata_dst);
-
-static netdev_tx_t vxlan_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;
-}
-
-static const struct net_device_ops vxlan_netdev_ether_ops = {
- .ndo_init = vxlan_init,
- .ndo_uninit = vxlan_uninit,
- .ndo_open = vxlan_open,
- .ndo_stop = vxlan_stop,
- .ndo_start_xmit = vxlan_dev_xmit,
- .ndo_get_stats64 = ip_tunnel_get_stats64,
- .ndo_set_rx_mode = vxlan_set_multicast_list,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = vxlan_change_mtu,
-#else
- .ndo_change_mtu = vxlan_change_mtu,
-#endif
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
-#ifdef HAVE_NDO_FILL_METADATA_DST
- .ndo_fill_metadata_dst = ovs_vxlan_fill_metadata_dst,
-#endif
-};
-
-static const struct net_device_ops vxlan_netdev_raw_ops = {
- .ndo_init = vxlan_init,
- .ndo_uninit = vxlan_uninit,
- .ndo_open = vxlan_open,
- .ndo_stop = vxlan_stop,
- .ndo_start_xmit = vxlan_dev_xmit,
- .ndo_get_stats64 = ip_tunnel_get_stats64,
-#ifdef HAVE_RHEL7_MAX_MTU
- .ndo_size = sizeof(struct net_device_ops),
- .extended.ndo_change_mtu = vxlan_change_mtu,
-#else
- .ndo_change_mtu = vxlan_change_mtu,
-#endif
-#ifdef HAVE_NDO_FILL_METADATA_DST
- .ndo_fill_metadata_dst = ovs_vxlan_fill_metadata_dst,
-#endif
-};
-
-/* Info for udev, that this is a virtual tunnel endpoint */
-static struct device_type vxlan_type = {
- .name = "vxlan",
-};
-
-/* Calls the ndo_add_vxlan_port or ndo_udp_tunnel_add of the caller
- * in order to supply the listening VXLAN udp ports. Callers are
- * expected to implement the ndo_add_vxlan_port.
- */
-static void vxlan_push_rx_ports(struct net_device *dev)
-{
-#ifdef HAVE_NDO_ADD_VXLAN_PORT
- struct vxlan_sock *vs;
- struct net *net = dev_net(dev);
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- sa_family_t sa_family;
- __be16 port;
- unsigned int i;
-
- if (!dev->netdev_ops->ndo_add_vxlan_port)
- return;
-
- spin_lock(&vn->sock_lock);
- for (i = 0; i < PORT_HASH_SIZE; ++i) {
- hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
- port = inet_sk(vs->sock->sk)->inet_sport;
- sa_family = vxlan_get_sk_family(vs);
- dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
- port);
- }
- }
- spin_unlock(&vn->sock_lock);
-#elif defined(HAVE_NDO_UDP_TUNNEL_ADD)
- struct vxlan_sock *vs;
- struct net *net = dev_net(dev);
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- unsigned int i;
-
- if (!dev->netdev_ops->ndo_udp_tunnel_add)
- return;
-
- spin_lock(&vn->sock_lock);
- for (i = 0; i < PORT_HASH_SIZE; ++i) {
- hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
- struct udp_tunnel_info ti;
- if (vs->flags & VXLAN_F_GPE)
- ti.type = UDP_TUNNEL_TYPE_VXLAN_GPE;
- else
- ti.type = UDP_TUNNEL_TYPE_VXLAN;
- ti.port = inet_sk(vs->sock->sk)->inet_sport;
- ti.sa_family = vxlan_get_sk_family(vs);
-
- dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti);
- }
- }
- spin_unlock(&vn->sock_lock);
-#endif
-}
-
-/* Initialize the device structure. */
-static void vxlan_setup(struct net_device *dev)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
- unsigned int h;
-
- eth_hw_addr_random(dev);
- ether_setup(dev);
-
-#ifndef HAVE_NEEDS_FREE_NETDEV
- dev->destructor = free_netdev;
-#else
- dev->needs_free_netdev = true;
-#endif
- SET_NETDEV_DEVTYPE(dev, &vxlan_type);
-
- dev->features |= NETIF_F_LLTX;
- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->features |= NETIF_F_RXCSUM;
- dev->features |= NETIF_F_GSO_SOFTWARE;
-
- dev->vlan_features = dev->features;
- dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
- dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
- dev->hw_features |= NETIF_F_GSO_SOFTWARE;
- dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
-#if 0
- netif_keep_dst(dev);
-#endif
- dev->priv_flags |= IFF_NO_QUEUE;
-
- INIT_LIST_HEAD(&vxlan->next);
- spin_lock_init(&vxlan->hash_lock);
-
-#ifdef HAVE_INIT_TIMER_DEFERRABLE
- init_timer_deferrable(&vxlan->age_timer);
- vxlan->age_timer.function = vxlan_cleanup;
- vxlan->age_timer.data = (unsigned long) vxlan;
-#else
- timer_setup(&vxlan->age_timer, vxlan_cleanup, TIMER_DEFERRABLE);
-#endif
-
- vxlan->cfg.dst_port = htons(vxlan_port);
-
- vxlan->dev = dev;
-
- for (h = 0; h < FDB_HASH_SIZE; ++h)
- INIT_HLIST_HEAD(&vxlan->fdb_head[h]);
-}
-
-static void vxlan_ether_setup(struct net_device *dev)
-{
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
- dev->netdev_ops = &vxlan_netdev_ether_ops;
-}
-
-static void vxlan_raw_setup(struct net_device *dev)
-{
- dev->header_ops = NULL;
- dev->type = ARPHRD_NONE;
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
- dev->netdev_ops = &vxlan_netdev_raw_ops;
-}
-
-static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
- [IFLA_VXLAN_ID] = { .type = NLA_U32 },
- [IFLA_VXLAN_GROUP] = { .len = sizeof_field(struct iphdr, daddr) },
- [IFLA_VXLAN_GROUP6] = { .len = sizeof(struct in6_addr) },
- [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
- [IFLA_VXLAN_LOCAL] = { .len = sizeof_field(struct iphdr, saddr) },
- [IFLA_VXLAN_LOCAL6] = { .len = sizeof(struct in6_addr) },
- [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
- [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
- [IFLA_VXLAN_LABEL] = { .type = NLA_U32 },
- [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
- [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
- [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
- [IFLA_VXLAN_PORT_RANGE] = { .len = sizeof(struct ifla_vxlan_port_range) },
- [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
- [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
- [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
- [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
- [IFLA_VXLAN_COLLECT_METADATA] = { .type = NLA_U8 },
- [IFLA_VXLAN_PORT] = { .type = NLA_U16 },
- [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 },
- [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
- [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
- [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 },
- [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 },
- [IFLA_VXLAN_GBP] = { .type = NLA_FLAG, },
- [IFLA_VXLAN_GPE] = { .type = NLA_FLAG, },
- [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG },
-};
-
-#ifdef HAVE_RTNLOP_VALIDATE_WITH_EXTACK
-static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- if (tb[IFLA_ADDRESS]) {
- if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
- pr_debug("invalid link address (not ethernet)\n");
- return -EINVAL;
- }
-
- if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
- pr_debug("invalid all zero ethernet address\n");
- return -EADDRNOTAVAIL;
- }
- }
-
- if (!data)
- return -EINVAL;
-
- if (data[IFLA_VXLAN_ID]) {
- __u32 id = nla_get_u32(data[IFLA_VXLAN_ID]);
- if (id >= VXLAN_VID_MASK)
- return -ERANGE;
- }
-
- if (data[IFLA_VXLAN_PORT_RANGE]) {
- const struct ifla_vxlan_port_range *p
- = nla_data(data[IFLA_VXLAN_PORT_RANGE]);
-
- if (ntohs(p->high) < ntohs(p->low)) {
- pr_debug("port range %u .. %u not valid\n",
- ntohs(p->low), ntohs(p->high));
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static void vxlan_get_drvinfo(struct net_device *netdev,
- struct ethtool_drvinfo *drvinfo)
-{
- strlcpy(drvinfo->version, VXLAN_VERSION, sizeof(drvinfo->version));
- strlcpy(drvinfo->driver, "vxlan", sizeof(drvinfo->driver));
-}
-
-static const struct ethtool_ops vxlan_ethtool_ops = {
- .get_drvinfo = vxlan_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-
-static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
- __be16 port, u32 flags)
-{
- struct socket *sock;
- struct udp_port_cfg udp_conf;
- int err;
-
- memset(&udp_conf, 0, sizeof(udp_conf));
-
- if (ipv6) {
- udp_conf.family = AF_INET6;
- udp_conf.use_udp6_rx_checksums =
- !(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
- udp_conf.ipv6_v6only = 1;
- } else {
- udp_conf.family = AF_INET;
- }
-
- 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 struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6,
- __be16 port, u32 flags)
-{
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- struct vxlan_sock *vs;
- struct socket *sock;
- unsigned int h;
- struct udp_tunnel_sock_cfg tunnel_cfg;
-
- vs = kzalloc(sizeof(*vs), GFP_KERNEL);
- if (!vs)
- return ERR_PTR(-ENOMEM);
-
- for (h = 0; h < VNI_HASH_SIZE; ++h)
- INIT_HLIST_HEAD(&vs->vni_list[h]);
-
- sock = vxlan_create_sock(net, ipv6, port, flags);
- if (IS_ERR(sock)) {
- kfree(vs);
- return ERR_CAST(sock);
- }
-
- vs->sock = sock;
- atomic_set(&vs->refcnt, 1);
- vs->flags = (flags & VXLAN_F_RCV_FLAGS);
-
-#ifdef HAVE_UDP_OFFLOAD
- vs->udp_offloads.port = port;
- vs->udp_offloads.callbacks.gro_receive = vxlan_gro_receive;
- vs->udp_offloads.callbacks.gro_complete = vxlan_gro_complete;
-#endif
-
- spin_lock(&vn->sock_lock);
- hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
- vxlan_notify_add_rx_port(vs);
- spin_unlock(&vn->sock_lock);
-
- /* Mark socket as an encapsulation socket. */
- memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
- tunnel_cfg.sk_user_data = vs;
- tunnel_cfg.encap_type = 1;
- tunnel_cfg.encap_rcv = vxlan_rcv;
- tunnel_cfg.encap_destroy = NULL;
-#ifdef HAVE_UDP_TUNNEL_SOCK_CFG_GRO_RECEIVE
- tunnel_cfg.gro_receive = vxlan_gro_receive;
- tunnel_cfg.gro_complete = vxlan_gro_complete;
-#endif
- setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
-
- return vs;
-}
-
-static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6)
-{
- struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
- struct vxlan_sock *vs = NULL;
-
- if (!vxlan->cfg.no_share) {
- spin_lock(&vn->sock_lock);
- vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
- vxlan->cfg.dst_port, vxlan->flags);
- if (vs && !atomic_add_unless(&vs->refcnt, 1, 0)) {
- spin_unlock(&vn->sock_lock);
- return -EBUSY;
- }
- spin_unlock(&vn->sock_lock);
- }
- if (!vs)
- vs = vxlan_socket_create(vxlan->net, ipv6,
- vxlan->cfg.dst_port, vxlan->flags);
- if (IS_ERR(vs))
- return PTR_ERR(vs);
-#if IS_ENABLED(CONFIG_IPV6)
- if (ipv6)
- rcu_assign_pointer(vxlan->vn6_sock, vs);
- else
-#endif
- rcu_assign_pointer(vxlan->vn4_sock, vs);
- vxlan_vs_add_dev(vs, vxlan);
- return 0;
-}
-
-static int vxlan_sock_add(struct vxlan_dev *vxlan)
-{
- bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA;
- bool ipv6 = vxlan->flags & VXLAN_F_IPV6 || metadata;
- bool ipv4 = !ipv6 || metadata;
- int ret = 0;
-
- RCU_INIT_POINTER(vxlan->vn4_sock, NULL);
-#if IS_ENABLED(CONFIG_IPV6)
- RCU_INIT_POINTER(vxlan->vn6_sock, NULL);
- if (ipv6) {
- ret = __vxlan_sock_add(vxlan, true);
- if (ret < 0 && ret != -EAFNOSUPPORT)
- ipv4 = false;
- }
-#endif
- if (ipv4)
- ret = __vxlan_sock_add(vxlan, false);
- if (ret < 0)
- vxlan_sock_release(vxlan);
- return ret;
-}
-
-static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
- struct vxlan_config *conf)
-{
- struct vxlan_net *vn = net_generic(src_net, vxlan_net_id);
- struct vxlan_dev *vxlan = netdev_priv(dev), *tmp;
- struct vxlan_rdst *dst = &vxlan->default_dst;
- unsigned short needed_headroom = ETH_HLEN;
- int err;
- bool use_ipv6 = false;
- __be16 default_port = vxlan->cfg.dst_port;
- struct net_device *lowerdev = NULL;
-
- if (conf->flags & VXLAN_F_GPE) {
- if (conf->flags & ~VXLAN_F_ALLOWED_GPE)
- return -EINVAL;
- /* For now, allow GPE only together with COLLECT_METADATA.
- * This can be relaxed later; in such case, the other side
- * of the PtP link will have to be provided.
- */
- if (!(conf->flags & VXLAN_F_COLLECT_METADATA))
- return -EINVAL;
-
- vxlan_raw_setup(dev);
- } else {
- vxlan_ether_setup(dev);
- }
-
- vxlan->net = src_net;
-
- dst->remote_vni = conf->vni;
-
- memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip));
-
- /* Unless IPv6 is explicitly requested, assume IPv4 */
- if (!dst->remote_ip.sa.sa_family)
- dst->remote_ip.sa.sa_family = AF_INET;
-
- if (dst->remote_ip.sa.sa_family == AF_INET6 ||
- vxlan->cfg.saddr.sa.sa_family == AF_INET6) {
- if (!IS_ENABLED(CONFIG_IPV6))
- return -EPFNOSUPPORT;
- use_ipv6 = true;
- vxlan->flags |= VXLAN_F_IPV6;
- }
-
- if (conf->label && !use_ipv6) {
- pr_info("label only supported in use with IPv6\n");
- return -EINVAL;
- }
-
- if (conf->remote_ifindex) {
- lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
- dst->remote_ifindex = conf->remote_ifindex;
-
- if (!lowerdev) {
- pr_info("ifindex %d does not exist\n", dst->remote_ifindex);
- return -ENODEV;
- }
-
-#if IS_ENABLED(CONFIG_IPV6)
- if (use_ipv6) {
- struct inet6_dev *idev = __in6_dev_get(lowerdev);
- if (idev && idev->cnf.disable_ipv6) {
- pr_info("IPv6 is disabled via sysctl\n");
- return -EPERM;
- }
- }
-#endif
-
- if (!conf->mtu)
- dev->mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
-
- needed_headroom = lowerdev->hard_header_len;
- }
-
- if (conf->mtu) {
- err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false);
- if (err)
- return err;
- }
-
- if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
- needed_headroom += VXLAN6_HEADROOM;
- else
- needed_headroom += VXLAN_HEADROOM;
- dev->needed_headroom = needed_headroom;
-
- memcpy(&vxlan->cfg, conf, sizeof(*conf));
- if (!vxlan->cfg.dst_port) {
- if (conf->flags & VXLAN_F_GPE)
- vxlan->cfg.dst_port = 4790; /* IANA assigned VXLAN-GPE port */
- else
- vxlan->cfg.dst_port = default_port;
- }
- vxlan->flags |= conf->flags;
-
- if (!vxlan->cfg.age_interval)
- vxlan->cfg.age_interval = FDB_AGE_DEFAULT;
-
- list_for_each_entry(tmp, &vn->vxlan_list, next) {
- if (tmp->cfg.vni == conf->vni &&
- (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 ||
- tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 &&
- tmp->cfg.dst_port == vxlan->cfg.dst_port &&
- (tmp->flags & VXLAN_F_RCV_FLAGS) ==
- (vxlan->flags & VXLAN_F_RCV_FLAGS))
- return -EEXIST;
- }
-
- dev->ethtool_ops = &vxlan_ethtool_ops;
-
- /* create an fdb entry for a valid default destination */
- if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) {
- err = vxlan_fdb_create(vxlan, all_zeros_mac,
- &vxlan->default_dst.remote_ip,
- NUD_REACHABLE|NUD_PERMANENT,
- NLM_F_EXCL|NLM_F_CREATE,
- vxlan->cfg.dst_port,
- vxlan->default_dst.remote_vni,
- vxlan->default_dst.remote_ifindex,
- NTF_SELF);
- if (err)
- return err;
- }
-
- err = register_netdevice(dev);
- if (err) {
- vxlan_fdb_delete_default(vxlan);
- return err;
- }
-
- list_add(&vxlan->next, &vn->vxlan_list);
-
- return 0;
-}
-
-#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
-static int vxlan_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-#else
-static int vxlan_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-#endif
-{
- pr_info("unsupported operation\n");
- return -EINVAL;
-}
-
-static void vxlan_dellink(struct net_device *dev, struct list_head *head)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
- struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
-
- spin_lock(&vn->sock_lock);
- if (!hlist_unhashed(&vxlan->hlist))
- hlist_del_rcu(&vxlan->hlist);
- spin_unlock(&vn->sock_lock);
-
- list_del(&vxlan->next);
- unregister_netdevice_queue(dev, head);
-}
-
-static size_t vxlan_get_size(const struct net_device *dev)
-{
-
- return nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_ID */
- nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_GROUP{6} */
- nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LINK */
- nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_LOCAL{6} */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TTL */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TOS */
- nla_total_size(sizeof(__be32)) + /* IFLA_VXLAN_LABEL */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_PROXY */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_RSC */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L2MISS */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L3MISS */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_COLLECT_METADATA */
- nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */
- nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */
- nla_total_size(sizeof(struct ifla_vxlan_port_range)) +
- nla_total_size(sizeof(__be16)) + /* IFLA_VXLAN_PORT */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_CSUM */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_TX */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */
- nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */
- 0;
-}
-
-static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- const struct vxlan_dev *vxlan = netdev_priv(dev);
- const struct vxlan_rdst *dst = &vxlan->default_dst;
- struct ifla_vxlan_port_range ports = {
- .low = htons(vxlan->cfg.port_min),
- .high = htons(vxlan->cfg.port_max),
- };
-
- if (nla_put_u32(skb, IFLA_VXLAN_ID, be32_to_cpu(dst->remote_vni)))
- goto nla_put_failure;
-
- if (!vxlan_addr_any(&dst->remote_ip)) {
- if (dst->remote_ip.sa.sa_family == AF_INET) {
- if (nla_put_in_addr(skb, IFLA_VXLAN_GROUP,
- dst->remote_ip.sin.sin_addr.s_addr))
- goto nla_put_failure;
-#if IS_ENABLED(CONFIG_IPV6)
- } else {
- if (nla_put_in6_addr(skb, IFLA_VXLAN_GROUP6,
- &dst->remote_ip.sin6.sin6_addr))
- goto nla_put_failure;
-#endif
- }
- }
-
- if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex))
- goto nla_put_failure;
-
- if (!vxlan_addr_any(&vxlan->cfg.saddr)) {
- if (vxlan->cfg.saddr.sa.sa_family == AF_INET) {
- if (nla_put_in_addr(skb, IFLA_VXLAN_LOCAL,
- vxlan->cfg.saddr.sin.sin_addr.s_addr))
- goto nla_put_failure;
-#if IS_ENABLED(CONFIG_IPV6)
- } else {
- if (nla_put_in6_addr(skb, IFLA_VXLAN_LOCAL6,
- &vxlan->cfg.saddr.sin6.sin6_addr))
- goto nla_put_failure;
-#endif
- }
- }
-
- if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) ||
- nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) ||
- nla_put_be32(skb, IFLA_VXLAN_LABEL, vxlan->cfg.label) ||
- nla_put_u8(skb, IFLA_VXLAN_LEARNING,
- !!(vxlan->flags & VXLAN_F_LEARN)) ||
- nla_put_u8(skb, IFLA_VXLAN_PROXY,
- !!(vxlan->flags & VXLAN_F_PROXY)) ||
- nla_put_u8(skb, IFLA_VXLAN_RSC, !!(vxlan->flags & VXLAN_F_RSC)) ||
- nla_put_u8(skb, IFLA_VXLAN_L2MISS,
- !!(vxlan->flags & VXLAN_F_L2MISS)) ||
- nla_put_u8(skb, IFLA_VXLAN_L3MISS,
- !!(vxlan->flags & VXLAN_F_L3MISS)) ||
- nla_put_u8(skb, IFLA_VXLAN_COLLECT_METADATA,
- !!(vxlan->flags & VXLAN_F_COLLECT_METADATA)) ||
- nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->cfg.age_interval) ||
- nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->cfg.addrmax) ||
- nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->cfg.dst_port) ||
- nla_put_u8(skb, IFLA_VXLAN_UDP_CSUM,
- !(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) ||
- nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
- !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) ||
- nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
- !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) ||
- nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX,
- !!(vxlan->flags & VXLAN_F_REMCSUM_TX)) ||
- nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX,
- !!(vxlan->flags & VXLAN_F_REMCSUM_RX)))
- goto nla_put_failure;
-
- if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
- goto nla_put_failure;
-
- if (vxlan->flags & VXLAN_F_GBP &&
- nla_put_flag(skb, IFLA_VXLAN_GBP))
- goto nla_put_failure;
-
- if (vxlan->flags & VXLAN_F_GPE &&
- nla_put_flag(skb, IFLA_VXLAN_GPE))
- goto nla_put_failure;
-
- if (vxlan->flags & VXLAN_F_REMCSUM_NOPARTIAL &&
- nla_put_flag(skb, IFLA_VXLAN_REMCSUM_NOPARTIAL))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-#ifdef HAVE_GET_LINK_NET
-static struct net *vxlan_get_link_net(const struct net_device *dev)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
-
- return vxlan->net;
-}
-#endif
-
-static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
- .kind = "ovs_vxlan",
- .maxtype = IFLA_VXLAN_MAX,
- .policy = vxlan_policy,
- .priv_size = sizeof(struct vxlan_dev),
- .setup = vxlan_setup,
- .validate = vxlan_validate,
- .newlink = vxlan_newlink,
- .dellink = vxlan_dellink,
- .get_size = vxlan_get_size,
- .fill_info = vxlan_fill_info,
-#ifdef HAVE_GET_LINK_NET
- .get_link_net = vxlan_get_link_net,
-#endif
-};
-
-struct net_device *rpl_vxlan_dev_create(struct net *net, const char *name,
- u8 name_assign_type,
- struct vxlan_config *conf)
-{
- struct nlattr *tb[IFLA_MAX + 1];
- struct net_device *dev;
- int err;
-
- memset(&tb, 0, sizeof(tb));
-
- dev = rtnl_create_link(net, name, name_assign_type,
- &vxlan_link_ops, tb);
- if (IS_ERR(dev))
- return dev;
-
- err = vxlan_dev_configure(net, dev, conf);
- if (err < 0) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
- err = rtnl_configure_link(dev, NULL);
- if (err < 0) {
- LIST_HEAD(list_kill);
-
- vxlan_dellink(dev, &list_kill);
- unregister_netdevice_many(&list_kill);
- return ERR_PTR(err);
- }
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(rpl_vxlan_dev_create);
-
-static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn,
- struct net_device *dev)
-{
- struct vxlan_dev *vxlan, *next;
- LIST_HEAD(list_kill);
-
- list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) {
- struct vxlan_rdst *dst = &vxlan->default_dst;
-
- /* In case we created vxlan device with carrier
- * and we loose the carrier due to module unload
- * we also need to remove vxlan device. In other
- * cases, it's not necessary and remote_ifindex
- * is 0 here, so no matches.
- */
- if (dst->remote_ifindex == dev->ifindex)
- vxlan_dellink(vxlan->dev, &list_kill);
- }
-
- unregister_netdevice_many(&list_kill);
-}
-
-static int vxlan_netdevice_event(struct notifier_block *unused,
- unsigned long event, void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
-
- if (event == NETDEV_UNREGISTER)
- vxlan_handle_lowerdev_unregister(vn, dev);
- else if (event == NETDEV_OFFLOAD_PUSH_VXLAN)
- vxlan_push_rx_ports(dev);
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block vxlan_notifier_block __read_mostly = {
- .notifier_call = vxlan_netdevice_event,
-};
-
-static __net_init int vxlan_init_net(struct net *net)
-{
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- unsigned int h;
-
- INIT_LIST_HEAD(&vn->vxlan_list);
- spin_lock_init(&vn->sock_lock);
-
- for (h = 0; h < PORT_HASH_SIZE; ++h)
- INIT_HLIST_HEAD(&vn->sock_list[h]);
-
- return 0;
-}
-
-static void __net_exit vxlan_exit_net(struct net *net)
-{
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- struct vxlan_dev *vxlan, *next;
- struct net_device *dev, *aux;
- LIST_HEAD(list);
-
- rtnl_lock();
- for_each_netdev_safe(net, dev, aux)
- if (dev->rtnl_link_ops == &vxlan_link_ops)
- unregister_netdevice_queue(dev, &list);
-
- list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) {
- /* If vxlan->dev is in the same netns, it has already been added
- * to the list by the previous loop.
- */
- if (!net_eq(dev_net(vxlan->dev), net)) {
- unregister_netdevice_queue(vxlan->dev, &list);
- }
- }
-
- unregister_netdevice_many(&list);
- rtnl_unlock();
-}
-
-static struct pernet_operations vxlan_net_ops = {
- .init = vxlan_init_net,
- .exit = vxlan_exit_net,
- .id = &vxlan_net_id,
- .size = sizeof(struct vxlan_net),
-};
-
-int rpl_vxlan_init_module(void)
-{
- int rc;
-
- get_random_bytes(&vxlan_salt, sizeof(vxlan_salt));
-
- rc = register_pernet_subsys(&vxlan_net_ops);
- if (rc)
- goto out1;
-
- rc = register_netdevice_notifier(&vxlan_notifier_block);
- if (rc)
- goto out2;
-
- rc = rtnl_link_register(&vxlan_link_ops);
- if (rc)
- goto out3;
-
- pr_info("VxLAN tunneling driver\n");
- return 0;
-out3:
- unregister_netdevice_notifier(&vxlan_notifier_block);
-out2:
- unregister_pernet_subsys(&vxlan_net_ops);
-out1:
- pr_err("Error while initializing VxLAN %d\n", rc);
- return rc;
-}
-
-void rpl_vxlan_cleanup_module(void)
-{
- rtnl_link_unregister(&vxlan_link_ops);
- unregister_netdevice_notifier(&vxlan_notifier_block);
- unregister_pernet_subsys(&vxlan_net_ops);
- /* rcu_barrier() is called by netns */
-}
-#endif