|
@@ -429,12 +429,14 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
|
|
|
|
|
|
switch (off) {
|
|
|
case offsetof(struct iphdr, daddr):
|
|
|
- set_ip_addr->ipv4_dst_mask = mask;
|
|
|
- set_ip_addr->ipv4_dst = exact;
|
|
|
+ set_ip_addr->ipv4_dst_mask |= mask;
|
|
|
+ set_ip_addr->ipv4_dst &= ~mask;
|
|
|
+ set_ip_addr->ipv4_dst |= exact & mask;
|
|
|
break;
|
|
|
case offsetof(struct iphdr, saddr):
|
|
|
- set_ip_addr->ipv4_src_mask = mask;
|
|
|
- set_ip_addr->ipv4_src = exact;
|
|
|
+ set_ip_addr->ipv4_src_mask |= mask;
|
|
|
+ set_ip_addr->ipv4_src &= ~mask;
|
|
|
+ set_ip_addr->ipv4_src |= exact & mask;
|
|
|
break;
|
|
|
default:
|
|
|
return -EOPNOTSUPP;
|
|
@@ -448,11 +450,12 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
{
|
|
|
- ip6->ipv6[idx % 4].mask = mask;
|
|
|
- ip6->ipv6[idx % 4].exact = exact;
|
|
|
+ ip6->ipv6[word].mask |= mask;
|
|
|
+ ip6->ipv6[word].exact &= ~mask;
|
|
|
+ ip6->ipv6[word].exact |= exact & mask;
|
|
|
|
|
|
ip6->reserved = cpu_to_be16(0);
|
|
|
ip6->head.jump_id = opcode_tag;
|
|
@@ -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)
|
|
|
{
|
|
|
__be32 exact, mask;
|
|
|
+ u8 word;
|
|
|
|
|
|
/* We are expecting tcf_pedit to return a big endian value */
|
|
|
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,
|
|
|
if (exact & ~mask)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (off < offsetof(struct ipv6hdr, saddr))
|
|
|
+ if (off < offsetof(struct ipv6hdr, saddr)) {
|
|
|
return -EOPNOTSUPP;
|
|
|
- else if (off < offsetof(struct ipv6hdr, daddr))
|
|
|
- nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, idx,
|
|
|
+ } else if (off < offsetof(struct ipv6hdr, daddr)) {
|
|
|
+ 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);
|
|
|
- else if (off < offsetof(struct ipv6hdr, daddr) +
|
|
|
- sizeof(struct in6_addr))
|
|
|
- nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_DST, idx,
|
|
|
+ } else if (off < offsetof(struct ipv6hdr, daddr) +
|
|
|
+ sizeof(struct in6_addr)) {
|
|
|
+ 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);
|
|
|
- else
|
|
|
+ } else {
|
|
|
return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -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;
|
|
|
enum pedit_header_type htype;
|
|
|
int idx, nkeys, err;
|
|
|
- size_t act_size;
|
|
|
+ size_t act_size = 0;
|
|
|
u32 offset, cmd;
|
|
|
u8 ip_proto = 0;
|
|
|
|
|
@@ -599,7 +606,9 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
|
|
|
act_size = sizeof(set_eth);
|
|
|
memcpy(nfp_action, &set_eth, 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);
|
|
|
memcpy(nfp_action, &set_ip_addr, act_size);
|
|
|
*a_len += act_size;
|
|
@@ -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. */
|
|
|
*csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR |
|
|
|
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,
|
|
|
* the hardware requires this to be 2 separate actions.
|
|
|
*/
|
|
|
+ nfp_action += act_size;
|
|
|
act_size = sizeof(set_ip6_src);
|
|
|
memcpy(nfp_action, &set_ip6_src, act_size);
|
|
|
*a_len += act_size;
|
|
@@ -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. */
|
|
|
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
|
|
|
} else if (set_ip6_dst.head.len_lw) {
|
|
|
+ nfp_action += act_size;
|
|
|
act_size = sizeof(set_ip6_dst);
|
|
|
memcpy(nfp_action, &set_ip6_dst, act_size);
|
|
|
*a_len += act_size;
|
|
@@ -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. */
|
|
|
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
|
|
|
} else if (set_ip6_src.head.len_lw) {
|
|
|
+ nfp_action += act_size;
|
|
|
act_size = sizeof(set_ip6_src);
|
|
|
memcpy(nfp_action, &set_ip6_src, act_size);
|
|
|
*a_len += act_size;
|
|
|
|
|
|
/* Hardware will automatically fix TCP/UDP checksum. */
|
|
|
*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);
|
|
|
memcpy(nfp_action, &set_tport, act_size);
|
|
|
*a_len += act_size;
|