Skip to content

Commit 3643abd

Browse files
HoratiuVulturPaolo Abeni
authored andcommitted
net: lan966x: add tc flower support for VCAP API
Currently the only supported action is ACTION_TRAP and the only dissector is ETH_ADDRS. Others will be added in future patches. Signed-off-by: Horatiu Vultur <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent f919ccc commit 3643abd

File tree

5 files changed

+421
-1
lines changed

5 files changed

+421
-1
lines changed

drivers/net/ethernet/microchip/lan966x/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
1212
lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \
1313
lan966x_tbf.o lan966x_cbs.o lan966x_ets.o \
1414
lan966x_tc_matchall.o lan966x_police.o lan966x_mirror.o \
15-
lan966x_xdp.o lan966x_vcap_impl.o lan966x_vcap_ag_api.o
15+
lan966x_xdp.o lan966x_vcap_impl.o lan966x_vcap_ag_api.o \
16+
lan966x_tc_flower.o
1617

1718
# Provide include files
1819
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap

drivers/net/ethernet/microchip/lan966x/lan966x_main.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,9 @@ static inline bool lan966x_xdp_port_present(struct lan966x_port *port)
588588
int lan966x_vcap_init(struct lan966x *lan966x);
589589
void lan966x_vcap_deinit(struct lan966x *lan966x);
590590

591+
int lan966x_tc_flower(struct lan966x_port *port,
592+
struct flow_cls_offload *f);
593+
591594
static inline void __iomem *lan_addr(void __iomem *base[],
592595
int id, int tinst, int tcnt,
593596
int gbase, int ginst,

drivers/net/ethernet/microchip/lan966x/lan966x_tc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ static int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data,
6969
switch (type) {
7070
case TC_SETUP_CLSMATCHALL:
7171
return lan966x_tc_matchall(port, type_data, ingress);
72+
case TC_SETUP_CLSFLOWER:
73+
return lan966x_tc_flower(port, type_data);
7274
default:
7375
return -EOPNOTSUPP;
7476
}
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
3+
#include "lan966x_main.h"
4+
#include "vcap_api.h"
5+
#include "vcap_api_client.h"
6+
7+
/* Controls how PORT_MASK is applied */
8+
enum LAN966X_PORT_MASK_MODE {
9+
LAN966X_PMM_NO_ACTION,
10+
LAN966X_PMM_REPLACE,
11+
LAN966X_PMM_FORWARDING,
12+
LAN966X_PMM_REDIRECT,
13+
};
14+
15+
struct lan966x_tc_flower_parse_usage {
16+
struct flow_cls_offload *f;
17+
struct flow_rule *frule;
18+
struct vcap_rule *vrule;
19+
unsigned int used_keys;
20+
u16 l3_proto;
21+
};
22+
23+
static int lan966x_tc_flower_handler_ethaddr_usage(struct lan966x_tc_flower_parse_usage *st)
24+
{
25+
enum vcap_key_field smac_key = VCAP_KF_L2_SMAC;
26+
enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC;
27+
struct flow_match_eth_addrs match;
28+
struct vcap_u48_key smac, dmac;
29+
int err = 0;
30+
31+
flow_rule_match_eth_addrs(st->frule, &match);
32+
33+
if (!is_zero_ether_addr(match.mask->src)) {
34+
vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN);
35+
vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN);
36+
err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac);
37+
if (err)
38+
goto out;
39+
}
40+
41+
if (!is_zero_ether_addr(match.mask->dst)) {
42+
vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN);
43+
vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN);
44+
err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac);
45+
if (err)
46+
goto out;
47+
}
48+
49+
st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
50+
51+
return err;
52+
53+
out:
54+
NL_SET_ERR_MSG_MOD(st->f->common.extack, "eth_addr parse error");
55+
return err;
56+
}
57+
58+
static int
59+
(*lan966x_tc_flower_handlers_usage[])(struct lan966x_tc_flower_parse_usage *st) = {
60+
[FLOW_DISSECTOR_KEY_ETH_ADDRS] = lan966x_tc_flower_handler_ethaddr_usage,
61+
};
62+
63+
static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f,
64+
struct vcap_admin *admin,
65+
struct vcap_rule *vrule,
66+
u16 *l3_proto)
67+
{
68+
struct lan966x_tc_flower_parse_usage state = {
69+
.f = f,
70+
.vrule = vrule,
71+
.l3_proto = ETH_P_ALL,
72+
};
73+
int err = 0;
74+
75+
state.frule = flow_cls_offload_flow_rule(f);
76+
for (int i = 0; i < ARRAY_SIZE(lan966x_tc_flower_handlers_usage); ++i) {
77+
if (!flow_rule_match_key(state.frule, i) ||
78+
!lan966x_tc_flower_handlers_usage[i])
79+
continue;
80+
81+
err = lan966x_tc_flower_handlers_usage[i](&state);
82+
if (err)
83+
return err;
84+
}
85+
86+
if (l3_proto)
87+
*l3_proto = state.l3_proto;
88+
89+
return err;
90+
}
91+
92+
static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
93+
struct flow_cls_offload *fco,
94+
struct vcap_admin *admin)
95+
{
96+
struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
97+
struct flow_action_entry *actent, *last_actent = NULL;
98+
struct flow_action *act = &rule->action;
99+
u64 action_mask = 0;
100+
int idx;
101+
102+
if (!flow_action_has_entries(act)) {
103+
NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
104+
return -EINVAL;
105+
}
106+
107+
if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
108+
return -EOPNOTSUPP;
109+
110+
flow_action_for_each(idx, actent, act) {
111+
if (action_mask & BIT(actent->id)) {
112+
NL_SET_ERR_MSG_MOD(fco->common.extack,
113+
"More actions of the same type");
114+
return -EINVAL;
115+
}
116+
action_mask |= BIT(actent->id);
117+
last_actent = actent; /* Save last action for later check */
118+
}
119+
120+
/* Check that last action is a goto */
121+
if (last_actent->id != FLOW_ACTION_GOTO) {
122+
NL_SET_ERR_MSG_MOD(fco->common.extack,
123+
"Last action must be 'goto'");
124+
return -EINVAL;
125+
}
126+
127+
/* Check if the goto chain is in the next lookup */
128+
if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
129+
last_actent->chain_index)) {
130+
NL_SET_ERR_MSG_MOD(fco->common.extack,
131+
"Invalid goto chain");
132+
return -EINVAL;
133+
}
134+
135+
/* Catch unsupported combinations of actions */
136+
if (action_mask & BIT(FLOW_ACTION_TRAP) &&
137+
action_mask & BIT(FLOW_ACTION_ACCEPT)) {
138+
NL_SET_ERR_MSG_MOD(fco->common.extack,
139+
"Cannot combine pass and trap action");
140+
return -EOPNOTSUPP;
141+
}
142+
143+
return 0;
144+
}
145+
146+
static int lan966x_tc_flower_add(struct lan966x_port *port,
147+
struct flow_cls_offload *f,
148+
struct vcap_admin *admin)
149+
{
150+
struct flow_action_entry *act;
151+
u16 l3_proto = ETH_P_ALL;
152+
struct flow_rule *frule;
153+
struct vcap_rule *vrule;
154+
int err, idx;
155+
156+
err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, f,
157+
admin);
158+
if (err)
159+
return err;
160+
161+
vrule = vcap_alloc_rule(port->lan966x->vcap_ctrl, port->dev,
162+
f->common.chain_index, VCAP_USER_TC,
163+
f->common.prio, 0);
164+
if (IS_ERR(vrule))
165+
return PTR_ERR(vrule);
166+
167+
vrule->cookie = f->cookie;
168+
err = lan966x_tc_flower_use_dissectors(f, admin, vrule, &l3_proto);
169+
if (err)
170+
goto out;
171+
172+
frule = flow_cls_offload_flow_rule(f);
173+
174+
flow_action_for_each(idx, act, &frule->action) {
175+
switch (act->id) {
176+
case FLOW_ACTION_TRAP:
177+
err = vcap_rule_add_action_bit(vrule,
178+
VCAP_AF_CPU_COPY_ENA,
179+
VCAP_BIT_1);
180+
err |= vcap_rule_add_action_u32(vrule,
181+
VCAP_AF_CPU_QUEUE_NUM,
182+
0);
183+
err |= vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
184+
LAN966X_PMM_REPLACE);
185+
err |= vcap_set_rule_set_actionset(vrule,
186+
VCAP_AFS_BASE_TYPE);
187+
if (err)
188+
goto out;
189+
190+
break;
191+
case FLOW_ACTION_GOTO:
192+
break;
193+
default:
194+
NL_SET_ERR_MSG_MOD(f->common.extack,
195+
"Unsupported TC action");
196+
err = -EOPNOTSUPP;
197+
goto out;
198+
}
199+
}
200+
201+
err = vcap_val_rule(vrule, l3_proto);
202+
if (err) {
203+
vcap_set_tc_exterr(f, vrule);
204+
goto out;
205+
}
206+
207+
err = vcap_add_rule(vrule);
208+
if (err)
209+
NL_SET_ERR_MSG_MOD(f->common.extack,
210+
"Could not add the filter");
211+
out:
212+
vcap_free_rule(vrule);
213+
return err;
214+
}
215+
216+
static int lan966x_tc_flower_del(struct lan966x_port *port,
217+
struct flow_cls_offload *f,
218+
struct vcap_admin *admin)
219+
{
220+
struct vcap_control *vctrl;
221+
int err = -ENOENT, rule_id;
222+
223+
vctrl = port->lan966x->vcap_ctrl;
224+
while (true) {
225+
rule_id = vcap_lookup_rule_by_cookie(vctrl, f->cookie);
226+
if (rule_id <= 0)
227+
break;
228+
229+
err = vcap_del_rule(vctrl, port->dev, rule_id);
230+
if (err) {
231+
NL_SET_ERR_MSG_MOD(f->common.extack,
232+
"Cannot delete rule");
233+
break;
234+
}
235+
}
236+
237+
return err;
238+
}
239+
240+
int lan966x_tc_flower(struct lan966x_port *port,
241+
struct flow_cls_offload *f)
242+
{
243+
struct vcap_admin *admin;
244+
245+
admin = vcap_find_admin(port->lan966x->vcap_ctrl,
246+
f->common.chain_index);
247+
if (!admin) {
248+
NL_SET_ERR_MSG_MOD(f->common.extack, "Invalid chain");
249+
return -EINVAL;
250+
}
251+
252+
switch (f->command) {
253+
case FLOW_CLS_REPLACE:
254+
return lan966x_tc_flower_add(port, f, admin);
255+
case FLOW_CLS_DESTROY:
256+
return lan966x_tc_flower_del(port, f, admin);
257+
default:
258+
return -EOPNOTSUPP;
259+
}
260+
261+
return 0;
262+
}

0 commit comments

Comments
 (0)