Commit 19d0f54e authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

nfp: bpf: add packet marking support

Add missing ABI defines and eBPF instructions to allow
mark to be passed on and extend prepend parsing on the
RX path to pick it up from packet metadata.
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 66860beb
...@@ -91,6 +91,8 @@ enum nfp_bpf_reg_type { ...@@ -91,6 +91,8 @@ enum nfp_bpf_reg_type {
#define imm_both(np) reg_both((np)->regs_per_thread - STATIC_REG_IMM) #define imm_both(np) reg_both((np)->regs_per_thread - STATIC_REG_IMM)
#define NFP_BPF_ABI_FLAGS reg_nnr(0) #define NFP_BPF_ABI_FLAGS reg_nnr(0)
#define NFP_BPF_ABI_FLAG_MARK 1
#define NFP_BPF_ABI_MARK reg_nnr(1)
#define NFP_BPF_ABI_PKT reg_nnr(2) #define NFP_BPF_ABI_PKT reg_nnr(2)
#define NFP_BPF_ABI_LEN reg_nnr(3) #define NFP_BPF_ABI_LEN reg_nnr(3)
......
...@@ -674,6 +674,16 @@ static int construct_data_ld(struct nfp_prog *nfp_prog, u16 offset, u8 size) ...@@ -674,6 +674,16 @@ static int construct_data_ld(struct nfp_prog *nfp_prog, u16 offset, u8 size)
return construct_data_ind_ld(nfp_prog, offset, 0, false, size); return construct_data_ind_ld(nfp_prog, offset, 0, false, size);
} }
static int wrp_set_mark(struct nfp_prog *nfp_prog, u8 src)
{
emit_alu(nfp_prog, NFP_BPF_ABI_MARK,
reg_none(), ALU_OP_NONE, reg_b(src));
emit_alu(nfp_prog, NFP_BPF_ABI_FLAGS,
NFP_BPF_ABI_FLAGS, ALU_OP_OR, reg_imm(NFP_BPF_ABI_FLAG_MARK));
return 0;
}
static void static void
wrp_alu_imm(struct nfp_prog *nfp_prog, u8 dst, enum alu_op alu_op, u32 imm) wrp_alu_imm(struct nfp_prog *nfp_prog, u8 dst, enum alu_op alu_op, u32 imm)
{ {
...@@ -1117,6 +1127,14 @@ static int mem_ldx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) ...@@ -1117,6 +1127,14 @@ static int mem_ldx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
return 0; return 0;
} }
static int mem_stx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
if (meta->insn.off == offsetof(struct sk_buff, mark))
return wrp_set_mark(nfp_prog, meta->insn.src_reg * 2);
return -ENOTSUPP;
}
static int jump(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) static int jump(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{ {
if (meta->insn.off < 0) /* TODO */ if (meta->insn.off < 0) /* TODO */
...@@ -1306,6 +1324,7 @@ static const instr_cb_t instr_cb[256] = { ...@@ -1306,6 +1324,7 @@ static const instr_cb_t instr_cb[256] = {
[BPF_LD | BPF_IND | BPF_H] = data_ind_ld2, [BPF_LD | BPF_IND | BPF_H] = data_ind_ld2,
[BPF_LD | BPF_IND | BPF_W] = data_ind_ld4, [BPF_LD | BPF_IND | BPF_W] = data_ind_ld4,
[BPF_LDX | BPF_MEM | BPF_W] = mem_ldx4, [BPF_LDX | BPF_MEM | BPF_W] = mem_ldx4,
[BPF_STX | BPF_MEM | BPF_W] = mem_stx4,
[BPF_JMP | BPF_JA | BPF_K] = jump, [BPF_JMP | BPF_JA | BPF_K] = jump,
[BPF_JMP | BPF_JEQ | BPF_K] = jeq_imm, [BPF_JMP | BPF_JEQ | BPF_K] = jeq_imm,
[BPF_JMP | BPF_JGT | BPF_K] = jgt_imm, [BPF_JMP | BPF_JGT | BPF_K] = jgt_imm,
......
...@@ -269,6 +269,8 @@ struct nfp_net_rx_desc { ...@@ -269,6 +269,8 @@ struct nfp_net_rx_desc {
}; };
}; };
#define NFP_NET_META_FIELD_MASK GENMASK(NFP_NET_META_FIELD_SIZE - 1, 0)
struct nfp_net_rx_hash { struct nfp_net_rx_hash {
__be32 hash_type; __be32 hash_type;
__be32 hash; __be32 hash;
......
...@@ -1293,36 +1293,70 @@ static void nfp_net_rx_csum(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, ...@@ -1293,36 +1293,70 @@ static void nfp_net_rx_csum(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
} }
} }
/**
* nfp_net_set_hash() - Set SKB hash data
* @netdev: adapter's net_device structure
* @skb: SKB to set the hash data on
* @rxd: RX descriptor
*
* The RSS hash and hash-type are pre-pended to the packet data.
* Extract and decode it and set the skb fields.
*/
static void nfp_net_set_hash(struct net_device *netdev, struct sk_buff *skb, static void nfp_net_set_hash(struct net_device *netdev, struct sk_buff *skb,
unsigned int type, __be32 *hash)
{
if (!(netdev->features & NETIF_F_RXHASH))
return;
switch (type) {
case NFP_NET_RSS_IPV4:
case NFP_NET_RSS_IPV6:
case NFP_NET_RSS_IPV6_EX:
skb_set_hash(skb, get_unaligned_be32(hash), PKT_HASH_TYPE_L3);
break;
default:
skb_set_hash(skb, get_unaligned_be32(hash), PKT_HASH_TYPE_L4);
break;
}
}
static void
nfp_net_set_hash_desc(struct net_device *netdev, struct sk_buff *skb,
struct nfp_net_rx_desc *rxd) struct nfp_net_rx_desc *rxd)
{ {
struct nfp_net_rx_hash *rx_hash; struct nfp_net_rx_hash *rx_hash;
if (!(rxd->rxd.flags & PCIE_DESC_RX_RSS) || if (!(rxd->rxd.flags & PCIE_DESC_RX_RSS))
!(netdev->features & NETIF_F_RXHASH))
return; return;
rx_hash = (struct nfp_net_rx_hash *)(skb->data - sizeof(*rx_hash)); rx_hash = (struct nfp_net_rx_hash *)(skb->data - sizeof(*rx_hash));
switch (be32_to_cpu(rx_hash->hash_type)) { nfp_net_set_hash(netdev, skb, get_unaligned_be32(&rx_hash->hash_type),
case NFP_NET_RSS_IPV4: &rx_hash->hash);
case NFP_NET_RSS_IPV6: }
case NFP_NET_RSS_IPV6_EX:
skb_set_hash(skb, be32_to_cpu(rx_hash->hash), PKT_HASH_TYPE_L3); static void *
nfp_net_parse_meta(struct net_device *netdev, struct sk_buff *skb,
int meta_len)
{
u8 *data = skb->data - meta_len;
u32 meta_info;
meta_info = get_unaligned_be32(data);
data += 4;
while (meta_info) {
switch (meta_info & NFP_NET_META_FIELD_MASK) {
case NFP_NET_META_HASH:
meta_info >>= NFP_NET_META_FIELD_SIZE;
nfp_net_set_hash(netdev, skb,
meta_info & NFP_NET_META_FIELD_MASK,
(__be32 *)data);
data += 4;
break; break;
default: case NFP_NET_META_MARK:
skb_set_hash(skb, be32_to_cpu(rx_hash->hash), PKT_HASH_TYPE_L4); skb->mark = get_unaligned_be32(data);
data += 4;
break; break;
default:
return NULL;
}
meta_info >>= NFP_NET_META_FIELD_SIZE;
} }
return data;
} }
/** /**
...@@ -1439,14 +1473,29 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) ...@@ -1439,14 +1473,29 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
skb_reserve(skb, nn->rx_offset); skb_reserve(skb, nn->rx_offset);
skb_put(skb, data_len - meta_len); skb_put(skb, data_len - meta_len);
nfp_net_set_hash(nn->netdev, skb, rxd);
/* Stats update */ /* Stats update */
u64_stats_update_begin(&r_vec->rx_sync); u64_stats_update_begin(&r_vec->rx_sync);
r_vec->rx_pkts++; r_vec->rx_pkts++;
r_vec->rx_bytes += skb->len; r_vec->rx_bytes += skb->len;
u64_stats_update_end(&r_vec->rx_sync); u64_stats_update_end(&r_vec->rx_sync);
if (nn->fw_ver.major <= 3) {
nfp_net_set_hash_desc(nn->netdev, skb, rxd);
} else if (meta_len) {
void *end;
end = nfp_net_parse_meta(nn->netdev, skb, meta_len);
if (unlikely(end != skb->data)) {
u64_stats_update_begin(&r_vec->rx_sync);
r_vec->rx_drops++;
u64_stats_update_end(&r_vec->rx_sync);
dev_kfree_skb_any(skb);
nn_warn_ratelimit(nn, "invalid RX packet metadata\n");
continue;
}
}
skb_record_rx_queue(skb, rx_ring->idx); skb_record_rx_queue(skb, rx_ring->idx);
skb->protocol = eth_type_trans(skb, nn->netdev); skb->protocol = eth_type_trans(skb, nn->netdev);
......
...@@ -65,6 +65,13 @@ ...@@ -65,6 +65,13 @@
*/ */
#define NFP_NET_LSO_MAX_HDR_SZ 255 #define NFP_NET_LSO_MAX_HDR_SZ 255
/**
* Prepend field types
*/
#define NFP_NET_META_FIELD_SIZE 4
#define NFP_NET_META_HASH 1 /* next field carries hash type */
#define NFP_NET_META_MARK 2
/** /**
* Hash type pre-pended when a RSS hash was computed * Hash type pre-pended when a RSS hash was computed
*/ */
......
...@@ -148,7 +148,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, ...@@ -148,7 +148,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
dev_warn(&pdev->dev, "OBSOLETE Firmware detected - VF isolation not available\n"); dev_warn(&pdev->dev, "OBSOLETE Firmware detected - VF isolation not available\n");
} else { } else {
switch (fw_ver.major) { switch (fw_ver.major) {
case 1 ... 3: case 1 ... 4:
if (is_nfp3200) { if (is_nfp3200) {
stride = 2; stride = 2;
tx_bar_no = NFP_NET_Q0_BAR; tx_bar_no = NFP_NET_Q0_BAR;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment