1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4 #include <linux/if_macvlan.h>
5 #include <linux/if_vlan.h>
6 #include <net/bareudp.h>
7 #include <net/bonding.h>
10 #include "en/tc_tun_encap.h"
11 #include "en/tc_priv.h"
15 same_vf_reps(struct mlx5e_priv *priv, struct net_device *out_dev)
17 return mlx5e_eswitch_vf_rep(priv->netdev) &&
18 priv->netdev == out_dev;
22 verify_uplink_forwarding(struct mlx5e_priv *priv,
23 struct mlx5_flow_attr *attr,
24 struct net_device *out_dev,
25 struct netlink_ext_ack *extack)
27 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
28 struct mlx5e_rep_priv *rep_priv;
30 /* Forwarding non encapsulated traffic between
31 * uplink ports is allowed only if
32 * termination_table_raw_traffic cap is set.
34 * Input vport was stored attr->in_rep.
35 * In LAG case, *priv* is the private data of
36 * uplink which may be not the input vport.
38 rep_priv = mlx5e_rep_to_rep_priv(attr->esw_attr->in_rep);
40 if (!(mlx5e_eswitch_uplink_rep(rep_priv->netdev) &&
41 mlx5e_eswitch_uplink_rep(out_dev)))
44 if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev,
45 termination_table_raw_traffic)) {
46 NL_SET_ERR_MSG_MOD(extack,
47 "devices are both uplink, can't offload forwarding");
49 } else if (out_dev != rep_priv->netdev) {
50 NL_SET_ERR_MSG_MOD(extack,
51 "devices are not the same uplink, can't offload forwarding");
58 is_duplicated_output_device(struct net_device *dev,
59 struct net_device *out_dev,
60 int *ifindexes, int if_count,
61 struct netlink_ext_ack *extack)
65 for (i = 0; i < if_count; i++) {
66 if (ifindexes[i] == out_dev->ifindex) {
67 NL_SET_ERR_MSG_MOD(extack, "can't duplicate output to same device");
68 netdev_err(dev, "can't duplicate output to same device: %s\n",
77 static struct net_device *
78 get_fdb_out_dev(struct net_device *uplink_dev, struct net_device *out_dev)
80 struct net_device *fdb_out_dev = out_dev;
81 struct net_device *uplink_upper;
84 uplink_upper = netdev_master_upper_dev_get_rcu(uplink_dev);
85 if (uplink_upper && netif_is_lag_master(uplink_upper) &&
86 uplink_upper == out_dev) {
87 fdb_out_dev = uplink_dev;
88 } else if (netif_is_lag_master(out_dev)) {
89 fdb_out_dev = bond_option_active_slave_get_rcu(netdev_priv(out_dev));
91 (!mlx5e_eswitch_rep(fdb_out_dev) ||
92 !netdev_port_same_parent_id(fdb_out_dev, uplink_dev)))
100 tc_act_can_offload_mirred(struct mlx5e_tc_act_parse_state *parse_state,
101 const struct flow_action_entry *act,
103 struct mlx5_flow_attr *attr)
105 struct netlink_ext_ack *extack = parse_state->extack;
106 struct mlx5e_tc_flow *flow = parse_state->flow;
107 struct mlx5e_tc_flow_parse_attr *parse_attr;
108 struct net_device *out_dev = act->dev;
109 struct mlx5e_priv *priv = flow->priv;
110 struct mlx5_esw_flow_attr *esw_attr;
112 parse_attr = attr->parse_attr;
113 esw_attr = attr->esw_attr;
116 /* out_dev is NULL when filters with
117 * non-existing mirred device are replayed to
123 if (parse_state->mpls_push && !netif_is_bareudp(out_dev)) {
124 NL_SET_ERR_MSG_MOD(extack, "mpls is supported only through a bareudp device");
128 if (mlx5e_is_ft_flow(flow) && out_dev == priv->netdev) {
129 /* Ignore forward to self rules generated
130 * by adding both mlx5 devs to the flow table
131 * block on a normal nft offload setup.
136 if (esw_attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
137 NL_SET_ERR_MSG_MOD(extack,
138 "can't support more output ports, can't offload forwarding");
139 netdev_warn(priv->netdev,
140 "can't support more than %d output ports, can't offload forwarding\n",
141 esw_attr->out_count);
145 if (parse_state->encap ||
146 netdev_port_same_parent_id(priv->netdev, out_dev) ||
147 netif_is_ovs_master(out_dev))
150 if (parse_attr->filter_dev != priv->netdev) {
151 /* All mlx5 devices are called to configure
152 * high level device filters. Therefore, the
153 * *attempt* to install a filter on invalid
154 * eswitch should not trigger an explicit error
159 NL_SET_ERR_MSG_MOD(extack, "devices are not on same switch HW, can't offload forwarding");
165 parse_mirred_encap(struct mlx5e_tc_act_parse_state *parse_state,
166 const struct flow_action_entry *act,
167 struct mlx5_flow_attr *attr)
169 struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
170 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
171 struct net_device *out_dev = act->dev;
173 parse_attr->mirred_ifindex[esw_attr->out_count] = out_dev->ifindex;
174 parse_attr->tun_info[esw_attr->out_count] =
175 mlx5e_dup_tun_info(parse_state->tun_info);
177 if (!parse_attr->tun_info[esw_attr->out_count])
180 parse_state->encap = false;
181 esw_attr->dests[esw_attr->out_count].flags |= MLX5_ESW_DEST_ENCAP;
182 esw_attr->out_count++;
183 /* attr->dests[].rep is resolved when we handle encap */
189 parse_mirred(struct mlx5e_tc_act_parse_state *parse_state,
190 const struct flow_action_entry *act,
191 struct mlx5e_priv *priv,
192 struct mlx5_flow_attr *attr)
194 struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
195 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
196 struct netlink_ext_ack *extack = parse_state->extack;
197 struct mlx5e_rep_priv *rpriv = priv->ppriv;
198 struct net_device *out_dev = act->dev;
199 struct net_device *uplink_dev;
200 struct mlx5e_priv *out_priv;
201 struct mlx5_eswitch *esw;
206 esw = priv->mdev->priv.eswitch;
207 uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
208 ifindexes = parse_state->ifindexes;
209 if_count = parse_state->if_count;
211 if (is_duplicated_output_device(priv->netdev, out_dev, ifindexes, if_count, extack))
214 parse_state->ifindexes[if_count] = out_dev->ifindex;
215 parse_state->if_count++;
217 out_dev = get_fdb_out_dev(uplink_dev, out_dev);
221 if (is_vlan_dev(out_dev)) {
222 err = mlx5e_tc_act_vlan_add_push_action(priv, attr, &out_dev, extack);
227 if (is_vlan_dev(parse_attr->filter_dev)) {
228 err = mlx5e_tc_act_vlan_add_pop_action(priv, attr, extack);
233 if (netif_is_macvlan(out_dev))
234 out_dev = macvlan_dev_real_dev(out_dev);
236 err = verify_uplink_forwarding(priv, attr, out_dev, extack);
240 if (!mlx5e_is_valid_eswitch_fwd_dev(priv, out_dev)) {
241 NL_SET_ERR_MSG_MOD(extack,
242 "devices are not on same switch HW, can't offload forwarding");
246 if (same_vf_reps(priv, out_dev)) {
247 NL_SET_ERR_MSG_MOD(extack, "can't forward from a VF to itself");
251 out_priv = netdev_priv(out_dev);
252 rpriv = out_priv->ppriv;
253 esw_attr->dests[esw_attr->out_count].rep = rpriv->rep;
254 esw_attr->dests[esw_attr->out_count].mdev = out_priv->mdev;
255 esw_attr->out_count++;
261 parse_mirred_ovs_master(struct mlx5e_tc_act_parse_state *parse_state,
262 const struct flow_action_entry *act,
263 struct mlx5e_priv *priv,
264 struct mlx5_flow_attr *attr)
266 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
267 struct net_device *out_dev = act->dev;
270 err = mlx5e_set_fwd_to_int_port_actions(priv, attr, out_dev->ifindex,
271 MLX5E_TC_INT_PORT_EGRESS,
272 &attr->action, esw_attr->out_count);
276 esw_attr->out_count++;
281 tc_act_parse_mirred(struct mlx5e_tc_act_parse_state *parse_state,
282 const struct flow_action_entry *act,
283 struct mlx5e_priv *priv,
284 struct mlx5_flow_attr *attr)
286 struct net_device *out_dev = act->dev;
287 int err = -EOPNOTSUPP;
289 if (parse_state->encap)
290 err = parse_mirred_encap(parse_state, act, attr);
291 else if (netdev_port_same_parent_id(priv->netdev, out_dev))
292 err = parse_mirred(parse_state, act, priv, attr);
293 else if (netif_is_ovs_master(out_dev))
294 err = parse_mirred_ovs_master(parse_state, act, priv, attr);
299 attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
300 MLX5_FLOW_CONTEXT_ACTION_COUNT;
305 struct mlx5e_tc_act mlx5e_tc_act_mirred = {
306 .can_offload = tc_act_can_offload_mirred,
307 .parse_action = tc_act_parse_mirred,