@@ -22,6 +22,7 @@ struct prestera_acl {
22
22
23
23
struct prestera_acl_ruleset_ht_key {
24
24
struct prestera_flow_block * block ;
25
+ u32 chain_index ;
25
26
};
26
27
27
28
struct prestera_acl_rule_entry {
@@ -33,6 +34,10 @@ struct prestera_acl_rule_entry {
33
34
struct {
34
35
u8 valid :1 ;
35
36
} accept , drop , trap ;
37
+ struct {
38
+ struct prestera_acl_action_jump i ;
39
+ u8 valid :1 ;
40
+ } jump ;
36
41
struct {
37
42
u32 id ;
38
43
struct prestera_counter_block * block ;
@@ -49,6 +54,7 @@ struct prestera_acl_ruleset {
49
54
refcount_t refcount ;
50
55
void * keymask ;
51
56
u32 vtcam_id ;
57
+ u32 index ;
52
58
u16 pcl_id ;
53
59
bool offload ;
54
60
};
@@ -83,20 +89,45 @@ static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = {
83
89
.automatic_shrinking = true,
84
90
};
85
91
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
+
86
112
static struct prestera_acl_ruleset *
87
113
prestera_acl_ruleset_create (struct prestera_acl * acl ,
88
- struct prestera_flow_block * block )
114
+ struct prestera_flow_block * block ,
115
+ u32 chain_index )
89
116
{
90
117
struct prestera_acl_ruleset * ruleset ;
91
118
u32 uid = 0 ;
92
119
int err ;
93
120
121
+ if (!prestera_acl_chain_is_supported (chain_index ))
122
+ return ERR_PTR (- EINVAL );
123
+
94
124
ruleset = kzalloc (sizeof (* ruleset ), GFP_KERNEL );
95
125
if (!ruleset )
96
126
return ERR_PTR (- ENOMEM );
97
127
98
128
ruleset -> acl = acl ;
99
129
ruleset -> ht_key .block = block ;
130
+ ruleset -> ht_key .chain_index = chain_index ;
100
131
refcount_set (& ruleset -> refcount , 1 );
101
132
102
133
err = rhashtable_init (& ruleset -> rule_ht , & prestera_acl_rule_ht_params );
@@ -108,7 +139,9 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
108
139
goto err_ruleset_create ;
109
140
110
141
/* 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
+
112
145
err = rhashtable_insert_fast (& acl -> ruleset_ht , & ruleset -> ht_node ,
113
146
prestera_acl_ruleset_ht_params );
114
147
if (err )
@@ -133,59 +166,91 @@ void prestera_acl_ruleset_keymask_set(struct prestera_acl_ruleset *ruleset,
133
166
134
167
int prestera_acl_ruleset_offload (struct prestera_acl_ruleset * ruleset )
135
168
{
169
+ struct prestera_acl_iface iface ;
136
170
u32 vtcam_id ;
137
171
int err ;
138
172
139
173
if (ruleset -> offload )
140
174
return - EEXIST ;
141
175
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 ,
143
178
ruleset -> keymask , & vtcam_id );
144
179
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
+ }
146
193
147
194
ruleset -> vtcam_id = vtcam_id ;
148
195
ruleset -> offload = true;
149
196
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 ;
150
202
}
151
203
152
204
static void prestera_acl_ruleset_destroy (struct prestera_acl_ruleset * ruleset )
153
205
{
154
206
struct prestera_acl * acl = ruleset -> acl ;
155
207
u8 uid = ruleset -> pcl_id & PRESTERA_ACL_KEYMASK_PCL_ID_USER ;
208
+ int err ;
156
209
157
210
rhashtable_remove_fast (& acl -> ruleset_ht , & ruleset -> ht_node ,
158
211
prestera_acl_ruleset_ht_params );
159
212
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
+ }
161
223
WARN_ON (prestera_acl_vtcam_id_put (acl , ruleset -> vtcam_id ));
224
+ }
162
225
163
226
idr_remove (& acl -> uid , uid );
164
-
165
227
rhashtable_destroy (& ruleset -> rule_ht );
166
228
kfree (ruleset -> keymask );
167
229
kfree (ruleset );
168
230
}
169
231
170
232
static struct prestera_acl_ruleset *
171
233
__prestera_acl_ruleset_lookup (struct prestera_acl * acl ,
172
- struct prestera_flow_block * block )
234
+ struct prestera_flow_block * block ,
235
+ u32 chain_index )
173
236
{
174
237
struct prestera_acl_ruleset_ht_key ht_key ;
175
238
176
239
memset (& ht_key , 0 , sizeof (ht_key ));
177
240
ht_key .block = block ;
241
+ ht_key .chain_index = chain_index ;
178
242
return rhashtable_lookup_fast (& acl -> ruleset_ht , & ht_key ,
179
243
prestera_acl_ruleset_ht_params );
180
244
}
181
245
182
246
struct prestera_acl_ruleset *
183
247
prestera_acl_ruleset_lookup (struct prestera_acl * acl ,
184
- struct prestera_flow_block * block )
248
+ struct prestera_flow_block * block ,
249
+ u32 chain_index )
185
250
{
186
251
struct prestera_acl_ruleset * ruleset ;
187
252
188
- ruleset = __prestera_acl_ruleset_lookup (acl , block );
253
+ ruleset = __prestera_acl_ruleset_lookup (acl , block , chain_index );
189
254
if (!ruleset )
190
255
return ERR_PTR (- ENOENT );
191
256
@@ -195,17 +260,18 @@ prestera_acl_ruleset_lookup(struct prestera_acl *acl,
195
260
196
261
struct prestera_acl_ruleset *
197
262
prestera_acl_ruleset_get (struct prestera_acl * acl ,
198
- struct prestera_flow_block * block )
263
+ struct prestera_flow_block * block ,
264
+ u32 chain_index )
199
265
{
200
266
struct prestera_acl_ruleset * ruleset ;
201
267
202
- ruleset = __prestera_acl_ruleset_lookup (acl , block );
268
+ ruleset = __prestera_acl_ruleset_lookup (acl , block , chain_index );
203
269
if (ruleset ) {
204
270
refcount_inc (& ruleset -> refcount );
205
271
return ruleset ;
206
272
}
207
273
208
- return prestera_acl_ruleset_create (acl , block );
274
+ return prestera_acl_ruleset_create (acl , block , chain_index );
209
275
}
210
276
211
277
void prestera_acl_ruleset_put (struct prestera_acl_ruleset * ruleset )
@@ -293,14 +359,19 @@ prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset,
293
359
prestera_acl_rule_ht_params );
294
360
}
295
361
362
+ u32 prestera_acl_ruleset_index_get (const struct prestera_acl_ruleset * ruleset )
363
+ {
364
+ return ruleset -> index ;
365
+ }
366
+
296
367
bool prestera_acl_ruleset_is_offload (struct prestera_acl_ruleset * ruleset )
297
368
{
298
369
return ruleset -> offload ;
299
370
}
300
371
301
372
struct prestera_acl_rule *
302
373
prestera_acl_rule_create (struct prestera_acl_ruleset * ruleset ,
303
- unsigned long cookie )
374
+ unsigned long cookie , u32 chain_index )
304
375
{
305
376
struct prestera_acl_rule * rule ;
306
377
@@ -310,6 +381,7 @@ prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset,
310
381
311
382
rule -> ruleset = ruleset ;
312
383
rule -> cookie = cookie ;
384
+ rule -> chain_index = chain_index ;
313
385
314
386
refcount_inc (& ruleset -> refcount );
315
387
@@ -324,6 +396,10 @@ void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule,
324
396
325
397
void prestera_acl_rule_destroy (struct prestera_acl_rule * rule )
326
398
{
399
+ if (rule -> jump_ruleset )
400
+ /* release ruleset kept by jump action */
401
+ prestera_acl_ruleset_put (rule -> jump_ruleset );
402
+
327
403
prestera_acl_ruleset_put (rule -> ruleset );
328
404
kfree (rule );
329
405
}
@@ -347,7 +423,10 @@ int prestera_acl_rule_add(struct prestera_switch *sw,
347
423
348
424
/* setup counter */
349
425
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 ;
351
430
352
431
rule -> re = prestera_acl_rule_entry_find (sw -> acl , & rule -> re_key );
353
432
err = WARN_ON (rule -> re ) ? - EEXIST : 0 ;
@@ -360,8 +439,10 @@ int prestera_acl_rule_add(struct prestera_switch *sw,
360
439
if (err )
361
440
goto err_rule_add ;
362
441
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 ) {
365
446
err = prestera_acl_ruleset_block_bind (ruleset , block );
366
447
if (err )
367
448
goto err_acl_block_bind ;
@@ -395,7 +476,7 @@ void prestera_acl_rule_del(struct prestera_switch *sw,
395
476
prestera_acl_rule_entry_destroy (sw -> acl , rule -> re );
396
477
397
478
/* unbind block (all ports) */
398
- if (!ruleset -> rule_count )
479
+ if (!ruleset -> ht_key . chain_index && ! ruleset -> rule_count )
399
480
prestera_acl_ruleset_block_unbind (ruleset , block );
400
481
}
401
482
@@ -459,6 +540,12 @@ static int __prestera_acl_rule_entry2hw_add(struct prestera_switch *sw,
459
540
act_hw [act_num ].id = PRESTERA_ACL_RULE_ACTION_TRAP ;
460
541
act_num ++ ;
461
542
}
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
+ }
462
549
/* counter */
463
550
if (e -> counter .block ) {
464
551
act_hw [act_num ].id = PRESTERA_ACL_RULE_ACTION_COUNT ;
@@ -505,6 +592,9 @@ __prestera_acl_rule_entry_act_construct(struct prestera_switch *sw,
505
592
e -> drop .valid = arg -> drop .valid ;
506
593
/* trap */
507
594
e -> trap .valid = arg -> trap .valid ;
595
+ /* jump */
596
+ e -> jump .valid = arg -> jump .valid ;
597
+ e -> jump .i = arg -> jump .i ;
508
598
/* counter */
509
599
if (arg -> count .valid ) {
510
600
int err ;
0 commit comments