mirror of https://gitee.com/openkylin/linux.git
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: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a3c6b063fe
commit
4234d62c27
|
@ -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;
|
||||
}
|
||||
|
||||
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
|
||||
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_src)
|
||||
struct nfp_fl_set_ipv6_addr *ip_src,
|
||||
struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl)
|
||||
{
|
||||
__be32 exact, mask;
|
||||
int err = 0;
|
||||
u8 word;
|
||||
|
||||
/* 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,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
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)) {
|
||||
word = (off - offsetof(struct ipv6hdr, saddr)) / sizeof(exact);
|
||||
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,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -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)
|
||||
{
|
||||
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_addrs set_ip_addr;
|
||||
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,
|
|||
u32 offset, cmd;
|
||||
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_ip6_dst, 0, sizeof(set_ip6_dst));
|
||||
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,
|
|||
break;
|
||||
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
|
||||
err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst,
|
||||
&set_ip6_src);
|
||||
&set_ip6_src, &set_ip6_tc_hl_fl);
|
||||
break;
|
||||
case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
|
||||
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,
|
|||
*csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR |
|
||||
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) {
|
||||
/* TC compiles set src and dst IPv6 address as a single action,
|
||||
* the hardware requires this to be 2 separate actions.
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#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_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_TCP 15
|
||||
#define NFP_FL_ACTION_OPCODE_PRE_LAG 16
|
||||
|
@ -83,6 +84,8 @@
|
|||
#define NFP_FL_PUSH_VLAN_CFI BIT(12)
|
||||
#define NFP_FL_PUSH_VLAN_VID GENMASK(11, 0)
|
||||
|
||||
#define IPV6_FLOW_LABEL_MASK cpu_to_be32(0x000fffff)
|
||||
|
||||
/* LAG ports */
|
||||
#define NFP_FL_LAG_OUT 0xC0DE0000
|
||||
|
||||
|
@ -135,6 +138,17 @@ struct nfp_fl_set_ip4_ttl_tos {
|
|||
__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_act_head head;
|
||||
__be16 reserved;
|
||||
|
|
Loading…
Reference in New Issue