1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 4 #include <linux/if_vlan.h> 5 #include "act.h" 6 #include "vlan.h" 7 #include "en/tc_priv.h" 8 9 static int 10 add_vlan_prio_tag_rewrite_action(struct mlx5e_priv *priv, 11 struct mlx5e_tc_flow_parse_attr *parse_attr, 12 struct pedit_headers_action *hdrs, 13 u32 *action, struct netlink_ext_ack *extack) 14 { 15 const struct flow_action_entry prio_tag_act = { 16 .vlan.vid = 0, 17 .vlan.prio = 18 MLX5_GET(fte_match_set_lyr_2_4, 19 mlx5e_get_match_headers_value(*action, 20 &parse_attr->spec), 21 first_prio) & 22 MLX5_GET(fte_match_set_lyr_2_4, 23 mlx5e_get_match_headers_criteria(*action, 24 &parse_attr->spec), 25 first_prio), 26 }; 27 28 return mlx5e_tc_act_vlan_add_rewrite_action(priv, MLX5_FLOW_NAMESPACE_FDB, 29 &prio_tag_act, parse_attr, hdrs, action, 30 extack); 31 } 32 33 static int 34 parse_tc_vlan_action(struct mlx5e_priv *priv, 35 const struct flow_action_entry *act, 36 struct mlx5_esw_flow_attr *attr, 37 u32 *action, 38 struct netlink_ext_ack *extack) 39 { 40 u8 vlan_idx = attr->total_vlan; 41 42 if (vlan_idx >= MLX5_FS_VLAN_DEPTH) { 43 NL_SET_ERR_MSG_MOD(extack, "Total vlans used is greater than supported"); 44 return -EOPNOTSUPP; 45 } 46 47 switch (act->id) { 48 case FLOW_ACTION_VLAN_POP: 49 if (vlan_idx) { 50 if (!mlx5_eswitch_vlan_actions_supported(priv->mdev, 51 MLX5_FS_VLAN_DEPTH)) { 52 NL_SET_ERR_MSG_MOD(extack, "vlan pop action is not supported"); 53 return -EOPNOTSUPP; 54 } 55 56 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2; 57 } else { 58 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 59 } 60 break; 61 case FLOW_ACTION_VLAN_PUSH: 62 attr->vlan_vid[vlan_idx] = act->vlan.vid; 63 attr->vlan_prio[vlan_idx] = act->vlan.prio; 64 attr->vlan_proto[vlan_idx] = act->vlan.proto; 65 if (!attr->vlan_proto[vlan_idx]) 66 attr->vlan_proto[vlan_idx] = htons(ETH_P_8021Q); 67 68 if (vlan_idx) { 69 if (!mlx5_eswitch_vlan_actions_supported(priv->mdev, 70 MLX5_FS_VLAN_DEPTH)) { 71 NL_SET_ERR_MSG_MOD(extack, 72 "vlan push action is not supported for vlan depth > 1"); 73 return -EOPNOTSUPP; 74 } 75 76 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2; 77 } else { 78 if (!mlx5_eswitch_vlan_actions_supported(priv->mdev, 1) && 79 (act->vlan.proto != htons(ETH_P_8021Q) || 80 act->vlan.prio)) { 81 NL_SET_ERR_MSG_MOD(extack, "vlan push action is not supported"); 82 return -EOPNOTSUPP; 83 } 84 85 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; 86 } 87 break; 88 default: 89 NL_SET_ERR_MSG_MOD(extack, "Unexpected action id for VLAN"); 90 return -EINVAL; 91 } 92 93 attr->total_vlan = vlan_idx + 1; 94 95 return 0; 96 } 97 98 int 99 mlx5e_tc_act_vlan_add_push_action(struct mlx5e_priv *priv, 100 struct mlx5_flow_attr *attr, 101 struct net_device **out_dev, 102 struct netlink_ext_ack *extack) 103 { 104 struct net_device *vlan_dev = *out_dev; 105 struct flow_action_entry vlan_act = { 106 .id = FLOW_ACTION_VLAN_PUSH, 107 .vlan.vid = vlan_dev_vlan_id(vlan_dev), 108 .vlan.proto = vlan_dev_vlan_proto(vlan_dev), 109 .vlan.prio = 0, 110 }; 111 int err; 112 113 err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action, extack); 114 if (err) 115 return err; 116 117 rcu_read_lock(); 118 *out_dev = dev_get_by_index_rcu(dev_net(vlan_dev), dev_get_iflink(vlan_dev)); 119 rcu_read_unlock(); 120 if (!*out_dev) 121 return -ENODEV; 122 123 if (is_vlan_dev(*out_dev)) 124 err = mlx5e_tc_act_vlan_add_push_action(priv, attr, out_dev, extack); 125 126 return err; 127 } 128 129 int 130 mlx5e_tc_act_vlan_add_pop_action(struct mlx5e_priv *priv, 131 struct mlx5_flow_attr *attr, 132 struct netlink_ext_ack *extack) 133 { 134 struct flow_action_entry vlan_act = { 135 .id = FLOW_ACTION_VLAN_POP, 136 }; 137 int nest_level, err = 0; 138 139 nest_level = attr->parse_attr->filter_dev->lower_level - 140 priv->netdev->lower_level; 141 while (nest_level--) { 142 err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action, 143 extack); 144 if (err) 145 return err; 146 } 147 148 return err; 149 } 150 151 static bool 152 tc_act_can_offload_vlan(struct mlx5e_tc_act_parse_state *parse_state, 153 const struct flow_action_entry *act, 154 int act_index) 155 { 156 return true; 157 } 158 159 static int 160 tc_act_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state, 161 const struct flow_action_entry *act, 162 struct mlx5e_priv *priv, 163 struct mlx5_flow_attr *attr) 164 { 165 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr; 166 int err; 167 168 if (act->id == FLOW_ACTION_VLAN_PUSH && 169 (attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP)) { 170 /* Replace vlan pop+push with vlan modify */ 171 attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 172 err = mlx5e_tc_act_vlan_add_rewrite_action(priv, MLX5_FLOW_NAMESPACE_FDB, act, 173 attr->parse_attr, parse_state->hdrs, 174 &attr->action, parse_state->extack); 175 } else { 176 err = parse_tc_vlan_action(priv, act, esw_attr, &attr->action, 177 parse_state->extack); 178 } 179 180 if (err) 181 return err; 182 183 esw_attr->split_count = esw_attr->out_count; 184 185 return 0; 186 } 187 188 static int 189 tc_act_post_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state, 190 struct mlx5e_priv *priv, 191 struct mlx5_flow_attr *attr) 192 { 193 struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr; 194 struct pedit_headers_action *hdrs = parse_state->hdrs; 195 struct netlink_ext_ack *extack = parse_state->extack; 196 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 197 int err; 198 199 if (MLX5_CAP_GEN(esw->dev, prio_tag_required) && 200 attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) { 201 /* For prio tag mode, replace vlan pop with rewrite vlan prio 202 * tag rewrite. 203 */ 204 attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 205 err = add_vlan_prio_tag_rewrite_action(priv, parse_attr, hdrs, 206 &attr->action, extack); 207 if (err) 208 return err; 209 } 210 211 return 0; 212 } 213 214 struct mlx5e_tc_act mlx5e_tc_act_vlan = { 215 .can_offload = tc_act_can_offload_vlan, 216 .parse_action = tc_act_parse_vlan, 217 .post_parse = tc_act_post_parse_vlan, 218 }; 219