1ab3f3d5eSRoi Dayan // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2ab3f3d5eSRoi Dayan // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3ab3f3d5eSRoi Dayan
4ab3f3d5eSRoi Dayan #include <linux/if_macvlan.h>
5ab3f3d5eSRoi Dayan #include <linux/if_vlan.h>
6ab3f3d5eSRoi Dayan #include <net/bareudp.h>
7ab3f3d5eSRoi Dayan #include <net/bonding.h>
8ab3f3d5eSRoi Dayan #include "act.h"
9ab3f3d5eSRoi Dayan #include "vlan.h"
10ab3f3d5eSRoi Dayan #include "en/tc_tun_encap.h"
11ab3f3d5eSRoi Dayan #include "en/tc_priv.h"
12ab3f3d5eSRoi Dayan #include "en_rep.h"
1394db3317SEli Cohen #include "lag/lag.h"
14ab3f3d5eSRoi Dayan
15ab3f3d5eSRoi Dayan static bool
same_vf_reps(struct mlx5e_priv * priv,struct net_device * out_dev)16ab3f3d5eSRoi Dayan same_vf_reps(struct mlx5e_priv *priv, struct net_device *out_dev)
17ab3f3d5eSRoi Dayan {
18ab3f3d5eSRoi Dayan return mlx5e_eswitch_vf_rep(priv->netdev) &&
19ab3f3d5eSRoi Dayan priv->netdev == out_dev;
20ab3f3d5eSRoi Dayan }
21ab3f3d5eSRoi Dayan
22ab3f3d5eSRoi Dayan static int
verify_uplink_forwarding(struct mlx5e_priv * priv,struct mlx5_flow_attr * attr,struct net_device * out_dev,struct netlink_ext_ack * extack)23ab3f3d5eSRoi Dayan verify_uplink_forwarding(struct mlx5e_priv *priv,
24ab3f3d5eSRoi Dayan struct mlx5_flow_attr *attr,
25ab3f3d5eSRoi Dayan struct net_device *out_dev,
26ab3f3d5eSRoi Dayan struct netlink_ext_ack *extack)
27ab3f3d5eSRoi Dayan {
28ab3f3d5eSRoi Dayan struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
29ab3f3d5eSRoi Dayan struct mlx5e_rep_priv *rep_priv;
30ab3f3d5eSRoi Dayan
31ab3f3d5eSRoi Dayan /* Forwarding non encapsulated traffic between
32ab3f3d5eSRoi Dayan * uplink ports is allowed only if
33ab3f3d5eSRoi Dayan * termination_table_raw_traffic cap is set.
34ab3f3d5eSRoi Dayan *
35ab3f3d5eSRoi Dayan * Input vport was stored attr->in_rep.
36ab3f3d5eSRoi Dayan * In LAG case, *priv* is the private data of
37ab3f3d5eSRoi Dayan * uplink which may be not the input vport.
38ab3f3d5eSRoi Dayan */
39ab3f3d5eSRoi Dayan rep_priv = mlx5e_rep_to_rep_priv(attr->esw_attr->in_rep);
40ab3f3d5eSRoi Dayan
41ab3f3d5eSRoi Dayan if (!(mlx5e_eswitch_uplink_rep(rep_priv->netdev) &&
42ab3f3d5eSRoi Dayan mlx5e_eswitch_uplink_rep(out_dev)))
43ab3f3d5eSRoi Dayan return 0;
44ab3f3d5eSRoi Dayan
45ab3f3d5eSRoi Dayan if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev,
46ab3f3d5eSRoi Dayan termination_table_raw_traffic)) {
47ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack,
48ab3f3d5eSRoi Dayan "devices are both uplink, can't offload forwarding");
49ab3f3d5eSRoi Dayan return -EOPNOTSUPP;
50ab3f3d5eSRoi Dayan } else if (out_dev != rep_priv->netdev) {
51ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack,
52ab3f3d5eSRoi Dayan "devices are not the same uplink, can't offload forwarding");
53ab3f3d5eSRoi Dayan return -EOPNOTSUPP;
54ab3f3d5eSRoi Dayan }
55ab3f3d5eSRoi Dayan return 0;
56ab3f3d5eSRoi Dayan }
57ab3f3d5eSRoi Dayan
58ab3f3d5eSRoi Dayan static bool
is_duplicated_output_device(struct net_device * dev,struct net_device * out_dev,int * ifindexes,int if_count,struct netlink_ext_ack * extack)59ab3f3d5eSRoi Dayan is_duplicated_output_device(struct net_device *dev,
60ab3f3d5eSRoi Dayan struct net_device *out_dev,
61ab3f3d5eSRoi Dayan int *ifindexes, int if_count,
62ab3f3d5eSRoi Dayan struct netlink_ext_ack *extack)
63ab3f3d5eSRoi Dayan {
64ab3f3d5eSRoi Dayan int i;
65ab3f3d5eSRoi Dayan
66ab3f3d5eSRoi Dayan for (i = 0; i < if_count; i++) {
67ab3f3d5eSRoi Dayan if (ifindexes[i] == out_dev->ifindex) {
68ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack, "can't duplicate output to same device");
69ab3f3d5eSRoi Dayan netdev_err(dev, "can't duplicate output to same device: %s\n",
70ab3f3d5eSRoi Dayan out_dev->name);
71ab3f3d5eSRoi Dayan return true;
72ab3f3d5eSRoi Dayan }
73ab3f3d5eSRoi Dayan }
74ab3f3d5eSRoi Dayan
75ab3f3d5eSRoi Dayan return false;
76ab3f3d5eSRoi Dayan }
77ab3f3d5eSRoi Dayan
78ab3f3d5eSRoi Dayan static struct net_device *
get_fdb_out_dev(struct net_device * uplink_dev,struct net_device * out_dev)79ab3f3d5eSRoi Dayan get_fdb_out_dev(struct net_device *uplink_dev, struct net_device *out_dev)
80ab3f3d5eSRoi Dayan {
81ab3f3d5eSRoi Dayan struct net_device *fdb_out_dev = out_dev;
82ab3f3d5eSRoi Dayan struct net_device *uplink_upper;
83ab3f3d5eSRoi Dayan
84ab3f3d5eSRoi Dayan rcu_read_lock();
85ab3f3d5eSRoi Dayan uplink_upper = netdev_master_upper_dev_get_rcu(uplink_dev);
86ab3f3d5eSRoi Dayan if (uplink_upper && netif_is_lag_master(uplink_upper) &&
87ab3f3d5eSRoi Dayan uplink_upper == out_dev) {
88ab3f3d5eSRoi Dayan fdb_out_dev = uplink_dev;
89ab3f3d5eSRoi Dayan } else if (netif_is_lag_master(out_dev)) {
90ab3f3d5eSRoi Dayan fdb_out_dev = bond_option_active_slave_get_rcu(netdev_priv(out_dev));
91ab3f3d5eSRoi Dayan if (fdb_out_dev &&
92ab3f3d5eSRoi Dayan (!mlx5e_eswitch_rep(fdb_out_dev) ||
93ab3f3d5eSRoi Dayan !netdev_port_same_parent_id(fdb_out_dev, uplink_dev)))
94ab3f3d5eSRoi Dayan fdb_out_dev = NULL;
95ab3f3d5eSRoi Dayan }
96ab3f3d5eSRoi Dayan rcu_read_unlock();
97ab3f3d5eSRoi Dayan return fdb_out_dev;
98ab3f3d5eSRoi Dayan }
99ab3f3d5eSRoi Dayan
100ab3f3d5eSRoi Dayan static bool
tc_act_can_offload_mirred(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,int act_index,struct mlx5_flow_attr * attr)101ab3f3d5eSRoi Dayan tc_act_can_offload_mirred(struct mlx5e_tc_act_parse_state *parse_state,
102ab3f3d5eSRoi Dayan const struct flow_action_entry *act,
1038be9686dSRoi Dayan int act_index,
1048be9686dSRoi Dayan struct mlx5_flow_attr *attr)
105ab3f3d5eSRoi Dayan {
106ab3f3d5eSRoi Dayan struct netlink_ext_ack *extack = parse_state->extack;
107ab3f3d5eSRoi Dayan struct mlx5e_tc_flow *flow = parse_state->flow;
108ab3f3d5eSRoi Dayan struct mlx5e_tc_flow_parse_attr *parse_attr;
109ab3f3d5eSRoi Dayan struct net_device *out_dev = act->dev;
110ab3f3d5eSRoi Dayan struct mlx5e_priv *priv = flow->priv;
111ab3f3d5eSRoi Dayan struct mlx5_esw_flow_attr *esw_attr;
112ab3f3d5eSRoi Dayan
1138be9686dSRoi Dayan parse_attr = attr->parse_attr;
1148be9686dSRoi Dayan esw_attr = attr->esw_attr;
115ab3f3d5eSRoi Dayan
116ab3f3d5eSRoi Dayan if (!out_dev) {
117ab3f3d5eSRoi Dayan /* out_dev is NULL when filters with
118ab3f3d5eSRoi Dayan * non-existing mirred device are replayed to
119ab3f3d5eSRoi Dayan * the driver.
120ab3f3d5eSRoi Dayan */
121ab3f3d5eSRoi Dayan return false;
122ab3f3d5eSRoi Dayan }
123ab3f3d5eSRoi Dayan
124ab3f3d5eSRoi Dayan if (parse_state->mpls_push && !netif_is_bareudp(out_dev)) {
125ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack, "mpls is supported only through a bareudp device");
126ab3f3d5eSRoi Dayan return false;
127ab3f3d5eSRoi Dayan }
128ab3f3d5eSRoi Dayan
129725726fdSMaor Dickman if (parse_state->eth_pop && !parse_state->mpls_push) {
130725726fdSMaor Dickman NL_SET_ERR_MSG_MOD(extack, "vlan pop eth is supported only with mpls push");
131725726fdSMaor Dickman return false;
132725726fdSMaor Dickman }
133725726fdSMaor Dickman
134697319b2SMaor Dickman if (flow_flag_test(parse_state->flow, L3_TO_L2_DECAP) && !parse_state->eth_push) {
135697319b2SMaor Dickman NL_SET_ERR_MSG_MOD(extack, "mpls pop is only supported with vlan eth push");
136697319b2SMaor Dickman return false;
137697319b2SMaor Dickman }
138697319b2SMaor Dickman
139ab3f3d5eSRoi Dayan if (mlx5e_is_ft_flow(flow) && out_dev == priv->netdev) {
140ab3f3d5eSRoi Dayan /* Ignore forward to self rules generated
141ab3f3d5eSRoi Dayan * by adding both mlx5 devs to the flow table
142ab3f3d5eSRoi Dayan * block on a normal nft offload setup.
143ab3f3d5eSRoi Dayan */
144ab3f3d5eSRoi Dayan return false;
145ab3f3d5eSRoi Dayan }
146ab3f3d5eSRoi Dayan
147ab3f3d5eSRoi Dayan if (esw_attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
148ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack,
149ab3f3d5eSRoi Dayan "can't support more output ports, can't offload forwarding");
150ab3f3d5eSRoi Dayan netdev_warn(priv->netdev,
151ab3f3d5eSRoi Dayan "can't support more than %d output ports, can't offload forwarding\n",
152ab3f3d5eSRoi Dayan esw_attr->out_count);
153ab3f3d5eSRoi Dayan return false;
154ab3f3d5eSRoi Dayan }
155ab3f3d5eSRoi Dayan
156ab3f3d5eSRoi Dayan if (parse_state->encap ||
157ab3f3d5eSRoi Dayan netdev_port_same_parent_id(priv->netdev, out_dev) ||
158ab3f3d5eSRoi Dayan netif_is_ovs_master(out_dev))
159ab3f3d5eSRoi Dayan return true;
160ab3f3d5eSRoi Dayan
161ab3f3d5eSRoi Dayan if (parse_attr->filter_dev != priv->netdev) {
162ab3f3d5eSRoi Dayan /* All mlx5 devices are called to configure
163ab3f3d5eSRoi Dayan * high level device filters. Therefore, the
164ab3f3d5eSRoi Dayan * *attempt* to install a filter on invalid
165ab3f3d5eSRoi Dayan * eswitch should not trigger an explicit error
166ab3f3d5eSRoi Dayan */
167ab3f3d5eSRoi Dayan return false;
168ab3f3d5eSRoi Dayan }
169ab3f3d5eSRoi Dayan
170ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack, "devices are not on same switch HW, can't offload forwarding");
171ab3f3d5eSRoi Dayan
172ab3f3d5eSRoi Dayan return false;
173ab3f3d5eSRoi Dayan }
174ab3f3d5eSRoi Dayan
175ab3f3d5eSRoi Dayan static int
parse_mirred_encap(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5_flow_attr * attr)176ab3f3d5eSRoi Dayan parse_mirred_encap(struct mlx5e_tc_act_parse_state *parse_state,
177ab3f3d5eSRoi Dayan const struct flow_action_entry *act,
178ab3f3d5eSRoi Dayan struct mlx5_flow_attr *attr)
179ab3f3d5eSRoi Dayan {
180ab3f3d5eSRoi Dayan struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
181ab3f3d5eSRoi Dayan struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
182ab3f3d5eSRoi Dayan struct net_device *out_dev = act->dev;
183ab3f3d5eSRoi Dayan
184ab3f3d5eSRoi Dayan parse_attr->mirred_ifindex[esw_attr->out_count] = out_dev->ifindex;
185ab3f3d5eSRoi Dayan parse_attr->tun_info[esw_attr->out_count] =
186ab3f3d5eSRoi Dayan mlx5e_dup_tun_info(parse_state->tun_info);
187ab3f3d5eSRoi Dayan
188ab3f3d5eSRoi Dayan if (!parse_attr->tun_info[esw_attr->out_count])
189ab3f3d5eSRoi Dayan return -ENOMEM;
190ab3f3d5eSRoi Dayan
191ab3f3d5eSRoi Dayan parse_state->encap = false;
192c63741b4SMaor Dickman
193c63741b4SMaor Dickman if (parse_state->mpls_push) {
194c63741b4SMaor Dickman memcpy(&parse_attr->mpls_info[esw_attr->out_count],
195c63741b4SMaor Dickman &parse_state->mpls_info, sizeof(parse_state->mpls_info));
196c63741b4SMaor Dickman parse_state->mpls_push = false;
197c63741b4SMaor Dickman }
198ab3f3d5eSRoi Dayan esw_attr->dests[esw_attr->out_count].flags |= MLX5_ESW_DEST_ENCAP;
199ab3f3d5eSRoi Dayan esw_attr->out_count++;
200*96c8c465SVlad Buslov /* attr->dests[].vport is resolved when we handle encap */
201ab3f3d5eSRoi Dayan
202ab3f3d5eSRoi Dayan return 0;
203ab3f3d5eSRoi Dayan }
204ab3f3d5eSRoi Dayan
205ab3f3d5eSRoi Dayan static int
parse_mirred(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)206ab3f3d5eSRoi Dayan parse_mirred(struct mlx5e_tc_act_parse_state *parse_state,
207ab3f3d5eSRoi Dayan const struct flow_action_entry *act,
208ab3f3d5eSRoi Dayan struct mlx5e_priv *priv,
209ab3f3d5eSRoi Dayan struct mlx5_flow_attr *attr)
210ab3f3d5eSRoi Dayan {
211ab3f3d5eSRoi Dayan struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
212ab3f3d5eSRoi Dayan struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
213ab3f3d5eSRoi Dayan struct netlink_ext_ack *extack = parse_state->extack;
214ab3f3d5eSRoi Dayan struct mlx5e_rep_priv *rpriv = priv->ppriv;
215ab3f3d5eSRoi Dayan struct net_device *out_dev = act->dev;
216ab3f3d5eSRoi Dayan struct net_device *uplink_dev;
217ab3f3d5eSRoi Dayan struct mlx5e_priv *out_priv;
218ab3f3d5eSRoi Dayan struct mlx5_eswitch *esw;
219ab3f3d5eSRoi Dayan int *ifindexes;
220ab3f3d5eSRoi Dayan int if_count;
221ab3f3d5eSRoi Dayan int err;
222ab3f3d5eSRoi Dayan
223ab3f3d5eSRoi Dayan esw = priv->mdev->priv.eswitch;
224ab3f3d5eSRoi Dayan uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
225ab3f3d5eSRoi Dayan ifindexes = parse_state->ifindexes;
226ab3f3d5eSRoi Dayan if_count = parse_state->if_count;
227ab3f3d5eSRoi Dayan
228ab3f3d5eSRoi Dayan if (is_duplicated_output_device(priv->netdev, out_dev, ifindexes, if_count, extack))
229ab3f3d5eSRoi Dayan return -EOPNOTSUPP;
230ab3f3d5eSRoi Dayan
231ab3f3d5eSRoi Dayan parse_state->ifindexes[if_count] = out_dev->ifindex;
232ab3f3d5eSRoi Dayan parse_state->if_count++;
2332afcfae7SRoi Dayan
2342afcfae7SRoi Dayan if (mlx5_lag_mpesw_do_mirred(priv->mdev, out_dev, extack))
2352afcfae7SRoi Dayan return -EOPNOTSUPP;
236ab3f3d5eSRoi Dayan
23763b02048SMaor Dickman if (netif_is_macvlan(out_dev))
23863b02048SMaor Dickman out_dev = macvlan_dev_real_dev(out_dev);
23963b02048SMaor Dickman
240ab3f3d5eSRoi Dayan out_dev = get_fdb_out_dev(uplink_dev, out_dev);
241ab3f3d5eSRoi Dayan if (!out_dev)
242ab3f3d5eSRoi Dayan return -ENODEV;
243ab3f3d5eSRoi Dayan
244ab3f3d5eSRoi Dayan if (is_vlan_dev(out_dev)) {
245ab3f3d5eSRoi Dayan err = mlx5e_tc_act_vlan_add_push_action(priv, attr, &out_dev, extack);
246ab3f3d5eSRoi Dayan if (err)
247ab3f3d5eSRoi Dayan return err;
248ab3f3d5eSRoi Dayan }
249ab3f3d5eSRoi Dayan
250ab3f3d5eSRoi Dayan if (is_vlan_dev(parse_attr->filter_dev)) {
251ab3f3d5eSRoi Dayan err = mlx5e_tc_act_vlan_add_pop_action(priv, attr, extack);
252ab3f3d5eSRoi Dayan if (err)
253ab3f3d5eSRoi Dayan return err;
254ab3f3d5eSRoi Dayan }
255ab3f3d5eSRoi Dayan
256ab3f3d5eSRoi Dayan err = verify_uplink_forwarding(priv, attr, out_dev, extack);
257ab3f3d5eSRoi Dayan if (err)
258ab3f3d5eSRoi Dayan return err;
259ab3f3d5eSRoi Dayan
260ab3f3d5eSRoi Dayan if (!mlx5e_is_valid_eswitch_fwd_dev(priv, out_dev)) {
261ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack,
262ab3f3d5eSRoi Dayan "devices are not on same switch HW, can't offload forwarding");
263ab3f3d5eSRoi Dayan return -EOPNOTSUPP;
264ab3f3d5eSRoi Dayan }
265ab3f3d5eSRoi Dayan
266ab3f3d5eSRoi Dayan if (same_vf_reps(priv, out_dev)) {
267ab3f3d5eSRoi Dayan NL_SET_ERR_MSG_MOD(extack, "can't forward from a VF to itself");
268ab3f3d5eSRoi Dayan return -EOPNOTSUPP;
269ab3f3d5eSRoi Dayan }
270ab3f3d5eSRoi Dayan
271ab3f3d5eSRoi Dayan out_priv = netdev_priv(out_dev);
272ab3f3d5eSRoi Dayan rpriv = out_priv->ppriv;
273*96c8c465SVlad Buslov esw_attr->dests[esw_attr->out_count].vport_valid = true;
274*96c8c465SVlad Buslov esw_attr->dests[esw_attr->out_count].vport = rpriv->rep->vport;
275ab3f3d5eSRoi Dayan esw_attr->dests[esw_attr->out_count].mdev = out_priv->mdev;
27694db3317SEli Cohen
277ab3f3d5eSRoi Dayan esw_attr->out_count++;
278ab3f3d5eSRoi Dayan
279ab3f3d5eSRoi Dayan return 0;
280ab3f3d5eSRoi Dayan }
281ab3f3d5eSRoi Dayan
282ab3f3d5eSRoi Dayan static int
parse_mirred_ovs_master(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)283ab3f3d5eSRoi Dayan parse_mirred_ovs_master(struct mlx5e_tc_act_parse_state *parse_state,
284ab3f3d5eSRoi Dayan const struct flow_action_entry *act,
285ab3f3d5eSRoi Dayan struct mlx5e_priv *priv,
286ab3f3d5eSRoi Dayan struct mlx5_flow_attr *attr)
287ab3f3d5eSRoi Dayan {
288ab3f3d5eSRoi Dayan struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
289ab3f3d5eSRoi Dayan struct net_device *out_dev = act->dev;
290ab3f3d5eSRoi Dayan int err;
291ab3f3d5eSRoi Dayan
292ab3f3d5eSRoi Dayan err = mlx5e_set_fwd_to_int_port_actions(priv, attr, out_dev->ifindex,
293ab3f3d5eSRoi Dayan MLX5E_TC_INT_PORT_EGRESS,
294ab3f3d5eSRoi Dayan &attr->action, esw_attr->out_count);
295ab3f3d5eSRoi Dayan if (err)
296ab3f3d5eSRoi Dayan return err;
297ab3f3d5eSRoi Dayan
298b7558a77SJianbo Liu parse_state->if_count = 0;
299ab3f3d5eSRoi Dayan esw_attr->out_count++;
300ab3f3d5eSRoi Dayan return 0;
301ab3f3d5eSRoi Dayan }
302ab3f3d5eSRoi Dayan
303ab3f3d5eSRoi Dayan static int
tc_act_parse_mirred(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)304ab3f3d5eSRoi Dayan tc_act_parse_mirred(struct mlx5e_tc_act_parse_state *parse_state,
305ab3f3d5eSRoi Dayan const struct flow_action_entry *act,
306ab3f3d5eSRoi Dayan struct mlx5e_priv *priv,
307ab3f3d5eSRoi Dayan struct mlx5_flow_attr *attr)
308ab3f3d5eSRoi Dayan {
309ab3f3d5eSRoi Dayan struct net_device *out_dev = act->dev;
310ab3f3d5eSRoi Dayan int err = -EOPNOTSUPP;
311ab3f3d5eSRoi Dayan
312ab3f3d5eSRoi Dayan if (parse_state->encap)
313ab3f3d5eSRoi Dayan err = parse_mirred_encap(parse_state, act, attr);
314ab3f3d5eSRoi Dayan else if (netdev_port_same_parent_id(priv->netdev, out_dev))
315ab3f3d5eSRoi Dayan err = parse_mirred(parse_state, act, priv, attr);
316ab3f3d5eSRoi Dayan else if (netif_is_ovs_master(out_dev))
317ab3f3d5eSRoi Dayan err = parse_mirred_ovs_master(parse_state, act, priv, attr);
318ab3f3d5eSRoi Dayan
319ab3f3d5eSRoi Dayan if (err)
320ab3f3d5eSRoi Dayan return err;
321ab3f3d5eSRoi Dayan
3222a829fe2SRoi Dayan attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
323ab3f3d5eSRoi Dayan
324ab3f3d5eSRoi Dayan return 0;
325ab3f3d5eSRoi Dayan }
326ab3f3d5eSRoi Dayan
327ab3f3d5eSRoi Dayan struct mlx5e_tc_act mlx5e_tc_act_mirred = {
328ab3f3d5eSRoi Dayan .can_offload = tc_act_can_offload_mirred,
329ab3f3d5eSRoi Dayan .parse_action = tc_act_parse_mirred,
330d3f6b0dfSOz Shlomo .is_terminating_action = false,
331d3f6b0dfSOz Shlomo };
332d3f6b0dfSOz Shlomo
333d3f6b0dfSOz Shlomo struct mlx5e_tc_act mlx5e_tc_act_redirect = {
334d3f6b0dfSOz Shlomo .can_offload = tc_act_can_offload_mirred,
335d3f6b0dfSOz Shlomo .parse_action = tc_act_parse_mirred,
336d3f6b0dfSOz Shlomo .is_terminating_action = true,
337ab3f3d5eSRoi Dayan };
338