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> 45a54e20b4SHadar Hen Zion #include <net/vxlan.h> 46e8f887acSAmir Vadai #include "en.h" 47e8f887acSAmir Vadai #include "en_tc.h" 4803a9d11eSOr Gerlitz #include "eswitch.h" 49bbd00f7eSHadar Hen Zion #include "vxlan.h" 50e8f887acSAmir Vadai 513bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr { 523bc4b7bfSOr Gerlitz u32 action; 533bc4b7bfSOr Gerlitz u32 flow_tag; 543bc4b7bfSOr Gerlitz }; 553bc4b7bfSOr Gerlitz 5665ba8fb7SOr Gerlitz enum { 5765ba8fb7SOr Gerlitz MLX5E_TC_FLOW_ESWITCH = BIT(0), 583bc4b7bfSOr Gerlitz MLX5E_TC_FLOW_NIC = BIT(1), 5965ba8fb7SOr Gerlitz }; 6065ba8fb7SOr Gerlitz 61e8f887acSAmir Vadai struct mlx5e_tc_flow { 62e8f887acSAmir Vadai struct rhash_head node; 63e8f887acSAmir Vadai u64 cookie; 6465ba8fb7SOr Gerlitz u8 flags; 6574491de9SMark Bloch struct mlx5_flow_handle *rule; 66a54e20b4SHadar Hen Zion struct list_head encap; /* flows sharing the same encap */ 673bc4b7bfSOr Gerlitz union { 68ecf5bb79SOr Gerlitz struct mlx5_esw_flow_attr esw_attr[0]; 693bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr nic_attr[0]; 703bc4b7bfSOr Gerlitz }; 71e8f887acSAmir Vadai }; 72e8f887acSAmir Vadai 7317091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr { 7417091853SOr Gerlitz struct mlx5_flow_spec spec; 7517091853SOr Gerlitz }; 7617091853SOr Gerlitz 77a54e20b4SHadar Hen Zion enum { 78a54e20b4SHadar Hen Zion MLX5_HEADER_TYPE_VXLAN = 0x0, 79a54e20b4SHadar Hen Zion MLX5_HEADER_TYPE_NVGRE = 0x1, 80a54e20b4SHadar Hen Zion }; 81a54e20b4SHadar Hen Zion 82acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_ENTRIES 1024 83acff797cSMaor Gottlieb #define MLX5E_TC_TABLE_NUM_GROUPS 4 84e8f887acSAmir Vadai 8574491de9SMark Bloch static struct mlx5_flow_handle * 8674491de9SMark Bloch mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, 8717091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 883bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr *attr) 89e8f887acSAmir Vadai { 90aad7e08dSAmir Vadai struct mlx5_core_dev *dev = priv->mdev; 91aad7e08dSAmir Vadai struct mlx5_flow_destination dest = { 0 }; 9266958ed9SHadar Hen Zion struct mlx5_flow_act flow_act = { 933bc4b7bfSOr Gerlitz .action = attr->action, 943bc4b7bfSOr Gerlitz .flow_tag = attr->flow_tag, 9566958ed9SHadar Hen Zion .encap_id = 0, 9666958ed9SHadar Hen Zion }; 97aad7e08dSAmir Vadai struct mlx5_fc *counter = NULL; 9874491de9SMark Bloch struct mlx5_flow_handle *rule; 99e8f887acSAmir Vadai bool table_created = false; 100e8f887acSAmir Vadai 1013bc4b7bfSOr Gerlitz if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 102aad7e08dSAmir Vadai dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 103aad7e08dSAmir Vadai dest.ft = priv->fs.vlan.ft.t; 1043bc4b7bfSOr Gerlitz } else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 105aad7e08dSAmir Vadai counter = mlx5_fc_create(dev, true); 106aad7e08dSAmir Vadai if (IS_ERR(counter)) 107aad7e08dSAmir Vadai return ERR_CAST(counter); 108aad7e08dSAmir Vadai 109aad7e08dSAmir Vadai dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 110aad7e08dSAmir Vadai dest.counter = counter; 111aad7e08dSAmir Vadai } 112aad7e08dSAmir Vadai 113acff797cSMaor Gottlieb if (IS_ERR_OR_NULL(priv->fs.tc.t)) { 114acff797cSMaor Gottlieb priv->fs.tc.t = 115acff797cSMaor Gottlieb mlx5_create_auto_grouped_flow_table(priv->fs.ns, 116acff797cSMaor Gottlieb MLX5E_TC_PRIO, 117acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_ENTRIES, 118acff797cSMaor Gottlieb MLX5E_TC_TABLE_NUM_GROUPS, 119c9f1b073SHadar Hen Zion 0, 0); 120acff797cSMaor Gottlieb if (IS_ERR(priv->fs.tc.t)) { 121e8f887acSAmir Vadai netdev_err(priv->netdev, 122e8f887acSAmir Vadai "Failed to create tc offload table\n"); 123aad7e08dSAmir Vadai rule = ERR_CAST(priv->fs.tc.t); 124aad7e08dSAmir Vadai goto err_create_ft; 125e8f887acSAmir Vadai } 126e8f887acSAmir Vadai 127e8f887acSAmir Vadai table_created = true; 128e8f887acSAmir Vadai } 129e8f887acSAmir Vadai 13017091853SOr Gerlitz parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 13117091853SOr Gerlitz rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec, 13217091853SOr Gerlitz &flow_act, &dest, 1); 133e8f887acSAmir Vadai 134aad7e08dSAmir Vadai if (IS_ERR(rule)) 135aad7e08dSAmir Vadai goto err_add_rule; 136aad7e08dSAmir Vadai 137aad7e08dSAmir Vadai return rule; 138aad7e08dSAmir Vadai 139aad7e08dSAmir Vadai err_add_rule: 140aad7e08dSAmir Vadai if (table_created) { 141acff797cSMaor Gottlieb mlx5_destroy_flow_table(priv->fs.tc.t); 142acff797cSMaor Gottlieb priv->fs.tc.t = NULL; 143e8f887acSAmir Vadai } 144aad7e08dSAmir Vadai err_create_ft: 145aad7e08dSAmir Vadai mlx5_fc_destroy(dev, counter); 146e8f887acSAmir Vadai 147e8f887acSAmir Vadai return rule; 148e8f887acSAmir Vadai } 149e8f887acSAmir Vadai 150d85cdccbSOr Gerlitz static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, 151d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 152d85cdccbSOr Gerlitz { 153d85cdccbSOr Gerlitz struct mlx5_fc *counter = NULL; 154d85cdccbSOr Gerlitz 155d85cdccbSOr Gerlitz if (!IS_ERR(flow->rule)) { 156d85cdccbSOr Gerlitz counter = mlx5_flow_rule_counter(flow->rule); 157d85cdccbSOr Gerlitz mlx5_del_flow_rules(flow->rule); 158d85cdccbSOr Gerlitz mlx5_fc_destroy(priv->mdev, counter); 159d85cdccbSOr Gerlitz } 160d85cdccbSOr Gerlitz 161d85cdccbSOr Gerlitz if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) { 162d85cdccbSOr Gerlitz mlx5_destroy_flow_table(priv->fs.tc.t); 163d85cdccbSOr Gerlitz priv->fs.tc.t = NULL; 164d85cdccbSOr Gerlitz } 165d85cdccbSOr Gerlitz } 166d85cdccbSOr Gerlitz 16774491de9SMark Bloch static struct mlx5_flow_handle * 16874491de9SMark Bloch mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, 16917091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr, 170776b12b6SOr Gerlitz struct mlx5_esw_flow_attr *attr) 171adb4c123SOr Gerlitz { 172adb4c123SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 1738b32580dSOr Gerlitz int err; 1748b32580dSOr Gerlitz 1758b32580dSOr Gerlitz err = mlx5_eswitch_add_vlan_action(esw, attr); 1768b32580dSOr Gerlitz if (err) 1778b32580dSOr Gerlitz return ERR_PTR(err); 178adb4c123SOr Gerlitz 17917091853SOr Gerlitz return mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); 180adb4c123SOr Gerlitz } 181adb4c123SOr Gerlitz 1825067b602SRoi Dayan static void mlx5e_detach_encap(struct mlx5e_priv *priv, 183d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow); 184d85cdccbSOr Gerlitz 185d85cdccbSOr Gerlitz static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, 186d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 187d85cdccbSOr Gerlitz { 188d85cdccbSOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 189d85cdccbSOr Gerlitz 190ecf5bb79SOr Gerlitz mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr); 191d85cdccbSOr Gerlitz 192ecf5bb79SOr Gerlitz mlx5_eswitch_del_vlan_action(esw, flow->esw_attr); 193d85cdccbSOr Gerlitz 194ecf5bb79SOr Gerlitz if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) 195d85cdccbSOr Gerlitz mlx5e_detach_encap(priv, flow); 196d85cdccbSOr Gerlitz } 197d85cdccbSOr Gerlitz 198d85cdccbSOr Gerlitz static void mlx5e_detach_encap(struct mlx5e_priv *priv, 199d85cdccbSOr Gerlitz struct mlx5e_tc_flow *flow) 200d85cdccbSOr Gerlitz { 2015067b602SRoi Dayan struct list_head *next = flow->encap.next; 2025067b602SRoi Dayan 2035067b602SRoi Dayan list_del(&flow->encap); 2045067b602SRoi Dayan if (list_empty(next)) { 2055067b602SRoi Dayan struct mlx5_encap_entry *e; 2065067b602SRoi Dayan 2075067b602SRoi Dayan e = list_entry(next, struct mlx5_encap_entry, flows); 2085067b602SRoi Dayan if (e->n) { 2095067b602SRoi Dayan mlx5_encap_dealloc(priv->mdev, e->encap_id); 2105067b602SRoi Dayan neigh_release(e->n); 2115067b602SRoi Dayan } 2125067b602SRoi Dayan hlist_del_rcu(&e->encap_hlist); 2135067b602SRoi Dayan kfree(e); 2145067b602SRoi Dayan } 2155067b602SRoi Dayan } 2165067b602SRoi Dayan 2175e86397aSOr Gerlitz /* we get here also when setting rule to the FW failed, etc. It means that the 2185e86397aSOr Gerlitz * flow rule itself might not exist, but some offloading related to the actions 2195e86397aSOr Gerlitz * should be cleaned. 2205e86397aSOr Gerlitz */ 221e8f887acSAmir Vadai static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, 222961e8979SRoi Dayan struct mlx5e_tc_flow *flow) 223e8f887acSAmir Vadai { 224d85cdccbSOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) 225d85cdccbSOr Gerlitz mlx5e_tc_del_fdb_flow(priv, flow); 226d85cdccbSOr Gerlitz else 227d85cdccbSOr Gerlitz mlx5e_tc_del_nic_flow(priv, flow); 228e8f887acSAmir Vadai } 229e8f887acSAmir Vadai 230bbd00f7eSHadar Hen Zion static void parse_vxlan_attr(struct mlx5_flow_spec *spec, 231bbd00f7eSHadar Hen Zion struct tc_cls_flower_offload *f) 232bbd00f7eSHadar Hen Zion { 233bbd00f7eSHadar Hen Zion void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 234bbd00f7eSHadar Hen Zion outer_headers); 235bbd00f7eSHadar Hen Zion void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 236bbd00f7eSHadar Hen Zion outer_headers); 237bbd00f7eSHadar Hen Zion void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 238bbd00f7eSHadar Hen Zion misc_parameters); 239bbd00f7eSHadar Hen Zion void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 240bbd00f7eSHadar Hen Zion misc_parameters); 241bbd00f7eSHadar Hen Zion 242bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol); 243bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP); 244bbd00f7eSHadar Hen Zion 245bbd00f7eSHadar Hen Zion if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) { 246bbd00f7eSHadar Hen Zion struct flow_dissector_key_keyid *key = 247bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 248bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, 249bbd00f7eSHadar Hen Zion f->key); 250bbd00f7eSHadar Hen Zion struct flow_dissector_key_keyid *mask = 251bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 252bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, 253bbd00f7eSHadar Hen Zion f->mask); 254bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni, 255bbd00f7eSHadar Hen Zion be32_to_cpu(mask->keyid)); 256bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni, 257bbd00f7eSHadar Hen Zion be32_to_cpu(key->keyid)); 258bbd00f7eSHadar Hen Zion } 259bbd00f7eSHadar Hen Zion } 260bbd00f7eSHadar Hen Zion 261bbd00f7eSHadar Hen Zion static int parse_tunnel_attr(struct mlx5e_priv *priv, 262bbd00f7eSHadar Hen Zion struct mlx5_flow_spec *spec, 263bbd00f7eSHadar Hen Zion struct tc_cls_flower_offload *f) 264bbd00f7eSHadar Hen Zion { 265bbd00f7eSHadar Hen Zion void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 266bbd00f7eSHadar Hen Zion outer_headers); 267bbd00f7eSHadar Hen Zion void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 268bbd00f7eSHadar Hen Zion outer_headers); 269bbd00f7eSHadar Hen Zion 2702e72eb43SOr Gerlitz struct flow_dissector_key_control *enc_control = 2712e72eb43SOr Gerlitz skb_flow_dissector_target(f->dissector, 2722e72eb43SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_CONTROL, 2732e72eb43SOr Gerlitz f->key); 2742e72eb43SOr Gerlitz 275bbd00f7eSHadar Hen Zion if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) { 276bbd00f7eSHadar Hen Zion struct flow_dissector_key_ports *key = 277bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 278bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, 279bbd00f7eSHadar Hen Zion f->key); 280bbd00f7eSHadar Hen Zion struct flow_dissector_key_ports *mask = 281bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 282bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, 283bbd00f7eSHadar Hen Zion f->mask); 2841ad9a00aSPaul Blakey struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 2851ad9a00aSPaul Blakey struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw); 2861ad9a00aSPaul Blakey struct mlx5e_priv *up_priv = netdev_priv(up_dev); 287bbd00f7eSHadar Hen Zion 288bbd00f7eSHadar Hen Zion /* Full udp dst port must be given */ 289bbd00f7eSHadar Hen Zion if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst))) 2902fcd82e9SOr Gerlitz goto vxlan_match_offload_err; 291bbd00f7eSHadar Hen Zion 2921ad9a00aSPaul Blakey if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->dst)) && 293bbd00f7eSHadar Hen Zion MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) 294bbd00f7eSHadar Hen Zion parse_vxlan_attr(spec, f); 2952fcd82e9SOr Gerlitz else { 2962fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 2972fcd82e9SOr Gerlitz "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst)); 298bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 2992fcd82e9SOr Gerlitz } 300bbd00f7eSHadar Hen Zion 301bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 302bbd00f7eSHadar Hen Zion udp_dport, ntohs(mask->dst)); 303bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 304bbd00f7eSHadar Hen Zion udp_dport, ntohs(key->dst)); 305bbd00f7eSHadar Hen Zion 306cd377663SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, 307cd377663SOr Gerlitz udp_sport, ntohs(mask->src)); 308cd377663SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, 309cd377663SOr Gerlitz udp_sport, ntohs(key->src)); 310bbd00f7eSHadar Hen Zion } else { /* udp dst port must be given */ 3112fcd82e9SOr Gerlitz vxlan_match_offload_err: 3122fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 3132fcd82e9SOr Gerlitz "IP tunnel decap offload supported only for vxlan, must set UDP dport\n"); 314bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 315bbd00f7eSHadar Hen Zion } 316bbd00f7eSHadar Hen Zion 3172e72eb43SOr Gerlitz if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 318bbd00f7eSHadar Hen Zion struct flow_dissector_key_ipv4_addrs *key = 319bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 320bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, 321bbd00f7eSHadar Hen Zion f->key); 322bbd00f7eSHadar Hen Zion struct flow_dissector_key_ipv4_addrs *mask = 323bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 324bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, 325bbd00f7eSHadar Hen Zion f->mask); 326bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 327bbd00f7eSHadar Hen Zion src_ipv4_src_ipv6.ipv4_layout.ipv4, 328bbd00f7eSHadar Hen Zion ntohl(mask->src)); 329bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 330bbd00f7eSHadar Hen Zion src_ipv4_src_ipv6.ipv4_layout.ipv4, 331bbd00f7eSHadar Hen Zion ntohl(key->src)); 332bbd00f7eSHadar Hen Zion 333bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, 334bbd00f7eSHadar Hen Zion dst_ipv4_dst_ipv6.ipv4_layout.ipv4, 335bbd00f7eSHadar Hen Zion ntohl(mask->dst)); 336bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, 337bbd00f7eSHadar Hen Zion dst_ipv4_dst_ipv6.ipv4_layout.ipv4, 338bbd00f7eSHadar Hen Zion ntohl(key->dst)); 339bbd00f7eSHadar Hen Zion 340bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); 341bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP); 34219f44401SOr Gerlitz } else if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 34319f44401SOr Gerlitz struct flow_dissector_key_ipv6_addrs *key = 34419f44401SOr Gerlitz skb_flow_dissector_target(f->dissector, 34519f44401SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, 34619f44401SOr Gerlitz f->key); 34719f44401SOr Gerlitz struct flow_dissector_key_ipv6_addrs *mask = 34819f44401SOr Gerlitz skb_flow_dissector_target(f->dissector, 34919f44401SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, 35019f44401SOr Gerlitz f->mask); 35119f44401SOr Gerlitz 35219f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 35319f44401SOr Gerlitz src_ipv4_src_ipv6.ipv6_layout.ipv6), 35419f44401SOr Gerlitz &mask->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 35519f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 35619f44401SOr Gerlitz src_ipv4_src_ipv6.ipv6_layout.ipv6), 35719f44401SOr Gerlitz &key->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 35819f44401SOr Gerlitz 35919f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 36019f44401SOr Gerlitz dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 36119f44401SOr Gerlitz &mask->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 36219f44401SOr Gerlitz memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 36319f44401SOr Gerlitz dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 36419f44401SOr Gerlitz &key->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6)); 36519f44401SOr Gerlitz 36619f44401SOr Gerlitz MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); 36719f44401SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IPV6); 3682e72eb43SOr Gerlitz } 369bbd00f7eSHadar Hen Zion 370bbd00f7eSHadar Hen Zion /* Enforce DMAC when offloading incoming tunneled flows. 371bbd00f7eSHadar Hen Zion * Flow counters require a match on the DMAC. 372bbd00f7eSHadar Hen Zion */ 373bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_47_16); 374bbd00f7eSHadar Hen Zion MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, dmac_15_0); 375bbd00f7eSHadar Hen Zion ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 376bbd00f7eSHadar Hen Zion dmac_47_16), priv->netdev->dev_addr); 377bbd00f7eSHadar Hen Zion 378bbd00f7eSHadar Hen Zion /* let software handle IP fragments */ 379bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1); 380bbd00f7eSHadar Hen Zion MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 0); 381bbd00f7eSHadar Hen Zion 382bbd00f7eSHadar Hen Zion return 0; 383bbd00f7eSHadar Hen Zion } 384bbd00f7eSHadar Hen Zion 385de0af0bfSRoi Dayan static int __parse_cls_flower(struct mlx5e_priv *priv, 386de0af0bfSRoi Dayan struct mlx5_flow_spec *spec, 387de0af0bfSRoi Dayan struct tc_cls_flower_offload *f, 388de0af0bfSRoi Dayan u8 *min_inline) 389e3a2b7edSAmir Vadai { 390c5bb1730SMaor Gottlieb void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 391c5bb1730SMaor Gottlieb outer_headers); 392c5bb1730SMaor Gottlieb void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 393c5bb1730SMaor Gottlieb outer_headers); 394e3a2b7edSAmir Vadai u16 addr_type = 0; 395e3a2b7edSAmir Vadai u8 ip_proto = 0; 396e3a2b7edSAmir Vadai 397de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_L2; 398de0af0bfSRoi Dayan 399e3a2b7edSAmir Vadai if (f->dissector->used_keys & 400e3a2b7edSAmir Vadai ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 401e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_BASIC) | 402e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 403095b6cfdSOr Gerlitz BIT(FLOW_DISSECTOR_KEY_VLAN) | 404e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 405e3a2b7edSAmir Vadai BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 406bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_PORTS) | 407bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | 408bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | 409bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | 410bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | 411bbd00f7eSHadar Hen Zion BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL))) { 412e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", 413e3a2b7edSAmir Vadai f->dissector->used_keys); 414e3a2b7edSAmir Vadai return -EOPNOTSUPP; 415e3a2b7edSAmir Vadai } 416e3a2b7edSAmir Vadai 417bbd00f7eSHadar Hen Zion if ((dissector_uses_key(f->dissector, 418bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) || 419bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID) || 420bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) && 421bbd00f7eSHadar Hen Zion dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL)) { 422bbd00f7eSHadar Hen Zion struct flow_dissector_key_control *key = 423bbd00f7eSHadar Hen Zion skb_flow_dissector_target(f->dissector, 424bbd00f7eSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_CONTROL, 425bbd00f7eSHadar Hen Zion f->key); 426bbd00f7eSHadar Hen Zion switch (key->addr_type) { 427bbd00f7eSHadar Hen Zion case FLOW_DISSECTOR_KEY_IPV4_ADDRS: 42819f44401SOr Gerlitz case FLOW_DISSECTOR_KEY_IPV6_ADDRS: 429bbd00f7eSHadar Hen Zion if (parse_tunnel_attr(priv, spec, f)) 430bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 431bbd00f7eSHadar Hen Zion break; 432bbd00f7eSHadar Hen Zion default: 433bbd00f7eSHadar Hen Zion return -EOPNOTSUPP; 434bbd00f7eSHadar Hen Zion } 435bbd00f7eSHadar Hen Zion 436bbd00f7eSHadar Hen Zion /* In decap flow, header pointers should point to the inner 437bbd00f7eSHadar Hen Zion * headers, outer header were already set by parse_tunnel_attr 438bbd00f7eSHadar Hen Zion */ 439bbd00f7eSHadar Hen Zion headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, 440bbd00f7eSHadar Hen Zion inner_headers); 441bbd00f7eSHadar Hen Zion headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, 442bbd00f7eSHadar Hen Zion inner_headers); 443bbd00f7eSHadar Hen Zion } 444bbd00f7eSHadar Hen Zion 445e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) { 446e3a2b7edSAmir Vadai struct flow_dissector_key_control *key = 447e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 4481dbd0d37SHadar Hen Zion FLOW_DISSECTOR_KEY_CONTROL, 449e3a2b7edSAmir Vadai f->key); 4503f7d0eb4SOr Gerlitz 4513f7d0eb4SOr Gerlitz struct flow_dissector_key_control *mask = 4523f7d0eb4SOr Gerlitz skb_flow_dissector_target(f->dissector, 4533f7d0eb4SOr Gerlitz FLOW_DISSECTOR_KEY_CONTROL, 4543f7d0eb4SOr Gerlitz f->mask); 455e3a2b7edSAmir Vadai addr_type = key->addr_type; 4563f7d0eb4SOr Gerlitz 4573f7d0eb4SOr Gerlitz if (mask->flags & FLOW_DIS_IS_FRAGMENT) { 4583f7d0eb4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1); 4593f7d0eb4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 4603f7d0eb4SOr Gerlitz key->flags & FLOW_DIS_IS_FRAGMENT); 4610827444dSOr Gerlitz 4620827444dSOr Gerlitz /* the HW doesn't need L3 inline to match on frag=no */ 4630827444dSOr Gerlitz if (key->flags & FLOW_DIS_IS_FRAGMENT) 4640827444dSOr Gerlitz *min_inline = MLX5_INLINE_MODE_IP; 4653f7d0eb4SOr Gerlitz } 466e3a2b7edSAmir Vadai } 467e3a2b7edSAmir Vadai 468e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) { 469e3a2b7edSAmir Vadai struct flow_dissector_key_basic *key = 470e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 471e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 472e3a2b7edSAmir Vadai f->key); 473e3a2b7edSAmir Vadai struct flow_dissector_key_basic *mask = 474e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 475e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_BASIC, 476e3a2b7edSAmir Vadai f->mask); 477e3a2b7edSAmir Vadai ip_proto = key->ip_proto; 478e3a2b7edSAmir Vadai 479e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype, 480e3a2b7edSAmir Vadai ntohs(mask->n_proto)); 481e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 482e3a2b7edSAmir Vadai ntohs(key->n_proto)); 483e3a2b7edSAmir Vadai 484e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol, 485e3a2b7edSAmir Vadai mask->ip_proto); 486e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 487e3a2b7edSAmir Vadai key->ip_proto); 488de0af0bfSRoi Dayan 489de0af0bfSRoi Dayan if (mask->ip_proto) 490de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 491e3a2b7edSAmir Vadai } 492e3a2b7edSAmir Vadai 493e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 494e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *key = 495e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 496e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 497e3a2b7edSAmir Vadai f->key); 498e3a2b7edSAmir Vadai struct flow_dissector_key_eth_addrs *mask = 499e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 500e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_ETH_ADDRS, 501e3a2b7edSAmir Vadai f->mask); 502e3a2b7edSAmir Vadai 503e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 504e3a2b7edSAmir Vadai dmac_47_16), 505e3a2b7edSAmir Vadai mask->dst); 506e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 507e3a2b7edSAmir Vadai dmac_47_16), 508e3a2b7edSAmir Vadai key->dst); 509e3a2b7edSAmir Vadai 510e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 511e3a2b7edSAmir Vadai smac_47_16), 512e3a2b7edSAmir Vadai mask->src); 513e3a2b7edSAmir Vadai ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 514e3a2b7edSAmir Vadai smac_47_16), 515e3a2b7edSAmir Vadai key->src); 516e3a2b7edSAmir Vadai } 517e3a2b7edSAmir Vadai 518095b6cfdSOr Gerlitz if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) { 519095b6cfdSOr Gerlitz struct flow_dissector_key_vlan *key = 520095b6cfdSOr Gerlitz skb_flow_dissector_target(f->dissector, 521095b6cfdSOr Gerlitz FLOW_DISSECTOR_KEY_VLAN, 522095b6cfdSOr Gerlitz f->key); 523095b6cfdSOr Gerlitz struct flow_dissector_key_vlan *mask = 524095b6cfdSOr Gerlitz skb_flow_dissector_target(f->dissector, 525095b6cfdSOr Gerlitz FLOW_DISSECTOR_KEY_VLAN, 526095b6cfdSOr Gerlitz f->mask); 527358d79a4SOr Gerlitz if (mask->vlan_id || mask->vlan_priority) { 52810543365SMohamad Haj Yahia MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); 52910543365SMohamad Haj Yahia MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1); 530095b6cfdSOr Gerlitz 531095b6cfdSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, mask->vlan_id); 532095b6cfdSOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, key->vlan_id); 533358d79a4SOr Gerlitz 534358d79a4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_prio, mask->vlan_priority); 535358d79a4SOr Gerlitz MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, key->vlan_priority); 536095b6cfdSOr Gerlitz } 537095b6cfdSOr Gerlitz } 538095b6cfdSOr Gerlitz 539e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 540e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *key = 541e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 542e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 543e3a2b7edSAmir Vadai f->key); 544e3a2b7edSAmir Vadai struct flow_dissector_key_ipv4_addrs *mask = 545e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 546e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV4_ADDRS, 547e3a2b7edSAmir Vadai f->mask); 548e3a2b7edSAmir Vadai 549e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 550e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 551e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 552e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 553e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv4_layout.ipv4), 554e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 555e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 556e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 557e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 558e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 559e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv4_layout.ipv4), 560e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 561de0af0bfSRoi Dayan 562de0af0bfSRoi Dayan if (mask->src || mask->dst) 563de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 564e3a2b7edSAmir Vadai } 565e3a2b7edSAmir Vadai 566e3a2b7edSAmir Vadai if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { 567e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *key = 568e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 569e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 570e3a2b7edSAmir Vadai f->key); 571e3a2b7edSAmir Vadai struct flow_dissector_key_ipv6_addrs *mask = 572e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 573e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_IPV6_ADDRS, 574e3a2b7edSAmir Vadai f->mask); 575e3a2b7edSAmir Vadai 576e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 577e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 578e3a2b7edSAmir Vadai &mask->src, sizeof(mask->src)); 579e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 580e3a2b7edSAmir Vadai src_ipv4_src_ipv6.ipv6_layout.ipv6), 581e3a2b7edSAmir Vadai &key->src, sizeof(key->src)); 582e3a2b7edSAmir Vadai 583e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, 584e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 585e3a2b7edSAmir Vadai &mask->dst, sizeof(mask->dst)); 586e3a2b7edSAmir Vadai memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, 587e3a2b7edSAmir Vadai dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 588e3a2b7edSAmir Vadai &key->dst, sizeof(key->dst)); 589de0af0bfSRoi Dayan 590de0af0bfSRoi Dayan if (ipv6_addr_type(&mask->src) != IPV6_ADDR_ANY || 591de0af0bfSRoi Dayan ipv6_addr_type(&mask->dst) != IPV6_ADDR_ANY) 592de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_IP; 593e3a2b7edSAmir Vadai } 594e3a2b7edSAmir Vadai 595e3a2b7edSAmir Vadai if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) { 596e3a2b7edSAmir Vadai struct flow_dissector_key_ports *key = 597e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 598e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 599e3a2b7edSAmir Vadai f->key); 600e3a2b7edSAmir Vadai struct flow_dissector_key_ports *mask = 601e3a2b7edSAmir Vadai skb_flow_dissector_target(f->dissector, 602e3a2b7edSAmir Vadai FLOW_DISSECTOR_KEY_PORTS, 603e3a2b7edSAmir Vadai f->mask); 604e3a2b7edSAmir Vadai switch (ip_proto) { 605e3a2b7edSAmir Vadai case IPPROTO_TCP: 606e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 607e3a2b7edSAmir Vadai tcp_sport, ntohs(mask->src)); 608e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 609e3a2b7edSAmir Vadai tcp_sport, ntohs(key->src)); 610e3a2b7edSAmir Vadai 611e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 612e3a2b7edSAmir Vadai tcp_dport, ntohs(mask->dst)); 613e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 614e3a2b7edSAmir Vadai tcp_dport, ntohs(key->dst)); 615e3a2b7edSAmir Vadai break; 616e3a2b7edSAmir Vadai 617e3a2b7edSAmir Vadai case IPPROTO_UDP: 618e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 619e3a2b7edSAmir Vadai udp_sport, ntohs(mask->src)); 620e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 621e3a2b7edSAmir Vadai udp_sport, ntohs(key->src)); 622e3a2b7edSAmir Vadai 623e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_c, 624e3a2b7edSAmir Vadai udp_dport, ntohs(mask->dst)); 625e3a2b7edSAmir Vadai MLX5_SET(fte_match_set_lyr_2_4, headers_v, 626e3a2b7edSAmir Vadai udp_dport, ntohs(key->dst)); 627e3a2b7edSAmir Vadai break; 628e3a2b7edSAmir Vadai default: 629e3a2b7edSAmir Vadai netdev_err(priv->netdev, 630e3a2b7edSAmir Vadai "Only UDP and TCP transport are supported\n"); 631e3a2b7edSAmir Vadai return -EINVAL; 632e3a2b7edSAmir Vadai } 633de0af0bfSRoi Dayan 634de0af0bfSRoi Dayan if (mask->src || mask->dst) 635de0af0bfSRoi Dayan *min_inline = MLX5_INLINE_MODE_TCP_UDP; 636e3a2b7edSAmir Vadai } 637e3a2b7edSAmir Vadai 638e3a2b7edSAmir Vadai return 0; 639e3a2b7edSAmir Vadai } 640e3a2b7edSAmir Vadai 641de0af0bfSRoi Dayan static int parse_cls_flower(struct mlx5e_priv *priv, 64265ba8fb7SOr Gerlitz struct mlx5e_tc_flow *flow, 643de0af0bfSRoi Dayan struct mlx5_flow_spec *spec, 644de0af0bfSRoi Dayan struct tc_cls_flower_offload *f) 645de0af0bfSRoi Dayan { 646de0af0bfSRoi Dayan struct mlx5_core_dev *dev = priv->mdev; 647de0af0bfSRoi Dayan struct mlx5_eswitch *esw = dev->priv.eswitch; 648de0af0bfSRoi Dayan struct mlx5_eswitch_rep *rep = priv->ppriv; 649de0af0bfSRoi Dayan u8 min_inline; 650de0af0bfSRoi Dayan int err; 651de0af0bfSRoi Dayan 652de0af0bfSRoi Dayan err = __parse_cls_flower(priv, spec, f, &min_inline); 653de0af0bfSRoi Dayan 65465ba8fb7SOr Gerlitz if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH) && 655de0af0bfSRoi Dayan rep->vport != FDB_UPLINK_VPORT) { 656de0af0bfSRoi Dayan if (min_inline > esw->offloads.inline_mode) { 657de0af0bfSRoi Dayan netdev_warn(priv->netdev, 658de0af0bfSRoi Dayan "Flow is not offloaded due to min inline setting, required %d actual %d\n", 659de0af0bfSRoi Dayan min_inline, esw->offloads.inline_mode); 660de0af0bfSRoi Dayan return -EOPNOTSUPP; 661de0af0bfSRoi Dayan } 662de0af0bfSRoi Dayan } 663de0af0bfSRoi Dayan 664de0af0bfSRoi Dayan return err; 665de0af0bfSRoi Dayan } 666de0af0bfSRoi Dayan 6675c40348cSOr Gerlitz static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 6683bc4b7bfSOr Gerlitz struct mlx5_nic_flow_attr *attr) 669e3a2b7edSAmir Vadai { 670e3a2b7edSAmir Vadai const struct tc_action *a; 67122dc13c8SWANG Cong LIST_HEAD(actions); 672e3a2b7edSAmir Vadai 673e3a2b7edSAmir Vadai if (tc_no_actions(exts)) 674e3a2b7edSAmir Vadai return -EINVAL; 675e3a2b7edSAmir Vadai 6763bc4b7bfSOr Gerlitz attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; 6773bc4b7bfSOr Gerlitz attr->action = 0; 678e3a2b7edSAmir Vadai 67922dc13c8SWANG Cong tcf_exts_to_list(exts, &actions); 68022dc13c8SWANG Cong list_for_each_entry(a, &actions, list) { 681e3a2b7edSAmir Vadai /* Only support a single action per rule */ 6823bc4b7bfSOr Gerlitz if (attr->action) 683e3a2b7edSAmir Vadai return -EINVAL; 684e3a2b7edSAmir Vadai 685e3a2b7edSAmir Vadai if (is_tcf_gact_shot(a)) { 6863bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP; 687aad7e08dSAmir Vadai if (MLX5_CAP_FLOWTABLE(priv->mdev, 688aad7e08dSAmir Vadai flow_table_properties_nic_receive.flow_counter)) 6893bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 690e3a2b7edSAmir Vadai continue; 691e3a2b7edSAmir Vadai } 692e3a2b7edSAmir Vadai 693e3a2b7edSAmir Vadai if (is_tcf_skbedit_mark(a)) { 694e3a2b7edSAmir Vadai u32 mark = tcf_skbedit_mark(a); 695e3a2b7edSAmir Vadai 696e3a2b7edSAmir Vadai if (mark & ~MLX5E_TC_FLOW_ID_MASK) { 697e3a2b7edSAmir Vadai netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n", 698e3a2b7edSAmir Vadai mark); 699e3a2b7edSAmir Vadai return -EINVAL; 700e3a2b7edSAmir Vadai } 701e3a2b7edSAmir Vadai 7023bc4b7bfSOr Gerlitz attr->flow_tag = mark; 7033bc4b7bfSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; 704e3a2b7edSAmir Vadai continue; 705e3a2b7edSAmir Vadai } 706e3a2b7edSAmir Vadai 707e3a2b7edSAmir Vadai return -EINVAL; 708e3a2b7edSAmir Vadai } 709e3a2b7edSAmir Vadai 710e3a2b7edSAmir Vadai return 0; 711e3a2b7edSAmir Vadai } 712e3a2b7edSAmir Vadai 71376f7444dSOr Gerlitz static inline int cmp_encap_info(struct ip_tunnel_key *a, 71476f7444dSOr Gerlitz struct ip_tunnel_key *b) 715a54e20b4SHadar Hen Zion { 716a54e20b4SHadar Hen Zion return memcmp(a, b, sizeof(*a)); 717a54e20b4SHadar Hen Zion } 718a54e20b4SHadar Hen Zion 71976f7444dSOr Gerlitz static inline int hash_encap_info(struct ip_tunnel_key *key) 720a54e20b4SHadar Hen Zion { 72176f7444dSOr Gerlitz return jhash(key, sizeof(*key), 0); 722a54e20b4SHadar Hen Zion } 723a54e20b4SHadar Hen Zion 724a54e20b4SHadar Hen Zion static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, 725a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 726a54e20b4SHadar Hen Zion struct net_device **out_dev, 727a54e20b4SHadar Hen Zion struct flowi4 *fl4, 728a54e20b4SHadar Hen Zion struct neighbour **out_n, 729a54e20b4SHadar Hen Zion int *out_ttl) 730a54e20b4SHadar Hen Zion { 7313e621b19SHadar Hen Zion struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 732a54e20b4SHadar Hen Zion struct rtable *rt; 733a54e20b4SHadar Hen Zion struct neighbour *n = NULL; 734a54e20b4SHadar Hen Zion 735a54e20b4SHadar Hen Zion #if IS_ENABLED(CONFIG_INET) 736abeffce9SArnd Bergmann int ret; 737abeffce9SArnd Bergmann 738a54e20b4SHadar Hen Zion rt = ip_route_output_key(dev_net(mirred_dev), fl4); 739abeffce9SArnd Bergmann ret = PTR_ERR_OR_ZERO(rt); 740abeffce9SArnd Bergmann if (ret) 741abeffce9SArnd Bergmann return ret; 742a54e20b4SHadar Hen Zion #else 743a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 744a54e20b4SHadar Hen Zion #endif 7453e621b19SHadar Hen Zion /* if the egress device isn't on the same HW e-switch, we use the uplink */ 7463e621b19SHadar Hen Zion if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) 7473e621b19SHadar Hen Zion *out_dev = mlx5_eswitch_get_uplink_netdev(esw); 7483e621b19SHadar Hen Zion else 7493e621b19SHadar Hen Zion *out_dev = rt->dst.dev; 750a54e20b4SHadar Hen Zion 75175c33da8SOr Gerlitz *out_ttl = ip4_dst_hoplimit(&rt->dst); 752a54e20b4SHadar Hen Zion n = dst_neigh_lookup(&rt->dst, &fl4->daddr); 753a54e20b4SHadar Hen Zion ip_rt_put(rt); 754a54e20b4SHadar Hen Zion if (!n) 755a54e20b4SHadar Hen Zion return -ENOMEM; 756a54e20b4SHadar Hen Zion 757a54e20b4SHadar Hen Zion *out_n = n; 758a54e20b4SHadar Hen Zion return 0; 759a54e20b4SHadar Hen Zion } 760a54e20b4SHadar Hen Zion 761ce99f6b9SOr Gerlitz static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, 762ce99f6b9SOr Gerlitz struct net_device *mirred_dev, 763ce99f6b9SOr Gerlitz struct net_device **out_dev, 764ce99f6b9SOr Gerlitz struct flowi6 *fl6, 765ce99f6b9SOr Gerlitz struct neighbour **out_n, 766ce99f6b9SOr Gerlitz int *out_ttl) 767ce99f6b9SOr Gerlitz { 768ce99f6b9SOr Gerlitz struct neighbour *n = NULL; 769ce99f6b9SOr Gerlitz struct dst_entry *dst; 770ce99f6b9SOr Gerlitz 771ce99f6b9SOr Gerlitz #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) 772ce99f6b9SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 773ce99f6b9SOr Gerlitz int ret; 774ce99f6b9SOr Gerlitz 775ce99f6b9SOr Gerlitz dst = ip6_route_output(dev_net(mirred_dev), NULL, fl6); 776ce99f6b9SOr Gerlitz ret = dst->error; 777321fa4ffSArnd Bergmann if (ret) { 778ce99f6b9SOr Gerlitz dst_release(dst); 779ce99f6b9SOr Gerlitz return ret; 780ce99f6b9SOr Gerlitz } 781ce99f6b9SOr Gerlitz 782ce99f6b9SOr Gerlitz *out_ttl = ip6_dst_hoplimit(dst); 783ce99f6b9SOr Gerlitz 784ce99f6b9SOr Gerlitz /* if the egress device isn't on the same HW e-switch, we use the uplink */ 785ce99f6b9SOr Gerlitz if (!switchdev_port_same_parent_id(priv->netdev, dst->dev)) 786ce99f6b9SOr Gerlitz *out_dev = mlx5_eswitch_get_uplink_netdev(esw); 787ce99f6b9SOr Gerlitz else 788ce99f6b9SOr Gerlitz *out_dev = dst->dev; 789ce99f6b9SOr Gerlitz #else 790ce99f6b9SOr Gerlitz return -EOPNOTSUPP; 791ce99f6b9SOr Gerlitz #endif 792ce99f6b9SOr Gerlitz 793ce99f6b9SOr Gerlitz n = dst_neigh_lookup(dst, &fl6->daddr); 794ce99f6b9SOr Gerlitz dst_release(dst); 795ce99f6b9SOr Gerlitz if (!n) 796ce99f6b9SOr Gerlitz return -ENOMEM; 797ce99f6b9SOr Gerlitz 798ce99f6b9SOr Gerlitz *out_n = n; 799ce99f6b9SOr Gerlitz return 0; 800ce99f6b9SOr Gerlitz } 801ce99f6b9SOr Gerlitz 802a54e20b4SHadar Hen Zion static int gen_vxlan_header_ipv4(struct net_device *out_dev, 803a54e20b4SHadar Hen Zion char buf[], 804a54e20b4SHadar Hen Zion unsigned char h_dest[ETH_ALEN], 805a54e20b4SHadar Hen Zion int ttl, 806a54e20b4SHadar Hen Zion __be32 daddr, 807a54e20b4SHadar Hen Zion __be32 saddr, 808a54e20b4SHadar Hen Zion __be16 udp_dst_port, 809a54e20b4SHadar Hen Zion __be32 vx_vni) 810a54e20b4SHadar Hen Zion { 811a54e20b4SHadar Hen Zion int encap_size = VXLAN_HLEN + sizeof(struct iphdr) + ETH_HLEN; 812a54e20b4SHadar Hen Zion struct ethhdr *eth = (struct ethhdr *)buf; 813a54e20b4SHadar Hen Zion struct iphdr *ip = (struct iphdr *)((char *)eth + sizeof(struct ethhdr)); 814a54e20b4SHadar Hen Zion struct udphdr *udp = (struct udphdr *)((char *)ip + sizeof(struct iphdr)); 815a54e20b4SHadar Hen Zion struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 816a54e20b4SHadar Hen Zion 817a54e20b4SHadar Hen Zion memset(buf, 0, encap_size); 818a54e20b4SHadar Hen Zion 819a54e20b4SHadar Hen Zion ether_addr_copy(eth->h_dest, h_dest); 820a54e20b4SHadar Hen Zion ether_addr_copy(eth->h_source, out_dev->dev_addr); 821a54e20b4SHadar Hen Zion eth->h_proto = htons(ETH_P_IP); 822a54e20b4SHadar Hen Zion 823a54e20b4SHadar Hen Zion ip->daddr = daddr; 824a54e20b4SHadar Hen Zion ip->saddr = saddr; 825a54e20b4SHadar Hen Zion 826a54e20b4SHadar Hen Zion ip->ttl = ttl; 827a54e20b4SHadar Hen Zion ip->protocol = IPPROTO_UDP; 828a54e20b4SHadar Hen Zion ip->version = 0x4; 829a54e20b4SHadar Hen Zion ip->ihl = 0x5; 830a54e20b4SHadar Hen Zion 831a54e20b4SHadar Hen Zion udp->dest = udp_dst_port; 832a54e20b4SHadar Hen Zion vxh->vx_flags = VXLAN_HF_VNI; 833a54e20b4SHadar Hen Zion vxh->vx_vni = vxlan_vni_field(vx_vni); 834a54e20b4SHadar Hen Zion 835a54e20b4SHadar Hen Zion return encap_size; 836a54e20b4SHadar Hen Zion } 837a54e20b4SHadar Hen Zion 838ce99f6b9SOr Gerlitz static int gen_vxlan_header_ipv6(struct net_device *out_dev, 839ce99f6b9SOr Gerlitz char buf[], 840ce99f6b9SOr Gerlitz unsigned char h_dest[ETH_ALEN], 841ce99f6b9SOr Gerlitz int ttl, 842ce99f6b9SOr Gerlitz struct in6_addr *daddr, 843ce99f6b9SOr Gerlitz struct in6_addr *saddr, 844ce99f6b9SOr Gerlitz __be16 udp_dst_port, 845ce99f6b9SOr Gerlitz __be32 vx_vni) 846ce99f6b9SOr Gerlitz { 847ce99f6b9SOr Gerlitz int encap_size = VXLAN_HLEN + sizeof(struct ipv6hdr) + ETH_HLEN; 848ce99f6b9SOr Gerlitz struct ethhdr *eth = (struct ethhdr *)buf; 849ce99f6b9SOr Gerlitz struct ipv6hdr *ip6h = (struct ipv6hdr *)((char *)eth + sizeof(struct ethhdr)); 850ce99f6b9SOr Gerlitz struct udphdr *udp = (struct udphdr *)((char *)ip6h + sizeof(struct ipv6hdr)); 851ce99f6b9SOr Gerlitz struct vxlanhdr *vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); 852ce99f6b9SOr Gerlitz 853ce99f6b9SOr Gerlitz memset(buf, 0, encap_size); 854ce99f6b9SOr Gerlitz 855ce99f6b9SOr Gerlitz ether_addr_copy(eth->h_dest, h_dest); 856ce99f6b9SOr Gerlitz ether_addr_copy(eth->h_source, out_dev->dev_addr); 857ce99f6b9SOr Gerlitz eth->h_proto = htons(ETH_P_IPV6); 858ce99f6b9SOr Gerlitz 859ce99f6b9SOr Gerlitz ip6_flow_hdr(ip6h, 0, 0); 860ce99f6b9SOr Gerlitz /* the HW fills up ipv6 payload len */ 861ce99f6b9SOr Gerlitz ip6h->nexthdr = IPPROTO_UDP; 862ce99f6b9SOr Gerlitz ip6h->hop_limit = ttl; 863ce99f6b9SOr Gerlitz ip6h->daddr = *daddr; 864ce99f6b9SOr Gerlitz ip6h->saddr = *saddr; 865ce99f6b9SOr Gerlitz 866ce99f6b9SOr Gerlitz udp->dest = udp_dst_port; 867ce99f6b9SOr Gerlitz vxh->vx_flags = VXLAN_HF_VNI; 868ce99f6b9SOr Gerlitz vxh->vx_vni = vxlan_vni_field(vx_vni); 869ce99f6b9SOr Gerlitz 870ce99f6b9SOr Gerlitz return encap_size; 871ce99f6b9SOr Gerlitz } 872ce99f6b9SOr Gerlitz 873a54e20b4SHadar Hen Zion static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, 874a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 875a54e20b4SHadar Hen Zion struct mlx5_encap_entry *e, 876a54e20b4SHadar Hen Zion struct net_device **out_dev) 877a54e20b4SHadar Hen Zion { 878a54e20b4SHadar Hen Zion int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); 87976f7444dSOr Gerlitz struct ip_tunnel_key *tun_key = &e->tun_info.key; 8809a941117SOr Gerlitz int encap_size, ttl, err; 881a42485ebSOr Gerlitz struct neighbour *n = NULL; 882a54e20b4SHadar Hen Zion struct flowi4 fl4 = {}; 883a54e20b4SHadar Hen Zion char *encap_header; 884a54e20b4SHadar Hen Zion 885a54e20b4SHadar Hen Zion encap_header = kzalloc(max_encap_size, GFP_KERNEL); 886a54e20b4SHadar Hen Zion if (!encap_header) 887a54e20b4SHadar Hen Zion return -ENOMEM; 888a54e20b4SHadar Hen Zion 889a54e20b4SHadar Hen Zion switch (e->tunnel_type) { 890a54e20b4SHadar Hen Zion case MLX5_HEADER_TYPE_VXLAN: 891a54e20b4SHadar Hen Zion fl4.flowi4_proto = IPPROTO_UDP; 89276f7444dSOr Gerlitz fl4.fl4_dport = tun_key->tp_dst; 893a54e20b4SHadar Hen Zion break; 894a54e20b4SHadar Hen Zion default: 895a54e20b4SHadar Hen Zion err = -EOPNOTSUPP; 896a54e20b4SHadar Hen Zion goto out; 897a54e20b4SHadar Hen Zion } 8989a941117SOr Gerlitz fl4.flowi4_tos = tun_key->tos; 89976f7444dSOr Gerlitz fl4.daddr = tun_key->u.ipv4.dst; 9009a941117SOr Gerlitz fl4.saddr = tun_key->u.ipv4.src; 901a54e20b4SHadar Hen Zion 902a54e20b4SHadar Hen Zion err = mlx5e_route_lookup_ipv4(priv, mirred_dev, out_dev, 9039a941117SOr Gerlitz &fl4, &n, &ttl); 904a54e20b4SHadar Hen Zion if (err) 905a54e20b4SHadar Hen Zion goto out; 906a54e20b4SHadar Hen Zion 907a54e20b4SHadar Hen Zion if (!(n->nud_state & NUD_VALID)) { 908a42485ebSOr Gerlitz pr_warn("%s: can't offload, neighbour to %pI4 invalid\n", __func__, &fl4.daddr); 909a42485ebSOr Gerlitz err = -EOPNOTSUPP; 910a54e20b4SHadar Hen Zion goto out; 911a54e20b4SHadar Hen Zion } 912a54e20b4SHadar Hen Zion 91375c33da8SOr Gerlitz e->n = n; 91475c33da8SOr Gerlitz e->out_dev = *out_dev; 91575c33da8SOr Gerlitz 916a54e20b4SHadar Hen Zion neigh_ha_snapshot(e->h_dest, n, *out_dev); 917a54e20b4SHadar Hen Zion 918a54e20b4SHadar Hen Zion switch (e->tunnel_type) { 919a54e20b4SHadar Hen Zion case MLX5_HEADER_TYPE_VXLAN: 920a54e20b4SHadar Hen Zion encap_size = gen_vxlan_header_ipv4(*out_dev, encap_header, 921a54e20b4SHadar Hen Zion e->h_dest, ttl, 9229a941117SOr Gerlitz fl4.daddr, 9239a941117SOr Gerlitz fl4.saddr, tun_key->tp_dst, 92476f7444dSOr Gerlitz tunnel_id_to_key32(tun_key->tun_id)); 925a54e20b4SHadar Hen Zion break; 926a54e20b4SHadar Hen Zion default: 927a54e20b4SHadar Hen Zion err = -EOPNOTSUPP; 928a54e20b4SHadar Hen Zion goto out; 929a54e20b4SHadar Hen Zion } 930a54e20b4SHadar Hen Zion 931a54e20b4SHadar Hen Zion err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, 932a54e20b4SHadar Hen Zion encap_size, encap_header, &e->encap_id); 933a54e20b4SHadar Hen Zion out: 934a42485ebSOr Gerlitz if (err && n) 935a42485ebSOr Gerlitz neigh_release(n); 936a54e20b4SHadar Hen Zion kfree(encap_header); 937a54e20b4SHadar Hen Zion return err; 938a54e20b4SHadar Hen Zion } 939a54e20b4SHadar Hen Zion 940ce99f6b9SOr Gerlitz static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, 941ce99f6b9SOr Gerlitz struct net_device *mirred_dev, 942ce99f6b9SOr Gerlitz struct mlx5_encap_entry *e, 943ce99f6b9SOr Gerlitz struct net_device **out_dev) 944ce99f6b9SOr Gerlitz 945ce99f6b9SOr Gerlitz { 946ce99f6b9SOr Gerlitz int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); 947ce99f6b9SOr Gerlitz struct ip_tunnel_key *tun_key = &e->tun_info.key; 948ce99f6b9SOr Gerlitz int encap_size, err, ttl = 0; 949ce99f6b9SOr Gerlitz struct neighbour *n = NULL; 950ce99f6b9SOr Gerlitz struct flowi6 fl6 = {}; 951ce99f6b9SOr Gerlitz char *encap_header; 952ce99f6b9SOr Gerlitz 953ce99f6b9SOr Gerlitz encap_header = kzalloc(max_encap_size, GFP_KERNEL); 954ce99f6b9SOr Gerlitz if (!encap_header) 955ce99f6b9SOr Gerlitz return -ENOMEM; 956ce99f6b9SOr Gerlitz 957ce99f6b9SOr Gerlitz switch (e->tunnel_type) { 958ce99f6b9SOr Gerlitz case MLX5_HEADER_TYPE_VXLAN: 959ce99f6b9SOr Gerlitz fl6.flowi6_proto = IPPROTO_UDP; 960ce99f6b9SOr Gerlitz fl6.fl6_dport = tun_key->tp_dst; 961ce99f6b9SOr Gerlitz break; 962ce99f6b9SOr Gerlitz default: 963ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 964ce99f6b9SOr Gerlitz goto out; 965ce99f6b9SOr Gerlitz } 966ce99f6b9SOr Gerlitz 967ce99f6b9SOr Gerlitz fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tun_key->tos), tun_key->label); 968ce99f6b9SOr Gerlitz fl6.daddr = tun_key->u.ipv6.dst; 969ce99f6b9SOr Gerlitz fl6.saddr = tun_key->u.ipv6.src; 970ce99f6b9SOr Gerlitz 971ce99f6b9SOr Gerlitz err = mlx5e_route_lookup_ipv6(priv, mirred_dev, out_dev, 972ce99f6b9SOr Gerlitz &fl6, &n, &ttl); 973ce99f6b9SOr Gerlitz if (err) 974ce99f6b9SOr Gerlitz goto out; 975ce99f6b9SOr Gerlitz 976ce99f6b9SOr Gerlitz if (!(n->nud_state & NUD_VALID)) { 977ce99f6b9SOr Gerlitz pr_warn("%s: can't offload, neighbour to %pI6 invalid\n", __func__, &fl6.daddr); 978ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 979ce99f6b9SOr Gerlitz goto out; 980ce99f6b9SOr Gerlitz } 981ce99f6b9SOr Gerlitz 982ce99f6b9SOr Gerlitz e->n = n; 983ce99f6b9SOr Gerlitz e->out_dev = *out_dev; 984ce99f6b9SOr Gerlitz 985ce99f6b9SOr Gerlitz neigh_ha_snapshot(e->h_dest, n, *out_dev); 986ce99f6b9SOr Gerlitz 987ce99f6b9SOr Gerlitz switch (e->tunnel_type) { 988ce99f6b9SOr Gerlitz case MLX5_HEADER_TYPE_VXLAN: 989ce99f6b9SOr Gerlitz encap_size = gen_vxlan_header_ipv6(*out_dev, encap_header, 990ce99f6b9SOr Gerlitz e->h_dest, ttl, 991ce99f6b9SOr Gerlitz &fl6.daddr, 992ce99f6b9SOr Gerlitz &fl6.saddr, tun_key->tp_dst, 993ce99f6b9SOr Gerlitz tunnel_id_to_key32(tun_key->tun_id)); 994ce99f6b9SOr Gerlitz break; 995ce99f6b9SOr Gerlitz default: 996ce99f6b9SOr Gerlitz err = -EOPNOTSUPP; 997ce99f6b9SOr Gerlitz goto out; 998ce99f6b9SOr Gerlitz } 999ce99f6b9SOr Gerlitz 1000ce99f6b9SOr Gerlitz err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, 1001ce99f6b9SOr Gerlitz encap_size, encap_header, &e->encap_id); 1002ce99f6b9SOr Gerlitz out: 1003ce99f6b9SOr Gerlitz if (err && n) 1004ce99f6b9SOr Gerlitz neigh_release(n); 1005ce99f6b9SOr Gerlitz kfree(encap_header); 1006ce99f6b9SOr Gerlitz return err; 1007ce99f6b9SOr Gerlitz } 1008ce99f6b9SOr Gerlitz 1009a54e20b4SHadar Hen Zion static int mlx5e_attach_encap(struct mlx5e_priv *priv, 1010a54e20b4SHadar Hen Zion struct ip_tunnel_info *tun_info, 1011a54e20b4SHadar Hen Zion struct net_device *mirred_dev, 1012776b12b6SOr Gerlitz struct mlx5_esw_flow_attr *attr) 101303a9d11eSOr Gerlitz { 1014a54e20b4SHadar Hen Zion struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 10151ad9a00aSPaul Blakey struct net_device *up_dev = mlx5_eswitch_get_uplink_netdev(esw); 10161ad9a00aSPaul Blakey struct mlx5e_priv *up_priv = netdev_priv(up_dev); 1017a54e20b4SHadar Hen Zion unsigned short family = ip_tunnel_info_af(tun_info); 1018a54e20b4SHadar Hen Zion struct ip_tunnel_key *key = &tun_info->key; 1019a54e20b4SHadar Hen Zion struct mlx5_encap_entry *e; 1020a54e20b4SHadar Hen Zion struct net_device *out_dev; 1021ce99f6b9SOr Gerlitz int tunnel_type, err = -EOPNOTSUPP; 1022a54e20b4SHadar Hen Zion uintptr_t hash_key; 1023a54e20b4SHadar Hen Zion bool found = false; 1024a54e20b4SHadar Hen Zion 10252fcd82e9SOr Gerlitz /* udp dst port must be set */ 1026a54e20b4SHadar Hen Zion if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst))) 10272fcd82e9SOr Gerlitz goto vxlan_encap_offload_err; 1028a54e20b4SHadar Hen Zion 1029cd377663SOr Gerlitz /* setting udp src port isn't supported */ 10302fcd82e9SOr Gerlitz if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) { 10312fcd82e9SOr Gerlitz vxlan_encap_offload_err: 10322fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 10332fcd82e9SOr Gerlitz "must set udp dst port and not set udp src port\n"); 1034cd377663SOr Gerlitz return -EOPNOTSUPP; 10352fcd82e9SOr Gerlitz } 1036cd377663SOr Gerlitz 10371ad9a00aSPaul Blakey if (mlx5e_vxlan_lookup_port(up_priv, be16_to_cpu(key->tp_dst)) && 1038a54e20b4SHadar Hen Zion MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) { 1039a54e20b4SHadar Hen Zion tunnel_type = MLX5_HEADER_TYPE_VXLAN; 1040a54e20b4SHadar Hen Zion } else { 10412fcd82e9SOr Gerlitz netdev_warn(priv->netdev, 10422fcd82e9SOr Gerlitz "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst)); 1043a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 1044a54e20b4SHadar Hen Zion } 1045a54e20b4SHadar Hen Zion 104676f7444dSOr Gerlitz hash_key = hash_encap_info(key); 1047a54e20b4SHadar Hen Zion 1048a54e20b4SHadar Hen Zion hash_for_each_possible_rcu(esw->offloads.encap_tbl, e, 1049a54e20b4SHadar Hen Zion encap_hlist, hash_key) { 105076f7444dSOr Gerlitz if (!cmp_encap_info(&e->tun_info.key, key)) { 1051a54e20b4SHadar Hen Zion found = true; 1052a54e20b4SHadar Hen Zion break; 1053a54e20b4SHadar Hen Zion } 1054a54e20b4SHadar Hen Zion } 1055a54e20b4SHadar Hen Zion 1056a54e20b4SHadar Hen Zion if (found) { 1057a54e20b4SHadar Hen Zion attr->encap = e; 1058a54e20b4SHadar Hen Zion return 0; 1059a54e20b4SHadar Hen Zion } 1060a54e20b4SHadar Hen Zion 1061a54e20b4SHadar Hen Zion e = kzalloc(sizeof(*e), GFP_KERNEL); 1062a54e20b4SHadar Hen Zion if (!e) 1063a54e20b4SHadar Hen Zion return -ENOMEM; 1064a54e20b4SHadar Hen Zion 106576f7444dSOr Gerlitz e->tun_info = *tun_info; 1066a54e20b4SHadar Hen Zion e->tunnel_type = tunnel_type; 1067a54e20b4SHadar Hen Zion INIT_LIST_HEAD(&e->flows); 1068a54e20b4SHadar Hen Zion 1069ce99f6b9SOr Gerlitz if (family == AF_INET) 1070a54e20b4SHadar Hen Zion err = mlx5e_create_encap_header_ipv4(priv, mirred_dev, e, &out_dev); 1071ce99f6b9SOr Gerlitz else if (family == AF_INET6) 1072ce99f6b9SOr Gerlitz err = mlx5e_create_encap_header_ipv6(priv, mirred_dev, e, &out_dev); 1073ce99f6b9SOr Gerlitz 1074a54e20b4SHadar Hen Zion if (err) 1075a54e20b4SHadar Hen Zion goto out_err; 1076a54e20b4SHadar Hen Zion 1077a54e20b4SHadar Hen Zion attr->encap = e; 1078a54e20b4SHadar Hen Zion hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key); 1079a54e20b4SHadar Hen Zion 1080a54e20b4SHadar Hen Zion return err; 1081a54e20b4SHadar Hen Zion 1082a54e20b4SHadar Hen Zion out_err: 1083a54e20b4SHadar Hen Zion kfree(e); 1084a54e20b4SHadar Hen Zion return err; 1085a54e20b4SHadar Hen Zion } 1086a54e20b4SHadar Hen Zion 1087a54e20b4SHadar Hen Zion static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, 1088a54e20b4SHadar Hen Zion struct mlx5e_tc_flow *flow) 1089a54e20b4SHadar Hen Zion { 1090ecf5bb79SOr Gerlitz struct mlx5_esw_flow_attr *attr = flow->esw_attr; 1091a54e20b4SHadar Hen Zion struct ip_tunnel_info *info = NULL; 109203a9d11eSOr Gerlitz const struct tc_action *a; 109322dc13c8SWANG Cong LIST_HEAD(actions); 1094a54e20b4SHadar Hen Zion bool encap = false; 1095a54e20b4SHadar Hen Zion int err; 109603a9d11eSOr Gerlitz 109703a9d11eSOr Gerlitz if (tc_no_actions(exts)) 109803a9d11eSOr Gerlitz return -EINVAL; 109903a9d11eSOr Gerlitz 1100776b12b6SOr Gerlitz memset(attr, 0, sizeof(*attr)); 1101776b12b6SOr Gerlitz attr->in_rep = priv->ppriv; 110203a9d11eSOr Gerlitz 110322dc13c8SWANG Cong tcf_exts_to_list(exts, &actions); 110422dc13c8SWANG Cong list_for_each_entry(a, &actions, list) { 110503a9d11eSOr Gerlitz if (is_tcf_gact_shot(a)) { 11068b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP | 110703a9d11eSOr Gerlitz MLX5_FLOW_CONTEXT_ACTION_COUNT; 110803a9d11eSOr Gerlitz continue; 110903a9d11eSOr Gerlitz } 111003a9d11eSOr Gerlitz 11115724b8b5SShmulik Ladkani if (is_tcf_mirred_egress_redirect(a)) { 111203a9d11eSOr Gerlitz int ifindex = tcf_mirred_ifindex(a); 111303a9d11eSOr Gerlitz struct net_device *out_dev; 111403a9d11eSOr Gerlitz struct mlx5e_priv *out_priv; 111503a9d11eSOr Gerlitz 111603a9d11eSOr Gerlitz out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex); 111703a9d11eSOr Gerlitz 1118a54e20b4SHadar Hen Zion if (switchdev_port_same_parent_id(priv->netdev, 1119a54e20b4SHadar Hen Zion out_dev)) { 1120e37a79e5SMark Bloch attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1121e37a79e5SMark Bloch MLX5_FLOW_CONTEXT_ACTION_COUNT; 112203a9d11eSOr Gerlitz out_priv = netdev_priv(out_dev); 1123776b12b6SOr Gerlitz attr->out_rep = out_priv->ppriv; 1124a54e20b4SHadar Hen Zion } else if (encap) { 1125a54e20b4SHadar Hen Zion err = mlx5e_attach_encap(priv, info, 1126a54e20b4SHadar Hen Zion out_dev, attr); 1127a54e20b4SHadar Hen Zion if (err) 1128a54e20b4SHadar Hen Zion return err; 1129a54e20b4SHadar Hen Zion list_add(&flow->encap, &attr->encap->flows); 1130a54e20b4SHadar Hen Zion attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP | 1131a54e20b4SHadar Hen Zion MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1132a54e20b4SHadar Hen Zion MLX5_FLOW_CONTEXT_ACTION_COUNT; 1133a54e20b4SHadar Hen Zion out_priv = netdev_priv(attr->encap->out_dev); 1134a54e20b4SHadar Hen Zion attr->out_rep = out_priv->ppriv; 1135a54e20b4SHadar Hen Zion } else { 1136a54e20b4SHadar Hen Zion pr_err("devices %s %s not on same switch HW, can't offload forwarding\n", 1137a54e20b4SHadar Hen Zion priv->netdev->name, out_dev->name); 1138a54e20b4SHadar Hen Zion return -EINVAL; 1139a54e20b4SHadar Hen Zion } 1140a54e20b4SHadar Hen Zion continue; 1141a54e20b4SHadar Hen Zion } 1142a54e20b4SHadar Hen Zion 1143a54e20b4SHadar Hen Zion if (is_tcf_tunnel_set(a)) { 1144a54e20b4SHadar Hen Zion info = tcf_tunnel_info(a); 1145a54e20b4SHadar Hen Zion if (info) 1146a54e20b4SHadar Hen Zion encap = true; 1147a54e20b4SHadar Hen Zion else 1148a54e20b4SHadar Hen Zion return -EOPNOTSUPP; 114903a9d11eSOr Gerlitz continue; 115003a9d11eSOr Gerlitz } 115103a9d11eSOr Gerlitz 11528b32580dSOr Gerlitz if (is_tcf_vlan(a)) { 115309c91ddfSOr Gerlitz if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { 11548b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 115509c91ddfSOr Gerlitz } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { 11568b32580dSOr Gerlitz if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q)) 11578b32580dSOr Gerlitz return -EOPNOTSUPP; 11588b32580dSOr Gerlitz 11598b32580dSOr Gerlitz attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; 11608b32580dSOr Gerlitz attr->vlan = tcf_vlan_push_vid(a); 116109c91ddfSOr Gerlitz } else { /* action is TCA_VLAN_ACT_MODIFY */ 116209c91ddfSOr Gerlitz return -EOPNOTSUPP; 11638b32580dSOr Gerlitz } 11648b32580dSOr Gerlitz continue; 11658b32580dSOr Gerlitz } 11668b32580dSOr Gerlitz 1167bbd00f7eSHadar Hen Zion if (is_tcf_tunnel_release(a)) { 1168bbd00f7eSHadar Hen Zion attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; 1169bbd00f7eSHadar Hen Zion continue; 1170bbd00f7eSHadar Hen Zion } 1171bbd00f7eSHadar Hen Zion 117203a9d11eSOr Gerlitz return -EINVAL; 117303a9d11eSOr Gerlitz } 117403a9d11eSOr Gerlitz return 0; 117503a9d11eSOr Gerlitz } 117603a9d11eSOr Gerlitz 1177e3a2b7edSAmir Vadai int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, 1178e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 1179e3a2b7edSAmir Vadai { 1180adb4c123SOr Gerlitz struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 118117091853SOr Gerlitz struct mlx5e_tc_flow_parse_attr *parse_attr; 11823bc4b7bfSOr Gerlitz struct mlx5e_tc_table *tc = &priv->fs.tc; 11833bc4b7bfSOr Gerlitz struct mlx5e_tc_flow *flow; 11843bc4b7bfSOr Gerlitz int attr_size, err = 0; 118565ba8fb7SOr Gerlitz u8 flow_flags = 0; 1186e3a2b7edSAmir Vadai 118765ba8fb7SOr Gerlitz if (esw && esw->mode == SRIOV_OFFLOADS) { 118865ba8fb7SOr Gerlitz flow_flags = MLX5E_TC_FLOW_ESWITCH; 118965ba8fb7SOr Gerlitz attr_size = sizeof(struct mlx5_esw_flow_attr); 11903bc4b7bfSOr Gerlitz } else { 11913bc4b7bfSOr Gerlitz flow_flags = MLX5E_TC_FLOW_NIC; 11923bc4b7bfSOr Gerlitz attr_size = sizeof(struct mlx5_nic_flow_attr); 119365ba8fb7SOr Gerlitz } 1194776b12b6SOr Gerlitz 119565ba8fb7SOr Gerlitz flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL); 119617091853SOr Gerlitz parse_attr = mlx5_vzalloc(sizeof(*parse_attr)); 119717091853SOr Gerlitz if (!parse_attr || !flow) { 1198e3a2b7edSAmir Vadai err = -ENOMEM; 1199e3a2b7edSAmir Vadai goto err_free; 1200e3a2b7edSAmir Vadai } 1201e3a2b7edSAmir Vadai 1202e3a2b7edSAmir Vadai flow->cookie = f->cookie; 120365ba8fb7SOr Gerlitz flow->flags = flow_flags; 1204e3a2b7edSAmir Vadai 120517091853SOr Gerlitz err = parse_cls_flower(priv, flow, &parse_attr->spec, f); 1206e3a2b7edSAmir Vadai if (err < 0) 1207e3a2b7edSAmir Vadai goto err_free; 1208e3a2b7edSAmir Vadai 120965ba8fb7SOr Gerlitz if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { 1210a54e20b4SHadar Hen Zion err = parse_tc_fdb_actions(priv, f->exts, flow); 1211adb4c123SOr Gerlitz if (err < 0) 1212adb4c123SOr Gerlitz goto err_free; 121317091853SOr Gerlitz flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow->esw_attr); 1214adb4c123SOr Gerlitz } else { 12153bc4b7bfSOr Gerlitz err = parse_tc_nic_actions(priv, f->exts, flow->nic_attr); 1216e3a2b7edSAmir Vadai if (err < 0) 1217e3a2b7edSAmir Vadai goto err_free; 121817091853SOr Gerlitz flow->rule = mlx5e_tc_add_nic_flow(priv, parse_attr, flow->nic_attr); 1219adb4c123SOr Gerlitz } 1220adb4c123SOr Gerlitz 12215c40348cSOr Gerlitz if (IS_ERR(flow->rule)) { 12225c40348cSOr Gerlitz err = PTR_ERR(flow->rule); 12235e86397aSOr Gerlitz goto err_del_rule; 12245c40348cSOr Gerlitz } 12255c40348cSOr Gerlitz 1226e3a2b7edSAmir Vadai err = rhashtable_insert_fast(&tc->ht, &flow->node, 1227e3a2b7edSAmir Vadai tc->ht_params); 1228e3a2b7edSAmir Vadai if (err) 12295c40348cSOr Gerlitz goto err_del_rule; 1230e3a2b7edSAmir Vadai 1231e3a2b7edSAmir Vadai goto out; 1232e3a2b7edSAmir Vadai 12335c40348cSOr Gerlitz err_del_rule: 12345e86397aSOr Gerlitz mlx5e_tc_del_flow(priv, flow); 1235e3a2b7edSAmir Vadai 1236e3a2b7edSAmir Vadai err_free: 1237e3a2b7edSAmir Vadai kfree(flow); 1238e3a2b7edSAmir Vadai out: 123917091853SOr Gerlitz kvfree(parse_attr); 1240e3a2b7edSAmir Vadai return err; 1241e3a2b7edSAmir Vadai } 1242e3a2b7edSAmir Vadai 1243e3a2b7edSAmir Vadai int mlx5e_delete_flower(struct mlx5e_priv *priv, 1244e3a2b7edSAmir Vadai struct tc_cls_flower_offload *f) 1245e3a2b7edSAmir Vadai { 1246e3a2b7edSAmir Vadai struct mlx5e_tc_flow *flow; 1247acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 1248e3a2b7edSAmir Vadai 1249e3a2b7edSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 1250e3a2b7edSAmir Vadai tc->ht_params); 1251e3a2b7edSAmir Vadai if (!flow) 1252e3a2b7edSAmir Vadai return -EINVAL; 1253e3a2b7edSAmir Vadai 1254e3a2b7edSAmir Vadai rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params); 1255e3a2b7edSAmir Vadai 1256961e8979SRoi Dayan mlx5e_tc_del_flow(priv, flow); 1257e3a2b7edSAmir Vadai 1258a54e20b4SHadar Hen Zion 1259e3a2b7edSAmir Vadai kfree(flow); 1260e3a2b7edSAmir Vadai 1261e3a2b7edSAmir Vadai return 0; 1262e3a2b7edSAmir Vadai } 1263e3a2b7edSAmir Vadai 1264aad7e08dSAmir Vadai int mlx5e_stats_flower(struct mlx5e_priv *priv, 1265aad7e08dSAmir Vadai struct tc_cls_flower_offload *f) 1266aad7e08dSAmir Vadai { 1267aad7e08dSAmir Vadai struct mlx5e_tc_table *tc = &priv->fs.tc; 1268aad7e08dSAmir Vadai struct mlx5e_tc_flow *flow; 1269aad7e08dSAmir Vadai struct tc_action *a; 1270aad7e08dSAmir Vadai struct mlx5_fc *counter; 127122dc13c8SWANG Cong LIST_HEAD(actions); 1272aad7e08dSAmir Vadai u64 bytes; 1273aad7e08dSAmir Vadai u64 packets; 1274aad7e08dSAmir Vadai u64 lastuse; 1275aad7e08dSAmir Vadai 1276aad7e08dSAmir Vadai flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, 1277aad7e08dSAmir Vadai tc->ht_params); 1278aad7e08dSAmir Vadai if (!flow) 1279aad7e08dSAmir Vadai return -EINVAL; 1280aad7e08dSAmir Vadai 1281aad7e08dSAmir Vadai counter = mlx5_flow_rule_counter(flow->rule); 1282aad7e08dSAmir Vadai if (!counter) 1283aad7e08dSAmir Vadai return 0; 1284aad7e08dSAmir Vadai 1285aad7e08dSAmir Vadai mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); 1286aad7e08dSAmir Vadai 1287fed06ee8SOr Gerlitz preempt_disable(); 1288fed06ee8SOr Gerlitz 128922dc13c8SWANG Cong tcf_exts_to_list(f->exts, &actions); 129022dc13c8SWANG Cong list_for_each_entry(a, &actions, list) 1291aad7e08dSAmir Vadai tcf_action_stats_update(a, bytes, packets, lastuse); 1292aad7e08dSAmir Vadai 1293fed06ee8SOr Gerlitz preempt_enable(); 1294fed06ee8SOr Gerlitz 1295aad7e08dSAmir Vadai return 0; 1296aad7e08dSAmir Vadai } 1297aad7e08dSAmir Vadai 1298e8f887acSAmir Vadai static const struct rhashtable_params mlx5e_tc_flow_ht_params = { 1299e8f887acSAmir Vadai .head_offset = offsetof(struct mlx5e_tc_flow, node), 1300e8f887acSAmir Vadai .key_offset = offsetof(struct mlx5e_tc_flow, cookie), 1301e8f887acSAmir Vadai .key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie), 1302e8f887acSAmir Vadai .automatic_shrinking = true, 1303e8f887acSAmir Vadai }; 1304e8f887acSAmir Vadai 1305e8f887acSAmir Vadai int mlx5e_tc_init(struct mlx5e_priv *priv) 1306e8f887acSAmir Vadai { 1307acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 1308e8f887acSAmir Vadai 1309e8f887acSAmir Vadai tc->ht_params = mlx5e_tc_flow_ht_params; 1310e8f887acSAmir Vadai return rhashtable_init(&tc->ht, &tc->ht_params); 1311e8f887acSAmir Vadai } 1312e8f887acSAmir Vadai 1313e8f887acSAmir Vadai static void _mlx5e_tc_del_flow(void *ptr, void *arg) 1314e8f887acSAmir Vadai { 1315e8f887acSAmir Vadai struct mlx5e_tc_flow *flow = ptr; 1316e8f887acSAmir Vadai struct mlx5e_priv *priv = arg; 1317e8f887acSAmir Vadai 1318961e8979SRoi Dayan mlx5e_tc_del_flow(priv, flow); 1319e8f887acSAmir Vadai kfree(flow); 1320e8f887acSAmir Vadai } 1321e8f887acSAmir Vadai 1322e8f887acSAmir Vadai void mlx5e_tc_cleanup(struct mlx5e_priv *priv) 1323e8f887acSAmir Vadai { 1324acff797cSMaor Gottlieb struct mlx5e_tc_table *tc = &priv->fs.tc; 1325e8f887acSAmir Vadai 1326e8f887acSAmir Vadai rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv); 1327e8f887acSAmir Vadai 1328acff797cSMaor Gottlieb if (!IS_ERR_OR_NULL(tc->t)) { 1329acff797cSMaor Gottlieb mlx5_destroy_flow_table(tc->t); 1330acff797cSMaor Gottlieb tc->t = NULL; 1331e8f887acSAmir Vadai } 1332e8f887acSAmir Vadai } 1333