2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-01 06:45:17 +00:00

compat: Backport nf_ct_netns_{get, put}()

This patch backports nf_ct_netns_get/put() in order to support a feature
in the follow up patch.

nf_ct_netns_{get,put} were first introduced in upstream net-next commit
ecb2421b5ddf ("netfilter: add and use nf_ct_netns_get/put") in kernel
v4.10, and then updated in commmit 7e35ec0e8044 ("netfilter: conntrack:
move nf_ct_netns_{get,put}() to core") in kernel v4.15.  We need to
invoke nf_ct_netns_get/put() when the underlying nf_conntrack_l3proto
supports net_ns_{get,put}().

Therefore, there are 3 cases that we need to consider.
1) Before nf_ct_{get,put}() is introduced.
    We just mock nf_ct_nets_{get,put}() and do nothing.

2) After 1) and before v4.15
    Backports based on commit 7e35ec0e8044 .

3) Staring from v4.15
    Use the upstream version.

Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Justin Pettit <jpettit@ovn.org>
This commit is contained in:
Yi-Hung Wei
2018-08-17 02:05:02 -07:00
committed by Justin Pettit
parent 7f63d8302e
commit 179fccce34
5 changed files with 141 additions and 1 deletions

View File

@@ -589,6 +589,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
[OVS_DEFINE([HAVE_NF_HOOKFN_ARG_PRIV])])
OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netfilter.h], [nf_hook_ops],
[owner], [OVS_DEFINE([HAVE_NF_HOOKS_OPS_OWNER])])
OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [NFPROTO_INET])
OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netfilter_ipv6.h], [nf_ipv6_ops],
[fragment.*sock], [OVS_DEFINE([HAVE_NF_IPV6_OPS_FRAGMENT])])
@@ -611,6 +613,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
[nf_ct_is_untracked])
OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_zones.h],
[nf_ct_zone_init])
OVS_FIND_FIELD_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_l3proto.h],
[net_ns_get])
OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_labels.h],
[nf_connlabels_get])
OVS_FIND_PARAM_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_labels.h],

View File

@@ -18,6 +18,7 @@ openvswitch_sources += \
linux/compat/lisp.c \
linux/compat/netdevice.c \
linux/compat/nf_conntrack_core.c \
linux/compat/nf_conntrack_proto.c \
linux/compat/nf_conntrack_reasm.c \
linux/compat/reciprocal_div.c \
linux/compat/skbuff-openvswitch.c \
@@ -107,5 +108,6 @@ openvswitch_headers += \
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/net/erspan.h \
linux/compat/include/uapi/linux/netfilter.h
EXTRA_DIST += linux/compat/build-aux/export-check-whitelist

View File

@@ -22,4 +22,12 @@ nf_ct_set(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info info)
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 */

View File

@@ -0,0 +1,14 @@
#ifndef _NETFILTER_WRAPPER_H
#define _NETFILTER_WRAPPER_H
#include_next <uapi/linux/netfilter.h>
/*
* NFPROTO_INET was introduced in net-next commit 1d49144c0aaa
* ("netfilter: nf_tables: add "inet" table for IPv4/IPv6") in v3.14.
* Define this symbol to support back to v3.10 kernel. */
#ifndef HAVE_NFPROTO_INET
#define NFPROTO_INET 1
#endif
#endif /* _NETFILTER_WRAPPER_H */

View File

@@ -0,0 +1,112 @@
#include <linux/types.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
/*
* Upstream net-next commmit 7e35ec0e8044
* ("netfilter: conntrack: move nf_ct_netns_{get,put}() to core")
* is introduced in v4.15, and it supports NFPROTO_INET in
* nf_ct_netns_{get,put}() that OVS conntrack uses this feature.
*
* However, we only need this feature if the underlying nf_conntrack_l3proto
* supports net_ns_get/put. Thus, we just mock the functions if
* HAVE_NET_NS_SET is false.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)
#ifdef HAVE_NET_NS_SET
static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
{
const struct nf_conntrack_l3proto *l3proto;
int ret;
might_sleep();
ret = nf_ct_l3proto_try_module_get(nfproto);
if (ret < 0)
return ret;
/* we already have a reference, can't fail */
rcu_read_lock();
l3proto = __nf_ct_l3proto_find(nfproto);
rcu_read_unlock();
if (!l3proto->net_ns_get)
return 0;
ret = l3proto->net_ns_get(net);
if (ret < 0)
nf_ct_l3proto_module_put(nfproto);
return ret;
}
int rpl_nf_ct_netns_get(struct net *net, u8 nfproto)
{
int err;
if (nfproto == NFPROTO_INET) {
err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
if (err < 0)
goto err1;
err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
if (err < 0)
goto err2;
} else {
err = nf_ct_netns_do_get(net, nfproto);
if (err < 0)
goto err1;
}
return 0;
err2:
nf_ct_netns_put(net, NFPROTO_IPV4);
err1:
return err;
}
EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_get);
static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
{
const struct nf_conntrack_l3proto *l3proto;
might_sleep();
/* same as nf_conntrack_netns_get(), reference assumed */
rcu_read_lock();
l3proto = __nf_ct_l3proto_find(nfproto);
rcu_read_unlock();
if (WARN_ON(!l3proto))
return;
if (l3proto->net_ns_put)
l3proto->net_ns_put(net);
nf_ct_l3proto_module_put(nfproto);
}
void rpl_nf_ct_netns_put(struct net *net, uint8_t nfproto)
{
if (nfproto == NFPROTO_INET) {
nf_ct_netns_do_put(net, NFPROTO_IPV4);
nf_ct_netns_do_put(net, NFPROTO_IPV6);
} else
nf_ct_netns_do_put(net, nfproto);
}
EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_put);
#else /* !HAVE_NET_NS_SET */
void rpl_nf_ct_netns_put(struct net *net, uint8_t nfproto)
{
}
EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_put);
int rpl_nf_ct_netns_get(struct net *net, u8 nfproto)
{
return 0;
}
EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_get);
#endif /* HAVE_NET_NS_SET */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) */