Commit 660a38bf authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'support-for-the-ioam-insertion-frequency'

Justin Iurman says:

====================
Support for the IOAM insertion frequency

The insertion frequency is represented as "k/n", meaning IOAM will be
added to {k} packets over {n} packets, with 0 < k <= n and 1 <= {k,n} <=
1000000. Therefore, it provides the following percentages of insertion
frequency: [0.0001% (min) ... 100% (max)].

Not only this solution allows an operator to apply dynamic frequencies
based on the current traffic load, but it also provides some
flexibility, i.e., by distinguishing similar cases (e.g., "1/2" and
"2/4").

"1/2" = Y N Y N Y N Y N ...
"2/4" = Y Y N N Y Y N N ...
====================

Link: https://lore.kernel.org/r/20220202142554.9691-1-justin.iurman@uliege.beSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents c78b8b20 08731d30
...@@ -41,6 +41,15 @@ enum { ...@@ -41,6 +41,15 @@ enum {
/* IOAM Trace Header */ /* IOAM Trace Header */
IOAM6_IPTUNNEL_TRACE, /* struct ioam6_trace_hdr */ IOAM6_IPTUNNEL_TRACE, /* struct ioam6_trace_hdr */
/* Insertion frequency:
* "k over n" packets (0 < k <= n)
* [0.0001% ... 100%]
*/
#define IOAM6_IPTUNNEL_FREQ_MIN 1
#define IOAM6_IPTUNNEL_FREQ_MAX 1000000
IOAM6_IPTUNNEL_FREQ_K, /* u32 */
IOAM6_IPTUNNEL_FREQ_N, /* u32 */
__IOAM6_IPTUNNEL_MAX, __IOAM6_IPTUNNEL_MAX,
}; };
......
...@@ -32,13 +32,25 @@ struct ioam6_lwt_encap { ...@@ -32,13 +32,25 @@ struct ioam6_lwt_encap {
struct ioam6_trace_hdr traceh; struct ioam6_trace_hdr traceh;
} __packed; } __packed;
struct ioam6_lwt_freq {
u32 k;
u32 n;
};
struct ioam6_lwt { struct ioam6_lwt {
struct dst_cache cache; struct dst_cache cache;
struct ioam6_lwt_freq freq;
atomic_t pkt_cnt;
u8 mode; u8 mode;
struct in6_addr tundst; struct in6_addr tundst;
struct ioam6_lwt_encap tuninfo; struct ioam6_lwt_encap tuninfo;
}; };
static struct netlink_range_validation freq_range = {
.min = IOAM6_IPTUNNEL_FREQ_MIN,
.max = IOAM6_IPTUNNEL_FREQ_MAX,
};
static struct ioam6_lwt *ioam6_lwt_state(struct lwtunnel_state *lwt) static struct ioam6_lwt *ioam6_lwt_state(struct lwtunnel_state *lwt)
{ {
return (struct ioam6_lwt *)lwt->data; return (struct ioam6_lwt *)lwt->data;
...@@ -55,6 +67,8 @@ static struct ioam6_trace_hdr *ioam6_lwt_trace(struct lwtunnel_state *lwt) ...@@ -55,6 +67,8 @@ static struct ioam6_trace_hdr *ioam6_lwt_trace(struct lwtunnel_state *lwt)
} }
static const struct nla_policy ioam6_iptunnel_policy[IOAM6_IPTUNNEL_MAX + 1] = { static const struct nla_policy ioam6_iptunnel_policy[IOAM6_IPTUNNEL_MAX + 1] = {
[IOAM6_IPTUNNEL_FREQ_K] = NLA_POLICY_FULL_RANGE(NLA_U32, &freq_range),
[IOAM6_IPTUNNEL_FREQ_N] = NLA_POLICY_FULL_RANGE(NLA_U32, &freq_range),
[IOAM6_IPTUNNEL_MODE] = NLA_POLICY_RANGE(NLA_U8, [IOAM6_IPTUNNEL_MODE] = NLA_POLICY_RANGE(NLA_U8,
IOAM6_IPTUNNEL_MODE_MIN, IOAM6_IPTUNNEL_MODE_MIN,
IOAM6_IPTUNNEL_MODE_MAX), IOAM6_IPTUNNEL_MODE_MAX),
...@@ -96,6 +110,7 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla, ...@@ -96,6 +110,7 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla,
struct lwtunnel_state *lwt; struct lwtunnel_state *lwt;
struct ioam6_lwt *ilwt; struct ioam6_lwt *ilwt;
int len_aligned, err; int len_aligned, err;
u32 freq_k, freq_n;
u8 mode; u8 mode;
if (family != AF_INET6) if (family != AF_INET6)
...@@ -106,6 +121,23 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla, ...@@ -106,6 +121,23 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla,
if (err < 0) if (err < 0)
return err; return err;
if ((!tb[IOAM6_IPTUNNEL_FREQ_K] && tb[IOAM6_IPTUNNEL_FREQ_N]) ||
(tb[IOAM6_IPTUNNEL_FREQ_K] && !tb[IOAM6_IPTUNNEL_FREQ_N])) {
NL_SET_ERR_MSG(extack, "freq: missing parameter");
return -EINVAL;
} else if (!tb[IOAM6_IPTUNNEL_FREQ_K] && !tb[IOAM6_IPTUNNEL_FREQ_N]) {
freq_k = IOAM6_IPTUNNEL_FREQ_MIN;
freq_n = IOAM6_IPTUNNEL_FREQ_MIN;
} else {
freq_k = nla_get_u32(tb[IOAM6_IPTUNNEL_FREQ_K]);
freq_n = nla_get_u32(tb[IOAM6_IPTUNNEL_FREQ_N]);
if (freq_k > freq_n) {
NL_SET_ERR_MSG(extack, "freq: k > n is forbidden");
return -EINVAL;
}
}
if (!tb[IOAM6_IPTUNNEL_MODE]) if (!tb[IOAM6_IPTUNNEL_MODE])
mode = IOAM6_IPTUNNEL_MODE_INLINE; mode = IOAM6_IPTUNNEL_MODE_INLINE;
else else
...@@ -140,6 +172,10 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla, ...@@ -140,6 +172,10 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla,
return err; return err;
} }
atomic_set(&ilwt->pkt_cnt, 0);
ilwt->freq.k = freq_k;
ilwt->freq.n = freq_n;
ilwt->mode = mode; ilwt->mode = mode;
if (tb[IOAM6_IPTUNNEL_DST]) if (tb[IOAM6_IPTUNNEL_DST])
ilwt->tundst = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_DST]); ilwt->tundst = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_DST]);
...@@ -263,11 +299,18 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb) ...@@ -263,11 +299,18 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
struct in6_addr orig_daddr; struct in6_addr orig_daddr;
struct ioam6_lwt *ilwt; struct ioam6_lwt *ilwt;
int err = -EINVAL; int err = -EINVAL;
u32 pkt_cnt;
if (skb->protocol != htons(ETH_P_IPV6)) if (skb->protocol != htons(ETH_P_IPV6))
goto drop; goto drop;
ilwt = ioam6_lwt_state(dst->lwtstate); ilwt = ioam6_lwt_state(dst->lwtstate);
/* Check for insertion frequency (i.e., "k over n" insertions) */
pkt_cnt = atomic_fetch_inc(&ilwt->pkt_cnt);
if (pkt_cnt % ilwt->freq.n >= ilwt->freq.k)
goto out;
orig_daddr = ipv6_hdr(skb)->daddr; orig_daddr = ipv6_hdr(skb)->daddr;
switch (ilwt->mode) { switch (ilwt->mode) {
...@@ -358,6 +401,14 @@ static int ioam6_fill_encap_info(struct sk_buff *skb, ...@@ -358,6 +401,14 @@ static int ioam6_fill_encap_info(struct sk_buff *skb,
struct ioam6_lwt *ilwt = ioam6_lwt_state(lwtstate); struct ioam6_lwt *ilwt = ioam6_lwt_state(lwtstate);
int err; int err;
err = nla_put_u32(skb, IOAM6_IPTUNNEL_FREQ_K, ilwt->freq.k);
if (err)
goto ret;
err = nla_put_u32(skb, IOAM6_IPTUNNEL_FREQ_N, ilwt->freq.n);
if (err)
goto ret;
err = nla_put_u8(skb, IOAM6_IPTUNNEL_MODE, ilwt->mode); err = nla_put_u8(skb, IOAM6_IPTUNNEL_MODE, ilwt->mode);
if (err) if (err)
goto ret; goto ret;
...@@ -379,7 +430,9 @@ static int ioam6_encap_nlsize(struct lwtunnel_state *lwtstate) ...@@ -379,7 +430,9 @@ static int ioam6_encap_nlsize(struct lwtunnel_state *lwtstate)
struct ioam6_lwt *ilwt = ioam6_lwt_state(lwtstate); struct ioam6_lwt *ilwt = ioam6_lwt_state(lwtstate);
int nlsize; int nlsize;
nlsize = nla_total_size(sizeof(ilwt->mode)) + nlsize = nla_total_size(sizeof(ilwt->freq.k)) +
nla_total_size(sizeof(ilwt->freq.n)) +
nla_total_size(sizeof(ilwt->mode)) +
nla_total_size(sizeof(ilwt->tuninfo.traceh)); nla_total_size(sizeof(ilwt->tuninfo.traceh));
if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE)
...@@ -395,7 +448,9 @@ static int ioam6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) ...@@ -395,7 +448,9 @@ static int ioam6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
struct ioam6_lwt *ilwt_a = ioam6_lwt_state(a); struct ioam6_lwt *ilwt_a = ioam6_lwt_state(a);
struct ioam6_lwt *ilwt_b = ioam6_lwt_state(b); struct ioam6_lwt *ilwt_b = ioam6_lwt_state(b);
return (ilwt_a->mode != ilwt_b->mode || 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->mode != IOAM6_IPTUNNEL_MODE_INLINE && (ilwt_a->mode != IOAM6_IPTUNNEL_MODE_INLINE &&
!ipv6_addr_equal(&ilwt_a->tundst, &ilwt_b->tundst)) || !ipv6_addr_equal(&ilwt_a->tundst, &ilwt_b->tundst)) ||
trace_a->namespace_id != trace_b->namespace_id); trace_a->namespace_id != trace_b->namespace_id);
......
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