1e8f887acSAmir Vadai /* 2e8f887acSAmir Vadai * Copyright (c) 2016, Mellanox Technologies. All rights reserved. 3e8f887acSAmir Vadai * 4e8f887acSAmir Vadai * This software is available to you under a choice of one of two 5e8f887acSAmir Vadai * licenses. You may choose to be licensed under the terms of the GNU 6e8f887acSAmir Vadai * General Public License (GPL) Version 2, available from the file 7e8f887acSAmir Vadai * COPYING in the main directory of this source tree, or the 8e8f887acSAmir Vadai * OpenIB.org BSD license below: 9e8f887acSAmir Vadai * 10e8f887acSAmir Vadai * Redistribution and use in source and binary forms, with or 11e8f887acSAmir Vadai * without modification, are permitted provided that the following 12e8f887acSAmir Vadai * conditions are met: 13e8f887acSAmir Vadai * 14e8f887acSAmir Vadai * - Redistributions of source code must retain the above 15e8f887acSAmir Vadai * copyright notice, this list of conditions and the following 16e8f887acSAmir Vadai * disclaimer. 17e8f887acSAmir Vadai * 18e8f887acSAmir Vadai * - Redistributions in binary form must reproduce the above 19e8f887acSAmir Vadai * copyright notice, this list of conditions and the following 20e8f887acSAmir Vadai * disclaimer in the documentation and/or other materials 21e8f887acSAmir Vadai * provided with the distribution. 22e8f887acSAmir Vadai * 23e8f887acSAmir Vadai * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24e8f887acSAmir Vadai * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25e8f887acSAmir Vadai * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26e8f887acSAmir Vadai * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27e8f887acSAmir Vadai * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28e8f887acSAmir Vadai * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29e8f887acSAmir Vadai * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30e8f887acSAmir Vadai * SOFTWARE. 31e8f887acSAmir Vadai */ 32e8f887acSAmir Vadai 33e3a2b7edSAmir Vadai #include <net/flow_dissector.h> 343f7d0eb4SOr Gerlitz #include <net/sch_generic.h> 35e3a2b7edSAmir Vadai #include <net/pkt_cls.h> 36e3a2b7edSAmir Vadai #include <net/tc_act/tc_gact.h> 3712185a9fSAmir Vadai #include <net/tc_act/tc_skbedit.h> 38e8f887acSAmir Vadai #include <linux/mlx5/fs.h> 39e8f887acSAmir Vadai #include <linux/mlx5/device.h> 40e8f887acSAmir Vadai #include <linux/rhashtable.h> 4103a9d11eSOr Gerlitz #include <net/switchdev.h> 4203a9d11eSOr Gerlitz #include <net/tc_act/tc_mirred.h> 43776b12b6SOr Gerlitz #include <net/tc_act/tc_vlan.h> 44bbd00f7eSHadar Hen Zion #include <net/tc_act/tc_tunnel_key.h> 45d79b6df6SOr Gerlitz #include <net/tc_act/tc_pedit.h> 46a54e20b4SHadar Hen Zion #include <net/vxlan.h> 47e8f887acSAmir Vadai #include "en.h" 48e8f887acSAmir Vadai #include "en_tc.h" 491d447a39SSaeed Mahameed #include "en_rep.h" 5003a9d11eSOr Gerlitz #include "eswitch.h" 51bbd00f7eSHadar Hen Zion #include "vxlan.h" 52e8f887acSAmir Vadai 533bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr { 543bc4b7bfSOr Gerlitz u32 action; 553bc4b7bfSOr Gerlitz u32 flow_tag; 562f4fe4caSOr Gerlitz u32 mod_hdr_id; 573bc4b7bfSOr Gerlitz }; 583bc4b7bfSOr Gerlitz 5965ba8fb7SOr Gerlitz enum { 6065ba8fb7SOr Gerlitz MLX5E_TC_FLOW_ESWITCH = BIT(0), 613bc4b7bfSOr Gerlitz MLX5E_TC_FLOW_NIC = BIT(1), 620b67a38fSHadar Hen Zion MLX5E_TC_FLOW_OFFLOADED = BIT(2), 6365ba8fb7SOr Gerlitz }; 6465ba8fb7SOr Gerlitz 65e8f887acSAmir Vadai struct mlx5e_tc_flow { 66e8f887acSAmir Vadai struct rhash_head node; 67e8f887acSAmir Vadai u64 cookie; 6865ba8fb7SOr Gerlitz u8 flags; 6974491de9SMark Bloch struct mlx5_flow_handle *rule; 70a54e20b4SHadar Hen Zion struct list_head encap; /* flows sharing the same encap */ 713bc4b7bfSOr Gerlitz union { 72ecf5bb79SOr Gerlitz struct mlx5_esw_flow_attr esw_attr[0]; 733bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr nic_attr[0]; 743bc4b7bfSOr Gerlitz }; 75e8f887acSAmir Vadai }; 76e8f887acSAmir Vadai 7717091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr { 7817091853SOr Gerlitz struct mlx5_flow_spec spec; 79d79b6df6SOr Gerlitz int num_mod_hdr_actions; 80d79b6df6SOr Gerlitz void *mod_hdr_actions; 8117091853SOr Gerlitz }; 8217091853SOr Gerlitz 83a54e20b4SHadar Hen Zion enum { 84a54e20b4SHadar Hen Zion MLX5_HEADER_TYPE_VXLAN = 0x0, 85a54e20b4SHadar Hen Zion MLX5_HEADER_TYPE_NVGRE = 0x1, 86a54e20b4SHadar Hen Zion }; 87a54e20b4SHadar Hen Zion 88acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_ENTRIES 1024 89acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_GROUPS 4 90e8f887acSAmir Vadai 9174491de9SMark Bloch static struct mlx5_flow_handle * 9274491de9SMark Bloch mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, 9317091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 94aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow) 95e8f887acSAmir Vadai { 96aa0cbbaeSOr Gerlitz struct mlx5_nic_flow_attr *attr = flow->nic_attr; 97aad7e08dSAmir Vadai struct mlx5_core_dev *dev = priv->mdev; 98aa0cbbaeSOr Gerlitz struct mlx5_flow_destination dest = {}; 9966958ed9SHadar Hen Zion struct mlx5_flow_act flow_act = { 1003bc4b7bfSOr Gerlitz .action = attr->action, 1013bc4b7bfSOr Gerlitz .flow_tag = attr->flow_tag, 10266958ed9SHadar Hen Zion .encap_id = 0, 10366958ed9SHadar Hen Zion }; 104aad7e08dSAmir Vadai struct mlx5_fc *counter = NULL; 10574491de9SMark Bloch struct mlx5_flow_handle *rule; 106e8f887acSAmir Vadai bool table_created = false; 1072f4fe4caSOr Gerlitz int err; 108e8f887acSAmir Vadai 1093bc4b7bfSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 110aad7e08dSAmir Vadai dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 111aad7e08dSAmir Vadai dest.ft = priv->fs.vlan.ft.t; 1123bc4b7bfSOr Gerlitz } else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 113aad7e08dSAmir Vadai counter = mlx5_fc_create(dev, true); 114aad7e08dSAmir Vadai if (IS_ERR(counter)) 115aad7e08dSAmir Vadai return ERR_CAST(counter); 116aad7e08dSAmir Vadai 117aad7e08dSAmir Vadai dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 118aad7e08dSAmir Vadai dest.counter = counter; 119aad7e08dSAmir Vadai } 120aad7e08dSAmir Vadai 1212f4fe4caSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { 1222f4fe4caSOr Gerlitz err = mlx5_modify_header_alloc(dev, MLX5_FLOW_NAMESPACE_KERNEL, 1232f4fe4caSOr Gerlitz parse_attr->num_mod_hdr_actions, 1242f4fe4caSOr Gerlitz parse_attr->mod_hdr_actions, 1252f4fe4caSOr Gerlitz &attr->mod_hdr_id); 126d7e75a32SOr Gerlitz flow_act.modify_id = attr->mod_hdr_id; 1272f4fe4caSOr Gerlitz kfree(parse_attr->mod_hdr_actions); 1282f4fe4caSOr Gerlitz if (err) { 1292f4fe4caSOr Gerlitz rule = ERR_PTR(err); 1302f4fe4caSOr Gerlitz goto err_create_mod_hdr_id; 1312f4fe4caSOr Gerlitz } 1322f4fe4caSOr Gerlitz } 1332f4fe4caSOr Gerlitz 134acff797cSMaor Gottlieb if (IS_ERR_OR_NULL(priv->fs.tc.t)) { 135acff797cSMaor Gottlieb priv->fs.tc.t = 136acff797cSMaor Gottlieb mlx5_create_auto_grouped_flow_table(priv->fs.ns, 137acff797cSMaor Gottlieb MLX5E_TC_PRIO, 138acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_ENTRIES, 139acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_GROUPS, 140c9f1b073SHadar Hen Zion 0, 0); 141acff797cSMaor Gottlieb if (IS_ERR(priv->fs.tc.t)) { 142e8f887acSAmir Vadai netdev_err(priv->netdev, 143e8f887acSAmir Vadai "Failed to create tc offload table\n"); 144aad7e08dSAmir Vadai rule = ERR_CAST(priv->fs.tc.t); 145aad7e08dSAmir Vadai goto err_create_ft; 146e8f887acSAmir Vadai } 147e8f887acSAmir Vadai 148e8f887acSAmir Vadai table_created = true; 149e8f887acSAmir Vadai } 150e8f887acSAmir Vadai 15117091853SOr Gerlitz parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 15217091853SOr Gerlitz rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec, 15317091853SOr Gerlitz &flow_act, &dest, 1); 154e8f887acSAmir Vadai 155aad7e08dSAmir Vadai if (IS_ERR(rule)) 156aad7e08dSAmir Vadai goto err_add_rule; 157aad7e08dSAmir Vadai 158aad7e08dSAmir Vadai return rule; 159aad7e08dSAmir Vadai 160aad7e08dSAmir Vadai err_add_rule: 161aad7e08dSAmir Vadai if (table_created) { 162acff797cSMaor Gottlieb mlx5_destroy_flow_table(priv->fs.tc.t); 163acff797cSMaor Gottlieb priv->fs.tc.t = NULL; 164e8f887acSAmir Vadai } 165aad7e08dSAmir Vadai err_create_ft: 1662f4fe4caSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 1672f4fe4caSOr Gerlitz mlx5_modify_header_dealloc(priv->mdev, 1682f4fe4caSOr Gerlitz attr->mod_hdr_id); 1692f4fe4caSOr Gerlitz err_create_mod_hdr_id: 170aad7e08dSAmir Vadai mlx5_fc_destroy(dev, counter); 171e8f887acSAmir Vadai 172e8f887acSAmir Vadai return rule; 173e8f887acSAmir Vadai } 174e8f887acSAmir Vadai 175d85cdccbSOr Gerlitz static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, 176d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 177d85cdccbSOr Gerlitz { 178d85cdccbSOr Gerlitz struct mlx5_fc *counter = NULL; 179d85cdccbSOr Gerlitz 180d85cdccbSOr Gerlitz counter = mlx5_flow_rule_counter(flow->rule); 181d85cdccbSOr Gerlitz mlx5_del_flow_rules(flow->rule); 182d85cdccbSOr Gerlitz mlx5_fc_destroy(priv->mdev, counter); 183d85cdccbSOr Gerlitz 184d85cdccbSOr Gerlitz if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) { 185d85cdccbSOr Gerlitz mlx5_destroy_flow_table(priv->fs.tc.t); 186d85cdccbSOr Gerlitz priv->fs.tc.t = NULL; 187d85cdccbSOr Gerlitz } 1882f4fe4caSOr Gerlitz 1892f4fe4caSOr Gerlitz if (flow->nic_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 1902f4fe4caSOr Gerlitz mlx5_modify_header_dealloc(priv->mdev, 1912f4fe4caSOr Gerlitz flow->nic_attr->mod_hdr_id); 192d85cdccbSOr Gerlitz } 193d85cdccbSOr Gerlitz 194aa0cbbaeSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv, 195aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow); 196aa0cbbaeSOr Gerlitz 19774491de9SMark Bloch static struct mlx5_flow_handle * 19874491de9SMark Bloch mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, 19917091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 200aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow) 201adb4c123SOr Gerlitz { 202adb4c123SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 203aa0cbbaeSOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 204aa0cbbaeSOr Gerlitz struct mlx5_flow_handle *rule; 2058b32580dSOr Gerlitz int err; 2068b32580dSOr Gerlitz 2078b32580dSOr Gerlitz err = mlx5_eswitch_add_vlan_action(esw, attr); 208aa0cbbaeSOr Gerlitz if (err) { 209aa0cbbaeSOr Gerlitz rule = ERR_PTR(err); 210aa0cbbaeSOr Gerlitz goto err_add_vlan; 211adb4c123SOr Gerlitz } 212adb4c123SOr Gerlitz 213d7e75a32SOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { 214d7e75a32SOr Gerlitz err = mlx5_modify_header_alloc(priv->mdev, MLX5_FLOW_NAMESPACE_FDB, 215d7e75a32SOr Gerlitz parse_attr->num_mod_hdr_actions, 216d7e75a32SOr Gerlitz parse_attr->mod_hdr_actions, 217d7e75a32SOr Gerlitz &attr->mod_hdr_id); 218d7e75a32SOr Gerlitz kfree(parse_attr->mod_hdr_actions); 219d7e75a32SOr Gerlitz if (err) { 220d7e75a32SOr Gerlitz rule = ERR_PTR(err); 221d7e75a32SOr Gerlitz goto err_mod_hdr; 222d7e75a32SOr Gerlitz } 223d7e75a32SOr Gerlitz } 224d7e75a32SOr Gerlitz 225aa0cbbaeSOr Gerlitz rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); 226aa0cbbaeSOr Gerlitz if (IS_ERR(rule)) 227aa0cbbaeSOr Gerlitz goto err_add_rule; 228aa0cbbaeSOr Gerlitz 229aa0cbbaeSOr Gerlitz return rule; 230aa0cbbaeSOr Gerlitz 231aa0cbbaeSOr Gerlitz err_add_rule: 232d7e75a32SOr Gerlitz if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 233d7e75a32SOr Gerlitz mlx5_modify_header_dealloc(priv->mdev, 234d7e75a32SOr Gerlitz attr->mod_hdr_id); 235d7e75a32SOr Gerlitz err_mod_hdr: 236aa0cbbaeSOr Gerlitz mlx5_eswitch_del_vlan_action(esw, attr); 237aa0cbbaeSOr Gerlitz err_add_vlan: 238aa0cbbaeSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) 239aa0cbbaeSOr Gerlitz mlx5e_detach_encap(priv, flow); 240aa0cbbaeSOr Gerlitz return rule; 241aa0cbbaeSOr Gerlitz } 242d85cdccbSOr Gerlitz 243d85cdccbSOr Gerlitz static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, 244d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 245d85cdccbSOr Gerlitz { 246d85cdccbSOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 247d7e75a32SOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 248d85cdccbSOr Gerlitz 2490b67a38fSHadar Hen Zion if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) 250ecf5bb79SOr Gerlitz mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr); 251d85cdccbSOr Gerlitz 252ecf5bb79SOr Gerlitz mlx5_eswitch_del_vlan_action(esw, flow->esw_attr); 253d85cdccbSOr Gerlitz 254ecf5bb79SOr Gerlitz if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) 255d85cdccbSOr Gerlitz mlx5e_detach_encap(priv, flow); 256d7e75a32SOr Gerlitz 257d7e75a32SOr Gerlitz if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 258d7e75a32SOr Gerlitz mlx5_modify_header_dealloc(priv->mdev, 259d7e75a32SOr Gerlitz attr->mod_hdr_id); 260d85cdccbSOr Gerlitz } 261d85cdccbSOr Gerlitz 262d85cdccbSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv, 263d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 264d85cdccbSOr Gerlitz { 2655067b602SRoi Dayan struct list_head *next = flow->encap.next; 2665067b602SRoi Dayan 2675067b602SRoi Dayan list_del(&flow->encap); 2685067b602SRoi Dayan if (list_empty(next)) { 269c1ae1152SOr Gerlitz struct mlx5e_encap_entry *e; 2705067b602SRoi Dayan 271c1ae1152SOr Gerlitz e = list_entry(next, struct mlx5e_encap_entry, flows); 2725067b602SRoi Dayan if (e->n) { 2735067b602SRoi Dayan mlx5_encap_dealloc(priv->mdev, e->encap_id); 2745067b602SRoi Dayan neigh_release(e->n); 2755067b602SRoi Dayan } 2765067b602SRoi Dayan hlist_del_rcu(&e->encap_hlist); 2775067b602SRoi Dayan kfree(e); 2785067b602SRoi Dayan } 2795067b602SRoi Dayan } 2805067b602SRoi Dayan 281e8f887acSAmir Vadai static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, 282961e8979SRoi Dayan struct mlx5e_tc_flow *flow) 283e8f887acSAmir Vadai { 284d85cdccbSOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) 285d85cdccbSOr Gerlitz mlx5e_tc_del_fdb_flow(priv, flow); 286d85cdccbSOr Gerlitz else 287d85cdccbSOr Gerlitz mlx5e_tc_del_nic_flow(priv, flow); 288e8f887acSAmir Vadai } 289e8f887acSAmir Vadai 290bbd00f7eSHadar Hen Zion static void parse_vxlan_attr(struct mlx5_flow_spec *spec, 291bbd00f7eSHadar Hen Zion struct tc_cls_flower_offload *f) 292bbd00f7eSHadar Hen Zion { 293bbd00f7eSHadar Hen Zion void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 294bbd00f7eSHadar Hen Zion outer_headers); 295bbd00f7eSHadar Hen Zion void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 296bbd00f7eSHadar Hen Zion outer_headers); 297bbd00f7eSHadar Hen Zion void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 298bbd00f7eSHadar Hen Zion misc_parameters); 299bbd00f7eSHadar Hen Zion void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 300bbd00f7eSHadar Hen Zion misc_parameters); 301bbd00f7eSHadar Hen Zion 302bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol); 303bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP); 304bbd00f7eSHadar Hen Zion 305bbd00f7eSHadar Hen Zion if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) { 306bbd00f7eSHadar Hen Zion struct flow_dissector_key_keyid *key = 307bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 308bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, 309bbd00f7eSHadar Hen Zion f->key); 310bbd00f7eSHadar Hen Zion struct flow_dissector_key_keyid *mask = 311bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 312bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, 313bbd00f7eSHadar Hen Zion f->mask); 314bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni, 315bbd00f7eSHadar Hen Zion be32_to_cpu(mask->keyid)); 316bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni, 317bbd00f7eSHadar Hen Zion be32_to_cpu(key->keyid)); 318bbd00f7eSHadar Hen Zion } 319bbd00f7eSHadar Hen Zion } 320bbd00f7eSHadar Hen Zion 321bbd00f7eSHadar Hen Zion static int parse_tunnel_attr(struct mlx5e_priv *priv, 322bbd00f7eSHadar Hen Zion struct mlx5_flow_spec *spec, 323bbd00f7eSHadar Hen Zion struct tc_cls_flower_offload *f) 324bbd00f7eSHadar Hen Zion { 325bbd00f7eSHadar Hen Zion void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 326bbd00f7eSHadar Hen Zion outer_headers); 327bbd00f7eSHadar Hen Zion void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 328bbd00f7eSHadar Hen Zion outer_headers); 329bbd00f7eSHadar Hen Zion 3302e72eb43SOr Gerlitz struct flow_dissector_key_control *enc_control = 3312e72eb43SOr Gerlitz skb_flow_dissector_target(f->dissector, 3322e72eb43SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_CONTROL, 3332e72eb43SOr Gerlitz f->key); 3342e72eb43SOr Gerlitz 335bbd00f7eSHadar Hen Zion if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) { 336bbd00f7eSHadar Hen Zion struct flow_dissector_key_ports *key = 337bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 338bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, 339bbd00f7eSHadar Hen Zion f->key); 340bbd00f7eSHadar Hen Zion struct flow_dissector_key_ports *mask = 341bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 342bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, 343bbd00f7eSHadar Hen Zion f->mask); 3441ad9a00aSPaul Blakey struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 3451ad9a00aSPaul Blakey struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw); 3461ad9a00aSPaul Blakey struct mlx5e_priv *up_priv = netdev_priv(up_dev); 347bbd00f7eSHadar Hen Zion 348bbd00f7eSHadar Hen Zion /* Full udp dst port must be given */ 349bbd00f7eSHadar Hen Zion if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst))) 3502fcd82e9SOr Gerlitz goto vxlan_match_offload_err; 351bbd00f7eSHadar Hen Zion 3521ad9a00aSPaul Blakey if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->dst)) && 353bbd00f7eSHadar Hen Zion MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) 354bbd00f7eSHadar Hen Zion parse_vxlan_attr(spec, f); 3552fcd82e9SOr Gerlitz else { 3562fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 3572fcd82e9SOr Gerlitz "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst)); 358bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 3592fcd82e9SOr Gerlitz } 360bbd00f7eSHadar Hen Zion 361bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 362bbd00f7eSHadar Hen Zion udp_dport, ntohs(mask->dst)); 363bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 364bbd00f7eSHadar Hen Zion udp_dport, ntohs(key->dst)); 365bbd00f7eSHadar Hen Zion 366cd377663SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, 367cd377663SOr Gerlitz udp_sport, ntohs(mask->src)); 368cd377663SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, 369cd377663SOr Gerlitz udp_sport, ntohs(key->src)); 370bbd00f7eSHadar Hen Zion } else { /* udp dst port must be given */ 3712fcd82e9SOr Gerlitz vxlan_match_offload_err: 3722fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 3732fcd82e9SOr Gerlitz "IP tunnel decap offload supported only for vxlan, must set UDP dport\n"); 374bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 375bbd00f7eSHadar Hen Zion } 376bbd00f7eSHadar Hen Zion 3772e72eb43SOr Gerlitz if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 378bbd00f7eSHadar Hen Zion struct flow_dissector_key_ipv4_addrs *key = 379bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 380bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, 381bbd00f7eSHadar Hen Zion f->key); 382bbd00f7eSHadar Hen Zion struct flow_dissector_key_ipv4_addrs *mask = 383bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 384bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, 385bbd00f7eSHadar Hen Zion f->mask); 386bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 387bbd00f7eSHadar Hen Zion src_ipv4_src_ipv6.ipv4_layout.ipv4, 388bbd00f7eSHadar Hen Zion ntohl(mask->src)); 389bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 390bbd00f7eSHadar Hen Zion src_ipv4_src_ipv6.ipv4_layout.ipv4, 391bbd00f7eSHadar Hen Zion ntohl(key->src)); 392bbd00f7eSHadar Hen Zion 393bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 394bbd00f7eSHadar Hen Zion dst_ipv4_dst_ipv6.ipv4_layout.ipv4, 395bbd00f7eSHadar Hen Zion ntohl(mask->dst)); 396bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 397bbd00f7eSHadar Hen Zion dst_ipv4_dst_ipv6.ipv4_layout.ipv4, 398bbd00f7eSHadar Hen Zion ntohl(key->dst)); 399bbd00f7eSHadar Hen Zion 400bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); 401bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP); 40219f44401SOr Gerlitz } else if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 40319f44401SOr Gerlitz struct flow_dissector_key_ipv6_addrs *key = 40419f44401SOr Gerlitz skb_flow_dissector_target(f->dissector, 40519f44401SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, 40619f44401SOr Gerlitz f->key); 40719f44401SOr Gerlitz struct flow_dissector_key_ipv6_addrs *mask = 40819f44401SOr Gerlitz skb_flow_dissector_target(f->dissector, 40919f44401SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, 41019f44401SOr Gerlitz f->mask); 41119f44401SOr Gerlitz 41219f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 41319f44401SOr Gerlitz src_ipv4_src_ipv6.ipv6_layout.ipv6), 41419f44401SOr Gerlitz &mask->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 41519f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 41619f44401SOr Gerlitz src_ipv4_src_ipv6.ipv6_layout.ipv6), 41719f44401SOr Gerlitz &key->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 41819f44401SOr Gerlitz 41919f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 42019f44401SOr Gerlitz dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 42119f44401SOr Gerlitz &mask->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 42219f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 42319f44401SOr Gerlitz dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 42419f44401SOr Gerlitz &key->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 42519f44401SOr Gerlitz 42619f44401SOr Gerlitz MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); 42719f44401SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IPV6); 4282e72eb43SOr Gerlitz } 429bbd00f7eSHadar Hen Zion 430bbd00f7eSHadar Hen Zion /* Enforce DMAC when offloading incoming tunneled flows. 431bbd00f7eSHadar Hen Zion * Flow counters require a match on the DMAC. 432bbd00f7eSHadar Hen Zion */ 433bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_47_16); 434bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_15_0); 435bbd00f7eSHadar Hen Zion ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 436bbd00f7eSHadar Hen Zion dmac_47_16), priv->netdev->dev_addr); 437bbd00f7eSHadar Hen Zion 438bbd00f7eSHadar Hen Zion /* let software handle IP fragments */ 439bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1); 440bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 0); 441bbd00f7eSHadar Hen Zion 442bbd00f7eSHadar Hen Zion return 0; 443bbd00f7eSHadar Hen Zion } 444bbd00f7eSHadar Hen Zion 445de0af0bfSRoi Dayan static int __parse_cls_flower(struct mlx5e_priv *priv, 446de0af0bfSRoi Dayan struct mlx5_flow_spec *spec, 447de0af0bfSRoi Dayan struct tc_cls_flower_offload *f, 448de0af0bfSRoi Dayan u8 *min_inline) 449e3a2b7edSAmir Vadai { 450c5bb1730SMaor Gottlieb void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 451c5bb1730SMaor Gottlieb outer_headers); 452c5bb1730SMaor Gottlieb void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 453c5bb1730SMaor Gottlieb outer_headers); 454e3a2b7edSAmir Vadai u16 addr_type = 0; 455e3a2b7edSAmir Vadai u8 ip_proto = 0; 456e3a2b7edSAmir Vadai 457de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_L2; 458de0af0bfSRoi Dayan 459e3a2b7edSAmir Vadai if (f->dissector->used_keys & 460e3a2b7edSAmir Vadai ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 461e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_BASIC) | 462e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 463095b6cfdSOr Gerlitz BIT(FLOW_DISSECTOR_KEY_VLAN) | 464e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 465e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 466bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_PORTS) | 467bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | 468bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | 469bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | 470bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | 471bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL))) { 472e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", 473e3a2b7edSAmir Vadai f->dissector->used_keys); 474e3a2b7edSAmir Vadai return -EOPNOTSUPP; 475e3a2b7edSAmir Vadai } 476e3a2b7edSAmir Vadai 477bbd00f7eSHadar Hen Zion if ((dissector_uses_key(f->dissector, 478bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) || 479bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID) || 480bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) && 481bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL)) { 482bbd00f7eSHadar Hen Zion struct flow_dissector_key_control *key = 483bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 484bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_CONTROL, 485bbd00f7eSHadar Hen Zion f->key); 486bbd00f7eSHadar Hen Zion switch (key->addr_type) { 487bbd00f7eSHadar Hen Zion case FLOW_DISSECTOR_KEY_IPV4_ADDRS: 48819f44401SOr Gerlitz case FLOW_DISSECTOR_KEY_IPV6_ADDRS: 489bbd00f7eSHadar Hen Zion if (parse_tunnel_attr(priv, spec, f)) 490bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 491bbd00f7eSHadar Hen Zion break; 492bbd00f7eSHadar Hen Zion default: 493bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 494bbd00f7eSHadar Hen Zion } 495bbd00f7eSHadar Hen Zion 496bbd00f7eSHadar Hen Zion /* In decap flow, header pointers should point to the inner 497bbd00f7eSHadar Hen Zion * headers, outer header were already set by parse_tunnel_attr 498bbd00f7eSHadar Hen Zion */ 499bbd00f7eSHadar Hen Zion headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 500bbd00f7eSHadar Hen Zion inner_headers); 501bbd00f7eSHadar Hen Zion headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 502bbd00f7eSHadar Hen Zion inner_headers); 503bbd00f7eSHadar Hen Zion } 504bbd00f7eSHadar Hen Zion 505e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) { 506e3a2b7edSAmir Vadai struct flow_dissector_key_control *key = 507e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 5081dbd0d37SHadar Hen Zion FLOW_DISSECTOR_KEY_CONTROL, 509e3a2b7edSAmir Vadai f->key); 5103f7d0eb4SOr Gerlitz 5113f7d0eb4SOr Gerlitz struct flow_dissector_key_control *mask = 5123f7d0eb4SOr Gerlitz skb_flow_dissector_target(f->dissector, 5133f7d0eb4SOr Gerlitz FLOW_DISSECTOR_KEY_CONTROL, 5143f7d0eb4SOr Gerlitz f->mask); 515e3a2b7edSAmir Vadai addr_type = key->addr_type; 5163f7d0eb4SOr Gerlitz 5173f7d0eb4SOr Gerlitz if (mask->flags & FLOW_DIS_IS_FRAGMENT) { 5183f7d0eb4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1); 5193f7d0eb4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 5203f7d0eb4SOr Gerlitz key->flags & FLOW_DIS_IS_FRAGMENT); 5210827444dSOr Gerlitz 5220827444dSOr Gerlitz /* the HW doesn't need L3 inline to match on frag=no */ 5230827444dSOr Gerlitz if (key->flags & FLOW_DIS_IS_FRAGMENT) 5240827444dSOr Gerlitz *min_inline = MLX5_INLINE_MODE_IP; 5253f7d0eb4SOr Gerlitz } 526e3a2b7edSAmir Vadai } 527e3a2b7edSAmir Vadai 528e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) { 529e3a2b7edSAmir Vadai struct flow_dissector_key_basic *key = 530e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 531e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 532e3a2b7edSAmir Vadai f->key); 533e3a2b7edSAmir Vadai struct flow_dissector_key_basic *mask = 534e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 535e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 536e3a2b7edSAmir Vadai f->mask); 537e3a2b7edSAmir Vadai ip_proto = key->ip_proto; 538e3a2b7edSAmir Vadai 539e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype, 540e3a2b7edSAmir Vadai ntohs(mask->n_proto)); 541e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 542e3a2b7edSAmir Vadai ntohs(key->n_proto)); 543e3a2b7edSAmir Vadai 544e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol, 545e3a2b7edSAmir Vadai mask->ip_proto); 546e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 547e3a2b7edSAmir Vadai key->ip_proto); 548de0af0bfSRoi Dayan 549de0af0bfSRoi Dayan if (mask->ip_proto) 550de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 551e3a2b7edSAmir Vadai } 552e3a2b7edSAmir Vadai 553e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 554e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *key = 555e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 556e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 557e3a2b7edSAmir Vadai f->key); 558e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *mask = 559e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 560e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 561e3a2b7edSAmir Vadai f->mask); 562e3a2b7edSAmir Vadai 563e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 564e3a2b7edSAmir Vadai dmac_47_16), 565e3a2b7edSAmir Vadai mask->dst); 566e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 567e3a2b7edSAmir Vadai dmac_47_16), 568e3a2b7edSAmir Vadai key->dst); 569e3a2b7edSAmir Vadai 570e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 571e3a2b7edSAmir Vadai smac_47_16), 572e3a2b7edSAmir Vadai mask->src); 573e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 574e3a2b7edSAmir Vadai smac_47_16), 575e3a2b7edSAmir Vadai key->src); 576e3a2b7edSAmir Vadai } 577e3a2b7edSAmir Vadai 578095b6cfdSOr Gerlitz if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) { 579095b6cfdSOr Gerlitz struct flow_dissector_key_vlan *key = 580095b6cfdSOr Gerlitz skb_flow_dissector_target(f->dissector, 581095b6cfdSOr Gerlitz FLOW_DISSECTOR_KEY_VLAN, 582095b6cfdSOr Gerlitz f->key); 583095b6cfdSOr Gerlitz struct flow_dissector_key_vlan *mask = 584095b6cfdSOr Gerlitz skb_flow_dissector_target(f->dissector, 585095b6cfdSOr Gerlitz FLOW_DISSECTOR_KEY_VLAN, 586095b6cfdSOr Gerlitz f->mask); 587358d79a4SOr Gerlitz if (mask->vlan_id || mask->vlan_priority) { 58810543365SMohamad Haj Yahia MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); 58910543365SMohamad Haj Yahia MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1); 590095b6cfdSOr Gerlitz 591095b6cfdSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, mask->vlan_id); 592095b6cfdSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, key->vlan_id); 593358d79a4SOr Gerlitz 594358d79a4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_prio, mask->vlan_priority); 595358d79a4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, key->vlan_priority); 596095b6cfdSOr Gerlitz } 597095b6cfdSOr Gerlitz } 598095b6cfdSOr Gerlitz 599e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 600e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *key = 601e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 602e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 603e3a2b7edSAmir Vadai f->key); 604e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *mask = 605e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 606e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 607e3a2b7edSAmir Vadai f->mask); 608e3a2b7edSAmir Vadai 609e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 610e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 611e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 612e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 613e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 614e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 615e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 616e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 617e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 618e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 619e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 620e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 621de0af0bfSRoi Dayan 622de0af0bfSRoi Dayan if (mask->src || mask->dst) 623de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 624e3a2b7edSAmir Vadai } 625e3a2b7edSAmir Vadai 626e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 627e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *key = 628e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 629e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 630e3a2b7edSAmir Vadai f->key); 631e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *mask = 632e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 633e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 634e3a2b7edSAmir Vadai f->mask); 635e3a2b7edSAmir Vadai 636e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 637e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 638e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 639e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 640e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 641e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 642e3a2b7edSAmir Vadai 643e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 644e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 645e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 646e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 647e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 648e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 649de0af0bfSRoi Dayan 650de0af0bfSRoi Dayan if (ipv6_addr_type(&mask->src) != IPV6_ADDR_ANY || 651de0af0bfSRoi Dayan ipv6_addr_type(&mask->dst) != IPV6_ADDR_ANY) 652de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 653e3a2b7edSAmir Vadai } 654e3a2b7edSAmir Vadai 655e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) { 656e3a2b7edSAmir Vadai struct flow_dissector_key_ports *key = 657e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 658e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 659e3a2b7edSAmir Vadai f->key); 660e3a2b7edSAmir Vadai struct flow_dissector_key_ports *mask = 661e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 662e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 663e3a2b7edSAmir Vadai f->mask); 664e3a2b7edSAmir Vadai switch (ip_proto) { 665e3a2b7edSAmir Vadai case IPPROTO_TCP: 666e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 667e3a2b7edSAmir Vadai tcp_sport, ntohs(mask->src)); 668e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 669e3a2b7edSAmir Vadai tcp_sport, ntohs(key->src)); 670e3a2b7edSAmir Vadai 671e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 672e3a2b7edSAmir Vadai tcp_dport, ntohs(mask->dst)); 673e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 674e3a2b7edSAmir Vadai tcp_dport, ntohs(key->dst)); 675e3a2b7edSAmir Vadai break; 676e3a2b7edSAmir Vadai 677e3a2b7edSAmir Vadai case IPPROTO_UDP: 678e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 679e3a2b7edSAmir Vadai udp_sport, ntohs(mask->src)); 680e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 681e3a2b7edSAmir Vadai udp_sport, ntohs(key->src)); 682e3a2b7edSAmir Vadai 683e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 684e3a2b7edSAmir Vadai udp_dport, ntohs(mask->dst)); 685e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 686e3a2b7edSAmir Vadai udp_dport, ntohs(key->dst)); 687e3a2b7edSAmir Vadai break; 688e3a2b7edSAmir Vadai default: 689e3a2b7edSAmir Vadai netdev_err(priv->netdev, 690e3a2b7edSAmir Vadai "Only UDP and TCP transport are supported\n"); 691e3a2b7edSAmir Vadai return -EINVAL; 692e3a2b7edSAmir Vadai } 693de0af0bfSRoi Dayan 694de0af0bfSRoi Dayan if (mask->src || mask->dst) 695de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_TCP_UDP; 696e3a2b7edSAmir Vadai } 697e3a2b7edSAmir Vadai 698e3a2b7edSAmir Vadai return 0; 699e3a2b7edSAmir Vadai } 700e3a2b7edSAmir Vadai 701de0af0bfSRoi Dayan static int parse_cls_flower(struct mlx5e_priv *priv, 70265ba8fb7SOr Gerlitz struct mlx5e_tc_flow *flow, 703de0af0bfSRoi Dayan struct mlx5_flow_spec *spec, 704de0af0bfSRoi Dayan struct tc_cls_flower_offload *f) 705de0af0bfSRoi Dayan { 706de0af0bfSRoi Dayan struct mlx5_core_dev *dev = priv->mdev; 707de0af0bfSRoi Dayan struct mlx5_eswitch *esw = dev->priv.eswitch; 7081d447a39SSaeed Mahameed struct mlx5e_rep_priv *rpriv = priv->ppriv; 7091d447a39SSaeed Mahameed struct mlx5_eswitch_rep *rep; 710de0af0bfSRoi Dayan u8 min_inline; 711de0af0bfSRoi Dayan int err; 712de0af0bfSRoi Dayan 713de0af0bfSRoi Dayan err = __parse_cls_flower(priv, spec, f, &min_inline); 714de0af0bfSRoi Dayan 7151d447a39SSaeed Mahameed if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH)) { 7161d447a39SSaeed Mahameed rep = rpriv->rep; 7171d447a39SSaeed Mahameed if (rep->vport != FDB_UPLINK_VPORT && 7181d447a39SSaeed Mahameed (esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE && 7191d447a39SSaeed Mahameed esw->offloads.inline_mode < min_inline)) { 720de0af0bfSRoi Dayan netdev_warn(priv->netdev, 721de0af0bfSRoi Dayan "Flow is not offloaded due to min inline setting, required %d actual %d\n", 722de0af0bfSRoi Dayan min_inline, esw->offloads.inline_mode); 723de0af0bfSRoi Dayan return -EOPNOTSUPP; 724de0af0bfSRoi Dayan } 725de0af0bfSRoi Dayan } 726de0af0bfSRoi Dayan 727de0af0bfSRoi Dayan return err; 728de0af0bfSRoi Dayan } 729de0af0bfSRoi Dayan 730d79b6df6SOr Gerlitz struct pedit_headers { 731d79b6df6SOr Gerlitz struct ethhdr eth; 732d79b6df6SOr Gerlitz struct iphdr ip4; 733d79b6df6SOr Gerlitz struct ipv6hdr ip6; 734d79b6df6SOr Gerlitz struct tcphdr tcp; 735d79b6df6SOr Gerlitz struct udphdr udp; 736d79b6df6SOr Gerlitz }; 737d79b6df6SOr Gerlitz 738d79b6df6SOr Gerlitz static int pedit_header_offsets[] = { 739d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = offsetof(struct pedit_headers, eth), 740d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = offsetof(struct pedit_headers, ip4), 741d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = offsetof(struct pedit_headers, ip6), 742d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = offsetof(struct pedit_headers, tcp), 743d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = offsetof(struct pedit_headers, udp), 744d79b6df6SOr Gerlitz }; 745d79b6df6SOr Gerlitz 746d79b6df6SOr Gerlitz #define pedit_header(_ph, _htype) ((void *)(_ph) + pedit_header_offsets[_htype]) 747d79b6df6SOr Gerlitz 748d79b6df6SOr Gerlitz static int set_pedit_val(u8 hdr_type, u32 mask, u32 val, u32 offset, 749d79b6df6SOr Gerlitz struct pedit_headers *masks, 750d79b6df6SOr Gerlitz struct pedit_headers *vals) 751d79b6df6SOr Gerlitz { 752d79b6df6SOr Gerlitz u32 *curr_pmask, *curr_pval; 753d79b6df6SOr Gerlitz 754d79b6df6SOr Gerlitz if (hdr_type >= __PEDIT_HDR_TYPE_MAX) 755d79b6df6SOr Gerlitz goto out_err; 756d79b6df6SOr Gerlitz 757d79b6df6SOr Gerlitz curr_pmask = (u32 *)(pedit_header(masks, hdr_type) + offset); 758d79b6df6SOr Gerlitz curr_pval = (u32 *)(pedit_header(vals, hdr_type) + offset); 759d79b6df6SOr Gerlitz 760d79b6df6SOr Gerlitz if (*curr_pmask & mask) /* disallow acting twice on the same location */ 761d79b6df6SOr Gerlitz goto out_err; 762d79b6df6SOr Gerlitz 763d79b6df6SOr Gerlitz *curr_pmask |= mask; 764d79b6df6SOr Gerlitz *curr_pval |= (val & mask); 765d79b6df6SOr Gerlitz 766d79b6df6SOr Gerlitz return 0; 767d79b6df6SOr Gerlitz 768d79b6df6SOr Gerlitz out_err: 769d79b6df6SOr Gerlitz return -EOPNOTSUPP; 770d79b6df6SOr Gerlitz } 771d79b6df6SOr Gerlitz 772d79b6df6SOr Gerlitz struct mlx5_fields { 773d79b6df6SOr Gerlitz u8 field; 774d79b6df6SOr Gerlitz u8 size; 775d79b6df6SOr Gerlitz u32 offset; 776d79b6df6SOr Gerlitz }; 777d79b6df6SOr Gerlitz 778d79b6df6SOr Gerlitz static struct mlx5_fields fields[] = { 779d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16, 4, offsetof(struct pedit_headers, eth.h_dest[0])}, 780d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0, 2, offsetof(struct pedit_headers, eth.h_dest[4])}, 781d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16, 4, offsetof(struct pedit_headers, eth.h_source[0])}, 782d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0, 2, offsetof(struct pedit_headers, eth.h_source[4])}, 783d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE, 2, offsetof(struct pedit_headers, eth.h_proto)}, 784d79b6df6SOr Gerlitz 785d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_IP_DSCP, 1, offsetof(struct pedit_headers, ip4.tos)}, 786d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_IP_TTL, 1, offsetof(struct pedit_headers, ip4.ttl)}, 787d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_SIPV4, 4, offsetof(struct pedit_headers, ip4.saddr)}, 788d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_DIPV4, 4, offsetof(struct pedit_headers, ip4.daddr)}, 789d79b6df6SOr Gerlitz 790d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[0])}, 791d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[1])}, 792d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[2])}, 793d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[3])}, 794d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[0])}, 795d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[1])}, 796d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[2])}, 797d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[3])}, 798d79b6df6SOr Gerlitz 799d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT, 2, offsetof(struct pedit_headers, tcp.source)}, 800d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT, 2, offsetof(struct pedit_headers, tcp.dest)}, 801d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS, 1, offsetof(struct pedit_headers, tcp.ack_seq) + 5}, 802d79b6df6SOr Gerlitz 803d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT, 2, offsetof(struct pedit_headers, udp.source)}, 804d79b6df6SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT, 2, offsetof(struct pedit_headers, udp.dest)}, 805d79b6df6SOr Gerlitz }; 806d79b6df6SOr Gerlitz 807d79b6df6SOr Gerlitz /* On input attr->num_mod_hdr_actions tells how many HW actions can be parsed at 808d79b6df6SOr Gerlitz * max from the SW pedit action. On success, it says how many HW actions were 809d79b6df6SOr Gerlitz * actually parsed. 810d79b6df6SOr Gerlitz */ 811d79b6df6SOr Gerlitz static int offload_pedit_fields(struct pedit_headers *masks, 812d79b6df6SOr Gerlitz struct pedit_headers *vals, 813d79b6df6SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr) 814d79b6df6SOr Gerlitz { 815d79b6df6SOr Gerlitz struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals; 816d79b6df6SOr Gerlitz int i, action_size, nactions, max_actions, first, last; 817d79b6df6SOr Gerlitz void *s_masks_p, *a_masks_p, *vals_p; 818d79b6df6SOr Gerlitz u32 s_mask, a_mask, val; 819d79b6df6SOr Gerlitz struct mlx5_fields *f; 820d79b6df6SOr Gerlitz u8 cmd, field_bsize; 821d79b6df6SOr Gerlitz unsigned long mask; 822d79b6df6SOr Gerlitz void *action; 823d79b6df6SOr Gerlitz 824d79b6df6SOr Gerlitz set_masks = &masks[TCA_PEDIT_KEY_EX_CMD_SET]; 825d79b6df6SOr Gerlitz add_masks = &masks[TCA_PEDIT_KEY_EX_CMD_ADD]; 826d79b6df6SOr Gerlitz set_vals = &vals[TCA_PEDIT_KEY_EX_CMD_SET]; 827d79b6df6SOr Gerlitz add_vals = &vals[TCA_PEDIT_KEY_EX_CMD_ADD]; 828d79b6df6SOr Gerlitz 829d79b6df6SOr Gerlitz action_size = MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto); 830d79b6df6SOr Gerlitz action = parse_attr->mod_hdr_actions; 831d79b6df6SOr Gerlitz max_actions = parse_attr->num_mod_hdr_actions; 832d79b6df6SOr Gerlitz nactions = 0; 833d79b6df6SOr Gerlitz 834d79b6df6SOr Gerlitz for (i = 0; i < ARRAY_SIZE(fields); i++) { 835d79b6df6SOr Gerlitz f = &fields[i]; 836d79b6df6SOr Gerlitz /* avoid seeing bits set from previous iterations */ 837d79b6df6SOr Gerlitz s_mask = a_mask = mask = val = 0; 838d79b6df6SOr Gerlitz 839d79b6df6SOr Gerlitz s_masks_p = (void *)set_masks + f->offset; 840d79b6df6SOr Gerlitz a_masks_p = (void *)add_masks + f->offset; 841d79b6df6SOr Gerlitz 842d79b6df6SOr Gerlitz memcpy(&s_mask, s_masks_p, f->size); 843d79b6df6SOr Gerlitz memcpy(&a_mask, a_masks_p, f->size); 844d79b6df6SOr Gerlitz 845d79b6df6SOr Gerlitz if (!s_mask && !a_mask) /* nothing to offload here */ 846d79b6df6SOr Gerlitz continue; 847d79b6df6SOr Gerlitz 848d79b6df6SOr Gerlitz if (s_mask && a_mask) { 849d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: can't set and add to the same HW field (%x)\n", f->field); 850d79b6df6SOr Gerlitz return -EOPNOTSUPP; 851d79b6df6SOr Gerlitz } 852d79b6df6SOr Gerlitz 853d79b6df6SOr Gerlitz if (nactions == max_actions) { 854d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: parsed %d pedit actions, can't do more\n", nactions); 855d79b6df6SOr Gerlitz return -EOPNOTSUPP; 856d79b6df6SOr Gerlitz } 857d79b6df6SOr Gerlitz 858d79b6df6SOr Gerlitz if (s_mask) { 859d79b6df6SOr Gerlitz cmd = MLX5_ACTION_TYPE_SET; 860d79b6df6SOr Gerlitz mask = s_mask; 861d79b6df6SOr Gerlitz vals_p = (void *)set_vals + f->offset; 862d79b6df6SOr Gerlitz /* clear to denote we consumed this field */ 863d79b6df6SOr Gerlitz memset(s_masks_p, 0, f->size); 864d79b6df6SOr Gerlitz } else { 865d79b6df6SOr Gerlitz cmd = MLX5_ACTION_TYPE_ADD; 866d79b6df6SOr Gerlitz mask = a_mask; 867d79b6df6SOr Gerlitz vals_p = (void *)add_vals + f->offset; 868d79b6df6SOr Gerlitz /* clear to denote we consumed this field */ 869d79b6df6SOr Gerlitz memset(a_masks_p, 0, f->size); 870d79b6df6SOr Gerlitz } 871d79b6df6SOr Gerlitz 872d79b6df6SOr Gerlitz memcpy(&val, vals_p, f->size); 873d79b6df6SOr Gerlitz 874d79b6df6SOr Gerlitz field_bsize = f->size * BITS_PER_BYTE; 875d79b6df6SOr Gerlitz first = find_first_bit(&mask, field_bsize); 876d79b6df6SOr Gerlitz last = find_last_bit(&mask, field_bsize); 877d79b6df6SOr Gerlitz if (first > 0 || last != (field_bsize - 1)) { 878d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: partial rewrite (mask %lx) is currently not offloaded\n", 879d79b6df6SOr Gerlitz mask); 880d79b6df6SOr Gerlitz return -EOPNOTSUPP; 881d79b6df6SOr Gerlitz } 882d79b6df6SOr Gerlitz 883d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, action_type, cmd); 884d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, field, f->field); 885d79b6df6SOr Gerlitz 886d79b6df6SOr Gerlitz if (cmd == MLX5_ACTION_TYPE_SET) { 887d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, offset, 0); 888d79b6df6SOr Gerlitz /* length is num of bits to be written, zero means length of 32 */ 889d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, length, field_bsize); 890d79b6df6SOr Gerlitz } 891d79b6df6SOr Gerlitz 892d79b6df6SOr Gerlitz if (field_bsize == 32) 893d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, data, ntohl(val)); 894d79b6df6SOr Gerlitz else if (field_bsize == 16) 895d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, data, ntohs(val)); 896d79b6df6SOr Gerlitz else if (field_bsize == 8) 897d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, data, val); 898d79b6df6SOr Gerlitz 899d79b6df6SOr Gerlitz action += action_size; 900d79b6df6SOr Gerlitz nactions++; 901d79b6df6SOr Gerlitz } 902d79b6df6SOr Gerlitz 903d79b6df6SOr Gerlitz parse_attr->num_mod_hdr_actions = nactions; 904d79b6df6SOr Gerlitz return 0; 905d79b6df6SOr Gerlitz } 906d79b6df6SOr Gerlitz 907d79b6df6SOr Gerlitz static int alloc_mod_hdr_actions(struct mlx5e_priv *priv, 908d79b6df6SOr Gerlitz const struct tc_action *a, int namespace, 909d79b6df6SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr) 910d79b6df6SOr Gerlitz { 911d79b6df6SOr Gerlitz int nkeys, action_size, max_actions; 912d79b6df6SOr Gerlitz 913d79b6df6SOr Gerlitz nkeys = tcf_pedit_nkeys(a); 914d79b6df6SOr Gerlitz action_size = MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto); 915d79b6df6SOr Gerlitz 916d79b6df6SOr Gerlitz if (namespace == MLX5_FLOW_NAMESPACE_FDB) /* FDB offloading */ 917d79b6df6SOr Gerlitz max_actions = MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, max_modify_header_actions); 918d79b6df6SOr Gerlitz else /* namespace is MLX5_FLOW_NAMESPACE_KERNEL - NIC offloading */ 919d79b6df6SOr Gerlitz max_actions = MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, max_modify_header_actions); 920d79b6df6SOr Gerlitz 921d79b6df6SOr Gerlitz /* can get up to crazingly 16 HW actions in 32 bits pedit SW key */ 922d79b6df6SOr Gerlitz max_actions = min(max_actions, nkeys * 16); 923d79b6df6SOr Gerlitz 924d79b6df6SOr Gerlitz parse_attr->mod_hdr_actions = kcalloc(max_actions, action_size, GFP_KERNEL); 925d79b6df6SOr Gerlitz if (!parse_attr->mod_hdr_actions) 926d79b6df6SOr Gerlitz return -ENOMEM; 927d79b6df6SOr Gerlitz 928d79b6df6SOr Gerlitz parse_attr->num_mod_hdr_actions = max_actions; 929d79b6df6SOr Gerlitz return 0; 930d79b6df6SOr Gerlitz } 931d79b6df6SOr Gerlitz 932d79b6df6SOr Gerlitz static const struct pedit_headers zero_masks = {}; 933d79b6df6SOr Gerlitz 934d79b6df6SOr Gerlitz static int parse_tc_pedit_action(struct mlx5e_priv *priv, 935d79b6df6SOr Gerlitz const struct tc_action *a, int namespace, 936d79b6df6SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr) 937d79b6df6SOr Gerlitz { 938d79b6df6SOr Gerlitz struct pedit_headers masks[__PEDIT_CMD_MAX], vals[__PEDIT_CMD_MAX], *cmd_masks; 939d79b6df6SOr Gerlitz int nkeys, i, err = -EOPNOTSUPP; 940d79b6df6SOr Gerlitz u32 mask, val, offset; 941d79b6df6SOr Gerlitz u8 cmd, htype; 942d79b6df6SOr Gerlitz 943d79b6df6SOr Gerlitz nkeys = tcf_pedit_nkeys(a); 944d79b6df6SOr Gerlitz 945d79b6df6SOr Gerlitz memset(masks, 0, sizeof(struct pedit_headers) * __PEDIT_CMD_MAX); 946d79b6df6SOr Gerlitz memset(vals, 0, sizeof(struct pedit_headers) * __PEDIT_CMD_MAX); 947d79b6df6SOr Gerlitz 948d79b6df6SOr Gerlitz for (i = 0; i < nkeys; i++) { 949d79b6df6SOr Gerlitz htype = tcf_pedit_htype(a, i); 950d79b6df6SOr Gerlitz cmd = tcf_pedit_cmd(a, i); 951d79b6df6SOr Gerlitz err = -EOPNOTSUPP; /* can't be all optimistic */ 952d79b6df6SOr Gerlitz 953d79b6df6SOr Gerlitz if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) { 954d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: legacy pedit isn't offloaded\n"); 955d79b6df6SOr Gerlitz goto out_err; 956d79b6df6SOr Gerlitz } 957d79b6df6SOr Gerlitz 958d79b6df6SOr Gerlitz if (cmd != TCA_PEDIT_KEY_EX_CMD_SET && cmd != TCA_PEDIT_KEY_EX_CMD_ADD) { 959d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: pedit cmd %d isn't offloaded\n", cmd); 960d79b6df6SOr Gerlitz goto out_err; 961d79b6df6SOr Gerlitz } 962d79b6df6SOr Gerlitz 963d79b6df6SOr Gerlitz mask = tcf_pedit_mask(a, i); 964d79b6df6SOr Gerlitz val = tcf_pedit_val(a, i); 965d79b6df6SOr Gerlitz offset = tcf_pedit_offset(a, i); 966d79b6df6SOr Gerlitz 967d79b6df6SOr Gerlitz err = set_pedit_val(htype, ~mask, val, offset, &masks[cmd], &vals[cmd]); 968d79b6df6SOr Gerlitz if (err) 969d79b6df6SOr Gerlitz goto out_err; 970d79b6df6SOr Gerlitz } 971d79b6df6SOr Gerlitz 972d79b6df6SOr Gerlitz err = alloc_mod_hdr_actions(priv, a, namespace, parse_attr); 973d79b6df6SOr Gerlitz if (err) 974d79b6df6SOr Gerlitz goto out_err; 975d79b6df6SOr Gerlitz 976d79b6df6SOr Gerlitz err = offload_pedit_fields(masks, vals, parse_attr); 977d79b6df6SOr Gerlitz if (err < 0) 978d79b6df6SOr Gerlitz goto out_dealloc_parsed_actions; 979d79b6df6SOr Gerlitz 980d79b6df6SOr Gerlitz for (cmd = 0; cmd < __PEDIT_CMD_MAX; cmd++) { 981d79b6df6SOr Gerlitz cmd_masks = &masks[cmd]; 982d79b6df6SOr Gerlitz if (memcmp(cmd_masks, &zero_masks, sizeof(zero_masks))) { 983d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: attempt to offload an unsupported field (cmd %d)\n", 984d79b6df6SOr Gerlitz cmd); 985d79b6df6SOr Gerlitz print_hex_dump(KERN_WARNING, "mask: ", DUMP_PREFIX_ADDRESS, 986d79b6df6SOr Gerlitz 16, 1, cmd_masks, sizeof(zero_masks), true); 987d79b6df6SOr Gerlitz err = -EOPNOTSUPP; 988d79b6df6SOr Gerlitz goto out_dealloc_parsed_actions; 989d79b6df6SOr Gerlitz } 990d79b6df6SOr Gerlitz } 991d79b6df6SOr Gerlitz 992d79b6df6SOr Gerlitz return 0; 993d79b6df6SOr Gerlitz 994d79b6df6SOr Gerlitz out_dealloc_parsed_actions: 995d79b6df6SOr Gerlitz kfree(parse_attr->mod_hdr_actions); 996d79b6df6SOr Gerlitz out_err: 997d79b6df6SOr Gerlitz return err; 998d79b6df6SOr Gerlitz } 999d79b6df6SOr Gerlitz 10005c40348cSOr Gerlitz static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 1001aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 1002aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow) 1003e3a2b7edSAmir Vadai { 1004aa0cbbaeSOr Gerlitz struct mlx5_nic_flow_attr *attr = flow->nic_attr; 1005e3a2b7edSAmir Vadai const struct tc_action *a; 100622dc13c8SWANG Cong LIST_HEAD(actions); 10072f4fe4caSOr Gerlitz int err; 1008e3a2b7edSAmir Vadai 1009e3a2b7edSAmir Vadai if (tc_no_actions(exts)) 1010e3a2b7edSAmir Vadai return -EINVAL; 1011e3a2b7edSAmir Vadai 10123bc4b7bfSOr Gerlitz attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; 10133bc4b7bfSOr Gerlitz attr->action = 0; 1014e3a2b7edSAmir Vadai 101522dc13c8SWANG Cong tcf_exts_to_list(exts, &actions); 101622dc13c8SWANG Cong list_for_each_entry(a, &actions, list) { 1017e3a2b7edSAmir Vadai /* Only support a single action per rule */ 10183bc4b7bfSOr Gerlitz if (attr->action) 1019e3a2b7edSAmir Vadai return -EINVAL; 1020e3a2b7edSAmir Vadai 1021e3a2b7edSAmir Vadai if (is_tcf_gact_shot(a)) { 10223bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP; 1023aad7e08dSAmir Vadai if (MLX5_CAP_FLOWTABLE(priv->mdev, 1024aad7e08dSAmir Vadai flow_table_properties_nic_receive.flow_counter)) 10253bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 1026e3a2b7edSAmir Vadai continue; 1027e3a2b7edSAmir Vadai } 1028e3a2b7edSAmir Vadai 10292f4fe4caSOr Gerlitz if (is_tcf_pedit(a)) { 10302f4fe4caSOr Gerlitz err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_KERNEL, 10312f4fe4caSOr Gerlitz parse_attr); 10322f4fe4caSOr Gerlitz if (err) 10332f4fe4caSOr Gerlitz return err; 10342f4fe4caSOr Gerlitz 10352f4fe4caSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | 10362f4fe4caSOr Gerlitz MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 10372f4fe4caSOr Gerlitz continue; 10382f4fe4caSOr Gerlitz } 10392f4fe4caSOr Gerlitz 1040e3a2b7edSAmir Vadai if (is_tcf_skbedit_mark(a)) { 1041e3a2b7edSAmir Vadai u32 mark = tcf_skbedit_mark(a); 1042e3a2b7edSAmir Vadai 1043e3a2b7edSAmir Vadai if (mark & ~MLX5E_TC_FLOW_ID_MASK) { 1044e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n", 1045e3a2b7edSAmir Vadai mark); 1046e3a2b7edSAmir Vadai return -EINVAL; 1047e3a2b7edSAmir Vadai } 1048e3a2b7edSAmir Vadai 10493bc4b7bfSOr Gerlitz attr->flow_tag = mark; 10503bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 1051e3a2b7edSAmir Vadai continue; 1052e3a2b7edSAmir Vadai } 1053e3a2b7edSAmir Vadai 1054e3a2b7edSAmir Vadai return -EINVAL; 1055e3a2b7edSAmir Vadai } 1056e3a2b7edSAmir Vadai 1057e3a2b7edSAmir Vadai return 0; 1058e3a2b7edSAmir Vadai } 1059e3a2b7edSAmir Vadai 106076f7444dSOr Gerlitz static inline int cmp_encap_info(struct ip_tunnel_key *a, 106176f7444dSOr Gerlitz struct ip_tunnel_key *b) 1062a54e20b4SHadar Hen Zion { 1063a54e20b4SHadar Hen Zion return memcmp(a, b, sizeof(*a)); 1064a54e20b4SHadar Hen Zion } 1065a54e20b4SHadar Hen Zion 106676f7444dSOr Gerlitz static inline int hash_encap_info(struct ip_tunnel_key *key) 1067a54e20b4SHadar Hen Zion { 106876f7444dSOr Gerlitz return jhash(key, sizeof(*key), 0); 1069a54e20b4SHadar Hen Zion } 1070a54e20b4SHadar Hen Zion 1071a54e20b4SHadar Hen Zion static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, 1072a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 1073a54e20b4SHadar Hen Zion struct net_device **out_dev, 1074a54e20b4SHadar Hen Zion struct flowi4 *fl4, 1075a54e20b4SHadar Hen Zion struct neighbour **out_n, 1076a54e20b4SHadar Hen Zion int *out_ttl) 1077a54e20b4SHadar Hen Zion { 10783e621b19SHadar Hen Zion struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 1079a54e20b4SHadar Hen Zion struct rtable *rt; 1080a54e20b4SHadar Hen Zion struct neighbour *n = NULL; 1081a54e20b4SHadar Hen Zion 1082a54e20b4SHadar Hen Zion #if IS_ENABLED(CONFIG_INET) 1083abeffce9SArnd Bergmann int ret; 1084abeffce9SArnd Bergmann 1085a54e20b4SHadar Hen Zion rt = ip_route_output_key(dev_net(mirred_dev), fl4); 1086abeffce9SArnd Bergmann ret = PTR_ERR_OR_ZERO(rt); 1087abeffce9SArnd Bergmann if (ret) 1088abeffce9SArnd Bergmann return ret; 1089a54e20b4SHadar Hen Zion #else 1090a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 1091a54e20b4SHadar Hen Zion #endif 10923e621b19SHadar Hen Zion /* if the egress device isn't on the same HW e-switch, we use the uplink */ 10933e621b19SHadar Hen Zion if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) 10943e621b19SHadar Hen Zion *out_dev = mlx5_eswitch_get_uplink_netdev(esw); 10953e621b19SHadar Hen Zion else 10963e621b19SHadar Hen Zion *out_dev = rt->dst.dev; 1097a54e20b4SHadar Hen Zion 109875c33da8SOr Gerlitz *out_ttl = ip4_dst_hoplimit(&rt->dst); 1099a54e20b4SHadar Hen Zion n = dst_neigh_lookup(&rt->dst, &fl4->daddr); 1100a54e20b4SHadar Hen Zion ip_rt_put(rt); 1101a54e20b4SHadar Hen Zion if (!n) 1102a54e20b4SHadar Hen Zion return -ENOMEM; 1103a54e20b4SHadar Hen Zion 1104a54e20b4SHadar Hen Zion *out_n = n; 1105a54e20b4SHadar Hen Zion return 0; 1106a54e20b4SHadar Hen Zion } 1107a54e20b4SHadar Hen Zion 1108ce99f6b9SOr Gerlitz static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, 1109ce99f6b9SOr Gerlitz struct net_device *mirred_dev, 1110ce99f6b9SOr Gerlitz struct net_device **out_dev, 1111ce99f6b9SOr Gerlitz struct flowi6 *fl6, 1112ce99f6b9SOr Gerlitz struct neighbour **out_n, 1113ce99f6b9SOr Gerlitz int *out_ttl) 1114ce99f6b9SOr Gerlitz { 1115ce99f6b9SOr Gerlitz struct neighbour *n = NULL; 1116ce99f6b9SOr Gerlitz struct dst_entry *dst; 1117ce99f6b9SOr Gerlitz 1118ce99f6b9SOr Gerlitz #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) 1119ce99f6b9SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 1120ce99f6b9SOr Gerlitz int ret; 1121ce99f6b9SOr Gerlitz 1122ce99f6b9SOr Gerlitz dst = ip6_route_output(dev_net(mirred_dev), NULL, fl6); 1123ce99f6b9SOr Gerlitz ret = dst->error; 1124321fa4ffSArnd Bergmann if (ret) { 1125ce99f6b9SOr Gerlitz dst_release(dst); 1126ce99f6b9SOr Gerlitz return ret; 1127ce99f6b9SOr Gerlitz } 1128ce99f6b9SOr Gerlitz 1129ce99f6b9SOr Gerlitz *out_ttl = ip6_dst_hoplimit(dst); 1130ce99f6b9SOr Gerlitz 1131ce99f6b9SOr Gerlitz /* if the egress device isn't on the same HW e-switch, we use the uplink */ 1132ce99f6b9SOr Gerlitz if (!switchdev_port_same_parent_id(priv->netdev, dst->dev)) 1133ce99f6b9SOr Gerlitz *out_dev = mlx5_eswitch_get_uplink_netdev(esw); 1134ce99f6b9SOr Gerlitz else 1135ce99f6b9SOr Gerlitz *out_dev = dst->dev; 1136ce99f6b9SOr Gerlitz #else 1137ce99f6b9SOr Gerlitz return -EOPNOTSUPP; 1138ce99f6b9SOr Gerlitz #endif 1139ce99f6b9SOr Gerlitz 1140ce99f6b9SOr Gerlitz n = dst_neigh_lookup(dst, &fl6->daddr); 1141ce99f6b9SOr Gerlitz dst_release(dst); 1142ce99f6b9SOr Gerlitz if (!n) 1143ce99f6b9SOr Gerlitz return -ENOMEM; 1144ce99f6b9SOr Gerlitz 1145ce99f6b9SOr Gerlitz *out_n = n; 1146ce99f6b9SOr Gerlitz return 0; 1147ce99f6b9SOr Gerlitz } 1148ce99f6b9SOr Gerlitz 114932f3671fSOr Gerlitz static void gen_vxlan_header_ipv4(struct net_device *out_dev, 115032f3671fSOr Gerlitz char buf[], int encap_size, 1151a54e20b4SHadar Hen Zion unsigned char h_dest[ETH_ALEN], 1152a54e20b4SHadar Hen Zion int ttl, 1153a54e20b4SHadar Hen Zion __be32 daddr, 1154a54e20b4SHadar Hen Zion __be32 saddr, 1155a54e20b4SHadar Hen Zion __be16 udp_dst_port, 1156a54e20b4SHadar Hen Zion __be32 vx_vni) 1157a54e20b4SHadar Hen Zion { 1158a54e20b4SHadar Hen Zion struct ethhdr *eth = (struct ethhdr *)buf; 1159a54e20b4SHadar Hen Zion struct iphdr *ip = (struct iphdr *)((char *)eth + sizeof(struct ethhdr)); 1160a54e20b4SHadar Hen Zion struct udphdr *udp = (struct udphdr *)((char *)ip + sizeof(struct iphdr)); 1161a54e20b4SHadar Hen Zion struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 1162a54e20b4SHadar Hen Zion 1163a54e20b4SHadar Hen Zion memset(buf, 0, encap_size); 1164a54e20b4SHadar Hen Zion 1165a54e20b4SHadar Hen Zion ether_addr_copy(eth->h_dest, h_dest); 1166a54e20b4SHadar Hen Zion ether_addr_copy(eth->h_source, out_dev->dev_addr); 1167a54e20b4SHadar Hen Zion eth->h_proto = htons(ETH_P_IP); 1168a54e20b4SHadar Hen Zion 1169a54e20b4SHadar Hen Zion ip->daddr = daddr; 1170a54e20b4SHadar Hen Zion ip->saddr = saddr; 1171a54e20b4SHadar Hen Zion 1172a54e20b4SHadar Hen Zion ip->ttl = ttl; 1173a54e20b4SHadar Hen Zion ip->protocol = IPPROTO_UDP; 1174a54e20b4SHadar Hen Zion ip->version = 0x4; 1175a54e20b4SHadar Hen Zion ip->ihl = 0x5; 1176a54e20b4SHadar Hen Zion 1177a54e20b4SHadar Hen Zion udp->dest = udp_dst_port; 1178a54e20b4SHadar Hen Zion vxh->vx_flags = VXLAN_HF_VNI; 1179a54e20b4SHadar Hen Zion vxh->vx_vni = vxlan_vni_field(vx_vni); 1180a54e20b4SHadar Hen Zion } 1181a54e20b4SHadar Hen Zion 1182225aabafSOr Gerlitz static void gen_vxlan_header_ipv6(struct net_device *out_dev, 1183225aabafSOr Gerlitz char buf[], int encap_size, 1184ce99f6b9SOr Gerlitz unsigned char h_dest[ETH_ALEN], 1185ce99f6b9SOr Gerlitz int ttl, 1186ce99f6b9SOr Gerlitz struct in6_addr *daddr, 1187ce99f6b9SOr Gerlitz struct in6_addr *saddr, 1188ce99f6b9SOr Gerlitz __be16 udp_dst_port, 1189ce99f6b9SOr Gerlitz __be32 vx_vni) 1190ce99f6b9SOr Gerlitz { 1191ce99f6b9SOr Gerlitz struct ethhdr *eth = (struct ethhdr *)buf; 1192ce99f6b9SOr Gerlitz struct ipv6hdr *ip6h = (struct ipv6hdr *)((char *)eth + sizeof(struct ethhdr)); 1193ce99f6b9SOr Gerlitz struct udphdr *udp = (struct udphdr *)((char *)ip6h + sizeof(struct ipv6hdr)); 1194ce99f6b9SOr Gerlitz struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 1195ce99f6b9SOr Gerlitz 1196ce99f6b9SOr Gerlitz memset(buf, 0, encap_size); 1197ce99f6b9SOr Gerlitz 1198ce99f6b9SOr Gerlitz ether_addr_copy(eth->h_dest, h_dest); 1199ce99f6b9SOr Gerlitz ether_addr_copy(eth->h_source, out_dev->dev_addr); 1200ce99f6b9SOr Gerlitz eth->h_proto = htons(ETH_P_IPV6); 1201ce99f6b9SOr Gerlitz 1202ce99f6b9SOr Gerlitz ip6_flow_hdr(ip6h, 0, 0); 1203ce99f6b9SOr Gerlitz /* the HW fills up ipv6 payload len */ 1204ce99f6b9SOr Gerlitz ip6h->nexthdr = IPPROTO_UDP; 1205ce99f6b9SOr Gerlitz ip6h->hop_limit = ttl; 1206ce99f6b9SOr Gerlitz ip6h->daddr = *daddr; 1207ce99f6b9SOr Gerlitz ip6h->saddr = *saddr; 1208ce99f6b9SOr Gerlitz 1209ce99f6b9SOr Gerlitz udp->dest = udp_dst_port; 1210ce99f6b9SOr Gerlitz vxh->vx_flags = VXLAN_HF_VNI; 1211ce99f6b9SOr Gerlitz vxh->vx_vni = vxlan_vni_field(vx_vni); 1212ce99f6b9SOr Gerlitz } 1213ce99f6b9SOr Gerlitz 1214a54e20b4SHadar Hen Zion static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, 1215a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 12161a8552bdSHadar Hen Zion struct mlx5e_encap_entry *e) 1217a54e20b4SHadar Hen Zion { 1218a54e20b4SHadar Hen Zion int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); 121932f3671fSOr Gerlitz int ipv4_encap_size = ETH_HLEN + sizeof(struct iphdr) + VXLAN_HLEN; 122076f7444dSOr Gerlitz struct ip_tunnel_key *tun_key = &e->tun_info.key; 12211a8552bdSHadar Hen Zion struct net_device *out_dev; 1222a42485ebSOr Gerlitz struct neighbour *n = NULL; 1223a54e20b4SHadar Hen Zion struct flowi4 fl4 = {}; 1224a54e20b4SHadar Hen Zion char *encap_header; 122532f3671fSOr Gerlitz int ttl, err; 1226a54e20b4SHadar Hen Zion 122732f3671fSOr Gerlitz if (max_encap_size < ipv4_encap_size) { 122832f3671fSOr Gerlitz mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", 122932f3671fSOr Gerlitz ipv4_encap_size, max_encap_size); 123032f3671fSOr Gerlitz return -EOPNOTSUPP; 123132f3671fSOr Gerlitz } 123232f3671fSOr Gerlitz 123332f3671fSOr Gerlitz encap_header = kzalloc(ipv4_encap_size, GFP_KERNEL); 1234a54e20b4SHadar Hen Zion if (!encap_header) 1235a54e20b4SHadar Hen Zion return -ENOMEM; 1236a54e20b4SHadar Hen Zion 1237a54e20b4SHadar Hen Zion switch (e->tunnel_type) { 1238a54e20b4SHadar Hen Zion case MLX5_HEADER_TYPE_VXLAN: 1239a54e20b4SHadar Hen Zion fl4.flowi4_proto = IPPROTO_UDP; 124076f7444dSOr Gerlitz fl4.fl4_dport = tun_key->tp_dst; 1241a54e20b4SHadar Hen Zion break; 1242a54e20b4SHadar Hen Zion default: 1243a54e20b4SHadar Hen Zion err = -EOPNOTSUPP; 1244a54e20b4SHadar Hen Zion goto out; 1245a54e20b4SHadar Hen Zion } 12469a941117SOr Gerlitz fl4.flowi4_tos = tun_key->tos; 124776f7444dSOr Gerlitz fl4.daddr = tun_key->u.ipv4.dst; 12489a941117SOr Gerlitz fl4.saddr = tun_key->u.ipv4.src; 1249a54e20b4SHadar Hen Zion 12501a8552bdSHadar Hen Zion err = mlx5e_route_lookup_ipv4(priv, mirred_dev, &out_dev, 12519a941117SOr Gerlitz &fl4, &n, &ttl); 1252a54e20b4SHadar Hen Zion if (err) 1253a54e20b4SHadar Hen Zion goto out; 1254a54e20b4SHadar Hen Zion 1255a54e20b4SHadar Hen Zion if (!(n->nud_state & NUD_VALID)) { 1256a42485ebSOr Gerlitz pr_warn("%s: can't offload, neighbour to %pI4 invalid\n", __func__, &fl4.daddr); 1257a42485ebSOr Gerlitz err = -EOPNOTSUPP; 1258a54e20b4SHadar Hen Zion goto out; 1259a54e20b4SHadar Hen Zion } 1260a54e20b4SHadar Hen Zion 126175c33da8SOr Gerlitz e->n = n; 12621a8552bdSHadar Hen Zion e->out_dev = out_dev; 126375c33da8SOr Gerlitz 12641a8552bdSHadar Hen Zion neigh_ha_snapshot(e->h_dest, n, out_dev); 1265a54e20b4SHadar Hen Zion 1266a54e20b4SHadar Hen Zion switch (e->tunnel_type) { 1267a54e20b4SHadar Hen Zion case MLX5_HEADER_TYPE_VXLAN: 12681a8552bdSHadar Hen Zion gen_vxlan_header_ipv4(out_dev, encap_header, 126932f3671fSOr Gerlitz ipv4_encap_size, e->h_dest, ttl, 12709a941117SOr Gerlitz fl4.daddr, 12719a941117SOr Gerlitz fl4.saddr, tun_key->tp_dst, 127276f7444dSOr Gerlitz tunnel_id_to_key32(tun_key->tun_id)); 1273a54e20b4SHadar Hen Zion break; 1274a54e20b4SHadar Hen Zion default: 1275a54e20b4SHadar Hen Zion err = -EOPNOTSUPP; 1276a54e20b4SHadar Hen Zion goto out; 1277a54e20b4SHadar Hen Zion } 1278a54e20b4SHadar Hen Zion 1279a54e20b4SHadar Hen Zion err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, 128032f3671fSOr Gerlitz ipv4_encap_size, encap_header, &e->encap_id); 1281a54e20b4SHadar Hen Zion out: 1282a42485ebSOr Gerlitz if (err && n) 1283a42485ebSOr Gerlitz neigh_release(n); 1284a54e20b4SHadar Hen Zion kfree(encap_header); 1285a54e20b4SHadar Hen Zion return err; 1286a54e20b4SHadar Hen Zion } 1287a54e20b4SHadar Hen Zion 1288ce99f6b9SOr Gerlitz static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, 1289ce99f6b9SOr Gerlitz struct net_device *mirred_dev, 12901a8552bdSHadar Hen Zion struct mlx5e_encap_entry *e) 1291ce99f6b9SOr Gerlitz { 1292ce99f6b9SOr Gerlitz int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); 1293225aabafSOr Gerlitz int ipv6_encap_size = ETH_HLEN + sizeof(struct ipv6hdr) + VXLAN_HLEN; 1294ce99f6b9SOr Gerlitz struct ip_tunnel_key *tun_key = &e->tun_info.key; 12951a8552bdSHadar Hen Zion struct net_device *out_dev; 1296ce99f6b9SOr Gerlitz struct neighbour *n = NULL; 1297ce99f6b9SOr Gerlitz struct flowi6 fl6 = {}; 1298ce99f6b9SOr Gerlitz char *encap_header; 1299225aabafSOr Gerlitz int err, ttl = 0; 1300ce99f6b9SOr Gerlitz 1301225aabafSOr Gerlitz if (max_encap_size < ipv6_encap_size) { 1302225aabafSOr Gerlitz mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", 1303225aabafSOr Gerlitz ipv6_encap_size, max_encap_size); 1304225aabafSOr Gerlitz return -EOPNOTSUPP; 1305225aabafSOr Gerlitz } 1306225aabafSOr Gerlitz 1307225aabafSOr Gerlitz encap_header = kzalloc(ipv6_encap_size, GFP_KERNEL); 1308ce99f6b9SOr Gerlitz if (!encap_header) 1309ce99f6b9SOr Gerlitz return -ENOMEM; 1310ce99f6b9SOr Gerlitz 1311ce99f6b9SOr Gerlitz switch (e->tunnel_type) { 1312ce99f6b9SOr Gerlitz case MLX5_HEADER_TYPE_VXLAN: 1313ce99f6b9SOr Gerlitz fl6.flowi6_proto = IPPROTO_UDP; 1314ce99f6b9SOr Gerlitz fl6.fl6_dport = tun_key->tp_dst; 1315ce99f6b9SOr Gerlitz break; 1316ce99f6b9SOr Gerlitz default: 1317ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 1318ce99f6b9SOr Gerlitz goto out; 1319ce99f6b9SOr Gerlitz } 1320ce99f6b9SOr Gerlitz 1321ce99f6b9SOr Gerlitz fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tun_key->tos), tun_key->label); 1322ce99f6b9SOr Gerlitz fl6.daddr = tun_key->u.ipv6.dst; 1323ce99f6b9SOr Gerlitz fl6.saddr = tun_key->u.ipv6.src; 1324ce99f6b9SOr Gerlitz 13251a8552bdSHadar Hen Zion err = mlx5e_route_lookup_ipv6(priv, mirred_dev, &out_dev, 1326ce99f6b9SOr Gerlitz &fl6, &n, &ttl); 1327ce99f6b9SOr Gerlitz if (err) 1328ce99f6b9SOr Gerlitz goto out; 1329ce99f6b9SOr Gerlitz 1330ce99f6b9SOr Gerlitz if (!(n->nud_state & NUD_VALID)) { 1331ce99f6b9SOr Gerlitz pr_warn("%s: can't offload, neighbour to %pI6 invalid\n", __func__, &fl6.daddr); 1332ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 1333ce99f6b9SOr Gerlitz goto out; 1334ce99f6b9SOr Gerlitz } 1335ce99f6b9SOr Gerlitz 1336ce99f6b9SOr Gerlitz e->n = n; 13371a8552bdSHadar Hen Zion e->out_dev = out_dev; 1338ce99f6b9SOr Gerlitz 13391a8552bdSHadar Hen Zion neigh_ha_snapshot(e->h_dest, n, out_dev); 1340ce99f6b9SOr Gerlitz 1341ce99f6b9SOr Gerlitz switch (e->tunnel_type) { 1342ce99f6b9SOr Gerlitz case MLX5_HEADER_TYPE_VXLAN: 13431a8552bdSHadar Hen Zion gen_vxlan_header_ipv6(out_dev, encap_header, 1344225aabafSOr Gerlitz ipv6_encap_size, e->h_dest, ttl, 1345ce99f6b9SOr Gerlitz &fl6.daddr, 1346ce99f6b9SOr Gerlitz &fl6.saddr, tun_key->tp_dst, 1347ce99f6b9SOr Gerlitz tunnel_id_to_key32(tun_key->tun_id)); 1348ce99f6b9SOr Gerlitz break; 1349ce99f6b9SOr Gerlitz default: 1350ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 1351ce99f6b9SOr Gerlitz goto out; 1352ce99f6b9SOr Gerlitz } 1353ce99f6b9SOr Gerlitz 1354ce99f6b9SOr Gerlitz err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, 1355225aabafSOr Gerlitz ipv6_encap_size, encap_header, &e->encap_id); 1356ce99f6b9SOr Gerlitz out: 1357ce99f6b9SOr Gerlitz if (err && n) 1358ce99f6b9SOr Gerlitz neigh_release(n); 1359ce99f6b9SOr Gerlitz kfree(encap_header); 1360ce99f6b9SOr Gerlitz return err; 1361ce99f6b9SOr Gerlitz } 1362ce99f6b9SOr Gerlitz 1363a54e20b4SHadar Hen Zion static int mlx5e_attach_encap(struct mlx5e_priv *priv, 1364a54e20b4SHadar Hen Zion struct ip_tunnel_info *tun_info, 1365a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 136645247bf2SOr Gerlitz struct net_device **encap_dev, 136745247bf2SOr Gerlitz struct mlx5e_tc_flow *flow) 136803a9d11eSOr Gerlitz { 1369a54e20b4SHadar Hen Zion struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 13701ad9a00aSPaul Blakey struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw); 1371a54e20b4SHadar Hen Zion unsigned short family = ip_tunnel_info_af(tun_info); 137245247bf2SOr Gerlitz struct mlx5e_priv *up_priv = netdev_priv(up_dev); 137345247bf2SOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 1374a54e20b4SHadar Hen Zion struct ip_tunnel_key *key = &tun_info->key; 1375c1ae1152SOr Gerlitz struct mlx5e_encap_entry *e; 137645247bf2SOr Gerlitz int tunnel_type, err = 0; 1377a54e20b4SHadar Hen Zion uintptr_t hash_key; 1378a54e20b4SHadar Hen Zion bool found = false; 1379a54e20b4SHadar Hen Zion 13802fcd82e9SOr Gerlitz /* udp dst port must be set */ 1381a54e20b4SHadar Hen Zion if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst))) 13822fcd82e9SOr Gerlitz goto vxlan_encap_offload_err; 1383a54e20b4SHadar Hen Zion 1384cd377663SOr Gerlitz /* setting udp src port isn't supported */ 13852fcd82e9SOr Gerlitz if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) { 13862fcd82e9SOr Gerlitz vxlan_encap_offload_err: 13872fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 13882fcd82e9SOr Gerlitz "must set udp dst port and not set udp src port\n"); 1389cd377663SOr Gerlitz return -EOPNOTSUPP; 13902fcd82e9SOr Gerlitz } 1391cd377663SOr Gerlitz 13921ad9a00aSPaul Blakey if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->tp_dst)) && 1393a54e20b4SHadar Hen Zion MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) { 1394a54e20b4SHadar Hen Zion tunnel_type = MLX5_HEADER_TYPE_VXLAN; 1395a54e20b4SHadar Hen Zion } else { 13962fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 13972fcd82e9SOr Gerlitz "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst)); 1398a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 1399a54e20b4SHadar Hen Zion } 1400a54e20b4SHadar Hen Zion 140176f7444dSOr Gerlitz hash_key = hash_encap_info(key); 1402a54e20b4SHadar Hen Zion 1403a54e20b4SHadar Hen Zion hash_for_each_possible_rcu(esw->offloads.encap_tbl, e, 1404a54e20b4SHadar Hen Zion encap_hlist, hash_key) { 140576f7444dSOr Gerlitz if (!cmp_encap_info(&e->tun_info.key, key)) { 1406a54e20b4SHadar Hen Zion found = true; 1407a54e20b4SHadar Hen Zion break; 1408a54e20b4SHadar Hen Zion } 1409a54e20b4SHadar Hen Zion } 1410a54e20b4SHadar Hen Zion 141145247bf2SOr Gerlitz if (found) 141245247bf2SOr Gerlitz goto attach_flow; 1413a54e20b4SHadar Hen Zion 1414a54e20b4SHadar Hen Zion e = kzalloc(sizeof(*e), GFP_KERNEL); 1415a54e20b4SHadar Hen Zion if (!e) 1416a54e20b4SHadar Hen Zion return -ENOMEM; 1417a54e20b4SHadar Hen Zion 141876f7444dSOr Gerlitz e->tun_info = *tun_info; 1419a54e20b4SHadar Hen Zion e->tunnel_type = tunnel_type; 1420a54e20b4SHadar Hen Zion INIT_LIST_HEAD(&e->flows); 1421a54e20b4SHadar Hen Zion 1422ce99f6b9SOr Gerlitz if (family == AF_INET) 14231a8552bdSHadar Hen Zion err = mlx5e_create_encap_header_ipv4(priv, mirred_dev, e); 1424ce99f6b9SOr Gerlitz else if (family == AF_INET6) 14251a8552bdSHadar Hen Zion err = mlx5e_create_encap_header_ipv6(priv, mirred_dev, e); 1426ce99f6b9SOr Gerlitz 1427a54e20b4SHadar Hen Zion if (err) 1428a54e20b4SHadar Hen Zion goto out_err; 1429a54e20b4SHadar Hen Zion 1430a54e20b4SHadar Hen Zion hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key); 1431a54e20b4SHadar Hen Zion 143245247bf2SOr Gerlitz attach_flow: 143345247bf2SOr Gerlitz list_add(&flow->encap, &e->flows); 143445247bf2SOr Gerlitz *encap_dev = e->out_dev; 143545247bf2SOr Gerlitz attr->encap_id = e->encap_id; 143645247bf2SOr Gerlitz 143745247bf2SOr Gerlitz return 0; 1438a54e20b4SHadar Hen Zion 1439a54e20b4SHadar Hen Zion out_err: 1440a54e20b4SHadar Hen Zion kfree(e); 1441a54e20b4SHadar Hen Zion return err; 1442a54e20b4SHadar Hen Zion } 1443a54e20b4SHadar Hen Zion 1444a54e20b4SHadar Hen Zion static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 1445d7e75a32SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 1446a54e20b4SHadar Hen Zion struct mlx5e_tc_flow *flow) 1447a54e20b4SHadar Hen Zion { 1448ecf5bb79SOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 14491d447a39SSaeed Mahameed struct mlx5e_rep_priv *rpriv = priv->ppriv; 1450a54e20b4SHadar Hen Zion struct ip_tunnel_info *info = NULL; 145103a9d11eSOr Gerlitz const struct tc_action *a; 145222dc13c8SWANG Cong LIST_HEAD(actions); 1453a54e20b4SHadar Hen Zion bool encap = false; 1454a54e20b4SHadar Hen Zion int err; 145503a9d11eSOr Gerlitz 145603a9d11eSOr Gerlitz if (tc_no_actions(exts)) 145703a9d11eSOr Gerlitz return -EINVAL; 145803a9d11eSOr Gerlitz 1459776b12b6SOr Gerlitz memset(attr, 0, sizeof(*attr)); 14601d447a39SSaeed Mahameed attr->in_rep = rpriv->rep; 146103a9d11eSOr Gerlitz 146222dc13c8SWANG Cong tcf_exts_to_list(exts, &actions); 146322dc13c8SWANG Cong list_for_each_entry(a, &actions, list) { 146403a9d11eSOr Gerlitz if (is_tcf_gact_shot(a)) { 14658b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP | 146603a9d11eSOr Gerlitz MLX5_FLOW_CONTEXT_ACTION_COUNT; 146703a9d11eSOr Gerlitz continue; 146803a9d11eSOr Gerlitz } 146903a9d11eSOr Gerlitz 1470d7e75a32SOr Gerlitz if (is_tcf_pedit(a)) { 1471d7e75a32SOr Gerlitz err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_FDB, 1472d7e75a32SOr Gerlitz parse_attr); 1473d7e75a32SOr Gerlitz if (err) 1474d7e75a32SOr Gerlitz return err; 1475d7e75a32SOr Gerlitz 1476d7e75a32SOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; 1477d7e75a32SOr Gerlitz continue; 1478d7e75a32SOr Gerlitz } 1479d7e75a32SOr Gerlitz 14805724b8b5SShmulik Ladkani if (is_tcf_mirred_egress_redirect(a)) { 148103a9d11eSOr Gerlitz int ifindex = tcf_mirred_ifindex(a); 148245247bf2SOr Gerlitz struct net_device *out_dev, *encap_dev = NULL; 148303a9d11eSOr Gerlitz struct mlx5e_priv *out_priv; 148403a9d11eSOr Gerlitz 148503a9d11eSOr Gerlitz out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex); 148603a9d11eSOr Gerlitz 1487a54e20b4SHadar Hen Zion if (switchdev_port_same_parent_id(priv->netdev, 1488a54e20b4SHadar Hen Zion out_dev)) { 1489e37a79e5SMark Bloch attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1490e37a79e5SMark Bloch MLX5_FLOW_CONTEXT_ACTION_COUNT; 149103a9d11eSOr Gerlitz out_priv = netdev_priv(out_dev); 14921d447a39SSaeed Mahameed rpriv = out_priv->ppriv; 14931d447a39SSaeed Mahameed attr->out_rep = rpriv->rep; 1494a54e20b4SHadar Hen Zion } else if (encap) { 1495a54e20b4SHadar Hen Zion err = mlx5e_attach_encap(priv, info, 149645247bf2SOr Gerlitz out_dev, &encap_dev, flow); 1497a54e20b4SHadar Hen Zion if (err) 1498a54e20b4SHadar Hen Zion return err; 1499a54e20b4SHadar Hen Zion attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP | 1500a54e20b4SHadar Hen Zion MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1501a54e20b4SHadar Hen Zion MLX5_FLOW_CONTEXT_ACTION_COUNT; 150245247bf2SOr Gerlitz out_priv = netdev_priv(encap_dev); 15031d447a39SSaeed Mahameed rpriv = out_priv->ppriv; 15041d447a39SSaeed Mahameed attr->out_rep = rpriv->rep; 1505a54e20b4SHadar Hen Zion } else { 1506a54e20b4SHadar Hen Zion pr_err("devices %s %s not on same switch HW, can't offload forwarding\n", 1507a54e20b4SHadar Hen Zion priv->netdev->name, out_dev->name); 1508a54e20b4SHadar Hen Zion return -EINVAL; 1509a54e20b4SHadar Hen Zion } 1510a54e20b4SHadar Hen Zion continue; 1511a54e20b4SHadar Hen Zion } 1512a54e20b4SHadar Hen Zion 1513a54e20b4SHadar Hen Zion if (is_tcf_tunnel_set(a)) { 1514a54e20b4SHadar Hen Zion info = tcf_tunnel_info(a); 1515a54e20b4SHadar Hen Zion if (info) 1516a54e20b4SHadar Hen Zion encap = true; 1517a54e20b4SHadar Hen Zion else 1518a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 151903a9d11eSOr Gerlitz continue; 152003a9d11eSOr Gerlitz } 152103a9d11eSOr Gerlitz 15228b32580dSOr Gerlitz if (is_tcf_vlan(a)) { 152309c91ddfSOr Gerlitz if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { 15248b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 152509c91ddfSOr Gerlitz } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { 15268b32580dSOr Gerlitz if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q)) 15278b32580dSOr Gerlitz return -EOPNOTSUPP; 15288b32580dSOr Gerlitz 15298b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; 15308b32580dSOr Gerlitz attr->vlan = tcf_vlan_push_vid(a); 153109c91ddfSOr Gerlitz } else { /* action is TCA_VLAN_ACT_MODIFY */ 153209c91ddfSOr Gerlitz return -EOPNOTSUPP; 15338b32580dSOr Gerlitz } 15348b32580dSOr Gerlitz continue; 15358b32580dSOr Gerlitz } 15368b32580dSOr Gerlitz 1537bbd00f7eSHadar Hen Zion if (is_tcf_tunnel_release(a)) { 1538bbd00f7eSHadar Hen Zion attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; 1539bbd00f7eSHadar Hen Zion continue; 1540bbd00f7eSHadar Hen Zion } 1541bbd00f7eSHadar Hen Zion 154203a9d11eSOr Gerlitz return -EINVAL; 154303a9d11eSOr Gerlitz } 154403a9d11eSOr Gerlitz return 0; 154503a9d11eSOr Gerlitz } 154603a9d11eSOr Gerlitz 1547e3a2b7edSAmir Vadai int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, 1548e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 1549e3a2b7edSAmir Vadai { 1550adb4c123SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 155117091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr; 15523bc4b7bfSOr Gerlitz struct mlx5e_tc_table *tc = &priv->fs.tc; 15533bc4b7bfSOr Gerlitz struct mlx5e_tc_flow *flow; 15543bc4b7bfSOr Gerlitz int attr_size, err = 0; 155565ba8fb7SOr Gerlitz u8 flow_flags = 0; 1556e3a2b7edSAmir Vadai 155765ba8fb7SOr Gerlitz if (esw && esw->mode == SRIOV_OFFLOADS) { 155865ba8fb7SOr Gerlitz flow_flags = MLX5E_TC_FLOW_ESWITCH; 155965ba8fb7SOr Gerlitz attr_size = sizeof(struct mlx5_esw_flow_attr); 15603bc4b7bfSOr Gerlitz } else { 15613bc4b7bfSOr Gerlitz flow_flags = MLX5E_TC_FLOW_NIC; 15623bc4b7bfSOr Gerlitz attr_size = sizeof(struct mlx5_nic_flow_attr); 156365ba8fb7SOr Gerlitz } 1564776b12b6SOr Gerlitz 156565ba8fb7SOr Gerlitz flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL); 156617091853SOr Gerlitz parse_attr = mlx5_vzalloc(sizeof(*parse_attr)); 156717091853SOr Gerlitz if (!parse_attr || !flow) { 1568e3a2b7edSAmir Vadai err = -ENOMEM; 1569e3a2b7edSAmir Vadai goto err_free; 1570e3a2b7edSAmir Vadai } 1571e3a2b7edSAmir Vadai 1572e3a2b7edSAmir Vadai flow->cookie = f->cookie; 157365ba8fb7SOr Gerlitz flow->flags = flow_flags; 1574e3a2b7edSAmir Vadai 157517091853SOr Gerlitz err = parse_cls_flower(priv, flow, &parse_attr->spec, f); 1576e3a2b7edSAmir Vadai if (err < 0) 1577e3a2b7edSAmir Vadai goto err_free; 1578e3a2b7edSAmir Vadai 157965ba8fb7SOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { 1580d7e75a32SOr Gerlitz err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow); 1581adb4c123SOr Gerlitz if (err < 0) 1582adb4c123SOr Gerlitz goto err_free; 1583aa0cbbaeSOr Gerlitz flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow); 1584adb4c123SOr Gerlitz } else { 1585aa0cbbaeSOr Gerlitz err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow); 1586e3a2b7edSAmir Vadai if (err < 0) 1587e3a2b7edSAmir Vadai goto err_free; 1588aa0cbbaeSOr Gerlitz flow->rule = mlx5e_tc_add_nic_flow(priv, parse_attr, flow); 1589adb4c123SOr Gerlitz } 1590adb4c123SOr Gerlitz 15915c40348cSOr Gerlitz if (IS_ERR(flow->rule)) { 15925c40348cSOr Gerlitz err = PTR_ERR(flow->rule); 1593aa0cbbaeSOr Gerlitz goto err_free; 15945c40348cSOr Gerlitz } 15955c40348cSOr Gerlitz 15960b67a38fSHadar Hen Zion flow->flags |= MLX5E_TC_FLOW_OFFLOADED; 1597e3a2b7edSAmir Vadai err = rhashtable_insert_fast(&tc->ht, &flow->node, 1598e3a2b7edSAmir Vadai tc->ht_params); 1599e3a2b7edSAmir Vadai if (err) 16005c40348cSOr Gerlitz goto err_del_rule; 1601e3a2b7edSAmir Vadai 1602e3a2b7edSAmir Vadai goto out; 1603e3a2b7edSAmir Vadai 16045c40348cSOr Gerlitz err_del_rule: 16055e86397aSOr Gerlitz mlx5e_tc_del_flow(priv, flow); 1606e3a2b7edSAmir Vadai 1607e3a2b7edSAmir Vadai err_free: 1608e3a2b7edSAmir Vadai kfree(flow); 1609e3a2b7edSAmir Vadai out: 161017091853SOr Gerlitz kvfree(parse_attr); 1611e3a2b7edSAmir Vadai return err; 1612e3a2b7edSAmir Vadai } 1613e3a2b7edSAmir Vadai 1614e3a2b7edSAmir Vadai int mlx5e_delete_flower(struct mlx5e_priv *priv, 1615e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 1616e3a2b7edSAmir Vadai { 1617e3a2b7edSAmir Vadai struct mlx5e_tc_flow *flow; 1618acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 1619e3a2b7edSAmir Vadai 1620e3a2b7edSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 1621e3a2b7edSAmir Vadai tc->ht_params); 1622e3a2b7edSAmir Vadai if (!flow) 1623e3a2b7edSAmir Vadai return -EINVAL; 1624e3a2b7edSAmir Vadai 1625e3a2b7edSAmir Vadai rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params); 1626e3a2b7edSAmir Vadai 1627961e8979SRoi Dayan mlx5e_tc_del_flow(priv, flow); 1628e3a2b7edSAmir Vadai 1629a54e20b4SHadar Hen Zion 1630e3a2b7edSAmir Vadai kfree(flow); 1631e3a2b7edSAmir Vadai 1632e3a2b7edSAmir Vadai return 0; 1633e3a2b7edSAmir Vadai } 1634e3a2b7edSAmir Vadai 1635aad7e08dSAmir Vadai int mlx5e_stats_flower(struct mlx5e_priv *priv, 1636aad7e08dSAmir Vadai struct tc_cls_flower_offload *f) 1637aad7e08dSAmir Vadai { 1638aad7e08dSAmir Vadai struct mlx5e_tc_table *tc = &priv->fs.tc; 1639aad7e08dSAmir Vadai struct mlx5e_tc_flow *flow; 1640aad7e08dSAmir Vadai struct tc_action *a; 1641aad7e08dSAmir Vadai struct mlx5_fc *counter; 164222dc13c8SWANG Cong LIST_HEAD(actions); 1643aad7e08dSAmir Vadai u64 bytes; 1644aad7e08dSAmir Vadai u64 packets; 1645aad7e08dSAmir Vadai u64 lastuse; 1646aad7e08dSAmir Vadai 1647aad7e08dSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 1648aad7e08dSAmir Vadai tc->ht_params); 1649aad7e08dSAmir Vadai if (!flow) 1650aad7e08dSAmir Vadai return -EINVAL; 1651aad7e08dSAmir Vadai 16520b67a38fSHadar Hen Zion if (!(flow->flags & MLX5E_TC_FLOW_OFFLOADED)) 16530b67a38fSHadar Hen Zion return 0; 16540b67a38fSHadar Hen Zion 1655aad7e08dSAmir Vadai counter = mlx5_flow_rule_counter(flow->rule); 1656aad7e08dSAmir Vadai if (!counter) 1657aad7e08dSAmir Vadai return 0; 1658aad7e08dSAmir Vadai 1659aad7e08dSAmir Vadai mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); 1660aad7e08dSAmir Vadai 1661fed06ee8SOr Gerlitz preempt_disable(); 1662fed06ee8SOr Gerlitz 166322dc13c8SWANG Cong tcf_exts_to_list(f->exts, &actions); 166422dc13c8SWANG Cong list_for_each_entry(a, &actions, list) 1665aad7e08dSAmir Vadai tcf_action_stats_update(a, bytes, packets, lastuse); 1666aad7e08dSAmir Vadai 1667fed06ee8SOr Gerlitz preempt_enable(); 1668fed06ee8SOr Gerlitz 1669aad7e08dSAmir Vadai return 0; 1670aad7e08dSAmir Vadai } 1671aad7e08dSAmir Vadai 1672e8f887acSAmir Vadai static const struct rhashtable_params mlx5e_tc_flow_ht_params = { 1673e8f887acSAmir Vadai .head_offset = offsetof(struct mlx5e_tc_flow, node), 1674e8f887acSAmir Vadai .key_offset = offsetof(struct mlx5e_tc_flow, cookie), 1675e8f887acSAmir Vadai .key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie), 1676e8f887acSAmir Vadai .automatic_shrinking = true, 1677e8f887acSAmir Vadai }; 1678e8f887acSAmir Vadai 1679e8f887acSAmir Vadai int mlx5e_tc_init(struct mlx5e_priv *priv) 1680e8f887acSAmir Vadai { 1681acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 1682e8f887acSAmir Vadai 1683e8f887acSAmir Vadai tc->ht_params = mlx5e_tc_flow_ht_params; 1684e8f887acSAmir Vadai return rhashtable_init(&tc->ht, &tc->ht_params); 1685e8f887acSAmir Vadai } 1686e8f887acSAmir Vadai 1687e8f887acSAmir Vadai static void _mlx5e_tc_del_flow(void *ptr, void *arg) 1688e8f887acSAmir Vadai { 1689e8f887acSAmir Vadai struct mlx5e_tc_flow *flow = ptr; 1690e8f887acSAmir Vadai struct mlx5e_priv *priv = arg; 1691e8f887acSAmir Vadai 1692961e8979SRoi Dayan mlx5e_tc_del_flow(priv, flow); 1693e8f887acSAmir Vadai kfree(flow); 1694e8f887acSAmir Vadai } 1695e8f887acSAmir Vadai 1696e8f887acSAmir Vadai void mlx5e_tc_cleanup(struct mlx5e_priv *priv) 1697e8f887acSAmir Vadai { 1698acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 1699e8f887acSAmir Vadai 1700e8f887acSAmir Vadai rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv); 1701e8f887acSAmir Vadai 1702acff797cSMaor Gottlieb if (!IS_ERR_OR_NULL(tc->t)) { 1703acff797cSMaor Gottlieb mlx5_destroy_flow_table(tc->t); 1704acff797cSMaor Gottlieb tc->t = NULL; 1705e8f887acSAmir Vadai } 1706e8f887acSAmir Vadai } 1707