@@ -302,16 +302,64 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
302
302
return 0 ;
303
303
}
304
304
305
+ static void
306
+ nfp_fl_set_ip6_helper (int opcode_tag , int idx , __be32 exact , __be32 mask ,
307
+ struct nfp_fl_set_ipv6_addr * ip6 )
308
+ {
309
+ u16 tmp_set_op ;
310
+
311
+ ip6 -> ipv6 [idx % 4 ].mask = mask ;
312
+ ip6 -> ipv6 [idx % 4 ].exact = exact ;
313
+
314
+ ip6 -> reserved = cpu_to_be16 (0 );
315
+ tmp_set_op = FIELD_PREP (NFP_FL_ACT_LEN_LW , sizeof (* ip6 ) >>
316
+ NFP_FL_LW_SIZ ) |
317
+ FIELD_PREP (NFP_FL_ACT_JMP_ID , opcode_tag );
318
+ ip6 -> a_op = cpu_to_be16 (tmp_set_op );
319
+ }
320
+
321
+ static int
322
+ nfp_fl_set_ip6 (const struct tc_action * action , int idx , u32 off ,
323
+ struct nfp_fl_set_ipv6_addr * ip_dst ,
324
+ struct nfp_fl_set_ipv6_addr * ip_src )
325
+ {
326
+ __be32 exact , mask ;
327
+
328
+ /* We are expecting tcf_pedit to return a big endian value */
329
+ mask = (__force __be32 )~tcf_pedit_mask (action , idx );
330
+ exact = (__force __be32 )tcf_pedit_val (action , idx );
331
+
332
+ if (exact & ~mask )
333
+ return - EOPNOTSUPP ;
334
+
335
+ if (off < offsetof(struct ipv6hdr , saddr ))
336
+ return - EOPNOTSUPP ;
337
+ else if (off < offsetof(struct ipv6hdr , daddr ))
338
+ nfp_fl_set_ip6_helper (NFP_FL_ACTION_OPCODE_SET_IPV6_SRC , idx ,
339
+ exact , mask , ip_src );
340
+ else if (off < offsetof(struct ipv6hdr , daddr ) +
341
+ sizeof (struct in6_addr ))
342
+ nfp_fl_set_ip6_helper (NFP_FL_ACTION_OPCODE_SET_IPV6_DST , idx ,
343
+ exact , mask , ip_dst );
344
+ else
345
+ return - EOPNOTSUPP ;
346
+
347
+ return 0 ;
348
+ }
349
+
305
350
static int
306
351
nfp_fl_pedit (const struct tc_action * action , char * nfp_action , int * a_len )
307
352
{
353
+ struct nfp_fl_set_ipv6_addr set_ip6_dst , set_ip6_src ;
308
354
struct nfp_fl_set_ip4_addrs set_ip_addr ;
309
355
struct nfp_fl_set_eth set_eth ;
310
356
enum pedit_header_type htype ;
311
357
int idx , nkeys , err ;
312
358
size_t act_size ;
313
359
u32 offset , cmd ;
314
360
361
+ memset (& set_ip6_dst , 0 , sizeof (set_ip6_dst ));
362
+ memset (& set_ip6_src , 0 , sizeof (set_ip6_src ));
315
363
memset (& set_ip_addr , 0 , sizeof (set_ip_addr ));
316
364
memset (& set_eth , 0 , sizeof (set_eth ));
317
365
nkeys = tcf_pedit_nkeys (action );
@@ -331,6 +379,10 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len)
331
379
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 :
332
380
err = nfp_fl_set_ip4 (action , idx , offset , & set_ip_addr );
333
381
break ;
382
+ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 :
383
+ err = nfp_fl_set_ip6 (action , idx , offset , & set_ip6_dst ,
384
+ & set_ip6_src );
385
+ break ;
334
386
default :
335
387
return - EOPNOTSUPP ;
336
388
}
@@ -346,6 +398,26 @@ nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len)
346
398
act_size = sizeof (set_ip_addr );
347
399
memcpy (nfp_action , & set_ip_addr , act_size );
348
400
* a_len += act_size ;
401
+ } else if (set_ip6_dst .a_op && set_ip6_src .a_op ) {
402
+ /* TC compiles set src and dst IPv6 address as a single action,
403
+ * the hardware requires this to be 2 separate actions.
404
+ */
405
+ act_size = sizeof (set_ip6_src );
406
+ memcpy (nfp_action , & set_ip6_src , act_size );
407
+ * a_len += act_size ;
408
+
409
+ act_size = sizeof (set_ip6_dst );
410
+ memcpy (& nfp_action [sizeof (set_ip6_src )], & set_ip6_dst ,
411
+ act_size );
412
+ * a_len += act_size ;
413
+ } else if (set_ip6_dst .a_op ) {
414
+ act_size = sizeof (set_ip6_dst );
415
+ memcpy (nfp_action , & set_ip6_dst , act_size );
416
+ * a_len += act_size ;
417
+ } else if (set_ip6_src .a_op ) {
418
+ act_size = sizeof (set_ip6_src );
419
+ memcpy (nfp_action , & set_ip6_src , act_size );
420
+ * a_len += act_size ;
349
421
}
350
422
351
423
return 0 ;
0 commit comments