Skip to content

Commit 3eb6800

Browse files
Herat Ramanigregkh
authored andcommitted
cxgb4: handle 4-tuple PEDIT to NAT mode translation
[ Upstream commit 2ef813b ] The 4-tuple NAT offload via PEDIT always overwrites all the 4-tuple fields even if they had not been explicitly enabled. If any fields in the 4-tuple are not enabled, then the hardware overwrites the disabled fields with zeros, instead of ignoring them. So, add a parser that can translate the enabled 4-tuple PEDIT fields to one of the NAT mode combinations supported by the hardware and hence avoid overwriting disabled fields to 0. Any rule with unsupported NAT mode combination is rejected. Signed-off-by: Herat Ramani <herat@chelsio.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 4b470a7 commit 3eb6800

2 files changed

Lines changed: 177 additions & 13 deletions

File tree

drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c

Lines changed: 162 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,89 @@ static struct ch_tc_pedit_fields pedits[] = {
6060
PEDIT_FIELDS(IP6_, DST_127_96, 4, nat_lip, 12),
6161
};
6262

63+
static const struct cxgb4_natmode_config cxgb4_natmode_config_array[] = {
64+
/* Default supported NAT modes */
65+
{
66+
.chip = CHELSIO_T5,
67+
.flags = CXGB4_ACTION_NATMODE_NONE,
68+
.natmode = NAT_MODE_NONE,
69+
},
70+
{
71+
.chip = CHELSIO_T5,
72+
.flags = CXGB4_ACTION_NATMODE_DIP,
73+
.natmode = NAT_MODE_DIP,
74+
},
75+
{
76+
.chip = CHELSIO_T5,
77+
.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_DPORT,
78+
.natmode = NAT_MODE_DIP_DP,
79+
},
80+
{
81+
.chip = CHELSIO_T5,
82+
.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_DPORT |
83+
CXGB4_ACTION_NATMODE_SIP,
84+
.natmode = NAT_MODE_DIP_DP_SIP,
85+
},
86+
{
87+
.chip = CHELSIO_T5,
88+
.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_DPORT |
89+
CXGB4_ACTION_NATMODE_SPORT,
90+
.natmode = NAT_MODE_DIP_DP_SP,
91+
},
92+
{
93+
.chip = CHELSIO_T5,
94+
.flags = CXGB4_ACTION_NATMODE_SIP | CXGB4_ACTION_NATMODE_SPORT,
95+
.natmode = NAT_MODE_SIP_SP,
96+
},
97+
{
98+
.chip = CHELSIO_T5,
99+
.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SIP |
100+
CXGB4_ACTION_NATMODE_SPORT,
101+
.natmode = NAT_MODE_DIP_SIP_SP,
102+
},
103+
{
104+
.chip = CHELSIO_T5,
105+
.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SIP |
106+
CXGB4_ACTION_NATMODE_DPORT |
107+
CXGB4_ACTION_NATMODE_SPORT,
108+
.natmode = NAT_MODE_ALL,
109+
},
110+
/* T6+ can ignore L4 ports when they're disabled. */
111+
{
112+
.chip = CHELSIO_T6,
113+
.flags = CXGB4_ACTION_NATMODE_SIP,
114+
.natmode = NAT_MODE_SIP_SP,
115+
},
116+
{
117+
.chip = CHELSIO_T6,
118+
.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SPORT,
119+
.natmode = NAT_MODE_DIP_DP_SP,
120+
},
121+
{
122+
.chip = CHELSIO_T6,
123+
.flags = CXGB4_ACTION_NATMODE_DIP | CXGB4_ACTION_NATMODE_SIP,
124+
.natmode = NAT_MODE_ALL,
125+
},
126+
};
127+
128+
static void cxgb4_action_natmode_tweak(struct ch_filter_specification *fs,
129+
u8 natmode_flags)
130+
{
131+
u8 i = 0;
132+
133+
/* Translate the enabled NAT 4-tuple fields to one of the
134+
* hardware supported NAT mode configurations. This ensures
135+
* that we pick a valid combination, where the disabled fields
136+
* do not get overwritten to 0.
137+
*/
138+
for (i = 0; i < ARRAY_SIZE(cxgb4_natmode_config_array); i++) {
139+
if (cxgb4_natmode_config_array[i].flags == natmode_flags) {
140+
fs->nat_mode = cxgb4_natmode_config_array[i].natmode;
141+
return;
142+
}
143+
}
144+
}
145+
63146
static struct ch_tc_flower_entry *allocate_flower_entry(void)
64147
{
65148
struct ch_tc_flower_entry *new = kzalloc(sizeof(*new), GFP_KERNEL);
@@ -289,7 +372,8 @@ static void offload_pedit(struct ch_filter_specification *fs, u32 val, u32 mask,
289372
}
290373

291374
static void process_pedit_field(struct ch_filter_specification *fs, u32 val,
292-
u32 mask, u32 offset, u8 htype)
375+
u32 mask, u32 offset, u8 htype,
376+
u8 *natmode_flags)
293377
{
294378
switch (htype) {
295379
case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
@@ -314,67 +398,102 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val,
314398
switch (offset) {
315399
case PEDIT_IP4_SRC:
316400
offload_pedit(fs, val, mask, IP4_SRC);
401+
*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
317402
break;
318403
case PEDIT_IP4_DST:
319404
offload_pedit(fs, val, mask, IP4_DST);
405+
*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
320406
}
321-
fs->nat_mode = NAT_MODE_ALL;
322407
break;
323408
case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
324409
switch (offset) {
325410
case PEDIT_IP6_SRC_31_0:
326411
offload_pedit(fs, val, mask, IP6_SRC_31_0);
412+
*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
327413
break;
328414
case PEDIT_IP6_SRC_63_32:
329415
offload_pedit(fs, val, mask, IP6_SRC_63_32);
416+
*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
330417
break;
331418
case PEDIT_IP6_SRC_95_64:
332419
offload_pedit(fs, val, mask, IP6_SRC_95_64);
420+
*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
333421
break;
334422
case PEDIT_IP6_SRC_127_96:
335423
offload_pedit(fs, val, mask, IP6_SRC_127_96);
424+
*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
336425
break;
337426
case PEDIT_IP6_DST_31_0:
338427
offload_pedit(fs, val, mask, IP6_DST_31_0);
428+
*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
339429
break;
340430
case PEDIT_IP6_DST_63_32:
341431
offload_pedit(fs, val, mask, IP6_DST_63_32);
432+
*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
342433
break;
343434
case PEDIT_IP6_DST_95_64:
344435
offload_pedit(fs, val, mask, IP6_DST_95_64);
436+
*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
345437
break;
346438
case PEDIT_IP6_DST_127_96:
347439
offload_pedit(fs, val, mask, IP6_DST_127_96);
440+
*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
348441
}
349-
fs->nat_mode = NAT_MODE_ALL;
350442
break;
351443
case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
352444
switch (offset) {
353445
case PEDIT_TCP_SPORT_DPORT:
354-
if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
446+
if (~mask & PEDIT_TCP_UDP_SPORT_MASK) {
355447
fs->nat_fport = val;
356-
else
448+
*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
449+
} else {
357450
fs->nat_lport = val >> 16;
451+
*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
452+
}
358453
}
359-
fs->nat_mode = NAT_MODE_ALL;
360454
break;
361455
case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
362456
switch (offset) {
363457
case PEDIT_UDP_SPORT_DPORT:
364-
if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
458+
if (~mask & PEDIT_TCP_UDP_SPORT_MASK) {
365459
fs->nat_fport = val;
366-
else
460+
*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
461+
} else {
367462
fs->nat_lport = val >> 16;
463+
*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
464+
}
368465
}
369-
fs->nat_mode = NAT_MODE_ALL;
466+
break;
467+
}
468+
}
469+
470+
static int cxgb4_action_natmode_validate(struct adapter *adap, u8 natmode_flags,
471+
struct netlink_ext_ack *extack)
472+
{
473+
u8 i = 0;
474+
475+
/* Extract the NAT mode to enable based on what 4-tuple fields
476+
* are enabled to be overwritten. This ensures that the
477+
* disabled fields don't get overwritten to 0.
478+
*/
479+
for (i = 0; i < ARRAY_SIZE(cxgb4_natmode_config_array); i++) {
480+
const struct cxgb4_natmode_config *c;
481+
482+
c = &cxgb4_natmode_config_array[i];
483+
if (CHELSIO_CHIP_VERSION(adap->params.chip) >= c->chip &&
484+
natmode_flags == c->flags)
485+
return 0;
370486
}
487+
NL_SET_ERR_MSG_MOD(extack, "Unsupported NAT mode 4-tuple combination");
488+
return -EOPNOTSUPP;
371489
}
372490

373491
void cxgb4_process_flow_actions(struct net_device *in,
374492
struct flow_action *actions,
375493
struct ch_filter_specification *fs)
376494
{
377495
struct flow_action_entry *act;
496+
u8 natmode_flags = 0;
378497
int i;
379498

380499
flow_action_for_each(i, act, actions) {
@@ -426,7 +545,8 @@ void cxgb4_process_flow_actions(struct net_device *in,
426545
val = act->mangle.val;
427546
offset = act->mangle.offset;
428547

429-
process_pedit_field(fs, val, mask, offset, htype);
548+
process_pedit_field(fs, val, mask, offset, htype,
549+
&natmode_flags);
430550
}
431551
break;
432552
case FLOW_ACTION_QUEUE:
@@ -438,6 +558,9 @@ void cxgb4_process_flow_actions(struct net_device *in,
438558
break;
439559
}
440560
}
561+
if (natmode_flags)
562+
cxgb4_action_natmode_tweak(fs, natmode_flags);
563+
441564
}
442565

443566
static bool valid_l4_mask(u32 mask)
@@ -454,7 +577,8 @@ static bool valid_l4_mask(u32 mask)
454577
}
455578

456579
static bool valid_pedit_action(struct net_device *dev,
457-
const struct flow_action_entry *act)
580+
const struct flow_action_entry *act,
581+
u8 *natmode_flags)
458582
{
459583
u32 mask, offset;
460584
u8 htype;
@@ -479,7 +603,10 @@ static bool valid_pedit_action(struct net_device *dev,
479603
case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
480604
switch (offset) {
481605
case PEDIT_IP4_SRC:
606+
*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
607+
break;
482608
case PEDIT_IP4_DST:
609+
*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
483610
break;
484611
default:
485612
netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -493,10 +620,13 @@ static bool valid_pedit_action(struct net_device *dev,
493620
case PEDIT_IP6_SRC_63_32:
494621
case PEDIT_IP6_SRC_95_64:
495622
case PEDIT_IP6_SRC_127_96:
623+
*natmode_flags |= CXGB4_ACTION_NATMODE_SIP;
624+
break;
496625
case PEDIT_IP6_DST_31_0:
497626
case PEDIT_IP6_DST_63_32:
498627
case PEDIT_IP6_DST_95_64:
499628
case PEDIT_IP6_DST_127_96:
629+
*natmode_flags |= CXGB4_ACTION_NATMODE_DIP;
500630
break;
501631
default:
502632
netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -512,6 +642,10 @@ static bool valid_pedit_action(struct net_device *dev,
512642
__func__);
513643
return false;
514644
}
645+
if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
646+
*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
647+
else
648+
*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
515649
break;
516650
default:
517651
netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -527,6 +661,10 @@ static bool valid_pedit_action(struct net_device *dev,
527661
__func__);
528662
return false;
529663
}
664+
if (~mask & PEDIT_TCP_UDP_SPORT_MASK)
665+
*natmode_flags |= CXGB4_ACTION_NATMODE_SPORT;
666+
else
667+
*natmode_flags |= CXGB4_ACTION_NATMODE_DPORT;
530668
break;
531669
default:
532670
netdev_err(dev, "%s: Unsupported pedit field\n",
@@ -546,10 +684,12 @@ int cxgb4_validate_flow_actions(struct net_device *dev,
546684
struct netlink_ext_ack *extack,
547685
u8 matchall_filter)
548686
{
687+
struct adapter *adap = netdev2adap(dev);
549688
struct flow_action_entry *act;
550689
bool act_redir = false;
551690
bool act_pedit = false;
552691
bool act_vlan = false;
692+
u8 natmode_flags = 0;
553693
int i;
554694

555695
if (!flow_action_basic_hw_stats_check(actions, extack))
@@ -563,7 +703,6 @@ int cxgb4_validate_flow_actions(struct net_device *dev,
563703
break;
564704
case FLOW_ACTION_MIRRED:
565705
case FLOW_ACTION_REDIRECT: {
566-
struct adapter *adap = netdev2adap(dev);
567706
struct net_device *n_dev, *target_dev;
568707
bool found = false;
569708
unsigned int i;
@@ -620,7 +759,8 @@ int cxgb4_validate_flow_actions(struct net_device *dev,
620759
}
621760
break;
622761
case FLOW_ACTION_MANGLE: {
623-
bool pedit_valid = valid_pedit_action(dev, act);
762+
bool pedit_valid = valid_pedit_action(dev, act,
763+
&natmode_flags);
624764

625765
if (!pedit_valid)
626766
return -EOPNOTSUPP;
@@ -642,6 +782,15 @@ int cxgb4_validate_flow_actions(struct net_device *dev,
642782
return -EINVAL;
643783
}
644784

785+
if (act_pedit) {
786+
int ret;
787+
788+
ret = cxgb4_action_natmode_validate(adap, natmode_flags,
789+
extack);
790+
if (ret)
791+
return ret;
792+
}
793+
645794
return 0;
646795
}
647796

drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,21 @@ struct ch_tc_pedit_fields {
108108
#define PEDIT_TCP_SPORT_DPORT 0x0
109109
#define PEDIT_UDP_SPORT_DPORT 0x0
110110

111+
enum cxgb4_action_natmode_flags {
112+
CXGB4_ACTION_NATMODE_NONE = 0,
113+
CXGB4_ACTION_NATMODE_DIP = (1 << 0),
114+
CXGB4_ACTION_NATMODE_SIP = (1 << 1),
115+
CXGB4_ACTION_NATMODE_DPORT = (1 << 2),
116+
CXGB4_ACTION_NATMODE_SPORT = (1 << 3),
117+
};
118+
119+
/* TC PEDIT action to NATMODE translation entry */
120+
struct cxgb4_natmode_config {
121+
enum chip_type chip;
122+
u8 flags;
123+
u8 natmode;
124+
};
125+
111126
void cxgb4_process_flow_actions(struct net_device *in,
112127
struct flow_action *actions,
113128
struct ch_filter_specification *fs);

0 commit comments

Comments
 (0)