nfp: extend flower add flow offload
authorPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Thu, 29 Jun 2017 20:08:14 +0000 (22:08 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 1 Jul 2017 15:51:32 +0000 (08:51 -0700)
Extends the flower flow add function by calculating which match
fields are present in the flower offload structure and allocating
the appropriate space to describe these.

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/main.h
drivers/net/ethernet/netronome/nfp/flower/offload.c

index c10ae76..1b1888e 100644 (file)
 
 #include "../nfp_app.h"
 
+#define NFP_FLOWER_LAYER_META          BIT(0)
+#define NFP_FLOWER_LAYER_PORT          BIT(1)
+#define NFP_FLOWER_LAYER_MAC           BIT(2)
+#define NFP_FLOWER_LAYER_TP            BIT(3)
+#define NFP_FLOWER_LAYER_IPV4          BIT(4)
+#define NFP_FLOWER_LAYER_IPV6          BIT(5)
+#define NFP_FLOWER_LAYER_CT            BIT(6)
+#define NFP_FLOWER_LAYER_VXLAN         BIT(7)
+
+#define NFP_FLOWER_LAYER_ETHER         BIT(3)
+#define NFP_FLOWER_LAYER_ARP           BIT(4)
+
+/* Metadata without L2 (1W/4B)
+ * ----------------------------------------------------------------
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  key_layers   |    mask_id    |           reserved            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_meta_one {
+       u8 nfp_flow_key_layer;
+       u8 mask_id;
+       u16 reserved;
+};
+
+/* Metadata with L2 (1W/4B)
+ * ----------------------------------------------------------------
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |    key_type   |    mask_id    | PCP |p|   vlan outermost VID  |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *                                 ^                               ^
+ *                           NOTE: |             TCI               |
+ *                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_meta_two {
+       u8 nfp_flow_key_layer;
+       u8 mask_id;
+       __be16 tci;
+};
+
+/* Port details (1W/4B)
+ * ----------------------------------------------------------------
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         port_ingress                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_in_port {
+       __be32 in_port;
+};
+
+/* L2 details (4W/16B)
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     mac_addr_dst, 31 - 0                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |      mac_addr_dst, 47 - 32    |     mac_addr_src, 15 - 0      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     mac_addr_src, 47 - 16                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |       mpls outermost label            |  TC |B|   reserved  |q|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_mac_mpls {
+       u8 mac_dst[6];
+       u8 mac_src[6];
+       __be32 mpls_lse;
+};
+
+/* L4 ports (for UDP, TCP, SCTP) (1W/4B)
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            port_src           |           port_dst            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_tp_ports {
+       __be16 port_src;
+       __be16 port_dst;
+};
+
+/* L3 IPv4 details (3W/12B)
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |    DSCP   |ECN|   protocol    |           reserved            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                        ipv4_addr_src                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                        ipv4_addr_dst                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_ipv4 {
+       u8 tos;
+       u8 proto;
+       u8 ttl;
+       u8 reserved;
+       __be32 ipv4_src;
+       __be32 ipv4_dst;
+};
+
+/* L3 IPv6 details (10W/40B)
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |    DSCP   |ECN|   protocol    |          reserved             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   ipv6_exthdr   | res |            ipv6_flow_label            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_src,   31 - 0                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_src,  63 - 32                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_src,  95 - 64                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_src, 127 - 96                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_dst,   31 - 0                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_dst,  63 - 32                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_dst,  95 - 64                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                  ipv6_addr_dst, 127 - 96                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_ipv6 {
+       u8 tos;
+       u8 proto;
+       u8 ttl;
+       u8 reserved;
+       __be32 ipv6_flow_label_exthdr;
+       struct in6_addr ipv6_src;
+       struct in6_addr ipv6_dst;
+};
+
 /* The base header for a control message packet.
  * Defines an 8-bit version, and an 8-bit type, padded
  * to a 32-bit word. Rest of the packet is type-specific.
index c7a1952..ba3e14c 100644 (file)
@@ -40,6 +40,30 @@ struct tc_to_netdev;
 struct net_device;
 struct nfp_app;
 
+struct nfp_fl_key_ls {
+       u32 key_layer_two;
+       u8 key_layer;
+       int key_size;
+};
+
+struct nfp_fl_rule_metadata {
+       u8 key_len;
+       u8 mask_len;
+       u8 act_len;
+       u8 flags;
+       __be32 host_ctx_id;
+       __be64 host_cookie __packed;
+       __be64 flow_version __packed;
+       __be32 shortcut;
+};
+
+struct nfp_fl_payload {
+       struct nfp_fl_rule_metadata meta;
+       char *unmasked_data;
+       char *mask_data;
+       char *action_data;
+};
+
 int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev,
                        u32 handle, __be16 proto, struct tc_to_netdev *tc);
 #endif
index 2fe0353..fb9f73a 100644 (file)
 #include "../nfp_net.h"
 #include "../nfp_port.h"
 
+static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
+{
+       return dissector_uses_key(f->dissector,
+                                 FLOW_DISSECTOR_KEY_IPV4_ADDRS) ||
+               dissector_uses_key(f->dissector,
+                                  FLOW_DISSECTOR_KEY_IPV6_ADDRS) ||
+               dissector_uses_key(f->dissector,
+                                  FLOW_DISSECTOR_KEY_PORTS) ||
+               dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ICMP);
+}
+
+static int
+nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
+                               struct tc_cls_flower_offload *flow)
+{
+       struct flow_dissector_key_control *mask_enc_ctl;
+       struct flow_dissector_key_basic *mask_basic;
+       struct flow_dissector_key_basic *key_basic;
+       u32 key_layer_two;
+       u8 key_layer;
+       int key_size;
+
+       mask_enc_ctl = skb_flow_dissector_target(flow->dissector,
+                                                FLOW_DISSECTOR_KEY_ENC_CONTROL,
+                                                flow->mask);
+
+       mask_basic = skb_flow_dissector_target(flow->dissector,
+                                              FLOW_DISSECTOR_KEY_BASIC,
+                                              flow->mask);
+
+       key_basic = skb_flow_dissector_target(flow->dissector,
+                                             FLOW_DISSECTOR_KEY_BASIC,
+                                             flow->key);
+       key_layer_two = 0;
+       key_layer = NFP_FLOWER_LAYER_PORT | NFP_FLOWER_LAYER_MAC;
+       key_size = sizeof(struct nfp_flower_meta_one) +
+                  sizeof(struct nfp_flower_in_port) +
+                  sizeof(struct nfp_flower_mac_mpls);
+
+       /* We are expecting a tunnel. For now we ignore offloading. */
+       if (mask_enc_ctl->addr_type)
+               return -EOPNOTSUPP;
+
+       if (mask_basic->n_proto) {
+               /* Ethernet type is present in the key. */
+               switch (key_basic->n_proto) {
+               case cpu_to_be16(ETH_P_IP):
+                       key_layer |= NFP_FLOWER_LAYER_IPV4;
+                       key_size += sizeof(struct nfp_flower_ipv4);
+                       break;
+
+               case cpu_to_be16(ETH_P_IPV6):
+                       key_layer |= NFP_FLOWER_LAYER_IPV6;
+                       key_size += sizeof(struct nfp_flower_ipv6);
+                       break;
+
+               /* Currently we do not offload ARP
+                * because we rely on it to get to the host.
+                */
+               case cpu_to_be16(ETH_P_ARP):
+                       return -EOPNOTSUPP;
+
+               /* Will be included in layer 2. */
+               case cpu_to_be16(ETH_P_8021Q):
+                       break;
+
+               default:
+                       /* Other ethtype - we need check the masks for the
+                        * remainder of the key to ensure we can offload.
+                        */
+                       if (nfp_flower_check_higher_than_mac(flow))
+                               return -EOPNOTSUPP;
+                       break;
+               }
+       }
+
+       if (mask_basic->ip_proto) {
+               /* Ethernet type is present in the key. */
+               switch (key_basic->ip_proto) {
+               case IPPROTO_TCP:
+               case IPPROTO_UDP:
+               case IPPROTO_SCTP:
+               case IPPROTO_ICMP:
+               case IPPROTO_ICMPV6:
+                       key_layer |= NFP_FLOWER_LAYER_TP;
+                       key_size += sizeof(struct nfp_flower_tp_ports);
+                       break;
+               default:
+                       /* Other ip proto - we need check the masks for the
+                        * remainder of the key to ensure we can offload.
+                        */
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       ret_key_ls->key_layer = key_layer;
+       ret_key_ls->key_layer_two = key_layer_two;
+       ret_key_ls->key_size = key_size;
+
+       return 0;
+}
+
+static struct nfp_fl_payload *
+nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer)
+{
+       struct nfp_fl_payload *flow_pay;
+
+       flow_pay = kmalloc(sizeof(*flow_pay), GFP_KERNEL);
+       if (!flow_pay)
+               return NULL;
+
+       flow_pay->meta.key_len = key_layer->key_size;
+       flow_pay->unmasked_data = kmalloc(key_layer->key_size, GFP_KERNEL);
+       if (!flow_pay->unmasked_data)
+               goto err_free_flow;
+
+       flow_pay->meta.mask_len = key_layer->key_size;
+       flow_pay->mask_data = kmalloc(key_layer->key_size, GFP_KERNEL);
+       if (!flow_pay->mask_data)
+               goto err_free_unmasked;
+
+       flow_pay->meta.flags = 0;
+
+       return flow_pay;
+
+err_free_unmasked:
+       kfree(flow_pay->unmasked_data);
+err_free_flow:
+       kfree(flow_pay);
+       return NULL;
+}
+
 /**
  * nfp_flower_add_offload() - Adds a new flow to hardware.
  * @app:       Pointer to the APP handle
@@ -58,7 +190,34 @@ static int
 nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
                       struct tc_cls_flower_offload *flow)
 {
-       return -EOPNOTSUPP;
+       struct nfp_fl_payload *flow_pay;
+       struct nfp_fl_key_ls *key_layer;
+       int err;
+
+       key_layer = kmalloc(sizeof(*key_layer), GFP_KERNEL);
+       if (!key_layer)
+               return -ENOMEM;
+
+       err = nfp_flower_calculate_key_layers(key_layer, flow);
+       if (err)
+               goto err_free_key_ls;
+
+       flow_pay = nfp_flower_allocate_new(key_layer);
+       if (!flow_pay) {
+               err = -ENOMEM;
+               goto err_free_key_ls;
+       }
+
+       /* TODO: Complete flower_add_offload. */
+       err = -EOPNOTSUPP;
+
+       kfree(flow_pay->mask_data);
+       kfree(flow_pay->unmasked_data);
+       kfree(flow_pay);
+
+err_free_key_ls:
+       kfree(key_layer);
+       return err;
 }
 
 /**