From patchwork Thu Jul 4 14:23:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1127582 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45fgQN3zrkz9sNw for ; Fri, 5 Jul 2019 00:31:24 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5A66E1257; Thu, 4 Jul 2019 14:23:52 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp2.linuxfoundation.org (smtp2.linux-foundation.org [172.17.192.36]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 788FE11D7 for ; Thu, 4 Jul 2019 14:23:46 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp2.linuxfoundation.org (Postfix) with ESMTP id 380B11DCF0 for ; Thu, 4 Jul 2019 14:23:44 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE2 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 4 Jul 2019 17:23:37 +0300 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id x64ENaFL008452; Thu, 4 Jul 2019 17:23:37 +0300 From: Paul Blakey To: Paul Blakey , dev@openvswitch.org Date: Thu, 4 Jul 2019 17:23:20 +0300 Message-Id: <1562250200-17683-12-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1562250200-17683-1-git-send-email-paulb@mellanox.com> References: <1562250200-17683-1-git-send-email-paulb@mellanox.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp2.linux-foundation.org Cc: Marcelo Ricardo Leitner , Oz Shlomo , Simon Horman , Rony Efraim , David Miller , Yossi Kuperman Subject: [ovs-dev] [PATCH RFC 8/8] netdev-tc-offloads: Add conntrack nat support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Signed-off-by: Paul Blakey --- lib/netdev-offload-tc.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/tc.c | 84 +++++++++++++++++++++++++++++++++++++++ lib/tc.h | 24 +++++++++++ 3 files changed, 211 insertions(+) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 9c5c25e..0a0ada8 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -776,6 +776,39 @@ parse_tc_flower_to_match(struct tc_flower *flower, ct_label->mask = action->ct.label_mask; } + if (action->ct.nat_type) { + size_t nat_offset = nl_msg_start_nested(buf, OVS_CT_ATTR_NAT); + + if (action->ct.nat_type == TC_NAT_SRC) { + nl_msg_put_flag(buf, OVS_NAT_ATTR_SRC); + } else if (action->ct.nat_type == TC_NAT_DST) { + nl_msg_put_flag(buf, OVS_NAT_ATTR_DST); + } + + if (action->ct.range.ip_family == AF_INET) { + nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MIN, + action->ct.range.min_addr.ipv4); + nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MAX, + action->ct.range.max_addr.ipv4); + } else if (action->ct.range.ip_family == AF_INET6) { + nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MIN, + &action->ct.range.min_addr.ipv6); + nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MAX, + &action->ct.range.max_addr.ipv6); + } + + if (action->ct.range.min_port) { + nl_msg_put_be16(buf, OVS_NAT_ATTR_PROTO_MIN, + action->ct.range.min_port); + if (action->ct.range.max_port) { + nl_msg_put_be16(buf, OVS_NAT_ATTR_PROTO_MAX, + action->ct.range.max_port); + } + } + + nl_msg_end_nested(buf, nat_offset); + } + nl_msg_end_nested(buf, ct_offset); } break; @@ -851,6 +884,66 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, } static int +parse_put_flow_nat_action(struct tc_action *action, + const struct nlattr *nat, + size_t nat_len) +{ + const struct nlattr *nat_attr; + size_t nat_left; + + action->ct.nat_type = TC_NAT_RESTORE; + NL_ATTR_FOR_EACH_UNSAFE(nat_attr, nat_left, nat, nat_len) { + switch (nl_attr_type(nat_attr)) { + case OVS_NAT_ATTR_SRC: { + action->ct.nat_type = TC_NAT_SRC; + }; + break; + case OVS_NAT_ATTR_DST: { + action->ct.nat_type = TC_NAT_DST; + }; + break; + case OVS_NAT_ATTR_IP_MIN: { + if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) { + ovs_be32 addr = nl_attr_get_be32(nat_attr); + + action->ct.range.min_addr.ipv4 = addr; + action->ct.range.ip_family = AF_INET; + } else { + struct in6_addr addr = nl_attr_get_in6_addr(nat_attr); + + action->ct.range.min_addr.ipv6 = addr; + action->ct.range.ip_family = AF_INET6; + } + }; + break; + case OVS_NAT_ATTR_IP_MAX: { + if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) { + ovs_be32 addr = nl_attr_get_be32(nat_attr); + + action->ct.range.max_addr.ipv4 = addr; + action->ct.range.ip_family = AF_INET; + } else { + struct in6_addr addr = nl_attr_get_in6_addr(nat_attr); + + action->ct.range.max_addr.ipv6 = addr; + action->ct.range.ip_family = AF_INET6; + } + }; + break; + case OVS_NAT_ATTR_PROTO_MIN: { + action->ct.range.min_port = nl_attr_get_be16(nat_attr); + }; + break; + case OVS_NAT_ATTR_PROTO_MAX: { + action->ct.range.max_port = nl_attr_get_be16(nat_attr); + }; + break; + } + } + return 0; +} + +static int parse_put_flow_ct_action(struct tc_flower *flower, struct tc_action *action, const struct nlattr *ct, @@ -870,6 +963,16 @@ parse_put_flow_ct_action(struct tc_flower *flower, action->ct.zone = nl_attr_get_u16(ct_attr); } break; + case OVS_CT_ATTR_NAT: { + const struct nlattr *nat = nl_attr_get(ct_attr); + const size_t nat_len = nl_attr_get_size(ct_attr); + + err = parse_put_flow_nat_action(action, nat, nat_len); + if (err) { + return err; + } + } + break; case OVS_CT_ATTR_MARK: { const struct { uint32_t key; diff --git a/lib/tc.c b/lib/tc.c index 33a32e4..2aa3523 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -1264,6 +1264,18 @@ static const struct nl_policy ct_policy[] = { .optional = true, }, [TCA_CT_LABELS_MASK] = { .type = NL_A_UNSPEC, .optional = true, }, + [TCA_CT_NAT_IPV4_MIN] = { .type = NL_A_U32, + .optional = true, }, + [TCA_CT_NAT_IPV4_MAX] = { .type = NL_A_U32, + .optional = true, }, + [TCA_CT_NAT_IPV6_MIN] = { .min_len = sizeof(struct in6_addr), + .optional = true, }, + [TCA_CT_NAT_IPV6_MAX] = { .min_len = sizeof(struct in6_addr), + .optional = true, }, + [TCA_CT_NAT_PORT_MIN] = { .type = NL_A_U16, + .optional = true, }, + [TCA_CT_NAT_PORT_MAX] = { .type = NL_A_U16, + .optional = true, }, }; static int @@ -1306,6 +1318,47 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) action->ct.label_mask = label_mask ? nl_attr_get_u128(label_mask) : OVS_U128_ZERO; + if (ct_action & TCA_CT_ACT_NAT) { + struct nlattr *ipv4_min = ct_attrs[TCA_CT_NAT_IPV4_MIN]; + struct nlattr *ipv4_max = ct_attrs[TCA_CT_NAT_IPV4_MAX]; + struct nlattr *ipv6_min = ct_attrs[TCA_CT_NAT_IPV6_MIN]; + struct nlattr *ipv6_max = ct_attrs[TCA_CT_NAT_IPV6_MAX]; + struct nlattr *min_port = ct_attrs[TCA_CT_NAT_PORT_MIN]; + struct nlattr *max_port = ct_attrs[TCA_CT_NAT_PORT_MAX]; + + action->ct.nat_type = TC_NAT_RESTORE; + if (ct_action & TCA_CT_ACT_NAT_SRC) { + action->ct.nat_type = TC_NAT_SRC; + } else if (ct_action & TCA_CT_ACT_NAT_DST) { + action->ct.nat_type = TC_NAT_DST; + } + + if (ipv4_min) { + action->ct.range.ip_family = AF_INET; + action->ct.range.min_addr.ipv4 = nl_attr_get_be32(ipv4_min); + if (ipv4_max) { + ovs_be32 port = nl_attr_get_be32(ipv4_max); + + action->ct.range.max_addr.ipv4 = port; + } + } else if (ipv6_min) { + action->ct.range.ip_family = AF_INET6; + action->ct.range.min_addr.ipv6 + = nl_attr_get_in6_addr(ipv6_min); + if (ipv6_max) { + struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max); + + action->ct.range.max_addr.ipv6 = addr; + } + } + + if (min_port) { + action->ct.range.min_port = nl_attr_get_be16(min_port); + if (max_port) { + action->ct.range.max_port = nl_attr_get_be16(max_port); + } + } + } } action->type = TC_ACT_CT; @@ -1882,6 +1935,37 @@ nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action) ct_action |= TCA_CT_ACT_FORCE; } } + + if (action->ct.nat_type) { + ct_action |= TCA_CT_ACT_NAT; + + if (action->ct.nat_type == TC_NAT_SRC) { + ct_action |= TCA_CT_ACT_NAT_SRC; + } else if (action->ct.nat_type == TC_NAT_DST) { + ct_action |= TCA_CT_ACT_NAT_DST; + } + + if (action->ct.range.ip_family == AF_INET) { + nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MIN, + action->ct.range.min_addr.ipv4); + nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MAX, + action->ct.range.max_addr.ipv4); + } else if (action->ct.range.ip_family == AF_INET6) { + nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MIN, + &action->ct.range.min_addr.ipv6); + nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MAX, + &action->ct.range.max_addr.ipv6); + } + + if (action->ct.range.min_port) { + nl_msg_put_be16(request, TCA_CT_NAT_PORT_MIN, + action->ct.range.min_port); + if (action->ct.range.max_port) { + nl_msg_put_be16(request, TCA_CT_NAT_PORT_MAX, + action->ct.range.max_port); + } + } + } } else { ct_action = TCA_CT_ACT_CLEAR; } diff --git a/lib/tc.h b/lib/tc.h index ebe6073..1068f3e 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -162,6 +162,13 @@ enum tc_action_type { TC_ACT_CT, }; +enum nat_type { + TC_NO_NAT = 0, + TC_NAT_SRC, + TC_NAT_DST, + TC_NAT_RESTORE, +}; + struct tc_action { union { int chain; @@ -202,6 +209,23 @@ struct tc_action { uint32_t mark_mask; ovs_u128 label; ovs_u128 label_mask; + uint8_t nat_type; + struct { + uint8_t ip_family; + + union { + struct in6_addr ipv6; + ovs_be32 ipv4; + } min_addr; + + union { + struct in6_addr ipv6; + ovs_be32 ipv4; + } max_addr; + + ovs_be16 min_port; + ovs_be16 max_port; + } range; bool clear; bool force; bool commit;