@@ -47,6 +47,20 @@ struct ch_tc_pedit_fields pedits[] = {
4747 PEDIT_FIELDS (ETH_ , DMAC_47_32 , 2 , dmac , 4 ),
4848 PEDIT_FIELDS (ETH_ , SMAC_15_0 , 2 , smac , 0 ),
4949 PEDIT_FIELDS (ETH_ , SMAC_47_16 , 4 , smac , 2 ),
50+ PEDIT_FIELDS (IP4_ , SRC , 4 , nat_fip , 0 ),
51+ PEDIT_FIELDS (IP4_ , DST , 4 , nat_lip , 0 ),
52+ PEDIT_FIELDS (IP6_ , SRC_31_0 , 4 , nat_fip , 0 ),
53+ PEDIT_FIELDS (IP6_ , SRC_63_32 , 4 , nat_fip , 4 ),
54+ PEDIT_FIELDS (IP6_ , SRC_95_64 , 4 , nat_fip , 8 ),
55+ PEDIT_FIELDS (IP6_ , SRC_127_96 , 4 , nat_fip , 12 ),
56+ PEDIT_FIELDS (IP6_ , DST_31_0 , 4 , nat_lip , 0 ),
57+ PEDIT_FIELDS (IP6_ , DST_63_32 , 4 , nat_lip , 4 ),
58+ PEDIT_FIELDS (IP6_ , DST_95_64 , 4 , nat_lip , 8 ),
59+ PEDIT_FIELDS (IP6_ , DST_127_96 , 4 , nat_lip , 12 ),
60+ PEDIT_FIELDS (TCP_ , SPORT , 2 , nat_fport , 0 ),
61+ PEDIT_FIELDS (TCP_ , DPORT , 2 , nat_lport , 0 ),
62+ PEDIT_FIELDS (UDP_ , SPORT , 2 , nat_fport , 0 ),
63+ PEDIT_FIELDS (UDP_ , DPORT , 2 , nat_lport , 0 ),
5064};
5165
5266static struct ch_tc_flower_entry * allocate_flower_entry (void )
@@ -121,6 +135,11 @@ static void cxgb4_process_flow_match(struct net_device *dev,
121135 memcpy (& fs -> val .fip [0 ], & key -> src , sizeof (key -> src ));
122136 memcpy (& fs -> mask .lip [0 ], & mask -> dst , sizeof (mask -> dst ));
123137 memcpy (& fs -> mask .fip [0 ], & mask -> src , sizeof (mask -> src ));
138+
139+ /* also initialize nat_lip/fip to same values */
140+ memcpy (& fs -> nat_lip [0 ], & key -> dst , sizeof (key -> dst ));
141+ memcpy (& fs -> nat_fip [0 ], & key -> src , sizeof (key -> src ));
142+
124143 }
125144
126145 if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS ) {
@@ -138,6 +157,10 @@ static void cxgb4_process_flow_match(struct net_device *dev,
138157 memcpy (& fs -> val .fip [0 ], key -> src .s6_addr , sizeof (key -> src ));
139158 memcpy (& fs -> mask .lip [0 ], mask -> dst .s6_addr , sizeof (mask -> dst ));
140159 memcpy (& fs -> mask .fip [0 ], mask -> src .s6_addr , sizeof (mask -> src ));
160+
161+ /* also initialize nat_lip/fip to same values */
162+ memcpy (& fs -> nat_lip [0 ], key -> dst .s6_addr , sizeof (key -> dst ));
163+ memcpy (& fs -> nat_fip [0 ], key -> src .s6_addr , sizeof (key -> src ));
141164 }
142165
143166 if (dissector_uses_key (cls -> dissector , FLOW_DISSECTOR_KEY_PORTS )) {
@@ -153,6 +176,10 @@ static void cxgb4_process_flow_match(struct net_device *dev,
153176 fs -> mask .lport = cpu_to_be16 (mask -> dst );
154177 fs -> val .fport = cpu_to_be16 (key -> src );
155178 fs -> mask .fport = cpu_to_be16 (mask -> src );
179+
180+ /* also initialize nat_lport/fport to same values */
181+ fs -> nat_lport = cpu_to_be16 (key -> dst );
182+ fs -> nat_fport = cpu_to_be16 (key -> src );
156183 }
157184
158185 if (dissector_uses_key (cls -> dissector , FLOW_DISSECTOR_KEY_IP )) {
@@ -301,6 +328,70 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val,
301328 fs -> newsmac = 1 ;
302329 offload_pedit (fs , val , mask , ETH_SMAC_47_16 );
303330 }
331+ break ;
332+ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 :
333+ switch (offset ) {
334+ case PEDIT_IP4_SRC :
335+ offload_pedit (fs , val , mask , IP4_SRC );
336+ break ;
337+ case PEDIT_IP4_DST :
338+ offload_pedit (fs , val , mask , IP4_DST );
339+ }
340+ fs -> nat_mode = NAT_MODE_ALL ;
341+ break ;
342+ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 :
343+ switch (offset ) {
344+ case PEDIT_IP6_SRC_31_0 :
345+ offload_pedit (fs , val , mask , IP6_SRC_31_0 );
346+ break ;
347+ case PEDIT_IP6_SRC_63_32 :
348+ offload_pedit (fs , val , mask , IP6_SRC_63_32 );
349+ break ;
350+ case PEDIT_IP6_SRC_95_64 :
351+ offload_pedit (fs , val , mask , IP6_SRC_95_64 );
352+ break ;
353+ case PEDIT_IP6_SRC_127_96 :
354+ offload_pedit (fs , val , mask , IP6_SRC_127_96 );
355+ break ;
356+ case PEDIT_IP6_DST_31_0 :
357+ offload_pedit (fs , val , mask , IP6_DST_31_0 );
358+ break ;
359+ case PEDIT_IP6_DST_63_32 :
360+ offload_pedit (fs , val , mask , IP6_DST_63_32 );
361+ break ;
362+ case PEDIT_IP6_DST_95_64 :
363+ offload_pedit (fs , val , mask , IP6_DST_95_64 );
364+ break ;
365+ case PEDIT_IP6_DST_127_96 :
366+ offload_pedit (fs , val , mask , IP6_DST_127_96 );
367+ }
368+ fs -> nat_mode = NAT_MODE_ALL ;
369+ break ;
370+ case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP :
371+ switch (offset ) {
372+ case PEDIT_TCP_SPORT_DPORT :
373+ if (~mask & PEDIT_TCP_UDP_SPORT_MASK )
374+ offload_pedit (fs , cpu_to_be32 (val ) >> 16 ,
375+ cpu_to_be32 (mask ) >> 16 ,
376+ TCP_SPORT );
377+ else
378+ offload_pedit (fs , cpu_to_be32 (val ),
379+ cpu_to_be32 (mask ), TCP_DPORT );
380+ }
381+ fs -> nat_mode = NAT_MODE_ALL ;
382+ break ;
383+ case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP :
384+ switch (offset ) {
385+ case PEDIT_UDP_SPORT_DPORT :
386+ if (~mask & PEDIT_TCP_UDP_SPORT_MASK )
387+ offload_pedit (fs , cpu_to_be32 (val ) >> 16 ,
388+ cpu_to_be32 (mask ) >> 16 ,
389+ UDP_SPORT );
390+ else
391+ offload_pedit (fs , cpu_to_be32 (val ),
392+ cpu_to_be32 (mask ), UDP_DPORT );
393+ }
394+ fs -> nat_mode = NAT_MODE_ALL ;
304395 }
305396}
306397
@@ -365,6 +456,119 @@ static void cxgb4_process_flow_actions(struct net_device *in,
365456 }
366457}
367458
459+ static bool valid_l4_mask (u32 mask )
460+ {
461+ u16 hi , lo ;
462+
463+ /* Either the upper 16-bits (SPORT) OR the lower
464+ * 16-bits (DPORT) can be set, but NOT BOTH.
465+ */
466+ hi = (mask >> 16 ) & 0xFFFF ;
467+ lo = mask & 0xFFFF ;
468+
469+ return hi && lo ? false : true;
470+ }
471+
472+ static bool valid_pedit_action (struct net_device * dev ,
473+ const struct tc_action * a )
474+ {
475+ u32 mask , offset ;
476+ u8 cmd , htype ;
477+ int nkeys , i ;
478+
479+ nkeys = tcf_pedit_nkeys (a );
480+ for (i = 0 ; i < nkeys ; i ++ ) {
481+ htype = tcf_pedit_htype (a , i );
482+ cmd = tcf_pedit_cmd (a , i );
483+ mask = tcf_pedit_mask (a , i );
484+ offset = tcf_pedit_offset (a , i );
485+
486+ if (cmd != TCA_PEDIT_KEY_EX_CMD_SET ) {
487+ netdev_err (dev , "%s: Unsupported pedit cmd\n" ,
488+ __func__ );
489+ return false;
490+ }
491+
492+ switch (htype ) {
493+ case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH :
494+ switch (offset ) {
495+ case PEDIT_ETH_DMAC_31_0 :
496+ case PEDIT_ETH_DMAC_47_32_SMAC_15_0 :
497+ case PEDIT_ETH_SMAC_47_16 :
498+ break ;
499+ default :
500+ netdev_err (dev , "%s: Unsupported pedit field\n" ,
501+ __func__ );
502+ return false;
503+ }
504+ break ;
505+ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 :
506+ switch (offset ) {
507+ case PEDIT_IP4_SRC :
508+ case PEDIT_IP4_DST :
509+ break ;
510+ default :
511+ netdev_err (dev , "%s: Unsupported pedit field\n" ,
512+ __func__ );
513+ return false;
514+ }
515+ break ;
516+ case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 :
517+ switch (offset ) {
518+ case PEDIT_IP6_SRC_31_0 :
519+ case PEDIT_IP6_SRC_63_32 :
520+ case PEDIT_IP6_SRC_95_64 :
521+ case PEDIT_IP6_SRC_127_96 :
522+ case PEDIT_IP6_DST_31_0 :
523+ case PEDIT_IP6_DST_63_32 :
524+ case PEDIT_IP6_DST_95_64 :
525+ case PEDIT_IP6_DST_127_96 :
526+ break ;
527+ default :
528+ netdev_err (dev , "%s: Unsupported pedit field\n" ,
529+ __func__ );
530+ return false;
531+ }
532+ break ;
533+ case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP :
534+ switch (offset ) {
535+ case PEDIT_TCP_SPORT_DPORT :
536+ if (!valid_l4_mask (~mask )) {
537+ netdev_err (dev , "%s: Unsupported mask for TCP L4 ports\n" ,
538+ __func__ );
539+ return false;
540+ }
541+ break ;
542+ default :
543+ netdev_err (dev , "%s: Unsupported pedit field\n" ,
544+ __func__ );
545+ return false;
546+ }
547+ break ;
548+ case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP :
549+ switch (offset ) {
550+ case PEDIT_UDP_SPORT_DPORT :
551+ if (!valid_l4_mask (~mask )) {
552+ netdev_err (dev , "%s: Unsupported mask for UDP L4 ports\n" ,
553+ __func__ );
554+ return false;
555+ }
556+ break ;
557+ default :
558+ netdev_err (dev , "%s: Unsupported pedit field\n" ,
559+ __func__ );
560+ return false;
561+ }
562+ break ;
563+ default :
564+ netdev_err (dev , "%s: Unsupported pedit type\n" ,
565+ __func__ );
566+ return false;
567+ }
568+ }
569+ return true;
570+ }
571+
368572static int cxgb4_validate_flow_actions (struct net_device * dev ,
369573 struct tc_cls_flower_offload * cls )
370574{
@@ -426,43 +630,10 @@ static int cxgb4_validate_flow_actions(struct net_device *dev,
426630 }
427631 act_vlan = true;
428632 } else if (is_tcf_pedit (a )) {
429- u32 mask , val , offset ;
430- u8 cmd , htype ;
431- int nkeys , i ;
633+ bool pedit_valid = valid_pedit_action (dev , a );
432634
433- nkeys = tcf_pedit_nkeys (a );
434- for (i = 0 ; i < nkeys ; i ++ ) {
435- htype = tcf_pedit_htype (a , i );
436- cmd = tcf_pedit_cmd (a , i );
437- mask = tcf_pedit_mask (a , i );
438- val = tcf_pedit_val (a , i );
439- offset = tcf_pedit_offset (a , i );
440-
441- if (cmd != TCA_PEDIT_KEY_EX_CMD_SET ) {
442- netdev_err (dev , "%s: Unsupported pedit cmd\n" ,
443- __func__ );
444- return - EOPNOTSUPP ;
445- }
446-
447- switch (htype ) {
448- case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH :
449- switch (offset ) {
450- case PEDIT_ETH_DMAC_31_0 :
451- case PEDIT_ETH_DMAC_47_32_SMAC_15_0 :
452- case PEDIT_ETH_SMAC_47_16 :
453- break ;
454- default :
455- netdev_err (dev , "%s: Unsupported pedit field\n" ,
456- __func__ );
457- return - EOPNOTSUPP ;
458- }
459- break ;
460- default :
461- netdev_err (dev , "%s: Unsupported pedit type\n" ,
462- __func__ );
463- return - EOPNOTSUPP ;
464- }
465- }
635+ if (!pedit_valid )
636+ return - EOPNOTSUPP ;
466637 act_pedit = true;
467638 } else {
468639 netdev_err (dev , "%s: Unsupported action\n" , __func__ );
@@ -503,8 +674,8 @@ int cxgb4_tc_flower_replace(struct net_device *dev,
503674
504675 fs = & ch_flower -> fs ;
505676 fs -> hitcnts = 1 ;
506- cxgb4_process_flow_actions (dev , cls , fs );
507677 cxgb4_process_flow_match (dev , cls , fs );
678+ cxgb4_process_flow_actions (dev , cls , fs );
508679
509680 fidx = cxgb4_get_free_ftid (dev , fs -> type ? PF_INET6 : PF_INET );
510681 if (fidx < 0 ) {
0 commit comments