Commit bd8be2cf authored by David S. Miller's avatar David S. Miller

Merge branch 'nfp-fix-pedit-set-action-offloads'

Jakub Kicinski says:

====================
nfp: fix pedit set action offloads

Pieter says:

This set fixes set actions when using multiple pedit actions with
partial masks and with multiple keys per pedit action. Additionally
it fixes set ipv6 pedit action offloads when using it in combination
with other header keys.

The problem would only trigger if one combines multiple pedit actions
of the same type with partial masks, e.g.:

$ tc filter add dev netdev protocol ip parent ffff: \
    flower indev netdev \
    ip_proto tcp \
    action pedit ex munge \
    ip src set 11.11.11.11 retain 65535 munge \
    ip src set 22.22.22.22 retain 4294901760 pipe \
    csum ip and tcp pipe \
    mirred egress redirect dev netdev
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1890fea7 140b6aba
...@@ -429,12 +429,14 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off, ...@@ -429,12 +429,14 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
switch (off) { switch (off) {
case offsetof(struct iphdr, daddr): case offsetof(struct iphdr, daddr):
set_ip_addr->ipv4_dst_mask = mask; set_ip_addr->ipv4_dst_mask |= mask;
set_ip_addr->ipv4_dst = exact; set_ip_addr->ipv4_dst &= ~mask;
set_ip_addr->ipv4_dst |= exact & mask;
break; break;
case offsetof(struct iphdr, saddr): case offsetof(struct iphdr, saddr):
set_ip_addr->ipv4_src_mask = mask; set_ip_addr->ipv4_src_mask |= mask;
set_ip_addr->ipv4_src = exact; set_ip_addr->ipv4_src &= ~mask;
set_ip_addr->ipv4_src |= exact & mask;
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -448,11 +450,12 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off, ...@@ -448,11 +450,12 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
} }
static void static void
nfp_fl_set_ip6_helper(int opcode_tag, int idx, __be32 exact, __be32 mask, nfp_fl_set_ip6_helper(int opcode_tag, u8 word, __be32 exact, __be32 mask,
struct nfp_fl_set_ipv6_addr *ip6) struct nfp_fl_set_ipv6_addr *ip6)
{ {
ip6->ipv6[idx % 4].mask = mask; ip6->ipv6[word].mask |= mask;
ip6->ipv6[idx % 4].exact = exact; ip6->ipv6[word].exact &= ~mask;
ip6->ipv6[word].exact |= exact & mask;
ip6->reserved = cpu_to_be16(0); ip6->reserved = cpu_to_be16(0);
ip6->head.jump_id = opcode_tag; ip6->head.jump_id = opcode_tag;
...@@ -465,6 +468,7 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off, ...@@ -465,6 +468,7 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
struct nfp_fl_set_ipv6_addr *ip_src) struct nfp_fl_set_ipv6_addr *ip_src)
{ {
__be32 exact, mask; __be32 exact, mask;
u8 word;
/* We are expecting tcf_pedit to return a big endian value */ /* We are expecting tcf_pedit to return a big endian value */
mask = (__force __be32)~tcf_pedit_mask(action, idx); mask = (__force __be32)~tcf_pedit_mask(action, idx);
...@@ -473,17 +477,20 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off, ...@@ -473,17 +477,20 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
if (exact & ~mask) if (exact & ~mask)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (off < offsetof(struct ipv6hdr, saddr)) if (off < offsetof(struct ipv6hdr, saddr)) {
return -EOPNOTSUPP; return -EOPNOTSUPP;
else if (off < offsetof(struct ipv6hdr, daddr)) } else if (off < offsetof(struct ipv6hdr, daddr)) {
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, idx, word = (off - offsetof(struct ipv6hdr, saddr)) / sizeof(exact);
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, word,
exact, mask, ip_src); exact, mask, ip_src);
else if (off < offsetof(struct ipv6hdr, daddr) + } else if (off < offsetof(struct ipv6hdr, daddr) +
sizeof(struct in6_addr)) sizeof(struct in6_addr)) {
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_DST, idx, word = (off - offsetof(struct ipv6hdr, daddr)) / sizeof(exact);
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_DST, word,
exact, mask, ip_dst); exact, mask, ip_dst);
else } else {
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
return 0; return 0;
} }
...@@ -541,7 +548,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -541,7 +548,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
struct nfp_fl_set_eth set_eth; struct nfp_fl_set_eth set_eth;
enum pedit_header_type htype; enum pedit_header_type htype;
int idx, nkeys, err; int idx, nkeys, err;
size_t act_size; size_t act_size = 0;
u32 offset, cmd; u32 offset, cmd;
u8 ip_proto = 0; u8 ip_proto = 0;
...@@ -599,7 +606,9 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -599,7 +606,9 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
act_size = sizeof(set_eth); act_size = sizeof(set_eth);
memcpy(nfp_action, &set_eth, act_size); memcpy(nfp_action, &set_eth, act_size);
*a_len += act_size; *a_len += act_size;
} else if (set_ip_addr.head.len_lw) { }
if (set_ip_addr.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip_addr); act_size = sizeof(set_ip_addr);
memcpy(nfp_action, &set_ip_addr, act_size); memcpy(nfp_action, &set_ip_addr, act_size);
*a_len += act_size; *a_len += act_size;
...@@ -607,10 +616,12 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -607,10 +616,12 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
/* Hardware will automatically fix IPv4 and TCP/UDP checksum. */ /* Hardware will automatically fix IPv4 and TCP/UDP checksum. */
*csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR | *csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR |
nfp_fl_csum_l4_to_flag(ip_proto); nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_dst.head.len_lw && set_ip6_src.head.len_lw) { }
if (set_ip6_dst.head.len_lw && set_ip6_src.head.len_lw) {
/* TC compiles set src and dst IPv6 address as a single action, /* TC compiles set src and dst IPv6 address as a single action,
* the hardware requires this to be 2 separate actions. * the hardware requires this to be 2 separate actions.
*/ */
nfp_action += act_size;
act_size = sizeof(set_ip6_src); act_size = sizeof(set_ip6_src);
memcpy(nfp_action, &set_ip6_src, act_size); memcpy(nfp_action, &set_ip6_src, act_size);
*a_len += act_size; *a_len += act_size;
...@@ -623,6 +634,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -623,6 +634,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
/* Hardware will automatically fix TCP/UDP checksum. */ /* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto); *csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_dst.head.len_lw) { } else if (set_ip6_dst.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip6_dst); act_size = sizeof(set_ip6_dst);
memcpy(nfp_action, &set_ip6_dst, act_size); memcpy(nfp_action, &set_ip6_dst, act_size);
*a_len += act_size; *a_len += act_size;
...@@ -630,13 +642,16 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -630,13 +642,16 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
/* Hardware will automatically fix TCP/UDP checksum. */ /* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto); *csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_src.head.len_lw) { } else if (set_ip6_src.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip6_src); act_size = sizeof(set_ip6_src);
memcpy(nfp_action, &set_ip6_src, act_size); memcpy(nfp_action, &set_ip6_src, act_size);
*a_len += act_size; *a_len += act_size;
/* Hardware will automatically fix TCP/UDP checksum. */ /* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto); *csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_tport.head.len_lw) { }
if (set_tport.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_tport); act_size = sizeof(set_tport);
memcpy(nfp_action, &set_tport, act_size); memcpy(nfp_action, &set_tport, act_size);
*a_len += act_size; *a_len += act_size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment