bnxt_en: Add support for L2 rewrite
This patch adds support for packet edit offload of L2 fields (src mac & dst mac, also referred as L2 rewrite). Only when the mask is fully exact match for a field, the command is sent down to the adapter to offload such a flow. Otherwise, an error is returned. v2: Fix pointer alignment issue in bnxt_fill_l2_rewrite_fields() [MChan] Signed-off-by: Venkat Duvvuru <venkatkumar.duvvuru@broadcom.com> Signed-off-by: Michael Chan <michael.chan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e43ea83cc7
commit
90f906243b
2 changed files with 143 additions and 0 deletions
|
@ -16,6 +16,7 @@
|
||||||
#include <net/tc_act/tc_skbedit.h>
|
#include <net/tc_act/tc_skbedit.h>
|
||||||
#include <net/tc_act/tc_mirred.h>
|
#include <net/tc_act/tc_mirred.h>
|
||||||
#include <net/tc_act/tc_vlan.h>
|
#include <net/tc_act/tc_vlan.h>
|
||||||
|
#include <net/tc_act/tc_pedit.h>
|
||||||
#include <net/tc_act/tc_tunnel_key.h>
|
#include <net/tc_act/tc_tunnel_key.h>
|
||||||
|
|
||||||
#include "bnxt_hsi.h"
|
#include "bnxt_hsi.h"
|
||||||
|
@ -36,6 +37,8 @@
|
||||||
#define is_vid_exactmatch(vlan_tci_mask) \
|
#define is_vid_exactmatch(vlan_tci_mask) \
|
||||||
((ntohs(vlan_tci_mask) & VLAN_VID_MASK) == VLAN_VID_MASK)
|
((ntohs(vlan_tci_mask) & VLAN_VID_MASK) == VLAN_VID_MASK)
|
||||||
|
|
||||||
|
static bool is_wildcard(void *mask, int len);
|
||||||
|
static bool is_exactmatch(void *mask, int len);
|
||||||
/* Return the dst fid of the func for flow forwarding
|
/* Return the dst fid of the func for flow forwarding
|
||||||
* For PFs: src_fid is the fid of the PF
|
* For PFs: src_fid is the fid of the PF
|
||||||
* For VF-reps: src_fid the fid of the VF
|
* For VF-reps: src_fid the fid of the VF
|
||||||
|
@ -111,10 +114,115 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Key & Mask from the stack comes unaligned in multiple iterations.
|
||||||
|
* This routine consolidates such multiple unaligned values into one
|
||||||
|
* field each for Key & Mask (for src and dst macs separately)
|
||||||
|
* For example,
|
||||||
|
* Mask/Key Offset Iteration
|
||||||
|
* ========== ====== =========
|
||||||
|
* dst mac 0xffffffff 0 1
|
||||||
|
* dst mac 0x0000ffff 4 2
|
||||||
|
*
|
||||||
|
* src mac 0xffff0000 4 1
|
||||||
|
* src mac 0xffffffff 8 2
|
||||||
|
*
|
||||||
|
* The above combination coming from the stack will be consolidated as
|
||||||
|
* Mask/Key
|
||||||
|
* ==============
|
||||||
|
* src mac: 0xffffffffffff
|
||||||
|
* dst mac: 0xffffffffffff
|
||||||
|
*/
|
||||||
|
static void bnxt_set_l2_key_mask(u32 part_key, u32 part_mask,
|
||||||
|
u8 *actual_key, u8 *actual_mask)
|
||||||
|
{
|
||||||
|
u32 key = get_unaligned((u32 *)actual_key);
|
||||||
|
u32 mask = get_unaligned((u32 *)actual_mask);
|
||||||
|
|
||||||
|
part_key &= part_mask;
|
||||||
|
part_key |= key & ~part_mask;
|
||||||
|
|
||||||
|
put_unaligned(mask | part_mask, (u32 *)actual_mask);
|
||||||
|
put_unaligned(part_key, (u32 *)actual_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions,
|
||||||
|
u16 *eth_addr, u16 *eth_addr_mask)
|
||||||
|
{
|
||||||
|
u16 *p;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (unlikely(bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!is_wildcard(ð_addr_mask[0], ETH_ALEN)) {
|
||||||
|
if (!is_exactmatch(ð_addr_mask[0], ETH_ALEN))
|
||||||
|
return -EINVAL;
|
||||||
|
/* FW expects dmac to be in u16 array format */
|
||||||
|
p = eth_addr;
|
||||||
|
for (j = 0; j < 3; j++)
|
||||||
|
actions->l2_rewrite_dmac[j] = cpu_to_be16(*(p + j));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_wildcard(ð_addr_mask[ETH_ALEN], ETH_ALEN)) {
|
||||||
|
if (!is_exactmatch(ð_addr_mask[ETH_ALEN], ETH_ALEN))
|
||||||
|
return -EINVAL;
|
||||||
|
/* FW expects smac to be in u16 array format */
|
||||||
|
p = ð_addr[ETH_ALEN / 2];
|
||||||
|
for (j = 0; j < 3; j++)
|
||||||
|
actions->l2_rewrite_smac[j] = cpu_to_be16(*(p + j));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions,
|
||||||
|
struct flow_action_entry *act, u8 *eth_addr,
|
||||||
|
u8 *eth_addr_mask)
|
||||||
|
{
|
||||||
|
u32 mask, val, offset;
|
||||||
|
u8 htype;
|
||||||
|
|
||||||
|
offset = act->mangle.offset;
|
||||||
|
htype = act->mangle.htype;
|
||||||
|
switch (htype) {
|
||||||
|
case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
|
||||||
|
if (offset > PEDIT_OFFSET_SMAC_LAST_4_BYTES) {
|
||||||
|
netdev_err(bp->dev,
|
||||||
|
"%s: eth_hdr: Invalid pedit field\n",
|
||||||
|
__func__);
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
netdev_err(bp->dev, "%s: Unsupported pedit hdr type\n",
|
||||||
|
__func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int bnxt_tc_parse_actions(struct bnxt *bp,
|
static int bnxt_tc_parse_actions(struct bnxt *bp,
|
||||||
struct bnxt_tc_actions *actions,
|
struct bnxt_tc_actions *actions,
|
||||||
struct flow_action *flow_action)
|
struct flow_action *flow_action)
|
||||||
{
|
{
|
||||||
|
/* Used to store the L2 rewrite mask for dmac (6 bytes) followed by
|
||||||
|
* smac (6 bytes) if rewrite of both is specified, otherwise either
|
||||||
|
* dmac or smac
|
||||||
|
*/
|
||||||
|
u16 eth_addr_mask[ETH_ALEN] = { 0 };
|
||||||
|
/* Used to store the L2 rewrite key for dmac (6 bytes) followed by
|
||||||
|
* smac (6 bytes) if rewrite of both is specified, otherwise either
|
||||||
|
* dmac or smac
|
||||||
|
*/
|
||||||
|
u16 eth_addr[ETH_ALEN] = { 0 };
|
||||||
struct flow_action_entry *act;
|
struct flow_action_entry *act;
|
||||||
int i, rc;
|
int i, rc;
|
||||||
|
|
||||||
|
@ -148,11 +256,26 @@ static int bnxt_tc_parse_actions(struct bnxt *bp,
|
||||||
case FLOW_ACTION_TUNNEL_DECAP:
|
case FLOW_ACTION_TUNNEL_DECAP:
|
||||||
actions->flags |= BNXT_TC_ACTION_FLAG_TUNNEL_DECAP;
|
actions->flags |= BNXT_TC_ACTION_FLAG_TUNNEL_DECAP;
|
||||||
break;
|
break;
|
||||||
|
/* Packet edit: L2 rewrite, NAT, NAPT */
|
||||||
|
case FLOW_ACTION_MANGLE:
|
||||||
|
rc = bnxt_tc_parse_pedit(bp, actions, act,
|
||||||
|
(u8 *)eth_addr,
|
||||||
|
(u8 *)eth_addr_mask);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) {
|
||||||
|
rc = bnxt_fill_l2_rewrite_fields(actions, eth_addr,
|
||||||
|
eth_addr_mask);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
if (actions->flags & BNXT_TC_ACTION_FLAG_FWD) {
|
if (actions->flags & BNXT_TC_ACTION_FLAG_FWD) {
|
||||||
if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) {
|
if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) {
|
||||||
/* dst_fid is PF's fid */
|
/* dst_fid is PF's fid */
|
||||||
|
@ -401,6 +524,15 @@ static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow,
|
||||||
req.src_fid = cpu_to_le16(flow->src_fid);
|
req.src_fid = cpu_to_le16(flow->src_fid);
|
||||||
req.ref_flow_handle = ref_flow_handle;
|
req.ref_flow_handle = ref_flow_handle;
|
||||||
|
|
||||||
|
if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) {
|
||||||
|
memcpy(req.l2_rewrite_dmac, actions->l2_rewrite_dmac,
|
||||||
|
ETH_ALEN);
|
||||||
|
memcpy(req.l2_rewrite_smac, actions->l2_rewrite_smac,
|
||||||
|
ETH_ALEN);
|
||||||
|
action_flags |=
|
||||||
|
CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE;
|
||||||
|
}
|
||||||
|
|
||||||
if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP ||
|
if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP ||
|
||||||
actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) {
|
actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) {
|
||||||
req.tunnel_handle = tunnel_handle;
|
req.tunnel_handle = tunnel_handle;
|
||||||
|
|
|
@ -62,6 +62,12 @@ struct bnxt_tc_tunnel_key {
|
||||||
__be32 id;
|
__be32 id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask) \
|
||||||
|
((is_wildcard(&(eth_addr)[0], ETH_ALEN) && \
|
||||||
|
is_wildcard(&(eth_addr)[ETH_ALEN], ETH_ALEN)) || \
|
||||||
|
(is_wildcard(&(eth_addr_mask)[0], ETH_ALEN) && \
|
||||||
|
is_wildcard(&(eth_addr_mask)[ETH_ALEN], ETH_ALEN)))
|
||||||
|
|
||||||
struct bnxt_tc_actions {
|
struct bnxt_tc_actions {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
#define BNXT_TC_ACTION_FLAG_FWD BIT(0)
|
#define BNXT_TC_ACTION_FLAG_FWD BIT(0)
|
||||||
|
@ -71,6 +77,7 @@ struct bnxt_tc_actions {
|
||||||
#define BNXT_TC_ACTION_FLAG_DROP BIT(5)
|
#define BNXT_TC_ACTION_FLAG_DROP BIT(5)
|
||||||
#define BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP BIT(6)
|
#define BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP BIT(6)
|
||||||
#define BNXT_TC_ACTION_FLAG_TUNNEL_DECAP BIT(7)
|
#define BNXT_TC_ACTION_FLAG_TUNNEL_DECAP BIT(7)
|
||||||
|
#define BNXT_TC_ACTION_FLAG_L2_REWRITE BIT(8)
|
||||||
|
|
||||||
u16 dst_fid;
|
u16 dst_fid;
|
||||||
struct net_device *dst_dev;
|
struct net_device *dst_dev;
|
||||||
|
@ -79,6 +86,10 @@ struct bnxt_tc_actions {
|
||||||
|
|
||||||
/* tunnel encap */
|
/* tunnel encap */
|
||||||
struct ip_tunnel_key tun_encap_key;
|
struct ip_tunnel_key tun_encap_key;
|
||||||
|
#define PEDIT_OFFSET_SMAC_LAST_4_BYTES 0x8
|
||||||
|
__be16 l2_rewrite_dmac[3];
|
||||||
|
__be16 l2_rewrite_smac[3];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bnxt_tc_flow {
|
struct bnxt_tc_flow {
|
||||||
|
|
Loading…
Add table
Reference in a new issue