FILE
vlan.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/vlan.c
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 9static int 10add_vlan_prio_tag_rewrite_action(struct mlx5e_priv *priv, 11 struct mlx5e_tc_flow_parse_attr *parse_attr, 12 u32 *action, struct netlink_ext_ack *extack) 13{ 14 const struct flow_action_entry prio_tag_act = { 15 .vlan.vid = 0, 16 .vlan.prio = 17 MLX5_GET(fte_match_set_lyr_2_4, 18 mlx5e_get_match_headers_value(*action, 19 &parse_attr->spec), 20 first_prio) & 21 MLX5_GET(fte_match_set_lyr_2_4, 22 mlx5e_get_match_headers_criteria(*action, 23 &parse_attr->spec), 24 first_prio), 25 }; 26 27 return mlx5e_tc_act_vlan_add_rewrite_action(priv, MLX5_FLOW_NAMESPACE_FDB, 28 &prio_tag_act, parse_attr, action, 29 extack); 30} 31 32static int 33parse_tc_vlan_action(struct mlx5e_priv *priv, 34 const struct flow_action_entry *act, 35 struct mlx5_esw_flow_attr *attr, 36 u32 *action, 37 struct netlink_ext_ack *extack, 38 struct mlx5e_tc_act_parse_state *parse_state) 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 if (!mlx5_eswitch_vlan_actions_supported(priv->mdev, vlan_idx)) { 48 NL_SET_ERR_MSG_MOD(extack, "firmware vlan actions is not supported"); 49 return -EOPNOTSUPP; 50 } 51 52 switch (act->id) { 53 case FLOW_ACTION_VLAN_POP: 54 if (vlan_idx) 55 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2; 56 else 57 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 58 break; 59 case FLOW_ACTION_VLAN_PUSH: 60 attr->vlan_vid[vlan_idx] = act->vlan.vid; 61 attr->vlan_prio[vlan_idx] = act->vlan.prio; 62 attr->vlan_proto[vlan_idx] = act->vlan.proto; 63 if (!attr->vlan_proto[vlan_idx]) 64 attr->vlan_proto[vlan_idx] = htons(ETH_P_8021Q); 65 66 if (vlan_idx) 67 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2; 68 else 69 *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; 70 break; 71 case FLOW_ACTION_VLAN_POP_ETH: 72 parse_state->eth_pop = true; 73 break; 74 case FLOW_ACTION_VLAN_PUSH_ETH: 75 if (!flow_flag_test(parse_state->flow, L3_TO_L2_DECAP)) 76 return -EOPNOTSUPP; 77 parse_state->eth_push = true; 78 memcpy(attr->eth.h_dest, act->vlan_push_eth.dst, ETH_ALEN); 79 memcpy(attr->eth.h_source, act->vlan_push_eth.src, ETH_ALEN); 80 break; 81 default: 82 NL_SET_ERR_MSG_MOD(extack, "Unexpected action id for VLAN"); 83 return -EINVAL; 84 } 85 86 attr->total_vlan = vlan_idx + 1; 87 88 return 0; 89} 90 91int 92mlx5e_tc_act_vlan_add_push_action(struct mlx5e_priv *priv, 93 struct mlx5_flow_attr *attr, 94 struct net_device **out_dev, 95 struct netlink_ext_ack *extack) 96{ 97 do { 98 struct net_device *vlan_dev = *out_dev; 99 struct flow_action_entry vlan_act = { 100 .id = FLOW_ACTION_VLAN_PUSH, 101 .vlan.vid = vlan_dev_vlan_id(vlan_dev), 102 .vlan.proto = vlan_dev_vlan_proto(vlan_dev), 103 .vlan.prio = 0, 104 }; 105 int err; 106 107 err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, 108 &attr->action, extack, NULL); 109 if (err) 110 return err; 111 112 rcu_read_lock(); 113 *out_dev = dev_get_by_index_rcu(dev_net(vlan_dev), 114 dev_get_iflink(vlan_dev)); 115 rcu_read_unlock(); 116 if (!*out_dev) 117 return -ENODEV; 118 } while (is_vlan_dev(*out_dev)); 119 120 return 0; 121} 122 123int 124mlx5e_tc_act_vlan_add_pop_action(struct mlx5e_priv *priv, 125 struct mlx5_flow_attr *attr, 126 struct netlink_ext_ack *extack) 127{ 128 struct flow_action_entry vlan_act = { 129 .id = FLOW_ACTION_VLAN_POP, 130 }; 131 int nest_level, err = 0; 132 133 nest_level = attr->parse_attr->filter_dev->lower_level - 134 priv->netdev->lower_level; 135 while (nest_level--) { 136 err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action, 137 extack, NULL); 138 if (err) 139 return err; 140 } 141 142 return err; 143} 144 145static int 146tc_act_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state, 147 const struct flow_action_entry *act, 148 struct mlx5e_priv *priv, 149 struct mlx5_flow_attr *attr) 150{ 151 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr; 152 int err; 153 154 if (act->id == FLOW_ACTION_VLAN_PUSH && 155 (attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP)) { 156 /* Replace vlan pop+push with vlan modify */ 157 attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 158 err = mlx5e_tc_act_vlan_add_rewrite_action(priv, MLX5_FLOW_NAMESPACE_FDB, act, 159 attr->parse_attr, &attr->action, 160 parse_state->extack); 161 } else { 162 err = parse_tc_vlan_action(priv, act, esw_attr, &attr->action, 163 parse_state->extack, parse_state); 164 } 165 166 if (err) 167 return err; 168 169 esw_attr->split_count = esw_attr->out_count; 170 parse_state->if_count = 0; 171 172 return 0; 173} 174 175static int 176tc_act_post_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state, 177 struct mlx5e_priv *priv, 178 struct mlx5_flow_attr *attr) 179{ 180 struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr; 181 struct netlink_ext_ack *extack = parse_state->extack; 182 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 183 int err; 184 185 if (MLX5_CAP_GEN(esw->dev, prio_tag_required) && 186 attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) { 187 /* For prio tag mode, replace vlan pop with rewrite vlan prio 188 * tag rewrite. 189 */ 190 attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 191 err = add_vlan_prio_tag_rewrite_action(priv, parse_attr, 192 &attr->action, extack); 193 if (err) 194 return err; 195 } 196 197 return 0; 198} 199 200struct mlx5e_tc_act mlx5e_tc_act_vlan = { 201 .parse_action = tc_act_parse_vlan, 202 .post_parse = tc_act_post_parse_vlan, 203};
~/
Read-only file preview.