Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
[sfrench/cifs-2.6.git] / drivers / net / ethernet / netronome / nfp / flower / offload.c
index 553f94f55dce64ba9cdb661ff9bdb04faf41acac..eb5c13dea8f59234a31a105d84d7a55f390427a0 100644 (file)
@@ -130,12 +130,15 @@ static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
 }
 
 static int
-nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
+nfp_flower_calculate_key_layers(struct nfp_app *app,
+                               struct nfp_fl_key_ls *ret_key_ls,
                                struct tc_cls_flower_offload *flow,
-                               bool egress)
+                               bool egress,
+                               enum nfp_flower_tun_type *tun_type)
 {
        struct flow_dissector_key_basic *mask_basic = NULL;
        struct flow_dissector_key_basic *key_basic = NULL;
+       struct nfp_flower_priv *priv = app->priv;
        u32 key_layer_two;
        u8 key_layer;
        int key_size;
@@ -150,10 +153,15 @@ nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
                return -EOPNOTSUPP;
 
        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);
+       key_layer = NFP_FLOWER_LAYER_PORT;
+       key_size = sizeof(struct nfp_flower_meta_tci) +
+                  sizeof(struct nfp_flower_in_port);
+
+       if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS) ||
+           dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_MPLS)) {
+               key_layer |= NFP_FLOWER_LAYER_MAC;
+               key_size += sizeof(struct nfp_flower_mac_mpls);
+       }
 
        if (dissector_uses_key(flow->dissector,
                               FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
@@ -192,12 +200,27 @@ nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
                                                  FLOW_DISSECTOR_KEY_ENC_PORTS,
                                                  flow->key);
 
-               if (mask_enc_ports->dst != cpu_to_be16(~0) ||
-                   enc_ports->dst != htons(NFP_FL_VXLAN_PORT))
+               if (mask_enc_ports->dst != cpu_to_be16(~0))
                        return -EOPNOTSUPP;
 
-               key_layer |= NFP_FLOWER_LAYER_VXLAN;
-               key_size += sizeof(struct nfp_flower_vxlan);
+               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);
+                       break;
+               case htons(NFP_FL_GENEVE_PORT):
+                       if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE))
+                               return -EOPNOTSUPP;
+                       *tun_type = NFP_FL_TUNNEL_GENEVE;
+                       key_layer |= NFP_FLOWER_LAYER_EXT_META;
+                       key_size += sizeof(struct nfp_flower_ext_meta);
+                       key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
+                       key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
        } else if (egress) {
                /* Reject non tunnel matches offloaded to egress repr. */
                return -EOPNOTSUPP;
@@ -325,6 +348,8 @@ static int
 nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
                       struct tc_cls_flower_offload *flow, bool egress)
 {
+       enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE;
+       struct nfp_port *port = nfp_port_from_netdev(netdev);
        struct nfp_flower_priv *priv = app->priv;
        struct nfp_fl_payload *flow_pay;
        struct nfp_fl_key_ls *key_layer;
@@ -334,7 +359,8 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
        if (!key_layer)
                return -ENOMEM;
 
-       err = nfp_flower_calculate_key_layers(key_layer, flow, egress);
+       err = nfp_flower_calculate_key_layers(app, key_layer, flow, egress,
+                                             &tun_type);
        if (err)
                goto err_free_key_ls;
 
@@ -344,7 +370,8 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
                goto err_free_key_ls;
        }
 
-       err = nfp_flower_compile_flow_match(flow, key_layer, netdev, flow_pay);
+       err = nfp_flower_compile_flow_match(flow, key_layer, netdev, flow_pay,
+                                           tun_type);
        if (err)
                goto err_destroy_flow;
 
@@ -364,6 +391,7 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
        INIT_HLIST_NODE(&flow_pay->link);
        flow_pay->tc_flower_cookie = flow->cookie;
        hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie);
+       port->tc_offload_cnt++;
 
        /* Deallocate flow payload when flower rule has been destroyed. */
        kfree(key_layer);
@@ -395,6 +423,7 @@ static int
 nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
                       struct tc_cls_flower_offload *flow)
 {
+       struct nfp_port *port = nfp_port_from_netdev(netdev);
        struct nfp_fl_payload *nfp_flow;
        int err;
 
@@ -416,6 +445,7 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
 
 err_free_flow:
        hash_del_rcu(&nfp_flow->link);
+       port->tc_offload_cnt--;
        kfree(nfp_flow->action_data);
        kfree(nfp_flow->mask_data);
        kfree(nfp_flow->unmasked_data);
@@ -457,8 +487,7 @@ static int
 nfp_flower_repr_offload(struct nfp_app *app, struct net_device *netdev,
                        struct tc_cls_flower_offload *flower, bool egress)
 {
-       if (!eth_proto_is_802_3(flower->common.protocol) ||
-           flower->common.chain_index)
+       if (!eth_proto_is_802_3(flower->common.protocol))
                return -EOPNOTSUPP;
 
        switch (flower->command) {
@@ -478,7 +507,7 @@ int nfp_flower_setup_tc_egress_cb(enum tc_setup_type type, void *type_data,
 {
        struct nfp_repr *repr = cb_priv;
 
-       if (!tc_can_offload(repr->netdev))
+       if (!tc_cls_can_offload_and_chain0(repr->netdev, type_data))
                return -EOPNOTSUPP;
 
        switch (type) {
@@ -495,7 +524,7 @@ static int nfp_flower_setup_tc_block_cb(enum tc_setup_type type,
 {
        struct nfp_repr *repr = cb_priv;
 
-       if (!tc_can_offload(repr->netdev))
+       if (!tc_cls_can_offload_and_chain0(repr->netdev, type_data))
                return -EOPNOTSUPP;
 
        switch (type) {