1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/* Copyright (c) 2020 Mellanox Technologies Inc. All rights reserved. */
3
4#include "mlx5_core.h"
5#include "eswitch.h"
6#include "helper.h"
7
8struct mlx5_flow_table *
9esw_acl_table_create(struct mlx5_eswitch *esw, struct mlx5_vport *vport, int ns, int size)
10{
11 struct mlx5_flow_table_attr ft_attr = {};
12 struct mlx5_core_dev *dev = esw->dev;
13 struct mlx5_flow_namespace *root_ns;
14 struct mlx5_flow_table *acl;
15 int acl_supported;
16 u16 vport_num;
17 int err;
18
19 acl_supported = (ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS) ?
20 MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support) :
21 MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support);
22
23 if (!acl_supported)
24 return ERR_PTR(error: -EOPNOTSUPP);
25
26 vport_num = vport->vport;
27 esw_debug(dev, "Create vport[%d] %s ACL table\n", vport_num,
28 ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS ? "ingress" : "egress");
29
30 root_ns = mlx5_get_flow_vport_namespace(dev, type: ns, vport_idx: vport->index);
31 if (!root_ns) {
32 esw_warn(dev, "Failed to get E-Switch root namespace for vport (%d)\n",
33 vport_num);
34 return ERR_PTR(error: -EOPNOTSUPP);
35 }
36
37 ft_attr.max_fte = size;
38 if (vport_num || mlx5_core_is_ecpf(dev: esw->dev))
39 ft_attr.flags = MLX5_FLOW_TABLE_OTHER_VPORT;
40 acl = mlx5_create_vport_flow_table(ns: root_ns, ft_attr: &ft_attr, vport: vport_num);
41 if (IS_ERR(ptr: acl)) {
42 err = PTR_ERR(ptr: acl);
43 esw_warn(dev, "vport[%d] create %s ACL table, err(%d)\n", vport_num,
44 ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS ? "ingress" : "egress", err);
45 }
46 return acl;
47}
48
49int esw_egress_acl_vlan_create(struct mlx5_eswitch *esw,
50 struct mlx5_vport *vport,
51 struct mlx5_flow_destination *fwd_dest,
52 u16 vlan_id, u32 flow_action)
53{
54 struct mlx5_flow_act flow_act = {};
55 struct mlx5_flow_spec *spec;
56 int err = 0;
57
58 if (vport->egress.allowed_vlan)
59 return -EEXIST;
60
61 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
62 if (!spec)
63 return -ENOMEM;
64
65 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
66 MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
67 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
68 MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id);
69
70 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
71 flow_act.action = flow_action;
72 vport->egress.allowed_vlan =
73 mlx5_add_flow_rules(ft: vport->egress.acl, spec,
74 flow_act: &flow_act, dest: fwd_dest, num_dest: 0);
75 if (IS_ERR(ptr: vport->egress.allowed_vlan)) {
76 err = PTR_ERR(ptr: vport->egress.allowed_vlan);
77 esw_warn(esw->dev,
78 "vport[%d] configure egress vlan rule failed, err(%d)\n",
79 vport->vport, err);
80 vport->egress.allowed_vlan = NULL;
81 }
82
83 kvfree(addr: spec);
84 return err;
85}
86
87void esw_acl_egress_vlan_destroy(struct mlx5_vport *vport)
88{
89 if (!IS_ERR_OR_NULL(ptr: vport->egress.allowed_vlan)) {
90 mlx5_del_flow_rules(fr: vport->egress.allowed_vlan);
91 vport->egress.allowed_vlan = NULL;
92 }
93}
94
95int esw_acl_egress_vlan_grp_create(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
96{
97 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
98 struct mlx5_flow_group *vlan_grp;
99 void *match_criteria;
100 u32 *flow_group_in;
101 int ret = 0;
102
103 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
104 if (!flow_group_in)
105 return -ENOMEM;
106
107 MLX5_SET(create_flow_group_in, flow_group_in,
108 match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
109 match_criteria = MLX5_ADDR_OF(create_flow_group_in,
110 flow_group_in, match_criteria);
111 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
112 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid);
113 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
114 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
115
116 vlan_grp = mlx5_create_flow_group(ft: vport->egress.acl, in: flow_group_in);
117 if (IS_ERR(ptr: vlan_grp)) {
118 ret = PTR_ERR(ptr: vlan_grp);
119 esw_warn(esw->dev,
120 "Failed to create E-Switch vport[%d] egress pop vlans flow group, err(%d)\n",
121 vport->vport, ret);
122 goto out;
123 }
124 vport->egress.vlan_grp = vlan_grp;
125
126out:
127 kvfree(addr: flow_group_in);
128 return ret;
129}
130
131void esw_acl_egress_vlan_grp_destroy(struct mlx5_vport *vport)
132{
133 if (!IS_ERR_OR_NULL(ptr: vport->egress.vlan_grp)) {
134 mlx5_destroy_flow_group(fg: vport->egress.vlan_grp);
135 vport->egress.vlan_grp = NULL;
136 }
137}
138
139void esw_acl_egress_table_destroy(struct mlx5_vport *vport)
140{
141 if (IS_ERR_OR_NULL(ptr: vport->egress.acl))
142 return;
143
144 mlx5_destroy_flow_table(ft: vport->egress.acl);
145 vport->egress.acl = NULL;
146}
147
148void esw_acl_ingress_table_destroy(struct mlx5_vport *vport)
149{
150 if (!vport->ingress.acl)
151 return;
152
153 mlx5_destroy_flow_table(ft: vport->ingress.acl);
154 vport->ingress.acl = NULL;
155}
156
157void esw_acl_ingress_allow_rule_destroy(struct mlx5_vport *vport)
158{
159 if (!vport->ingress.allow_rule)
160 return;
161
162 mlx5_del_flow_rules(fr: vport->ingress.allow_rule);
163 vport->ingress.allow_rule = NULL;
164}
165

source code of linux/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c