Commit cfb9eb61 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 3e46ec18 f655c78d
......@@ -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 */
......@@ -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 */
......@@ -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;
......
......@@ -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,
};
......
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