mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 07:47:50 +00:00
tools: ynl: support creating non-genl sockets
Classic netlink has static family IDs specified in YAML, there is no family name -> ID lookup. Support providing the ID info to the library via the generated struct and make library use it. Since NETLINK_ROUTE is ID 0 we need an extra boolean to indicate classic_id is to be used. Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Reviewed-by: Donald Hunter <donald.hunter@gmail.com> Link: https://patch.msgid.link/20250410014658.782120-8-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -663,6 +663,7 @@ ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
|
||||
struct sockaddr_nl addr;
|
||||
struct ynl_sock *ys;
|
||||
socklen_t addrlen;
|
||||
int sock_type;
|
||||
int one = 1;
|
||||
|
||||
ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE);
|
||||
@@ -675,7 +676,9 @@ ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
|
||||
ys->rx_buf = &ys->raw_buf[YNL_SOCKET_BUFFER_SIZE];
|
||||
ys->ntf_last_next = &ys->ntf_first;
|
||||
|
||||
ys->socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
|
||||
sock_type = yf->is_classic ? yf->classic_id : NETLINK_GENERIC;
|
||||
|
||||
ys->socket = socket(AF_NETLINK, SOCK_RAW, sock_type);
|
||||
if (ys->socket < 0) {
|
||||
__perr(yse, "failed to create a netlink socket");
|
||||
goto err_free_sock;
|
||||
@@ -708,8 +711,9 @@ ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
|
||||
ys->portid = addr.nl_pid;
|
||||
ys->seq = random();
|
||||
|
||||
|
||||
if (ynl_sock_read_family(ys, yf->name)) {
|
||||
if (yf->is_classic) {
|
||||
ys->family_id = yf->classic_id;
|
||||
} else if (ynl_sock_read_family(ys, yf->name)) {
|
||||
if (yse)
|
||||
memcpy(yse, &ys->err, sizeof(*yse));
|
||||
goto err_close_sock;
|
||||
@@ -791,13 +795,21 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
|
||||
struct ynl_parse_arg yarg = { .ys = ys, };
|
||||
const struct ynl_ntf_info *info;
|
||||
struct ynl_ntf_base_type *rsp;
|
||||
struct genlmsghdr *gehdr;
|
||||
__u32 cmd;
|
||||
int ret;
|
||||
|
||||
gehdr = ynl_nlmsg_data(nlh);
|
||||
if (gehdr->cmd >= ys->family->ntf_info_size)
|
||||
if (ys->family->is_classic) {
|
||||
cmd = nlh->nlmsg_type;
|
||||
} else {
|
||||
struct genlmsghdr *gehdr;
|
||||
|
||||
gehdr = ynl_nlmsg_data(nlh);
|
||||
cmd = gehdr->cmd;
|
||||
}
|
||||
|
||||
if (cmd >= ys->family->ntf_info_size)
|
||||
return YNL_PARSE_CB_ERROR;
|
||||
info = &ys->family->ntf_info[gehdr->cmd];
|
||||
info = &ys->family->ntf_info[cmd];
|
||||
if (!info->cb)
|
||||
return YNL_PARSE_CB_ERROR;
|
||||
|
||||
@@ -811,7 +823,7 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
|
||||
goto err_free;
|
||||
|
||||
rsp->family = nlh->nlmsg_type;
|
||||
rsp->cmd = gehdr->cmd;
|
||||
rsp->cmd = cmd;
|
||||
|
||||
*ys->ntf_last_next = rsp;
|
||||
ys->ntf_last_next = &rsp->next;
|
||||
@@ -863,18 +875,23 @@ int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg)
|
||||
static int
|
||||
ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
|
||||
{
|
||||
struct genlmsghdr *gehdr;
|
||||
if (ys->family->is_classic) {
|
||||
if (nlh->nlmsg_type != rsp_cmd)
|
||||
return ynl_ntf_parse(ys, nlh);
|
||||
} else {
|
||||
struct genlmsghdr *gehdr;
|
||||
|
||||
if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) {
|
||||
yerr(ys, YNL_ERROR_INV_RESP,
|
||||
"Kernel responded with truncated message");
|
||||
return -1;
|
||||
if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) {
|
||||
yerr(ys, YNL_ERROR_INV_RESP,
|
||||
"Kernel responded with truncated message");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gehdr = ynl_nlmsg_data(nlh);
|
||||
if (gehdr->cmd != rsp_cmd)
|
||||
return ynl_ntf_parse(ys, nlh);
|
||||
}
|
||||
|
||||
gehdr = ynl_nlmsg_data(nlh);
|
||||
if (gehdr->cmd != rsp_cmd)
|
||||
return ynl_ntf_parse(ys, nlh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifndef __YNL_C_H
|
||||
#define __YNL_C_H 1
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/types.h>
|
||||
@@ -48,6 +49,8 @@ struct ynl_family {
|
||||
/* private: */
|
||||
const char *name;
|
||||
size_t hdr_len;
|
||||
bool is_classic;
|
||||
__u16 classic_id;
|
||||
const struct ynl_ntf_info *ntf_info;
|
||||
unsigned int ntf_info_size;
|
||||
};
|
||||
|
||||
@@ -971,9 +971,6 @@ class Family(SpecFamily):
|
||||
def resolve(self):
|
||||
self.resolve_up(super())
|
||||
|
||||
if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}:
|
||||
raise Exception("Codegen only supported for genetlink")
|
||||
|
||||
self.c_name = c_lower(self.ident_name)
|
||||
if 'name-prefix' in self.yaml['operations']:
|
||||
self.op_prefix = c_upper(self.yaml['operations']['name-prefix'])
|
||||
@@ -1020,6 +1017,9 @@ class Family(SpecFamily):
|
||||
def new_operation(self, elem, req_value, rsp_value):
|
||||
return Operation(self, elem, req_value, rsp_value)
|
||||
|
||||
def is_classic(self):
|
||||
return self.proto == 'netlink-raw'
|
||||
|
||||
def _mark_notify(self):
|
||||
for op in self.msgs.values():
|
||||
if 'notify' in op:
|
||||
@@ -2730,6 +2730,9 @@ def render_user_family(family, cw, prototype):
|
||||
|
||||
cw.block_start(f'{symbol} = ')
|
||||
cw.p(f'.name\t\t= "{family.c_name}",')
|
||||
if family.is_classic():
|
||||
cw.p(f'.is_classic\t= true,')
|
||||
cw.p(f'.classic_id\t= {family.get("protonum")},')
|
||||
if family.fixed_header:
|
||||
cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),')
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user