net/mlx5e: Allow TC csum offload if applied together with pedit action
authorOr Gerlitz <ogerlitz@mellanox.com>
Wed, 10 May 2017 10:59:54 +0000 (13:59 +0300)
committerSaeed Mahameed <saeedm@mellanox.com>
Tue, 23 May 2017 13:23:31 +0000 (16:23 +0300)
When offloading header re-writes, the HW re-calculates the relevant L3/L4
checksums. Hence, when upper layers (as done by OVS) ask for TC checksum action
offload together with pedit offload, don't err. This command now works:

tc filter add dev ens1f0 protocol ip parent ffff: prio 20 flower skip_sw
ip_proto tcp dst_port 9001
action pedit ex munge tcp dport set 0x1234 pipe
        action csum tcp

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Reported-by: Paul Blakey <paulb@mellanox.com>
Reviewed-by: Paul Blakey <paulb@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

index a90dd26ea51cf7c474995f30af0fcc144e28c498..9dd83c7e4c51aa918239e07e607fea78d8918779 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/tc_act/tc_vlan.h>
 #include <net/tc_act/tc_tunnel_key.h>
 #include <net/tc_act/tc_pedit.h>
+#include <net/tc_act/tc_csum.h>
 #include <net/vxlan.h>
 #include <net/arp.h>
 #include "en.h"
@@ -1109,6 +1110,28 @@ out_err:
        return err;
 }
 
+static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 update_flags)
+{
+       u32 prot_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR | TCA_CSUM_UPDATE_FLAG_TCP |
+                        TCA_CSUM_UPDATE_FLAG_UDP;
+
+       /*  The HW recalcs checksums only if re-writing headers */
+       if (!(action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) {
+               netdev_warn(priv->netdev,
+                           "TC csum action is only offloaded with pedit\n");
+               return false;
+       }
+
+       if (update_flags & ~prot_flags) {
+               netdev_warn(priv->netdev,
+                           "can't offload TC csum action for some header/s - flags %#x\n",
+                           update_flags);
+               return false;
+       }
+
+       return true;
+}
+
 static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                                struct mlx5e_tc_flow_parse_attr *parse_attr,
                                struct mlx5e_tc_flow *flow)
@@ -1149,6 +1172,14 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                        continue;
                }
 
+               if (is_tcf_csum(a)) {
+                       if (csum_offload_supported(priv, attr->action,
+                                                  tcf_csum_update_flags(a)))
+                               continue;
+
+                       return -EOPNOTSUPP;
+               }
+
                if (is_tcf_skbedit_mark(a)) {
                        u32 mark = tcf_skbedit_mark(a);
 
@@ -1651,6 +1682,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                        continue;
                }
 
+               if (is_tcf_csum(a)) {
+                       if (csum_offload_supported(priv, attr->action,
+                                                  tcf_csum_update_flags(a)))
+                               continue;
+
+                       return -EOPNOTSUPP;
+               }
+
                if (is_tcf_mirred_egress_redirect(a)) {
                        int ifindex = tcf_mirred_ifindex(a);
                        struct net_device *out_dev, *encap_dev = NULL;