From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA57ECA9EAF for ; Wed, 30 Oct 2019 08:00:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 94E942054F for ; Wed, 30 Oct 2019 08:00:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="bmR0mZyU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726345AbfJ3IAC (ORCPT ); Wed, 30 Oct 2019 04:00:02 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:46280 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725822AbfJ3IAC (ORCPT ); Wed, 30 Oct 2019 04:00:02 -0400 Received: by mail-pf1-f194.google.com with SMTP id b25so997270pfi.13 for ; Wed, 30 Oct 2019 01:00:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=GR/F5TH53j9xb8dCjUMFFAWLakr7P4+VWnWrX2ocn6k=; b=bmR0mZyUD8NFme+7ON+ws+v75WjwFParxPixbeBVYfvTiNrCOVxnhL5TRwX+1UxLWd SBhvm0MLDTwrz93ItjXK0L5v325KsPYXLKG67MhvJM+iahAVwLeJdsVN2Y/EHApuUc0O erhZHe9Qw1BR8szUwKraff72ZJW5mXOK3pu9Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=GR/F5TH53j9xb8dCjUMFFAWLakr7P4+VWnWrX2ocn6k=; b=sIfw592skuXcRG0jgchEV4exsHYOxcMNw2yvaYH3R/sOwrS2xmy9LfBSLIdZxNUsfP 48/kwVMWoinFDnnURonJkTZkDK4a64tfsu/wOT1rzZeRzNY2INVtF3hFgWm9NteRDduZ a5SvJctI8mgF3+IJ38oWoBMoR/WaoXmfTcLAHlAD8M0YnUszYJBVDUwyBE8EnMe3h5e+ Bx/KoLtnFVpP98/tl1D+ODniFyfVvKlgMnYJJLRQq4hSsN1B9tWK3Sv6KsuhWbuTgPUq dlsT+JHRDhO6x86zrCS5tPMz2ctBofkvrFAF62ETfayav63En/TER2Ar7OEkY89sU6G4 Z83w== X-Gm-Message-State: APjAAAVMfk3lVflDs/TXLKuC59mD1vR3/mAUONTMEyRYYQlm/7Shs19n QR+VEKtugRnHP9HZsulgikT6Bw== X-Google-Smtp-Source: APXvYqw3vQrOr2d5HGi7ASSxa2QvBNJuZ4yZcr3KDxGlhlt+Od7c4p6nNexIvKn269EYdvBY8JHrqw== X-Received: by 2002:a63:1743:: with SMTP id 3mr33654220pgx.161.1572422401298; Wed, 30 Oct 2019 01:00:01 -0700 (PDT) Received: from localhost.swdvt.lab.broadcom.com ([192.19.223.252]) by smtp.gmail.com with ESMTPSA id r21sm1960649pfc.27.2019.10.30.00.59.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 Oct 2019 01:00:00 -0700 (PDT) From: Michael Chan To: davem@davemloft.net Cc: netdev@vger.kernel.org, Somnath Kotur Subject: [PATCH net-next 3/7] bnxt_en: Add support for NAT(L3/L4 rewrite) Date: Wed, 30 Oct 2019 03:59:31 -0400 Message-Id: <1572422375-7269-4-git-send-email-michael.chan@broadcom.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1572422375-7269-1-git-send-email-michael.chan@broadcom.com> References: <1572422375-7269-1-git-send-email-michael.chan@broadcom.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Somnath Kotur Provides support for modifying L3/L4 Header parameters to support NAT. Sets the appropriate fields/bits in cfa_flow_alloc cmd. Sample cmd for offloading an IPv4 flow with SNAT: ovs-ofctl add-flow ovsbr0 "ip,nw_src=192.168.201.44 \ actions=mod_nw_src:203.31.220.144,output:p7p1" Replace 'nw_src' with 'nw_dst' in above cmd for DNAT with IPv4 Sample cmd for offloading an IPv4 flow with SNAPT: ovs-ofctl add-flow ovsbr0 "ip,nw_src=192.168.201.44 \ actions=mod_nw_src:203.31.220.144, mod_tp_src:6789,output:p7p1" Similar to DNAT, replace 'tp_src' with 'tp_dst' for offloading flow with DNAPT Sample cmd for offloading an IPv6 flow with SNAT: ovs-ofctl add-flow ovsbr0 "ipv6, ipv6_src=2001:5c0:9168::2/64 \ actions=load:0x1->NXM_NX_IPV6_SRC[0..63], \ load:0x20010db801920000->NXM_NX_IPV6_SRC[64..127],output:p7p1" Replace 'SRC' with DST' above for IPv6 DNAT Signed-off-by: Somnath Kotur Signed-off-by: Michael Chan --- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 140 +++++++++++++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h | 11 ++- 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index 2d86796..272a9fb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -114,7 +114,8 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp, return 0; } -/* Key & Mask from the stack comes unaligned in multiple iterations. +/* Key & Mask from the stack comes unaligned in multiple iterations of 4 bytes + * each(u32). * This routine consolidates such multiple unaligned values into one * field each for Key & Mask (for src and dst macs separately) * For example, @@ -178,14 +179,19 @@ bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions, static int bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, - struct flow_action_entry *act, u8 *eth_addr, + struct flow_action_entry *act, int act_idx, u8 *eth_addr, u8 *eth_addr_mask) { - u32 mask, val, offset; + size_t offset_of_ip6_daddr = offsetof(struct ipv6hdr, daddr); + size_t offset_of_ip6_saddr = offsetof(struct ipv6hdr, saddr); + u32 mask, val, offset, idx; u8 htype; offset = act->mangle.offset; htype = act->mangle.htype; + mask = ~act->mangle.mask; + val = act->mangle.val; + switch (htype) { case FLOW_ACT_MANGLE_HDR_TYPE_ETH: if (offset > PEDIT_OFFSET_SMAC_LAST_4_BYTES) { @@ -195,12 +201,73 @@ bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, return -EINVAL; } actions->flags |= BNXT_TC_ACTION_FLAG_L2_REWRITE; - mask = ~act->mangle.mask; - val = act->mangle.val; bnxt_set_l2_key_mask(val, mask, ð_addr[offset], ð_addr_mask[offset]); break; + case FLOW_ACT_MANGLE_HDR_TYPE_IP4: + actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE; + actions->nat.l3_is_ipv4 = true; + if (offset == offsetof(struct iphdr, saddr)) { + actions->nat.src_xlate = true; + actions->nat.l3.ipv4.saddr.s_addr = htonl(val); + } else if (offset == offsetof(struct iphdr, daddr)) { + actions->nat.src_xlate = false; + actions->nat.l3.ipv4.daddr.s_addr = htonl(val); + } else { + netdev_err(bp->dev, + "%s: IPv4_hdr: Invalid pedit field\n", + __func__); + return -EINVAL; + } + + netdev_dbg(bp->dev, "nat.src_xlate = %d src IP: %pI4 dst ip : %pI4\n", + actions->nat.src_xlate, &actions->nat.l3.ipv4.saddr, + &actions->nat.l3.ipv4.daddr); + break; + + case FLOW_ACT_MANGLE_HDR_TYPE_IP6: + actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE; + actions->nat.l3_is_ipv4 = false; + if (offset >= offsetof(struct ipv6hdr, saddr) && + offset < offset_of_ip6_daddr) { + /* 16 byte IPv6 address comes in 4 iterations of + * 4byte chunks each + */ + actions->nat.src_xlate = true; + idx = (offset - offset_of_ip6_saddr) / 4; + /* First 4bytes will be copied to idx 0 and so on */ + actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val); + } else if (offset >= offset_of_ip6_daddr && + offset < offset_of_ip6_daddr + 16) { + actions->nat.src_xlate = false; + idx = (offset - offset_of_ip6_daddr) / 4; + actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val); + } else { + netdev_err(bp->dev, + "%s: IPv6_hdr: Invalid pedit field\n", + __func__); + return -EINVAL; + } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: + /* HW does not support L4 rewrite alone without L3 + * rewrite + */ + if (!(actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE)) { + netdev_err(bp->dev, + "Need to specify L3 rewrite as well\n"); + return -EINVAL; + } + if (actions->nat.src_xlate) + actions->nat.l4.ports.sport = htons(val); + else + actions->nat.l4.ports.dport = htons(val); + netdev_dbg(bp->dev, "actions->nat.sport = %d dport = %d\n", + actions->nat.l4.ports.sport, + actions->nat.l4.ports.dport); + break; default: netdev_err(bp->dev, "%s: Unsupported pedit hdr type\n", __func__); @@ -258,7 +325,7 @@ static int bnxt_tc_parse_actions(struct bnxt *bp, break; /* Packet edit: L2 rewrite, NAT, NAPT */ case FLOW_ACTION_MANGLE: - rc = bnxt_tc_parse_pedit(bp, actions, act, eth_addr, + rc = bnxt_tc_parse_pedit(bp, actions, act, i, eth_addr, eth_addr_mask); if (rc) return rc; @@ -532,6 +599,67 @@ static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow, CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE; } + if (actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE) { + if (actions->nat.l3_is_ipv4) { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_IPV4_ADDRESS; + + if (actions->nat.src_xlate) { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC; + /* L3 source rewrite */ + req.nat_ip_address[0] = + actions->nat.l3.ipv4.saddr.s_addr; + /* L4 source port */ + if (actions->nat.l4.ports.sport) + req.nat_port = + actions->nat.l4.ports.sport; + } else { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST; + /* L3 destination rewrite */ + req.nat_ip_address[0] = + actions->nat.l3.ipv4.daddr.s_addr; + /* L4 destination port */ + if (actions->nat.l4.ports.dport) + req.nat_port = + actions->nat.l4.ports.dport; + } + netdev_dbg(bp->dev, + "req.nat_ip_address: %pI4 src_xlate: %d req.nat_port: %x\n", + req.nat_ip_address, actions->nat.src_xlate, + req.nat_port); + } else { + if (actions->nat.src_xlate) { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC; + /* L3 source rewrite */ + memcpy(req.nat_ip_address, + actions->nat.l3.ipv6.saddr.s6_addr32, + sizeof(req.nat_ip_address)); + /* L4 source port */ + if (actions->nat.l4.ports.sport) + req.nat_port = + actions->nat.l4.ports.sport; + } else { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST; + /* L3 destination rewrite */ + memcpy(req.nat_ip_address, + actions->nat.l3.ipv6.daddr.s6_addr32, + sizeof(req.nat_ip_address)); + /* L4 destination port */ + if (actions->nat.l4.ports.dport) + req.nat_port = + actions->nat.l4.ports.dport; + } + netdev_dbg(bp->dev, + "req.nat_ip_address: %pI6 src_xlate: %d req.nat_port: %x\n", + req.nat_ip_address, actions->nat.src_xlate, + req.nat_port); + } + } + if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP || actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) { req.tunnel_handle = tunnel_handle; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h index 6d0d485..2867549 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h @@ -78,6 +78,7 @@ struct bnxt_tc_actions { #define BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP BIT(6) #define BNXT_TC_ACTION_FLAG_TUNNEL_DECAP BIT(7) #define BNXT_TC_ACTION_FLAG_L2_REWRITE BIT(8) +#define BNXT_TC_ACTION_FLAG_NAT_XLATE BIT(9) u16 dst_fid; struct net_device *dst_dev; @@ -89,7 +90,15 @@ struct bnxt_tc_actions { #define PEDIT_OFFSET_SMAC_LAST_4_BYTES 0x8 __be16 l2_rewrite_dmac[3]; __be16 l2_rewrite_smac[3]; - + struct { + bool src_xlate; /* true => translate src, + * false => translate dst + * Mutually exclusive, i.e cannot set both + */ + bool l3_is_ipv4; /* false means L3 is ipv6 */ + struct bnxt_tc_l3_key l3; + struct bnxt_tc_l4_key l4; + } nat; }; struct bnxt_tc_flow { -- 2.5.1