Skip to content

Commit 9b9eb51

Browse files
skotur-brcmdavem330
authored andcommitted
bnxt_en: Add support for NAT(L3/L4 rewrite)
Provides support for modifying L3/L4 Header parameters to support NAT. Sets the appropriate fields/bits in cfa_flow_alloc cmd. Sample cmd for offloading an IPv4 flow with SNAT: ovs-ofctl add-flow ovsbr0 "ip,nw_src=192.168.201.44 \ actions=mod_nw_src:203.31.220.144,output:p7p1" Replace 'nw_src' with 'nw_dst' in above cmd for DNAT with IPv4 Sample cmd for offloading an IPv4 flow with SNAPT: ovs-ofctl add-flow ovsbr0 "ip,nw_src=192.168.201.44 \ actions=mod_nw_src:203.31.220.144, mod_tp_src:6789,output:p7p1" Similar to DNAT, replace 'tp_src' with 'tp_dst' for offloading flow with DNAPT Sample cmd for offloading an IPv6 flow with SNAT: ovs-ofctl add-flow ovsbr0 "ipv6, ipv6_src=2001:5c0:9168::2/64 \ actions=load:0x1->NXM_NX_IPV6_SRC[0..63], \ load:0x20010db801920000->NXM_NX_IPV6_SRC[64..127],output:p7p1" Replace 'SRC' with DST' above for IPv6 DNAT Signed-off-by: Somnath Kotur <[email protected]> Signed-off-by: Michael Chan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 08f8280 commit 9b9eb51

File tree

2 files changed

+144
-7
lines changed

2 files changed

+144
-7
lines changed

drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c

Lines changed: 134 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp,
114114
return 0;
115115
}
116116

117-
/* Key & Mask from the stack comes unaligned in multiple iterations.
117+
/* Key & Mask from the stack comes unaligned in multiple iterations of 4 bytes
118+
* each(u32).
118119
* This routine consolidates such multiple unaligned values into one
119120
* field each for Key & Mask (for src and dst macs separately)
120121
* For example,
@@ -178,14 +179,19 @@ bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions,
178179

179180
static int
180181
bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions,
181-
struct flow_action_entry *act, u8 *eth_addr,
182+
struct flow_action_entry *act, int act_idx, u8 *eth_addr,
182183
u8 *eth_addr_mask)
183184
{
184-
u32 mask, val, offset;
185+
size_t offset_of_ip6_daddr = offsetof(struct ipv6hdr, daddr);
186+
size_t offset_of_ip6_saddr = offsetof(struct ipv6hdr, saddr);
187+
u32 mask, val, offset, idx;
185188
u8 htype;
186189

187190
offset = act->mangle.offset;
188191
htype = act->mangle.htype;
192+
mask = ~act->mangle.mask;
193+
val = act->mangle.val;
194+
189195
switch (htype) {
190196
case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
191197
if (offset > PEDIT_OFFSET_SMAC_LAST_4_BYTES) {
@@ -195,12 +201,73 @@ bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions,
195201
return -EINVAL;
196202
}
197203
actions->flags |= BNXT_TC_ACTION_FLAG_L2_REWRITE;
198-
mask = ~act->mangle.mask;
199-
val = act->mangle.val;
200204

201205
bnxt_set_l2_key_mask(val, mask, &eth_addr[offset],
202206
&eth_addr_mask[offset]);
203207
break;
208+
case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
209+
actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE;
210+
actions->nat.l3_is_ipv4 = true;
211+
if (offset == offsetof(struct iphdr, saddr)) {
212+
actions->nat.src_xlate = true;
213+
actions->nat.l3.ipv4.saddr.s_addr = htonl(val);
214+
} else if (offset == offsetof(struct iphdr, daddr)) {
215+
actions->nat.src_xlate = false;
216+
actions->nat.l3.ipv4.daddr.s_addr = htonl(val);
217+
} else {
218+
netdev_err(bp->dev,
219+
"%s: IPv4_hdr: Invalid pedit field\n",
220+
__func__);
221+
return -EINVAL;
222+
}
223+
224+
netdev_dbg(bp->dev, "nat.src_xlate = %d src IP: %pI4 dst ip : %pI4\n",
225+
actions->nat.src_xlate, &actions->nat.l3.ipv4.saddr,
226+
&actions->nat.l3.ipv4.daddr);
227+
break;
228+
229+
case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
230+
actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE;
231+
actions->nat.l3_is_ipv4 = false;
232+
if (offset >= offsetof(struct ipv6hdr, saddr) &&
233+
offset < offset_of_ip6_daddr) {
234+
/* 16 byte IPv6 address comes in 4 iterations of
235+
* 4byte chunks each
236+
*/
237+
actions->nat.src_xlate = true;
238+
idx = (offset - offset_of_ip6_saddr) / 4;
239+
/* First 4bytes will be copied to idx 0 and so on */
240+
actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val);
241+
} else if (offset >= offset_of_ip6_daddr &&
242+
offset < offset_of_ip6_daddr + 16) {
243+
actions->nat.src_xlate = false;
244+
idx = (offset - offset_of_ip6_daddr) / 4;
245+
actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val);
246+
} else {
247+
netdev_err(bp->dev,
248+
"%s: IPv6_hdr: Invalid pedit field\n",
249+
__func__);
250+
return -EINVAL;
251+
}
252+
break;
253+
case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
254+
case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
255+
/* HW does not support L4 rewrite alone without L3
256+
* rewrite
257+
*/
258+
if (!(actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE)) {
259+
netdev_err(bp->dev,
260+
"Need to specify L3 rewrite as well\n");
261+
return -EINVAL;
262+
}
263+
if (actions->nat.src_xlate)
264+
actions->nat.l4.ports.sport = htons(val);
265+
else
266+
actions->nat.l4.ports.dport = htons(val);
267+
netdev_dbg(bp->dev, "actions->nat.sport = %d dport = %d\n",
268+
actions->nat.l4.ports.sport,
269+
actions->nat.l4.ports.dport);
270+
break;
204271
default:
205272
netdev_err(bp->dev, "%s: Unsupported pedit hdr type\n",
206273
__func__);
@@ -258,7 +325,7 @@ static int bnxt_tc_parse_actions(struct bnxt *bp,
258325
break;
259326
/* Packet edit: L2 rewrite, NAT, NAPT */
260327
case FLOW_ACTION_MANGLE:
261-
rc = bnxt_tc_parse_pedit(bp, actions, act,
328+
rc = bnxt_tc_parse_pedit(bp, actions, act, i,
262329
(u8 *)eth_addr,
263330
(u8 *)eth_addr_mask);
264331
if (rc)
@@ -533,6 +600,67 @@ static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow,
533600
CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE;
534601
}
535602

603+
if (actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE) {
604+
if (actions->nat.l3_is_ipv4) {
605+
action_flags |=
606+
CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_IPV4_ADDRESS;
607+
608+
if (actions->nat.src_xlate) {
609+
action_flags |=
610+
CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC;
611+
/* L3 source rewrite */
612+
req.nat_ip_address[0] =
613+
actions->nat.l3.ipv4.saddr.s_addr;
614+
/* L4 source port */
615+
if (actions->nat.l4.ports.sport)
616+
req.nat_port =
617+
actions->nat.l4.ports.sport;
618+
} else {
619+
action_flags |=
620+
CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST;
621+
/* L3 destination rewrite */
622+
req.nat_ip_address[0] =
623+
actions->nat.l3.ipv4.daddr.s_addr;
624+
/* L4 destination port */
625+
if (actions->nat.l4.ports.dport)
626+
req.nat_port =
627+
actions->nat.l4.ports.dport;
628+
}
629+
netdev_dbg(bp->dev,
630+
"req.nat_ip_address: %pI4 src_xlate: %d req.nat_port: %x\n",
631+
req.nat_ip_address, actions->nat.src_xlate,
632+
req.nat_port);
633+
} else {
634+
if (actions->nat.src_xlate) {
635+
action_flags |=
636+
CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC;
637+
/* L3 source rewrite */
638+
memcpy(req.nat_ip_address,
639+
actions->nat.l3.ipv6.saddr.s6_addr32,
640+
sizeof(req.nat_ip_address));
641+
/* L4 source port */
642+
if (actions->nat.l4.ports.sport)
643+
req.nat_port =
644+
actions->nat.l4.ports.sport;
645+
} else {
646+
action_flags |=
647+
CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST;
648+
/* L3 destination rewrite */
649+
memcpy(req.nat_ip_address,
650+
actions->nat.l3.ipv6.daddr.s6_addr32,
651+
sizeof(req.nat_ip_address));
652+
/* L4 destination port */
653+
if (actions->nat.l4.ports.dport)
654+
req.nat_port =
655+
actions->nat.l4.ports.dport;
656+
}
657+
netdev_dbg(bp->dev,
658+
"req.nat_ip_address: %pI6 src_xlate: %d req.nat_port: %x\n",
659+
req.nat_ip_address, actions->nat.src_xlate,
660+
req.nat_port);
661+
}
662+
}
663+
536664
if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP ||
537665
actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) {
538666
req.tunnel_handle = tunnel_handle;

drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ struct bnxt_tc_actions {
7878
#define BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP BIT(6)
7979
#define BNXT_TC_ACTION_FLAG_TUNNEL_DECAP BIT(7)
8080
#define BNXT_TC_ACTION_FLAG_L2_REWRITE BIT(8)
81+
#define BNXT_TC_ACTION_FLAG_NAT_XLATE BIT(9)
8182

8283
u16 dst_fid;
8384
struct net_device *dst_dev;
@@ -89,7 +90,15 @@ struct bnxt_tc_actions {
8990
#define PEDIT_OFFSET_SMAC_LAST_4_BYTES 0x8
9091
__be16 l2_rewrite_dmac[3];
9192
__be16 l2_rewrite_smac[3];
92-
93+
struct {
94+
bool src_xlate; /* true => translate src,
95+
* false => translate dst
96+
* Mutually exclusive, i.e cannot set both
97+
*/
98+
bool l3_is_ipv4; /* false means L3 is ipv6 */
99+
struct bnxt_tc_l3_key l3;
100+
struct bnxt_tc_l4_key l4;
101+
} nat;
93102
};
94103

95104
struct bnxt_tc_flow {

0 commit comments

Comments
 (0)