Commit c0c3ab63 authored by Xin Long's avatar Xin Long Committed by Jakub Kicinski
Browse files

net: create nf_conntrack_ovs for ovs and tc use



Similar to nf_nat_ovs created by Commit ebddb140 ("net: move the
nat function to nf_nat_ovs for ovs and tc"), this patch is to create
nf_conntrack_ovs to get these functions shared by OVS and TC only.

There are nf_ct_helper() and nf_ct_add_helper() from nf_conntrak_helper
in this patch, and will be more in the following patches.

Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Reviewed-by: default avatarSimon Horman <simon.horman@corigine.com>
Reviewed-by: default avatarAaron Conole <aconole@redhat.com>
Acked-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 025a785f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -189,6 +189,9 @@ config NF_CONNTRACK_LABELS
	  to connection tracking entries.  It can be used with xtables connlabel
	  match and the nftables ct expression.

config NF_CONNTRACK_OVS
	bool

config NF_CT_PROTO_DCCP
	bool 'DCCP protocol connection tracking support'
	depends on NETFILTER_ADVANCED
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_LABELS) += nf_conntrack_labels.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_OVS) += nf_conntrack_ovs.o
nf_conntrack-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
nf_conntrack-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
nf_conntrack-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
+0 −98
Original line number Diff line number Diff line
@@ -242,104 +242,6 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
}
EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);

/* 'skb' should already be pulled to nh_ofs. */
int nf_ct_helper(struct sk_buff *skb, struct nf_conn *ct,
		 enum ip_conntrack_info ctinfo, u16 proto)
{
	const struct nf_conntrack_helper *helper;
	const struct nf_conn_help *help;
	unsigned int protoff;
	int err;

	if (ctinfo == IP_CT_RELATED_REPLY)
		return NF_ACCEPT;

	help = nfct_help(ct);
	if (!help)
		return NF_ACCEPT;

	helper = rcu_dereference(help->helper);
	if (!helper)
		return NF_ACCEPT;

	if (helper->tuple.src.l3num != NFPROTO_UNSPEC &&
	    helper->tuple.src.l3num != proto)
		return NF_ACCEPT;

	switch (proto) {
	case NFPROTO_IPV4:
		protoff = ip_hdrlen(skb);
		proto = ip_hdr(skb)->protocol;
		break;
	case NFPROTO_IPV6: {
		u8 nexthdr = ipv6_hdr(skb)->nexthdr;
		__be16 frag_off;
		int ofs;

		ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
				       &frag_off);
		if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
			pr_debug("proto header not found\n");
			return NF_ACCEPT;
		}
		protoff = ofs;
		proto = nexthdr;
		break;
	}
	default:
		WARN_ONCE(1, "helper invoked on non-IP family!");
		return NF_DROP;
	}

	if (helper->tuple.dst.protonum != proto)
		return NF_ACCEPT;

	err = helper->help(skb, protoff, ct, ctinfo);
	if (err != NF_ACCEPT)
		return err;

	/* Adjust seqs after helper.  This is needed due to some helpers (e.g.,
	 * FTP with NAT) adusting the TCP payload size when mangling IP
	 * addresses and/or port numbers in the text-based control connection.
	 */
	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
	    !nf_ct_seq_adjust(skb, ct, ctinfo, protoff))
		return NF_DROP;
	return NF_ACCEPT;
}
EXPORT_SYMBOL_GPL(nf_ct_helper);

int nf_ct_add_helper(struct nf_conn *ct, const char *name, u8 family,
		     u8 proto, bool nat, struct nf_conntrack_helper **hp)
{
	struct nf_conntrack_helper *helper;
	struct nf_conn_help *help;
	int ret = 0;

	helper = nf_conntrack_helper_try_module_get(name, family, proto);
	if (!helper)
		return -EINVAL;

	help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
	if (!help) {
		nf_conntrack_helper_put(helper);
		return -ENOMEM;
	}
#if IS_ENABLED(CONFIG_NF_NAT)
	if (nat) {
		ret = nf_nat_helper_try_module_get(name, family, proto);
		if (ret) {
			nf_conntrack_helper_put(helper);
			return ret;
		}
	}
#endif
	rcu_assign_pointer(help->helper, helper);
	*hp = helper;
	return ret;
}
EXPORT_SYMBOL_GPL(nf_ct_add_helper);

/* appropriate ct lock protecting must be taken by caller */
static int unhelp(struct nf_conn *ct, void *me)
{
+104 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Support ct functions for openvswitch and used by OVS and TC conntrack. */

#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_seqadj.h>
#include <net/ip.h>

/* 'skb' should already be pulled to nh_ofs. */
int nf_ct_helper(struct sk_buff *skb, struct nf_conn *ct,
		 enum ip_conntrack_info ctinfo, u16 proto)
{
	const struct nf_conntrack_helper *helper;
	const struct nf_conn_help *help;
	unsigned int protoff;
	int err;

	if (ctinfo == IP_CT_RELATED_REPLY)
		return NF_ACCEPT;

	help = nfct_help(ct);
	if (!help)
		return NF_ACCEPT;

	helper = rcu_dereference(help->helper);
	if (!helper)
		return NF_ACCEPT;

	if (helper->tuple.src.l3num != NFPROTO_UNSPEC &&
	    helper->tuple.src.l3num != proto)
		return NF_ACCEPT;

	switch (proto) {
	case NFPROTO_IPV4:
		protoff = ip_hdrlen(skb);
		proto = ip_hdr(skb)->protocol;
		break;
	case NFPROTO_IPV6: {
		u8 nexthdr = ipv6_hdr(skb)->nexthdr;
		__be16 frag_off;
		int ofs;

		ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
				       &frag_off);
		if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
			pr_debug("proto header not found\n");
			return NF_ACCEPT;
		}
		protoff = ofs;
		proto = nexthdr;
		break;
	}
	default:
		WARN_ONCE(1, "helper invoked on non-IP family!");
		return NF_DROP;
	}

	if (helper->tuple.dst.protonum != proto)
		return NF_ACCEPT;

	err = helper->help(skb, protoff, ct, ctinfo);
	if (err != NF_ACCEPT)
		return err;

	/* Adjust seqs after helper.  This is needed due to some helpers (e.g.,
	 * FTP with NAT) adusting the TCP payload size when mangling IP
	 * addresses and/or port numbers in the text-based control connection.
	 */
	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
	    !nf_ct_seq_adjust(skb, ct, ctinfo, protoff))
		return NF_DROP;
	return NF_ACCEPT;
}
EXPORT_SYMBOL_GPL(nf_ct_helper);

int nf_ct_add_helper(struct nf_conn *ct, const char *name, u8 family,
		     u8 proto, bool nat, struct nf_conntrack_helper **hp)
{
	struct nf_conntrack_helper *helper;
	struct nf_conn_help *help;
	int ret = 0;

	helper = nf_conntrack_helper_try_module_get(name, family, proto);
	if (!helper)
		return -EINVAL;

	help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
	if (!help) {
		nf_conntrack_helper_put(helper);
		return -ENOMEM;
	}
#if IS_ENABLED(CONFIG_NF_NAT)
	if (nat) {
		ret = nf_nat_helper_try_module_get(name, family, proto);
		if (ret) {
			nf_conntrack_helper_put(helper);
			return ret;
		}
	}
#endif
	rcu_assign_pointer(help->helper, helper);
	*hp = helper;
	return ret;
}
EXPORT_SYMBOL_GPL(nf_ct_add_helper);
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ config OPENVSWITCH
	select NET_MPLS_GSO
	select DST_CACHE
	select NET_NSH
	select NF_CONNTRACK_OVS if NF_CONNTRACK
	select NF_NAT_OVS if NF_NAT
	help
	  Open vSwitch is a multilayer Ethernet switch targeted at virtualized
Loading