mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-01 01:14:19 -04:00
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:
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user