net/mlx5e: Use short attribute form when adding/deleting offloaded TC flows
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index ec63158ab64330c939ffa4ca8c001f8134f8e4e2..a9feddc31667ca5f6821dc615cc8519a199b923b 100644 (file)
@@ -177,6 +177,7 @@ err_create_mod_hdr_id:
 static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
                                  struct mlx5e_tc_flow *flow)
 {
+       struct mlx5_nic_flow_attr *attr = flow->nic_attr;
        struct mlx5_fc *counter = NULL;
 
        counter = mlx5_flow_rule_counter(flow->rule);
@@ -188,9 +189,9 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
                priv->fs.tc.t = NULL;
        }
 
-       if (flow->nic_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
                mlx5_modify_header_dealloc(priv->mdev,
-                                          flow->nic_attr->mod_hdr_id);
+                                          attr->mod_hdr_id);
 }
 
 static void mlx5e_detach_encap(struct mlx5e_priv *priv,
@@ -231,7 +232,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
        return rule;
 
 err_add_rule:
-       if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
                mlx5_modify_header_dealloc(priv->mdev,
                                           attr->mod_hdr_id);
 err_mod_hdr:
@@ -250,17 +251,17 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
 
        if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
                flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
-               mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr);
+               mlx5_eswitch_del_offloaded_rule(esw, flow->rule, attr);
        }
 
-       mlx5_eswitch_del_vlan_action(esw, flow->esw_attr);
+       mlx5_eswitch_del_vlan_action(esw, attr);
 
-       if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) {
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) {
                mlx5e_detach_encap(priv, flow);
-               kvfree(flow->esw_attr->parse_attr);
+               kvfree(attr->parse_attr);
        }
 
-       if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
                mlx5_modify_header_dealloc(priv->mdev,
                                           attr->mod_hdr_id);
 }
@@ -581,7 +582,9 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
              BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
              BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
              BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) |
-             BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL))) {
+             BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
+             BIT(FLOW_DISSECTOR_KEY_TCP) |
+             BIT(FLOW_DISSECTOR_KEY_IP))) {
                netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
                            f->dissector->used_keys);
                return -EOPNOTSUPP;
@@ -808,6 +811,48 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
                        *min_inline = MLX5_INLINE_MODE_TCP_UDP;
        }
 
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP)) {
+               struct flow_dissector_key_ip *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IP,
+                                                 f->key);
+               struct flow_dissector_key_ip *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IP,
+                                                 f->mask);
+
+               MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn, mask->tos & 0x3);
+               MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, key->tos & 0x3);
+
+               MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2);
+               MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos  >> 2);
+
+               if (mask->tos)
+                       *min_inline = MLX5_INLINE_MODE_IP;
+
+               if (mask->ttl) /* currently not supported */
+                       return -EOPNOTSUPP;
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) {
+               struct flow_dissector_key_tcp *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_TCP,
+                                                 f->key);
+               struct flow_dissector_key_tcp *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_TCP,
+                                                 f->mask);
+
+               MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_flags,
+                        ntohs(mask->flags));
+               MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
+                        ntohs(key->flags));
+
+               if (mask->flags)
+                       *min_inline = MLX5_INLINE_MODE_TCP_UDP;
+       }
+
        return 0;
 }
 
@@ -1150,10 +1195,6 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
 
        tcf_exts_to_list(exts, &actions);
        list_for_each_entry(a, &actions, list) {
-               /* Only support a single action per rule */
-               if (attr->action)
-                       return -EINVAL;
-
                if (is_tcf_gact_shot(a)) {
                        attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
                        if (MLX5_CAP_FLOWTABLE(priv->mdev,
@@ -1436,8 +1477,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
 
        if (!(nud_state & NUD_VALID)) {
                neigh_event_send(n, NULL);
-               neigh_release(n);
-               return -EAGAIN;
+               err = -EAGAIN;
+               goto out;
        }
 
        err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
@@ -1542,8 +1583,8 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
 
        if (!(nud_state & NUD_VALID)) {
                neigh_event_send(n, NULL);
-               neigh_release(n);
-               return -EAGAIN;
+               err = -EAGAIN;
+               goto out;
        }
 
        err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
@@ -1778,7 +1819,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
        }
 
        flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL);
-       parse_attr = mlx5_vzalloc(sizeof(*parse_attr));
+       parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL);
        if (!parse_attr || !flow) {
                err = -ENOMEM;
                goto err_free;
@@ -1863,9 +1904,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
 {
        struct mlx5e_tc_table *tc = &priv->fs.tc;
        struct mlx5e_tc_flow *flow;
-       struct tc_action *a;
        struct mlx5_fc *counter;
-       LIST_HEAD(actions);
        u64 bytes;
        u64 packets;
        u64 lastuse;
@@ -1884,13 +1923,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
 
        mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
 
-       preempt_disable();
-
-       tcf_exts_to_list(f->exts, &actions);
-       list_for_each_entry(a, &actions, list)
-               tcf_action_stats_update(a, bytes, packets, lastuse);
-
-       preempt_enable();
+       tcf_exts_stats_update(f->exts, bytes, packets, lastuse);
 
        return 0;
 }