Merge branch 'ioam6-mcast-events'

Justin Iurman says:

====================
ioam6: netlink multicast event

v5:
 - remove the "must be the destination" check before sending an ioam6
   event
v4:
 - rebase on top of net merge
v3:
 - patchset was mistakenly superseded due to same cover title used for
   iproute2-next equivalent patch -> resend (renamed)
v2:
 - fix warnings

Add generic netlink multicast event support to ioam6 as another solution
to share IOAM data with user space. The other one being via IPv6 raw
sockets combined with ancillary data (or packet socket, if the listener
does not need the processing of the IOAM Option-Type, since the hook is
before in that case). This patchset focuses on the IOAM Pre-allocated
Trace (the only Option-Type currently supported in the kernel), and so
on IOAM "trace" events. See an example of a consumer here [1].

  [1] https://github.com/Advanced-Observability/ioam-agent-python/blob/netlink_event/ioam-agent.py
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller
2024-02-28 11:19:42 +00:00
4 changed files with 92 additions and 0 deletions

View File

@@ -12,6 +12,7 @@
#include <linux/net.h>
#include <linux/ipv6.h>
#include <linux/ioam6.h>
#include <linux/ioam6_genl.h>
#include <linux/rhashtable-types.h>
struct ioam6_namespace {
@@ -65,4 +66,7 @@ void ioam6_exit(void);
int ioam6_iptunnel_init(void);
void ioam6_iptunnel_exit(void);
void ioam6_event(enum ioam6_event_type type, struct net *net, gfp_t gfp,
void *opt, unsigned int opt_len);
#endif /* _NET_IOAM6_H */

View File

@@ -49,4 +49,24 @@ enum {
#define IOAM6_CMD_MAX (__IOAM6_CMD_MAX - 1)
#define IOAM6_GENL_EV_GRP_NAME "ioam6_events"
enum ioam6_event_type {
IOAM6_EVENT_UNSPEC,
IOAM6_EVENT_TRACE,
};
enum ioam6_event_attr {
IOAM6_EVENT_ATTR_UNSPEC,
IOAM6_EVENT_ATTR_TRACE_NAMESPACE, /* u16 */
IOAM6_EVENT_ATTR_TRACE_NODELEN, /* u8 */
IOAM6_EVENT_ATTR_TRACE_TYPE, /* u32 */
IOAM6_EVENT_ATTR_TRACE_DATA, /* Binary */
__IOAM6_EVENT_ATTR_MAX
};
#define IOAM6_EVENT_ATTR_MAX (__IOAM6_EVENT_ATTR_MAX - 1)
#endif /* _UAPI_LINUX_IOAM6_GENL_H */

View File

@@ -50,6 +50,7 @@
#endif
#include <net/rpl.h>
#include <linux/ioam6.h>
#include <linux/ioam6_genl.h>
#include <net/ioam6.h>
#include <net/dst_metadata.h>
@@ -954,6 +955,9 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
+ optoff + sizeof(*hdr));
ioam6_fill_trace_data(skb, ns, trace, true);
ioam6_event(IOAM6_EVENT_TRACE, dev_net(skb->dev),
GFP_ATOMIC, (void *)trace, hdr->opt_len - 2);
break;
default:
break;

View File

@@ -612,6 +612,68 @@ static const struct genl_ops ioam6_genl_ops[] = {
},
};
#define IOAM6_GENL_EV_GRP_OFFSET 0
static const struct genl_multicast_group ioam6_mcgrps[] = {
[IOAM6_GENL_EV_GRP_OFFSET] = { .name = IOAM6_GENL_EV_GRP_NAME,
.flags = GENL_MCAST_CAP_NET_ADMIN },
};
static int ioam6_event_put_trace(struct sk_buff *skb,
struct ioam6_trace_hdr *trace,
unsigned int len)
{
if (nla_put_u16(skb, IOAM6_EVENT_ATTR_TRACE_NAMESPACE,
be16_to_cpu(trace->namespace_id)) ||
nla_put_u8(skb, IOAM6_EVENT_ATTR_TRACE_NODELEN, trace->nodelen) ||
nla_put_u32(skb, IOAM6_EVENT_ATTR_TRACE_TYPE,
be32_to_cpu(trace->type_be32)) ||
nla_put(skb, IOAM6_EVENT_ATTR_TRACE_DATA,
len - sizeof(struct ioam6_trace_hdr) - trace->remlen * 4,
trace->data + trace->remlen * 4))
return 1;
return 0;
}
void ioam6_event(enum ioam6_event_type type, struct net *net, gfp_t gfp,
void *opt, unsigned int opt_len)
{
struct nlmsghdr *nlh;
struct sk_buff *skb;
if (!genl_has_listeners(&ioam6_genl_family, net,
IOAM6_GENL_EV_GRP_OFFSET))
return;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!skb)
return;
nlh = genlmsg_put(skb, 0, 0, &ioam6_genl_family, 0, type);
if (!nlh)
goto nla_put_failure;
switch (type) {
case IOAM6_EVENT_UNSPEC:
WARN_ON_ONCE(1);
break;
case IOAM6_EVENT_TRACE:
if (ioam6_event_put_trace(skb, (struct ioam6_trace_hdr *)opt,
opt_len))
goto nla_put_failure;
break;
}
genlmsg_end(skb, nlh);
genlmsg_multicast_netns(&ioam6_genl_family, net, skb, 0,
IOAM6_GENL_EV_GRP_OFFSET, gfp);
return;
nla_put_failure:
nlmsg_free(skb);
}
static struct genl_family ioam6_genl_family __ro_after_init = {
.name = IOAM6_GENL_NAME,
.version = IOAM6_GENL_VERSION,
@@ -620,6 +682,8 @@ static struct genl_family ioam6_genl_family __ro_after_init = {
.ops = ioam6_genl_ops,
.n_ops = ARRAY_SIZE(ioam6_genl_ops),
.resv_start_op = IOAM6_CMD_NS_SET_SCHEMA + 1,
.mcgrps = ioam6_mcgrps,
.n_mcgrps = ARRAY_SIZE(ioam6_mcgrps),
.module = THIS_MODULE,
};