blob: 9a8a1a6bd99e5eb6028a890887f24bd8cb9b3fa4 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <linux/if_vlan.h>
#include "act.h"
#include "vlan.h"
#include "en/tc_priv.h"
struct pedit_headers_action;
int
mlx5e_tc_act_vlan_add_rewrite_action(struct mlx5e_priv *priv, int namespace,
const struct flow_action_entry *act,
struct mlx5e_tc_flow_parse_attr *parse_attr,
u32 *action, struct netlink_ext_ack *extack)
{
u16 mask16 = VLAN_VID_MASK;
u16 val16 = act->vlan.vid & VLAN_VID_MASK;
const struct flow_action_entry pedit_act = {
.id = FLOW_ACTION_MANGLE,
.mangle.htype = FLOW_ACT_MANGLE_HDR_TYPE_ETH,
.mangle.offset = offsetof(struct vlan_ethhdr, h_vlan_TCI),
.mangle.mask = ~(u32)be16_to_cpu(*(__be16 *)&mask16),
.mangle.val = (u32)be16_to_cpu(*(__be16 *)&val16),
};
u8 match_prio_mask, match_prio_val;
void *headers_c, *headers_v;
int err;
headers_c = mlx5e_get_match_headers_criteria(*action, &parse_attr->spec);
headers_v = mlx5e_get_match_headers_value(*action, &parse_attr->spec);
if (!(MLX5_GET(fte_match_set_lyr_2_4, headers_c, cvlan_tag) &&
MLX5_GET(fte_match_set_lyr_2_4, headers_v, cvlan_tag))) {
NL_SET_ERR_MSG_MOD(extack, "VLAN rewrite action must have VLAN protocol match");
return -EOPNOTSUPP;
}
match_prio_mask = MLX5_GET(fte_match_set_lyr_2_4, headers_c, first_prio);
match_prio_val = MLX5_GET(fte_match_set_lyr_2_4, headers_v, first_prio);
if (act->vlan.prio != (match_prio_val & match_prio_mask)) {
NL_SET_ERR_MSG_MOD(extack, "Changing VLAN prio is not supported");
return -EOPNOTSUPP;
}
err = mlx5e_tc_act_pedit_parse_action(priv, &pedit_act, namespace, parse_attr->hdrs,
extack);
*action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
return err;
}
static bool
tc_act_can_offload_vlan_mangle(struct mlx5e_tc_act_parse_state *parse_state,
const struct flow_action_entry *act,
int act_index,
struct mlx5_flow_attr *attr)
{
return true;
}
static int
tc_act_parse_vlan_mangle(struct mlx5e_tc_act_parse_state *parse_state,
const struct flow_action_entry *act,
struct mlx5e_priv *priv,
struct mlx5_flow_attr *attr)
{
enum mlx5_flow_namespace_type ns_type;
int err;
ns_type = mlx5e_get_flow_namespace(parse_state->flow);
err = mlx5e_tc_act_vlan_add_rewrite_action(priv, ns_type, act, attr->parse_attr,
&attr->action, parse_state->extack);
if (err)
return err;
if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
attr->esw_attr->split_count = attr->esw_attr->out_count;
return 0;
}
struct mlx5e_tc_act mlx5e_tc_act_vlan_mangle = {
.can_offload = tc_act_can_offload_vlan_mangle,
.parse_action = tc_act_parse_vlan_mangle,
};