net: ioam6: multicast event

Add a multicast group to the ioam6 generic netlink family and provide
ioam6_event() to send an ioam6 event to the multicast group.

Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Justin Iurman 2024-02-26 14:14:11 +01:00 committed by David S. Miller
parent 5fa918a335
commit 67c8e4bb4f
2 changed files with 68 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

@ -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,
};