mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
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>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,7 +34,6 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
/aclocal.m4
|
||||
/all-distfiles
|
||||
/all-gitfiles
|
||||
/autom4te.cache
|
||||
/build-arch-stamp
|
||||
|
23
Makefile.am
23
Makefile.am
@@ -7,7 +7,6 @@
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = datapath
|
||||
|
||||
AM_CPPFLAGS = $(SSL_CFLAGS)
|
||||
AM_LDFLAGS = $(SSL_LDFLAGS)
|
||||
@@ -198,25 +197,22 @@ CLEAN_LOCAL += clean-pycov
|
||||
ALL_LOCAL += dist-hook-git
|
||||
dist-hook-git: distfiles
|
||||
@if test -e $(srcdir)/.git && (git --version) >/dev/null 2>&1; then \
|
||||
(cd datapath && $(MAKE) distfiles); \
|
||||
(cat distfiles; sed 's|^|datapath/|' datapath/distfiles) | \
|
||||
LC_ALL=C sort -u > all-distfiles; \
|
||||
(cd $(srcdir) && git ls-files) | grep -v '\.gitignore$$' | \
|
||||
grep -v '\.gitattributes$$' | \
|
||||
LC_ALL=C sort -u > all-gitfiles; \
|
||||
LC_ALL=C comm -1 -3 all-distfiles all-gitfiles > missing-distfiles; \
|
||||
LC_ALL=C comm -1 -3 distfiles all-gitfiles > missing-distfiles; \
|
||||
if test -s missing-distfiles; then \
|
||||
echo "The following files are in git but not the distribution:"; \
|
||||
cat missing-distfiles; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
if LC_ALL=C grep '\.gitignore$$' all-distfiles; then \
|
||||
if LC_ALL=C grep '\.gitignore$$' distfiles; then \
|
||||
echo "See above for list of files that are distributed but"; \
|
||||
echo "should not be."; \
|
||||
exit 1; \
|
||||
fi \
|
||||
fi
|
||||
CLEANFILES += all-distfiles all-gitfiles missing-distfiles
|
||||
CLEANFILES += all-gitfiles missing-distfiles
|
||||
# The following is based on commands for the Automake "distdir" target.
|
||||
distfiles: Makefile
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
@@ -235,7 +231,7 @@ config-h-check:
|
||||
@cd $(srcdir); \
|
||||
if test -e .git && (git --version) >/dev/null 2>&1 && \
|
||||
git --no-pager grep -L '#include <config\.h>' `git ls-files | grep '\.c$$' | \
|
||||
grep -vE '^datapath|^lib/sflow|^third-party|^datapath-windows|^python'`; \
|
||||
grep -vE '^datapath-windows|^lib/sflow|^python|^third-party'`; \
|
||||
then \
|
||||
echo "See above for list of violations of the rule that"; \
|
||||
echo "every C source file must #include <config.h>."; \
|
||||
@@ -256,7 +252,7 @@ printf-check:
|
||||
@cd $(srcdir); \
|
||||
if test -e .git && (git --version) >/dev/null 2>&1 && \
|
||||
git --no-pager grep -n -E -e '%[-+ #0-9.*]*([ztj]|hh)' --and --not -e 'ovs_scan' `git ls-files | grep '\.[ch]$$' | \
|
||||
grep -vE '^datapath|^lib/sflow|^third-party'`; \
|
||||
grep -vE '^datapath-windows|^lib/sflow|^third-party'`; \
|
||||
then \
|
||||
echo "See above for list of violations of the rule that"; \
|
||||
echo "'z', 't', 'j', 'hh' printf() type modifiers are"; \
|
||||
@@ -299,7 +295,7 @@ check-endian:
|
||||
@if test -e $(srcdir)/.git && (git --version) >/dev/null 2>&1 && \
|
||||
(cd $(srcdir) && git --no-pager grep -l -E \
|
||||
-e 'BIG_ENDIAN|LITTLE_ENDIAN' --and --not -e 'BYTE_ORDER' | \
|
||||
$(EGREP) -v '^datapath/|^include/sparse/rte_'); \
|
||||
$(EGREP) -v '^include/sparse/rte_'); \
|
||||
then \
|
||||
echo "See above for list of files that misuse LITTLE""_ENDIAN"; \
|
||||
echo "or BIG""_ENDIAN. Please use WORDS_BIGENDIAN instead."; \
|
||||
@@ -339,7 +335,7 @@ thread-safety-check:
|
||||
if test -e .git && (git --version) >/dev/null 2>&1 && \
|
||||
grep -n -f build-aux/thread-safety-forbidden \
|
||||
`git ls-files | grep '\.[ch]$$' \
|
||||
| $(EGREP) -v '^datapath|^lib/sflow|^third-party'` /dev/null \
|
||||
| $(EGREP) -v '^datapath-windows|^lib/sflow|^third-party'` /dev/null \
|
||||
| $(EGREP) -v ':[ ]*/?\*'; \
|
||||
then \
|
||||
echo "See above for list of calls to functions that are"; \
|
||||
@@ -468,11 +464,6 @@ install-data-local: $(INSTALL_DATA_LOCAL)
|
||||
uninstall-local: $(UNINSTALL_LOCAL)
|
||||
.PHONY: $(DIST_HOOKS) $(CLEAN_LOCAL) $(INSTALL_DATA_LOCAL) $(UNINSTALL_LOCAL)
|
||||
|
||||
modules_install:
|
||||
if LINUX_ENABLED
|
||||
cd datapath/linux && $(MAKE) modules_install
|
||||
endif
|
||||
|
||||
dist-docs:
|
||||
VERSION=$(VERSION) MAKE='$(MAKE)' $(srcdir)/build-aux/dist-docs $(srcdir) $(docs)
|
||||
.PHONY: dist-docs
|
||||
|
3
NEWS
3
NEWS
@@ -74,6 +74,9 @@ Post-v2.17.0
|
||||
- Linux datapath:
|
||||
* Add offloading meter tc police.
|
||||
* Add support for offloading the check_pkt_len action.
|
||||
- Previously deprecated Linux kernel module is now fully removed from
|
||||
the OVS source tree. The version provided with the Linux kernel
|
||||
should be used instead.
|
||||
|
||||
|
||||
v2.17.0 - 17 Feb 2022
|
||||
|
@@ -3,7 +3,6 @@
|
||||
\.mk$
|
||||
\.png$
|
||||
\.sln$
|
||||
^datapath/
|
||||
^include/linux/
|
||||
^include/sparse/rte_
|
||||
^include/windows/
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT(openvswitch, 2.17.90, bugs@openvswitch.org)
|
||||
AC_CONFIG_SRCDIR([datapath/datapath.c])
|
||||
AC_CONFIG_SRCDIR([vswitchd/ovs-vswitchd.c])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@@ -204,10 +204,6 @@ AC_SUBST([OVS_CFLAGS])
|
||||
AC_SUBST([OVS_LDFLAGS])
|
||||
|
||||
AC_CONFIG_FILES(Makefile)
|
||||
AC_CONFIG_FILES(datapath/Makefile)
|
||||
AC_CONFIG_FILES(datapath/linux/Kbuild)
|
||||
AC_CONFIG_FILES(datapath/linux/Makefile)
|
||||
AC_CONFIG_FILES(datapath/linux/Makefile.main)
|
||||
AC_CONFIG_FILES(tests/atlocal)
|
||||
AC_CONFIG_FILES(lib/libopenvswitch.pc)
|
||||
AC_CONFIG_FILES(lib/libsflow.pc)
|
||||
|
@@ -3,7 +3,7 @@ BUILT_SOURCES += $(srcdir)/datapath-windows/include/OvsDpInterface.h
|
||||
endif
|
||||
|
||||
$(srcdir)/datapath-windows/include/OvsDpInterface.h: \
|
||||
datapath/linux/compat/include/linux/openvswitch.h \
|
||||
include/linux/openvswitch.h \
|
||||
build-aux/extract-odp-netlink-windows-dp-h
|
||||
$(AM_V_GEN)sed -f $(srcdir)/build-aux/extract-odp-netlink-windows-dp-h < $< > $@
|
||||
|
||||
|
7
datapath/.gitignore
vendored
7
datapath/.gitignore
vendored
@@ -1,7 +0,0 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
*.cmd
|
||||
*.ko
|
||||
*.mod.c
|
||||
Module.symvers
|
||||
/distfiles
|
@@ -1,60 +0,0 @@
|
||||
SUBDIRS =
|
||||
if LINUX_ENABLED
|
||||
SUBDIRS += linux
|
||||
endif
|
||||
|
||||
EXTRA_DIST = $(dist_headers) $(dist_sources) $(dist_extras)
|
||||
|
||||
# Suppress warnings about GNU extensions in Modules.mk files.
|
||||
AUTOMAKE_OPTIONS = -Wno-portability
|
||||
|
||||
include Modules.mk
|
||||
include linux/Modules.mk
|
||||
|
||||
# The following is based on commands for the Automake "distdir" target.
|
||||
distfiles: Makefile
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t" | sort -u > $@
|
||||
CLEANFILES = distfiles
|
||||
|
||||
# Print name of all modules.
|
||||
print-build-modules:
|
||||
@if test -z "$(build_modules)"; \
|
||||
then \
|
||||
echo "Could not find any kernel module."; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "$(build_modules)" | tr '_' '-';
|
||||
|
||||
if !WIN32
|
||||
COMPAT_GET_FUNCTIONS := find $(top_srcdir)/datapath/linux/compat -name "*.h" \
|
||||
-exec sed -n '/^[a-z][a-z]* \*\?[A-Za-z0-9_][A-Za-z0-9_]*([a-z]/p; /^struct [a-z0-9_][a-z0-9_]* \*\?[A-Za-z0-9_][A-Za-z0-9_]*([a-z]/p' {} \; | tr -d '*' | cut -d '(' -f1 | rev | cut -d ' ' -f1 | rev
|
||||
COMPAT_GET_EXPORTS := find $(top_srcdir)/datapath/linux/compat -name "*.c" \
|
||||
-exec sed -n 's/^EXPORT_SYMBOL[A-Z_]*(\([a-z_][a-z_]*\));$$/\1/p' {} \;
|
||||
COMPAT_FUNCTIONS := $(shell $(COMPAT_GET_FUNCTIONS))
|
||||
COMPAT_EXPORTS := $(shell $(COMPAT_GET_EXPORTS))
|
||||
|
||||
# Checks that all public functions are 'rpl_' or 'ovs_' prefixed.
|
||||
# Checks that all EXPORT_SYMBOL_GPL() export 'rpl_' or 'ovs_' prefixed functions.
|
||||
check-export-symbol:
|
||||
@for fun_ in $(COMPAT_FUNCTIONS); do \
|
||||
if ! grep -- $${fun_} $(top_srcdir)/datapath/linux/compat/build-aux/export-check-allow-list > /dev/null; then \
|
||||
if ! echo $${fun_} | grep -q -E '^(rpl|ovs)_'; then \
|
||||
echo "error: $${fun_}() needs to be prefixed with 'rpl_' or 'ovs_'."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi; \
|
||||
done
|
||||
@for fun_ in $(COMPAT_EXPORTS); do \
|
||||
if ! echo $${fun_} | grep -q -E '^(rpl|ovs)_'; then \
|
||||
echo "error: $${fun_}() needs to be prefixed with 'rpl_' or 'ovs_'."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
all-local: check-export-symbol
|
||||
endif
|
@@ -1,58 +0,0 @@
|
||||
# Some modules should be built and distributed, e.g. openvswitch.
|
||||
#
|
||||
# Some modules should be built but not distributed, e.g. third-party
|
||||
# hwtable modules.
|
||||
build_multi_modules = \
|
||||
openvswitch
|
||||
both_modules = \
|
||||
$(build_multi_modules) \
|
||||
vport_geneve \
|
||||
vport_gre \
|
||||
vport_lisp \
|
||||
vport_stt \
|
||||
vport_vxlan
|
||||
# When changing the name of 'build_modules', please also update the
|
||||
# print-build-modules in Makefile.am.
|
||||
build_modules = $(both_modules) # Modules to build
|
||||
dist_modules = $(both_modules) # Modules to distribute
|
||||
|
||||
openvswitch_sources = \
|
||||
actions.c \
|
||||
conntrack.c \
|
||||
datapath.c \
|
||||
dp_notify.c \
|
||||
flow.c \
|
||||
flow_netlink.c \
|
||||
flow_table.c \
|
||||
vport.c \
|
||||
vport-internal_dev.c \
|
||||
vport-netdev.c \
|
||||
nsh.c \
|
||||
meter.c
|
||||
|
||||
vport_geneve_sources = vport-geneve.c
|
||||
vport_vxlan_sources = vport-vxlan.c
|
||||
vport_gre_sources = vport-gre.c
|
||||
vport_lisp_sources = vport-lisp.c
|
||||
vport_stt_sources = vport-stt.c
|
||||
nsh_sources = nsh.c
|
||||
|
||||
openvswitch_headers = \
|
||||
compat.h \
|
||||
conntrack.h \
|
||||
datapath.h \
|
||||
flow.h \
|
||||
flow_netlink.h \
|
||||
flow_table.h \
|
||||
vport.h \
|
||||
vport-internal_dev.h \
|
||||
vport-netdev.h \
|
||||
meter.h
|
||||
|
||||
dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
|
||||
dist_headers = $(foreach module,$(dist_modules),$($(module)_headers))
|
||||
dist_extras = $(foreach module,$(dist_modules),$($(module)_extras))
|
||||
build_sources = $(foreach module,$(build_modules),$($(module)_sources))
|
||||
build_headers = $(foreach module,$(build_modules),$($(module)_headers))
|
||||
build_links = $(notdir $(build_sources))
|
||||
build_objects = $(notdir $(patsubst %.c,%.o,$(build_sources)))
|
1587
datapath/actions.c
1587
datapath/actions.c
File diff suppressed because it is too large
Load Diff
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2015 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
|
||||
*/
|
||||
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H 1
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/in_route.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/route.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
|
||||
#include <net/netfilter/nf_conntrack_count.h>
|
||||
|
||||
/* Fix grsecurity patch compilation issue. */
|
||||
#ifdef CONSTIFY_PLUGIN
|
||||
#include <linux/cache.h>
|
||||
#undef __read_mostly
|
||||
#define __read_mostly
|
||||
#endif
|
||||
|
||||
/* Even though vanilla 3.10 kernel has grp->id, RHEL 7 kernel is missing
|
||||
* this field. */
|
||||
#ifdef HAVE_GENL_MULTICAST_GROUP_WITH_ID
|
||||
#define GROUP_ID(grp) ((grp)->id)
|
||||
#else
|
||||
#define GROUP_ID(grp) 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NF_IPV6_OPS_FRAGMENT
|
||||
static inline int __init ip6_output_init(void) { return 0; }
|
||||
static inline void ip6_output_exit(void) { }
|
||||
#else
|
||||
int __init ip6_output_init(void);
|
||||
void ip6_output_exit(void);
|
||||
#endif
|
||||
|
||||
static inline int __init compat_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ipfrag_init();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = nf_ct_frag6_init();
|
||||
if (err)
|
||||
goto error_ipfrag_exit;
|
||||
|
||||
err = ip6_output_init();
|
||||
if (err)
|
||||
goto error_frag6_exit;
|
||||
|
||||
err = rpl_nf_conncount_modinit();
|
||||
if (err)
|
||||
goto error_nf_conncount_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
error_nf_conncount_exit:
|
||||
rpl_nf_conncount_modexit();
|
||||
error_frag6_exit:
|
||||
nf_ct_frag6_cleanup();
|
||||
error_ipfrag_exit:
|
||||
rpl_ipfrag_fini();
|
||||
return err;
|
||||
}
|
||||
static inline void compat_exit(void)
|
||||
{
|
||||
rpl_nf_conncount_modexit();
|
||||
ip6_output_exit();
|
||||
nf_ct_frag6_cleanup();
|
||||
rpl_ipfrag_fini();
|
||||
}
|
||||
|
||||
#endif /* compat.h */
|
2413
datapath/conntrack.c
2413
datapath/conntrack.c
File diff suppressed because it is too large
Load Diff
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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 OVS_CONNTRACK_H
|
||||
#define OVS_CONNTRACK_H 1
|
||||
|
||||
#include <linux/version.h>
|
||||
#include "flow.h"
|
||||
|
||||
struct ovs_conntrack_info;
|
||||
struct ovs_ct_limit_info;
|
||||
enum ovs_key_attr;
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
||||
int ovs_ct_init(struct net *);
|
||||
void ovs_ct_exit(struct net *);
|
||||
bool ovs_ct_verify(struct net *, enum ovs_key_attr attr);
|
||||
int ovs_ct_copy_action(struct net *, const struct nlattr *,
|
||||
const struct sw_flow_key *, struct sw_flow_actions **,
|
||||
bool log);
|
||||
int ovs_ct_action_to_attr(const struct ovs_conntrack_info *, struct sk_buff *);
|
||||
|
||||
int ovs_ct_execute(struct net *, struct sk_buff *, struct sw_flow_key *,
|
||||
const struct ovs_conntrack_info *);
|
||||
int ovs_ct_clear(struct sk_buff *skb, struct sw_flow_key *key);
|
||||
|
||||
void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key);
|
||||
int ovs_ct_put_key(const struct sw_flow_key *swkey,
|
||||
const struct sw_flow_key *output, struct sk_buff *skb);
|
||||
void ovs_ct_free_action(const struct nlattr *a);
|
||||
|
||||
#define CT_SUPPORTED_MASK (OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | \
|
||||
OVS_CS_F_RELATED | OVS_CS_F_REPLY_DIR | \
|
||||
OVS_CS_F_INVALID | OVS_CS_F_TRACKED | \
|
||||
OVS_CS_F_SRC_NAT | OVS_CS_F_DST_NAT)
|
||||
#else
|
||||
#include <linux/errno.h>
|
||||
|
||||
static inline int ovs_ct_init(struct net *net) { return 0; }
|
||||
|
||||
static inline void ovs_ct_exit(struct net *net) { }
|
||||
|
||||
static inline bool ovs_ct_verify(struct net *net, int attr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int ovs_ct_copy_action(struct net *net, const struct nlattr *nla,
|
||||
const struct sw_flow_key *key,
|
||||
struct sw_flow_actions **acts, bool log)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int ovs_ct_action_to_attr(const struct ovs_conntrack_info *info,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int ovs_ct_execute(struct net *net, struct sk_buff *skb,
|
||||
struct sw_flow_key *key,
|
||||
const struct ovs_conntrack_info *info)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int ovs_ct_clear(struct sk_buff *skb,
|
||||
struct sw_flow_key *key)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline void ovs_ct_fill_key(const struct sk_buff *skb,
|
||||
struct sw_flow_key *key)
|
||||
{
|
||||
key->ct_state = 0;
|
||||
key->ct_zone = 0;
|
||||
key->ct.mark = 0;
|
||||
memset(&key->ct.labels, 0, sizeof(key->ct.labels));
|
||||
/* Clear 'ct_orig_proto' to mark the non-existence of original
|
||||
* direction key fields.
|
||||
*/
|
||||
key->ct_orig_proto = 0;
|
||||
}
|
||||
|
||||
static inline int ovs_ct_put_key(const struct sw_flow_key *swkey,
|
||||
const struct sw_flow_key *output,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ovs_ct_free_action(const struct nlattr *a) { }
|
||||
|
||||
#define CT_SUPPORTED_MASK 0
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
|
||||
extern struct genl_family dp_ct_limit_genl_family;
|
||||
#endif
|
||||
#endif /* ovs_conntrack.h */
|
2707
datapath/datapath.c
2707
datapath/datapath.c
File diff suppressed because it is too large
Load Diff
@@ -1,283 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2015 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
|
||||
*/
|
||||
|
||||
#ifndef DATAPATH_H
|
||||
#define DATAPATH_H 1
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/ip_tunnels.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "flow.h"
|
||||
#include "flow_table.h"
|
||||
#include "meter.h"
|
||||
#include "vport-internal_dev.h"
|
||||
|
||||
#define DP_MAX_PORTS USHRT_MAX
|
||||
#define DP_VPORT_HASH_BUCKETS 1024
|
||||
|
||||
/**
|
||||
* struct dp_stats_percpu - per-cpu packet processing statistics for a given
|
||||
* datapath.
|
||||
* @n_hit: Number of received packets for which a matching flow was found in
|
||||
* the flow table.
|
||||
* @n_miss: Number of received packets that had no matching flow in the flow
|
||||
* table. The sum of @n_hit and @n_miss is the number of packets that have
|
||||
* been received by the datapath.
|
||||
* @n_lost: Number of received packets that had no matching flow in the flow
|
||||
* table that could not be sent to userspace (normally due to an overflow in
|
||||
* one of the datapath's queues).
|
||||
* @n_mask_hit: Number of masks looked up for flow match.
|
||||
* @n_mask_hit / (@n_hit + @n_missed) will be the average masks looked
|
||||
* up per packet.
|
||||
*/
|
||||
struct dp_stats_percpu {
|
||||
u64 n_hit;
|
||||
u64 n_missed;
|
||||
u64 n_lost;
|
||||
u64 n_mask_hit;
|
||||
struct u64_stats_sync syncp;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct datapath - datapath for flow-based packet switching
|
||||
* @rcu: RCU callback head for deferred destruction.
|
||||
* @list_node: Element in global 'dps' list.
|
||||
* @table: flow table.
|
||||
* @ports: Hash table for ports. %OVSP_LOCAL port always exists. Protected by
|
||||
* ovs_mutex and RCU.
|
||||
* @stats_percpu: Per-CPU datapath statistics.
|
||||
* @net: Reference to net namespace.
|
||||
* @max_headroom: the maximum headroom of all vports in this datapath; it will
|
||||
* be used by all the internal vports in this dp.
|
||||
*
|
||||
* Context: See the comment on locking at the top of datapath.c for additional
|
||||
* locking information.
|
||||
*/
|
||||
struct datapath {
|
||||
struct rcu_head rcu;
|
||||
struct list_head list_node;
|
||||
|
||||
/* Flow table. */
|
||||
struct flow_table table;
|
||||
|
||||
/* Switch ports. */
|
||||
struct hlist_head *ports;
|
||||
|
||||
/* Stats. */
|
||||
struct dp_stats_percpu __percpu *stats_percpu;
|
||||
|
||||
/* Network namespace ref. */
|
||||
possible_net_t net;
|
||||
|
||||
u32 user_features;
|
||||
|
||||
u32 max_headroom;
|
||||
|
||||
/* Switch meters. */
|
||||
struct hlist_head *meters;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ovs_skb_cb - OVS data in skb CB
|
||||
* @input_vport: The original vport packet came in on. This value is cached
|
||||
* when a packet is received by OVS.
|
||||
* @mru: The maximum received fragement size; 0 if the packet is not
|
||||
* fragmented.
|
||||
* @acts_origlen: The netlink size of the flow actions applied to this skb.
|
||||
* @cutlen: The number of bytes from the packet end to be removed.
|
||||
*/
|
||||
struct ovs_skb_cb {
|
||||
struct vport *input_vport;
|
||||
u16 mru;
|
||||
u16 acts_origlen;
|
||||
u32 cutlen;
|
||||
};
|
||||
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
|
||||
|
||||
/**
|
||||
* struct dp_upcall - metadata to include with a packet to send to userspace
|
||||
* @cmd: One of %OVS_PACKET_CMD_*.
|
||||
* @userdata: If nonnull, its variable-length value is passed to userspace as
|
||||
* %OVS_PACKET_ATTR_USERDATA.
|
||||
* @portid: Netlink portid to which packet should be sent. If @portid is 0
|
||||
* then no packet is sent and the packet is accounted in the datapath's @n_lost
|
||||
* counter.
|
||||
* @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY.
|
||||
* @mru: If not zero, Maximum received IP fragment size.
|
||||
*/
|
||||
struct dp_upcall_info {
|
||||
struct ip_tunnel_info *egress_tun_info;
|
||||
const struct nlattr *userdata;
|
||||
const struct nlattr *actions;
|
||||
int actions_len;
|
||||
u32 portid;
|
||||
u8 cmd;
|
||||
u16 mru;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ovs_net - Per net-namespace data for ovs.
|
||||
* @dps: List of datapaths to enable dumping them all out.
|
||||
* Protected by genl_mutex.
|
||||
*/
|
||||
struct ovs_net {
|
||||
struct list_head dps;
|
||||
struct work_struct dp_notify_work;
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
|
||||
struct ovs_ct_limit_info *ct_limit_info;
|
||||
#endif
|
||||
|
||||
/* Module reference for configuring conntrack. */
|
||||
bool xt_label;
|
||||
|
||||
#ifdef HAVE_INET_FRAG_LRU_MOVE
|
||||
struct net *net;
|
||||
struct netns_frags ipv4_frags;
|
||||
struct netns_frags nf_frags;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ovs_pkt_hash_types - hash info to include with a packet
|
||||
* to send to userspace.
|
||||
* @OVS_PACKET_HASH_SW_BIT: indicates hash was computed in software stack.
|
||||
* @OVS_PACKET_HASH_L4_BIT: indicates hash is a canonical 4-tuple hash
|
||||
* over transport ports.
|
||||
*/
|
||||
enum ovs_pkt_hash_types {
|
||||
OVS_PACKET_HASH_SW_BIT = (1ULL << 32),
|
||||
OVS_PACKET_HASH_L4_BIT = (1ULL << 33),
|
||||
};
|
||||
|
||||
extern unsigned int ovs_net_id;
|
||||
void ovs_lock(void);
|
||||
void ovs_unlock(void);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
int lockdep_ovsl_is_held(void);
|
||||
#else
|
||||
#define lockdep_ovsl_is_held() 1
|
||||
#endif
|
||||
|
||||
#define ASSERT_OVSL() WARN_ON(!lockdep_ovsl_is_held())
|
||||
#define ovsl_dereference(p) \
|
||||
rcu_dereference_protected(p, lockdep_ovsl_is_held())
|
||||
#define rcu_dereference_ovsl(p) \
|
||||
rcu_dereference_check(p, lockdep_ovsl_is_held())
|
||||
|
||||
static inline struct net *ovs_dp_get_net(const struct datapath *dp)
|
||||
{
|
||||
return rpl_read_pnet(&dp->net);
|
||||
}
|
||||
|
||||
static inline void ovs_dp_set_net(struct datapath *dp, struct net *net)
|
||||
{
|
||||
rpl_write_pnet(&dp->net, net);
|
||||
}
|
||||
|
||||
struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no);
|
||||
|
||||
static inline struct vport *ovs_vport_rcu(const struct datapath *dp, int port_no)
|
||||
{
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
return ovs_lookup_vport(dp, port_no);
|
||||
}
|
||||
|
||||
static inline struct vport *ovs_vport_ovsl_rcu(const struct datapath *dp, int port_no)
|
||||
{
|
||||
WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_ovsl_is_held());
|
||||
return ovs_lookup_vport(dp, port_no);
|
||||
}
|
||||
|
||||
static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_no)
|
||||
{
|
||||
ASSERT_OVSL();
|
||||
return ovs_lookup_vport(dp, port_no);
|
||||
}
|
||||
|
||||
/* Must be called with rcu_read_lock. */
|
||||
static inline struct datapath *get_dp_rcu(struct net *net, int dp_ifindex)
|
||||
{
|
||||
struct net_device *dev = dev_get_by_index_rcu(net, dp_ifindex);
|
||||
|
||||
if (dev) {
|
||||
struct vport *vport = ovs_internal_dev_get_vport(dev);
|
||||
|
||||
if (vport)
|
||||
return vport->dp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The caller must hold either ovs_mutex or rcu_read_lock to keep the
|
||||
* returned dp pointer valid.
|
||||
*/
|
||||
static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
|
||||
{
|
||||
struct datapath *dp;
|
||||
|
||||
WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_ovsl_is_held());
|
||||
rcu_read_lock();
|
||||
dp = get_dp_rcu(net, dp_ifindex);
|
||||
rcu_read_unlock();
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
extern struct notifier_block ovs_dp_device_notifier;
|
||||
extern struct genl_family dp_vport_genl_family;
|
||||
extern const struct genl_multicast_group ovs_dp_vport_multicast_group;
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(tc_recirc_sharing_support);
|
||||
|
||||
void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
|
||||
void ovs_dp_detach_port(struct vport *);
|
||||
int ovs_dp_upcall(struct datapath *, struct sk_buff *,
|
||||
const struct sw_flow_key *, const struct dp_upcall_info *,
|
||||
uint32_t cutlen);
|
||||
|
||||
const char *ovs_dp_name(const struct datapath *dp);
|
||||
struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
|
||||
u32 portid, u32 seq, u8 cmd);
|
||||
|
||||
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
|
||||
const struct sw_flow_actions *, struct sw_flow_key *);
|
||||
|
||||
void ovs_dp_notify_wq(struct work_struct *work);
|
||||
|
||||
int action_fifos_init(void);
|
||||
void action_fifos_exit(void);
|
||||
|
||||
/* 'KEY' must not have any bits set outside of the 'MASK' */
|
||||
#define OVS_MASKED(OLD, KEY, MASK) ((KEY) | ((OLD) & ~(MASK)))
|
||||
#define OVS_SET_MASKED(OLD, KEY, MASK) ((OLD) = OVS_MASKED(OLD, KEY, MASK))
|
||||
|
||||
#define OVS_NLERR(logging_allowed, fmt, ...) \
|
||||
do { \
|
||||
if (logging_allowed && net_ratelimit()) \
|
||||
pr_info("netlink: " fmt "\n", ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#endif /* datapath.h */
|
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2012 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/netdevice.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
||||
#include "datapath.h"
|
||||
#include "vport-internal_dev.h"
|
||||
#include "vport-netdev.h"
|
||||
|
||||
static void dp_detach_port_notify(struct vport *vport)
|
||||
{
|
||||
struct sk_buff *notify;
|
||||
struct datapath *dp;
|
||||
|
||||
dp = vport->dp;
|
||||
notify = ovs_vport_cmd_build_info(vport, ovs_dp_get_net(dp),
|
||||
0, 0, OVS_VPORT_CMD_DEL);
|
||||
ovs_dp_detach_port(vport);
|
||||
if (IS_ERR(notify)) {
|
||||
genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0,
|
||||
GROUP_ID(&ovs_dp_vport_multicast_group),
|
||||
PTR_ERR(notify));
|
||||
return;
|
||||
}
|
||||
|
||||
genlmsg_multicast_netns(&dp_vport_genl_family,
|
||||
ovs_dp_get_net(dp), notify, 0,
|
||||
GROUP_ID(&ovs_dp_vport_multicast_group),
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
void ovs_dp_notify_wq(struct work_struct *work)
|
||||
{
|
||||
struct ovs_net *ovs_net = container_of(work, struct ovs_net, dp_notify_work);
|
||||
struct datapath *dp;
|
||||
|
||||
ovs_lock();
|
||||
list_for_each_entry(dp, &ovs_net->dps, list_node) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
|
||||
struct vport *vport;
|
||||
struct hlist_node *n;
|
||||
|
||||
hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) {
|
||||
if (vport->ops->type == OVS_VPORT_TYPE_INTERNAL)
|
||||
continue;
|
||||
|
||||
if (!(vport->dev->priv_flags & IFF_OVS_DATAPATH))
|
||||
dp_detach_port_notify(vport);
|
||||
}
|
||||
}
|
||||
}
|
||||
ovs_unlock();
|
||||
}
|
||||
|
||||
static int dp_device_event(struct notifier_block *unused, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
struct ovs_net *ovs_net;
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct vport *vport = NULL;
|
||||
|
||||
if (!ovs_is_internal_dev(dev))
|
||||
vport = ovs_netdev_get_vport(dev);
|
||||
|
||||
if (!vport)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (event == NETDEV_UNREGISTER) {
|
||||
/* upper_dev_unlink and decrement promisc immediately */
|
||||
ovs_netdev_detach_dev(vport);
|
||||
|
||||
/* schedule vport destroy, dev_put and genl notification */
|
||||
ovs_net = net_generic(dev_net(dev), ovs_net_id);
|
||||
queue_work(system_wq, &ovs_net->dp_notify_work);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
struct notifier_block ovs_dp_device_notifier = {
|
||||
.notifier_call = dp_device_event
|
||||
};
|
972
datapath/flow.c
972
datapath/flow.c
@@ -1,972 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2015 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/uaccess.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/llc_pdu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/llc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/mpls.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/timekeeping.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/mpls.h>
|
||||
#include <net/ndisc.h>
|
||||
#include <net/nsh.h>
|
||||
|
||||
#include "datapath.h"
|
||||
#include "conntrack.h"
|
||||
#include "flow.h"
|
||||
#include "flow_netlink.h"
|
||||
#include "vport.h"
|
||||
|
||||
u64 ovs_flow_used_time(unsigned long flow_jiffies)
|
||||
{
|
||||
struct timespec64 cur_ts;
|
||||
u64 cur_ms, idle_ms;
|
||||
|
||||
ktime_get_ts64(&cur_ts);
|
||||
idle_ms = jiffies_to_msecs(jiffies - flow_jiffies);
|
||||
cur_ms = (u64)(u32)cur_ts.tv_sec * MSEC_PER_SEC +
|
||||
cur_ts.tv_nsec / NSEC_PER_MSEC;
|
||||
|
||||
return cur_ms - idle_ms;
|
||||
}
|
||||
|
||||
#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF))
|
||||
|
||||
void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
struct sw_flow_stats *stats;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
int len = skb->len + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
|
||||
|
||||
stats = rcu_dereference(flow->stats[cpu]);
|
||||
|
||||
/* Check if already have CPU-specific stats. */
|
||||
if (likely(stats)) {
|
||||
spin_lock(&stats->lock);
|
||||
/* Mark if we write on the pre-allocated stats. */
|
||||
if (cpu == 0 && unlikely(flow->stats_last_writer != cpu))
|
||||
flow->stats_last_writer = cpu;
|
||||
} else {
|
||||
stats = rcu_dereference(flow->stats[0]); /* Pre-allocated. */
|
||||
spin_lock(&stats->lock);
|
||||
|
||||
/* If the current CPU is the only writer on the
|
||||
* pre-allocated stats keep using them.
|
||||
*/
|
||||
if (unlikely(flow->stats_last_writer != cpu)) {
|
||||
/* A previous locker may have already allocated the
|
||||
* stats, so we need to check again. If CPU-specific
|
||||
* stats were already allocated, we update the pre-
|
||||
* allocated stats as we have already locked them.
|
||||
*/
|
||||
if (likely(flow->stats_last_writer != -1) &&
|
||||
likely(!rcu_access_pointer(flow->stats[cpu]))) {
|
||||
/* Try to allocate CPU-specific stats. */
|
||||
struct sw_flow_stats *new_stats;
|
||||
|
||||
new_stats =
|
||||
kmem_cache_alloc_node(flow_stats_cache,
|
||||
GFP_NOWAIT |
|
||||
__GFP_THISNODE |
|
||||
__GFP_NOWARN |
|
||||
__GFP_NOMEMALLOC,
|
||||
numa_node_id());
|
||||
if (likely(new_stats)) {
|
||||
new_stats->used = jiffies;
|
||||
new_stats->packet_count = 1;
|
||||
new_stats->byte_count = len;
|
||||
new_stats->tcp_flags = tcp_flags;
|
||||
spin_lock_init(&new_stats->lock);
|
||||
|
||||
rcu_assign_pointer(flow->stats[cpu],
|
||||
new_stats);
|
||||
cpumask_set_cpu(cpu, &flow->cpu_used_mask);
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
flow->stats_last_writer = cpu;
|
||||
}
|
||||
}
|
||||
|
||||
stats->used = jiffies;
|
||||
stats->packet_count++;
|
||||
stats->byte_count += len;
|
||||
stats->tcp_flags |= tcp_flags;
|
||||
unlock:
|
||||
spin_unlock(&stats->lock);
|
||||
}
|
||||
|
||||
/* Must be called with rcu_read_lock or ovs_mutex. */
|
||||
void ovs_flow_stats_get(const struct sw_flow *flow,
|
||||
struct ovs_flow_stats *ovs_stats,
|
||||
unsigned long *used, __be16 *tcp_flags)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
*used = 0;
|
||||
*tcp_flags = 0;
|
||||
memset(ovs_stats, 0, sizeof(*ovs_stats));
|
||||
|
||||
/* We open code this to make sure cpu 0 is always considered */
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask)) {
|
||||
struct sw_flow_stats *stats = rcu_dereference_ovsl(flow->stats[cpu]);
|
||||
|
||||
if (stats) {
|
||||
/* Local CPU may write on non-local stats, so we must
|
||||
* block bottom-halves here.
|
||||
*/
|
||||
spin_lock_bh(&stats->lock);
|
||||
if (!*used || time_after(stats->used, *used))
|
||||
*used = stats->used;
|
||||
*tcp_flags |= stats->tcp_flags;
|
||||
ovs_stats->n_packets += stats->packet_count;
|
||||
ovs_stats->n_bytes += stats->byte_count;
|
||||
spin_unlock_bh(&stats->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Called with ovs_mutex. */
|
||||
void ovs_flow_stats_clear(struct sw_flow *flow)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
/* We open code this to make sure cpu 0 is always considered */
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask)) {
|
||||
struct sw_flow_stats *stats = ovsl_dereference(flow->stats[cpu]);
|
||||
|
||||
if (stats) {
|
||||
spin_lock_bh(&stats->lock);
|
||||
stats->used = 0;
|
||||
stats->packet_count = 0;
|
||||
stats->byte_count = 0;
|
||||
stats->tcp_flags = 0;
|
||||
spin_unlock_bh(&stats->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_header(struct sk_buff *skb, int len)
|
||||
{
|
||||
if (unlikely(skb->len < len))
|
||||
return -EINVAL;
|
||||
if (unlikely(!pskb_may_pull(skb, len)))
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool arphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
return pskb_may_pull(skb, skb_network_offset(skb) +
|
||||
sizeof(struct arp_eth_header));
|
||||
}
|
||||
|
||||
static int check_iphdr(struct sk_buff *skb)
|
||||
{
|
||||
unsigned int nh_ofs = skb_network_offset(skb);
|
||||
unsigned int ip_len;
|
||||
int err;
|
||||
|
||||
err = check_header(skb, nh_ofs + sizeof(struct iphdr));
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
ip_len = ip_hdrlen(skb);
|
||||
if (unlikely(ip_len < sizeof(struct iphdr) ||
|
||||
skb->len < nh_ofs + ip_len))
|
||||
return -EINVAL;
|
||||
|
||||
skb_set_transport_header(skb, nh_ofs + ip_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tcphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
int th_ofs = skb_transport_offset(skb);
|
||||
int tcp_len;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))))
|
||||
return false;
|
||||
|
||||
tcp_len = tcp_hdrlen(skb);
|
||||
if (unlikely(tcp_len < sizeof(struct tcphdr) ||
|
||||
skb->len < th_ofs + tcp_len))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool udphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
return pskb_may_pull(skb, skb_transport_offset(skb) +
|
||||
sizeof(struct udphdr));
|
||||
}
|
||||
|
||||
static bool sctphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
return pskb_may_pull(skb, skb_transport_offset(skb) +
|
||||
sizeof(struct sctphdr));
|
||||
}
|
||||
|
||||
static bool icmphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
return pskb_may_pull(skb, skb_transport_offset(skb) +
|
||||
sizeof(struct icmphdr));
|
||||
}
|
||||
|
||||
static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
unsigned short frag_off;
|
||||
unsigned int payload_ofs = 0;
|
||||
unsigned int nh_ofs = skb_network_offset(skb);
|
||||
unsigned int nh_len;
|
||||
struct ipv6hdr *nh;
|
||||
int err, nexthdr, flags = 0;
|
||||
|
||||
err = check_header(skb, nh_ofs + sizeof(*nh));
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
nh = ipv6_hdr(skb);
|
||||
|
||||
key->ip.proto = NEXTHDR_NONE;
|
||||
key->ip.tos = ipv6_get_dsfield(nh);
|
||||
key->ip.ttl = nh->hop_limit;
|
||||
key->ipv6.label = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
|
||||
key->ipv6.addr.src = nh->saddr;
|
||||
key->ipv6.addr.dst = nh->daddr;
|
||||
|
||||
nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags);
|
||||
if (flags & IP6_FH_F_FRAG) {
|
||||
if (frag_off) {
|
||||
key->ip.frag = OVS_FRAG_TYPE_LATER;
|
||||
key->ip.proto = nexthdr;
|
||||
return 0;
|
||||
}
|
||||
key->ip.frag = OVS_FRAG_TYPE_FIRST;
|
||||
} else {
|
||||
key->ip.frag = OVS_FRAG_TYPE_NONE;
|
||||
}
|
||||
|
||||
/* Delayed handling of error in ipv6_find_hdr() as it
|
||||
* always sets flags and frag_off to a valid value which may be
|
||||
* used to set key->ip.frag above.
|
||||
*/
|
||||
if (unlikely(nexthdr < 0))
|
||||
return -EPROTO;
|
||||
|
||||
nh_len = payload_ofs - nh_ofs;
|
||||
skb_set_transport_header(skb, nh_ofs + nh_len);
|
||||
key->ip.proto = nexthdr;
|
||||
return nh_len;
|
||||
}
|
||||
|
||||
static bool icmp6hdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
return pskb_may_pull(skb, skb_transport_offset(skb) +
|
||||
sizeof(struct icmp6hdr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse vlan tag from vlan header.
|
||||
* Returns ERROR on memory error.
|
||||
* Returns 0 if it encounters a non-vlan or incomplete packet.
|
||||
* Returns 1 after successfully parsing vlan tag.
|
||||
*/
|
||||
static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh,
|
||||
bool untag_vlan)
|
||||
{
|
||||
struct vlan_head *vh = (struct vlan_head *)skb->data;
|
||||
|
||||
if (likely(!eth_type_vlan(vh->tpid)))
|
||||
return 0;
|
||||
|
||||
if (unlikely(skb->len < sizeof(struct vlan_head) + sizeof(__be16)))
|
||||
return 0;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, sizeof(struct vlan_head) +
|
||||
sizeof(__be16))))
|
||||
return -ENOMEM;
|
||||
|
||||
vh = (struct vlan_head *)skb->data;
|
||||
key_vh->tci = vh->tci | htons(VLAN_CFI_MASK);
|
||||
key_vh->tpid = vh->tpid;
|
||||
|
||||
if (unlikely(untag_vlan)) {
|
||||
int offset = skb->data - skb_mac_header(skb);
|
||||
u16 tci;
|
||||
int err;
|
||||
|
||||
__skb_push(skb, offset);
|
||||
err = __skb_vlan_pop(skb, &tci);
|
||||
__skb_pull(skb, offset);
|
||||
if (err)
|
||||
return err;
|
||||
__vlan_hwaccel_put_tag(skb, key_vh->tpid, tci);
|
||||
} else {
|
||||
__skb_pull(skb, sizeof(struct vlan_head));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void clear_vlan(struct sw_flow_key *key)
|
||||
{
|
||||
key->eth.vlan.tci = 0;
|
||||
key->eth.vlan.tpid = 0;
|
||||
key->eth.cvlan.tci = 0;
|
||||
key->eth.cvlan.tpid = 0;
|
||||
}
|
||||
|
||||
static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
int res;
|
||||
|
||||
key->eth.vlan.tci = 0;
|
||||
key->eth.vlan.tpid = 0;
|
||||
key->eth.cvlan.tci = 0;
|
||||
key->eth.cvlan.tpid = 0;
|
||||
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
key->eth.vlan.tci = htons(skb->vlan_tci) | htons(VLAN_CFI_MASK);
|
||||
key->eth.vlan.tpid = skb->vlan_proto;
|
||||
} else {
|
||||
/* Parse outer vlan tag in the non-accelerated case. */
|
||||
res = parse_vlan_tag(skb, &key->eth.vlan, true);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Parse inner vlan tag. */
|
||||
res = parse_vlan_tag(skb, &key->eth.cvlan, false);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __be16 parse_ethertype(struct sk_buff *skb)
|
||||
{
|
||||
struct llc_snap_hdr {
|
||||
u8 dsap; /* Always 0xAA */
|
||||
u8 ssap; /* Always 0xAA */
|
||||
u8 ctrl;
|
||||
u8 oui[3];
|
||||
__be16 ethertype;
|
||||
};
|
||||
struct llc_snap_hdr *llc;
|
||||
__be16 proto;
|
||||
|
||||
proto = *(__be16 *) skb->data;
|
||||
__skb_pull(skb, sizeof(__be16));
|
||||
|
||||
if (eth_proto_is_802_3(proto))
|
||||
return proto;
|
||||
|
||||
if (skb->len < sizeof(struct llc_snap_hdr))
|
||||
return htons(ETH_P_802_2);
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, sizeof(struct llc_snap_hdr))))
|
||||
return htons(0);
|
||||
|
||||
llc = (struct llc_snap_hdr *) skb->data;
|
||||
if (llc->dsap != LLC_SAP_SNAP ||
|
||||
llc->ssap != LLC_SAP_SNAP ||
|
||||
(llc->oui[0] | llc->oui[1] | llc->oui[2]) != 0)
|
||||
return htons(ETH_P_802_2);
|
||||
|
||||
__skb_pull(skb, sizeof(struct llc_snap_hdr));
|
||||
|
||||
if (eth_proto_is_802_3(llc->ethertype))
|
||||
return llc->ethertype;
|
||||
|
||||
return htons(ETH_P_802_2);
|
||||
}
|
||||
|
||||
static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
|
||||
int nh_len)
|
||||
{
|
||||
struct icmp6hdr *icmp = icmp6_hdr(skb);
|
||||
|
||||
/* The ICMPv6 type and code fields use the 16-bit transport port
|
||||
* fields, so we need to store them in 16-bit network byte order.
|
||||
*/
|
||||
key->tp.src = htons(icmp->icmp6_type);
|
||||
key->tp.dst = htons(icmp->icmp6_code);
|
||||
memset(&key->ipv6.nd, 0, sizeof(key->ipv6.nd));
|
||||
|
||||
if (icmp->icmp6_code == 0 &&
|
||||
(icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION ||
|
||||
icmp->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT)) {
|
||||
int icmp_len = skb->len - skb_transport_offset(skb);
|
||||
struct nd_msg *nd;
|
||||
int offset;
|
||||
|
||||
/* In order to process neighbor discovery options, we need the
|
||||
* entire packet.
|
||||
*/
|
||||
if (unlikely(icmp_len < sizeof(*nd)))
|
||||
return 0;
|
||||
|
||||
if (unlikely(skb_linearize(skb)))
|
||||
return -ENOMEM;
|
||||
|
||||
nd = (struct nd_msg *)skb_transport_header(skb);
|
||||
key->ipv6.nd.target = nd->target;
|
||||
|
||||
icmp_len -= sizeof(*nd);
|
||||
offset = 0;
|
||||
while (icmp_len >= 8) {
|
||||
struct nd_opt_hdr *nd_opt =
|
||||
(struct nd_opt_hdr *)(nd->opt + offset);
|
||||
int opt_len = nd_opt->nd_opt_len * 8;
|
||||
|
||||
if (unlikely(!opt_len || opt_len > icmp_len))
|
||||
return 0;
|
||||
|
||||
/* Store the link layer address if the appropriate
|
||||
* option is provided. It is considered an error if
|
||||
* the same link layer option is specified twice.
|
||||
*/
|
||||
if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LL_ADDR
|
||||
&& opt_len == 8) {
|
||||
if (unlikely(!is_zero_ether_addr(key->ipv6.nd.sll)))
|
||||
goto invalid;
|
||||
ether_addr_copy(key->ipv6.nd.sll,
|
||||
&nd->opt[offset+sizeof(*nd_opt)]);
|
||||
} else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LL_ADDR
|
||||
&& opt_len == 8) {
|
||||
if (unlikely(!is_zero_ether_addr(key->ipv6.nd.tll)))
|
||||
goto invalid;
|
||||
ether_addr_copy(key->ipv6.nd.tll,
|
||||
&nd->opt[offset+sizeof(*nd_opt)]);
|
||||
}
|
||||
|
||||
icmp_len -= opt_len;
|
||||
offset += opt_len;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
invalid:
|
||||
memset(&key->ipv6.nd.target, 0, sizeof(key->ipv6.nd.target));
|
||||
memset(key->ipv6.nd.sll, 0, sizeof(key->ipv6.nd.sll));
|
||||
memset(key->ipv6.nd.tll, 0, sizeof(key->ipv6.nd.tll));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
struct nshhdr *nh;
|
||||
unsigned int nh_ofs = skb_network_offset(skb);
|
||||
u8 version, length;
|
||||
int err;
|
||||
|
||||
err = check_header(skb, nh_ofs + NSH_BASE_HDR_LEN);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
nh = nsh_hdr(skb);
|
||||
version = nsh_get_ver(nh);
|
||||
length = nsh_hdr_len(nh);
|
||||
|
||||
if (version != 0)
|
||||
return -EINVAL;
|
||||
|
||||
err = check_header(skb, nh_ofs + length);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
nh = nsh_hdr(skb);
|
||||
key->nsh.base.flags = nsh_get_flags(nh);
|
||||
key->nsh.base.ttl = nsh_get_ttl(nh);
|
||||
key->nsh.base.mdtype = nh->mdtype;
|
||||
key->nsh.base.np = nh->np;
|
||||
key->nsh.base.path_hdr = nh->path_hdr;
|
||||
switch (key->nsh.base.mdtype) {
|
||||
case NSH_M_TYPE1:
|
||||
if (length != NSH_M_TYPE1_LEN)
|
||||
return -EINVAL;
|
||||
memcpy(key->nsh.context, nh->md1.context,
|
||||
sizeof(nh->md1));
|
||||
break;
|
||||
case NSH_M_TYPE2:
|
||||
memset(key->nsh.context, 0,
|
||||
sizeof(nh->md1));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* key_extract_l3l4 - extracts L3/L4 header information.
|
||||
* @skb: sk_buff that contains the frame, with skb->data pointing to the
|
||||
* L3 header
|
||||
* @key: output flow key
|
||||
*/
|
||||
static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Network layer. */
|
||||
if (key->eth.type == htons(ETH_P_IP)) {
|
||||
struct iphdr *nh;
|
||||
__be16 offset;
|
||||
|
||||
error = check_iphdr(skb);
|
||||
if (unlikely(error)) {
|
||||
memset(&key->ip, 0, sizeof(key->ip));
|
||||
memset(&key->ipv4, 0, sizeof(key->ipv4));
|
||||
if (error == -EINVAL) {
|
||||
skb->transport_header = skb->network_header;
|
||||
error = 0;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
nh = ip_hdr(skb);
|
||||
key->ipv4.addr.src = nh->saddr;
|
||||
key->ipv4.addr.dst = nh->daddr;
|
||||
|
||||
key->ip.proto = nh->protocol;
|
||||
key->ip.tos = nh->tos;
|
||||
key->ip.ttl = nh->ttl;
|
||||
|
||||
offset = nh->frag_off & htons(IP_OFFSET);
|
||||
if (offset) {
|
||||
key->ip.frag = OVS_FRAG_TYPE_LATER;
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_SKB_GSO_UDP
|
||||
if (nh->frag_off & htons(IP_MF) ||
|
||||
skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
|
||||
#else
|
||||
if (nh->frag_off & htons(IP_MF))
|
||||
#endif
|
||||
key->ip.frag = OVS_FRAG_TYPE_FIRST;
|
||||
else
|
||||
key->ip.frag = OVS_FRAG_TYPE_NONE;
|
||||
|
||||
/* Transport layer. */
|
||||
if (key->ip.proto == IPPROTO_TCP) {
|
||||
if (tcphdr_ok(skb)) {
|
||||
struct tcphdr *tcp = tcp_hdr(skb);
|
||||
key->tp.src = tcp->source;
|
||||
key->tp.dst = tcp->dest;
|
||||
key->tp.flags = TCP_FLAGS_BE16(tcp);
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
|
||||
} else if (key->ip.proto == IPPROTO_UDP) {
|
||||
if (udphdr_ok(skb)) {
|
||||
struct udphdr *udp = udp_hdr(skb);
|
||||
key->tp.src = udp->source;
|
||||
key->tp.dst = udp->dest;
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
} else if (key->ip.proto == IPPROTO_SCTP) {
|
||||
if (sctphdr_ok(skb)) {
|
||||
struct sctphdr *sctp = sctp_hdr(skb);
|
||||
key->tp.src = sctp->source;
|
||||
key->tp.dst = sctp->dest;
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
} else if (key->ip.proto == IPPROTO_ICMP) {
|
||||
if (icmphdr_ok(skb)) {
|
||||
struct icmphdr *icmp = icmp_hdr(skb);
|
||||
/* The ICMP type and code fields use the 16-bit
|
||||
* transport port fields, so we need to store
|
||||
* them in 16-bit network byte order.
|
||||
*/
|
||||
key->tp.src = htons(icmp->type);
|
||||
key->tp.dst = htons(icmp->code);
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (key->eth.type == htons(ETH_P_ARP) ||
|
||||
key->eth.type == htons(ETH_P_RARP)) {
|
||||
struct arp_eth_header *arp;
|
||||
bool arp_available = arphdr_ok(skb);
|
||||
|
||||
arp = (struct arp_eth_header *)skb_network_header(skb);
|
||||
|
||||
if (arp_available &&
|
||||
arp->ar_hrd == htons(ARPHRD_ETHER) &&
|
||||
arp->ar_pro == htons(ETH_P_IP) &&
|
||||
arp->ar_hln == ETH_ALEN &&
|
||||
arp->ar_pln == 4) {
|
||||
|
||||
/* We only match on the lower 8 bits of the opcode. */
|
||||
if (ntohs(arp->ar_op) <= 0xff)
|
||||
key->ip.proto = ntohs(arp->ar_op);
|
||||
else
|
||||
key->ip.proto = 0;
|
||||
|
||||
memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
|
||||
memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
|
||||
ether_addr_copy(key->ipv4.arp.sha, arp->ar_sha);
|
||||
ether_addr_copy(key->ipv4.arp.tha, arp->ar_tha);
|
||||
} else {
|
||||
memset(&key->ip, 0, sizeof(key->ip));
|
||||
memset(&key->ipv4, 0, sizeof(key->ipv4));
|
||||
}
|
||||
} else if (eth_p_mpls(key->eth.type)) {
|
||||
u8 label_count = 1;
|
||||
|
||||
memset(&key->mpls, 0, sizeof(key->mpls));
|
||||
skb_set_inner_network_header(skb, skb->mac_len);
|
||||
while (1) {
|
||||
__be32 lse;
|
||||
|
||||
error = check_header(skb, skb->mac_len +
|
||||
label_count * MPLS_HLEN);
|
||||
if (unlikely(error))
|
||||
return 0;
|
||||
|
||||
memcpy(&lse, skb_inner_network_header(skb), MPLS_HLEN);
|
||||
|
||||
if (label_count <= MPLS_LABEL_DEPTH)
|
||||
memcpy(&key->mpls.lse[label_count - 1], &lse,
|
||||
MPLS_HLEN);
|
||||
|
||||
skb_set_inner_network_header(skb, skb->mac_len +
|
||||
label_count * MPLS_HLEN);
|
||||
if (lse & htonl(MPLS_LS_S_MASK))
|
||||
break;
|
||||
|
||||
label_count++;
|
||||
}
|
||||
if (label_count > MPLS_LABEL_DEPTH)
|
||||
label_count = MPLS_LABEL_DEPTH;
|
||||
|
||||
key->mpls.num_labels_mask = GENMASK(label_count - 1, 0);
|
||||
} else if (key->eth.type == htons(ETH_P_IPV6)) {
|
||||
int nh_len; /* IPv6 Header + Extensions */
|
||||
|
||||
nh_len = parse_ipv6hdr(skb, key);
|
||||
if (unlikely(nh_len < 0)) {
|
||||
switch (nh_len) {
|
||||
case -EINVAL:
|
||||
memset(&key->ip, 0, sizeof(key->ip));
|
||||
memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr));
|
||||
/* fall-through */
|
||||
case -EPROTO:
|
||||
skb->transport_header = skb->network_header;
|
||||
error = 0;
|
||||
break;
|
||||
default:
|
||||
error = nh_len;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
if (key->ip.frag == OVS_FRAG_TYPE_LATER) {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_SKB_GSO_UDP
|
||||
if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
|
||||
key->ip.frag = OVS_FRAG_TYPE_FIRST;
|
||||
|
||||
#endif
|
||||
/* Transport layer. */
|
||||
if (key->ip.proto == NEXTHDR_TCP) {
|
||||
if (tcphdr_ok(skb)) {
|
||||
struct tcphdr *tcp = tcp_hdr(skb);
|
||||
key->tp.src = tcp->source;
|
||||
key->tp.dst = tcp->dest;
|
||||
key->tp.flags = TCP_FLAGS_BE16(tcp);
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
} else if (key->ip.proto == NEXTHDR_UDP) {
|
||||
if (udphdr_ok(skb)) {
|
||||
struct udphdr *udp = udp_hdr(skb);
|
||||
key->tp.src = udp->source;
|
||||
key->tp.dst = udp->dest;
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
} else if (key->ip.proto == NEXTHDR_SCTP) {
|
||||
if (sctphdr_ok(skb)) {
|
||||
struct sctphdr *sctp = sctp_hdr(skb);
|
||||
key->tp.src = sctp->source;
|
||||
key->tp.dst = sctp->dest;
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
} else if (key->ip.proto == NEXTHDR_ICMP) {
|
||||
if (icmp6hdr_ok(skb)) {
|
||||
error = parse_icmpv6(skb, key, nh_len);
|
||||
if (error)
|
||||
return error;
|
||||
} else {
|
||||
memset(&key->tp, 0, sizeof(key->tp));
|
||||
}
|
||||
}
|
||||
} else if (key->eth.type == htons(ETH_P_NSH)) {
|
||||
error = parse_nsh(skb, key);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* key_extract - extracts a flow key from an Ethernet frame.
|
||||
* @skb: sk_buff that contains the frame, with skb->data pointing to the
|
||||
* Ethernet header
|
||||
* @key: output flow key
|
||||
*
|
||||
* The caller must ensure that skb->len >= ETH_HLEN.
|
||||
*
|
||||
* Returns 0 if successful, otherwise a negative errno value.
|
||||
*
|
||||
* Initializes @skb header fields as follows:
|
||||
*
|
||||
* - skb->mac_header: the L2 header.
|
||||
*
|
||||
* - skb->network_header: just past the L2 header, or just past the
|
||||
* VLAN header, to the first byte of the L2 payload.
|
||||
*
|
||||
* - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6
|
||||
* on output, then just past the IP header, if one is present and
|
||||
* of a correct length, otherwise the same as skb->network_header.
|
||||
* For other key->eth.type values it is left untouched.
|
||||
*
|
||||
* - skb->protocol: the type of the data starting at skb->network_header.
|
||||
* Equals to key->eth.type.
|
||||
*/
|
||||
static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
struct ethhdr *eth;
|
||||
|
||||
/* Flags are always used as part of stats */
|
||||
key->tp.flags = 0;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
/* Link layer. */
|
||||
clear_vlan(key);
|
||||
if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) {
|
||||
if (unlikely(eth_type_vlan(skb->protocol)))
|
||||
return -EINVAL;
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
key->eth.type = skb->protocol;
|
||||
} else {
|
||||
eth = eth_hdr(skb);
|
||||
ether_addr_copy(key->eth.src, eth->h_source);
|
||||
ether_addr_copy(key->eth.dst, eth->h_dest);
|
||||
|
||||
__skb_pull(skb, 2 * ETH_ALEN);
|
||||
/* We are going to push all headers that we pull, so no need to
|
||||
* update skb->csum here.
|
||||
*/
|
||||
|
||||
if (unlikely(parse_vlan(skb, key)))
|
||||
return -ENOMEM;
|
||||
|
||||
key->eth.type = parse_ethertype(skb);
|
||||
if (unlikely(key->eth.type == htons(0)))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Multiple tagged packets need to retain TPID to satisfy
|
||||
* skb_vlan_pop(), which will later shift the ethertype into
|
||||
* skb->protocol.
|
||||
*/
|
||||
if (key->eth.cvlan.tci & htons(VLAN_CFI_MASK))
|
||||
skb->protocol = key->eth.cvlan.tpid;
|
||||
else
|
||||
skb->protocol = key->eth.type;
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
__skb_push(skb, skb->data - skb_mac_header(skb));
|
||||
}
|
||||
|
||||
skb_reset_mac_len(skb);
|
||||
|
||||
/* Fill out L3/L4 key info, if any */
|
||||
return key_extract_l3l4(skb, key);
|
||||
}
|
||||
|
||||
/* In the case of conntrack fragment handling it expects L3 headers,
|
||||
* add a helper.
|
||||
*/
|
||||
int ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
return key_extract_l3l4(skb, key);
|
||||
}
|
||||
|
||||
int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = key_extract(skb, key);
|
||||
if (!res)
|
||||
key->mac_proto &= ~SW_FLOW_KEY_INVALID;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int key_extract_mac_proto(struct sk_buff *skb)
|
||||
{
|
||||
switch (skb->dev->type) {
|
||||
case ARPHRD_ETHER:
|
||||
return MAC_PROTO_ETHERNET;
|
||||
case ARPHRD_NONE:
|
||||
if (skb->protocol == htons(ETH_P_TEB))
|
||||
return MAC_PROTO_ETHERNET;
|
||||
return MAC_PROTO_NONE;
|
||||
}
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
|
||||
struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
|
||||
struct tc_skb_ext *tc_ext;
|
||||
#endif
|
||||
int res, err;
|
||||
|
||||
/* Extract metadata from packet. */
|
||||
if (tun_info) {
|
||||
key->tun_proto = ip_tunnel_info_af(tun_info);
|
||||
memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key));
|
||||
BUILD_BUG_ON(((1 << (sizeof(tun_info->options_len) * 8)) - 1) >
|
||||
sizeof(key->tun_opts));
|
||||
|
||||
if (tun_info->options_len) {
|
||||
ip_tunnel_info_opts_get(TUN_METADATA_OPTS(key, tun_info->options_len),
|
||||
tun_info);
|
||||
key->tun_opts_len = tun_info->options_len;
|
||||
} else {
|
||||
key->tun_opts_len = 0;
|
||||
}
|
||||
} else {
|
||||
key->tun_proto = 0;
|
||||
key->tun_opts_len = 0;
|
||||
memset(&key->tun_key, 0, sizeof(key->tun_key));
|
||||
}
|
||||
|
||||
key->phy.priority = skb->priority;
|
||||
key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
|
||||
key->phy.skb_mark = skb->mark;
|
||||
key->ovs_flow_hash = 0;
|
||||
res = key_extract_mac_proto(skb);
|
||||
if (res < 0)
|
||||
return res;
|
||||
key->mac_proto = res;
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
|
||||
if (static_branch_unlikely(&tc_recirc_sharing_support)) {
|
||||
tc_ext = skb_ext_find(skb, TC_SKB_EXT);
|
||||
key->recirc_id = tc_ext ? tc_ext->chain : 0;
|
||||
} else {
|
||||
key->recirc_id = 0;
|
||||
}
|
||||
#else
|
||||
key->recirc_id = 0;
|
||||
#endif
|
||||
|
||||
err = key_extract(skb, key);
|
||||
if (!err)
|
||||
ovs_ct_fill_key(skb, key); /* Must be after key_extract(). */
|
||||
return err;
|
||||
}
|
||||
|
||||
int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
|
||||
struct sk_buff *skb,
|
||||
struct sw_flow_key *key, bool log)
|
||||
{
|
||||
const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
|
||||
u64 attrs = 0;
|
||||
int err;
|
||||
|
||||
err = parse_flow_nlattrs(attr, a, &attrs, log);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
/* Extract metadata from netlink attributes. */
|
||||
err = ovs_nla_get_flow_metadata(net, a, attrs, key, log);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* key_extract assumes that skb->protocol is set-up for
|
||||
* layer 3 packets which is the case for other callers,
|
||||
* in particular packets received from the network stack.
|
||||
* Here the correct value can be set from the metadata
|
||||
* extracted above.
|
||||
* For L2 packet key eth type would be zero. skb protocol
|
||||
* would be set to correct value later during key-extact.
|
||||
*/
|
||||
|
||||
skb->protocol = key->eth.type;
|
||||
err = key_extract(skb, key);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Check that we have conntrack original direction tuple metadata only
|
||||
* for packets for which it makes sense. Otherwise the key may be
|
||||
* corrupted due to overlapping key fields.
|
||||
*/
|
||||
if (attrs & (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4) &&
|
||||
key->eth.type != htons(ETH_P_IP))
|
||||
return -EINVAL;
|
||||
if (attrs & (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6) &&
|
||||
(key->eth.type != htons(ETH_P_IPV6) ||
|
||||
sw_flow_key_is_nd(key)))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
297
datapath/flow.h
297
datapath/flow.h
@@ -1,297 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2017 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
|
||||
*/
|
||||
|
||||
#ifndef FLOW_H
|
||||
#define FLOW_H 1
|
||||
|
||||
#include <linux/cache.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/openvswitch.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <net/inet_ecn.h>
|
||||
#include <net/ip_tunnels.h>
|
||||
#include <net/dst_metadata.h>
|
||||
#include <net/nsh.h>
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
enum sw_flow_mac_proto {
|
||||
MAC_PROTO_NONE = 0,
|
||||
MAC_PROTO_ETHERNET,
|
||||
};
|
||||
#define SW_FLOW_KEY_INVALID 0x80
|
||||
#define MPLS_LABEL_DEPTH 3
|
||||
|
||||
/* Store options at the end of the array if they are less than the
|
||||
* maximum size. This allows us to get the benefits of variable length
|
||||
* matching for small options.
|
||||
*/
|
||||
#define TUN_METADATA_OFFSET(opt_len) \
|
||||
(sizeof_field(struct sw_flow_key, tun_opts) - opt_len)
|
||||
#define TUN_METADATA_OPTS(flow_key, opt_len) \
|
||||
((void *)((flow_key)->tun_opts + TUN_METADATA_OFFSET(opt_len)))
|
||||
|
||||
struct ovs_tunnel_info {
|
||||
struct metadata_dst *tun_dst;
|
||||
};
|
||||
|
||||
struct vlan_head {
|
||||
__be16 tpid; /* Vlan type. Generally 802.1q or 802.1ad.*/
|
||||
__be16 tci; /* 0 if no VLAN, VLAN_CFI_MASK set otherwise. */
|
||||
};
|
||||
|
||||
#define OVS_SW_FLOW_KEY_METADATA_SIZE \
|
||||
(offsetof(struct sw_flow_key, recirc_id) + \
|
||||
sizeof_field(struct sw_flow_key, recirc_id))
|
||||
|
||||
struct ovs_key_nsh {
|
||||
struct ovs_nsh_key_base base;
|
||||
__be32 context[NSH_MD1_CONTEXT_SIZE];
|
||||
};
|
||||
|
||||
struct sw_flow_key {
|
||||
u8 tun_opts[255];
|
||||
u8 tun_opts_len;
|
||||
struct ip_tunnel_key tun_key; /* Encapsulating tunnel key. */
|
||||
struct {
|
||||
u32 priority; /* Packet QoS priority. */
|
||||
u32 skb_mark; /* SKB mark. */
|
||||
u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
|
||||
} __packed phy; /* Safe when right after 'tun_key'. */
|
||||
u8 mac_proto; /* MAC layer protocol (e.g. Ethernet). */
|
||||
u8 tun_proto; /* Protocol of encapsulating tunnel. */
|
||||
u32 ovs_flow_hash; /* Datapath computed hash value. */
|
||||
u32 recirc_id; /* Recirculation ID. */
|
||||
struct {
|
||||
u8 src[ETH_ALEN]; /* Ethernet source address. */
|
||||
u8 dst[ETH_ALEN]; /* Ethernet destination address. */
|
||||
struct vlan_head vlan;
|
||||
struct vlan_head cvlan;
|
||||
__be16 type; /* Ethernet frame type. */
|
||||
} eth;
|
||||
/* Filling a hole of two bytes. */
|
||||
u8 ct_state;
|
||||
u8 ct_orig_proto; /* CT original direction tuple IP
|
||||
* protocol.
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */
|
||||
u8 tos; /* IP ToS. */
|
||||
u8 ttl; /* IP TTL/hop limit. */
|
||||
u8 frag; /* One of OVS_FRAG_TYPE_*. */
|
||||
} ip;
|
||||
};
|
||||
u16 ct_zone; /* Conntrack zone. */
|
||||
struct {
|
||||
__be16 src; /* TCP/UDP/SCTP source port. */
|
||||
__be16 dst; /* TCP/UDP/SCTP destination port. */
|
||||
__be16 flags; /* TCP flags. */
|
||||
} tp;
|
||||
union {
|
||||
struct {
|
||||
struct {
|
||||
__be32 src; /* IP source address. */
|
||||
__be32 dst; /* IP destination address. */
|
||||
} addr;
|
||||
union {
|
||||
struct {
|
||||
__be32 src;
|
||||
__be32 dst;
|
||||
} ct_orig; /* Conntrack original direction fields. */
|
||||
struct {
|
||||
u8 sha[ETH_ALEN]; /* ARP source hardware address. */
|
||||
u8 tha[ETH_ALEN]; /* ARP target hardware address. */
|
||||
} arp;
|
||||
};
|
||||
} ipv4;
|
||||
struct {
|
||||
struct {
|
||||
struct in6_addr src; /* IPv6 source address. */
|
||||
struct in6_addr dst; /* IPv6 destination address. */
|
||||
} addr;
|
||||
__be32 label; /* IPv6 flow label. */
|
||||
union {
|
||||
struct {
|
||||
struct in6_addr src;
|
||||
struct in6_addr dst;
|
||||
} ct_orig; /* Conntrack original direction fields. */
|
||||
struct {
|
||||
struct in6_addr target; /* ND target address. */
|
||||
u8 sll[ETH_ALEN]; /* ND source link layer address. */
|
||||
u8 tll[ETH_ALEN]; /* ND target link layer address. */
|
||||
} nd;
|
||||
};
|
||||
} ipv6;
|
||||
struct {
|
||||
u32 num_labels_mask; /* labels present bitmap of effective length MPLS_LABEL_DEPTH */
|
||||
__be32 lse[MPLS_LABEL_DEPTH]; /* label stack entry */
|
||||
} mpls;
|
||||
struct ovs_key_nsh nsh; /* network service header */
|
||||
};
|
||||
struct {
|
||||
/* Connection tracking fields not packed above. */
|
||||
struct {
|
||||
__be16 src; /* CT orig tuple tp src port. */
|
||||
__be16 dst; /* CT orig tuple tp dst port. */
|
||||
} orig_tp;
|
||||
u32 mark;
|
||||
struct ovs_key_ct_labels labels;
|
||||
} ct;
|
||||
|
||||
} __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */
|
||||
|
||||
static inline bool sw_flow_key_is_nd(const struct sw_flow_key *key)
|
||||
{
|
||||
return key->eth.type == htons(ETH_P_IPV6) &&
|
||||
key->ip.proto == NEXTHDR_ICMP &&
|
||||
key->tp.dst == 0 &&
|
||||
(key->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) ||
|
||||
key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT));
|
||||
}
|
||||
|
||||
struct sw_flow_key_range {
|
||||
unsigned short int start;
|
||||
unsigned short int end;
|
||||
};
|
||||
|
||||
struct sw_flow_mask {
|
||||
int ref_count;
|
||||
struct rcu_head rcu;
|
||||
struct sw_flow_key_range range;
|
||||
struct sw_flow_key key;
|
||||
};
|
||||
|
||||
struct sw_flow_match {
|
||||
struct sw_flow_key *key;
|
||||
struct sw_flow_key_range range;
|
||||
struct sw_flow_mask *mask;
|
||||
};
|
||||
|
||||
#define MAX_UFID_LENGTH 16 /* 128 bits */
|
||||
|
||||
struct sw_flow_id {
|
||||
u32 ufid_len;
|
||||
union {
|
||||
u32 ufid[MAX_UFID_LENGTH / 4];
|
||||
struct sw_flow_key *unmasked_key;
|
||||
};
|
||||
};
|
||||
|
||||
struct sw_flow_actions {
|
||||
struct rcu_head rcu;
|
||||
size_t orig_len; /* From flow_cmd_new netlink actions size */
|
||||
u32 actions_len;
|
||||
struct nlattr actions[];
|
||||
};
|
||||
|
||||
struct sw_flow_stats {
|
||||
u64 packet_count; /* Number of packets matched. */
|
||||
u64 byte_count; /* Number of bytes matched. */
|
||||
unsigned long used; /* Last used time (in jiffies). */
|
||||
spinlock_t lock; /* Lock for atomic stats update. */
|
||||
__be16 tcp_flags; /* Union of seen TCP flags. */
|
||||
};
|
||||
|
||||
struct sw_flow {
|
||||
struct rcu_head rcu;
|
||||
struct {
|
||||
struct hlist_node node[2];
|
||||
u32 hash;
|
||||
} flow_table, ufid_table;
|
||||
int stats_last_writer; /* CPU id of the last writer on
|
||||
* 'stats[0]'.
|
||||
*/
|
||||
struct sw_flow_key key;
|
||||
struct sw_flow_id id;
|
||||
struct cpumask cpu_used_mask;
|
||||
struct sw_flow_mask *mask;
|
||||
struct sw_flow_actions __rcu *sf_acts;
|
||||
struct sw_flow_stats __rcu *stats[]; /* One for each CPU. First one
|
||||
* is allocated at flow creation time,
|
||||
* the rest are allocated on demand
|
||||
* while holding the 'stats[0].lock'.
|
||||
*/
|
||||
};
|
||||
|
||||
struct arp_eth_header {
|
||||
__be16 ar_hrd; /* format of hardware address */
|
||||
__be16 ar_pro; /* format of protocol address */
|
||||
unsigned char ar_hln; /* length of hardware address */
|
||||
unsigned char ar_pln; /* length of protocol address */
|
||||
__be16 ar_op; /* ARP opcode (command) */
|
||||
|
||||
/* Ethernet+IPv4 specific members. */
|
||||
unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
|
||||
unsigned char ar_sip[4]; /* sender IP address */
|
||||
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
|
||||
unsigned char ar_tip[4]; /* target IP address */
|
||||
} __packed;
|
||||
|
||||
static inline u8 ovs_key_mac_proto(const struct sw_flow_key *key)
|
||||
{
|
||||
return key->mac_proto & ~SW_FLOW_KEY_INVALID;
|
||||
}
|
||||
|
||||
static inline u16 __ovs_mac_header_len(u8 mac_proto)
|
||||
{
|
||||
return mac_proto == MAC_PROTO_ETHERNET ? ETH_HLEN : 0;
|
||||
}
|
||||
|
||||
static inline u16 ovs_mac_header_len(const struct sw_flow_key *key)
|
||||
{
|
||||
return __ovs_mac_header_len(ovs_key_mac_proto(key));
|
||||
}
|
||||
|
||||
static inline bool ovs_identifier_is_ufid(const struct sw_flow_id *sfid)
|
||||
{
|
||||
return sfid->ufid_len;
|
||||
}
|
||||
|
||||
static inline bool ovs_identifier_is_key(const struct sw_flow_id *sfid)
|
||||
{
|
||||
return !ovs_identifier_is_ufid(sfid);
|
||||
}
|
||||
|
||||
void ovs_flow_stats_update(struct sw_flow *, __be16 tcp_flags,
|
||||
const struct sk_buff *);
|
||||
void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *,
|
||||
unsigned long *used, __be16 *tcp_flags);
|
||||
void ovs_flow_stats_clear(struct sw_flow *);
|
||||
u64 ovs_flow_used_time(unsigned long flow_jiffies);
|
||||
|
||||
/* Update the non-metadata part of the flow key using skb. */
|
||||
int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key);
|
||||
int ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key);
|
||||
int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
|
||||
struct sk_buff *skb,
|
||||
struct sw_flow_key *key);
|
||||
/* Extract key from packet coming from userspace. */
|
||||
int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
|
||||
struct sk_buff *skb,
|
||||
struct sw_flow_key *key, bool log);
|
||||
|
||||
#endif /* flow.h */
|
File diff suppressed because it is too large
Load Diff
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2015 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
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FLOW_NETLINK_H
|
||||
#define FLOW_NETLINK_H 1
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/openvswitch.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <net/inet_ecn.h>
|
||||
#include <net/ip_tunnels.h>
|
||||
|
||||
#include "flow.h"
|
||||
|
||||
size_t ovs_tun_key_attr_size(void);
|
||||
size_t ovs_key_attr_size(void);
|
||||
|
||||
void ovs_match_init(struct sw_flow_match *match,
|
||||
struct sw_flow_key *key, bool reset_key,
|
||||
struct sw_flow_mask *mask);
|
||||
|
||||
int ovs_nla_put_key(const struct sw_flow_key *, const struct sw_flow_key *,
|
||||
int attr, bool is_mask, struct sk_buff *);
|
||||
int parse_flow_nlattrs(const struct nlattr *attr, const struct nlattr *a[],
|
||||
u64 *attrsp, bool log);
|
||||
int ovs_nla_get_flow_metadata(struct net *net,
|
||||
const struct nlattr *a[OVS_KEY_ATTR_MAX + 1],
|
||||
u64 attrs, struct sw_flow_key *key, bool log);
|
||||
|
||||
int ovs_nla_put_identifier(const struct sw_flow *flow, struct sk_buff *skb);
|
||||
int ovs_nla_put_masked_key(const struct sw_flow *flow, struct sk_buff *skb);
|
||||
int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb);
|
||||
|
||||
int ovs_nla_get_match(struct net *, struct sw_flow_match *,
|
||||
const struct nlattr *key, const struct nlattr *mask,
|
||||
bool log);
|
||||
int ovs_nla_put_tunnel_info(struct sk_buff *skb,
|
||||
struct ip_tunnel_info *tun_info);
|
||||
|
||||
bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log);
|
||||
int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,
|
||||
const struct sw_flow_key *key, bool log);
|
||||
u32 ovs_nla_get_ufid_flags(const struct nlattr *attr);
|
||||
|
||||
int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
|
||||
const struct sw_flow_key *key,
|
||||
struct sw_flow_actions **sfa, bool log);
|
||||
int ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype,
|
||||
void *data, int len, bool log);
|
||||
int ovs_nla_put_actions(const struct nlattr *attr,
|
||||
int len, struct sk_buff *skb);
|
||||
|
||||
void ovs_nla_free_flow_actions(struct sw_flow_actions *);
|
||||
void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *);
|
||||
|
||||
int nsh_key_from_nlattr(const struct nlattr *attr, struct ovs_key_nsh *nsh,
|
||||
struct ovs_key_nsh *nsh_mask);
|
||||
int nsh_hdr_from_nlattr(const struct nlattr *attr, struct nshhdr *nh,
|
||||
size_t size);
|
||||
|
||||
#endif /* flow_netlink.h */
|
@@ -1,988 +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 "flow.h"
|
||||
#include "datapath.h"
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/llc_pdu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/llc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/ndisc.h>
|
||||
|
||||
#include "flow_netlink.h"
|
||||
|
||||
#define TBL_MIN_BUCKETS 1024
|
||||
#define MASK_ARRAY_SIZE_MIN 16
|
||||
#define REHASH_INTERVAL (10 * 60 * HZ)
|
||||
|
||||
#define MC_HASH_SHIFT 8
|
||||
#define MC_HASH_ENTRIES (1u << MC_HASH_SHIFT)
|
||||
#define MC_HASH_SEGS ((sizeof(uint32_t) * 8) / MC_HASH_SHIFT)
|
||||
|
||||
static struct kmem_cache *flow_cache;
|
||||
struct kmem_cache *flow_stats_cache __read_mostly;
|
||||
|
||||
static u16 range_n_bytes(const struct sw_flow_key_range *range)
|
||||
{
|
||||
return range->end - range->start;
|
||||
}
|
||||
|
||||
void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
|
||||
bool full, const struct sw_flow_mask *mask)
|
||||
{
|
||||
int start = full ? 0 : mask->range.start;
|
||||
int len = full ? sizeof *dst : range_n_bytes(&mask->range);
|
||||
const long *m = (const long *)((const u8 *)&mask->key + start);
|
||||
const long *s = (const long *)((const u8 *)src + start);
|
||||
long *d = (long *)((u8 *)dst + start);
|
||||
int i;
|
||||
|
||||
/* If 'full' is true then all of 'dst' is fully initialized. Otherwise,
|
||||
* if 'full' is false the memory outside of the 'mask->range' is left
|
||||
* uninitialized. This can be used as an optimization when further
|
||||
* operations on 'dst' only use contents within 'mask->range'.
|
||||
*/
|
||||
for (i = 0; i < len; i += sizeof(long))
|
||||
*d++ = *s++ & *m++;
|
||||
}
|
||||
|
||||
struct sw_flow *ovs_flow_alloc(void)
|
||||
{
|
||||
struct sw_flow *flow;
|
||||
struct sw_flow_stats *stats;
|
||||
|
||||
flow = kmem_cache_zalloc(flow_cache, GFP_KERNEL);
|
||||
if (!flow)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
flow->stats_last_writer = -1;
|
||||
|
||||
/* Initialize the default stat node. */
|
||||
stats = kmem_cache_alloc_node(flow_stats_cache,
|
||||
GFP_KERNEL | __GFP_ZERO,
|
||||
node_online(0) ? 0 : NUMA_NO_NODE);
|
||||
if (!stats)
|
||||
goto err;
|
||||
|
||||
spin_lock_init(&stats->lock);
|
||||
|
||||
RCU_INIT_POINTER(flow->stats[0], stats);
|
||||
|
||||
cpumask_set_cpu(0, &flow->cpu_used_mask);
|
||||
|
||||
return flow;
|
||||
err:
|
||||
kmem_cache_free(flow_cache, flow);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
int ovs_flow_tbl_count(const struct flow_table *table)
|
||||
{
|
||||
return table->count;
|
||||
}
|
||||
|
||||
static void flow_free(struct sw_flow *flow)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (ovs_identifier_is_key(&flow->id))
|
||||
kfree(flow->id.unmasked_key);
|
||||
if (flow->sf_acts)
|
||||
ovs_nla_free_flow_actions((struct sw_flow_actions __force *)flow->sf_acts);
|
||||
/* We open code this to make sure cpu 0 is always considered */
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask))
|
||||
if (flow->stats[cpu])
|
||||
kmem_cache_free(flow_stats_cache,
|
||||
rcu_dereference_raw(flow->stats[cpu]));
|
||||
kmem_cache_free(flow_cache, flow);
|
||||
}
|
||||
|
||||
static void rcu_free_flow_callback(struct rcu_head *rcu)
|
||||
{
|
||||
struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu);
|
||||
|
||||
flow_free(flow);
|
||||
}
|
||||
|
||||
void ovs_flow_free(struct sw_flow *flow, bool deferred)
|
||||
{
|
||||
if (!flow)
|
||||
return;
|
||||
|
||||
if (deferred)
|
||||
call_rcu(&flow->rcu, rcu_free_flow_callback);
|
||||
else
|
||||
flow_free(flow);
|
||||
}
|
||||
|
||||
static void __table_instance_destroy(struct table_instance *ti)
|
||||
{
|
||||
kvfree(ti->buckets);
|
||||
kfree(ti);
|
||||
}
|
||||
|
||||
static struct table_instance *table_instance_alloc(int new_size)
|
||||
{
|
||||
struct table_instance *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
|
||||
int i;
|
||||
|
||||
if (!ti)
|
||||
return NULL;
|
||||
|
||||
ti->buckets = kvmalloc_array(new_size, sizeof(struct hlist_head),
|
||||
GFP_KERNEL);
|
||||
if (!ti->buckets) {
|
||||
kfree(ti);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < new_size; i++)
|
||||
INIT_HLIST_HEAD(&ti->buckets[i]);
|
||||
|
||||
ti->n_buckets = new_size;
|
||||
ti->node_ver = 0;
|
||||
ti->keep_flows = false;
|
||||
get_random_bytes(&ti->hash_seed, sizeof(u32));
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
static void mask_array_rcu_cb(struct rcu_head *rcu)
|
||||
{
|
||||
struct mask_array *ma = container_of(rcu, struct mask_array, rcu);
|
||||
|
||||
kfree(ma);
|
||||
}
|
||||
|
||||
static struct mask_array *tbl_mask_array_alloc(int size)
|
||||
{
|
||||
struct mask_array *new;
|
||||
|
||||
size = max(MASK_ARRAY_SIZE_MIN, size);
|
||||
new = kzalloc(sizeof(struct mask_array) +
|
||||
sizeof(struct sw_flow_mask *) * size, GFP_KERNEL);
|
||||
if (!new)
|
||||
return NULL;
|
||||
|
||||
new->count = 0;
|
||||
new->max = size;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static int tbl_mask_array_realloc(struct flow_table *tbl, int size)
|
||||
{
|
||||
struct mask_array *old;
|
||||
struct mask_array *new;
|
||||
|
||||
new = tbl_mask_array_alloc(size);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
old = ovsl_dereference(tbl->mask_array);
|
||||
if (old) {
|
||||
int i, count = 0;
|
||||
|
||||
for (i = 0; i < old->max; i++) {
|
||||
if (ovsl_dereference(old->masks[i]))
|
||||
new->masks[count++] = old->masks[i];
|
||||
}
|
||||
|
||||
new->count = count;
|
||||
}
|
||||
rcu_assign_pointer(tbl->mask_array, new);
|
||||
|
||||
if (old)
|
||||
call_rcu(&old->rcu, mask_array_rcu_cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tbl_mask_array_add_mask(struct flow_table *tbl,
|
||||
struct sw_flow_mask *new)
|
||||
{
|
||||
struct mask_array *ma = ovsl_dereference(tbl->mask_array);
|
||||
int err, ma_count = READ_ONCE(ma->count);
|
||||
|
||||
if (ma_count >= ma->max) {
|
||||
err = tbl_mask_array_realloc(tbl, ma->max +
|
||||
MASK_ARRAY_SIZE_MIN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ma = ovsl_dereference(tbl->mask_array);
|
||||
}
|
||||
|
||||
BUG_ON(ovsl_dereference(ma->masks[ma_count]));
|
||||
|
||||
rcu_assign_pointer(ma->masks[ma_count], new);
|
||||
WRITE_ONCE(ma->count, ma_count +1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tbl_mask_array_del_mask(struct flow_table *tbl,
|
||||
struct sw_flow_mask *mask)
|
||||
{
|
||||
struct mask_array *ma = ovsl_dereference(tbl->mask_array);
|
||||
int i, ma_count = READ_ONCE(ma->count);
|
||||
|
||||
/* Remove the deleted mask pointers from the array */
|
||||
for (i = 0; i < ma_count; i++) {
|
||||
if (mask == ovsl_dereference(ma->masks[i]))
|
||||
goto found;
|
||||
}
|
||||
|
||||
BUG();
|
||||
return;
|
||||
|
||||
found:
|
||||
WRITE_ONCE(ma->count, ma_count -1);
|
||||
|
||||
rcu_assign_pointer(ma->masks[i], ma->masks[ma_count -1]);
|
||||
RCU_INIT_POINTER(ma->masks[ma_count -1], NULL);
|
||||
|
||||
kfree_rcu(mask, rcu);
|
||||
|
||||
/* Shrink the mask array if necessary. */
|
||||
if (ma->max >= (MASK_ARRAY_SIZE_MIN * 2) &&
|
||||
ma_count <= (ma->max / 3))
|
||||
tbl_mask_array_realloc(tbl, ma->max / 2);
|
||||
}
|
||||
|
||||
/* Remove 'mask' from the mask list, if it is not needed any more. */
|
||||
static void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask)
|
||||
{
|
||||
if (mask) {
|
||||
/* ovs-lock is required to protect mask-refcount and
|
||||
* mask list.
|
||||
*/
|
||||
ASSERT_OVSL();
|
||||
BUG_ON(!mask->ref_count);
|
||||
mask->ref_count--;
|
||||
|
||||
if (!mask->ref_count)
|
||||
tbl_mask_array_del_mask(tbl, mask);
|
||||
}
|
||||
}
|
||||
|
||||
int ovs_flow_tbl_init(struct flow_table *table)
|
||||
{
|
||||
struct table_instance *ti, *ufid_ti;
|
||||
struct mask_array *ma;
|
||||
|
||||
table->mask_cache = __alloc_percpu(sizeof(struct mask_cache_entry) *
|
||||
MC_HASH_ENTRIES, __alignof__(struct mask_cache_entry));
|
||||
if (!table->mask_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
ma = tbl_mask_array_alloc(MASK_ARRAY_SIZE_MIN);
|
||||
if (!ma)
|
||||
goto free_mask_cache;
|
||||
|
||||
ti = table_instance_alloc(TBL_MIN_BUCKETS);
|
||||
if (!ti)
|
||||
goto free_mask_array;
|
||||
|
||||
ufid_ti = table_instance_alloc(TBL_MIN_BUCKETS);
|
||||
if (!ufid_ti)
|
||||
goto free_ti;
|
||||
|
||||
rcu_assign_pointer(table->ti, ti);
|
||||
rcu_assign_pointer(table->ufid_ti, ufid_ti);
|
||||
rcu_assign_pointer(table->mask_array, ma);
|
||||
table->last_rehash = jiffies;
|
||||
table->count = 0;
|
||||
table->ufid_count = 0;
|
||||
return 0;
|
||||
|
||||
free_ti:
|
||||
__table_instance_destroy(ti);
|
||||
free_mask_array:
|
||||
kfree(ma);
|
||||
free_mask_cache:
|
||||
free_percpu(table->mask_cache);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu)
|
||||
{
|
||||
struct table_instance *ti = container_of(rcu, struct table_instance, rcu);
|
||||
|
||||
__table_instance_destroy(ti);
|
||||
}
|
||||
|
||||
static void table_instance_flow_free(struct flow_table *table,
|
||||
struct table_instance *ti,
|
||||
struct table_instance *ufid_ti,
|
||||
struct sw_flow *flow,
|
||||
bool count)
|
||||
{
|
||||
hlist_del_rcu(&flow->flow_table.node[ti->node_ver]);
|
||||
if (count)
|
||||
table->count--;
|
||||
|
||||
if (ovs_identifier_is_ufid(&flow->id)) {
|
||||
hlist_del_rcu(&flow->ufid_table.node[ufid_ti->node_ver]);
|
||||
|
||||
if (count)
|
||||
table->ufid_count--;
|
||||
}
|
||||
|
||||
flow_mask_remove(table, flow->mask);
|
||||
}
|
||||
|
||||
static void table_instance_destroy(struct flow_table *table,
|
||||
struct table_instance *ti,
|
||||
struct table_instance *ufid_ti,
|
||||
bool deferred)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ti)
|
||||
return;
|
||||
|
||||
BUG_ON(!ufid_ti);
|
||||
if (ti->keep_flows)
|
||||
goto skip_flows;
|
||||
|
||||
for (i = 0; i < ti->n_buckets; i++) {
|
||||
struct sw_flow *flow;
|
||||
struct hlist_head *head = &ti->buckets[i];
|
||||
struct hlist_node *n;
|
||||
|
||||
hlist_for_each_entry_safe(flow, n, head,
|
||||
flow_table.node[ti->node_ver]) {
|
||||
|
||||
table_instance_flow_free(table, ti, ufid_ti,
|
||||
flow, false);
|
||||
ovs_flow_free(flow, deferred);
|
||||
}
|
||||
}
|
||||
|
||||
skip_flows:
|
||||
if (deferred) {
|
||||
call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
|
||||
call_rcu(&ufid_ti->rcu, flow_tbl_destroy_rcu_cb);
|
||||
} else {
|
||||
__table_instance_destroy(ti);
|
||||
__table_instance_destroy(ufid_ti);
|
||||
}
|
||||
}
|
||||
|
||||
/* No need for locking this function is called from RCU callback or
|
||||
* error path.
|
||||
*/
|
||||
void ovs_flow_tbl_destroy(struct flow_table *table)
|
||||
{
|
||||
struct table_instance *ti = rcu_dereference_raw(table->ti);
|
||||
struct table_instance *ufid_ti = rcu_dereference_raw(table->ufid_ti);
|
||||
|
||||
free_percpu(table->mask_cache);
|
||||
kfree(rcu_dereference_raw(table->mask_array));
|
||||
table_instance_destroy(table, ti, ufid_ti, false);
|
||||
}
|
||||
|
||||
struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
|
||||
u32 *bucket, u32 *last)
|
||||
{
|
||||
struct sw_flow *flow;
|
||||
struct hlist_head *head;
|
||||
int ver;
|
||||
int i;
|
||||
|
||||
ver = ti->node_ver;
|
||||
while (*bucket < ti->n_buckets) {
|
||||
i = 0;
|
||||
head = &ti->buckets[*bucket];
|
||||
hlist_for_each_entry_rcu(flow, head, flow_table.node[ver]) {
|
||||
if (i < *last) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
*last = i + 1;
|
||||
return flow;
|
||||
}
|
||||
(*bucket)++;
|
||||
*last = 0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct hlist_head *find_bucket(struct table_instance *ti, u32 hash)
|
||||
{
|
||||
hash = jhash_1word(hash, ti->hash_seed);
|
||||
return &ti->buckets[hash & (ti->n_buckets - 1)];
|
||||
}
|
||||
|
||||
static void table_instance_insert(struct table_instance *ti,
|
||||
struct sw_flow *flow)
|
||||
{
|
||||
struct hlist_head *head;
|
||||
|
||||
head = find_bucket(ti, flow->flow_table.hash);
|
||||
hlist_add_head_rcu(&flow->flow_table.node[ti->node_ver], head);
|
||||
}
|
||||
|
||||
static void ufid_table_instance_insert(struct table_instance *ti,
|
||||
struct sw_flow *flow)
|
||||
{
|
||||
struct hlist_head *head;
|
||||
|
||||
head = find_bucket(ti, flow->ufid_table.hash);
|
||||
hlist_add_head_rcu(&flow->ufid_table.node[ti->node_ver], head);
|
||||
}
|
||||
|
||||
static void flow_table_copy_flows(struct table_instance *old,
|
||||
struct table_instance *new, bool ufid)
|
||||
{
|
||||
int old_ver;
|
||||
int i;
|
||||
|
||||
old_ver = old->node_ver;
|
||||
new->node_ver = !old_ver;
|
||||
|
||||
/* Insert in new table. */
|
||||
for (i = 0; i < old->n_buckets; i++) {
|
||||
struct sw_flow *flow;
|
||||
struct hlist_head *head = &old->buckets[i];
|
||||
|
||||
if (ufid)
|
||||
hlist_for_each_entry_rcu(flow, head,
|
||||
ufid_table.node[old_ver])
|
||||
ufid_table_instance_insert(new, flow);
|
||||
else
|
||||
hlist_for_each_entry_rcu(flow, head,
|
||||
flow_table.node[old_ver])
|
||||
table_instance_insert(new, flow);
|
||||
}
|
||||
|
||||
old->keep_flows = true;
|
||||
}
|
||||
|
||||
static struct table_instance *table_instance_rehash(struct table_instance *ti,
|
||||
int n_buckets, bool ufid)
|
||||
{
|
||||
struct table_instance *new_ti;
|
||||
|
||||
new_ti = table_instance_alloc(n_buckets);
|
||||
if (!new_ti)
|
||||
return NULL;
|
||||
|
||||
flow_table_copy_flows(ti, new_ti, ufid);
|
||||
|
||||
return new_ti;
|
||||
}
|
||||
|
||||
int ovs_flow_tbl_flush(struct flow_table *flow_table)
|
||||
{
|
||||
struct table_instance *old_ti, *new_ti;
|
||||
struct table_instance *old_ufid_ti, *new_ufid_ti;
|
||||
|
||||
new_ti = table_instance_alloc(TBL_MIN_BUCKETS);
|
||||
if (!new_ti)
|
||||
return -ENOMEM;
|
||||
new_ufid_ti = table_instance_alloc(TBL_MIN_BUCKETS);
|
||||
if (!new_ufid_ti)
|
||||
goto err_free_ti;
|
||||
|
||||
old_ti = ovsl_dereference(flow_table->ti);
|
||||
old_ufid_ti = ovsl_dereference(flow_table->ufid_ti);
|
||||
|
||||
rcu_assign_pointer(flow_table->ti, new_ti);
|
||||
rcu_assign_pointer(flow_table->ufid_ti, new_ufid_ti);
|
||||
flow_table->last_rehash = jiffies;
|
||||
flow_table->count = 0;
|
||||
flow_table->ufid_count = 0;
|
||||
|
||||
table_instance_destroy(flow_table, old_ti, old_ufid_ti, true);
|
||||
return 0;
|
||||
|
||||
err_free_ti:
|
||||
__table_instance_destroy(new_ti);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static u32 flow_hash(const struct sw_flow_key *key,
|
||||
const struct sw_flow_key_range *range)
|
||||
{
|
||||
const u32 *hash_key = (const u32 *)((const u8 *)key + range->start);
|
||||
|
||||
/* Make sure number of hash bytes are multiple of u32. */
|
||||
int hash_u32s = range_n_bytes(range) >> 2;
|
||||
|
||||
return jhash2(hash_key, hash_u32s, 0);
|
||||
}
|
||||
|
||||
static int flow_key_start(const struct sw_flow_key *key)
|
||||
{
|
||||
if (key->tun_proto)
|
||||
return 0;
|
||||
else
|
||||
return rounddown(offsetof(struct sw_flow_key, phy),
|
||||
sizeof(long));
|
||||
}
|
||||
|
||||
static bool cmp_key(const struct sw_flow_key *key1,
|
||||
const struct sw_flow_key *key2,
|
||||
int key_start, int key_end)
|
||||
{
|
||||
const long *cp1 = (const long *)((const u8 *)key1 + key_start);
|
||||
const long *cp2 = (const long *)((const u8 *)key2 + key_start);
|
||||
long diffs = 0;
|
||||
int i;
|
||||
|
||||
for (i = key_start; i < key_end; i += sizeof(long))
|
||||
diffs |= *cp1++ ^ *cp2++;
|
||||
|
||||
return diffs == 0;
|
||||
}
|
||||
|
||||
static bool flow_cmp_masked_key(const struct sw_flow *flow,
|
||||
const struct sw_flow_key *key,
|
||||
const struct sw_flow_key_range *range)
|
||||
{
|
||||
return cmp_key(&flow->key, key, range->start, range->end);
|
||||
}
|
||||
|
||||
static bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
|
||||
const struct sw_flow_match *match)
|
||||
{
|
||||
struct sw_flow_key *key = match->key;
|
||||
int key_start = flow_key_start(key);
|
||||
int key_end = match->range.end;
|
||||
|
||||
BUG_ON(ovs_identifier_is_ufid(&flow->id));
|
||||
return cmp_key(flow->id.unmasked_key, key, key_start, key_end);
|
||||
}
|
||||
|
||||
static struct sw_flow *masked_flow_lookup(struct table_instance *ti,
|
||||
const struct sw_flow_key *unmasked,
|
||||
const struct sw_flow_mask *mask,
|
||||
u32 *n_mask_hit)
|
||||
{
|
||||
struct sw_flow *flow;
|
||||
struct hlist_head *head;
|
||||
u32 hash;
|
||||
struct sw_flow_key masked_key;
|
||||
|
||||
ovs_flow_mask_key(&masked_key, unmasked, false, mask);
|
||||
hash = flow_hash(&masked_key, &mask->range);
|
||||
head = find_bucket(ti, hash);
|
||||
(*n_mask_hit)++;
|
||||
hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) {
|
||||
if (flow->mask == mask && flow->flow_table.hash == hash &&
|
||||
flow_cmp_masked_key(flow, &masked_key, &mask->range))
|
||||
return flow;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Flow lookup does full lookup on flow table. It starts with
|
||||
* mask from index passed in *index.
|
||||
*/
|
||||
static struct sw_flow *flow_lookup(struct flow_table *tbl,
|
||||
struct table_instance *ti,
|
||||
const struct mask_array *ma,
|
||||
const struct sw_flow_key *key,
|
||||
u32 *n_mask_hit,
|
||||
u32 *index)
|
||||
{
|
||||
struct sw_flow *flow;
|
||||
struct sw_flow_mask *mask;
|
||||
int i;
|
||||
|
||||
if (likely(*index < ma->max)) {
|
||||
mask = rcu_dereference_ovsl(ma->masks[*index]);
|
||||
if (mask) {
|
||||
flow = masked_flow_lookup(ti, key, mask, n_mask_hit);
|
||||
if (flow)
|
||||
return flow;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ma->max; i++) {
|
||||
|
||||
if (i == *index)
|
||||
continue;
|
||||
|
||||
mask = rcu_dereference_ovsl(ma->masks[i]);
|
||||
if (unlikely(!mask))
|
||||
break;
|
||||
|
||||
flow = masked_flow_lookup(ti, key, mask, n_mask_hit);
|
||||
if (flow) { /* Found */
|
||||
*index = i;
|
||||
return flow;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* mask_cache maps flow to probable mask. This cache is not tightly
|
||||
* coupled cache, It means updates to mask list can result in inconsistent
|
||||
* cache entry in mask cache.
|
||||
* This is per cpu cache and is divided in MC_HASH_SEGS segments.
|
||||
* In case of a hash collision the entry is hashed in next segment.
|
||||
*/
|
||||
struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
|
||||
const struct sw_flow_key *key,
|
||||
u32 skb_hash,
|
||||
u32 *n_mask_hit)
|
||||
{
|
||||
struct mask_array *ma = rcu_dereference(tbl->mask_array);
|
||||
struct table_instance *ti = rcu_dereference(tbl->ti);
|
||||
struct mask_cache_entry *entries, *ce;
|
||||
struct sw_flow *flow;
|
||||
u32 hash;
|
||||
int seg;
|
||||
|
||||
*n_mask_hit = 0;
|
||||
if (unlikely(!skb_hash)) {
|
||||
u32 mask_index = 0;
|
||||
|
||||
return flow_lookup(tbl, ti, ma, key, n_mask_hit, &mask_index);
|
||||
}
|
||||
|
||||
/* Pre and post recirulation flows usually have the same skb_hash
|
||||
* value. To avoid hash collisions, rehash the 'skb_hash' with
|
||||
* 'recirc_id'. */
|
||||
if (key->recirc_id)
|
||||
skb_hash = jhash_1word(skb_hash, key->recirc_id);
|
||||
|
||||
ce = NULL;
|
||||
hash = skb_hash;
|
||||
entries = this_cpu_ptr(tbl->mask_cache);
|
||||
|
||||
/* Find the cache entry 'ce' to operate on. */
|
||||
for (seg = 0; seg < MC_HASH_SEGS; seg++) {
|
||||
int index = hash & (MC_HASH_ENTRIES - 1);
|
||||
struct mask_cache_entry *e;
|
||||
|
||||
e = &entries[index];
|
||||
if (e->skb_hash == skb_hash) {
|
||||
flow = flow_lookup(tbl, ti, ma, key, n_mask_hit,
|
||||
&e->mask_index);
|
||||
if (!flow)
|
||||
e->skb_hash = 0;
|
||||
return flow;
|
||||
}
|
||||
|
||||
if (!ce || e->skb_hash < ce->skb_hash)
|
||||
ce = e; /* A better replacement cache candidate. */
|
||||
|
||||
hash >>= MC_HASH_SHIFT;
|
||||
}
|
||||
|
||||
/* Cache miss, do full lookup. */
|
||||
flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, &ce->mask_index);
|
||||
if (flow)
|
||||
ce->skb_hash = skb_hash;
|
||||
|
||||
return flow;
|
||||
}
|
||||
|
||||
struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl,
|
||||
const struct sw_flow_key *key)
|
||||
{
|
||||
struct table_instance *ti = rcu_dereference_ovsl(tbl->ti);
|
||||
struct mask_array *ma = rcu_dereference_ovsl(tbl->mask_array);
|
||||
u32 __always_unused n_mask_hit;
|
||||
u32 index = 0;
|
||||
|
||||
return flow_lookup(tbl, ti, ma, key, &n_mask_hit, &index);
|
||||
}
|
||||
|
||||
struct sw_flow *ovs_flow_tbl_lookup_exact(struct flow_table *tbl,
|
||||
const struct sw_flow_match *match)
|
||||
{
|
||||
struct mask_array *ma = ovsl_dereference(tbl->mask_array);
|
||||
int i;
|
||||
|
||||
/* Always called under ovs-mutex. */
|
||||
for (i = 0; i < ma->max; i++) {
|
||||
struct table_instance *ti = ovsl_dereference(tbl->ti);
|
||||
u32 __always_unused n_mask_hit;
|
||||
struct sw_flow_mask *mask;
|
||||
struct sw_flow *flow;
|
||||
|
||||
mask = ovsl_dereference(ma->masks[i]);
|
||||
if (!mask)
|
||||
continue;
|
||||
flow = masked_flow_lookup(ti, match->key, mask, &n_mask_hit);
|
||||
if (flow && ovs_identifier_is_key(&flow->id) &&
|
||||
ovs_flow_cmp_unmasked_key(flow, match))
|
||||
return flow;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u32 ufid_hash(const struct sw_flow_id *sfid)
|
||||
{
|
||||
return jhash(sfid->ufid, sfid->ufid_len, 0);
|
||||
}
|
||||
|
||||
static bool ovs_flow_cmp_ufid(const struct sw_flow *flow,
|
||||
const struct sw_flow_id *sfid)
|
||||
{
|
||||
if (flow->id.ufid_len != sfid->ufid_len)
|
||||
return false;
|
||||
|
||||
return !memcmp(flow->id.ufid, sfid->ufid, sfid->ufid_len);
|
||||
}
|
||||
|
||||
bool ovs_flow_cmp(const struct sw_flow *flow, const struct sw_flow_match *match)
|
||||
{
|
||||
if (ovs_identifier_is_ufid(&flow->id))
|
||||
return flow_cmp_masked_key(flow, match->key, &match->range);
|
||||
|
||||
return ovs_flow_cmp_unmasked_key(flow, match);
|
||||
}
|
||||
|
||||
struct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *tbl,
|
||||
const struct sw_flow_id *ufid)
|
||||
{
|
||||
struct table_instance *ti = rcu_dereference_ovsl(tbl->ufid_ti);
|
||||
struct sw_flow *flow;
|
||||
struct hlist_head *head;
|
||||
u32 hash;
|
||||
|
||||
hash = ufid_hash(ufid);
|
||||
head = find_bucket(ti, hash);
|
||||
hlist_for_each_entry_rcu(flow, head, ufid_table.node[ti->node_ver]) {
|
||||
if (flow->ufid_table.hash == hash &&
|
||||
ovs_flow_cmp_ufid(flow, ufid))
|
||||
return flow;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ovs_flow_tbl_num_masks(const struct flow_table *table)
|
||||
{
|
||||
struct mask_array *ma;
|
||||
|
||||
ma = rcu_dereference_ovsl(table->mask_array);
|
||||
return READ_ONCE(ma->count);
|
||||
}
|
||||
|
||||
static struct table_instance *table_instance_expand(struct table_instance *ti,
|
||||
bool ufid)
|
||||
{
|
||||
return table_instance_rehash(ti, ti->n_buckets * 2, ufid);
|
||||
}
|
||||
|
||||
/* Must be called with OVS mutex held. */
|
||||
void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow)
|
||||
{
|
||||
struct table_instance *ti = ovsl_dereference(table->ti);
|
||||
struct table_instance *ufid_ti = ovsl_dereference(table->ufid_ti);
|
||||
|
||||
BUG_ON(table->count == 0);
|
||||
table_instance_flow_free(table, ti, ufid_ti, flow, true);
|
||||
}
|
||||
|
||||
static struct sw_flow_mask *mask_alloc(void)
|
||||
{
|
||||
struct sw_flow_mask *mask;
|
||||
|
||||
mask = kmalloc(sizeof(*mask), GFP_KERNEL);
|
||||
if (mask)
|
||||
mask->ref_count = 1;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static bool mask_equal(const struct sw_flow_mask *a,
|
||||
const struct sw_flow_mask *b)
|
||||
{
|
||||
const u8 *a_ = (const u8 *)&a->key + a->range.start;
|
||||
const u8 *b_ = (const u8 *)&b->key + b->range.start;
|
||||
|
||||
return (a->range.end == b->range.end)
|
||||
&& (a->range.start == b->range.start)
|
||||
&& (memcmp(a_, b_, range_n_bytes(&a->range)) == 0);
|
||||
}
|
||||
|
||||
static struct sw_flow_mask *flow_mask_find(const struct flow_table *tbl,
|
||||
const struct sw_flow_mask *mask)
|
||||
{
|
||||
struct mask_array *ma;
|
||||
int i;
|
||||
|
||||
ma = ovsl_dereference(tbl->mask_array);
|
||||
for (i = 0; i < ma->max; i++) {
|
||||
struct sw_flow_mask *t;
|
||||
|
||||
t = ovsl_dereference(ma->masks[i]);
|
||||
if (t && mask_equal(mask, t))
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add 'mask' into the mask list, if it is not already there. */
|
||||
static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
|
||||
const struct sw_flow_mask *new)
|
||||
{
|
||||
struct sw_flow_mask *mask;
|
||||
|
||||
mask = flow_mask_find(tbl, new);
|
||||
if (!mask) {
|
||||
/* Allocate a new mask if none exsits. */
|
||||
mask = mask_alloc();
|
||||
if (!mask)
|
||||
return -ENOMEM;
|
||||
|
||||
mask->key = new->key;
|
||||
mask->range = new->range;
|
||||
|
||||
/* Add mask to mask-list. */
|
||||
if (tbl_mask_array_add_mask(tbl, mask)) {
|
||||
kfree(mask);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
} else {
|
||||
BUG_ON(!mask->ref_count);
|
||||
mask->ref_count++;
|
||||
}
|
||||
|
||||
flow->mask = mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must be called with OVS mutex held. */
|
||||
static void flow_key_insert(struct flow_table *table, struct sw_flow *flow)
|
||||
{
|
||||
struct table_instance *new_ti = NULL;
|
||||
struct table_instance *ti;
|
||||
|
||||
flow->flow_table.hash = flow_hash(&flow->key, &flow->mask->range);
|
||||
ti = ovsl_dereference(table->ti);
|
||||
table_instance_insert(ti, flow);
|
||||
table->count++;
|
||||
|
||||
/* Expand table, if necessary, to make room. */
|
||||
if (table->count > ti->n_buckets)
|
||||
new_ti = table_instance_expand(ti, false);
|
||||
else if (time_after(jiffies, table->last_rehash + REHASH_INTERVAL))
|
||||
new_ti = table_instance_rehash(ti, ti->n_buckets, false);
|
||||
|
||||
if (new_ti) {
|
||||
rcu_assign_pointer(table->ti, new_ti);
|
||||
call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
|
||||
table->last_rehash = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called with OVS mutex held. */
|
||||
static void flow_ufid_insert(struct flow_table *table, struct sw_flow *flow)
|
||||
{
|
||||
struct table_instance *ti;
|
||||
|
||||
flow->ufid_table.hash = ufid_hash(&flow->id);
|
||||
ti = ovsl_dereference(table->ufid_ti);
|
||||
ufid_table_instance_insert(ti, flow);
|
||||
table->ufid_count++;
|
||||
|
||||
/* Expand table, if necessary, to make room. */
|
||||
if (table->ufid_count > ti->n_buckets) {
|
||||
struct table_instance *new_ti;
|
||||
|
||||
new_ti = table_instance_expand(ti, true);
|
||||
if (new_ti) {
|
||||
rcu_assign_pointer(table->ufid_ti, new_ti);
|
||||
call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called with OVS mutex held. */
|
||||
int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
|
||||
const struct sw_flow_mask *mask)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = flow_mask_insert(table, flow, mask);
|
||||
if (err)
|
||||
return err;
|
||||
flow_key_insert(table, flow);
|
||||
if (ovs_identifier_is_ufid(&flow->id))
|
||||
flow_ufid_insert(table, flow);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initializes the flow module.
|
||||
* Returns zero if successful or a negative error code.
|
||||
*/
|
||||
int ovs_flow_init(void)
|
||||
{
|
||||
BUILD_BUG_ON(__alignof__(struct sw_flow_key) % __alignof__(long));
|
||||
BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long));
|
||||
|
||||
flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow)
|
||||
+ (nr_cpu_ids
|
||||
* sizeof(struct sw_flow_stats *)),
|
||||
0, 0, NULL);
|
||||
if (flow_cache == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
flow_stats_cache
|
||||
= kmem_cache_create("sw_flow_stats", sizeof(struct sw_flow_stats),
|
||||
0, SLAB_HWCACHE_ALIGN, NULL);
|
||||
if (flow_stats_cache == NULL) {
|
||||
kmem_cache_destroy(flow_cache);
|
||||
flow_cache = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Uninitializes the flow module. */
|
||||
void ovs_flow_exit(void)
|
||||
{
|
||||
kmem_cache_destroy(flow_stats_cache);
|
||||
kmem_cache_destroy(flow_cache);
|
||||
}
|
@@ -1,102 +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
|
||||
*/
|
||||
|
||||
#ifndef FLOW_TABLE_H
|
||||
#define FLOW_TABLE_H 1
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/openvswitch.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <net/inet_ecn.h>
|
||||
#include <net/ip_tunnels.h>
|
||||
|
||||
#include "flow.h"
|
||||
|
||||
struct mask_cache_entry {
|
||||
u32 skb_hash;
|
||||
u32 mask_index;
|
||||
};
|
||||
|
||||
struct mask_array {
|
||||
struct rcu_head rcu;
|
||||
int count, max;
|
||||
struct sw_flow_mask __rcu *masks[];
|
||||
};
|
||||
|
||||
struct table_instance {
|
||||
struct hlist_head *buckets;
|
||||
unsigned int n_buckets;
|
||||
struct rcu_head rcu;
|
||||
int node_ver;
|
||||
u32 hash_seed;
|
||||
bool keep_flows;
|
||||
};
|
||||
|
||||
struct flow_table {
|
||||
struct table_instance __rcu *ti;
|
||||
struct table_instance __rcu *ufid_ti;
|
||||
struct mask_cache_entry __percpu *mask_cache;
|
||||
struct mask_array __rcu *mask_array;
|
||||
unsigned long last_rehash;
|
||||
unsigned int count;
|
||||
unsigned int ufid_count;
|
||||
};
|
||||
|
||||
extern struct kmem_cache *flow_stats_cache;
|
||||
|
||||
int ovs_flow_init(void);
|
||||
void ovs_flow_exit(void);
|
||||
|
||||
struct sw_flow *ovs_flow_alloc(void);
|
||||
void ovs_flow_free(struct sw_flow *, bool deferred);
|
||||
|
||||
int ovs_flow_tbl_init(struct flow_table *);
|
||||
int ovs_flow_tbl_count(const struct flow_table *table);
|
||||
void ovs_flow_tbl_destroy(struct flow_table *table);
|
||||
int ovs_flow_tbl_flush(struct flow_table *flow_table);
|
||||
|
||||
int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
|
||||
const struct sw_flow_mask *mask);
|
||||
void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
|
||||
int ovs_flow_tbl_num_masks(const struct flow_table *table);
|
||||
struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table,
|
||||
u32 *bucket, u32 *idx);
|
||||
struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *,
|
||||
const struct sw_flow_key *,
|
||||
u32 skb_hash,
|
||||
u32 *n_mask_hit);
|
||||
struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *,
|
||||
const struct sw_flow_key *);
|
||||
struct sw_flow *ovs_flow_tbl_lookup_exact(struct flow_table *tbl,
|
||||
const struct sw_flow_match *match);
|
||||
struct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *,
|
||||
const struct sw_flow_id *);
|
||||
|
||||
bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *);
|
||||
|
||||
void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
|
||||
bool full, const struct sw_flow_mask *mask);
|
||||
#endif /* flow_table.h */
|
8
datapath/linux/.gitignore
vendored
8
datapath/linux/.gitignore
vendored
@@ -1,8 +0,0 @@
|
||||
/Kbuild
|
||||
/Makefile
|
||||
/Makefile.main
|
||||
/Module.markers
|
||||
/kcompat.h
|
||||
/modules.order
|
||||
/tmp
|
||||
/*.c
|
@@ -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))))
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
#
|
||||
################################################################################
|
@@ -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
|
@@ -1 +0,0 @@
|
||||
pskb_expand_head
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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 */
|
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -1,6 +0,0 @@
|
||||
#ifndef __LINUX_IF_WRAPPER_H
|
||||
#define __LINUX_IF_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/if.h>
|
||||
|
||||
#endif
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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 */
|
@@ -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
|
@@ -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 */
|
||||
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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 */
|
@@ -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 */
|
@@ -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
|
@@ -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) */
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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 */
|
@@ -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 */
|
@@ -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 */
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -1,6 +0,0 @@
|
||||
#ifndef __LINUX_WORKQUEUE_WRAPPER_H
|
||||
#define __LINUX_WORKQUEUE_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/workqueue.h>
|
||||
|
||||
#endif
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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 */
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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 */
|
@@ -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
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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 */
|
@@ -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
|
@@ -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 */
|
@@ -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 */
|
@@ -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 */
|
@@ -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 */
|
@@ -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 */
|
@@ -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 */
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user