From patchwork Sat Nov 7 19:59:55 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joe Stringer X-Patchwork-Id: 541375 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (li376-54.members.linode.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 0878A1402CC for ; Sun, 8 Nov 2015 07:01:51 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=nicira_com.20150623.gappssmtp.com header.i=@nicira_com.20150623.gappssmtp.com header.b=lIW4mRhV; dkim-atps=neutral Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id E0DA210AA4; Sat, 7 Nov 2015 12:00:39 -0800 (PST) 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 DD8B810A97 for ; Sat, 7 Nov 2015 12:00:36 -0800 (PST) Received: from bar3.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id 6F31B162F76 for ; Sat, 7 Nov 2015 13:00:36 -0700 (MST) X-ASG-Debug-ID: 1446926436-03dd7b490e1f110001-byXFYA Received: from mx3-pf2.cudamail.com ([192.168.14.1]) by bar3.cudamail.com with ESMTP id ogQE38iVuwfzAYN7 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Sat, 07 Nov 2015 13:00:36 -0700 (MST) X-Barracuda-Envelope-From: joestringer@nicira.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.1 Received: from unknown (HELO mail-pa0-f53.google.com) (209.85.220.53) by mx3-pf2.cudamail.com with ESMTPS (RC4-SHA encrypted); 7 Nov 2015 20:00:35 -0000 Received-SPF: unknown (mx3-pf2.cudamail.com: Multiple SPF records returned) X-Barracuda-RBL-Trusted-Forwarder: 209.85.220.53 Received: by pasz6 with SMTP id z6so160774006pas.2 for ; Sat, 07 Nov 2015 12:00:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nicira_com.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references; bh=6LZEvKMFVKyHdr8cKYPYfGAg+KEAEefr377JcxXhaLQ=; b=lIW4mRhVpsVoemdAVRWWxThWtOD4FdTR1vngHTq7NJufLoMC8fBPvzn8FoAcJkPPb7 Ysjm9BZ/P7MpMts3AgqN1Dikcmb6OpSAtQxemDPK4sh83Y6JGfTBEscn3QURSsggTJdg BkGzmRpKWCUvAjUpeMQBFDJGUygFhtdSnFqBrN4Kojma6ux9+SafKWRZpT7ogei88C4k +RHSqmvZrBXmdgH0LhqGbaW9OMDQpGi+vHVJqtluljkSpzM79ch9iiOTasMKradT4Q+c oY5HcQzX0vHQy3K7fI3xS8rJCSEM8TR1WQ/qLiC9VeI6+25GtY0kQDiaMdgk3qQ7b2Wr 0+vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=6LZEvKMFVKyHdr8cKYPYfGAg+KEAEefr377JcxXhaLQ=; b=Qc9qiGJUe8SmHbYrhh9LZ0mdewV2lgfp3I8I9YiBbnsWlusTYXgKvy7zwR1o2CAQU4 IIYc0HsA59XMXt1wSe+fAjlUZ7P8xMTwfBaTj/oGsPeAQsl7YrJaexMN3bTUcyF0z8L8 X6YOT4v9Dv87tdF52SNJB12J77ZSqC4T+cJ2d+lesuQSeHgG/bluzsKmu4TowgypROlj qe6s1fBCrxP3BfjbtTPJTiHdAWFvers6JevgoCN7f5V0WSouaDwAXWa4EaTqDH9zGaLy D3+h7PSqVdx8pWW2GjJ+CN+UHmXJhoN5vylIVl33sWXzsKWOPoQ03QVAeDABodtwnX+I JA8w== X-Gm-Message-State: ALoCoQk4MkxTdG9fToug9sAoUa6ckLXQe6epxtI/didrv57qtfs1X4wNv31IahazUXkoQFGb1xFO X-Received: by 10.68.170.98 with SMTP id al2mr27107852pbc.121.1446926435223; Sat, 07 Nov 2015 12:00:35 -0800 (PST) Received: from localhost.localdomain ([208.91.2.4]) by smtp.gmail.com with ESMTPSA id nu5sm7312219pbb.65.2015.11.07.12.00.34 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 07 Nov 2015 12:00:34 -0800 (PST) X-CudaMail-Envelope-Sender: joestringer@nicira.com X-Barracuda-Apparent-Source-IP: 208.91.2.4 From: Joe Stringer To: dev@openvswitch.org X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V2-1106015425 X-CudaMail-DTE: 110715 X-CudaMail-Originating-IP: 209.85.220.53 Date: Sat, 7 Nov 2015 11:59:55 -0800 X-ASG-Orig-Subj: [##CM-V2-1106015425##][PATCH 17/23] datapath: Allow attaching helpers to ct action Message-Id: <1446926401-55723-18-git-send-email-joestringer@nicira.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1446926401-55723-1-git-send-email-joestringer@nicira.com> References: <1446926401-55723-1-git-send-email-joestringer@nicira.com> X-Barracuda-Connect: UNKNOWN[192.168.14.1] X-Barracuda-Start-Time: 1446926436 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 17/23] datapath: Allow attaching helpers to ct action 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" Add support for using conntrack helpers to assist protocol detection. The new OVS_CT_ATTR_HELPER attribute of the CT action specifies a helper to be used for this connection. If no helper is specified, then helpers will be automatically applied as per the sysctl configuration of net.netfilter.nf_conntrack_helper. The helper may be specified as part of the conntrack action, eg: ct(helper=ftp). Initial packets for related connections should be committed to allow later packets for the flow to be considered established. Example ovs-ofctl flows allowing FTP connections from ports 1->2: in_port=1,tcp,action=ct(helper=ftp,commit),2 in_port=2,tcp,ct_state=-trk,action=ct(recirc) in_port=2,tcp,ct_state=+trk-new+est,action=1 in_port=2,tcp,ct_state=+trk+rel,action=1 Upstream: cae3a26 "openvswitch: Allow attaching helpers to ct action" Signed-off-by: Joe Stringer --- datapath/conntrack.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/datapath/conntrack.c b/datapath/conntrack.c index 721d0dfb786f..5038d839a7bd 100644 --- a/datapath/conntrack.c +++ b/datapath/conntrack.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ struct md_label { /* Conntrack action context for execution. */ struct ovs_conntrack_info { + struct nf_conntrack_helper *helper; struct nf_conntrack_zone zone; struct nf_conn *ct; u32 flags; @@ -240,6 +242,51 @@ static int ovs_ct_set_label(struct sk_buff *skb, struct sw_flow_key *key, return 0; } +/* 'skb' should already be pulled to nh_ofs. */ +static int ovs_ct_helper(struct sk_buff *skb, u16 proto) +{ + const struct nf_conntrack_helper *helper; + const struct nf_conn_help *help; + enum ip_conntrack_info ctinfo; + unsigned int protoff; + struct nf_conn *ct; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct || 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; + + switch (proto) { + case NFPROTO_IPV4: + protoff = ip_hdrlen(skb); + break; + case NFPROTO_IPV6: { + u8 nexthdr = ipv6_hdr(skb)->nexthdr; + __be16 frag_off; + + protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), + &nexthdr, &frag_off); + if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { + pr_debug("proto header not found\n"); + return NF_ACCEPT; + } + break; + } + default: + WARN_ONCE(1, "helper invoked on non-IP family!"); + return NF_DROP; + } + + return helper->help(skb, protoff, ct, ctinfo); +} + static int handle_fragments(struct net *net, struct sw_flow_key *key, u16 zone, struct sk_buff *skb) { @@ -317,6 +364,13 @@ static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb, return false; if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct))) return false; + if (info->helper) { + struct nf_conn_help *help; + + help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER); + if (help && rcu_access_pointer(help->helper) != info->helper) + return false; + } return true; } @@ -345,6 +399,11 @@ static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key, if (nf_conntrack_in(net, info->family, NF_INET_FORWARD, skb) != NF_ACCEPT) return -ENOENT; + + if (ovs_ct_helper(skb, info->family) != NF_ACCEPT) { + WARN_ONCE(1, "helper rejected packet"); + return -EINVAL; + } } return 0; @@ -453,6 +512,30 @@ err: return err; } +static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name, + const struct sw_flow_key *key, bool log) +{ + struct nf_conntrack_helper *helper; + struct nf_conn_help *help; + + helper = nf_conntrack_helper_try_module_get(name, info->family, + key->ip.proto); + if (!helper) { + OVS_NLERR(log, "Unknown helper \"%s\"", name); + return -EINVAL; + } + + help = nf_ct_helper_ext_add(info->ct, helper, GFP_KERNEL); + if (!help) { + module_put(helper->me); + return -ENOMEM; + } + + rcu_assign_pointer(help->helper, helper); + info->helper = helper; + return 0; +} + static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { [OVS_CT_ATTR_FLAGS] = { .minlen = sizeof(u32), .maxlen = sizeof(u32) }, @@ -462,10 +545,12 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { .maxlen = sizeof(struct md_mark) }, [OVS_CT_ATTR_LABEL] = { .minlen = sizeof(struct md_label), .maxlen = sizeof(struct md_label) }, + [OVS_CT_ATTR_HELPER] = { .minlen = 1, + .maxlen = NF_CT_HELPER_NAME_LEN } }; static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, - bool log) + const char **helper, bool log) { struct nlattr *a; int rem; @@ -513,6 +598,13 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, break; } #endif + case OVS_CT_ATTR_HELPER: + *helper = nla_data(a); + if (!memchr(*helper, '\0', nla_len(a))) { + OVS_NLERR(log, "Invalid conntrack helper"); + return -EINVAL; + } + break; default: OVS_NLERR(log, "Unknown conntrack attr (%d)", type); @@ -553,6 +645,7 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, struct sw_flow_actions **sfa, bool log) { struct ovs_conntrack_info ct_info; + const char *helper = NULL; u16 family; int err; @@ -568,7 +661,7 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID, NF_CT_DEFAULT_ZONE_DIR, 0); - err = parse_ct(attr, &ct_info, log); + err = parse_ct(attr, &ct_info, &helper, log); if (err) return err; @@ -578,6 +671,11 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, OVS_NLERR(log, "Failed to allocate conntrack template"); return -ENOMEM; } + if (helper) { + err = ovs_ct_add_helper(&ct_info, helper, key, log); + if (err) + goto err_free_ct; + } err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info, sizeof(ct_info), log); @@ -614,6 +712,11 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, nla_put(skb, OVS_CT_ATTR_LABEL, sizeof(ct_info->label), &ct_info->label)) return -EMSGSIZE; + if (ct_info->helper) { + if (nla_put_string(skb, OVS_CT_ATTR_HELPER, + ct_info->helper->name)) + return -EMSGSIZE; + } nla_nest_end(skb, start); @@ -624,6 +727,8 @@ void ovs_ct_free_action(const struct nlattr *a) { struct ovs_conntrack_info *ct_info = nla_data(a); + if (ct_info->helper) + module_put(ct_info->helper->me); if (ct_info->ct) nf_ct_put(ct_info->ct); }