Skip to content

Commit c6a1575

Browse files
committed
Merge branch 'nfp-extend-match-and-action'
Simon Horman says: ==================== nfp: extend match and action for flower offload Pieter says: This series extends flower offload match and action capabilities. It specifically adds offload capabilities for matching on MPLS, TTL, TOS and flow label. Furthermore offload capabilities for action have been expanded to include set ethernet, ipv4, ipv6, tcp and udp headers. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 4e64b1e + f8b7b0a commit c6a1575

File tree

4 files changed

+324
-23
lines changed

4 files changed

+324
-23
lines changed

drivers/net/ethernet/netronome/nfp/flower/action.c

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <net/switchdev.h>
3737
#include <net/tc_act/tc_gact.h>
3838
#include <net/tc_act/tc_mirred.h>
39+
#include <net/tc_act/tc_pedit.h>
3940
#include <net/tc_act/tc_vlan.h>
4041
#include <net/tc_act/tc_tunnel_key.h>
4142

@@ -223,6 +224,247 @@ nfp_fl_set_vxlan(struct nfp_fl_set_vxlan *set_vxlan,
223224
return 0;
224225
}
225226

227+
static void nfp_fl_set_helper32(u32 value, u32 mask, u8 *p_exact, u8 *p_mask)
228+
{
229+
u32 oldvalue = get_unaligned((u32 *)p_exact);
230+
u32 oldmask = get_unaligned((u32 *)p_mask);
231+
232+
value &= mask;
233+
value |= oldvalue & ~mask;
234+
235+
put_unaligned(oldmask | mask, (u32 *)p_mask);
236+
put_unaligned(value, (u32 *)p_exact);
237+
}
238+
239+
static int
240+
nfp_fl_set_eth(const struct tc_action *action, int idx, u32 off,
241+
struct nfp_fl_set_eth *set_eth)
242+
{
243+
u16 tmp_set_eth_op;
244+
u32 exact, mask;
245+
246+
if (off + 4 > ETH_ALEN * 2)
247+
return -EOPNOTSUPP;
248+
249+
mask = ~tcf_pedit_mask(action, idx);
250+
exact = tcf_pedit_val(action, idx);
251+
252+
if (exact & ~mask)
253+
return -EOPNOTSUPP;
254+
255+
nfp_fl_set_helper32(exact, mask, &set_eth->eth_addr_val[off],
256+
&set_eth->eth_addr_mask[off]);
257+
258+
set_eth->reserved = cpu_to_be16(0);
259+
tmp_set_eth_op = FIELD_PREP(NFP_FL_ACT_LEN_LW,
260+
sizeof(*set_eth) >> NFP_FL_LW_SIZ) |
261+
FIELD_PREP(NFP_FL_ACT_JMP_ID,
262+
NFP_FL_ACTION_OPCODE_SET_ETHERNET);
263+
set_eth->a_op = cpu_to_be16(tmp_set_eth_op);
264+
265+
return 0;
266+
}
267+
268+
static int
269+
nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
270+
struct nfp_fl_set_ip4_addrs *set_ip_addr)
271+
{
272+
u16 tmp_set_ipv4_op;
273+
__be32 exact, mask;
274+
275+
/* We are expecting tcf_pedit to return a big endian value */
276+
mask = (__force __be32)~tcf_pedit_mask(action, idx);
277+
exact = (__force __be32)tcf_pedit_val(action, idx);
278+
279+
if (exact & ~mask)
280+
return -EOPNOTSUPP;
281+
282+
switch (off) {
283+
case offsetof(struct iphdr, daddr):
284+
set_ip_addr->ipv4_dst_mask = mask;
285+
set_ip_addr->ipv4_dst = exact;
286+
break;
287+
case offsetof(struct iphdr, saddr):
288+
set_ip_addr->ipv4_src_mask = mask;
289+
set_ip_addr->ipv4_src = exact;
290+
break;
291+
default:
292+
return -EOPNOTSUPP;
293+
}
294+
295+
set_ip_addr->reserved = cpu_to_be16(0);
296+
tmp_set_ipv4_op = FIELD_PREP(NFP_FL_ACT_LEN_LW,
297+
sizeof(*set_ip_addr) >> NFP_FL_LW_SIZ) |
298+
FIELD_PREP(NFP_FL_ACT_JMP_ID,
299+
NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS);
300+
set_ip_addr->a_op = cpu_to_be16(tmp_set_ipv4_op);
301+
302+
return 0;
303+
}
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+
350+
static int
351+
nfp_fl_set_tport(const struct tc_action *action, int idx, u32 off,
352+
struct nfp_fl_set_tport *set_tport, int opcode)
353+
{
354+
u32 exact, mask;
355+
u16 tmp_set_op;
356+
357+
if (off)
358+
return -EOPNOTSUPP;
359+
360+
mask = ~tcf_pedit_mask(action, idx);
361+
exact = tcf_pedit_val(action, idx);
362+
363+
if (exact & ~mask)
364+
return -EOPNOTSUPP;
365+
366+
nfp_fl_set_helper32(exact, mask, set_tport->tp_port_val,
367+
set_tport->tp_port_mask);
368+
369+
set_tport->reserved = cpu_to_be16(0);
370+
tmp_set_op = FIELD_PREP(NFP_FL_ACT_LEN_LW,
371+
sizeof(*set_tport) >> NFP_FL_LW_SIZ);
372+
tmp_set_op |= FIELD_PREP(NFP_FL_ACT_JMP_ID, opcode);
373+
set_tport->a_op = cpu_to_be16(tmp_set_op);
374+
375+
return 0;
376+
}
377+
378+
static int
379+
nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len)
380+
{
381+
struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src;
382+
struct nfp_fl_set_ip4_addrs set_ip_addr;
383+
struct nfp_fl_set_tport set_tport;
384+
struct nfp_fl_set_eth set_eth;
385+
enum pedit_header_type htype;
386+
int idx, nkeys, err;
387+
size_t act_size;
388+
u32 offset, cmd;
389+
390+
memset(&set_ip6_dst, 0, sizeof(set_ip6_dst));
391+
memset(&set_ip6_src, 0, sizeof(set_ip6_src));
392+
memset(&set_ip_addr, 0, sizeof(set_ip_addr));
393+
memset(&set_tport, 0, sizeof(set_tport));
394+
memset(&set_eth, 0, sizeof(set_eth));
395+
nkeys = tcf_pedit_nkeys(action);
396+
397+
for (idx = 0; idx < nkeys; idx++) {
398+
cmd = tcf_pedit_cmd(action, idx);
399+
htype = tcf_pedit_htype(action, idx);
400+
offset = tcf_pedit_offset(action, idx);
401+
402+
if (cmd != TCA_PEDIT_KEY_EX_CMD_SET)
403+
return -EOPNOTSUPP;
404+
405+
switch (htype) {
406+
case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
407+
err = nfp_fl_set_eth(action, idx, offset, &set_eth);
408+
break;
409+
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
410+
err = nfp_fl_set_ip4(action, idx, offset, &set_ip_addr);
411+
break;
412+
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
413+
err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst,
414+
&set_ip6_src);
415+
break;
416+
case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
417+
err = nfp_fl_set_tport(action, idx, offset, &set_tport,
418+
NFP_FL_ACTION_OPCODE_SET_TCP);
419+
break;
420+
case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
421+
err = nfp_fl_set_tport(action, idx, offset, &set_tport,
422+
NFP_FL_ACTION_OPCODE_SET_UDP);
423+
break;
424+
default:
425+
return -EOPNOTSUPP;
426+
}
427+
if (err)
428+
return err;
429+
}
430+
431+
if (set_eth.a_op) {
432+
act_size = sizeof(set_eth);
433+
memcpy(nfp_action, &set_eth, act_size);
434+
*a_len += act_size;
435+
} else if (set_ip_addr.a_op) {
436+
act_size = sizeof(set_ip_addr);
437+
memcpy(nfp_action, &set_ip_addr, act_size);
438+
*a_len += act_size;
439+
} else if (set_ip6_dst.a_op && set_ip6_src.a_op) {
440+
/* TC compiles set src and dst IPv6 address as a single action,
441+
* the hardware requires this to be 2 separate actions.
442+
*/
443+
act_size = sizeof(set_ip6_src);
444+
memcpy(nfp_action, &set_ip6_src, act_size);
445+
*a_len += act_size;
446+
447+
act_size = sizeof(set_ip6_dst);
448+
memcpy(&nfp_action[sizeof(set_ip6_src)], &set_ip6_dst,
449+
act_size);
450+
*a_len += act_size;
451+
} else if (set_ip6_dst.a_op) {
452+
act_size = sizeof(set_ip6_dst);
453+
memcpy(nfp_action, &set_ip6_dst, act_size);
454+
*a_len += act_size;
455+
} else if (set_ip6_src.a_op) {
456+
act_size = sizeof(set_ip6_src);
457+
memcpy(nfp_action, &set_ip6_src, act_size);
458+
*a_len += act_size;
459+
} else if (set_tport.a_op) {
460+
act_size = sizeof(set_tport);
461+
memcpy(nfp_action, &set_tport, act_size);
462+
*a_len += act_size;
463+
}
464+
465+
return 0;
466+
}
467+
226468
static int
227469
nfp_flower_loop_action(const struct tc_action *a,
228470
struct nfp_fl_payload *nfp_fl, int *a_len,
@@ -301,6 +543,9 @@ nfp_flower_loop_action(const struct tc_action *a,
301543
} else if (is_tcf_tunnel_release(a)) {
302544
/* Tunnel decap is handled by default so accept action. */
303545
return 0;
546+
} else if (is_tcf_pedit(a)) {
547+
if (nfp_fl_pedit(a, &nfp_fl->action_data[*a_len], a_len))
548+
return -EOPNOTSUPP;
304549
} else {
305550
/* Currently we do not handle any other actions. */
306551
return -EOPNOTSUPP;

drivers/net/ethernet/netronome/nfp/flower/cmsg.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@
5757
#define NFP_FLOWER_MASK_VLAN_CFI BIT(12)
5858
#define NFP_FLOWER_MASK_VLAN_VID GENMASK(11, 0)
5959

60+
#define NFP_FLOWER_MASK_MPLS_LB GENMASK(31, 12)
61+
#define NFP_FLOWER_MASK_MPLS_TC GENMASK(11, 9)
62+
#define NFP_FLOWER_MASK_MPLS_BOS BIT(8)
63+
#define NFP_FLOWER_MASK_MPLS_Q BIT(0)
64+
6065
#define NFP_FL_SC_ACT_DROP 0x80000000
6166
#define NFP_FL_SC_ACT_USER 0x7D000000
6267
#define NFP_FL_SC_ACT_POPV 0x6A000000
@@ -72,6 +77,12 @@
7277
#define NFP_FL_ACTION_OPCODE_PUSH_VLAN 1
7378
#define NFP_FL_ACTION_OPCODE_POP_VLAN 2
7479
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL 6
80+
#define NFP_FL_ACTION_OPCODE_SET_ETHERNET 7
81+
#define NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS 9
82+
#define NFP_FL_ACTION_OPCODE_SET_IPV6_SRC 11
83+
#define NFP_FL_ACTION_OPCODE_SET_IPV6_DST 12
84+
#define NFP_FL_ACTION_OPCODE_SET_UDP 14
85+
#define NFP_FL_ACTION_OPCODE_SET_TCP 15
7586
#define NFP_FL_ACTION_OPCODE_PRE_TUNNEL 17
7687
#define NFP_FL_ACTION_OPCODE_NUM 32
7788

@@ -102,6 +113,38 @@ enum nfp_flower_tun_type {
102113
NFP_FL_TUNNEL_VXLAN = 2,
103114
};
104115

116+
struct nfp_fl_set_eth {
117+
__be16 a_op;
118+
__be16 reserved;
119+
u8 eth_addr_mask[ETH_ALEN * 2];
120+
u8 eth_addr_val[ETH_ALEN * 2];
121+
};
122+
123+
struct nfp_fl_set_ip4_addrs {
124+
__be16 a_op;
125+
__be16 reserved;
126+
__be32 ipv4_src_mask;
127+
__be32 ipv4_src;
128+
__be32 ipv4_dst_mask;
129+
__be32 ipv4_dst;
130+
};
131+
132+
struct nfp_fl_set_ipv6_addr {
133+
__be16 a_op;
134+
__be16 reserved;
135+
struct {
136+
__be32 mask;
137+
__be32 exact;
138+
} ipv6[4];
139+
};
140+
141+
struct nfp_fl_set_tport {
142+
__be16 a_op;
143+
__be16 reserved;
144+
u8 tp_port_mask[4];
145+
u8 tp_port_val[4];
146+
};
147+
105148
struct nfp_fl_output {
106149
__be16 a_op;
107150
__be16 flags;

0 commit comments

Comments
 (0)