Skip to content

Commit fa5d824

Browse files
Volodymyr Mytnykdavem330
authored andcommitted
net: prestera: acl: add multi-chain support offload
Add support of rule offloading added to the non-zero index chain, which was previously forbidden. Also, goto action is offloaded allowing to jump for processing of desired chain. Note that only implicit chain 0 is bound to the device port(s) for processing. The rest of chains have to be jumped by actions. Signed-off-by: Volodymyr Mytnyk <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e81f1e0 commit fa5d824

File tree

7 files changed

+203
-39
lines changed

7 files changed

+203
-39
lines changed

drivers/net/ethernet/marvell/prestera/prestera_acl.c

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct prestera_acl {
2222

2323
struct prestera_acl_ruleset_ht_key {
2424
struct prestera_flow_block *block;
25+
u32 chain_index;
2526
};
2627

2728
struct prestera_acl_rule_entry {
@@ -33,6 +34,10 @@ struct prestera_acl_rule_entry {
3334
struct {
3435
u8 valid:1;
3536
} accept, drop, trap;
37+
struct {
38+
struct prestera_acl_action_jump i;
39+
u8 valid:1;
40+
} jump;
3641
struct {
3742
u32 id;
3843
struct prestera_counter_block *block;
@@ -49,6 +54,7 @@ struct prestera_acl_ruleset {
4954
refcount_t refcount;
5055
void *keymask;
5156
u32 vtcam_id;
57+
u32 index;
5258
u16 pcl_id;
5359
bool offload;
5460
};
@@ -83,20 +89,45 @@ static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = {
8389
.automatic_shrinking = true,
8490
};
8591

92+
int prestera_acl_chain_to_client(u32 chain_index, u32 *client)
93+
{
94+
u32 client_map[] = {
95+
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0,
96+
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1,
97+
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2
98+
};
99+
100+
if (chain_index > ARRAY_SIZE(client_map))
101+
return -EINVAL;
102+
103+
*client = client_map[chain_index];
104+
return 0;
105+
}
106+
107+
static bool prestera_acl_chain_is_supported(u32 chain_index)
108+
{
109+
return (chain_index & ~PRESTERA_ACL_CHAIN_MASK) == 0;
110+
}
111+
86112
static struct prestera_acl_ruleset *
87113
prestera_acl_ruleset_create(struct prestera_acl *acl,
88-
struct prestera_flow_block *block)
114+
struct prestera_flow_block *block,
115+
u32 chain_index)
89116
{
90117
struct prestera_acl_ruleset *ruleset;
91118
u32 uid = 0;
92119
int err;
93120

121+
if (!prestera_acl_chain_is_supported(chain_index))
122+
return ERR_PTR(-EINVAL);
123+
94124
ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL);
95125
if (!ruleset)
96126
return ERR_PTR(-ENOMEM);
97127

98128
ruleset->acl = acl;
99129
ruleset->ht_key.block = block;
130+
ruleset->ht_key.chain_index = chain_index;
100131
refcount_set(&ruleset->refcount, 1);
101132

102133
err = rhashtable_init(&ruleset->rule_ht, &prestera_acl_rule_ht_params);
@@ -108,7 +139,9 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
108139
goto err_ruleset_create;
109140

110141
/* make pcl-id based on uid */
111-
ruleset->pcl_id = (u8)uid;
142+
ruleset->pcl_id = PRESTERA_ACL_PCL_ID_MAKE((u8)uid, chain_index);
143+
ruleset->index = uid;
144+
112145
err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node,
113146
prestera_acl_ruleset_ht_params);
114147
if (err)
@@ -133,59 +166,91 @@ void prestera_acl_ruleset_keymask_set(struct prestera_acl_ruleset *ruleset,
133166

134167
int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset)
135168
{
169+
struct prestera_acl_iface iface;
136170
u32 vtcam_id;
137171
int err;
138172

139173
if (ruleset->offload)
140174
return -EEXIST;
141175

142-
err = prestera_acl_vtcam_id_get(ruleset->acl, 0,
176+
err = prestera_acl_vtcam_id_get(ruleset->acl,
177+
ruleset->ht_key.chain_index,
143178
ruleset->keymask, &vtcam_id);
144179
if (err)
145-
return err;
180+
goto err_vtcam_create;
181+
182+
if (ruleset->ht_key.chain_index) {
183+
/* for chain > 0, bind iface index to pcl-id to be able
184+
* to jump from any other ruleset to this one using the index.
185+
*/
186+
iface.index = ruleset->index;
187+
iface.type = PRESTERA_ACL_IFACE_TYPE_INDEX;
188+
err = prestera_hw_vtcam_iface_bind(ruleset->acl->sw, &iface,
189+
vtcam_id, ruleset->pcl_id);
190+
if (err)
191+
goto err_ruleset_bind;
192+
}
146193

147194
ruleset->vtcam_id = vtcam_id;
148195
ruleset->offload = true;
149196
return 0;
197+
198+
err_ruleset_bind:
199+
prestera_acl_vtcam_id_put(ruleset->acl, ruleset->vtcam_id);
200+
err_vtcam_create:
201+
return err;
150202
}
151203

152204
static void prestera_acl_ruleset_destroy(struct prestera_acl_ruleset *ruleset)
153205
{
154206
struct prestera_acl *acl = ruleset->acl;
155207
u8 uid = ruleset->pcl_id & PRESTERA_ACL_KEYMASK_PCL_ID_USER;
208+
int err;
156209

157210
rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node,
158211
prestera_acl_ruleset_ht_params);
159212

160-
if (ruleset->offload)
213+
if (ruleset->offload) {
214+
if (ruleset->ht_key.chain_index) {
215+
struct prestera_acl_iface iface = {
216+
.type = PRESTERA_ACL_IFACE_TYPE_INDEX,
217+
.index = ruleset->index
218+
};
219+
err = prestera_hw_vtcam_iface_unbind(acl->sw, &iface,
220+
ruleset->vtcam_id);
221+
WARN_ON(err);
222+
}
161223
WARN_ON(prestera_acl_vtcam_id_put(acl, ruleset->vtcam_id));
224+
}
162225

163226
idr_remove(&acl->uid, uid);
164-
165227
rhashtable_destroy(&ruleset->rule_ht);
166228
kfree(ruleset->keymask);
167229
kfree(ruleset);
168230
}
169231

170232
static struct prestera_acl_ruleset *
171233
__prestera_acl_ruleset_lookup(struct prestera_acl *acl,
172-
struct prestera_flow_block *block)
234+
struct prestera_flow_block *block,
235+
u32 chain_index)
173236
{
174237
struct prestera_acl_ruleset_ht_key ht_key;
175238

176239
memset(&ht_key, 0, sizeof(ht_key));
177240
ht_key.block = block;
241+
ht_key.chain_index = chain_index;
178242
return rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key,
179243
prestera_acl_ruleset_ht_params);
180244
}
181245

182246
struct prestera_acl_ruleset *
183247
prestera_acl_ruleset_lookup(struct prestera_acl *acl,
184-
struct prestera_flow_block *block)
248+
struct prestera_flow_block *block,
249+
u32 chain_index)
185250
{
186251
struct prestera_acl_ruleset *ruleset;
187252

188-
ruleset = __prestera_acl_ruleset_lookup(acl, block);
253+
ruleset = __prestera_acl_ruleset_lookup(acl, block, chain_index);
189254
if (!ruleset)
190255
return ERR_PTR(-ENOENT);
191256

@@ -195,17 +260,18 @@ prestera_acl_ruleset_lookup(struct prestera_acl *acl,
195260

196261
struct prestera_acl_ruleset *
197262
prestera_acl_ruleset_get(struct prestera_acl *acl,
198-
struct prestera_flow_block *block)
263+
struct prestera_flow_block *block,
264+
u32 chain_index)
199265
{
200266
struct prestera_acl_ruleset *ruleset;
201267

202-
ruleset = __prestera_acl_ruleset_lookup(acl, block);
268+
ruleset = __prestera_acl_ruleset_lookup(acl, block, chain_index);
203269
if (ruleset) {
204270
refcount_inc(&ruleset->refcount);
205271
return ruleset;
206272
}
207273

208-
return prestera_acl_ruleset_create(acl, block);
274+
return prestera_acl_ruleset_create(acl, block, chain_index);
209275
}
210276

211277
void prestera_acl_ruleset_put(struct prestera_acl_ruleset *ruleset)
@@ -293,14 +359,19 @@ prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset,
293359
prestera_acl_rule_ht_params);
294360
}
295361

362+
u32 prestera_acl_ruleset_index_get(const struct prestera_acl_ruleset *ruleset)
363+
{
364+
return ruleset->index;
365+
}
366+
296367
bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset)
297368
{
298369
return ruleset->offload;
299370
}
300371

301372
struct prestera_acl_rule *
302373
prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset,
303-
unsigned long cookie)
374+
unsigned long cookie, u32 chain_index)
304375
{
305376
struct prestera_acl_rule *rule;
306377

@@ -310,6 +381,7 @@ prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset,
310381

311382
rule->ruleset = ruleset;
312383
rule->cookie = cookie;
384+
rule->chain_index = chain_index;
313385

314386
refcount_inc(&ruleset->refcount);
315387

@@ -324,6 +396,10 @@ void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule,
324396

325397
void prestera_acl_rule_destroy(struct prestera_acl_rule *rule)
326398
{
399+
if (rule->jump_ruleset)
400+
/* release ruleset kept by jump action */
401+
prestera_acl_ruleset_put(rule->jump_ruleset);
402+
327403
prestera_acl_ruleset_put(rule->ruleset);
328404
kfree(rule);
329405
}
@@ -347,7 +423,10 @@ int prestera_acl_rule_add(struct prestera_switch *sw,
347423

348424
/* setup counter */
349425
rule->re_arg.count.valid = true;
350-
rule->re_arg.count.client = PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0;
426+
err = prestera_acl_chain_to_client(ruleset->ht_key.chain_index,
427+
&rule->re_arg.count.client);
428+
if (err)
429+
goto err_rule_add;
351430

352431
rule->re = prestera_acl_rule_entry_find(sw->acl, &rule->re_key);
353432
err = WARN_ON(rule->re) ? -EEXIST : 0;
@@ -360,8 +439,10 @@ int prestera_acl_rule_add(struct prestera_switch *sw,
360439
if (err)
361440
goto err_rule_add;
362441

363-
/* bind the block (all ports) to chain index 0 */
364-
if (!ruleset->rule_count) {
442+
/* bind the block (all ports) to chain index 0, rest of
443+
* the chains are bound to goto action
444+
*/
445+
if (!ruleset->ht_key.chain_index && !ruleset->rule_count) {
365446
err = prestera_acl_ruleset_block_bind(ruleset, block);
366447
if (err)
367448
goto err_acl_block_bind;
@@ -395,7 +476,7 @@ void prestera_acl_rule_del(struct prestera_switch *sw,
395476
prestera_acl_rule_entry_destroy(sw->acl, rule->re);
396477

397478
/* unbind block (all ports) */
398-
if (!ruleset->rule_count)
479+
if (!ruleset->ht_key.chain_index && !ruleset->rule_count)
399480
prestera_acl_ruleset_block_unbind(ruleset, block);
400481
}
401482

@@ -459,6 +540,12 @@ static int __prestera_acl_rule_entry2hw_add(struct prestera_switch *sw,
459540
act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_TRAP;
460541
act_num++;
461542
}
543+
/* jump */
544+
if (e->jump.valid) {
545+
act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_JUMP;
546+
act_hw[act_num].jump = e->jump.i;
547+
act_num++;
548+
}
462549
/* counter */
463550
if (e->counter.block) {
464551
act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_COUNT;
@@ -505,6 +592,9 @@ __prestera_acl_rule_entry_act_construct(struct prestera_switch *sw,
505592
e->drop.valid = arg->drop.valid;
506593
/* trap */
507594
e->trap.valid = arg->trap.valid;
595+
/* jump */
596+
e->jump.valid = arg->jump.valid;
597+
e->jump.i = arg->jump.i;
508598
/* counter */
509599
if (arg->count.valid) {
510600
int err;

0 commit comments

Comments
 (0)