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> 4626c02749SOr Gerlitz #include <net/tc_act/tc_csum.h> 47a54e20b4SHadar Hen Zion #include <net/vxlan.h> 48f6dfb4c3SHadar Hen Zion #include <net/arp.h> 49e8f887acSAmir Vadai #include "en.h" 501d447a39SSaeed Mahameed #include "en_rep.h" 51232c0013SHadar Hen Zion #include "en_tc.h" 5203a9d11eSOr Gerlitz #include "eswitch.h" 53bbd00f7eSHadar Hen Zion #include "vxlan.h" 54e8f887acSAmir Vadai 553bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr { 563bc4b7bfSOr Gerlitz u32 action; 573bc4b7bfSOr Gerlitz u32 flow_tag; 582f4fe4caSOr Gerlitz u32 mod_hdr_id; 593bc4b7bfSOr Gerlitz }; 603bc4b7bfSOr Gerlitz 6165ba8fb7SOr Gerlitz enum { 6265ba8fb7SOr Gerlitz MLX5E_TC_FLOW_ESWITCH = BIT(0), 633bc4b7bfSOr Gerlitz MLX5E_TC_FLOW_NIC = BIT(1), 640b67a38fSHadar Hen Zion MLX5E_TC_FLOW_OFFLOADED = BIT(2), 6565ba8fb7SOr Gerlitz }; 6665ba8fb7SOr Gerlitz 67e8f887acSAmir Vadai struct mlx5e_tc_flow { 68e8f887acSAmir Vadai struct rhash_head node; 69e8f887acSAmir Vadai u64 cookie; 7065ba8fb7SOr Gerlitz u8 flags; 7174491de9SMark Bloch struct mlx5_flow_handle *rule; 7211c9c548SOr Gerlitz struct list_head encap; /* flows sharing the same encap ID */ 7311c9c548SOr Gerlitz struct list_head mod_hdr; /* flows sharing the same mod hdr ID */ 743bc4b7bfSOr Gerlitz union { 75ecf5bb79SOr Gerlitz struct mlx5_esw_flow_attr esw_attr[0]; 763bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr nic_attr[0]; 773bc4b7bfSOr Gerlitz }; 78e8f887acSAmir Vadai }; 79e8f887acSAmir Vadai 8017091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr { 8117091853SOr Gerlitz struct mlx5_flow_spec spec; 82d79b6df6SOr Gerlitz int num_mod_hdr_actions; 83d79b6df6SOr Gerlitz void *mod_hdr_actions; 8417091853SOr Gerlitz }; 8517091853SOr Gerlitz 86a54e20b4SHadar Hen Zion enum { 87a54e20b4SHadar Hen Zion MLX5_HEADER_TYPE_VXLAN = 0x0, 88a54e20b4SHadar Hen Zion MLX5_HEADER_TYPE_NVGRE = 0x1, 89a54e20b4SHadar Hen Zion }; 90a54e20b4SHadar Hen Zion 91acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_ENTRIES 1024 92acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_GROUPS 4 93e8f887acSAmir Vadai 9411c9c548SOr Gerlitz struct mod_hdr_key { 9511c9c548SOr Gerlitz int num_actions; 9611c9c548SOr Gerlitz void *actions; 9711c9c548SOr Gerlitz }; 9811c9c548SOr Gerlitz 9911c9c548SOr Gerlitz struct mlx5e_mod_hdr_entry { 10011c9c548SOr Gerlitz /* a node of a hash table which keeps all the mod_hdr entries */ 10111c9c548SOr Gerlitz struct hlist_node mod_hdr_hlist; 10211c9c548SOr Gerlitz 10311c9c548SOr Gerlitz /* flows sharing the same mod_hdr entry */ 10411c9c548SOr Gerlitz struct list_head flows; 10511c9c548SOr Gerlitz 10611c9c548SOr Gerlitz struct mod_hdr_key key; 10711c9c548SOr Gerlitz 10811c9c548SOr Gerlitz u32 mod_hdr_id; 10911c9c548SOr Gerlitz }; 11011c9c548SOr Gerlitz 11111c9c548SOr Gerlitz #define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto) 11211c9c548SOr Gerlitz 11311c9c548SOr Gerlitz static inline u32 hash_mod_hdr_info(struct mod_hdr_key *key) 11411c9c548SOr Gerlitz { 11511c9c548SOr Gerlitz return jhash(key->actions, 11611c9c548SOr Gerlitz key->num_actions * MLX5_MH_ACT_SZ, 0); 11711c9c548SOr Gerlitz } 11811c9c548SOr Gerlitz 11911c9c548SOr Gerlitz static inline int cmp_mod_hdr_info(struct mod_hdr_key *a, 12011c9c548SOr Gerlitz struct mod_hdr_key *b) 12111c9c548SOr Gerlitz { 12211c9c548SOr Gerlitz if (a->num_actions != b->num_actions) 12311c9c548SOr Gerlitz return 1; 12411c9c548SOr Gerlitz 12511c9c548SOr Gerlitz return memcmp(a->actions, b->actions, a->num_actions * MLX5_MH_ACT_SZ); 12611c9c548SOr Gerlitz } 12711c9c548SOr Gerlitz 12811c9c548SOr Gerlitz static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv, 12911c9c548SOr Gerlitz struct mlx5e_tc_flow *flow, 13011c9c548SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr) 13111c9c548SOr Gerlitz { 13211c9c548SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 13311c9c548SOr Gerlitz int num_actions, actions_size, namespace, err; 13411c9c548SOr Gerlitz struct mlx5e_mod_hdr_entry *mh; 13511c9c548SOr Gerlitz struct mod_hdr_key key; 13611c9c548SOr Gerlitz bool found = false; 13711c9c548SOr Gerlitz u32 hash_key; 13811c9c548SOr Gerlitz 13911c9c548SOr Gerlitz num_actions = parse_attr->num_mod_hdr_actions; 14011c9c548SOr Gerlitz actions_size = MLX5_MH_ACT_SZ * num_actions; 14111c9c548SOr Gerlitz 14211c9c548SOr Gerlitz key.actions = parse_attr->mod_hdr_actions; 14311c9c548SOr Gerlitz key.num_actions = num_actions; 14411c9c548SOr Gerlitz 14511c9c548SOr Gerlitz hash_key = hash_mod_hdr_info(&key); 14611c9c548SOr Gerlitz 14711c9c548SOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { 14811c9c548SOr Gerlitz namespace = MLX5_FLOW_NAMESPACE_FDB; 14911c9c548SOr Gerlitz hash_for_each_possible(esw->offloads.mod_hdr_tbl, mh, 15011c9c548SOr Gerlitz mod_hdr_hlist, hash_key) { 15111c9c548SOr Gerlitz if (!cmp_mod_hdr_info(&mh->key, &key)) { 15211c9c548SOr Gerlitz found = true; 15311c9c548SOr Gerlitz break; 15411c9c548SOr Gerlitz } 15511c9c548SOr Gerlitz } 15611c9c548SOr Gerlitz } else { 15711c9c548SOr Gerlitz namespace = MLX5_FLOW_NAMESPACE_KERNEL; 15811c9c548SOr Gerlitz hash_for_each_possible(priv->fs.tc.mod_hdr_tbl, mh, 15911c9c548SOr Gerlitz mod_hdr_hlist, hash_key) { 16011c9c548SOr Gerlitz if (!cmp_mod_hdr_info(&mh->key, &key)) { 16111c9c548SOr Gerlitz found = true; 16211c9c548SOr Gerlitz break; 16311c9c548SOr Gerlitz } 16411c9c548SOr Gerlitz } 16511c9c548SOr Gerlitz } 16611c9c548SOr Gerlitz 16711c9c548SOr Gerlitz if (found) 16811c9c548SOr Gerlitz goto attach_flow; 16911c9c548SOr Gerlitz 17011c9c548SOr Gerlitz mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL); 17111c9c548SOr Gerlitz if (!mh) 17211c9c548SOr Gerlitz return -ENOMEM; 17311c9c548SOr Gerlitz 17411c9c548SOr Gerlitz mh->key.actions = (void *)mh + sizeof(*mh); 17511c9c548SOr Gerlitz memcpy(mh->key.actions, key.actions, actions_size); 17611c9c548SOr Gerlitz mh->key.num_actions = num_actions; 17711c9c548SOr Gerlitz INIT_LIST_HEAD(&mh->flows); 17811c9c548SOr Gerlitz 17911c9c548SOr Gerlitz err = mlx5_modify_header_alloc(priv->mdev, namespace, 18011c9c548SOr Gerlitz mh->key.num_actions, 18111c9c548SOr Gerlitz mh->key.actions, 18211c9c548SOr Gerlitz &mh->mod_hdr_id); 18311c9c548SOr Gerlitz if (err) 18411c9c548SOr Gerlitz goto out_err; 18511c9c548SOr Gerlitz 18611c9c548SOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) 18711c9c548SOr Gerlitz hash_add(esw->offloads.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key); 18811c9c548SOr Gerlitz else 18911c9c548SOr Gerlitz hash_add(priv->fs.tc.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key); 19011c9c548SOr Gerlitz 19111c9c548SOr Gerlitz attach_flow: 19211c9c548SOr Gerlitz list_add(&flow->mod_hdr, &mh->flows); 19311c9c548SOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) 19411c9c548SOr Gerlitz flow->esw_attr->mod_hdr_id = mh->mod_hdr_id; 19511c9c548SOr Gerlitz else 19611c9c548SOr Gerlitz flow->nic_attr->mod_hdr_id = mh->mod_hdr_id; 19711c9c548SOr Gerlitz 19811c9c548SOr Gerlitz return 0; 19911c9c548SOr Gerlitz 20011c9c548SOr Gerlitz out_err: 20111c9c548SOr Gerlitz kfree(mh); 20211c9c548SOr Gerlitz return err; 20311c9c548SOr Gerlitz } 20411c9c548SOr Gerlitz 20511c9c548SOr Gerlitz static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv, 20611c9c548SOr Gerlitz struct mlx5e_tc_flow *flow) 20711c9c548SOr Gerlitz { 20811c9c548SOr Gerlitz struct list_head *next = flow->mod_hdr.next; 20911c9c548SOr Gerlitz 21011c9c548SOr Gerlitz list_del(&flow->mod_hdr); 21111c9c548SOr Gerlitz 21211c9c548SOr Gerlitz if (list_empty(next)) { 21311c9c548SOr Gerlitz struct mlx5e_mod_hdr_entry *mh; 21411c9c548SOr Gerlitz 21511c9c548SOr Gerlitz mh = list_entry(next, struct mlx5e_mod_hdr_entry, flows); 21611c9c548SOr Gerlitz 21711c9c548SOr Gerlitz mlx5_modify_header_dealloc(priv->mdev, mh->mod_hdr_id); 21811c9c548SOr Gerlitz hash_del(&mh->mod_hdr_hlist); 21911c9c548SOr Gerlitz kfree(mh); 22011c9c548SOr Gerlitz } 22111c9c548SOr Gerlitz } 22211c9c548SOr Gerlitz 22374491de9SMark Bloch static struct mlx5_flow_handle * 22474491de9SMark Bloch mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, 22517091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 226aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow) 227e8f887acSAmir Vadai { 228aa0cbbaeSOr Gerlitz struct mlx5_nic_flow_attr *attr = flow->nic_attr; 229aad7e08dSAmir Vadai struct mlx5_core_dev *dev = priv->mdev; 230aa0cbbaeSOr Gerlitz struct mlx5_flow_destination dest = {}; 23166958ed9SHadar Hen Zion struct mlx5_flow_act flow_act = { 2323bc4b7bfSOr Gerlitz .action = attr->action, 2333bc4b7bfSOr Gerlitz .flow_tag = attr->flow_tag, 23466958ed9SHadar Hen Zion .encap_id = 0, 23566958ed9SHadar Hen Zion }; 236aad7e08dSAmir Vadai struct mlx5_fc *counter = NULL; 23774491de9SMark Bloch struct mlx5_flow_handle *rule; 238e8f887acSAmir Vadai bool table_created = false; 2392f4fe4caSOr Gerlitz int err; 240e8f887acSAmir Vadai 2413bc4b7bfSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 242aad7e08dSAmir Vadai dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 243aad7e08dSAmir Vadai dest.ft = priv->fs.vlan.ft.t; 2443bc4b7bfSOr Gerlitz } else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 245aad7e08dSAmir Vadai counter = mlx5_fc_create(dev, true); 246aad7e08dSAmir Vadai if (IS_ERR(counter)) 247aad7e08dSAmir Vadai return ERR_CAST(counter); 248aad7e08dSAmir Vadai 249aad7e08dSAmir Vadai dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 250aad7e08dSAmir Vadai dest.counter = counter; 251aad7e08dSAmir Vadai } 252aad7e08dSAmir Vadai 2532f4fe4caSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { 2543099eb5aSOr Gerlitz err = mlx5e_attach_mod_hdr(priv, flow, parse_attr); 255d7e75a32SOr Gerlitz flow_act.modify_id = attr->mod_hdr_id; 2562f4fe4caSOr Gerlitz kfree(parse_attr->mod_hdr_actions); 2572f4fe4caSOr Gerlitz if (err) { 2582f4fe4caSOr Gerlitz rule = ERR_PTR(err); 2592f4fe4caSOr Gerlitz goto err_create_mod_hdr_id; 2602f4fe4caSOr Gerlitz } 2612f4fe4caSOr Gerlitz } 2622f4fe4caSOr Gerlitz 263acff797cSMaor Gottlieb if (IS_ERR_OR_NULL(priv->fs.tc.t)) { 264acff797cSMaor Gottlieb priv->fs.tc.t = 265acff797cSMaor Gottlieb mlx5_create_auto_grouped_flow_table(priv->fs.ns, 266acff797cSMaor Gottlieb MLX5E_TC_PRIO, 267acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_ENTRIES, 268acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_GROUPS, 269c9f1b073SHadar Hen Zion 0, 0); 270acff797cSMaor Gottlieb if (IS_ERR(priv->fs.tc.t)) { 271e8f887acSAmir Vadai netdev_err(priv->netdev, 272e8f887acSAmir Vadai "Failed to create tc offload table\n"); 273aad7e08dSAmir Vadai rule = ERR_CAST(priv->fs.tc.t); 274aad7e08dSAmir Vadai goto err_create_ft; 275e8f887acSAmir Vadai } 276e8f887acSAmir Vadai 277e8f887acSAmir Vadai table_created = true; 278e8f887acSAmir Vadai } 279e8f887acSAmir Vadai 28017091853SOr Gerlitz parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 28117091853SOr Gerlitz rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec, 28217091853SOr Gerlitz &flow_act, &dest, 1); 283e8f887acSAmir Vadai 284aad7e08dSAmir Vadai if (IS_ERR(rule)) 285aad7e08dSAmir Vadai goto err_add_rule; 286aad7e08dSAmir Vadai 287aad7e08dSAmir Vadai return rule; 288aad7e08dSAmir Vadai 289aad7e08dSAmir Vadai err_add_rule: 290aad7e08dSAmir Vadai if (table_created) { 291acff797cSMaor Gottlieb mlx5_destroy_flow_table(priv->fs.tc.t); 292acff797cSMaor Gottlieb priv->fs.tc.t = NULL; 293e8f887acSAmir Vadai } 294aad7e08dSAmir Vadai err_create_ft: 2952f4fe4caSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 2963099eb5aSOr Gerlitz mlx5e_detach_mod_hdr(priv, flow); 2972f4fe4caSOr Gerlitz err_create_mod_hdr_id: 298aad7e08dSAmir Vadai mlx5_fc_destroy(dev, counter); 299e8f887acSAmir Vadai 300e8f887acSAmir Vadai return rule; 301e8f887acSAmir Vadai } 302e8f887acSAmir Vadai 303d85cdccbSOr Gerlitz static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, 304d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 305d85cdccbSOr Gerlitz { 306513f8f7fSOr Gerlitz struct mlx5_nic_flow_attr *attr = flow->nic_attr; 307d85cdccbSOr Gerlitz struct mlx5_fc *counter = NULL; 308d85cdccbSOr Gerlitz 309d85cdccbSOr Gerlitz counter = mlx5_flow_rule_counter(flow->rule); 310d85cdccbSOr Gerlitz mlx5_del_flow_rules(flow->rule); 311d85cdccbSOr Gerlitz mlx5_fc_destroy(priv->mdev, counter); 312d85cdccbSOr Gerlitz 313d85cdccbSOr Gerlitz if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) { 314d85cdccbSOr Gerlitz mlx5_destroy_flow_table(priv->fs.tc.t); 315d85cdccbSOr Gerlitz priv->fs.tc.t = NULL; 316d85cdccbSOr Gerlitz } 3172f4fe4caSOr Gerlitz 318513f8f7fSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 3193099eb5aSOr Gerlitz mlx5e_detach_mod_hdr(priv, flow); 320d85cdccbSOr Gerlitz } 321d85cdccbSOr Gerlitz 322aa0cbbaeSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv, 323aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow); 324aa0cbbaeSOr Gerlitz 32574491de9SMark Bloch static struct mlx5_flow_handle * 32674491de9SMark Bloch mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, 32717091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 328aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow) 329adb4c123SOr Gerlitz { 330adb4c123SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 331aa0cbbaeSOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 332aa0cbbaeSOr Gerlitz struct mlx5_flow_handle *rule; 3338b32580dSOr Gerlitz int err; 3348b32580dSOr Gerlitz 3358b32580dSOr Gerlitz err = mlx5_eswitch_add_vlan_action(esw, attr); 336aa0cbbaeSOr Gerlitz if (err) { 337aa0cbbaeSOr Gerlitz rule = ERR_PTR(err); 338aa0cbbaeSOr Gerlitz goto err_add_vlan; 339adb4c123SOr Gerlitz } 340adb4c123SOr Gerlitz 341d7e75a32SOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { 3421a9527bbSOr Gerlitz err = mlx5e_attach_mod_hdr(priv, flow, parse_attr); 343d7e75a32SOr Gerlitz kfree(parse_attr->mod_hdr_actions); 344d7e75a32SOr Gerlitz if (err) { 345d7e75a32SOr Gerlitz rule = ERR_PTR(err); 346d7e75a32SOr Gerlitz goto err_mod_hdr; 347d7e75a32SOr Gerlitz } 348d7e75a32SOr Gerlitz } 349d7e75a32SOr Gerlitz 350aa0cbbaeSOr Gerlitz rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); 351aa0cbbaeSOr Gerlitz if (IS_ERR(rule)) 352aa0cbbaeSOr Gerlitz goto err_add_rule; 353aa0cbbaeSOr Gerlitz 354aa0cbbaeSOr Gerlitz return rule; 355aa0cbbaeSOr Gerlitz 356aa0cbbaeSOr Gerlitz err_add_rule: 357513f8f7fSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 3581a9527bbSOr Gerlitz mlx5e_detach_mod_hdr(priv, flow); 359d7e75a32SOr Gerlitz err_mod_hdr: 360aa0cbbaeSOr Gerlitz mlx5_eswitch_del_vlan_action(esw, attr); 361aa0cbbaeSOr Gerlitz err_add_vlan: 362aa0cbbaeSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) 363aa0cbbaeSOr Gerlitz mlx5e_detach_encap(priv, flow); 364aa0cbbaeSOr Gerlitz return rule; 365aa0cbbaeSOr Gerlitz } 366d85cdccbSOr Gerlitz 367d85cdccbSOr Gerlitz static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, 368d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 369d85cdccbSOr Gerlitz { 370d85cdccbSOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 371d7e75a32SOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 372d85cdccbSOr Gerlitz 373232c0013SHadar Hen Zion if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { 374232c0013SHadar Hen Zion flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; 375513f8f7fSOr Gerlitz mlx5_eswitch_del_offloaded_rule(esw, flow->rule, attr); 376232c0013SHadar Hen Zion } 377d85cdccbSOr Gerlitz 378513f8f7fSOr Gerlitz mlx5_eswitch_del_vlan_action(esw, attr); 379d85cdccbSOr Gerlitz 380513f8f7fSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) { 381d85cdccbSOr Gerlitz mlx5e_detach_encap(priv, flow); 382513f8f7fSOr Gerlitz kvfree(attr->parse_attr); 383232c0013SHadar Hen Zion } 384d7e75a32SOr Gerlitz 385513f8f7fSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) 3861a9527bbSOr Gerlitz mlx5e_detach_mod_hdr(priv, flow); 387d85cdccbSOr Gerlitz } 388d85cdccbSOr Gerlitz 389232c0013SHadar Hen Zion void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, 390232c0013SHadar Hen Zion struct mlx5e_encap_entry *e) 391232c0013SHadar Hen Zion { 392232c0013SHadar Hen Zion struct mlx5e_tc_flow *flow; 393232c0013SHadar Hen Zion int err; 394232c0013SHadar Hen Zion 395232c0013SHadar Hen Zion err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, 396232c0013SHadar Hen Zion e->encap_size, e->encap_header, 397232c0013SHadar Hen Zion &e->encap_id); 398232c0013SHadar Hen Zion if (err) { 399232c0013SHadar Hen Zion mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %d\n", 400232c0013SHadar Hen Zion err); 401232c0013SHadar Hen Zion return; 402232c0013SHadar Hen Zion } 403232c0013SHadar Hen Zion e->flags |= MLX5_ENCAP_ENTRY_VALID; 404f6dfb4c3SHadar Hen Zion mlx5e_rep_queue_neigh_stats_work(priv); 405232c0013SHadar Hen Zion 406232c0013SHadar Hen Zion list_for_each_entry(flow, &e->flows, encap) { 407232c0013SHadar Hen Zion flow->esw_attr->encap_id = e->encap_id; 408232c0013SHadar Hen Zion flow->rule = mlx5e_tc_add_fdb_flow(priv, 409232c0013SHadar Hen Zion flow->esw_attr->parse_attr, 410232c0013SHadar Hen Zion flow); 411232c0013SHadar Hen Zion if (IS_ERR(flow->rule)) { 412232c0013SHadar Hen Zion err = PTR_ERR(flow->rule); 413232c0013SHadar Hen Zion mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n", 414232c0013SHadar Hen Zion err); 415232c0013SHadar Hen Zion continue; 416232c0013SHadar Hen Zion } 417232c0013SHadar Hen Zion flow->flags |= MLX5E_TC_FLOW_OFFLOADED; 418232c0013SHadar Hen Zion } 419232c0013SHadar Hen Zion } 420232c0013SHadar Hen Zion 421232c0013SHadar Hen Zion void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, 422232c0013SHadar Hen Zion struct mlx5e_encap_entry *e) 423232c0013SHadar Hen Zion { 424232c0013SHadar Hen Zion struct mlx5e_tc_flow *flow; 425232c0013SHadar Hen Zion struct mlx5_fc *counter; 426232c0013SHadar Hen Zion 427232c0013SHadar Hen Zion list_for_each_entry(flow, &e->flows, encap) { 428232c0013SHadar Hen Zion if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { 429232c0013SHadar Hen Zion flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; 430232c0013SHadar Hen Zion counter = mlx5_flow_rule_counter(flow->rule); 431232c0013SHadar Hen Zion mlx5_del_flow_rules(flow->rule); 432232c0013SHadar Hen Zion mlx5_fc_destroy(priv->mdev, counter); 433232c0013SHadar Hen Zion } 434232c0013SHadar Hen Zion } 435232c0013SHadar Hen Zion 436232c0013SHadar Hen Zion if (e->flags & MLX5_ENCAP_ENTRY_VALID) { 437232c0013SHadar Hen Zion e->flags &= ~MLX5_ENCAP_ENTRY_VALID; 438232c0013SHadar Hen Zion mlx5_encap_dealloc(priv->mdev, e->encap_id); 439232c0013SHadar Hen Zion } 440232c0013SHadar Hen Zion } 441232c0013SHadar Hen Zion 442f6dfb4c3SHadar Hen Zion void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) 443f6dfb4c3SHadar Hen Zion { 444f6dfb4c3SHadar Hen Zion struct mlx5e_neigh *m_neigh = &nhe->m_neigh; 445f6dfb4c3SHadar Hen Zion u64 bytes, packets, lastuse = 0; 446f6dfb4c3SHadar Hen Zion struct mlx5e_tc_flow *flow; 447f6dfb4c3SHadar Hen Zion struct mlx5e_encap_entry *e; 448f6dfb4c3SHadar Hen Zion struct mlx5_fc *counter; 449f6dfb4c3SHadar Hen Zion struct neigh_table *tbl; 450f6dfb4c3SHadar Hen Zion bool neigh_used = false; 451f6dfb4c3SHadar Hen Zion struct neighbour *n; 452f6dfb4c3SHadar Hen Zion 453f6dfb4c3SHadar Hen Zion if (m_neigh->family == AF_INET) 454f6dfb4c3SHadar Hen Zion tbl = &arp_tbl; 455f6dfb4c3SHadar Hen Zion #if IS_ENABLED(CONFIG_IPV6) 456f6dfb4c3SHadar Hen Zion else if (m_neigh->family == AF_INET6) 457f6dfb4c3SHadar Hen Zion tbl = ipv6_stub->nd_tbl; 458f6dfb4c3SHadar Hen Zion #endif 459f6dfb4c3SHadar Hen Zion else 460f6dfb4c3SHadar Hen Zion return; 461f6dfb4c3SHadar Hen Zion 462f6dfb4c3SHadar Hen Zion list_for_each_entry(e, &nhe->encap_list, encap_list) { 463f6dfb4c3SHadar Hen Zion if (!(e->flags & MLX5_ENCAP_ENTRY_VALID)) 464f6dfb4c3SHadar Hen Zion continue; 465f6dfb4c3SHadar Hen Zion list_for_each_entry(flow, &e->flows, encap) { 466f6dfb4c3SHadar Hen Zion if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { 467f6dfb4c3SHadar Hen Zion counter = mlx5_flow_rule_counter(flow->rule); 468f6dfb4c3SHadar Hen Zion mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); 469f6dfb4c3SHadar Hen Zion if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) { 470f6dfb4c3SHadar Hen Zion neigh_used = true; 471f6dfb4c3SHadar Hen Zion break; 472f6dfb4c3SHadar Hen Zion } 473f6dfb4c3SHadar Hen Zion } 474f6dfb4c3SHadar Hen Zion } 475f6dfb4c3SHadar Hen Zion } 476f6dfb4c3SHadar Hen Zion 477f6dfb4c3SHadar Hen Zion if (neigh_used) { 478f6dfb4c3SHadar Hen Zion nhe->reported_lastuse = jiffies; 479f6dfb4c3SHadar Hen Zion 480f6dfb4c3SHadar Hen Zion /* find the relevant neigh according to the cached device and 481f6dfb4c3SHadar Hen Zion * dst ip pair 482f6dfb4c3SHadar Hen Zion */ 483f6dfb4c3SHadar Hen Zion n = neigh_lookup(tbl, &m_neigh->dst_ip, m_neigh->dev); 484f6dfb4c3SHadar Hen Zion if (!n) { 485f6dfb4c3SHadar Hen Zion WARN(1, "The neighbour already freed\n"); 486f6dfb4c3SHadar Hen Zion return; 487f6dfb4c3SHadar Hen Zion } 488f6dfb4c3SHadar Hen Zion 489f6dfb4c3SHadar Hen Zion neigh_event_send(n, NULL); 490f6dfb4c3SHadar Hen Zion neigh_release(n); 491f6dfb4c3SHadar Hen Zion } 492f6dfb4c3SHadar Hen Zion } 493f6dfb4c3SHadar Hen Zion 494d85cdccbSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv, 495d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 496d85cdccbSOr Gerlitz { 4975067b602SRoi Dayan struct list_head *next = flow->encap.next; 4985067b602SRoi Dayan 4995067b602SRoi Dayan list_del(&flow->encap); 5005067b602SRoi Dayan if (list_empty(next)) { 501c1ae1152SOr Gerlitz struct mlx5e_encap_entry *e; 5025067b602SRoi Dayan 503c1ae1152SOr Gerlitz e = list_entry(next, struct mlx5e_encap_entry, flows); 504232c0013SHadar Hen Zion mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); 505232c0013SHadar Hen Zion 506232c0013SHadar Hen Zion if (e->flags & MLX5_ENCAP_ENTRY_VALID) 5075067b602SRoi Dayan mlx5_encap_dealloc(priv->mdev, e->encap_id); 508232c0013SHadar Hen Zion 509cdc5a7f3SOr Gerlitz hash_del_rcu(&e->encap_hlist); 510232c0013SHadar Hen Zion kfree(e->encap_header); 5115067b602SRoi Dayan kfree(e); 5125067b602SRoi Dayan } 5135067b602SRoi Dayan } 5145067b602SRoi Dayan 515e8f887acSAmir Vadai static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, 516961e8979SRoi Dayan struct mlx5e_tc_flow *flow) 517e8f887acSAmir Vadai { 518d85cdccbSOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) 519d85cdccbSOr Gerlitz mlx5e_tc_del_fdb_flow(priv, flow); 520d85cdccbSOr Gerlitz else 521d85cdccbSOr Gerlitz mlx5e_tc_del_nic_flow(priv, flow); 522e8f887acSAmir Vadai } 523e8f887acSAmir Vadai 524bbd00f7eSHadar Hen Zion static void parse_vxlan_attr(struct mlx5_flow_spec *spec, 525bbd00f7eSHadar Hen Zion struct tc_cls_flower_offload *f) 526bbd00f7eSHadar Hen Zion { 527bbd00f7eSHadar Hen Zion void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 528bbd00f7eSHadar Hen Zion outer_headers); 529bbd00f7eSHadar Hen Zion void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 530bbd00f7eSHadar Hen Zion outer_headers); 531bbd00f7eSHadar Hen Zion void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 532bbd00f7eSHadar Hen Zion misc_parameters); 533bbd00f7eSHadar Hen Zion void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 534bbd00f7eSHadar Hen Zion misc_parameters); 535bbd00f7eSHadar Hen Zion 536bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol); 537bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP); 538bbd00f7eSHadar Hen Zion 539bbd00f7eSHadar Hen Zion if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) { 540bbd00f7eSHadar Hen Zion struct flow_dissector_key_keyid *key = 541bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 542bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, 543bbd00f7eSHadar Hen Zion f->key); 544bbd00f7eSHadar Hen Zion struct flow_dissector_key_keyid *mask = 545bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 546bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, 547bbd00f7eSHadar Hen Zion f->mask); 548bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni, 549bbd00f7eSHadar Hen Zion be32_to_cpu(mask->keyid)); 550bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni, 551bbd00f7eSHadar Hen Zion be32_to_cpu(key->keyid)); 552bbd00f7eSHadar Hen Zion } 553bbd00f7eSHadar Hen Zion } 554bbd00f7eSHadar Hen Zion 555bbd00f7eSHadar Hen Zion static int parse_tunnel_attr(struct mlx5e_priv *priv, 556bbd00f7eSHadar Hen Zion struct mlx5_flow_spec *spec, 557bbd00f7eSHadar Hen Zion struct tc_cls_flower_offload *f) 558bbd00f7eSHadar Hen Zion { 559bbd00f7eSHadar Hen Zion void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 560bbd00f7eSHadar Hen Zion outer_headers); 561bbd00f7eSHadar Hen Zion void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 562bbd00f7eSHadar Hen Zion outer_headers); 563bbd00f7eSHadar Hen Zion 5642e72eb43SOr Gerlitz struct flow_dissector_key_control *enc_control = 5652e72eb43SOr Gerlitz skb_flow_dissector_target(f->dissector, 5662e72eb43SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_CONTROL, 5672e72eb43SOr Gerlitz f->key); 5682e72eb43SOr Gerlitz 569bbd00f7eSHadar Hen Zion if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) { 570bbd00f7eSHadar Hen Zion struct flow_dissector_key_ports *key = 571bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 572bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, 573bbd00f7eSHadar Hen Zion f->key); 574bbd00f7eSHadar Hen Zion struct flow_dissector_key_ports *mask = 575bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 576bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, 577bbd00f7eSHadar Hen Zion f->mask); 5781ad9a00aSPaul Blakey struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 5791ad9a00aSPaul Blakey struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw); 5801ad9a00aSPaul Blakey struct mlx5e_priv *up_priv = netdev_priv(up_dev); 581bbd00f7eSHadar Hen Zion 582bbd00f7eSHadar Hen Zion /* Full udp dst port must be given */ 583bbd00f7eSHadar Hen Zion if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst))) 5842fcd82e9SOr Gerlitz goto vxlan_match_offload_err; 585bbd00f7eSHadar Hen Zion 5861ad9a00aSPaul Blakey if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->dst)) && 587bbd00f7eSHadar Hen Zion MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) 588bbd00f7eSHadar Hen Zion parse_vxlan_attr(spec, f); 5892fcd82e9SOr Gerlitz else { 5902fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 5912fcd82e9SOr Gerlitz "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst)); 592bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 5932fcd82e9SOr Gerlitz } 594bbd00f7eSHadar Hen Zion 595bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 596bbd00f7eSHadar Hen Zion udp_dport, ntohs(mask->dst)); 597bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 598bbd00f7eSHadar Hen Zion udp_dport, ntohs(key->dst)); 599bbd00f7eSHadar Hen Zion 600cd377663SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, 601cd377663SOr Gerlitz udp_sport, ntohs(mask->src)); 602cd377663SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, 603cd377663SOr Gerlitz udp_sport, ntohs(key->src)); 604bbd00f7eSHadar Hen Zion } else { /* udp dst port must be given */ 6052fcd82e9SOr Gerlitz vxlan_match_offload_err: 6062fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 6072fcd82e9SOr Gerlitz "IP tunnel decap offload supported only for vxlan, must set UDP dport\n"); 608bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 609bbd00f7eSHadar Hen Zion } 610bbd00f7eSHadar Hen Zion 6112e72eb43SOr Gerlitz if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 612bbd00f7eSHadar Hen Zion struct flow_dissector_key_ipv4_addrs *key = 613bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 614bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, 615bbd00f7eSHadar Hen Zion f->key); 616bbd00f7eSHadar Hen Zion struct flow_dissector_key_ipv4_addrs *mask = 617bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 618bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, 619bbd00f7eSHadar Hen Zion f->mask); 620bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 621bbd00f7eSHadar Hen Zion src_ipv4_src_ipv6.ipv4_layout.ipv4, 622bbd00f7eSHadar Hen Zion ntohl(mask->src)); 623bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 624bbd00f7eSHadar Hen Zion src_ipv4_src_ipv6.ipv4_layout.ipv4, 625bbd00f7eSHadar Hen Zion ntohl(key->src)); 626bbd00f7eSHadar Hen Zion 627bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 628bbd00f7eSHadar Hen Zion dst_ipv4_dst_ipv6.ipv4_layout.ipv4, 629bbd00f7eSHadar Hen Zion ntohl(mask->dst)); 630bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 631bbd00f7eSHadar Hen Zion dst_ipv4_dst_ipv6.ipv4_layout.ipv4, 632bbd00f7eSHadar Hen Zion ntohl(key->dst)); 633bbd00f7eSHadar Hen Zion 634bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); 635bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP); 63619f44401SOr Gerlitz } else if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 63719f44401SOr Gerlitz struct flow_dissector_key_ipv6_addrs *key = 63819f44401SOr Gerlitz skb_flow_dissector_target(f->dissector, 63919f44401SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, 64019f44401SOr Gerlitz f->key); 64119f44401SOr Gerlitz struct flow_dissector_key_ipv6_addrs *mask = 64219f44401SOr Gerlitz skb_flow_dissector_target(f->dissector, 64319f44401SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, 64419f44401SOr Gerlitz f->mask); 64519f44401SOr Gerlitz 64619f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 64719f44401SOr Gerlitz src_ipv4_src_ipv6.ipv6_layout.ipv6), 64819f44401SOr Gerlitz &mask->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 64919f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 65019f44401SOr Gerlitz src_ipv4_src_ipv6.ipv6_layout.ipv6), 65119f44401SOr Gerlitz &key->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 65219f44401SOr Gerlitz 65319f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 65419f44401SOr Gerlitz dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 65519f44401SOr Gerlitz &mask->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 65619f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 65719f44401SOr Gerlitz dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 65819f44401SOr Gerlitz &key->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 65919f44401SOr Gerlitz 66019f44401SOr Gerlitz MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); 66119f44401SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IPV6); 6622e72eb43SOr Gerlitz } 663bbd00f7eSHadar Hen Zion 664bbd00f7eSHadar Hen Zion /* Enforce DMAC when offloading incoming tunneled flows. 665bbd00f7eSHadar Hen Zion * Flow counters require a match on the DMAC. 666bbd00f7eSHadar Hen Zion */ 667bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_47_16); 668bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_15_0); 669bbd00f7eSHadar Hen Zion ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 670bbd00f7eSHadar Hen Zion dmac_47_16), priv->netdev->dev_addr); 671bbd00f7eSHadar Hen Zion 672bbd00f7eSHadar Hen Zion /* let software handle IP fragments */ 673bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1); 674bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 0); 675bbd00f7eSHadar Hen Zion 676bbd00f7eSHadar Hen Zion return 0; 677bbd00f7eSHadar Hen Zion } 678bbd00f7eSHadar Hen Zion 679de0af0bfSRoi Dayan static int __parse_cls_flower(struct mlx5e_priv *priv, 680de0af0bfSRoi Dayan struct mlx5_flow_spec *spec, 681de0af0bfSRoi Dayan struct tc_cls_flower_offload *f, 682de0af0bfSRoi Dayan u8 *min_inline) 683e3a2b7edSAmir Vadai { 684c5bb1730SMaor Gottlieb void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 685c5bb1730SMaor Gottlieb outer_headers); 686c5bb1730SMaor Gottlieb void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 687c5bb1730SMaor Gottlieb outer_headers); 688e3a2b7edSAmir Vadai u16 addr_type = 0; 689e3a2b7edSAmir Vadai u8 ip_proto = 0; 690e3a2b7edSAmir Vadai 691de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_L2; 692de0af0bfSRoi Dayan 693e3a2b7edSAmir Vadai if (f->dissector->used_keys & 694e3a2b7edSAmir Vadai ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 695e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_BASIC) | 696e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 697095b6cfdSOr Gerlitz BIT(FLOW_DISSECTOR_KEY_VLAN) | 698e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 699e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 700bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_PORTS) | 701bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | 702bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | 703bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | 704bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | 705e77834ecSOr Gerlitz BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | 706fd7da28bSOr Gerlitz BIT(FLOW_DISSECTOR_KEY_TCP) | 707fd7da28bSOr Gerlitz BIT(FLOW_DISSECTOR_KEY_IP))) { 708e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", 709e3a2b7edSAmir Vadai f->dissector->used_keys); 710e3a2b7edSAmir Vadai return -EOPNOTSUPP; 711e3a2b7edSAmir Vadai } 712e3a2b7edSAmir Vadai 713bbd00f7eSHadar Hen Zion if ((dissector_uses_key(f->dissector, 714bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) || 715bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID) || 716bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) && 717bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL)) { 718bbd00f7eSHadar Hen Zion struct flow_dissector_key_control *key = 719bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 720bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_CONTROL, 721bbd00f7eSHadar Hen Zion f->key); 722bbd00f7eSHadar Hen Zion switch (key->addr_type) { 723bbd00f7eSHadar Hen Zion case FLOW_DISSECTOR_KEY_IPV4_ADDRS: 72419f44401SOr Gerlitz case FLOW_DISSECTOR_KEY_IPV6_ADDRS: 725bbd00f7eSHadar Hen Zion if (parse_tunnel_attr(priv, spec, f)) 726bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 727bbd00f7eSHadar Hen Zion break; 728bbd00f7eSHadar Hen Zion default: 729bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 730bbd00f7eSHadar Hen Zion } 731bbd00f7eSHadar Hen Zion 732bbd00f7eSHadar Hen Zion /* In decap flow, header pointers should point to the inner 733bbd00f7eSHadar Hen Zion * headers, outer header were already set by parse_tunnel_attr 734bbd00f7eSHadar Hen Zion */ 735bbd00f7eSHadar Hen Zion headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 736bbd00f7eSHadar Hen Zion inner_headers); 737bbd00f7eSHadar Hen Zion headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 738bbd00f7eSHadar Hen Zion inner_headers); 739bbd00f7eSHadar Hen Zion } 740bbd00f7eSHadar Hen Zion 741e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) { 742e3a2b7edSAmir Vadai struct flow_dissector_key_control *key = 743e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 7441dbd0d37SHadar Hen Zion FLOW_DISSECTOR_KEY_CONTROL, 745e3a2b7edSAmir Vadai f->key); 7463f7d0eb4SOr Gerlitz 7473f7d0eb4SOr Gerlitz struct flow_dissector_key_control *mask = 7483f7d0eb4SOr Gerlitz skb_flow_dissector_target(f->dissector, 7493f7d0eb4SOr Gerlitz FLOW_DISSECTOR_KEY_CONTROL, 7503f7d0eb4SOr Gerlitz f->mask); 751e3a2b7edSAmir Vadai addr_type = key->addr_type; 7523f7d0eb4SOr Gerlitz 7533f7d0eb4SOr Gerlitz if (mask->flags & FLOW_DIS_IS_FRAGMENT) { 7543f7d0eb4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1); 7553f7d0eb4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 7563f7d0eb4SOr Gerlitz key->flags & FLOW_DIS_IS_FRAGMENT); 7570827444dSOr Gerlitz 7580827444dSOr Gerlitz /* the HW doesn't need L3 inline to match on frag=no */ 7590827444dSOr Gerlitz if (key->flags & FLOW_DIS_IS_FRAGMENT) 7600827444dSOr Gerlitz *min_inline = MLX5_INLINE_MODE_IP; 7613f7d0eb4SOr Gerlitz } 762e3a2b7edSAmir Vadai } 763e3a2b7edSAmir Vadai 764e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) { 765e3a2b7edSAmir Vadai struct flow_dissector_key_basic *key = 766e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 767e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 768e3a2b7edSAmir Vadai f->key); 769e3a2b7edSAmir Vadai struct flow_dissector_key_basic *mask = 770e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 771e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 772e3a2b7edSAmir Vadai f->mask); 773e3a2b7edSAmir Vadai ip_proto = key->ip_proto; 774e3a2b7edSAmir Vadai 775e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype, 776e3a2b7edSAmir Vadai ntohs(mask->n_proto)); 777e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 778e3a2b7edSAmir Vadai ntohs(key->n_proto)); 779e3a2b7edSAmir Vadai 780e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol, 781e3a2b7edSAmir Vadai mask->ip_proto); 782e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 783e3a2b7edSAmir Vadai key->ip_proto); 784de0af0bfSRoi Dayan 785de0af0bfSRoi Dayan if (mask->ip_proto) 786de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 787e3a2b7edSAmir Vadai } 788e3a2b7edSAmir Vadai 789e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 790e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *key = 791e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 792e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 793e3a2b7edSAmir Vadai f->key); 794e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *mask = 795e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 796e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 797e3a2b7edSAmir Vadai f->mask); 798e3a2b7edSAmir Vadai 799e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 800e3a2b7edSAmir Vadai dmac_47_16), 801e3a2b7edSAmir Vadai mask->dst); 802e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 803e3a2b7edSAmir Vadai dmac_47_16), 804e3a2b7edSAmir Vadai key->dst); 805e3a2b7edSAmir Vadai 806e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 807e3a2b7edSAmir Vadai smac_47_16), 808e3a2b7edSAmir Vadai mask->src); 809e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 810e3a2b7edSAmir Vadai smac_47_16), 811e3a2b7edSAmir Vadai key->src); 812e3a2b7edSAmir Vadai } 813e3a2b7edSAmir Vadai 814095b6cfdSOr Gerlitz if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) { 815095b6cfdSOr Gerlitz struct flow_dissector_key_vlan *key = 816095b6cfdSOr Gerlitz skb_flow_dissector_target(f->dissector, 817095b6cfdSOr Gerlitz FLOW_DISSECTOR_KEY_VLAN, 818095b6cfdSOr Gerlitz f->key); 819095b6cfdSOr Gerlitz struct flow_dissector_key_vlan *mask = 820095b6cfdSOr Gerlitz skb_flow_dissector_target(f->dissector, 821095b6cfdSOr Gerlitz FLOW_DISSECTOR_KEY_VLAN, 822095b6cfdSOr Gerlitz f->mask); 823358d79a4SOr Gerlitz if (mask->vlan_id || mask->vlan_priority) { 82410543365SMohamad Haj Yahia MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); 82510543365SMohamad Haj Yahia MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1); 826095b6cfdSOr Gerlitz 827095b6cfdSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, mask->vlan_id); 828095b6cfdSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, key->vlan_id); 829358d79a4SOr Gerlitz 830358d79a4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_prio, mask->vlan_priority); 831358d79a4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, key->vlan_priority); 832095b6cfdSOr Gerlitz } 833095b6cfdSOr Gerlitz } 834095b6cfdSOr Gerlitz 835e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 836e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *key = 837e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 838e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 839e3a2b7edSAmir Vadai f->key); 840e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *mask = 841e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 842e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 843e3a2b7edSAmir Vadai f->mask); 844e3a2b7edSAmir Vadai 845e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 846e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 847e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 848e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 849e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 850e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 851e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 852e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 853e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 854e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 855e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 856e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 857de0af0bfSRoi Dayan 858de0af0bfSRoi Dayan if (mask->src || mask->dst) 859de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 860e3a2b7edSAmir Vadai } 861e3a2b7edSAmir Vadai 862e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 863e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *key = 864e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 865e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 866e3a2b7edSAmir Vadai f->key); 867e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *mask = 868e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 869e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 870e3a2b7edSAmir Vadai f->mask); 871e3a2b7edSAmir Vadai 872e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 873e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 874e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 875e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 876e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 877e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 878e3a2b7edSAmir Vadai 879e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 880e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 881e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 882e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 883e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 884e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 885de0af0bfSRoi Dayan 886de0af0bfSRoi Dayan if (ipv6_addr_type(&mask->src) != IPV6_ADDR_ANY || 887de0af0bfSRoi Dayan ipv6_addr_type(&mask->dst) != IPV6_ADDR_ANY) 888de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 889e3a2b7edSAmir Vadai } 890e3a2b7edSAmir Vadai 8911f97a526SOr Gerlitz if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP)) { 8921f97a526SOr Gerlitz struct flow_dissector_key_ip *key = 8931f97a526SOr Gerlitz skb_flow_dissector_target(f->dissector, 8941f97a526SOr Gerlitz FLOW_DISSECTOR_KEY_IP, 8951f97a526SOr Gerlitz f->key); 8961f97a526SOr Gerlitz struct flow_dissector_key_ip *mask = 8971f97a526SOr Gerlitz skb_flow_dissector_target(f->dissector, 8981f97a526SOr Gerlitz FLOW_DISSECTOR_KEY_IP, 8991f97a526SOr Gerlitz f->mask); 9001f97a526SOr Gerlitz 9011f97a526SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn, mask->tos & 0x3); 9021f97a526SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, key->tos & 0x3); 9031f97a526SOr Gerlitz 9041f97a526SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2); 9051f97a526SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos >> 2); 9061f97a526SOr Gerlitz 907a8ade55fSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, ttl_hoplimit, mask->ttl); 908a8ade55fSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, ttl_hoplimit, key->ttl); 9091f97a526SOr Gerlitz 910a8ade55fSOr Gerlitz if (mask->ttl && 911a8ade55fSOr Gerlitz !MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, 912a8ade55fSOr Gerlitz ft_field_support.outer_ipv4_ttl)) 9131f97a526SOr Gerlitz return -EOPNOTSUPP; 914a8ade55fSOr Gerlitz 915a8ade55fSOr Gerlitz if (mask->tos || mask->ttl) 916a8ade55fSOr Gerlitz *min_inline = MLX5_INLINE_MODE_IP; 9171f97a526SOr Gerlitz } 9181f97a526SOr Gerlitz 919e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) { 920e3a2b7edSAmir Vadai struct flow_dissector_key_ports *key = 921e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 922e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 923e3a2b7edSAmir Vadai f->key); 924e3a2b7edSAmir Vadai struct flow_dissector_key_ports *mask = 925e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 926e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 927e3a2b7edSAmir Vadai f->mask); 928e3a2b7edSAmir Vadai switch (ip_proto) { 929e3a2b7edSAmir Vadai case IPPROTO_TCP: 930e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 931e3a2b7edSAmir Vadai tcp_sport, ntohs(mask->src)); 932e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 933e3a2b7edSAmir Vadai tcp_sport, ntohs(key->src)); 934e3a2b7edSAmir Vadai 935e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 936e3a2b7edSAmir Vadai tcp_dport, ntohs(mask->dst)); 937e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 938e3a2b7edSAmir Vadai tcp_dport, ntohs(key->dst)); 939e3a2b7edSAmir Vadai break; 940e3a2b7edSAmir Vadai 941e3a2b7edSAmir Vadai case IPPROTO_UDP: 942e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 943e3a2b7edSAmir Vadai udp_sport, ntohs(mask->src)); 944e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 945e3a2b7edSAmir Vadai udp_sport, ntohs(key->src)); 946e3a2b7edSAmir Vadai 947e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 948e3a2b7edSAmir Vadai udp_dport, ntohs(mask->dst)); 949e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 950e3a2b7edSAmir Vadai udp_dport, ntohs(key->dst)); 951e3a2b7edSAmir Vadai break; 952e3a2b7edSAmir Vadai default: 953e3a2b7edSAmir Vadai netdev_err(priv->netdev, 954e3a2b7edSAmir Vadai "Only UDP and TCP transport are supported\n"); 955e3a2b7edSAmir Vadai return -EINVAL; 956e3a2b7edSAmir Vadai } 957de0af0bfSRoi Dayan 958de0af0bfSRoi Dayan if (mask->src || mask->dst) 959de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_TCP_UDP; 960e3a2b7edSAmir Vadai } 961e3a2b7edSAmir Vadai 962e77834ecSOr Gerlitz if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) { 963e77834ecSOr Gerlitz struct flow_dissector_key_tcp *key = 964e77834ecSOr Gerlitz skb_flow_dissector_target(f->dissector, 965e77834ecSOr Gerlitz FLOW_DISSECTOR_KEY_TCP, 966e77834ecSOr Gerlitz f->key); 967e77834ecSOr Gerlitz struct flow_dissector_key_tcp *mask = 968e77834ecSOr Gerlitz skb_flow_dissector_target(f->dissector, 969e77834ecSOr Gerlitz FLOW_DISSECTOR_KEY_TCP, 970e77834ecSOr Gerlitz f->mask); 971e77834ecSOr Gerlitz 972e77834ecSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_flags, 973e77834ecSOr Gerlitz ntohs(mask->flags)); 974e77834ecSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags, 975e77834ecSOr Gerlitz ntohs(key->flags)); 976e77834ecSOr Gerlitz 977e77834ecSOr Gerlitz if (mask->flags) 978e77834ecSOr Gerlitz *min_inline = MLX5_INLINE_MODE_TCP_UDP; 979e77834ecSOr Gerlitz } 980e77834ecSOr Gerlitz 981e3a2b7edSAmir Vadai return 0; 982e3a2b7edSAmir Vadai } 983e3a2b7edSAmir Vadai 984de0af0bfSRoi Dayan static int parse_cls_flower(struct mlx5e_priv *priv, 98565ba8fb7SOr Gerlitz struct mlx5e_tc_flow *flow, 986de0af0bfSRoi Dayan struct mlx5_flow_spec *spec, 987de0af0bfSRoi Dayan struct tc_cls_flower_offload *f) 988de0af0bfSRoi Dayan { 989de0af0bfSRoi Dayan struct mlx5_core_dev *dev = priv->mdev; 990de0af0bfSRoi Dayan struct mlx5_eswitch *esw = dev->priv.eswitch; 9911d447a39SSaeed Mahameed struct mlx5e_rep_priv *rpriv = priv->ppriv; 9921d447a39SSaeed Mahameed struct mlx5_eswitch_rep *rep; 993de0af0bfSRoi Dayan u8 min_inline; 994de0af0bfSRoi Dayan int err; 995de0af0bfSRoi Dayan 996de0af0bfSRoi Dayan err = __parse_cls_flower(priv, spec, f, &min_inline); 997de0af0bfSRoi Dayan 9981d447a39SSaeed Mahameed if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH)) { 9991d447a39SSaeed Mahameed rep = rpriv->rep; 10001d447a39SSaeed Mahameed if (rep->vport != FDB_UPLINK_VPORT && 10011d447a39SSaeed Mahameed (esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE && 10021d447a39SSaeed Mahameed esw->offloads.inline_mode < min_inline)) { 1003de0af0bfSRoi Dayan netdev_warn(priv->netdev, 1004de0af0bfSRoi Dayan "Flow is not offloaded due to min inline setting, required %d actual %d\n", 1005de0af0bfSRoi Dayan min_inline, esw->offloads.inline_mode); 1006de0af0bfSRoi Dayan return -EOPNOTSUPP; 1007de0af0bfSRoi Dayan } 1008de0af0bfSRoi Dayan } 1009de0af0bfSRoi Dayan 1010de0af0bfSRoi Dayan return err; 1011de0af0bfSRoi Dayan } 1012de0af0bfSRoi Dayan 1013d79b6df6SOr Gerlitz struct pedit_headers { 1014d79b6df6SOr Gerlitz struct ethhdr eth; 1015d79b6df6SOr Gerlitz struct iphdr ip4; 1016d79b6df6SOr Gerlitz struct ipv6hdr ip6; 1017d79b6df6SOr Gerlitz struct tcphdr tcp; 1018d79b6df6SOr Gerlitz struct udphdr udp; 1019d79b6df6SOr Gerlitz }; 1020d79b6df6SOr Gerlitz 1021d79b6df6SOr Gerlitz static int pedit_header_offsets[] = { 1022d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = offsetof(struct pedit_headers, eth), 1023d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = offsetof(struct pedit_headers, ip4), 1024d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = offsetof(struct pedit_headers, ip6), 1025d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = offsetof(struct pedit_headers, tcp), 1026d79b6df6SOr Gerlitz [TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = offsetof(struct pedit_headers, udp), 1027d79b6df6SOr Gerlitz }; 1028d79b6df6SOr Gerlitz 1029d79b6df6SOr Gerlitz #define pedit_header(_ph, _htype) ((void *)(_ph) + pedit_header_offsets[_htype]) 1030d79b6df6SOr Gerlitz 1031d79b6df6SOr Gerlitz static int set_pedit_val(u8 hdr_type, u32 mask, u32 val, u32 offset, 1032d79b6df6SOr Gerlitz struct pedit_headers *masks, 1033d79b6df6SOr Gerlitz struct pedit_headers *vals) 1034d79b6df6SOr Gerlitz { 1035d79b6df6SOr Gerlitz u32 *curr_pmask, *curr_pval; 1036d79b6df6SOr Gerlitz 1037d79b6df6SOr Gerlitz if (hdr_type >= __PEDIT_HDR_TYPE_MAX) 1038d79b6df6SOr Gerlitz goto out_err; 1039d79b6df6SOr Gerlitz 1040d79b6df6SOr Gerlitz curr_pmask = (u32 *)(pedit_header(masks, hdr_type) + offset); 1041d79b6df6SOr Gerlitz curr_pval = (u32 *)(pedit_header(vals, hdr_type) + offset); 1042d79b6df6SOr Gerlitz 1043d79b6df6SOr Gerlitz if (*curr_pmask & mask) /* disallow acting twice on the same location */ 1044d79b6df6SOr Gerlitz goto out_err; 1045d79b6df6SOr Gerlitz 1046d79b6df6SOr Gerlitz *curr_pmask |= mask; 1047d79b6df6SOr Gerlitz *curr_pval |= (val & mask); 1048d79b6df6SOr Gerlitz 1049d79b6df6SOr Gerlitz return 0; 1050d79b6df6SOr Gerlitz 1051d79b6df6SOr Gerlitz out_err: 1052d79b6df6SOr Gerlitz return -EOPNOTSUPP; 1053d79b6df6SOr Gerlitz } 1054d79b6df6SOr Gerlitz 1055d79b6df6SOr Gerlitz struct mlx5_fields { 1056d79b6df6SOr Gerlitz u8 field; 1057d79b6df6SOr Gerlitz u8 size; 1058d79b6df6SOr Gerlitz u32 offset; 1059d79b6df6SOr Gerlitz }; 1060d79b6df6SOr Gerlitz 1061a8e4f0c4SOr Gerlitz #define OFFLOAD(fw_field, size, field, off) \ 1062a8e4f0c4SOr Gerlitz {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, size, offsetof(struct pedit_headers, field) + (off)} 1063a8e4f0c4SOr Gerlitz 1064d79b6df6SOr Gerlitz static struct mlx5_fields fields[] = { 1065a8e4f0c4SOr Gerlitz OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0), 1066a8e4f0c4SOr Gerlitz OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0), 1067a8e4f0c4SOr Gerlitz OFFLOAD(DMAC_15_0, 2, eth.h_dest[4], 0), 1068a8e4f0c4SOr Gerlitz OFFLOAD(SMAC_47_16, 4, eth.h_source[0], 0), 1069a8e4f0c4SOr Gerlitz OFFLOAD(SMAC_15_0, 2, eth.h_source[4], 0), 1070a8e4f0c4SOr Gerlitz OFFLOAD(ETHERTYPE, 2, eth.h_proto, 0), 1071d79b6df6SOr Gerlitz 1072a8e4f0c4SOr Gerlitz OFFLOAD(IP_TTL, 1, ip4.ttl, 0), 1073a8e4f0c4SOr Gerlitz OFFLOAD(SIPV4, 4, ip4.saddr, 0), 1074a8e4f0c4SOr Gerlitz OFFLOAD(DIPV4, 4, ip4.daddr, 0), 1075d79b6df6SOr Gerlitz 1076a8e4f0c4SOr Gerlitz OFFLOAD(SIPV6_127_96, 4, ip6.saddr.s6_addr32[0], 0), 1077a8e4f0c4SOr Gerlitz OFFLOAD(SIPV6_95_64, 4, ip6.saddr.s6_addr32[1], 0), 1078a8e4f0c4SOr Gerlitz OFFLOAD(SIPV6_63_32, 4, ip6.saddr.s6_addr32[2], 0), 1079a8e4f0c4SOr Gerlitz OFFLOAD(SIPV6_31_0, 4, ip6.saddr.s6_addr32[3], 0), 1080a8e4f0c4SOr Gerlitz OFFLOAD(DIPV6_127_96, 4, ip6.daddr.s6_addr32[0], 0), 1081a8e4f0c4SOr Gerlitz OFFLOAD(DIPV6_95_64, 4, ip6.daddr.s6_addr32[1], 0), 1082a8e4f0c4SOr Gerlitz OFFLOAD(DIPV6_63_32, 4, ip6.daddr.s6_addr32[2], 0), 1083a8e4f0c4SOr Gerlitz OFFLOAD(DIPV6_31_0, 4, ip6.daddr.s6_addr32[3], 0), 10840c0316f5SOr Gerlitz OFFLOAD(IPV6_HOPLIMIT, 1, ip6.hop_limit, 0), 1085d79b6df6SOr Gerlitz 1086a8e4f0c4SOr Gerlitz OFFLOAD(TCP_SPORT, 2, tcp.source, 0), 1087a8e4f0c4SOr Gerlitz OFFLOAD(TCP_DPORT, 2, tcp.dest, 0), 1088a8e4f0c4SOr Gerlitz OFFLOAD(TCP_FLAGS, 1, tcp.ack_seq, 5), 1089d79b6df6SOr Gerlitz 1090a8e4f0c4SOr Gerlitz OFFLOAD(UDP_SPORT, 2, udp.source, 0), 1091a8e4f0c4SOr Gerlitz OFFLOAD(UDP_DPORT, 2, udp.dest, 0), 1092d79b6df6SOr Gerlitz }; 1093d79b6df6SOr Gerlitz 1094d79b6df6SOr Gerlitz /* On input attr->num_mod_hdr_actions tells how many HW actions can be parsed at 1095d79b6df6SOr Gerlitz * max from the SW pedit action. On success, it says how many HW actions were 1096d79b6df6SOr Gerlitz * actually parsed. 1097d79b6df6SOr Gerlitz */ 1098d79b6df6SOr Gerlitz static int offload_pedit_fields(struct pedit_headers *masks, 1099d79b6df6SOr Gerlitz struct pedit_headers *vals, 1100d79b6df6SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr) 1101d79b6df6SOr Gerlitz { 1102d79b6df6SOr Gerlitz struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals; 11032b64bebaSOr Gerlitz int i, action_size, nactions, max_actions, first, last, next_z; 1104d79b6df6SOr Gerlitz void *s_masks_p, *a_masks_p, *vals_p; 1105d79b6df6SOr Gerlitz struct mlx5_fields *f; 1106d79b6df6SOr Gerlitz u8 cmd, field_bsize; 1107e3ca4e05SOr Gerlitz u32 s_mask, a_mask; 1108d79b6df6SOr Gerlitz unsigned long mask; 11092b64bebaSOr Gerlitz __be32 mask_be32; 11102b64bebaSOr Gerlitz __be16 mask_be16; 1111d79b6df6SOr Gerlitz void *action; 1112d79b6df6SOr Gerlitz 1113d79b6df6SOr Gerlitz set_masks = &masks[TCA_PEDIT_KEY_EX_CMD_SET]; 1114d79b6df6SOr Gerlitz add_masks = &masks[TCA_PEDIT_KEY_EX_CMD_ADD]; 1115d79b6df6SOr Gerlitz set_vals = &vals[TCA_PEDIT_KEY_EX_CMD_SET]; 1116d79b6df6SOr Gerlitz add_vals = &vals[TCA_PEDIT_KEY_EX_CMD_ADD]; 1117d79b6df6SOr Gerlitz 1118d79b6df6SOr Gerlitz action_size = MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto); 1119d79b6df6SOr Gerlitz action = parse_attr->mod_hdr_actions; 1120d79b6df6SOr Gerlitz max_actions = parse_attr->num_mod_hdr_actions; 1121d79b6df6SOr Gerlitz nactions = 0; 1122d79b6df6SOr Gerlitz 1123d79b6df6SOr Gerlitz for (i = 0; i < ARRAY_SIZE(fields); i++) { 1124d79b6df6SOr Gerlitz f = &fields[i]; 1125d79b6df6SOr Gerlitz /* avoid seeing bits set from previous iterations */ 1126e3ca4e05SOr Gerlitz s_mask = 0; 1127e3ca4e05SOr Gerlitz a_mask = 0; 1128d79b6df6SOr Gerlitz 1129d79b6df6SOr Gerlitz s_masks_p = (void *)set_masks + f->offset; 1130d79b6df6SOr Gerlitz a_masks_p = (void *)add_masks + f->offset; 1131d79b6df6SOr Gerlitz 1132d79b6df6SOr Gerlitz memcpy(&s_mask, s_masks_p, f->size); 1133d79b6df6SOr Gerlitz memcpy(&a_mask, a_masks_p, f->size); 1134d79b6df6SOr Gerlitz 1135d79b6df6SOr Gerlitz if (!s_mask && !a_mask) /* nothing to offload here */ 1136d79b6df6SOr Gerlitz continue; 1137d79b6df6SOr Gerlitz 1138d79b6df6SOr Gerlitz if (s_mask && a_mask) { 1139d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: can't set and add to the same HW field (%x)\n", f->field); 1140d79b6df6SOr Gerlitz return -EOPNOTSUPP; 1141d79b6df6SOr Gerlitz } 1142d79b6df6SOr Gerlitz 1143d79b6df6SOr Gerlitz if (nactions == max_actions) { 1144d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: parsed %d pedit actions, can't do more\n", nactions); 1145d79b6df6SOr Gerlitz return -EOPNOTSUPP; 1146d79b6df6SOr Gerlitz } 1147d79b6df6SOr Gerlitz 1148d79b6df6SOr Gerlitz if (s_mask) { 1149d79b6df6SOr Gerlitz cmd = MLX5_ACTION_TYPE_SET; 1150d79b6df6SOr Gerlitz mask = s_mask; 1151d79b6df6SOr Gerlitz vals_p = (void *)set_vals + f->offset; 1152d79b6df6SOr Gerlitz /* clear to denote we consumed this field */ 1153d79b6df6SOr Gerlitz memset(s_masks_p, 0, f->size); 1154d79b6df6SOr Gerlitz } else { 1155d79b6df6SOr Gerlitz cmd = MLX5_ACTION_TYPE_ADD; 1156d79b6df6SOr Gerlitz mask = a_mask; 1157d79b6df6SOr Gerlitz vals_p = (void *)add_vals + f->offset; 1158d79b6df6SOr Gerlitz /* clear to denote we consumed this field */ 1159d79b6df6SOr Gerlitz memset(a_masks_p, 0, f->size); 1160d79b6df6SOr Gerlitz } 1161d79b6df6SOr Gerlitz 1162d79b6df6SOr Gerlitz field_bsize = f->size * BITS_PER_BYTE; 1163e3ca4e05SOr Gerlitz 11642b64bebaSOr Gerlitz if (field_bsize == 32) { 11652b64bebaSOr Gerlitz mask_be32 = *(__be32 *)&mask; 11662b64bebaSOr Gerlitz mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32)); 11672b64bebaSOr Gerlitz } else if (field_bsize == 16) { 11682b64bebaSOr Gerlitz mask_be16 = *(__be16 *)&mask; 11692b64bebaSOr Gerlitz mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16)); 11702b64bebaSOr Gerlitz } 11712b64bebaSOr Gerlitz 1172d79b6df6SOr Gerlitz first = find_first_bit(&mask, field_bsize); 11732b64bebaSOr Gerlitz next_z = find_next_zero_bit(&mask, field_bsize, first); 1174d79b6df6SOr Gerlitz last = find_last_bit(&mask, field_bsize); 11752b64bebaSOr Gerlitz if (first < next_z && next_z < last) { 11762b64bebaSOr Gerlitz printk(KERN_WARNING "mlx5: rewrite of few sub-fields (mask %lx) isn't offloaded\n", 1177d79b6df6SOr Gerlitz mask); 1178d79b6df6SOr Gerlitz return -EOPNOTSUPP; 1179d79b6df6SOr Gerlitz } 1180d79b6df6SOr Gerlitz 1181d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, action_type, cmd); 1182d79b6df6SOr Gerlitz MLX5_SET(set_action_in, action, field, f->field); 1183d79b6df6SOr Gerlitz 1184d79b6df6SOr Gerlitz if (cmd == MLX5_ACTION_TYPE_SET) { 11852b64bebaSOr Gerlitz MLX5_SET(set_action_in, action, offset, first); 1186d79b6df6SOr Gerlitz /* length is num of bits to be written, zero means length of 32 */ 11872b64bebaSOr Gerlitz MLX5_SET(set_action_in, action, length, (last - first + 1)); 1188d79b6df6SOr Gerlitz } 1189d79b6df6SOr Gerlitz 1190d79b6df6SOr Gerlitz if (field_bsize == 32) 11912b64bebaSOr Gerlitz MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p) >> first); 1192d79b6df6SOr Gerlitz else if (field_bsize == 16) 11932b64bebaSOr Gerlitz MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p) >> first); 1194d79b6df6SOr Gerlitz else if (field_bsize == 8) 11952b64bebaSOr Gerlitz MLX5_SET(set_action_in, action, data, *(u8 *)vals_p >> first); 1196d79b6df6SOr Gerlitz 1197d79b6df6SOr Gerlitz action += action_size; 1198d79b6df6SOr Gerlitz nactions++; 1199d79b6df6SOr Gerlitz } 1200d79b6df6SOr Gerlitz 1201d79b6df6SOr Gerlitz parse_attr->num_mod_hdr_actions = nactions; 1202d79b6df6SOr Gerlitz return 0; 1203d79b6df6SOr Gerlitz } 1204d79b6df6SOr Gerlitz 1205d79b6df6SOr Gerlitz static int alloc_mod_hdr_actions(struct mlx5e_priv *priv, 1206d79b6df6SOr Gerlitz const struct tc_action *a, int namespace, 1207d79b6df6SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr) 1208d79b6df6SOr Gerlitz { 1209d79b6df6SOr Gerlitz int nkeys, action_size, max_actions; 1210d79b6df6SOr Gerlitz 1211d79b6df6SOr Gerlitz nkeys = tcf_pedit_nkeys(a); 1212d79b6df6SOr Gerlitz action_size = MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto); 1213d79b6df6SOr Gerlitz 1214d79b6df6SOr Gerlitz if (namespace == MLX5_FLOW_NAMESPACE_FDB) /* FDB offloading */ 1215d79b6df6SOr Gerlitz max_actions = MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, max_modify_header_actions); 1216d79b6df6SOr Gerlitz else /* namespace is MLX5_FLOW_NAMESPACE_KERNEL - NIC offloading */ 1217d79b6df6SOr Gerlitz max_actions = MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, max_modify_header_actions); 1218d79b6df6SOr Gerlitz 1219d79b6df6SOr Gerlitz /* can get up to crazingly 16 HW actions in 32 bits pedit SW key */ 1220d79b6df6SOr Gerlitz max_actions = min(max_actions, nkeys * 16); 1221d79b6df6SOr Gerlitz 1222d79b6df6SOr Gerlitz parse_attr->mod_hdr_actions = kcalloc(max_actions, action_size, GFP_KERNEL); 1223d79b6df6SOr Gerlitz if (!parse_attr->mod_hdr_actions) 1224d79b6df6SOr Gerlitz return -ENOMEM; 1225d79b6df6SOr Gerlitz 1226d79b6df6SOr Gerlitz parse_attr->num_mod_hdr_actions = max_actions; 1227d79b6df6SOr Gerlitz return 0; 1228d79b6df6SOr Gerlitz } 1229d79b6df6SOr Gerlitz 1230d79b6df6SOr Gerlitz static const struct pedit_headers zero_masks = {}; 1231d79b6df6SOr Gerlitz 1232d79b6df6SOr Gerlitz static int parse_tc_pedit_action(struct mlx5e_priv *priv, 1233d79b6df6SOr Gerlitz const struct tc_action *a, int namespace, 1234d79b6df6SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr) 1235d79b6df6SOr Gerlitz { 1236d79b6df6SOr Gerlitz struct pedit_headers masks[__PEDIT_CMD_MAX], vals[__PEDIT_CMD_MAX], *cmd_masks; 1237d79b6df6SOr Gerlitz int nkeys, i, err = -EOPNOTSUPP; 1238d79b6df6SOr Gerlitz u32 mask, val, offset; 1239d79b6df6SOr Gerlitz u8 cmd, htype; 1240d79b6df6SOr Gerlitz 1241d79b6df6SOr Gerlitz nkeys = tcf_pedit_nkeys(a); 1242d79b6df6SOr Gerlitz 1243d79b6df6SOr Gerlitz memset(masks, 0, sizeof(struct pedit_headers) * __PEDIT_CMD_MAX); 1244d79b6df6SOr Gerlitz memset(vals, 0, sizeof(struct pedit_headers) * __PEDIT_CMD_MAX); 1245d79b6df6SOr Gerlitz 1246d79b6df6SOr Gerlitz for (i = 0; i < nkeys; i++) { 1247d79b6df6SOr Gerlitz htype = tcf_pedit_htype(a, i); 1248d79b6df6SOr Gerlitz cmd = tcf_pedit_cmd(a, i); 1249d79b6df6SOr Gerlitz err = -EOPNOTSUPP; /* can't be all optimistic */ 1250d79b6df6SOr Gerlitz 1251d79b6df6SOr Gerlitz if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) { 1252d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: legacy pedit isn't offloaded\n"); 1253d79b6df6SOr Gerlitz goto out_err; 1254d79b6df6SOr Gerlitz } 1255d79b6df6SOr Gerlitz 1256d79b6df6SOr Gerlitz if (cmd != TCA_PEDIT_KEY_EX_CMD_SET && cmd != TCA_PEDIT_KEY_EX_CMD_ADD) { 1257d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: pedit cmd %d isn't offloaded\n", cmd); 1258d79b6df6SOr Gerlitz goto out_err; 1259d79b6df6SOr Gerlitz } 1260d79b6df6SOr Gerlitz 1261d79b6df6SOr Gerlitz mask = tcf_pedit_mask(a, i); 1262d79b6df6SOr Gerlitz val = tcf_pedit_val(a, i); 1263d79b6df6SOr Gerlitz offset = tcf_pedit_offset(a, i); 1264d79b6df6SOr Gerlitz 1265d79b6df6SOr Gerlitz err = set_pedit_val(htype, ~mask, val, offset, &masks[cmd], &vals[cmd]); 1266d79b6df6SOr Gerlitz if (err) 1267d79b6df6SOr Gerlitz goto out_err; 1268d79b6df6SOr Gerlitz } 1269d79b6df6SOr Gerlitz 1270d79b6df6SOr Gerlitz err = alloc_mod_hdr_actions(priv, a, namespace, parse_attr); 1271d79b6df6SOr Gerlitz if (err) 1272d79b6df6SOr Gerlitz goto out_err; 1273d79b6df6SOr Gerlitz 1274d79b6df6SOr Gerlitz err = offload_pedit_fields(masks, vals, parse_attr); 1275d79b6df6SOr Gerlitz if (err < 0) 1276d79b6df6SOr Gerlitz goto out_dealloc_parsed_actions; 1277d79b6df6SOr Gerlitz 1278d79b6df6SOr Gerlitz for (cmd = 0; cmd < __PEDIT_CMD_MAX; cmd++) { 1279d79b6df6SOr Gerlitz cmd_masks = &masks[cmd]; 1280d79b6df6SOr Gerlitz if (memcmp(cmd_masks, &zero_masks, sizeof(zero_masks))) { 1281d79b6df6SOr Gerlitz printk(KERN_WARNING "mlx5: attempt to offload an unsupported field (cmd %d)\n", 1282d79b6df6SOr Gerlitz cmd); 1283d79b6df6SOr Gerlitz print_hex_dump(KERN_WARNING, "mask: ", DUMP_PREFIX_ADDRESS, 1284d79b6df6SOr Gerlitz 16, 1, cmd_masks, sizeof(zero_masks), true); 1285d79b6df6SOr Gerlitz err = -EOPNOTSUPP; 1286d79b6df6SOr Gerlitz goto out_dealloc_parsed_actions; 1287d79b6df6SOr Gerlitz } 1288d79b6df6SOr Gerlitz } 1289d79b6df6SOr Gerlitz 1290d79b6df6SOr Gerlitz return 0; 1291d79b6df6SOr Gerlitz 1292d79b6df6SOr Gerlitz out_dealloc_parsed_actions: 1293d79b6df6SOr Gerlitz kfree(parse_attr->mod_hdr_actions); 1294d79b6df6SOr Gerlitz out_err: 1295d79b6df6SOr Gerlitz return err; 1296d79b6df6SOr Gerlitz } 1297d79b6df6SOr Gerlitz 129826c02749SOr Gerlitz static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 update_flags) 129926c02749SOr Gerlitz { 130026c02749SOr Gerlitz u32 prot_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR | TCA_CSUM_UPDATE_FLAG_TCP | 130126c02749SOr Gerlitz TCA_CSUM_UPDATE_FLAG_UDP; 130226c02749SOr Gerlitz 130326c02749SOr Gerlitz /* The HW recalcs checksums only if re-writing headers */ 130426c02749SOr Gerlitz if (!(action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) { 130526c02749SOr Gerlitz netdev_warn(priv->netdev, 130626c02749SOr Gerlitz "TC csum action is only offloaded with pedit\n"); 130726c02749SOr Gerlitz return false; 130826c02749SOr Gerlitz } 130926c02749SOr Gerlitz 131026c02749SOr Gerlitz if (update_flags & ~prot_flags) { 131126c02749SOr Gerlitz netdev_warn(priv->netdev, 131226c02749SOr Gerlitz "can't offload TC csum action for some header/s - flags %#x\n", 131326c02749SOr Gerlitz update_flags); 131426c02749SOr Gerlitz return false; 131526c02749SOr Gerlitz } 131626c02749SOr Gerlitz 131726c02749SOr Gerlitz return true; 131826c02749SOr Gerlitz } 131926c02749SOr Gerlitz 13205c40348cSOr Gerlitz static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 1321aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 1322aa0cbbaeSOr Gerlitz struct mlx5e_tc_flow *flow) 1323e3a2b7edSAmir Vadai { 1324aa0cbbaeSOr Gerlitz struct mlx5_nic_flow_attr *attr = flow->nic_attr; 1325e3a2b7edSAmir Vadai const struct tc_action *a; 132622dc13c8SWANG Cong LIST_HEAD(actions); 13272f4fe4caSOr Gerlitz int err; 1328e3a2b7edSAmir Vadai 1329e3a2b7edSAmir Vadai if (tc_no_actions(exts)) 1330e3a2b7edSAmir Vadai return -EINVAL; 1331e3a2b7edSAmir Vadai 13323bc4b7bfSOr Gerlitz attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; 13333bc4b7bfSOr Gerlitz attr->action = 0; 1334e3a2b7edSAmir Vadai 133522dc13c8SWANG Cong tcf_exts_to_list(exts, &actions); 133622dc13c8SWANG Cong list_for_each_entry(a, &actions, list) { 1337e3a2b7edSAmir Vadai if (is_tcf_gact_shot(a)) { 13383bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP; 1339aad7e08dSAmir Vadai if (MLX5_CAP_FLOWTABLE(priv->mdev, 1340aad7e08dSAmir Vadai flow_table_properties_nic_receive.flow_counter)) 13413bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 1342e3a2b7edSAmir Vadai continue; 1343e3a2b7edSAmir Vadai } 1344e3a2b7edSAmir Vadai 13452f4fe4caSOr Gerlitz if (is_tcf_pedit(a)) { 13462f4fe4caSOr Gerlitz err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_KERNEL, 13472f4fe4caSOr Gerlitz parse_attr); 13482f4fe4caSOr Gerlitz if (err) 13492f4fe4caSOr Gerlitz return err; 13502f4fe4caSOr Gerlitz 13512f4fe4caSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | 13522f4fe4caSOr Gerlitz MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 13532f4fe4caSOr Gerlitz continue; 13542f4fe4caSOr Gerlitz } 13552f4fe4caSOr Gerlitz 135626c02749SOr Gerlitz if (is_tcf_csum(a)) { 135726c02749SOr Gerlitz if (csum_offload_supported(priv, attr->action, 135826c02749SOr Gerlitz tcf_csum_update_flags(a))) 135926c02749SOr Gerlitz continue; 136026c02749SOr Gerlitz 136126c02749SOr Gerlitz return -EOPNOTSUPP; 136226c02749SOr Gerlitz } 136326c02749SOr Gerlitz 1364e3a2b7edSAmir Vadai if (is_tcf_skbedit_mark(a)) { 1365e3a2b7edSAmir Vadai u32 mark = tcf_skbedit_mark(a); 1366e3a2b7edSAmir Vadai 1367e3a2b7edSAmir Vadai if (mark & ~MLX5E_TC_FLOW_ID_MASK) { 1368e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n", 1369e3a2b7edSAmir Vadai mark); 1370e3a2b7edSAmir Vadai return -EINVAL; 1371e3a2b7edSAmir Vadai } 1372e3a2b7edSAmir Vadai 13733bc4b7bfSOr Gerlitz attr->flow_tag = mark; 13743bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 1375e3a2b7edSAmir Vadai continue; 1376e3a2b7edSAmir Vadai } 1377e3a2b7edSAmir Vadai 1378e3a2b7edSAmir Vadai return -EINVAL; 1379e3a2b7edSAmir Vadai } 1380e3a2b7edSAmir Vadai 1381e3a2b7edSAmir Vadai return 0; 1382e3a2b7edSAmir Vadai } 1383e3a2b7edSAmir Vadai 138476f7444dSOr Gerlitz static inline int cmp_encap_info(struct ip_tunnel_key *a, 138576f7444dSOr Gerlitz struct ip_tunnel_key *b) 1386a54e20b4SHadar Hen Zion { 1387a54e20b4SHadar Hen Zion return memcmp(a, b, sizeof(*a)); 1388a54e20b4SHadar Hen Zion } 1389a54e20b4SHadar Hen Zion 139076f7444dSOr Gerlitz static inline int hash_encap_info(struct ip_tunnel_key *key) 1391a54e20b4SHadar Hen Zion { 139276f7444dSOr Gerlitz return jhash(key, sizeof(*key), 0); 1393a54e20b4SHadar Hen Zion } 1394a54e20b4SHadar Hen Zion 1395a54e20b4SHadar Hen Zion static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, 1396a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 1397a54e20b4SHadar Hen Zion struct net_device **out_dev, 1398a54e20b4SHadar Hen Zion struct flowi4 *fl4, 1399a54e20b4SHadar Hen Zion struct neighbour **out_n, 1400a54e20b4SHadar Hen Zion int *out_ttl) 1401a54e20b4SHadar Hen Zion { 14023e621b19SHadar Hen Zion struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 1403a54e20b4SHadar Hen Zion struct rtable *rt; 1404a54e20b4SHadar Hen Zion struct neighbour *n = NULL; 1405a54e20b4SHadar Hen Zion 1406a54e20b4SHadar Hen Zion #if IS_ENABLED(CONFIG_INET) 1407abeffce9SArnd Bergmann int ret; 1408abeffce9SArnd Bergmann 1409a54e20b4SHadar Hen Zion rt = ip_route_output_key(dev_net(mirred_dev), fl4); 1410abeffce9SArnd Bergmann ret = PTR_ERR_OR_ZERO(rt); 1411abeffce9SArnd Bergmann if (ret) 1412abeffce9SArnd Bergmann return ret; 1413a54e20b4SHadar Hen Zion #else 1414a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 1415a54e20b4SHadar Hen Zion #endif 14163e621b19SHadar Hen Zion /* if the egress device isn't on the same HW e-switch, we use the uplink */ 14173e621b19SHadar Hen Zion if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) 14183e621b19SHadar Hen Zion *out_dev = mlx5_eswitch_get_uplink_netdev(esw); 14193e621b19SHadar Hen Zion else 14203e621b19SHadar Hen Zion *out_dev = rt->dst.dev; 1421a54e20b4SHadar Hen Zion 142275c33da8SOr Gerlitz *out_ttl = ip4_dst_hoplimit(&rt->dst); 1423a54e20b4SHadar Hen Zion n = dst_neigh_lookup(&rt->dst, &fl4->daddr); 1424a54e20b4SHadar Hen Zion ip_rt_put(rt); 1425a54e20b4SHadar Hen Zion if (!n) 1426a54e20b4SHadar Hen Zion return -ENOMEM; 1427a54e20b4SHadar Hen Zion 1428a54e20b4SHadar Hen Zion *out_n = n; 1429a54e20b4SHadar Hen Zion return 0; 1430a54e20b4SHadar Hen Zion } 1431a54e20b4SHadar Hen Zion 1432ce99f6b9SOr Gerlitz static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, 1433ce99f6b9SOr Gerlitz struct net_device *mirred_dev, 1434ce99f6b9SOr Gerlitz struct net_device **out_dev, 1435ce99f6b9SOr Gerlitz struct flowi6 *fl6, 1436ce99f6b9SOr Gerlitz struct neighbour **out_n, 1437ce99f6b9SOr Gerlitz int *out_ttl) 1438ce99f6b9SOr Gerlitz { 1439ce99f6b9SOr Gerlitz struct neighbour *n = NULL; 1440ce99f6b9SOr Gerlitz struct dst_entry *dst; 1441ce99f6b9SOr Gerlitz 1442ce99f6b9SOr Gerlitz #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) 1443ce99f6b9SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 1444ce99f6b9SOr Gerlitz int ret; 1445ce99f6b9SOr Gerlitz 144608820528SPaul Blakey ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst, 144708820528SPaul Blakey fl6); 144808820528SPaul Blakey if (ret < 0) 1449ce99f6b9SOr Gerlitz return ret; 1450ce99f6b9SOr Gerlitz 1451ce99f6b9SOr Gerlitz *out_ttl = ip6_dst_hoplimit(dst); 1452ce99f6b9SOr Gerlitz 1453ce99f6b9SOr Gerlitz /* if the egress device isn't on the same HW e-switch, we use the uplink */ 1454ce99f6b9SOr Gerlitz if (!switchdev_port_same_parent_id(priv->netdev, dst->dev)) 1455ce99f6b9SOr Gerlitz *out_dev = mlx5_eswitch_get_uplink_netdev(esw); 1456ce99f6b9SOr Gerlitz else 1457ce99f6b9SOr Gerlitz *out_dev = dst->dev; 1458ce99f6b9SOr Gerlitz #else 1459ce99f6b9SOr Gerlitz return -EOPNOTSUPP; 1460ce99f6b9SOr Gerlitz #endif 1461ce99f6b9SOr Gerlitz 1462ce99f6b9SOr Gerlitz n = dst_neigh_lookup(dst, &fl6->daddr); 1463ce99f6b9SOr Gerlitz dst_release(dst); 1464ce99f6b9SOr Gerlitz if (!n) 1465ce99f6b9SOr Gerlitz return -ENOMEM; 1466ce99f6b9SOr Gerlitz 1467ce99f6b9SOr Gerlitz *out_n = n; 1468ce99f6b9SOr Gerlitz return 0; 1469ce99f6b9SOr Gerlitz } 1470ce99f6b9SOr Gerlitz 147132f3671fSOr Gerlitz static void gen_vxlan_header_ipv4(struct net_device *out_dev, 147232f3671fSOr Gerlitz char buf[], int encap_size, 1473a54e20b4SHadar Hen Zion unsigned char h_dest[ETH_ALEN], 1474a54e20b4SHadar Hen Zion int ttl, 1475a54e20b4SHadar Hen Zion __be32 daddr, 1476a54e20b4SHadar Hen Zion __be32 saddr, 1477a54e20b4SHadar Hen Zion __be16 udp_dst_port, 1478a54e20b4SHadar Hen Zion __be32 vx_vni) 1479a54e20b4SHadar Hen Zion { 1480a54e20b4SHadar Hen Zion struct ethhdr *eth = (struct ethhdr *)buf; 1481a54e20b4SHadar Hen Zion struct iphdr *ip = (struct iphdr *)((char *)eth + sizeof(struct ethhdr)); 1482a54e20b4SHadar Hen Zion struct udphdr *udp = (struct udphdr *)((char *)ip + sizeof(struct iphdr)); 1483a54e20b4SHadar Hen Zion struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 1484a54e20b4SHadar Hen Zion 1485a54e20b4SHadar Hen Zion memset(buf, 0, encap_size); 1486a54e20b4SHadar Hen Zion 1487a54e20b4SHadar Hen Zion ether_addr_copy(eth->h_dest, h_dest); 1488a54e20b4SHadar Hen Zion ether_addr_copy(eth->h_source, out_dev->dev_addr); 1489a54e20b4SHadar Hen Zion eth->h_proto = htons(ETH_P_IP); 1490a54e20b4SHadar Hen Zion 1491a54e20b4SHadar Hen Zion ip->daddr = daddr; 1492a54e20b4SHadar Hen Zion ip->saddr = saddr; 1493a54e20b4SHadar Hen Zion 1494a54e20b4SHadar Hen Zion ip->ttl = ttl; 1495a54e20b4SHadar Hen Zion ip->protocol = IPPROTO_UDP; 1496a54e20b4SHadar Hen Zion ip->version = 0x4; 1497a54e20b4SHadar Hen Zion ip->ihl = 0x5; 1498a54e20b4SHadar Hen Zion 1499a54e20b4SHadar Hen Zion udp->dest = udp_dst_port; 1500a54e20b4SHadar Hen Zion vxh->vx_flags = VXLAN_HF_VNI; 1501a54e20b4SHadar Hen Zion vxh->vx_vni = vxlan_vni_field(vx_vni); 1502a54e20b4SHadar Hen Zion } 1503a54e20b4SHadar Hen Zion 1504225aabafSOr Gerlitz static void gen_vxlan_header_ipv6(struct net_device *out_dev, 1505225aabafSOr Gerlitz char buf[], int encap_size, 1506ce99f6b9SOr Gerlitz unsigned char h_dest[ETH_ALEN], 1507ce99f6b9SOr Gerlitz int ttl, 1508ce99f6b9SOr Gerlitz struct in6_addr *daddr, 1509ce99f6b9SOr Gerlitz struct in6_addr *saddr, 1510ce99f6b9SOr Gerlitz __be16 udp_dst_port, 1511ce99f6b9SOr Gerlitz __be32 vx_vni) 1512ce99f6b9SOr Gerlitz { 1513ce99f6b9SOr Gerlitz struct ethhdr *eth = (struct ethhdr *)buf; 1514ce99f6b9SOr Gerlitz struct ipv6hdr *ip6h = (struct ipv6hdr *)((char *)eth + sizeof(struct ethhdr)); 1515ce99f6b9SOr Gerlitz struct udphdr *udp = (struct udphdr *)((char *)ip6h + sizeof(struct ipv6hdr)); 1516ce99f6b9SOr Gerlitz struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 1517ce99f6b9SOr Gerlitz 1518ce99f6b9SOr Gerlitz memset(buf, 0, encap_size); 1519ce99f6b9SOr Gerlitz 1520ce99f6b9SOr Gerlitz ether_addr_copy(eth->h_dest, h_dest); 1521ce99f6b9SOr Gerlitz ether_addr_copy(eth->h_source, out_dev->dev_addr); 1522ce99f6b9SOr Gerlitz eth->h_proto = htons(ETH_P_IPV6); 1523ce99f6b9SOr Gerlitz 1524ce99f6b9SOr Gerlitz ip6_flow_hdr(ip6h, 0, 0); 1525ce99f6b9SOr Gerlitz /* the HW fills up ipv6 payload len */ 1526ce99f6b9SOr Gerlitz ip6h->nexthdr = IPPROTO_UDP; 1527ce99f6b9SOr Gerlitz ip6h->hop_limit = ttl; 1528ce99f6b9SOr Gerlitz ip6h->daddr = *daddr; 1529ce99f6b9SOr Gerlitz ip6h->saddr = *saddr; 1530ce99f6b9SOr Gerlitz 1531ce99f6b9SOr Gerlitz udp->dest = udp_dst_port; 1532ce99f6b9SOr Gerlitz vxh->vx_flags = VXLAN_HF_VNI; 1533ce99f6b9SOr Gerlitz vxh->vx_vni = vxlan_vni_field(vx_vni); 1534ce99f6b9SOr Gerlitz } 1535ce99f6b9SOr Gerlitz 1536a54e20b4SHadar Hen Zion static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, 1537a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 15381a8552bdSHadar Hen Zion struct mlx5e_encap_entry *e) 1539a54e20b4SHadar Hen Zion { 1540a54e20b4SHadar Hen Zion int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); 154132f3671fSOr Gerlitz int ipv4_encap_size = ETH_HLEN + sizeof(struct iphdr) + VXLAN_HLEN; 154276f7444dSOr Gerlitz struct ip_tunnel_key *tun_key = &e->tun_info.key; 15431a8552bdSHadar Hen Zion struct net_device *out_dev; 1544a42485ebSOr Gerlitz struct neighbour *n = NULL; 1545a54e20b4SHadar Hen Zion struct flowi4 fl4 = {}; 1546a54e20b4SHadar Hen Zion char *encap_header; 154732f3671fSOr Gerlitz int ttl, err; 1548033354d5SHadar Hen Zion u8 nud_state; 1549a54e20b4SHadar Hen Zion 155032f3671fSOr Gerlitz if (max_encap_size < ipv4_encap_size) { 155132f3671fSOr Gerlitz mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", 155232f3671fSOr Gerlitz ipv4_encap_size, max_encap_size); 155332f3671fSOr Gerlitz return -EOPNOTSUPP; 155432f3671fSOr Gerlitz } 155532f3671fSOr Gerlitz 155632f3671fSOr Gerlitz encap_header = kzalloc(ipv4_encap_size, GFP_KERNEL); 1557a54e20b4SHadar Hen Zion if (!encap_header) 1558a54e20b4SHadar Hen Zion return -ENOMEM; 1559a54e20b4SHadar Hen Zion 1560a54e20b4SHadar Hen Zion switch (e->tunnel_type) { 1561a54e20b4SHadar Hen Zion case MLX5_HEADER_TYPE_VXLAN: 1562a54e20b4SHadar Hen Zion fl4.flowi4_proto = IPPROTO_UDP; 156376f7444dSOr Gerlitz fl4.fl4_dport = tun_key->tp_dst; 1564a54e20b4SHadar Hen Zion break; 1565a54e20b4SHadar Hen Zion default: 1566a54e20b4SHadar Hen Zion err = -EOPNOTSUPP; 1567a54e20b4SHadar Hen Zion goto out; 1568a54e20b4SHadar Hen Zion } 15699a941117SOr Gerlitz fl4.flowi4_tos = tun_key->tos; 157076f7444dSOr Gerlitz fl4.daddr = tun_key->u.ipv4.dst; 15719a941117SOr Gerlitz fl4.saddr = tun_key->u.ipv4.src; 1572a54e20b4SHadar Hen Zion 15731a8552bdSHadar Hen Zion err = mlx5e_route_lookup_ipv4(priv, mirred_dev, &out_dev, 15749a941117SOr Gerlitz &fl4, &n, &ttl); 1575a54e20b4SHadar Hen Zion if (err) 1576a54e20b4SHadar Hen Zion goto out; 1577a54e20b4SHadar Hen Zion 1578232c0013SHadar Hen Zion /* used by mlx5e_detach_encap to lookup a neigh hash table 1579232c0013SHadar Hen Zion * entry in the neigh hash table when a user deletes a rule 1580232c0013SHadar Hen Zion */ 1581232c0013SHadar Hen Zion e->m_neigh.dev = n->dev; 1582f6dfb4c3SHadar Hen Zion e->m_neigh.family = n->ops->family; 1583232c0013SHadar Hen Zion memcpy(&e->m_neigh.dst_ip, n->primary_key, n->tbl->key_len); 1584232c0013SHadar Hen Zion e->out_dev = out_dev; 1585232c0013SHadar Hen Zion 1586232c0013SHadar Hen Zion /* It's importent to add the neigh to the hash table before checking 1587232c0013SHadar Hen Zion * the neigh validity state. So if we'll get a notification, in case the 1588232c0013SHadar Hen Zion * neigh changes it's validity state, we would find the relevant neigh 1589232c0013SHadar Hen Zion * in the hash. 1590232c0013SHadar Hen Zion */ 1591232c0013SHadar Hen Zion err = mlx5e_rep_encap_entry_attach(netdev_priv(out_dev), e); 1592232c0013SHadar Hen Zion if (err) 1593232c0013SHadar Hen Zion goto out; 1594232c0013SHadar Hen Zion 1595033354d5SHadar Hen Zion read_lock_bh(&n->lock); 1596033354d5SHadar Hen Zion nud_state = n->nud_state; 1597033354d5SHadar Hen Zion ether_addr_copy(e->h_dest, n->ha); 1598033354d5SHadar Hen Zion read_unlock_bh(&n->lock); 1599033354d5SHadar Hen Zion 1600a54e20b4SHadar Hen Zion switch (e->tunnel_type) { 1601a54e20b4SHadar Hen Zion case MLX5_HEADER_TYPE_VXLAN: 16021a8552bdSHadar Hen Zion gen_vxlan_header_ipv4(out_dev, encap_header, 160332f3671fSOr Gerlitz ipv4_encap_size, e->h_dest, ttl, 16049a941117SOr Gerlitz fl4.daddr, 16059a941117SOr Gerlitz fl4.saddr, tun_key->tp_dst, 160676f7444dSOr Gerlitz tunnel_id_to_key32(tun_key->tun_id)); 1607a54e20b4SHadar Hen Zion break; 1608a54e20b4SHadar Hen Zion default: 1609a54e20b4SHadar Hen Zion err = -EOPNOTSUPP; 1610232c0013SHadar Hen Zion goto destroy_neigh_entry; 1611232c0013SHadar Hen Zion } 1612232c0013SHadar Hen Zion e->encap_size = ipv4_encap_size; 1613232c0013SHadar Hen Zion e->encap_header = encap_header; 1614232c0013SHadar Hen Zion 1615232c0013SHadar Hen Zion if (!(nud_state & NUD_VALID)) { 1616232c0013SHadar Hen Zion neigh_event_send(n, NULL); 161727902f08SWei Yongjun err = -EAGAIN; 161827902f08SWei Yongjun goto out; 1619a54e20b4SHadar Hen Zion } 1620a54e20b4SHadar Hen Zion 1621a54e20b4SHadar Hen Zion err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, 162232f3671fSOr Gerlitz ipv4_encap_size, encap_header, &e->encap_id); 1623232c0013SHadar Hen Zion if (err) 1624232c0013SHadar Hen Zion goto destroy_neigh_entry; 1625232c0013SHadar Hen Zion 1626232c0013SHadar Hen Zion e->flags |= MLX5_ENCAP_ENTRY_VALID; 1627f6dfb4c3SHadar Hen Zion mlx5e_rep_queue_neigh_stats_work(netdev_priv(out_dev)); 1628a42485ebSOr Gerlitz neigh_release(n); 1629232c0013SHadar Hen Zion return err; 1630232c0013SHadar Hen Zion 1631232c0013SHadar Hen Zion destroy_neigh_entry: 1632232c0013SHadar Hen Zion mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); 1633232c0013SHadar Hen Zion out: 1634a54e20b4SHadar Hen Zion kfree(encap_header); 1635232c0013SHadar Hen Zion if (n) 1636232c0013SHadar Hen Zion neigh_release(n); 1637a54e20b4SHadar Hen Zion return err; 1638a54e20b4SHadar Hen Zion } 1639a54e20b4SHadar Hen Zion 1640ce99f6b9SOr Gerlitz static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, 1641ce99f6b9SOr Gerlitz struct net_device *mirred_dev, 16421a8552bdSHadar Hen Zion struct mlx5e_encap_entry *e) 1643ce99f6b9SOr Gerlitz { 1644ce99f6b9SOr Gerlitz int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); 1645225aabafSOr Gerlitz int ipv6_encap_size = ETH_HLEN + sizeof(struct ipv6hdr) + VXLAN_HLEN; 1646ce99f6b9SOr Gerlitz struct ip_tunnel_key *tun_key = &e->tun_info.key; 16471a8552bdSHadar Hen Zion struct net_device *out_dev; 1648ce99f6b9SOr Gerlitz struct neighbour *n = NULL; 1649ce99f6b9SOr Gerlitz struct flowi6 fl6 = {}; 1650ce99f6b9SOr Gerlitz char *encap_header; 1651225aabafSOr Gerlitz int err, ttl = 0; 1652033354d5SHadar Hen Zion u8 nud_state; 1653ce99f6b9SOr Gerlitz 1654225aabafSOr Gerlitz if (max_encap_size < ipv6_encap_size) { 1655225aabafSOr Gerlitz mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", 1656225aabafSOr Gerlitz ipv6_encap_size, max_encap_size); 1657225aabafSOr Gerlitz return -EOPNOTSUPP; 1658225aabafSOr Gerlitz } 1659225aabafSOr Gerlitz 1660225aabafSOr Gerlitz encap_header = kzalloc(ipv6_encap_size, GFP_KERNEL); 1661ce99f6b9SOr Gerlitz if (!encap_header) 1662ce99f6b9SOr Gerlitz return -ENOMEM; 1663ce99f6b9SOr Gerlitz 1664ce99f6b9SOr Gerlitz switch (e->tunnel_type) { 1665ce99f6b9SOr Gerlitz case MLX5_HEADER_TYPE_VXLAN: 1666ce99f6b9SOr Gerlitz fl6.flowi6_proto = IPPROTO_UDP; 1667ce99f6b9SOr Gerlitz fl6.fl6_dport = tun_key->tp_dst; 1668ce99f6b9SOr Gerlitz break; 1669ce99f6b9SOr Gerlitz default: 1670ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 1671ce99f6b9SOr Gerlitz goto out; 1672ce99f6b9SOr Gerlitz } 1673ce99f6b9SOr Gerlitz 1674ce99f6b9SOr Gerlitz fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tun_key->tos), tun_key->label); 1675ce99f6b9SOr Gerlitz fl6.daddr = tun_key->u.ipv6.dst; 1676ce99f6b9SOr Gerlitz fl6.saddr = tun_key->u.ipv6.src; 1677ce99f6b9SOr Gerlitz 16781a8552bdSHadar Hen Zion err = mlx5e_route_lookup_ipv6(priv, mirred_dev, &out_dev, 1679ce99f6b9SOr Gerlitz &fl6, &n, &ttl); 1680ce99f6b9SOr Gerlitz if (err) 1681ce99f6b9SOr Gerlitz goto out; 1682ce99f6b9SOr Gerlitz 1683232c0013SHadar Hen Zion /* used by mlx5e_detach_encap to lookup a neigh hash table 1684232c0013SHadar Hen Zion * entry in the neigh hash table when a user deletes a rule 1685232c0013SHadar Hen Zion */ 1686232c0013SHadar Hen Zion e->m_neigh.dev = n->dev; 1687f6dfb4c3SHadar Hen Zion e->m_neigh.family = n->ops->family; 1688232c0013SHadar Hen Zion memcpy(&e->m_neigh.dst_ip, n->primary_key, n->tbl->key_len); 1689232c0013SHadar Hen Zion e->out_dev = out_dev; 1690232c0013SHadar Hen Zion 1691232c0013SHadar Hen Zion /* It's importent to add the neigh to the hash table before checking 1692232c0013SHadar Hen Zion * the neigh validity state. So if we'll get a notification, in case the 1693232c0013SHadar Hen Zion * neigh changes it's validity state, we would find the relevant neigh 1694232c0013SHadar Hen Zion * in the hash. 1695232c0013SHadar Hen Zion */ 1696232c0013SHadar Hen Zion err = mlx5e_rep_encap_entry_attach(netdev_priv(out_dev), e); 1697232c0013SHadar Hen Zion if (err) 1698232c0013SHadar Hen Zion goto out; 1699232c0013SHadar Hen Zion 1700033354d5SHadar Hen Zion read_lock_bh(&n->lock); 1701033354d5SHadar Hen Zion nud_state = n->nud_state; 1702033354d5SHadar Hen Zion ether_addr_copy(e->h_dest, n->ha); 1703033354d5SHadar Hen Zion read_unlock_bh(&n->lock); 1704033354d5SHadar Hen Zion 1705ce99f6b9SOr Gerlitz switch (e->tunnel_type) { 1706ce99f6b9SOr Gerlitz case MLX5_HEADER_TYPE_VXLAN: 17071a8552bdSHadar Hen Zion gen_vxlan_header_ipv6(out_dev, encap_header, 1708225aabafSOr Gerlitz ipv6_encap_size, e->h_dest, ttl, 1709ce99f6b9SOr Gerlitz &fl6.daddr, 1710ce99f6b9SOr Gerlitz &fl6.saddr, tun_key->tp_dst, 1711ce99f6b9SOr Gerlitz tunnel_id_to_key32(tun_key->tun_id)); 1712ce99f6b9SOr Gerlitz break; 1713ce99f6b9SOr Gerlitz default: 1714ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 1715232c0013SHadar Hen Zion goto destroy_neigh_entry; 1716232c0013SHadar Hen Zion } 1717232c0013SHadar Hen Zion 1718232c0013SHadar Hen Zion e->encap_size = ipv6_encap_size; 1719232c0013SHadar Hen Zion e->encap_header = encap_header; 1720232c0013SHadar Hen Zion 1721232c0013SHadar Hen Zion if (!(nud_state & NUD_VALID)) { 1722232c0013SHadar Hen Zion neigh_event_send(n, NULL); 172327902f08SWei Yongjun err = -EAGAIN; 172427902f08SWei Yongjun goto out; 1725ce99f6b9SOr Gerlitz } 1726ce99f6b9SOr Gerlitz 1727ce99f6b9SOr Gerlitz err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, 1728225aabafSOr Gerlitz ipv6_encap_size, encap_header, &e->encap_id); 1729232c0013SHadar Hen Zion if (err) 1730232c0013SHadar Hen Zion goto destroy_neigh_entry; 1731232c0013SHadar Hen Zion 1732232c0013SHadar Hen Zion e->flags |= MLX5_ENCAP_ENTRY_VALID; 1733f6dfb4c3SHadar Hen Zion mlx5e_rep_queue_neigh_stats_work(netdev_priv(out_dev)); 1734ce99f6b9SOr Gerlitz neigh_release(n); 1735232c0013SHadar Hen Zion return err; 1736232c0013SHadar Hen Zion 1737232c0013SHadar Hen Zion destroy_neigh_entry: 1738232c0013SHadar Hen Zion mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); 1739232c0013SHadar Hen Zion out: 1740ce99f6b9SOr Gerlitz kfree(encap_header); 1741232c0013SHadar Hen Zion if (n) 1742232c0013SHadar Hen Zion neigh_release(n); 1743ce99f6b9SOr Gerlitz return err; 1744ce99f6b9SOr Gerlitz } 1745ce99f6b9SOr Gerlitz 1746a54e20b4SHadar Hen Zion static int mlx5e_attach_encap(struct mlx5e_priv *priv, 1747a54e20b4SHadar Hen Zion struct ip_tunnel_info *tun_info, 1748a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 174945247bf2SOr Gerlitz struct net_device **encap_dev, 175045247bf2SOr Gerlitz struct mlx5e_tc_flow *flow) 175103a9d11eSOr Gerlitz { 1752a54e20b4SHadar Hen Zion struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 17531ad9a00aSPaul Blakey struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw); 1754a54e20b4SHadar Hen Zion unsigned short family = ip_tunnel_info_af(tun_info); 175545247bf2SOr Gerlitz struct mlx5e_priv *up_priv = netdev_priv(up_dev); 175645247bf2SOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 1757a54e20b4SHadar Hen Zion struct ip_tunnel_key *key = &tun_info->key; 1758c1ae1152SOr Gerlitz struct mlx5e_encap_entry *e; 175945247bf2SOr Gerlitz int tunnel_type, err = 0; 1760a54e20b4SHadar Hen Zion uintptr_t hash_key; 1761a54e20b4SHadar Hen Zion bool found = false; 1762a54e20b4SHadar Hen Zion 17632fcd82e9SOr Gerlitz /* udp dst port must be set */ 1764a54e20b4SHadar Hen Zion if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst))) 17652fcd82e9SOr Gerlitz goto vxlan_encap_offload_err; 1766a54e20b4SHadar Hen Zion 1767cd377663SOr Gerlitz /* setting udp src port isn't supported */ 17682fcd82e9SOr Gerlitz if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) { 17692fcd82e9SOr Gerlitz vxlan_encap_offload_err: 17702fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 17712fcd82e9SOr Gerlitz "must set udp dst port and not set udp src port\n"); 1772cd377663SOr Gerlitz return -EOPNOTSUPP; 17732fcd82e9SOr Gerlitz } 1774cd377663SOr Gerlitz 17751ad9a00aSPaul Blakey if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->tp_dst)) && 1776a54e20b4SHadar Hen Zion MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) { 1777a54e20b4SHadar Hen Zion tunnel_type = MLX5_HEADER_TYPE_VXLAN; 1778a54e20b4SHadar Hen Zion } else { 17792fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 17802fcd82e9SOr Gerlitz "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst)); 1781a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 1782a54e20b4SHadar Hen Zion } 1783a54e20b4SHadar Hen Zion 178476f7444dSOr Gerlitz hash_key = hash_encap_info(key); 1785a54e20b4SHadar Hen Zion 1786a54e20b4SHadar Hen Zion hash_for_each_possible_rcu(esw->offloads.encap_tbl, e, 1787a54e20b4SHadar Hen Zion encap_hlist, hash_key) { 178876f7444dSOr Gerlitz if (!cmp_encap_info(&e->tun_info.key, key)) { 1789a54e20b4SHadar Hen Zion found = true; 1790a54e20b4SHadar Hen Zion break; 1791a54e20b4SHadar Hen Zion } 1792a54e20b4SHadar Hen Zion } 1793a54e20b4SHadar Hen Zion 179445247bf2SOr Gerlitz if (found) 179545247bf2SOr Gerlitz goto attach_flow; 1796a54e20b4SHadar Hen Zion 1797a54e20b4SHadar Hen Zion e = kzalloc(sizeof(*e), GFP_KERNEL); 1798a54e20b4SHadar Hen Zion if (!e) 1799a54e20b4SHadar Hen Zion return -ENOMEM; 1800a54e20b4SHadar Hen Zion 180176f7444dSOr Gerlitz e->tun_info = *tun_info; 1802a54e20b4SHadar Hen Zion e->tunnel_type = tunnel_type; 1803a54e20b4SHadar Hen Zion INIT_LIST_HEAD(&e->flows); 1804a54e20b4SHadar Hen Zion 1805ce99f6b9SOr Gerlitz if (family == AF_INET) 18061a8552bdSHadar Hen Zion err = mlx5e_create_encap_header_ipv4(priv, mirred_dev, e); 1807ce99f6b9SOr Gerlitz else if (family == AF_INET6) 18081a8552bdSHadar Hen Zion err = mlx5e_create_encap_header_ipv6(priv, mirred_dev, e); 1809ce99f6b9SOr Gerlitz 1810232c0013SHadar Hen Zion if (err && err != -EAGAIN) 1811a54e20b4SHadar Hen Zion goto out_err; 1812a54e20b4SHadar Hen Zion 1813a54e20b4SHadar Hen Zion hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key); 1814a54e20b4SHadar Hen Zion 181545247bf2SOr Gerlitz attach_flow: 181645247bf2SOr Gerlitz list_add(&flow->encap, &e->flows); 181745247bf2SOr Gerlitz *encap_dev = e->out_dev; 1818232c0013SHadar Hen Zion if (e->flags & MLX5_ENCAP_ENTRY_VALID) 181945247bf2SOr Gerlitz attr->encap_id = e->encap_id; 182045247bf2SOr Gerlitz 1821232c0013SHadar Hen Zion return err; 1822a54e20b4SHadar Hen Zion 1823a54e20b4SHadar Hen Zion out_err: 1824a54e20b4SHadar Hen Zion kfree(e); 1825a54e20b4SHadar Hen Zion return err; 1826a54e20b4SHadar Hen Zion } 1827a54e20b4SHadar Hen Zion 1828a54e20b4SHadar Hen Zion static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 1829d7e75a32SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 1830a54e20b4SHadar Hen Zion struct mlx5e_tc_flow *flow) 1831a54e20b4SHadar Hen Zion { 1832ecf5bb79SOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 18331d447a39SSaeed Mahameed struct mlx5e_rep_priv *rpriv = priv->ppriv; 1834a54e20b4SHadar Hen Zion struct ip_tunnel_info *info = NULL; 183503a9d11eSOr Gerlitz const struct tc_action *a; 183622dc13c8SWANG Cong LIST_HEAD(actions); 1837a54e20b4SHadar Hen Zion bool encap = false; 1838232c0013SHadar Hen Zion int err = 0; 183903a9d11eSOr Gerlitz 184003a9d11eSOr Gerlitz if (tc_no_actions(exts)) 184103a9d11eSOr Gerlitz return -EINVAL; 184203a9d11eSOr Gerlitz 1843776b12b6SOr Gerlitz memset(attr, 0, sizeof(*attr)); 18441d447a39SSaeed Mahameed attr->in_rep = rpriv->rep; 184503a9d11eSOr Gerlitz 184622dc13c8SWANG Cong tcf_exts_to_list(exts, &actions); 184722dc13c8SWANG Cong list_for_each_entry(a, &actions, list) { 184803a9d11eSOr Gerlitz if (is_tcf_gact_shot(a)) { 18498b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP | 185003a9d11eSOr Gerlitz MLX5_FLOW_CONTEXT_ACTION_COUNT; 185103a9d11eSOr Gerlitz continue; 185203a9d11eSOr Gerlitz } 185303a9d11eSOr Gerlitz 1854d7e75a32SOr Gerlitz if (is_tcf_pedit(a)) { 1855d7e75a32SOr Gerlitz err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_FDB, 1856d7e75a32SOr Gerlitz parse_attr); 1857d7e75a32SOr Gerlitz if (err) 1858d7e75a32SOr Gerlitz return err; 1859d7e75a32SOr Gerlitz 1860d7e75a32SOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; 1861d7e75a32SOr Gerlitz continue; 1862d7e75a32SOr Gerlitz } 1863d7e75a32SOr Gerlitz 186426c02749SOr Gerlitz if (is_tcf_csum(a)) { 186526c02749SOr Gerlitz if (csum_offload_supported(priv, attr->action, 186626c02749SOr Gerlitz tcf_csum_update_flags(a))) 186726c02749SOr Gerlitz continue; 186826c02749SOr Gerlitz 186926c02749SOr Gerlitz return -EOPNOTSUPP; 187026c02749SOr Gerlitz } 187126c02749SOr Gerlitz 18725724b8b5SShmulik Ladkani if (is_tcf_mirred_egress_redirect(a)) { 187303a9d11eSOr Gerlitz int ifindex = tcf_mirred_ifindex(a); 187445247bf2SOr Gerlitz struct net_device *out_dev, *encap_dev = NULL; 187503a9d11eSOr Gerlitz struct mlx5e_priv *out_priv; 187603a9d11eSOr Gerlitz 187703a9d11eSOr Gerlitz out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex); 187803a9d11eSOr Gerlitz 1879a54e20b4SHadar Hen Zion if (switchdev_port_same_parent_id(priv->netdev, 1880a54e20b4SHadar Hen Zion out_dev)) { 1881e37a79e5SMark Bloch attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1882e37a79e5SMark Bloch MLX5_FLOW_CONTEXT_ACTION_COUNT; 188303a9d11eSOr Gerlitz out_priv = netdev_priv(out_dev); 18841d447a39SSaeed Mahameed rpriv = out_priv->ppriv; 18851d447a39SSaeed Mahameed attr->out_rep = rpriv->rep; 1886a54e20b4SHadar Hen Zion } else if (encap) { 1887a54e20b4SHadar Hen Zion err = mlx5e_attach_encap(priv, info, 188845247bf2SOr Gerlitz out_dev, &encap_dev, flow); 1889232c0013SHadar Hen Zion if (err && err != -EAGAIN) 1890a54e20b4SHadar Hen Zion return err; 1891a54e20b4SHadar Hen Zion attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP | 1892a54e20b4SHadar Hen Zion MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1893a54e20b4SHadar Hen Zion MLX5_FLOW_CONTEXT_ACTION_COUNT; 189445247bf2SOr Gerlitz out_priv = netdev_priv(encap_dev); 18951d447a39SSaeed Mahameed rpriv = out_priv->ppriv; 18961d447a39SSaeed Mahameed attr->out_rep = rpriv->rep; 1897232c0013SHadar Hen Zion attr->parse_attr = parse_attr; 1898a54e20b4SHadar Hen Zion } else { 1899a54e20b4SHadar Hen Zion pr_err("devices %s %s not on same switch HW, can't offload forwarding\n", 1900a54e20b4SHadar Hen Zion priv->netdev->name, out_dev->name); 1901a54e20b4SHadar Hen Zion return -EINVAL; 1902a54e20b4SHadar Hen Zion } 1903a54e20b4SHadar Hen Zion continue; 1904a54e20b4SHadar Hen Zion } 1905a54e20b4SHadar Hen Zion 1906a54e20b4SHadar Hen Zion if (is_tcf_tunnel_set(a)) { 1907a54e20b4SHadar Hen Zion info = tcf_tunnel_info(a); 1908a54e20b4SHadar Hen Zion if (info) 1909a54e20b4SHadar Hen Zion encap = true; 1910a54e20b4SHadar Hen Zion else 1911a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 191203a9d11eSOr Gerlitz continue; 191303a9d11eSOr Gerlitz } 191403a9d11eSOr Gerlitz 19158b32580dSOr Gerlitz if (is_tcf_vlan(a)) { 191609c91ddfSOr Gerlitz if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { 19178b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 191809c91ddfSOr Gerlitz } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { 19198b32580dSOr Gerlitz if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q)) 19208b32580dSOr Gerlitz return -EOPNOTSUPP; 19218b32580dSOr Gerlitz 19228b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; 19238b32580dSOr Gerlitz attr->vlan = tcf_vlan_push_vid(a); 192409c91ddfSOr Gerlitz } else { /* action is TCA_VLAN_ACT_MODIFY */ 192509c91ddfSOr Gerlitz return -EOPNOTSUPP; 19268b32580dSOr Gerlitz } 19278b32580dSOr Gerlitz continue; 19288b32580dSOr Gerlitz } 19298b32580dSOr Gerlitz 1930bbd00f7eSHadar Hen Zion if (is_tcf_tunnel_release(a)) { 1931bbd00f7eSHadar Hen Zion attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; 1932bbd00f7eSHadar Hen Zion continue; 1933bbd00f7eSHadar Hen Zion } 1934bbd00f7eSHadar Hen Zion 193503a9d11eSOr Gerlitz return -EINVAL; 193603a9d11eSOr Gerlitz } 1937232c0013SHadar Hen Zion return err; 193803a9d11eSOr Gerlitz } 193903a9d11eSOr Gerlitz 1940e3a2b7edSAmir Vadai int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, 1941e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 1942e3a2b7edSAmir Vadai { 1943adb4c123SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 194417091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr; 19453bc4b7bfSOr Gerlitz struct mlx5e_tc_table *tc = &priv->fs.tc; 19463bc4b7bfSOr Gerlitz struct mlx5e_tc_flow *flow; 19473bc4b7bfSOr Gerlitz int attr_size, err = 0; 194865ba8fb7SOr Gerlitz u8 flow_flags = 0; 1949e3a2b7edSAmir Vadai 195065ba8fb7SOr Gerlitz if (esw && esw->mode == SRIOV_OFFLOADS) { 195165ba8fb7SOr Gerlitz flow_flags = MLX5E_TC_FLOW_ESWITCH; 195265ba8fb7SOr Gerlitz attr_size = sizeof(struct mlx5_esw_flow_attr); 19533bc4b7bfSOr Gerlitz } else { 19543bc4b7bfSOr Gerlitz flow_flags = MLX5E_TC_FLOW_NIC; 19553bc4b7bfSOr Gerlitz attr_size = sizeof(struct mlx5_nic_flow_attr); 195665ba8fb7SOr Gerlitz } 1957776b12b6SOr Gerlitz 195865ba8fb7SOr Gerlitz flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL); 19591b9a07eeSLeon Romanovsky parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL); 196017091853SOr Gerlitz if (!parse_attr || !flow) { 1961e3a2b7edSAmir Vadai err = -ENOMEM; 1962e3a2b7edSAmir Vadai goto err_free; 1963e3a2b7edSAmir Vadai } 1964e3a2b7edSAmir Vadai 1965e3a2b7edSAmir Vadai flow->cookie = f->cookie; 196665ba8fb7SOr Gerlitz flow->flags = flow_flags; 1967e3a2b7edSAmir Vadai 196817091853SOr Gerlitz err = parse_cls_flower(priv, flow, &parse_attr->spec, f); 1969e3a2b7edSAmir Vadai if (err < 0) 1970e3a2b7edSAmir Vadai goto err_free; 1971e3a2b7edSAmir Vadai 197265ba8fb7SOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { 1973d7e75a32SOr Gerlitz err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow); 1974adb4c123SOr Gerlitz if (err < 0) 1975232c0013SHadar Hen Zion goto err_handle_encap_flow; 1976aa0cbbaeSOr Gerlitz flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow); 1977adb4c123SOr Gerlitz } else { 1978aa0cbbaeSOr Gerlitz err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow); 1979e3a2b7edSAmir Vadai if (err < 0) 1980e3a2b7edSAmir Vadai goto err_free; 1981aa0cbbaeSOr Gerlitz flow->rule = mlx5e_tc_add_nic_flow(priv, parse_attr, flow); 1982adb4c123SOr Gerlitz } 1983adb4c123SOr Gerlitz 19845c40348cSOr Gerlitz if (IS_ERR(flow->rule)) { 19855c40348cSOr Gerlitz err = PTR_ERR(flow->rule); 1986aa0cbbaeSOr Gerlitz goto err_free; 19875c40348cSOr Gerlitz } 19885c40348cSOr Gerlitz 19890b67a38fSHadar Hen Zion flow->flags |= MLX5E_TC_FLOW_OFFLOADED; 1990e3a2b7edSAmir Vadai err = rhashtable_insert_fast(&tc->ht, &flow->node, 1991e3a2b7edSAmir Vadai tc->ht_params); 1992e3a2b7edSAmir Vadai if (err) 19935c40348cSOr Gerlitz goto err_del_rule; 1994e3a2b7edSAmir Vadai 1995232c0013SHadar Hen Zion if (flow->flags & MLX5E_TC_FLOW_ESWITCH && 1996232c0013SHadar Hen Zion !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)) 1997232c0013SHadar Hen Zion kvfree(parse_attr); 1998232c0013SHadar Hen Zion return err; 1999e3a2b7edSAmir Vadai 20005c40348cSOr Gerlitz err_del_rule: 20015e86397aSOr Gerlitz mlx5e_tc_del_flow(priv, flow); 2002e3a2b7edSAmir Vadai 2003232c0013SHadar Hen Zion err_handle_encap_flow: 2004232c0013SHadar Hen Zion if (err == -EAGAIN) { 2005232c0013SHadar Hen Zion err = rhashtable_insert_fast(&tc->ht, &flow->node, 2006232c0013SHadar Hen Zion tc->ht_params); 2007232c0013SHadar Hen Zion if (err) 2008232c0013SHadar Hen Zion mlx5e_tc_del_flow(priv, flow); 2009232c0013SHadar Hen Zion else 2010232c0013SHadar Hen Zion return 0; 2011232c0013SHadar Hen Zion } 2012232c0013SHadar Hen Zion 2013e3a2b7edSAmir Vadai err_free: 201417091853SOr Gerlitz kvfree(parse_attr); 2015232c0013SHadar Hen Zion kfree(flow); 2016e3a2b7edSAmir Vadai return err; 2017e3a2b7edSAmir Vadai } 2018e3a2b7edSAmir Vadai 2019e3a2b7edSAmir Vadai int mlx5e_delete_flower(struct mlx5e_priv *priv, 2020e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 2021e3a2b7edSAmir Vadai { 2022e3a2b7edSAmir Vadai struct mlx5e_tc_flow *flow; 2023acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 2024e3a2b7edSAmir Vadai 2025e3a2b7edSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 2026e3a2b7edSAmir Vadai tc->ht_params); 2027e3a2b7edSAmir Vadai if (!flow) 2028e3a2b7edSAmir Vadai return -EINVAL; 2029e3a2b7edSAmir Vadai 2030e3a2b7edSAmir Vadai rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params); 2031e3a2b7edSAmir Vadai 2032961e8979SRoi Dayan mlx5e_tc_del_flow(priv, flow); 2033e3a2b7edSAmir Vadai 2034e3a2b7edSAmir Vadai kfree(flow); 2035e3a2b7edSAmir Vadai 2036e3a2b7edSAmir Vadai return 0; 2037e3a2b7edSAmir Vadai } 2038e3a2b7edSAmir Vadai 2039aad7e08dSAmir Vadai int mlx5e_stats_flower(struct mlx5e_priv *priv, 2040aad7e08dSAmir Vadai struct tc_cls_flower_offload *f) 2041aad7e08dSAmir Vadai { 2042aad7e08dSAmir Vadai struct mlx5e_tc_table *tc = &priv->fs.tc; 2043aad7e08dSAmir Vadai struct mlx5e_tc_flow *flow; 2044aad7e08dSAmir Vadai struct mlx5_fc *counter; 2045aad7e08dSAmir Vadai u64 bytes; 2046aad7e08dSAmir Vadai u64 packets; 2047aad7e08dSAmir Vadai u64 lastuse; 2048aad7e08dSAmir Vadai 2049aad7e08dSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 2050aad7e08dSAmir Vadai tc->ht_params); 2051aad7e08dSAmir Vadai if (!flow) 2052aad7e08dSAmir Vadai return -EINVAL; 2053aad7e08dSAmir Vadai 20540b67a38fSHadar Hen Zion if (!(flow->flags & MLX5E_TC_FLOW_OFFLOADED)) 20550b67a38fSHadar Hen Zion return 0; 20560b67a38fSHadar Hen Zion 2057aad7e08dSAmir Vadai counter = mlx5_flow_rule_counter(flow->rule); 2058aad7e08dSAmir Vadai if (!counter) 2059aad7e08dSAmir Vadai return 0; 2060aad7e08dSAmir Vadai 2061aad7e08dSAmir Vadai mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); 2062aad7e08dSAmir Vadai 2063d897a638SJakub Kicinski tcf_exts_stats_update(f->exts, bytes, packets, lastuse); 2064fed06ee8SOr Gerlitz 2065aad7e08dSAmir Vadai return 0; 2066aad7e08dSAmir Vadai } 2067aad7e08dSAmir Vadai 2068e8f887acSAmir Vadai static const struct rhashtable_params mlx5e_tc_flow_ht_params = { 2069e8f887acSAmir Vadai .head_offset = offsetof(struct mlx5e_tc_flow, node), 2070e8f887acSAmir Vadai .key_offset = offsetof(struct mlx5e_tc_flow, cookie), 2071e8f887acSAmir Vadai .key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie), 2072e8f887acSAmir Vadai .automatic_shrinking = true, 2073e8f887acSAmir Vadai }; 2074e8f887acSAmir Vadai 2075e8f887acSAmir Vadai int mlx5e_tc_init(struct mlx5e_priv *priv) 2076e8f887acSAmir Vadai { 2077acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 2078e8f887acSAmir Vadai 207911c9c548SOr Gerlitz hash_init(tc->mod_hdr_tbl); 208011c9c548SOr Gerlitz 2081e8f887acSAmir Vadai tc->ht_params = mlx5e_tc_flow_ht_params; 2082e8f887acSAmir Vadai return rhashtable_init(&tc->ht, &tc->ht_params); 2083e8f887acSAmir Vadai } 2084e8f887acSAmir Vadai 2085e8f887acSAmir Vadai static void _mlx5e_tc_del_flow(void *ptr, void *arg) 2086e8f887acSAmir Vadai { 2087e8f887acSAmir Vadai struct mlx5e_tc_flow *flow = ptr; 2088e8f887acSAmir Vadai struct mlx5e_priv *priv = arg; 2089e8f887acSAmir Vadai 2090961e8979SRoi Dayan mlx5e_tc_del_flow(priv, flow); 2091e8f887acSAmir Vadai kfree(flow); 2092e8f887acSAmir Vadai } 2093e8f887acSAmir Vadai 2094e8f887acSAmir Vadai void mlx5e_tc_cleanup(struct mlx5e_priv *priv) 2095e8f887acSAmir Vadai { 2096acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 2097e8f887acSAmir Vadai 2098e8f887acSAmir Vadai rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv); 2099e8f887acSAmir Vadai 2100acff797cSMaor Gottlieb if (!IS_ERR_OR_NULL(tc->t)) { 2101acff797cSMaor Gottlieb mlx5_destroy_flow_table(tc->t); 2102acff797cSMaor Gottlieb tc->t = NULL; 2103e8f887acSAmir Vadai } 2104e8f887acSAmir Vadai } 2105