Skip to content

Commit 557ccbf

Browse files
Kumar Sanghvidavem330
authored andcommitted
cxgb4: add tc flower support for L3/L4 rewrite
Adds support to rewrite L3/L4 fields via TC-PEDIT action. Supported fields for rewrite are: IPv4 src/dst address, IPv6 src/dst address, TCP/UDP sport/dport. Also, process match fields first and then process the action items. Refactor pedit action validation to separate function to avoid excessive code indentation. Signed-off-by: Kumar Sanghvi <[email protected]> Signed-off-by: Rahul Lakkireddy <[email protected]> Signed-off-by: Ganesh Goudar <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0ff9099 commit 557ccbf

File tree

3 files changed

+244
-37
lines changed

3 files changed

+244
-37
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,10 @@ enum {
10971097
VLAN_REWRITE
10981098
};
10991099

1100+
enum {
1101+
NAT_MODE_ALL = 7, /* NAT on entire 4-tuple */
1102+
};
1103+
11001104
/* Host shadow copy of ingress filter entry. This is in host native format
11011105
* and doesn't match the ordering or bit order, etc. of the hardware of the
11021106
* firmware command. The use of bit-field structure elements is purely to

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

Lines changed: 208 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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

5266
static 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+
368572
static 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) {

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,25 @@ enum {
5959
ETH_DMAC_47_32, /* dmac bits 32..47 */
6060
ETH_SMAC_15_0, /* smac bits 0.. 15 */
6161
ETH_SMAC_47_16, /* smac bits 16..47 */
62+
63+
IP4_SRC, /* 32-bit IPv4 src */
64+
IP4_DST, /* 32-bit IPv4 dst */
65+
66+
IP6_SRC_31_0, /* src bits 0.. 31 */
67+
IP6_SRC_63_32, /* src bits 63.. 32 */
68+
IP6_SRC_95_64, /* src bits 95.. 64 */
69+
IP6_SRC_127_96, /* src bits 127..96 */
70+
71+
IP6_DST_31_0, /* dst bits 0.. 31 */
72+
IP6_DST_63_32, /* dst bits 63.. 32 */
73+
IP6_DST_95_64, /* dst bits 95.. 64 */
74+
IP6_DST_127_96, /* dst bits 127..96 */
75+
76+
TCP_SPORT, /* 16-bit TCP sport */
77+
TCP_DPORT, /* 16-bit TCP dport */
78+
79+
UDP_SPORT, /* 16-bit UDP sport */
80+
UDP_DPORT, /* 16-bit UDP dport */
6281
};
6382

6483
struct ch_tc_pedit_fields {
@@ -72,9 +91,22 @@ struct ch_tc_pedit_fields {
7291
offsetof(struct ch_filter_specification, fs_field) + (offset) }
7392

7493
#define PEDIT_ETH_DMAC_MASK 0xffff
94+
#define PEDIT_TCP_UDP_SPORT_MASK 0xffff
7595
#define PEDIT_ETH_DMAC_31_0 0x0
7696
#define PEDIT_ETH_DMAC_47_32_SMAC_15_0 0x4
7797
#define PEDIT_ETH_SMAC_47_16 0x8
98+
#define PEDIT_IP4_SRC 0xC
99+
#define PEDIT_IP4_DST 0x10
100+
#define PEDIT_IP6_SRC_31_0 0x8
101+
#define PEDIT_IP6_SRC_63_32 0xC
102+
#define PEDIT_IP6_SRC_95_64 0x10
103+
#define PEDIT_IP6_SRC_127_96 0x14
104+
#define PEDIT_IP6_DST_31_0 0x18
105+
#define PEDIT_IP6_DST_63_32 0x1C
106+
#define PEDIT_IP6_DST_95_64 0x20
107+
#define PEDIT_IP6_DST_127_96 0x24
108+
#define PEDIT_TCP_SPORT_DPORT 0x0
109+
#define PEDIT_UDP_SPORT_DPORT 0x0
78110

79111
int cxgb4_tc_flower_replace(struct net_device *dev,
80112
struct tc_cls_flower_offload *cls);

0 commit comments

Comments
 (0)