Commit 001b98c9 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'net-ipv6-ioam6-introduce-tunsrc'

Justin Iurman says:

====================
net: ipv6: ioam6: introduce tunsrc

This series introduces a new feature called "tunsrc" (just like seg6
already does).

v3:
- address Jakub's comments

v2:
- add links to performance result figures (see patch#2 description)
- move the ipv6_addr_any() check out of the datapath
====================

Link: https://patch.msgid.link/20240817131818.11834-1-justin.iurman@uliege.be


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents f32c821a 273f8c14
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -50,6 +50,12 @@ enum {
	IOAM6_IPTUNNEL_FREQ_K,		/* u32 */
	IOAM6_IPTUNNEL_FREQ_N,		/* u32 */

	/* Tunnel src address.
	 * For encap,auto modes.
	 * Optional (automatic if not provided).
	 */
	IOAM6_IPTUNNEL_SRC,		/* struct in6_addr */

	__IOAM6_IPTUNNEL_MAX,
};

+62 −12
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ struct ioam6_lwt {
	struct ioam6_lwt_freq freq;
	atomic_t pkt_cnt;
	u8 mode;
	bool has_tunsrc;
	struct in6_addr tunsrc;
	struct in6_addr tundst;
	struct ioam6_lwt_encap tuninfo;
};
@@ -72,8 +74,10 @@ static const struct nla_policy ioam6_iptunnel_policy[IOAM6_IPTUNNEL_MAX + 1] = {
	[IOAM6_IPTUNNEL_MODE]	= NLA_POLICY_RANGE(NLA_U8,
						   IOAM6_IPTUNNEL_MODE_MIN,
						   IOAM6_IPTUNNEL_MODE_MAX),
	[IOAM6_IPTUNNEL_SRC]	= NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
	[IOAM6_IPTUNNEL_DST]	= NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
	[IOAM6_IPTUNNEL_TRACE]	= NLA_POLICY_EXACT_LEN(sizeof(struct ioam6_trace_hdr)),
	[IOAM6_IPTUNNEL_TRACE]	= NLA_POLICY_EXACT_LEN(
					sizeof(struct ioam6_trace_hdr)),
};

static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace)
@@ -143,6 +147,11 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla,
	else
		mode = nla_get_u8(tb[IOAM6_IPTUNNEL_MODE]);

	if (tb[IOAM6_IPTUNNEL_SRC] && mode == IOAM6_IPTUNNEL_MODE_INLINE) {
		NL_SET_ERR_MSG(extack, "no tunnel src expected with this mode");
		return -EINVAL;
	}

	if (!tb[IOAM6_IPTUNNEL_DST] && mode != IOAM6_IPTUNNEL_MODE_INLINE) {
		NL_SET_ERR_MSG(extack, "this mode needs a tunnel destination");
		return -EINVAL;
@@ -167,16 +176,29 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla,

	ilwt = ioam6_lwt_state(lwt);
	err = dst_cache_init(&ilwt->cache, GFP_ATOMIC);
	if (err) {
		kfree(lwt);
		return err;
	}
	if (err)
		goto free_lwt;

	atomic_set(&ilwt->pkt_cnt, 0);
	ilwt->freq.k = freq_k;
	ilwt->freq.n = freq_n;

	ilwt->mode = mode;

	if (!tb[IOAM6_IPTUNNEL_SRC]) {
		ilwt->has_tunsrc = false;
	} else {
		ilwt->has_tunsrc = true;
		ilwt->tunsrc = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_SRC]);

		if (ipv6_addr_any(&ilwt->tunsrc)) {
			NL_SET_ERR_MSG_ATTR(extack, tb[IOAM6_IPTUNNEL_SRC],
					    "invalid tunnel source address");
			err = -EINVAL;
			goto free_cache;
		}
	}

	if (tb[IOAM6_IPTUNNEL_DST])
		ilwt->tundst = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_DST]);

@@ -201,6 +223,11 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla,
	*ts = lwt;

	return 0;
free_cache:
	dst_cache_destroy(&ilwt->cache);
free_lwt:
	kfree(lwt);
	return err;
}

static int ioam6_do_fill(struct net *net, struct sk_buff *skb)
@@ -256,6 +283,8 @@ static int ioam6_do_inline(struct net *net, struct sk_buff *skb,

static int ioam6_do_encap(struct net *net, struct sk_buff *skb,
			  struct ioam6_lwt_encap *tuninfo,
			  bool has_tunsrc,
			  struct in6_addr *tunsrc,
			  struct in6_addr *tundst)
{
	struct dst_entry *dst = skb_dst(skb);
@@ -285,6 +314,10 @@ static int ioam6_do_encap(struct net *net, struct sk_buff *skb,
	hdr->nexthdr = NEXTHDR_HOP;
	hdr->payload_len = cpu_to_be16(skb->len - sizeof(*hdr));
	hdr->daddr = *tundst;

	if (has_tunsrc)
		memcpy(&hdr->saddr, tunsrc, sizeof(*tunsrc));
	else
		ipv6_dev_get_saddr(net, dst->dev, &hdr->daddr,
				   IPV6_PREFER_SRC_PUBLIC, &hdr->saddr);

@@ -328,7 +361,9 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
	case IOAM6_IPTUNNEL_MODE_ENCAP:
do_encap:
		/* Encapsulation (ip6ip6) */
		err = ioam6_do_encap(net, skb, &ilwt->tuninfo, &ilwt->tundst);
		err = ioam6_do_encap(net, skb, &ilwt->tuninfo,
				     ilwt->has_tunsrc, &ilwt->tunsrc,
				     &ilwt->tundst);
		if (unlikely(err))
			goto drop;

@@ -414,6 +449,13 @@ static int ioam6_fill_encap_info(struct sk_buff *skb,
		goto ret;

	if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) {
		if (ilwt->has_tunsrc) {
			err = nla_put_in6_addr(skb, IOAM6_IPTUNNEL_SRC,
					       &ilwt->tunsrc);
			if (err)
				goto ret;
		}

		err = nla_put_in6_addr(skb, IOAM6_IPTUNNEL_DST, &ilwt->tundst);
		if (err)
			goto ret;
@@ -435,8 +477,12 @@ static int ioam6_encap_nlsize(struct lwtunnel_state *lwtstate)
		  nla_total_size(sizeof(ilwt->mode)) +
		  nla_total_size(sizeof(ilwt->tuninfo.traceh));

	if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE)
	if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) {
		if (ilwt->has_tunsrc)
			nlsize += nla_total_size(sizeof(ilwt->tunsrc));

		nlsize += nla_total_size(sizeof(ilwt->tundst));
	}

	return nlsize;
}
@@ -451,8 +497,12 @@ static int ioam6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
	return (ilwt_a->freq.k != ilwt_b->freq.k ||
		ilwt_a->freq.n != ilwt_b->freq.n ||
		ilwt_a->mode != ilwt_b->mode ||
		ilwt_a->has_tunsrc != ilwt_b->has_tunsrc ||
		(ilwt_a->mode != IOAM6_IPTUNNEL_MODE_INLINE &&
		 !ipv6_addr_equal(&ilwt_a->tundst, &ilwt_b->tundst)) ||
		(ilwt_a->mode != IOAM6_IPTUNNEL_MODE_INLINE &&
		 ilwt_a->has_tunsrc &&
		 !ipv6_addr_equal(&ilwt_a->tunsrc, &ilwt_b->tunsrc)) ||
		trace_a->namespace_id != trace_b->namespace_id);
}