nfp: bpf: add packet marking support
authorJakub Kicinski <jakub.kicinski@netronome.com>
Wed, 21 Sep 2016 10:44:04 +0000 (11:44 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 21 Sep 2016 23:50:03 +0000 (19:50 -0400)
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: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/nfp_bpf.h
drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c
drivers/net/ethernet/netronome/nfp/nfp_net.h
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c

index 3726421e353fe3291eedb706f4c60af8fcdd759f..2adb1d80c7b72a8d433dbfac87c40a1f6f42c702 100644 (file)
@@ -91,6 +91,8 @@ enum nfp_bpf_reg_type {
 #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_FLAG_MARK        1
+#define NFP_BPF_ABI_MARK       reg_nnr(1)
 #define NFP_BPF_ABI_PKT                reg_nnr(2)
 #define NFP_BPF_ABI_LEN                reg_nnr(3)
 
index cfbf53607fc9bbb4f92636ab23d319ac8d8e024b..368381f0357fd19d1fbfdd2e201874c1c478f134 100644 (file)
@@ -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);
 }
 
+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
 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)
        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)
 {
        if (meta->insn.off < 0) /* TODO */
@@ -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_W] =    data_ind_ld4,
        [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_JEQ | BPF_K] =   jeq_imm,
        [BPF_JMP | BPF_JGT | BPF_K] =   jgt_imm,
index 13c6a9001b4d46c51c63be56901c4d6adbf53989..ed824e11a1e3b5127138656dbbeaba2efcc3013b 100644 (file)
@@ -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 {
        __be32 hash_type;
        __be32 hash;
index f091eb758ca2017267dc6e17ac0b5d190bd40747..415691edcaa5fb2c5a6d9b12c04736b00c83c6cf 100644 (file)
@@ -1293,38 +1293,72 @@ 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,
-                            struct nfp_net_rx_desc *rxd)
+                            unsigned int type, __be32 *hash)
 {
-       struct nfp_net_rx_hash *rx_hash;
-
-       if (!(rxd->rxd.flags & PCIE_DESC_RX_RSS) ||
-           !(netdev->features & NETIF_F_RXHASH))
+       if (!(netdev->features & NETIF_F_RXHASH))
                return;
 
-       rx_hash = (struct nfp_net_rx_hash *)(skb->data - sizeof(*rx_hash));
-
-       switch (be32_to_cpu(rx_hash->hash_type)) {
+       switch (type) {
        case NFP_NET_RSS_IPV4:
        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);
+               skb_set_hash(skb, get_unaligned_be32(hash), PKT_HASH_TYPE_L3);
                break;
        default:
-               skb_set_hash(skb, be32_to_cpu(rx_hash->hash), PKT_HASH_TYPE_L4);
+               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_hash *rx_hash;
+
+       if (!(rxd->rxd.flags & PCIE_DESC_RX_RSS))
+               return;
+
+       rx_hash = (struct nfp_net_rx_hash *)(skb->data - sizeof(*rx_hash));
+
+       nfp_net_set_hash(netdev, skb, get_unaligned_be32(&rx_hash->hash_type),
+                        &rx_hash->hash);
+}
+
+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;
+               case NFP_NET_META_MARK:
+                       skb->mark = get_unaligned_be32(data);
+                       data += 4;
+                       break;
+               default:
+                       return NULL;
+               }
+
+               meta_info >>= NFP_NET_META_FIELD_SIZE;
+       }
+
+       return data;
+}
+
 /**
  * nfp_net_rx() - receive up to @budget packets on @rx_ring
  * @rx_ring:   RX ring to receive from
@@ -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_put(skb, data_len - meta_len);
 
-               nfp_net_set_hash(nn->netdev, skb, rxd);
-
                /* Stats update */
                u64_stats_update_begin(&r_vec->rx_sync);
                r_vec->rx_pkts++;
                r_vec->rx_bytes += skb->len;
                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->protocol = eth_type_trans(skb, nn->netdev);
 
index 7aa11f3c5ef08005fdace8644172b3ed9e096165..93b10b441acbfc98c78429d0d6cd31035e3b9c39 100644 (file)
  */
 #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
  */
index f7062cb648e1b777342797cd7fc69a767a7488e8..2800bbf65a891e14dcfc06d9a432f66c1add0640 100644 (file)
@@ -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");
        } else {
                switch (fw_ver.major) {
-               case 1 ... 3:
+               case 1 ... 4:
                        if (is_nfp3200) {
                                stride = 2;
                                tx_bar_no = NFP_NET_Q0_BAR;