From patchwork Wed Nov 30 09:09:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Vadai X-Patchwork-Id: 700909 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3tTF4N5vcnz9vFj for ; Wed, 30 Nov 2016 20:10:12 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757604AbcK3JKK (ORCPT ); Wed, 30 Nov 2016 04:10:10 -0500 Received: from mail-wm0-f66.google.com ([74.125.82.66]:35501 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757523AbcK3JJw (ORCPT ); Wed, 30 Nov 2016 04:09:52 -0500 Received: by mail-wm0-f66.google.com with SMTP id a20so28383953wme.2 for ; Wed, 30 Nov 2016 01:09:51 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=b++piy5mDThlNb2w8jL8fIGjx6Jqww99XxBHVxjQ6pA=; b=Ex+szbSd/9Fr7jGvx5sCXmR3MJrJnfdPaphJY9J4jTwVaJZrbNnKe34O51kyqVjMKQ 0YNWjmG2fhAl3+Zm15ULnC56ZZnnfILW/nCQJHNM/NVY3xY00+q1ZxoZXimSQbMWmLxq GQCS5mYcZrUebymgcF3pDbIYL/6gcw5XX/CIU15UefJPxHiJ+mjv+jy4Lt9d8NRDYxzc 2jG0cTJhin4BqFoDSuRaLYJef0fHNZbAEpKlMZitWVhF+Z+zY974hexGqgNbsycLYJu+ TtR+V7Ql8E2Q21Tb6tybTsxpH76Jz9raHatHxwjN0jqCGYKMR3dMpP4omDn7VK63Sv4K i/VQ== X-Gm-Message-State: AKaTC02lx0iCkldus/Ws/nM0xwMO9e1BmX+lqGxHrPY8dMKq7FBi+NceNdyzuEOZHECq5A== X-Received: by 10.28.72.198 with SMTP id v189mr28522772wma.13.1480496990462; Wed, 30 Nov 2016 01:09:50 -0800 (PST) Received: from office.vadai.me ([192.116.94.222]) by smtp.gmail.com with ESMTPSA id r138sm6937037wme.9.2016.11.30.01.09.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 Nov 2016 01:09:49 -0800 (PST) From: Amir Vadai To: "David S. Miller" Cc: netdev@vger.kernel.org, Jamal Hadi Salim , Or Gerlitz , Hadar Har-Zion , Amir Vadai Subject: [PATCH net-next 2/3] net/act_pedit: Support using offset relative to the conventional network headers Date: Wed, 30 Nov 2016 11:09:27 +0200 Message-Id: <20161130090928.14816-3-amir@vadai.me> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20161130090928.14816-1-amir@vadai.me> References: <20161130090928.14816-1-amir@vadai.me> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Extend pedit to enable the user using offset relative to network headers. This change would enable to work with more complex header schemes (vs the simple IPv4 case) where setting a fixed offset relative to the network header is not enough. It is also forward looking to enable hardware offloading of pedit more easier. The header type is embedded in the 8 MSB of the u32 key->shift which were never used till now. Therefore backward compatibility is being kept. Usage example: $ tc filter add dev enp0s9 protocol ip parent ffff: \ flower \ ip_proto tcp \ src_port 80 \ action pedit munge tcp dport set 8080 pipe \ action mirred egress redirect dev veth0 Will forward traffic to tcp port 80, and modify the destination port to 8080. hange-Id: Ibd7bbbe0b8c2f6adae0591868bb6892c55e75732 Signed-off-by: Amir Vadai --- include/uapi/linux/tc_act/tc_pedit.h | 17 ++++++++++ net/sched/act_pedit.c | 65 +++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/include/uapi/linux/tc_act/tc_pedit.h b/include/uapi/linux/tc_act/tc_pedit.h index 6389959a5157..604e6729ad38 100644 --- a/include/uapi/linux/tc_act/tc_pedit.h +++ b/include/uapi/linux/tc_act/tc_pedit.h @@ -32,4 +32,21 @@ struct tc_pedit_sel { }; #define tc_pedit tc_pedit_sel +#define PEDIT_TYPE_SHIFT 24 +#define PEDIT_TYPE_MASK 0xff + +#define PEDIT_TYPE_GET(_val) \ + (((_val) >> PEDIT_TYPE_SHIFT) & PEDIT_TYPE_MASK) +#define PEDIT_SHIFT_GET(_val) ((_val) & 0xff) + +enum pedit_header_type { + PEDIT_HDR_TYPE_RAW = 0, + + PEDIT_HDR_TYPE_ETH = 1, + PEDIT_HDR_TYPE_IP4 = 2, + PEDIT_HDR_TYPE_IP6 = 3, + PEDIT_HDR_TYPE_TCP = 4, + PEDIT_HDR_TYPE_UDP = 5, +}; + #endif diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index b27c4daec88f..4b9c7184c752 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -119,18 +119,45 @@ static bool offset_valid(struct sk_buff *skb, int offset) return true; } +static int pedit_skb_hdr_offset(struct sk_buff *skb, + enum pedit_header_type htype, int *hoffset) +{ + int ret = -1; + + switch (htype) { + case PEDIT_HDR_TYPE_ETH: + if (skb_mac_header_was_set(skb)) { + *hoffset = skb_mac_offset(skb); + ret = 0; + } + break; + case PEDIT_HDR_TYPE_RAW: + case PEDIT_HDR_TYPE_IP4: + case PEDIT_HDR_TYPE_IP6: + *hoffset = skb_network_offset(skb); + ret = 0; + break; + case PEDIT_HDR_TYPE_TCP: + case PEDIT_HDR_TYPE_UDP: + if (skb_transport_header_was_set(skb)) { + *hoffset = skb_transport_offset(skb); + ret = 0; + } + break; + }; + + return ret; +} + static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_pedit *p = to_pedit(a); int i; - unsigned int off; if (skb_unclone(skb, GFP_ATOMIC)) return p->tcf_action; - off = skb_network_offset(skb); - spin_lock(&p->tcf_lock); tcf_lastuse_update(&p->tcf_tm); @@ -141,20 +168,32 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, for (i = p->tcfp_nkeys; i > 0; i--, tkey++) { u32 *ptr, _data; int offset = tkey->off; + int hoffset; + int rc; + enum pedit_header_type htype = + PEDIT_TYPE_GET(tkey->shift); + + rc = pedit_skb_hdr_offset(skb, htype, &hoffset); + if (rc) { + pr_info("tc filter pedit bad header type specified (0x%x)\n", + htype); + goto bad; + } if (tkey->offmask) { char *d, _d; - if (!offset_valid(skb, off + tkey->at)) { + if (!offset_valid(skb, hoffset + tkey->at)) { pr_info("tc filter pedit 'at' offset %d out of bounds\n", - off + tkey->at); + hoffset + tkey->at); goto bad; } - d = skb_header_pointer(skb, off + tkey->at, 1, - &_d); + d = skb_header_pointer(skb, + hoffset + tkey->at, + 1, &_d); if (!d) goto bad; - offset += (*d & tkey->offmask) >> tkey->shift; + offset += (*d & tkey->offmask) >> PEDIT_SHIFT_GET(tkey->shift); } if (offset % 4) { @@ -163,19 +202,21 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, goto bad; } - if (!offset_valid(skb, off + offset)) { + if (!offset_valid(skb, hoffset + offset)) { pr_info("tc filter pedit offset %d out of bounds\n", - offset); + hoffset + offset); goto bad; } - ptr = skb_header_pointer(skb, off + offset, 4, &_data); + ptr = skb_header_pointer(skb, + hoffset + offset, + 4, &_data); if (!ptr) goto bad; /* just do it, baby */ *ptr = ((*ptr & tkey->mask) ^ tkey->val); if (ptr == &_data) - skb_store_bits(skb, off + offset, ptr, 4); + skb_store_bits(skb, hoffset + offset, ptr, 4); } goto done;