Commit 4234d62c authored by Pieter Jansen van Vuuren's avatar Pieter Jansen van Vuuren Committed by David S. Miller

nfp: flower: add ipv6 set flow label and hop limit offload

Add ipv6 set flow label and hop limit action offload. Since pedit sets
headers per 4 byte word, we need to ensure that setting either version,
priority, payload_len or nexthdr does not get offloaded.
Signed-off-by: default avatarPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a3c6b063
...@@ -476,12 +476,57 @@ nfp_fl_set_ip6_helper(int opcode_tag, u8 word, __be32 exact, __be32 mask, ...@@ -476,12 +476,57 @@ nfp_fl_set_ip6_helper(int opcode_tag, u8 word, __be32 exact, __be32 mask,
ip6->head.len_lw = sizeof(*ip6) >> NFP_FL_LW_SIZ; ip6->head.len_lw = sizeof(*ip6) >> NFP_FL_LW_SIZ;
} }
struct ipv6_hop_limit_word {
__be16 payload_len;
u8 nexthdr;
u8 hop_limit;
};
static int
nfp_fl_set_ip6_hop_limit_flow_label(u32 off, __be32 exact, __be32 mask,
struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl)
{
struct ipv6_hop_limit_word *fl_hl_mask;
struct ipv6_hop_limit_word *fl_hl;
switch (off) {
case offsetof(struct ipv6hdr, payload_len):
fl_hl_mask = (struct ipv6_hop_limit_word *)&mask;
fl_hl = (struct ipv6_hop_limit_word *)&exact;
if (fl_hl_mask->nexthdr || fl_hl_mask->payload_len)
return -EOPNOTSUPP;
ip_hl_fl->ipv6_hop_limit_mask |= fl_hl_mask->hop_limit;
ip_hl_fl->ipv6_hop_limit &= ~fl_hl_mask->hop_limit;
ip_hl_fl->ipv6_hop_limit |= fl_hl->hop_limit &
fl_hl_mask->hop_limit;
break;
case round_down(offsetof(struct ipv6hdr, flow_lbl), 4):
if (mask & ~IPV6_FLOW_LABEL_MASK ||
exact & ~IPV6_FLOW_LABEL_MASK)
return -EOPNOTSUPP;
ip_hl_fl->ipv6_label_mask |= mask;
ip_hl_fl->ipv6_label &= ~mask;
ip_hl_fl->ipv6_label |= exact & mask;
break;
}
ip_hl_fl->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV6_TC_HL_FL;
ip_hl_fl->head.len_lw = sizeof(*ip_hl_fl) >> NFP_FL_LW_SIZ;
return 0;
}
static int static int
nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off, nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
struct nfp_fl_set_ipv6_addr *ip_dst, struct nfp_fl_set_ipv6_addr *ip_dst,
struct nfp_fl_set_ipv6_addr *ip_src) struct nfp_fl_set_ipv6_addr *ip_src,
struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl)
{ {
__be32 exact, mask; __be32 exact, mask;
int err = 0;
u8 word; u8 word;
/* We are expecting tcf_pedit to return a big endian value */ /* We are expecting tcf_pedit to return a big endian value */
...@@ -492,7 +537,8 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off, ...@@ -492,7 +537,8 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (off < offsetof(struct ipv6hdr, saddr)) { if (off < offsetof(struct ipv6hdr, saddr)) {
return -EOPNOTSUPP; err = nfp_fl_set_ip6_hop_limit_flow_label(off, exact, mask,
ip_hl_fl);
} else if (off < offsetof(struct ipv6hdr, daddr)) { } else if (off < offsetof(struct ipv6hdr, daddr)) {
word = (off - offsetof(struct ipv6hdr, saddr)) / sizeof(exact); word = (off - offsetof(struct ipv6hdr, saddr)) / sizeof(exact);
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, word, nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, word,
...@@ -506,7 +552,7 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off, ...@@ -506,7 +552,7 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
return 0; return err;
} }
static int static int
...@@ -557,6 +603,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -557,6 +603,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
char *nfp_action, int *a_len, u32 *csum_updated) char *nfp_action, int *a_len, u32 *csum_updated)
{ {
struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src; struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src;
struct nfp_fl_set_ipv6_tc_hl_fl set_ip6_tc_hl_fl;
struct nfp_fl_set_ip4_ttl_tos set_ip_ttl_tos; struct nfp_fl_set_ip4_ttl_tos set_ip_ttl_tos;
struct nfp_fl_set_ip4_addrs set_ip_addr; struct nfp_fl_set_ip4_addrs set_ip_addr;
struct nfp_fl_set_tport set_tport; struct nfp_fl_set_tport set_tport;
...@@ -567,6 +614,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -567,6 +614,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
u32 offset, cmd; u32 offset, cmd;
u8 ip_proto = 0; u8 ip_proto = 0;
memset(&set_ip6_tc_hl_fl, 0, sizeof(set_ip6_tc_hl_fl));
memset(&set_ip_ttl_tos, 0, sizeof(set_ip_ttl_tos)); memset(&set_ip_ttl_tos, 0, sizeof(set_ip_ttl_tos));
memset(&set_ip6_dst, 0, sizeof(set_ip6_dst)); memset(&set_ip6_dst, 0, sizeof(set_ip6_dst));
memset(&set_ip6_src, 0, sizeof(set_ip6_src)); memset(&set_ip6_src, 0, sizeof(set_ip6_src));
...@@ -593,7 +641,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -593,7 +641,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
break; break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6: case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst, err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst,
&set_ip6_src); &set_ip6_src, &set_ip6_tc_hl_fl);
break; break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP: case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
err = nfp_fl_set_tport(action, idx, offset, &set_tport, err = nfp_fl_set_tport(action, idx, offset, &set_tport,
...@@ -644,6 +692,15 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow, ...@@ -644,6 +692,15 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
*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);
} }
if (set_ip6_tc_hl_fl.head.len_lw) {
nfp_action += act_size;
act_size = sizeof(set_ip6_tc_hl_fl);
memcpy(nfp_action, &set_ip6_tc_hl_fl, act_size);
*a_len += act_size;
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
}
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.
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS 10 #define NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS 10
#define NFP_FL_ACTION_OPCODE_SET_IPV6_SRC 11 #define NFP_FL_ACTION_OPCODE_SET_IPV6_SRC 11
#define NFP_FL_ACTION_OPCODE_SET_IPV6_DST 12 #define NFP_FL_ACTION_OPCODE_SET_IPV6_DST 12
#define NFP_FL_ACTION_OPCODE_SET_IPV6_TC_HL_FL 13
#define NFP_FL_ACTION_OPCODE_SET_UDP 14 #define NFP_FL_ACTION_OPCODE_SET_UDP 14
#define NFP_FL_ACTION_OPCODE_SET_TCP 15 #define NFP_FL_ACTION_OPCODE_SET_TCP 15
#define NFP_FL_ACTION_OPCODE_PRE_LAG 16 #define NFP_FL_ACTION_OPCODE_PRE_LAG 16
...@@ -83,6 +84,8 @@ ...@@ -83,6 +84,8 @@
#define NFP_FL_PUSH_VLAN_CFI BIT(12) #define NFP_FL_PUSH_VLAN_CFI BIT(12)
#define NFP_FL_PUSH_VLAN_VID GENMASK(11, 0) #define NFP_FL_PUSH_VLAN_VID GENMASK(11, 0)
#define IPV6_FLOW_LABEL_MASK cpu_to_be32(0x000fffff)
/* LAG ports */ /* LAG ports */
#define NFP_FL_LAG_OUT 0xC0DE0000 #define NFP_FL_LAG_OUT 0xC0DE0000
...@@ -135,6 +138,17 @@ struct nfp_fl_set_ip4_ttl_tos { ...@@ -135,6 +138,17 @@ struct nfp_fl_set_ip4_ttl_tos {
__be16 reserved; __be16 reserved;
}; };
struct nfp_fl_set_ipv6_tc_hl_fl {
struct nfp_fl_act_head head;
u8 ipv6_tc_mask;
u8 ipv6_hop_limit_mask;
__be16 reserved;
u8 ipv6_tc;
u8 ipv6_hop_limit;
__be32 ipv6_label_mask;
__be32 ipv6_label;
};
struct nfp_fl_set_ipv6_addr { struct nfp_fl_set_ipv6_addr {
struct nfp_fl_act_head head; struct nfp_fl_act_head head;
__be16 reserved; __be16 reserved;
......
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