From patchwork Tue Jun 14 22:25:24 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarno Rajahalme X-Patchwork-Id: 635618 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (archives.nicira.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 3rTklM1Kw6z9t0d for ; Wed, 15 Jun 2016 08:26:39 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 8CD3E10910; Tue, 14 Jun 2016 15:26:22 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id C1664106BF for ; Tue, 14 Jun 2016 15:26:19 -0700 (PDT) Received: from bar6.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id 594231623DB for ; Tue, 14 Jun 2016 16:26:19 -0600 (MDT) X-ASG-Debug-ID: 1465943178-0b32373691538140001-byXFYA Received: from mx3-pf1.cudamail.com ([192.168.14.2]) by bar6.cudamail.com with ESMTP id MI7wUF3dPzGijVev (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 14 Jun 2016 16:26:18 -0600 (MDT) X-Barracuda-Envelope-From: jarno@ovn.org X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.2 Received: from unknown (HELO relay6-d.mail.gandi.net) (217.70.183.198) by mx3-pf1.cudamail.com with ESMTPS (DHE-RSA-AES256-SHA encrypted); 14 Jun 2016 22:26:18 -0000 Received-SPF: pass (mx3-pf1.cudamail.com: SPF record at ovn.org designates 217.70.183.198 as permitted sender) X-Barracuda-Apparent-Source-IP: 217.70.183.198 X-Barracuda-RBL-IP: 217.70.183.198 Received: from mfilter18-d.gandi.net (mfilter18-d.gandi.net [217.70.178.146]) by relay6-d.mail.gandi.net (Postfix) with ESMTP id 1D352FB877; Wed, 15 Jun 2016 00:26:17 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at mfilter18-d.gandi.net Received: from relay6-d.mail.gandi.net ([IPv6:::ffff:217.70.183.198]) by mfilter18-d.gandi.net (mfilter18-d.gandi.net [::ffff:10.0.15.180]) (amavisd-new, port 10024) with ESMTP id t1gAptxlheEz; Wed, 15 Jun 2016 00:26:15 +0200 (CEST) X-Originating-IP: 208.91.1.34 Received: from sc9-mailhost3.vmware.com (unknown [208.91.1.34]) (Authenticated sender: jarno@ovn.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 8B4C9FB89E; Wed, 15 Jun 2016 00:26:14 +0200 (CEST) X-CudaMail-Envelope-Sender: jarno@ovn.org From: Jarno Rajahalme To: dev@openvswitch.org X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V1-613059807 X-CudaMail-DTE: 061416 X-CudaMail-Originating-IP: 217.70.183.198 Date: Tue, 14 Jun 2016 15:25:24 -0700 X-ASG-Orig-Subj: [##CM-V1-613059807##][PATCH v2 03/16] datapath: compat for NAT. Message-Id: <1465943137-16856-4-git-send-email-jarno@ovn.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1465943137-16856-1-git-send-email-jarno@ovn.org> References: <1465943137-16856-1-git-send-email-jarno@ovn.org> X-Barracuda-Connect: UNKNOWN[192.168.14.2] X-Barracuda-Start-Time: 1465943178 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 Subject: [ovs-dev] [PATCH v2 03/16] datapath: compat for NAT. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" Compat code required to make the NAT code in the following patch compile with Linux 3.10 - 4.3. Signed-off-by: Jarno Rajahalme --- acinclude.m4 | 3 + datapath/linux/Modules.mk | 4 + .../linux/compat/include/linux/netfilter/nf_nat.h | 15 ++++ .../include/net/netfilter/nf_conntrack_core.h | 28 ++++++- .../include/net/netfilter/nf_conntrack_seqadj.h | 30 ++++++++ .../linux/compat/include/net/netfilter/nf_nat.h | 44 +++++++++++ .../compat/include/net/netfilter/nf_nat_core.h | 88 ++++++++++++++++++++++ 7 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 datapath/linux/compat/include/linux/netfilter/nf_nat.h create mode 100644 datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h create mode 100644 datapath/linux/compat/include/net/netfilter/nf_nat.h create mode 100644 datapath/linux/compat/include/net/netfilter/nf_nat_core.h diff --git a/acinclude.m4 b/acinclude.m4 index 6871ba6..3fd2e93 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -472,6 +472,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ [nf_ct_frag6_consume_orig]) OVS_GREP_IFELSE([$KSRC/include/net/netfilter/ipv6/nf_defrag_ipv6.h], [nf_ct_frag6_output]) + OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_nat.h], [nf_ct_nat_ext_add]) + OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_nat.h], [nf_nat_alloc_null_binding]) + OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_seqadj.h], [nf_ct_seq_adjust]) OVS_GREP_IFELSE([$KSRC/include/linux/random.h], [prandom_u32]) OVS_GREP_IFELSE([$KSRC/include/linux/random.h], [prandom_u32_max]) diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index 8b65b71..55e85c4 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -55,6 +55,7 @@ openvswitch_headers += \ linux/compat/include/linux/netdevice.h \ linux/compat/include/linux/netdev_features.h \ linux/compat/include/linux/netfilter_ipv6.h \ + linux/compat/include/linux/netfilter/nf_nat.h \ linux/compat/include/linux/netlink.h \ linux/compat/include/linux/openvswitch.h \ linux/compat/include/linux/poison.h \ @@ -97,7 +98,10 @@ openvswitch_headers += \ linux/compat/include/net/netfilter/nf_conntrack_core.h \ linux/compat/include/net/netfilter/nf_conntrack_expect.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_zones.h \ + linux/compat/include/net/netfilter/nf_nat.h \ + linux/compat/include/net/netfilter/nf_nat_core.h \ linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h \ linux/compat/include/net/sctp/checksum.h EXTRA_DIST += linux/compat/build-aux/export-check-whitelist diff --git a/datapath/linux/compat/include/linux/netfilter/nf_nat.h b/datapath/linux/compat/include/linux/netfilter/nf_nat.h new file mode 100644 index 0000000..210b9a7 --- /dev/null +++ b/datapath/linux/compat/include/linux/netfilter/nf_nat.h @@ -0,0 +1,15 @@ +#ifndef _LINUX_NF_NAT_WRAPPER_H +#define _LINUX_NF_NAT_WRAPPER_H + +#include_next + +/* Linux kernel 3.13 and older do not have NF_NAT_RANGE_PROTO_RANDOM_FULLY + * (unless backported by the distribution), but we fake it to maintain OVS API + * compatibility. In this case NAT port allocation may happen sequentially + * instead. + */ +#ifndef NF_NAT_RANGE_PROTO_RANDOM_FULLY +#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4) +#endif + +#endif /* _LINUX_NF_NAT_WRAPPER_H */ diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h index faa219a..09a53c3 100644 --- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h +++ b/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h @@ -40,5 +40,31 @@ static void rpl_nf_ct_tmpl_free(struct nf_conn *tmpl) kfree(tmpl); } #define nf_ct_tmpl_free rpl_nf_ct_tmpl_free -#endif /* HAVE_NF_CT_TMPL_ALLOC */ + +static inline struct nf_conntrack_tuple_hash * +rpl_nf_conntrack_find_get(struct net *net, + const struct nf_conntrack_zone *zone, + const struct nf_conntrack_tuple *tuple) +{ + return nf_conntrack_find_get(net, zone->id, tuple); +} +#define nf_conntrack_find_get rpl_nf_conntrack_find_get +#endif /* HAVE_NF_CT_TMPL_ALLOC_TAKES_STRUCT_ZONE */ + +#ifndef HAVE_NF_CT_GET_TUPLEPR_TAKES_STRUCT_NET +static inline bool rpl_nf_ct_get_tuple(const struct sk_buff *skb, + unsigned int nhoff, + unsigned int dataoff, u_int16_t l3num, + u_int8_t protonum, + struct net *net, + struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_l3proto *l3proto, + const struct nf_conntrack_l4proto *l4proto) +{ + return nf_ct_get_tuple(skb, nhoff, dataoff, l3num, protonum, tuple, + l3proto, l4proto); +} +#define nf_ct_get_tuple rpl_nf_ct_get_tuple +#endif /* HAVE_NF_CT_GET_TUPLEPR_TAKES_STRUCT_NET */ + #endif /* _NF_CONNTRACK_CORE_WRAPPER_H */ diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h new file mode 100644 index 0000000..b11d1a5 --- /dev/null +++ b/datapath/linux/compat/include/net/netfilter/nf_conntrack_seqadj.h @@ -0,0 +1,30 @@ +#ifndef _NF_CONNTRACK_SEQADJ_WRAPPER_H +#define _NF_CONNTRACK_SEQADJ_WRAPPER_H + +#ifdef HAVE_NF_CT_SEQ_ADJUST +#include_next +#else + +#include + +/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ +static inline int +nf_ct_seq_adjust(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, + unsigned int protoff) +{ + typeof(nf_nat_seq_adjust_hook) seq_adjust; + + seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); + if (!seq_adjust || + !seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) { + NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); + return 0; + } + + return 1; +} + +#endif /* HAVE_NF_CT_SEQ_ADJUST */ + +#endif /* _NF_CONNTRACK_SEQADJ_WRAPPER_H */ diff --git a/datapath/linux/compat/include/net/netfilter/nf_nat.h b/datapath/linux/compat/include/net/netfilter/nf_nat.h new file mode 100644 index 0000000..773e569 --- /dev/null +++ b/datapath/linux/compat/include/net/netfilter/nf_nat.h @@ -0,0 +1,44 @@ +#ifndef _NF_NAT_WRAPPER_H +#define _NF_NAT_WRAPPER_H + +#include_next + +#ifndef HAVE_NF_CT_NAT_EXT_ADD + +static inline struct nf_conn_nat * +nf_ct_nat_ext_add(struct nf_conn *ct) +{ + struct nf_conn_nat *nat = nfct_nat(ct); + if (nat) + return nat; + + if (!nf_ct_is_confirmed(ct)) + nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); + + return nat; +} +#endif /* HAVE_NF_CT_NAT_EXT_ADD */ + +#ifndef HAVE_NF_NAT_ALLOC_NULL_BINDING +static inline unsigned int +nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) +{ + /* Force range to this IP; let proto decide mapping for + * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). + * Use reply in case it's already been mangled (eg local packet). + */ + union nf_inet_addr ip = + (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ? + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 : + ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3); + struct nf_nat_range range = { + .flags = NF_NAT_RANGE_MAP_IPS, + .min_addr = ip, + .max_addr = ip, + }; + return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); +} + +#endif /* HAVE_NF_NAT_ALLOC_NULL_BINDING */ + +#endif /* _NF_NAT_WRAPPER_H */ diff --git a/datapath/linux/compat/include/net/netfilter/nf_nat_core.h b/datapath/linux/compat/include/net/netfilter/nf_nat_core.h new file mode 100644 index 0000000..6b17ab7 --- /dev/null +++ b/datapath/linux/compat/include/net/netfilter/nf_nat_core.h @@ -0,0 +1,88 @@ +#ifndef _NF_NAT_CORE_WRAPPER_H +#define _NF_NAT_CORE_WRAPPER_H + +#include_next + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) + +/* Linux 4.6 and newer do not depend on skb_dst being set, so this workaround + * is not needed there. + */ +static inline unsigned int +rpl_nf_nat_packet(struct nf_conn *ct, enum ip_conntrack_info ctinfo, + unsigned int hooknum, struct sk_buff *skb) +{ + /* Change skb to CHECKSUM_PARTIAL to avoid running code that + * expects skb_dst being set. + */ + if (skb->ip_summed != CHECKSUM_PARTIAL) { + switch (skb->protocol) { + case ETH_P_IP: + switch (ip_hdr(skb)->protocol) { + case IPPROTO_TCP: + skb->csum_offset = offsetof(struct tcphdr, + check); + break; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + /* Skip if no csum. */ + if (!udp_hdr(skb)->check) + goto out; + skb->csum_offset = offsetof(struct udphdr, + check); + break; + case IPPROTO_SCTP: + skb->csum_offset = offsetof(struct sctphdr, + checksum); + break; + default: + goto out; + } + break; + case ETH_P_IPV6: { + struct ipv6hdr *nh = ipv6_hdr(skb); + u8 nexthdr = nh->nexthdr; + int payload_ofs = (u8 *)(nh + 1) - skb->data; + __be16 frag_off; + + payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, + &nexthdr, &frag_off); + if (unlikely(payload_ofs < 0)) + goto out; + + switch (nexthdr) { + case NEXTHDR_TCP: + skb->csum_offset = offsetof(struct tcphdr, + check); + break; + case NEXTHDR_UDP: + /* Skip if no csum. */ + if (!udp_hdr(skb)->check) + goto out; + skb->csum_offset = offsetof(struct udphdr, + check); + break; + case NEXTHDR_SCTP: + skb->csum_offset = offsetof(struct sctphdr, + checksum); + break; + default: + goto out; + } + break; + } + default: + goto out; + } + + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_headroom(skb) + skb_transport_offset(skb); + } + out: + return nf_nat_packet(ct, ctinfo, hooknum, skb); +} +#define nf_nat_packet rpl_nf_nat_packet + +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) */ + +#endif /* _NF_NAT_CORE_WRAPPER_H */