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> 34e3a2b7edSAmir Vadai #include <net/pkt_cls.h> 35e3a2b7edSAmir Vadai #include <net/tc_act/tc_gact.h> 3612185a9fSAmir Vadai #include <net/tc_act/tc_skbedit.h> 37e8f887acSAmir Vadai #include <linux/mlx5/fs.h> 38e8f887acSAmir Vadai #include <linux/mlx5/device.h> 39e8f887acSAmir Vadai #include <linux/rhashtable.h> 40e8f887acSAmir Vadai #include "en.h" 41e8f887acSAmir Vadai #include "en_tc.h" 42e8f887acSAmir Vadai 43e8f887acSAmir Vadai struct mlx5e_tc_flow { 44e8f887acSAmir Vadai struct rhash_head node; 45e8f887acSAmir Vadai u64 cookie; 46e8f887acSAmir Vadai struct mlx5_flow_rule *rule; 47e8f887acSAmir Vadai }; 48e8f887acSAmir Vadai 49acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_ENTRIES 1024 50acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_GROUPS 4 51e8f887acSAmir Vadai 52e8f887acSAmir Vadai static struct mlx5_flow_rule *mlx5e_tc_add_flow(struct mlx5e_priv *priv, 53e8f887acSAmir Vadai u32 *match_c, u32 *match_v, 54e8f887acSAmir Vadai u32 action, u32 flow_tag) 55e8f887acSAmir Vadai { 56e8f887acSAmir Vadai struct mlx5_flow_destination dest = { 57e8f887acSAmir Vadai .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE, 58acff797cSMaor Gottlieb {.ft = priv->fs.vlan.ft.t}, 59e8f887acSAmir Vadai }; 60e8f887acSAmir Vadai struct mlx5_flow_rule *rule; 61e8f887acSAmir Vadai bool table_created = false; 62e8f887acSAmir Vadai 63acff797cSMaor Gottlieb if (IS_ERR_OR_NULL(priv->fs.tc.t)) { 64acff797cSMaor Gottlieb priv->fs.tc.t = 65acff797cSMaor Gottlieb mlx5_create_auto_grouped_flow_table(priv->fs.ns, 66acff797cSMaor Gottlieb MLX5E_TC_PRIO, 67acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_ENTRIES, 68acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_GROUPS, 69d63cd286SMaor Gottlieb 0); 70acff797cSMaor Gottlieb if (IS_ERR(priv->fs.tc.t)) { 71e8f887acSAmir Vadai netdev_err(priv->netdev, 72e8f887acSAmir Vadai "Failed to create tc offload table\n"); 73acff797cSMaor Gottlieb return ERR_CAST(priv->fs.tc.t); 74e8f887acSAmir Vadai } 75e8f887acSAmir Vadai 76e8f887acSAmir Vadai table_created = true; 77e8f887acSAmir Vadai } 78e8f887acSAmir Vadai 79acff797cSMaor Gottlieb rule = mlx5_add_flow_rule(priv->fs.tc.t, MLX5_MATCH_OUTER_HEADERS, 80e8f887acSAmir Vadai match_c, match_v, 81e8f887acSAmir Vadai action, flow_tag, 82e8f887acSAmir Vadai action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST ? &dest : NULL); 83e8f887acSAmir Vadai 84e8f887acSAmir Vadai if (IS_ERR(rule) && table_created) { 85acff797cSMaor Gottlieb mlx5_destroy_flow_table(priv->fs.tc.t); 86acff797cSMaor Gottlieb priv->fs.tc.t = NULL; 87e8f887acSAmir Vadai } 88e8f887acSAmir Vadai 89e8f887acSAmir Vadai return rule; 90e8f887acSAmir Vadai } 91e8f887acSAmir Vadai 92e8f887acSAmir Vadai static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, 93e8f887acSAmir Vadai struct mlx5_flow_rule *rule) 94e8f887acSAmir Vadai { 95e8f887acSAmir Vadai mlx5_del_flow_rule(rule); 96e8f887acSAmir Vadai 97e8f887acSAmir Vadai if (!mlx5e_tc_num_filters(priv)) { 98acff797cSMaor Gottlieb mlx5_destroy_flow_table(priv->fs.tc.t); 99acff797cSMaor Gottlieb priv->fs.tc.t = NULL; 100e8f887acSAmir Vadai } 101e8f887acSAmir Vadai } 102e8f887acSAmir Vadai 103e3a2b7edSAmir Vadai static int parse_cls_flower(struct mlx5e_priv *priv, 104e3a2b7edSAmir Vadai u32 *match_c, u32 *match_v, 105e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 106e3a2b7edSAmir Vadai { 107e3a2b7edSAmir Vadai void *headers_c = MLX5_ADDR_OF(fte_match_param, match_c, outer_headers); 108e3a2b7edSAmir Vadai void *headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers); 109e3a2b7edSAmir Vadai u16 addr_type = 0; 110e3a2b7edSAmir Vadai u8 ip_proto = 0; 111e3a2b7edSAmir Vadai 112e3a2b7edSAmir Vadai if (f->dissector->used_keys & 113e3a2b7edSAmir Vadai ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 114e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_BASIC) | 115e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 116e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 117e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 118e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_PORTS))) { 119e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", 120e3a2b7edSAmir Vadai f->dissector->used_keys); 121e3a2b7edSAmir Vadai return -EOPNOTSUPP; 122e3a2b7edSAmir Vadai } 123e3a2b7edSAmir Vadai 124e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) { 125e3a2b7edSAmir Vadai struct flow_dissector_key_control *key = 126e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 127e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 128e3a2b7edSAmir Vadai f->key); 129e3a2b7edSAmir Vadai addr_type = key->addr_type; 130e3a2b7edSAmir Vadai } 131e3a2b7edSAmir Vadai 132e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) { 133e3a2b7edSAmir Vadai struct flow_dissector_key_basic *key = 134e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 135e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 136e3a2b7edSAmir Vadai f->key); 137e3a2b7edSAmir Vadai struct flow_dissector_key_basic *mask = 138e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 139e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 140e3a2b7edSAmir Vadai f->mask); 141e3a2b7edSAmir Vadai ip_proto = key->ip_proto; 142e3a2b7edSAmir Vadai 143e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype, 144e3a2b7edSAmir Vadai ntohs(mask->n_proto)); 145e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 146e3a2b7edSAmir Vadai ntohs(key->n_proto)); 147e3a2b7edSAmir Vadai 148e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol, 149e3a2b7edSAmir Vadai mask->ip_proto); 150e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 151e3a2b7edSAmir Vadai key->ip_proto); 152e3a2b7edSAmir Vadai } 153e3a2b7edSAmir Vadai 154e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 155e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *key = 156e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 157e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 158e3a2b7edSAmir Vadai f->key); 159e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *mask = 160e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 161e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 162e3a2b7edSAmir Vadai f->mask); 163e3a2b7edSAmir Vadai 164e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 165e3a2b7edSAmir Vadai dmac_47_16), 166e3a2b7edSAmir Vadai mask->dst); 167e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 168e3a2b7edSAmir Vadai dmac_47_16), 169e3a2b7edSAmir Vadai key->dst); 170e3a2b7edSAmir Vadai 171e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 172e3a2b7edSAmir Vadai smac_47_16), 173e3a2b7edSAmir Vadai mask->src); 174e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 175e3a2b7edSAmir Vadai smac_47_16), 176e3a2b7edSAmir Vadai key->src); 177e3a2b7edSAmir Vadai } 178e3a2b7edSAmir Vadai 179e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 180e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *key = 181e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 182e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 183e3a2b7edSAmir Vadai f->key); 184e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *mask = 185e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 186e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 187e3a2b7edSAmir Vadai f->mask); 188e3a2b7edSAmir Vadai 189e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 190e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 191e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 192e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 193e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 194e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 195e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 196e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 197e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 198e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 199e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 200e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 201e3a2b7edSAmir Vadai } 202e3a2b7edSAmir Vadai 203e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 204e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *key = 205e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 206e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 207e3a2b7edSAmir Vadai f->key); 208e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *mask = 209e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 210e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 211e3a2b7edSAmir Vadai f->mask); 212e3a2b7edSAmir Vadai 213e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 214e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 215e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 216e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 217e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 218e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 219e3a2b7edSAmir Vadai 220e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 221e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 222e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 223e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 224e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 225e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 226e3a2b7edSAmir Vadai } 227e3a2b7edSAmir Vadai 228e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) { 229e3a2b7edSAmir Vadai struct flow_dissector_key_ports *key = 230e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 231e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 232e3a2b7edSAmir Vadai f->key); 233e3a2b7edSAmir Vadai struct flow_dissector_key_ports *mask = 234e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 235e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 236e3a2b7edSAmir Vadai f->mask); 237e3a2b7edSAmir Vadai switch (ip_proto) { 238e3a2b7edSAmir Vadai case IPPROTO_TCP: 239e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 240e3a2b7edSAmir Vadai tcp_sport, ntohs(mask->src)); 241e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 242e3a2b7edSAmir Vadai tcp_sport, ntohs(key->src)); 243e3a2b7edSAmir Vadai 244e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 245e3a2b7edSAmir Vadai tcp_dport, ntohs(mask->dst)); 246e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 247e3a2b7edSAmir Vadai tcp_dport, ntohs(key->dst)); 248e3a2b7edSAmir Vadai break; 249e3a2b7edSAmir Vadai 250e3a2b7edSAmir Vadai case IPPROTO_UDP: 251e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 252e3a2b7edSAmir Vadai udp_sport, ntohs(mask->src)); 253e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 254e3a2b7edSAmir Vadai udp_sport, ntohs(key->src)); 255e3a2b7edSAmir Vadai 256e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 257e3a2b7edSAmir Vadai udp_dport, ntohs(mask->dst)); 258e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 259e3a2b7edSAmir Vadai udp_dport, ntohs(key->dst)); 260e3a2b7edSAmir Vadai break; 261e3a2b7edSAmir Vadai default: 262e3a2b7edSAmir Vadai netdev_err(priv->netdev, 263e3a2b7edSAmir Vadai "Only UDP and TCP transport are supported\n"); 264e3a2b7edSAmir Vadai return -EINVAL; 265e3a2b7edSAmir Vadai } 266e3a2b7edSAmir Vadai } 267e3a2b7edSAmir Vadai 268e3a2b7edSAmir Vadai return 0; 269e3a2b7edSAmir Vadai } 270e3a2b7edSAmir Vadai 271e3a2b7edSAmir Vadai static int parse_tc_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 272e3a2b7edSAmir Vadai u32 *action, u32 *flow_tag) 273e3a2b7edSAmir Vadai { 274e3a2b7edSAmir Vadai const struct tc_action *a; 275e3a2b7edSAmir Vadai 276e3a2b7edSAmir Vadai if (tc_no_actions(exts)) 277e3a2b7edSAmir Vadai return -EINVAL; 278e3a2b7edSAmir Vadai 279e3a2b7edSAmir Vadai *flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; 280e3a2b7edSAmir Vadai *action = 0; 281e3a2b7edSAmir Vadai 282e3a2b7edSAmir Vadai tc_for_each_action(a, exts) { 283e3a2b7edSAmir Vadai /* Only support a single action per rule */ 284e3a2b7edSAmir Vadai if (*action) 285e3a2b7edSAmir Vadai return -EINVAL; 286e3a2b7edSAmir Vadai 287e3a2b7edSAmir Vadai if (is_tcf_gact_shot(a)) { 288e3a2b7edSAmir Vadai *action |= MLX5_FLOW_CONTEXT_ACTION_DROP; 289e3a2b7edSAmir Vadai continue; 290e3a2b7edSAmir Vadai } 291e3a2b7edSAmir Vadai 292e3a2b7edSAmir Vadai if (is_tcf_skbedit_mark(a)) { 293e3a2b7edSAmir Vadai u32 mark = tcf_skbedit_mark(a); 294e3a2b7edSAmir Vadai 295e3a2b7edSAmir Vadai if (mark & ~MLX5E_TC_FLOW_ID_MASK) { 296e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n", 297e3a2b7edSAmir Vadai mark); 298e3a2b7edSAmir Vadai return -EINVAL; 299e3a2b7edSAmir Vadai } 300e3a2b7edSAmir Vadai 301e3a2b7edSAmir Vadai *flow_tag = mark; 302e3a2b7edSAmir Vadai *action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 303e3a2b7edSAmir Vadai continue; 304e3a2b7edSAmir Vadai } 305e3a2b7edSAmir Vadai 306e3a2b7edSAmir Vadai return -EINVAL; 307e3a2b7edSAmir Vadai } 308e3a2b7edSAmir Vadai 309e3a2b7edSAmir Vadai return 0; 310e3a2b7edSAmir Vadai } 311e3a2b7edSAmir Vadai 312e3a2b7edSAmir Vadai int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, 313e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 314e3a2b7edSAmir Vadai { 315acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 316e3a2b7edSAmir Vadai u32 *match_c; 317e3a2b7edSAmir Vadai u32 *match_v; 318e3a2b7edSAmir Vadai int err = 0; 319e3a2b7edSAmir Vadai u32 flow_tag; 320e3a2b7edSAmir Vadai u32 action; 321e3a2b7edSAmir Vadai struct mlx5e_tc_flow *flow; 322e3a2b7edSAmir Vadai struct mlx5_flow_rule *old = NULL; 323e3a2b7edSAmir Vadai 324e3a2b7edSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 325e3a2b7edSAmir Vadai tc->ht_params); 326e3a2b7edSAmir Vadai if (flow) 327e3a2b7edSAmir Vadai old = flow->rule; 328e3a2b7edSAmir Vadai else 329e3a2b7edSAmir Vadai flow = kzalloc(sizeof(*flow), GFP_KERNEL); 330e3a2b7edSAmir Vadai 331e3a2b7edSAmir Vadai match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 332e3a2b7edSAmir Vadai match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 333e3a2b7edSAmir Vadai if (!match_c || !match_v || !flow) { 334e3a2b7edSAmir Vadai err = -ENOMEM; 335e3a2b7edSAmir Vadai goto err_free; 336e3a2b7edSAmir Vadai } 337e3a2b7edSAmir Vadai 338e3a2b7edSAmir Vadai flow->cookie = f->cookie; 339e3a2b7edSAmir Vadai 340e3a2b7edSAmir Vadai err = parse_cls_flower(priv, match_c, match_v, f); 341e3a2b7edSAmir Vadai if (err < 0) 342e3a2b7edSAmir Vadai goto err_free; 343e3a2b7edSAmir Vadai 344e3a2b7edSAmir Vadai err = parse_tc_actions(priv, f->exts, &action, &flow_tag); 345e3a2b7edSAmir Vadai if (err < 0) 346e3a2b7edSAmir Vadai goto err_free; 347e3a2b7edSAmir Vadai 348e3a2b7edSAmir Vadai err = rhashtable_insert_fast(&tc->ht, &flow->node, 349e3a2b7edSAmir Vadai tc->ht_params); 350e3a2b7edSAmir Vadai if (err) 351e3a2b7edSAmir Vadai goto err_free; 352e3a2b7edSAmir Vadai 353e3a2b7edSAmir Vadai flow->rule = mlx5e_tc_add_flow(priv, match_c, match_v, action, 354e3a2b7edSAmir Vadai flow_tag); 355e3a2b7edSAmir Vadai if (IS_ERR(flow->rule)) { 356e3a2b7edSAmir Vadai err = PTR_ERR(flow->rule); 357e3a2b7edSAmir Vadai goto err_hash_del; 358e3a2b7edSAmir Vadai } 359e3a2b7edSAmir Vadai 360e3a2b7edSAmir Vadai if (old) 361e3a2b7edSAmir Vadai mlx5e_tc_del_flow(priv, old); 362e3a2b7edSAmir Vadai 363e3a2b7edSAmir Vadai goto out; 364e3a2b7edSAmir Vadai 365e3a2b7edSAmir Vadai err_hash_del: 366e3a2b7edSAmir Vadai rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params); 367e3a2b7edSAmir Vadai 368e3a2b7edSAmir Vadai err_free: 369e3a2b7edSAmir Vadai if (!old) 370e3a2b7edSAmir Vadai kfree(flow); 371e3a2b7edSAmir Vadai out: 372e3a2b7edSAmir Vadai kfree(match_c); 373e3a2b7edSAmir Vadai kfree(match_v); 374e3a2b7edSAmir Vadai return err; 375e3a2b7edSAmir Vadai } 376e3a2b7edSAmir Vadai 377e3a2b7edSAmir Vadai int mlx5e_delete_flower(struct mlx5e_priv *priv, 378e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 379e3a2b7edSAmir Vadai { 380e3a2b7edSAmir Vadai struct mlx5e_tc_flow *flow; 381acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 382e3a2b7edSAmir Vadai 383e3a2b7edSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 384e3a2b7edSAmir Vadai tc->ht_params); 385e3a2b7edSAmir Vadai if (!flow) 386e3a2b7edSAmir Vadai return -EINVAL; 387e3a2b7edSAmir Vadai 388e3a2b7edSAmir Vadai rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params); 389e3a2b7edSAmir Vadai 390e3a2b7edSAmir Vadai mlx5e_tc_del_flow(priv, flow->rule); 391e3a2b7edSAmir Vadai 392e3a2b7edSAmir Vadai kfree(flow); 393e3a2b7edSAmir Vadai 394e3a2b7edSAmir Vadai return 0; 395e3a2b7edSAmir Vadai } 396e3a2b7edSAmir Vadai 397e8f887acSAmir Vadai static const struct rhashtable_params mlx5e_tc_flow_ht_params = { 398e8f887acSAmir Vadai .head_offset = offsetof(struct mlx5e_tc_flow, node), 399e8f887acSAmir Vadai .key_offset = offsetof(struct mlx5e_tc_flow, cookie), 400e8f887acSAmir Vadai .key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie), 401e8f887acSAmir Vadai .automatic_shrinking = true, 402e8f887acSAmir Vadai }; 403e8f887acSAmir Vadai 404e8f887acSAmir Vadai int mlx5e_tc_init(struct mlx5e_priv *priv) 405e8f887acSAmir Vadai { 406acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 407e8f887acSAmir Vadai 408e8f887acSAmir Vadai tc->ht_params = mlx5e_tc_flow_ht_params; 409e8f887acSAmir Vadai return rhashtable_init(&tc->ht, &tc->ht_params); 410e8f887acSAmir Vadai } 411e8f887acSAmir Vadai 412e8f887acSAmir Vadai static void _mlx5e_tc_del_flow(void *ptr, void *arg) 413e8f887acSAmir Vadai { 414e8f887acSAmir Vadai struct mlx5e_tc_flow *flow = ptr; 415e8f887acSAmir Vadai struct mlx5e_priv *priv = arg; 416e8f887acSAmir Vadai 417e8f887acSAmir Vadai mlx5e_tc_del_flow(priv, flow->rule); 418e8f887acSAmir Vadai kfree(flow); 419e8f887acSAmir Vadai } 420e8f887acSAmir Vadai 421e8f887acSAmir Vadai void mlx5e_tc_cleanup(struct mlx5e_priv *priv) 422e8f887acSAmir Vadai { 423acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 424e8f887acSAmir Vadai 425e8f887acSAmir Vadai rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv); 426e8f887acSAmir Vadai 427acff797cSMaor Gottlieb if (!IS_ERR_OR_NULL(tc->t)) { 428acff797cSMaor Gottlieb mlx5_destroy_flow_table(tc->t); 429acff797cSMaor Gottlieb tc->t = NULL; 430e8f887acSAmir Vadai } 431e8f887acSAmir Vadai } 432