2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34 #include <linux/mlx5/fs.h>
36 static void arfs_destroy_table(struct arfs_table *arfs_t)
38 mlx5_del_flow_rule(arfs_t->default_rule);
39 mlx5e_destroy_flow_table(&arfs_t->ft);
42 void mlx5e_arfs_destroy_tables(struct mlx5e_priv *priv)
46 if (!(priv->netdev->hw_features & NETIF_F_NTUPLE))
48 for (i = 0; i < ARFS_NUM_TYPES; i++) {
49 if (!IS_ERR_OR_NULL(priv->fs.arfs.arfs_tables[i].ft.t))
50 arfs_destroy_table(&priv->fs.arfs.arfs_tables[i]);
54 static int arfs_add_default_rule(struct mlx5e_priv *priv,
57 struct arfs_table *arfs_t = &priv->fs.arfs.arfs_tables[type];
58 struct mlx5_flow_destination dest;
59 u8 match_criteria_enable = 0;
60 u32 *tirn = priv->indir_tirn;
65 match_value = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
66 match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
67 if (!match_value || !match_criteria) {
68 netdev_err(priv->netdev, "%s: alloc failed\n", __func__);
73 dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
76 dest.tir_num = tirn[MLX5E_TT_IPV4_TCP];
79 dest.tir_num = tirn[MLX5E_TT_IPV4_UDP];
82 dest.tir_num = tirn[MLX5E_TT_IPV6_TCP];
85 dest.tir_num = tirn[MLX5E_TT_IPV6_UDP];
92 arfs_t->default_rule = mlx5_add_flow_rule(arfs_t->ft.t, match_criteria_enable,
93 match_criteria, match_value,
94 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
95 MLX5_FS_DEFAULT_FLOW_TAG,
97 if (IS_ERR(arfs_t->default_rule)) {
98 err = PTR_ERR(arfs_t->default_rule);
99 arfs_t->default_rule = NULL;
100 netdev_err(priv->netdev, "%s: add rule failed, arfs type=%d\n",
104 kvfree(match_criteria);
109 #define MLX5E_ARFS_NUM_GROUPS 2
110 #define MLX5E_ARFS_GROUP1_SIZE BIT(12)
111 #define MLX5E_ARFS_GROUP2_SIZE BIT(0)
112 #define MLX5E_ARFS_TABLE_SIZE (MLX5E_ARFS_GROUP1_SIZE +\
113 MLX5E_ARFS_GROUP2_SIZE)
114 static int arfs_create_groups(struct mlx5e_flow_table *ft,
117 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
118 void *outer_headers_c;
124 ft->g = kcalloc(MLX5E_ARFS_NUM_GROUPS,
125 sizeof(*ft->g), GFP_KERNEL);
126 in = mlx5_vzalloc(inlen);
133 mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
134 outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc,
136 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ethertype);
140 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_dport);
141 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, tcp_sport);
145 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
146 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_sport);
156 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c,
157 src_ipv4_src_ipv6.ipv4_layout.ipv4);
158 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c,
159 dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
163 memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
164 src_ipv4_src_ipv6.ipv6_layout.ipv6),
166 memset(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
167 dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
175 MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
176 MLX5_SET_CFG(in, start_flow_index, ix);
177 ix += MLX5E_ARFS_GROUP1_SIZE;
178 MLX5_SET_CFG(in, end_flow_index, ix - 1);
179 ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
180 if (IS_ERR(ft->g[ft->num_groups]))
184 memset(in, 0, inlen);
185 MLX5_SET_CFG(in, start_flow_index, ix);
186 ix += MLX5E_ARFS_GROUP2_SIZE;
187 MLX5_SET_CFG(in, end_flow_index, ix - 1);
188 ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
189 if (IS_ERR(ft->g[ft->num_groups]))
197 err = PTR_ERR(ft->g[ft->num_groups]);
198 ft->g[ft->num_groups] = NULL;
205 static int arfs_create_table(struct mlx5e_priv *priv,
208 struct mlx5e_arfs_tables *arfs = &priv->fs.arfs;
209 struct mlx5e_flow_table *ft = &arfs->arfs_tables[type].ft;
212 ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO,
213 MLX5E_ARFS_TABLE_SIZE, MLX5E_ARFS_FT_LEVEL);
215 err = PTR_ERR(ft->t);
220 err = arfs_create_groups(ft, type);
224 err = arfs_add_default_rule(priv, type);
230 mlx5e_destroy_flow_table(ft);
234 int mlx5e_arfs_create_tables(struct mlx5e_priv *priv)
239 if (!(priv->netdev->hw_features & NETIF_F_NTUPLE))
242 for (i = 0; i < ARFS_NUM_TYPES; i++) {
243 err = arfs_create_table(priv, i);
249 mlx5e_arfs_destroy_tables(priv);