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
33 #include <net/flow_dissector.h>
34 #include <net/pkt_cls.h>
35 #include <net/tc_act/tc_gact.h>
36 #include <net/tc_act/tc_skbedit.h>
37 #include <linux/mlx5/fs.h>
38 #include <linux/mlx5/device.h>
39 #include <linux/rhashtable.h>
40 #include <net/switchdev.h>
41 #include <net/tc_act/tc_mirred.h>
46 struct mlx5e_tc_flow
{
47 struct rhash_head node
;
49 struct mlx5_flow_rule
*rule
;
52 #define MLX5E_TC_TABLE_NUM_ENTRIES 1024
53 #define MLX5E_TC_TABLE_NUM_GROUPS 4
55 static struct mlx5_flow_rule
*mlx5e_tc_add_nic_flow(struct mlx5e_priv
*priv
,
56 struct mlx5_flow_spec
*spec
,
57 u32 action
, u32 flow_tag
)
59 struct mlx5_core_dev
*dev
= priv
->mdev
;
60 struct mlx5_flow_destination dest
= { 0 };
61 struct mlx5_fc
*counter
= NULL
;
62 struct mlx5_flow_rule
*rule
;
63 bool table_created
= false;
65 if (action
& MLX5_FLOW_CONTEXT_ACTION_FWD_DEST
) {
66 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE
;
67 dest
.ft
= priv
->fs
.vlan
.ft
.t
;
68 } else if (action
& MLX5_FLOW_CONTEXT_ACTION_COUNT
) {
69 counter
= mlx5_fc_create(dev
, true);
71 return ERR_CAST(counter
);
73 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_COUNTER
;
74 dest
.counter
= counter
;
77 if (IS_ERR_OR_NULL(priv
->fs
.tc
.t
)) {
79 mlx5_create_auto_grouped_flow_table(priv
->fs
.ns
,
81 MLX5E_TC_TABLE_NUM_ENTRIES
,
82 MLX5E_TC_TABLE_NUM_GROUPS
,
84 if (IS_ERR(priv
->fs
.tc
.t
)) {
85 netdev_err(priv
->netdev
,
86 "Failed to create tc offload table\n");
87 rule
= ERR_CAST(priv
->fs
.tc
.t
);
94 spec
->match_criteria_enable
= MLX5_MATCH_OUTER_HEADERS
;
95 rule
= mlx5_add_flow_rule(priv
->fs
.tc
.t
, spec
,
106 mlx5_destroy_flow_table(priv
->fs
.tc
.t
);
107 priv
->fs
.tc
.t
= NULL
;
110 mlx5_fc_destroy(dev
, counter
);
115 static struct mlx5_flow_rule
*mlx5e_tc_add_fdb_flow(struct mlx5e_priv
*priv
,
116 struct mlx5_flow_spec
*spec
,
117 u32 action
, u32 dst_vport
)
119 struct mlx5_eswitch
*esw
= priv
->mdev
->priv
.eswitch
;
120 struct mlx5_eswitch_rep
*rep
= priv
->ppriv
;
123 if (rep
->vport
) /* set source vport for the flow */
124 src_vport
= rep
->vport
;
126 src_vport
= FDB_UPLINK_VPORT
;
128 return mlx5_eswitch_add_offloaded_rule(esw
, spec
, action
, src_vport
, dst_vport
);
131 static void mlx5e_tc_del_flow(struct mlx5e_priv
*priv
,
132 struct mlx5_flow_rule
*rule
)
134 struct mlx5_fc
*counter
= NULL
;
136 counter
= mlx5_flow_rule_counter(rule
);
138 mlx5_del_flow_rule(rule
);
140 mlx5_fc_destroy(priv
->mdev
, counter
);
142 if (!mlx5e_tc_num_filters(priv
) && (priv
->fs
.tc
.t
)) {
143 mlx5_destroy_flow_table(priv
->fs
.tc
.t
);
144 priv
->fs
.tc
.t
= NULL
;
148 static int parse_cls_flower(struct mlx5e_priv
*priv
, struct mlx5_flow_spec
*spec
,
149 struct tc_cls_flower_offload
*f
)
151 void *headers_c
= MLX5_ADDR_OF(fte_match_param
, spec
->match_criteria
,
153 void *headers_v
= MLX5_ADDR_OF(fte_match_param
, spec
->match_value
,
158 if (f
->dissector
->used_keys
&
159 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL
) |
160 BIT(FLOW_DISSECTOR_KEY_BASIC
) |
161 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS
) |
162 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS
) |
163 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS
) |
164 BIT(FLOW_DISSECTOR_KEY_PORTS
))) {
165 netdev_warn(priv
->netdev
, "Unsupported key used: 0x%x\n",
166 f
->dissector
->used_keys
);
170 if (dissector_uses_key(f
->dissector
, FLOW_DISSECTOR_KEY_CONTROL
)) {
171 struct flow_dissector_key_control
*key
=
172 skb_flow_dissector_target(f
->dissector
,
173 FLOW_DISSECTOR_KEY_CONTROL
,
175 addr_type
= key
->addr_type
;
178 if (dissector_uses_key(f
->dissector
, FLOW_DISSECTOR_KEY_BASIC
)) {
179 struct flow_dissector_key_basic
*key
=
180 skb_flow_dissector_target(f
->dissector
,
181 FLOW_DISSECTOR_KEY_BASIC
,
183 struct flow_dissector_key_basic
*mask
=
184 skb_flow_dissector_target(f
->dissector
,
185 FLOW_DISSECTOR_KEY_BASIC
,
187 ip_proto
= key
->ip_proto
;
189 MLX5_SET(fte_match_set_lyr_2_4
, headers_c
, ethertype
,
190 ntohs(mask
->n_proto
));
191 MLX5_SET(fte_match_set_lyr_2_4
, headers_v
, ethertype
,
192 ntohs(key
->n_proto
));
194 MLX5_SET(fte_match_set_lyr_2_4
, headers_c
, ip_protocol
,
196 MLX5_SET(fte_match_set_lyr_2_4
, headers_v
, ip_protocol
,
200 if (dissector_uses_key(f
->dissector
, FLOW_DISSECTOR_KEY_ETH_ADDRS
)) {
201 struct flow_dissector_key_eth_addrs
*key
=
202 skb_flow_dissector_target(f
->dissector
,
203 FLOW_DISSECTOR_KEY_ETH_ADDRS
,
205 struct flow_dissector_key_eth_addrs
*mask
=
206 skb_flow_dissector_target(f
->dissector
,
207 FLOW_DISSECTOR_KEY_ETH_ADDRS
,
210 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_c
,
213 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_v
,
217 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_c
,
220 ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_v
,
225 if (addr_type
== FLOW_DISSECTOR_KEY_IPV4_ADDRS
) {
226 struct flow_dissector_key_ipv4_addrs
*key
=
227 skb_flow_dissector_target(f
->dissector
,
228 FLOW_DISSECTOR_KEY_IPV4_ADDRS
,
230 struct flow_dissector_key_ipv4_addrs
*mask
=
231 skb_flow_dissector_target(f
->dissector
,
232 FLOW_DISSECTOR_KEY_IPV4_ADDRS
,
235 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_c
,
236 src_ipv4_src_ipv6
.ipv4_layout
.ipv4
),
237 &mask
->src
, sizeof(mask
->src
));
238 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_v
,
239 src_ipv4_src_ipv6
.ipv4_layout
.ipv4
),
240 &key
->src
, sizeof(key
->src
));
241 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_c
,
242 dst_ipv4_dst_ipv6
.ipv4_layout
.ipv4
),
243 &mask
->dst
, sizeof(mask
->dst
));
244 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_v
,
245 dst_ipv4_dst_ipv6
.ipv4_layout
.ipv4
),
246 &key
->dst
, sizeof(key
->dst
));
249 if (addr_type
== FLOW_DISSECTOR_KEY_IPV6_ADDRS
) {
250 struct flow_dissector_key_ipv6_addrs
*key
=
251 skb_flow_dissector_target(f
->dissector
,
252 FLOW_DISSECTOR_KEY_IPV6_ADDRS
,
254 struct flow_dissector_key_ipv6_addrs
*mask
=
255 skb_flow_dissector_target(f
->dissector
,
256 FLOW_DISSECTOR_KEY_IPV6_ADDRS
,
259 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_c
,
260 src_ipv4_src_ipv6
.ipv6_layout
.ipv6
),
261 &mask
->src
, sizeof(mask
->src
));
262 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_v
,
263 src_ipv4_src_ipv6
.ipv6_layout
.ipv6
),
264 &key
->src
, sizeof(key
->src
));
266 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_c
,
267 dst_ipv4_dst_ipv6
.ipv6_layout
.ipv6
),
268 &mask
->dst
, sizeof(mask
->dst
));
269 memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4
, headers_v
,
270 dst_ipv4_dst_ipv6
.ipv6_layout
.ipv6
),
271 &key
->dst
, sizeof(key
->dst
));
274 if (dissector_uses_key(f
->dissector
, FLOW_DISSECTOR_KEY_PORTS
)) {
275 struct flow_dissector_key_ports
*key
=
276 skb_flow_dissector_target(f
->dissector
,
277 FLOW_DISSECTOR_KEY_PORTS
,
279 struct flow_dissector_key_ports
*mask
=
280 skb_flow_dissector_target(f
->dissector
,
281 FLOW_DISSECTOR_KEY_PORTS
,
285 MLX5_SET(fte_match_set_lyr_2_4
, headers_c
,
286 tcp_sport
, ntohs(mask
->src
));
287 MLX5_SET(fte_match_set_lyr_2_4
, headers_v
,
288 tcp_sport
, ntohs(key
->src
));
290 MLX5_SET(fte_match_set_lyr_2_4
, headers_c
,
291 tcp_dport
, ntohs(mask
->dst
));
292 MLX5_SET(fte_match_set_lyr_2_4
, headers_v
,
293 tcp_dport
, ntohs(key
->dst
));
297 MLX5_SET(fte_match_set_lyr_2_4
, headers_c
,
298 udp_sport
, ntohs(mask
->src
));
299 MLX5_SET(fte_match_set_lyr_2_4
, headers_v
,
300 udp_sport
, ntohs(key
->src
));
302 MLX5_SET(fte_match_set_lyr_2_4
, headers_c
,
303 udp_dport
, ntohs(mask
->dst
));
304 MLX5_SET(fte_match_set_lyr_2_4
, headers_v
,
305 udp_dport
, ntohs(key
->dst
));
308 netdev_err(priv
->netdev
,
309 "Only UDP and TCP transport are supported\n");
317 static int parse_tc_nic_actions(struct mlx5e_priv
*priv
, struct tcf_exts
*exts
,
318 u32
*action
, u32
*flow_tag
)
320 const struct tc_action
*a
;
323 if (tc_no_actions(exts
))
326 *flow_tag
= MLX5_FS_DEFAULT_FLOW_TAG
;
329 tcf_exts_to_list(exts
, &actions
);
330 list_for_each_entry(a
, &actions
, list
) {
331 /* Only support a single action per rule */
335 if (is_tcf_gact_shot(a
)) {
336 *action
|= MLX5_FLOW_CONTEXT_ACTION_DROP
;
337 if (MLX5_CAP_FLOWTABLE(priv
->mdev
,
338 flow_table_properties_nic_receive
.flow_counter
))
339 *action
|= MLX5_FLOW_CONTEXT_ACTION_COUNT
;
343 if (is_tcf_skbedit_mark(a
)) {
344 u32 mark
= tcf_skbedit_mark(a
);
346 if (mark
& ~MLX5E_TC_FLOW_ID_MASK
) {
347 netdev_warn(priv
->netdev
, "Bad flow mark - only 16 bit is supported: 0x%x\n",
353 *action
|= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST
;
363 static int parse_tc_fdb_actions(struct mlx5e_priv
*priv
, struct tcf_exts
*exts
,
364 u32
*action
, u32
*dest_vport
)
366 const struct tc_action
*a
;
369 if (tc_no_actions(exts
))
374 tcf_exts_to_list(exts
, &actions
);
375 list_for_each_entry(a
, &actions
, list
) {
376 /* Only support a single action per rule */
380 if (is_tcf_gact_shot(a
)) {
381 *action
= MLX5_FLOW_CONTEXT_ACTION_DROP
|
382 MLX5_FLOW_CONTEXT_ACTION_COUNT
;
386 if (is_tcf_mirred_redirect(a
)) {
387 int ifindex
= tcf_mirred_ifindex(a
);
388 struct net_device
*out_dev
;
389 struct mlx5e_priv
*out_priv
;
390 struct mlx5_eswitch_rep
*out_rep
;
392 out_dev
= __dev_get_by_index(dev_net(priv
->netdev
), ifindex
);
394 if (!switchdev_port_same_parent_id(priv
->netdev
, out_dev
)) {
395 pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
396 priv
->netdev
->name
, out_dev
->name
);
400 out_priv
= netdev_priv(out_dev
);
401 out_rep
= out_priv
->ppriv
;
402 if (out_rep
->vport
== 0)
403 *dest_vport
= FDB_UPLINK_VPORT
;
405 *dest_vport
= out_rep
->vport
;
406 *action
= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST
;
415 int mlx5e_configure_flower(struct mlx5e_priv
*priv
, __be16 protocol
,
416 struct tc_cls_flower_offload
*f
)
418 struct mlx5e_tc_table
*tc
= &priv
->fs
.tc
;
420 u32 flow_tag
, action
, dest_vport
= 0;
421 struct mlx5e_tc_flow
*flow
;
422 struct mlx5_flow_spec
*spec
;
423 struct mlx5_flow_rule
*old
= NULL
;
424 struct mlx5_eswitch
*esw
= priv
->mdev
->priv
.eswitch
;
426 flow
= rhashtable_lookup_fast(&tc
->ht
, &f
->cookie
,
431 flow
= kzalloc(sizeof(*flow
), GFP_KERNEL
);
433 spec
= mlx5_vzalloc(sizeof(*spec
));
434 if (!spec
|| !flow
) {
439 flow
->cookie
= f
->cookie
;
441 err
= parse_cls_flower(priv
, spec
, f
);
445 if (esw
&& esw
->mode
== SRIOV_OFFLOADS
) {
446 err
= parse_tc_fdb_actions(priv
, f
->exts
, &action
, &dest_vport
);
449 flow
->rule
= mlx5e_tc_add_fdb_flow(priv
, spec
, action
, dest_vport
);
451 err
= parse_tc_nic_actions(priv
, f
->exts
, &action
, &flow_tag
);
454 flow
->rule
= mlx5e_tc_add_nic_flow(priv
, spec
, action
, flow_tag
);
457 if (IS_ERR(flow
->rule
)) {
458 err
= PTR_ERR(flow
->rule
);
462 err
= rhashtable_insert_fast(&tc
->ht
, &flow
->node
,
468 mlx5e_tc_del_flow(priv
, old
);
473 mlx5_del_flow_rule(flow
->rule
);
483 int mlx5e_delete_flower(struct mlx5e_priv
*priv
,
484 struct tc_cls_flower_offload
*f
)
486 struct mlx5e_tc_flow
*flow
;
487 struct mlx5e_tc_table
*tc
= &priv
->fs
.tc
;
489 flow
= rhashtable_lookup_fast(&tc
->ht
, &f
->cookie
,
494 rhashtable_remove_fast(&tc
->ht
, &flow
->node
, tc
->ht_params
);
496 mlx5e_tc_del_flow(priv
, flow
->rule
);
503 int mlx5e_stats_flower(struct mlx5e_priv
*priv
,
504 struct tc_cls_flower_offload
*f
)
506 struct mlx5e_tc_table
*tc
= &priv
->fs
.tc
;
507 struct mlx5e_tc_flow
*flow
;
509 struct mlx5_fc
*counter
;
515 flow
= rhashtable_lookup_fast(&tc
->ht
, &f
->cookie
,
520 counter
= mlx5_flow_rule_counter(flow
->rule
);
524 mlx5_fc_query_cached(counter
, &bytes
, &packets
, &lastuse
);
526 tcf_exts_to_list(f
->exts
, &actions
);
527 list_for_each_entry(a
, &actions
, list
)
528 tcf_action_stats_update(a
, bytes
, packets
, lastuse
);
533 static const struct rhashtable_params mlx5e_tc_flow_ht_params
= {
534 .head_offset
= offsetof(struct mlx5e_tc_flow
, node
),
535 .key_offset
= offsetof(struct mlx5e_tc_flow
, cookie
),
536 .key_len
= sizeof(((struct mlx5e_tc_flow
*)0)->cookie
),
537 .automatic_shrinking
= true,
540 int mlx5e_tc_init(struct mlx5e_priv
*priv
)
542 struct mlx5e_tc_table
*tc
= &priv
->fs
.tc
;
544 tc
->ht_params
= mlx5e_tc_flow_ht_params
;
545 return rhashtable_init(&tc
->ht
, &tc
->ht_params
);
548 static void _mlx5e_tc_del_flow(void *ptr
, void *arg
)
550 struct mlx5e_tc_flow
*flow
= ptr
;
551 struct mlx5e_priv
*priv
= arg
;
553 mlx5e_tc_del_flow(priv
, flow
->rule
);
557 void mlx5e_tc_cleanup(struct mlx5e_priv
*priv
)
559 struct mlx5e_tc_table
*tc
= &priv
->fs
.tc
;
561 rhashtable_free_and_destroy(&tc
->ht
, _mlx5e_tc_del_flow
, priv
);
563 if (!IS_ERR_OR_NULL(tc
->t
)) {
564 mlx5_destroy_flow_table(tc
->t
);