Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+61 −4
Original line number Diff line number Diff line
@@ -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.
+14 −0
Original line number Diff line number Diff line
@@ -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;