nfp: flower: add geneve option match offload
authorPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Tue, 7 Aug 2018 15:36:03 +0000 (17:36 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 7 Aug 2018 19:22:15 +0000 (12:22 -0700)
Introduce a new layer for matching on geneve options. This allows
offloading filters configured to match geneve with options.

Signed-off-by: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/flower/cmsg.h
drivers/net/ethernet/netronome/nfp/flower/match.c
drivers/net/ethernet/netronome/nfp/flower/offload.c

index f2aeae8..325954b 100644 (file)
@@ -52,6 +52,7 @@
 #define NFP_FLOWER_LAYER_VXLAN         BIT(7)
 
 #define NFP_FLOWER_LAYER2_GENEVE       BIT(5)
+#define NFP_FLOWER_LAYER2_GENEVE_OP    BIT(6)
 
 #define NFP_FLOWER_MASK_VLAN_PRIO      GENMASK(15, 13)
 #define NFP_FLOWER_MASK_VLAN_CFI       BIT(12)
@@ -85,6 +86,7 @@
 /* Maximum allowed geneve options */
 #define NFP_FL_MAX_GENEVE_OPT_ACT      32
 #define NFP_FL_MAX_GENEVE_OPT_CNT      64
+#define NFP_FL_MAX_GENEVE_OPT_KEY      32
 
 /* Action opcodes */
 #define NFP_FL_ACTION_OPCODE_OUTPUT            0
@@ -381,6 +383,10 @@ struct nfp_flower_ipv4_udp_tun {
        __be32 tun_id;
 };
 
+struct nfp_flower_geneve_options {
+       u8 data[NFP_FL_MAX_GENEVE_OPT_KEY];
+};
+
 #define NFP_FL_TUN_VNI_OFFSET 8
 
 /* The base header for a control message packet.
index b1cbe69..a0c72f2 100644 (file)
@@ -262,6 +262,21 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame,
        nfp_flower_compile_ip_ext(&frame->ip_ext, flow, mask_version);
 }
 
+static int
+nfp_flower_compile_geneve_opt(void *key_buf, struct tc_cls_flower_offload *flow,
+                             bool mask_version)
+{
+       struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
+       struct flow_dissector_key_enc_opts *opts;
+
+       opts = skb_flow_dissector_target(flow->dissector,
+                                        FLOW_DISSECTOR_KEY_ENC_OPTS,
+                                        target);
+       memcpy(key_buf, opts->data, opts->len);
+
+       return 0;
+}
+
 static void
 nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
                                struct tc_cls_flower_offload *flow,
@@ -424,6 +439,16 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
                        nfp_flow->nfp_tun_ipv4_addr = tun_dst;
                        nfp_tunnel_add_ipv4_off(netdev_repr->app, tun_dst);
                }
+
+               if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_GENEVE_OP) {
+                       err = nfp_flower_compile_geneve_opt(ext, flow, false);
+                       if (err)
+                               return err;
+
+                       err = nfp_flower_compile_geneve_opt(msk, flow, true);
+                       if (err)
+                               return err;
+               }
        }
 
        return 0;
index d2230a0..2edab01 100644 (file)
@@ -66,6 +66,7 @@
         BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
         BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
         BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
+        BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
         BIT(FLOW_DISSECTOR_KEY_ENC_IP) | \
         BIT(FLOW_DISSECTOR_KEY_MPLS) | \
         BIT(FLOW_DISSECTOR_KEY_IP))
@@ -75,6 +76,7 @@
         BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
         BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
         BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
+        BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
         BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
         BIT(FLOW_DISSECTOR_KEY_ENC_IP))
 
@@ -141,6 +143,21 @@ static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
 }
 
 static int
+nfp_flower_calc_opt_layer(struct flow_dissector_key_enc_opts *enc_opts,
+                         u32 *key_layer_two, int *key_size)
+{
+       if (enc_opts->len > NFP_FL_MAX_GENEVE_OPT_KEY)
+               return -EOPNOTSUPP;
+
+       if (enc_opts->len > 0) {
+               *key_layer_two |= NFP_FLOWER_LAYER2_GENEVE_OP;
+               *key_size += sizeof(struct nfp_flower_geneve_options);
+       }
+
+       return 0;
+}
+
+static int
 nfp_flower_calculate_key_layers(struct nfp_app *app,
                                struct nfp_fl_key_ls *ret_key_ls,
                                struct tc_cls_flower_offload *flow,
@@ -153,6 +170,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
        u32 key_layer_two;
        u8 key_layer;
        int key_size;
+       int err;
 
        if (flow->dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR)
                return -EOPNOTSUPP;
@@ -178,6 +196,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
                               FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
                struct flow_dissector_key_ipv4_addrs *mask_ipv4 = NULL;
                struct flow_dissector_key_ports *mask_enc_ports = NULL;
+               struct flow_dissector_key_enc_opts *enc_op = NULL;
                struct flow_dissector_key_ports *enc_ports = NULL;
                struct flow_dissector_key_control *mask_enc_ctl =
                        skb_flow_dissector_target(flow->dissector,
@@ -214,11 +233,21 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
                if (mask_enc_ports->dst != cpu_to_be16(~0))
                        return -EOPNOTSUPP;
 
+               if (dissector_uses_key(flow->dissector,
+                                      FLOW_DISSECTOR_KEY_ENC_OPTS)) {
+                       enc_op = skb_flow_dissector_target(flow->dissector,
+                                                          FLOW_DISSECTOR_KEY_ENC_OPTS,
+                                                          flow->key);
+               }
+
                switch (enc_ports->dst) {
                case htons(NFP_FL_VXLAN_PORT):
                        *tun_type = NFP_FL_TUNNEL_VXLAN;
                        key_layer |= NFP_FLOWER_LAYER_VXLAN;
                        key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+
+                       if (enc_op)
+                               return -EOPNOTSUPP;
                        break;
                case htons(NFP_FL_GENEVE_PORT):
                        if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE))
@@ -228,6 +257,15 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
                        key_size += sizeof(struct nfp_flower_ext_meta);
                        key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
                        key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+
+                       if (!enc_op)
+                               break;
+                       if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT))
+                               return -EOPNOTSUPP;
+                       err = nfp_flower_calc_opt_layer(enc_op, &key_layer_two,
+                                                       &key_size);
+                       if (err)
+                               return err;
                        break;
                default:
                        return -EOPNOTSUPP;