mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-07 17:27:11 -04:00
Merge branch 'tools-ynl-c-basic-netlink-raw-support'
Jakub Kicinski says: ==================== tools: ynl: c: basic netlink-raw support Basic support for netlink-raw AKA classic netlink in user space C codegen. This series is enough to read routes and addresses from the kernel (see the samples in patches 12 and 13). Specs need to be slightly adjusted and decorated with the c naming info. In terms of codegen this series includes just the basic plumbing required to skip genlmsghdr and handle request types which may technically also be legal in genetlink-legacy but are very uncommon there. Subsequent series will add support for: - handling CRUD-style notifications - code gen for array types classic netlink uses - sub-message support v1: https://lore.kernel.org/20250409000400.492371-1-kuba@kernel.org ==================== Link: https://patch.msgid.link/20250410014658.782120-1-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
name: rt-addr
|
||||
protocol: netlink-raw
|
||||
uapi-header: linux/rtnetlink.h
|
||||
protonum: 0
|
||||
|
||||
doc:
|
||||
@@ -49,6 +50,8 @@ definitions:
|
||||
-
|
||||
name: ifa-flags
|
||||
type: flags
|
||||
name-prefix: ifa-f-
|
||||
enum-name:
|
||||
entries:
|
||||
-
|
||||
name: secondary
|
||||
@@ -124,6 +127,7 @@ attribute-sets:
|
||||
operations:
|
||||
fixed-header: ifaddrmsg
|
||||
enum-model: directional
|
||||
name-prefix: rtm-
|
||||
list:
|
||||
-
|
||||
name: newaddr
|
||||
@@ -133,11 +137,6 @@ operations:
|
||||
request:
|
||||
value: 20
|
||||
attributes: &ifaddr-all
|
||||
- ifa-family
|
||||
- ifa-flags
|
||||
- ifa-prefixlen
|
||||
- ifa-scope
|
||||
- ifa-index
|
||||
- address
|
||||
- label
|
||||
- local
|
||||
@@ -150,11 +149,6 @@ operations:
|
||||
request:
|
||||
value: 21
|
||||
attributes:
|
||||
- ifa-family
|
||||
- ifa-flags
|
||||
- ifa-prefixlen
|
||||
- ifa-scope
|
||||
- ifa-index
|
||||
- address
|
||||
- local
|
||||
-
|
||||
@@ -164,8 +158,7 @@ operations:
|
||||
dump:
|
||||
request:
|
||||
value: 22
|
||||
attributes:
|
||||
- ifa-index
|
||||
attributes: []
|
||||
reply:
|
||||
value: 20
|
||||
attributes: *ifaddr-all
|
||||
@@ -177,9 +170,7 @@ operations:
|
||||
do:
|
||||
request:
|
||||
value: 58
|
||||
attributes:
|
||||
- ifa-family
|
||||
- ifa-index
|
||||
attributes: []
|
||||
reply:
|
||||
value: 58
|
||||
attributes: &mcaddr-attrs
|
||||
@@ -188,8 +179,7 @@ operations:
|
||||
dump:
|
||||
request:
|
||||
value: 58
|
||||
attributes:
|
||||
- ifa-family
|
||||
attributes: []
|
||||
reply:
|
||||
value: 58
|
||||
attributes: *mcaddr-attrs
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
name: rt-route
|
||||
protocol: netlink-raw
|
||||
uapi-header: linux/rtnetlink.h
|
||||
protonum: 0
|
||||
|
||||
doc:
|
||||
@@ -11,6 +12,7 @@ definitions:
|
||||
-
|
||||
name: rtm-type
|
||||
name-prefix: rtn-
|
||||
enum-name:
|
||||
type: enum
|
||||
entries:
|
||||
- unspec
|
||||
@@ -245,21 +247,19 @@ attribute-sets:
|
||||
|
||||
operations:
|
||||
enum-model: directional
|
||||
fixed-header: rtmsg
|
||||
name-prefix: rtm-
|
||||
list:
|
||||
-
|
||||
name: getroute
|
||||
doc: Dump route information.
|
||||
attribute-set: route-attrs
|
||||
fixed-header: rtmsg
|
||||
do:
|
||||
request:
|
||||
value: 26
|
||||
attributes:
|
||||
- rtm-family
|
||||
- src
|
||||
- rtm-src-len
|
||||
- dst
|
||||
- rtm-dst-len
|
||||
- iif
|
||||
- oif
|
||||
- ip-proto
|
||||
@@ -271,15 +271,6 @@ operations:
|
||||
reply:
|
||||
value: 24
|
||||
attributes: &all-route-attrs
|
||||
- rtm-family
|
||||
- rtm-dst-len
|
||||
- rtm-src-len
|
||||
- rtm-tos
|
||||
- rtm-table
|
||||
- rtm-protocol
|
||||
- rtm-scope
|
||||
- rtm-type
|
||||
- rtm-flags
|
||||
- dst
|
||||
- src
|
||||
- iif
|
||||
@@ -311,8 +302,7 @@ operations:
|
||||
dump:
|
||||
request:
|
||||
value: 26
|
||||
attributes:
|
||||
- rtm-family
|
||||
attributes: []
|
||||
reply:
|
||||
value: 24
|
||||
attributes: *all-route-attrs
|
||||
@@ -320,7 +310,6 @@ operations:
|
||||
name: newroute
|
||||
doc: Create a new route
|
||||
attribute-set: route-attrs
|
||||
fixed-header: rtmsg
|
||||
do:
|
||||
request:
|
||||
value: 24
|
||||
@@ -329,7 +318,6 @@ operations:
|
||||
name: delroute
|
||||
doc: Delete an existing route
|
||||
attribute-set: route-attrs
|
||||
fixed-header: rtmsg
|
||||
do:
|
||||
request:
|
||||
value: 25
|
||||
@@ -62,7 +62,7 @@ Sub-messages
|
||||
------------
|
||||
|
||||
Several raw netlink families such as
|
||||
:doc:`rt_link<../../networking/netlink_spec/rt_link>` and
|
||||
:doc:`rt-link<../../networking/netlink_spec/rt-link>` and
|
||||
:doc:`tc<../../networking/netlink_spec/tc>` use attribute nesting as an
|
||||
abstraction to carry module specific information.
|
||||
|
||||
|
||||
@@ -29,4 +29,6 @@ CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_NETLINK_H,nfsd_netlink.h)
|
||||
CFLAGS_ovs_datapath:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h)
|
||||
CFLAGS_ovs_flow:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h)
|
||||
CFLAGS_ovs_vport:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h)
|
||||
CFLAGS_rt-addr:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h)
|
||||
CFLAGS_rt-route:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h)
|
||||
CFLAGS_tcp_metrics:=$(call get_hdr_inc,_LINUX_TCP_METRICS_H,tcp_metrics.h)
|
||||
|
||||
@@ -25,7 +25,7 @@ SPECS_DIR:=../../../../Documentation/netlink/specs
|
||||
GENS_PATHS=$(shell grep -nrI --files-without-match \
|
||||
'protocol: netlink' \
|
||||
$(SPECS_DIR))
|
||||
GENS=$(patsubst $(SPECS_DIR)/%.yaml,%,${GENS_PATHS})
|
||||
GENS=$(patsubst $(SPECS_DIR)/%.yaml,%,${GENS_PATHS}) rt-addr rt-route
|
||||
SRCS=$(patsubst %,%-user.c,${GENS})
|
||||
HDRS=$(patsubst %,%-user.h,${GENS})
|
||||
OBJS=$(patsubst %,%-user.o,${GENS})
|
||||
|
||||
@@ -94,6 +94,9 @@ struct ynl_ntf_base_type {
|
||||
unsigned char data[] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id);
|
||||
struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id);
|
||||
|
||||
struct nlmsghdr *
|
||||
ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
|
||||
struct nlmsghdr *
|
||||
|
||||
@@ -451,14 +451,14 @@ ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags,
|
||||
return nlh;
|
||||
}
|
||||
|
||||
void ynl_msg_start_req(struct ynl_sock *ys, __u32 id)
|
||||
struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id)
|
||||
{
|
||||
ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK);
|
||||
return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK);
|
||||
}
|
||||
|
||||
void ynl_msg_start_dump(struct ynl_sock *ys, __u32 id)
|
||||
struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id)
|
||||
{
|
||||
ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
|
||||
return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
|
||||
}
|
||||
|
||||
struct nlmsghdr *
|
||||
@@ -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:
|
||||
@@ -1212,6 +1212,7 @@ class RenderInfo:
|
||||
|
||||
# 'do' and 'dump' response parsing is identical
|
||||
self.type_consistent = True
|
||||
self.type_oneside = False
|
||||
if op_mode != 'do' and 'dump' in op:
|
||||
if 'do' in op:
|
||||
if ('reply' in op['do']) != ('reply' in op["dump"]):
|
||||
@@ -1219,7 +1220,8 @@ class RenderInfo:
|
||||
elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]:
|
||||
self.type_consistent = False
|
||||
else:
|
||||
self.type_consistent = False
|
||||
self.type_consistent = True
|
||||
self.type_oneside = True
|
||||
|
||||
self.attr_set = attr_set
|
||||
if not self.attr_set:
|
||||
@@ -1247,6 +1249,9 @@ class RenderInfo:
|
||||
if op_mode == 'event':
|
||||
self.struct['reply'] = Struct(family, self.attr_set, type_list=op['event']['attributes'])
|
||||
|
||||
def type_empty(self, key):
|
||||
return len(self.struct[key].attr_list) == 0 and self.fixed_hdr is None
|
||||
|
||||
|
||||
class CodeWriter:
|
||||
def __init__(self, nlib, out_file=None, overwrite=True):
|
||||
@@ -1513,7 +1518,9 @@ def op_prefix(ri, direction, deref=False):
|
||||
suffix += f"{direction_to_suffix[direction]}"
|
||||
else:
|
||||
if direction == 'request':
|
||||
suffix += '_req_dump'
|
||||
suffix += '_req'
|
||||
if not ri.type_oneside:
|
||||
suffix += '_dump'
|
||||
else:
|
||||
if ri.type_consistent:
|
||||
if deref:
|
||||
@@ -1707,7 +1714,10 @@ def _multi_parse(ri, struct, init_lines, local_vars):
|
||||
ri.cw.p(f'dst->{arg} = {arg};')
|
||||
|
||||
if ri.fixed_hdr:
|
||||
ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));')
|
||||
if ri.family.is_classic():
|
||||
ri.cw.p('hdr = ynl_nlmsg_data(nlh);')
|
||||
else:
|
||||
ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));')
|
||||
ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));")
|
||||
for anest in sorted(all_multi):
|
||||
aspec = struct[anest]
|
||||
@@ -1854,7 +1864,10 @@ def print_req(ri):
|
||||
ri.cw.block_start()
|
||||
ri.cw.write_func_lvar(local_vars)
|
||||
|
||||
ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
|
||||
if ri.family.is_classic():
|
||||
ri.cw.p(f"nlh = ynl_msg_start_req(ys, {ri.op.enum_name});")
|
||||
else:
|
||||
ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
|
||||
|
||||
ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
|
||||
if 'reply' in ri.op[ri.op_mode]:
|
||||
@@ -1923,7 +1936,10 @@ def print_dump(ri):
|
||||
else:
|
||||
ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};')
|
||||
ri.cw.nl()
|
||||
ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
|
||||
if ri.family.is_classic():
|
||||
ri.cw.p(f"nlh = ynl_msg_start_dump(ys, {ri.op.enum_name});")
|
||||
else:
|
||||
ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
|
||||
|
||||
if ri.fixed_hdr:
|
||||
ri.cw.p("hdr_len = sizeof(req->_hdr);")
|
||||
@@ -1983,7 +1999,7 @@ def _print_type(ri, direction, struct):
|
||||
if not direction and ri.type_name_conflict:
|
||||
suffix += '_'
|
||||
|
||||
if ri.op_mode == 'dump':
|
||||
if ri.op_mode == 'dump' and not ri.type_oneside:
|
||||
suffix += '_dump'
|
||||
|
||||
ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}")
|
||||
@@ -2034,7 +2050,7 @@ def print_type_helpers(ri, direction, deref=False):
|
||||
|
||||
|
||||
def print_req_type_helpers(ri):
|
||||
if len(ri.struct["request"].attr_list) == 0:
|
||||
if ri.type_empty("request"):
|
||||
return
|
||||
print_alloc_wrapper(ri, "request")
|
||||
print_type_helpers(ri, "request")
|
||||
@@ -2057,7 +2073,7 @@ def print_parse_prototype(ri, direction, terminate=True):
|
||||
|
||||
|
||||
def print_req_type(ri):
|
||||
if len(ri.struct["request"].attr_list) == 0:
|
||||
if ri.type_empty("request"):
|
||||
return
|
||||
print_type(ri, "request")
|
||||
|
||||
@@ -2710,7 +2726,7 @@ def render_user_family(family, cw, prototype):
|
||||
return
|
||||
|
||||
if family.ntfs:
|
||||
cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ")
|
||||
cw.block_start(line=f"static const struct ynl_ntf_info {family.c_name}_ntf_info[] = ")
|
||||
for ntf_op_name, ntf_op in family.ntfs.items():
|
||||
if 'notify' in ntf_op:
|
||||
op = family.ops[ntf_op['notify']]
|
||||
@@ -2730,13 +2746,18 @@ def render_user_family(family, cw, prototype):
|
||||
|
||||
cw.block_start(f'{symbol} = ')
|
||||
cw.p(f'.name\t\t= "{family.c_name}",')
|
||||
if family.fixed_header:
|
||||
if family.is_classic():
|
||||
cw.p(f'.is_classic\t= true,')
|
||||
cw.p(f'.classic_id\t= {family.get("protonum")},')
|
||||
if family.is_classic():
|
||||
cw.p(f'.hdr_len\t= sizeof(struct {c_lower(family.fixed_header)}),')
|
||||
elif family.fixed_header:
|
||||
cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),')
|
||||
else:
|
||||
cw.p('.hdr_len\t= sizeof(struct genlmsghdr),')
|
||||
if family.ntfs:
|
||||
cw.p(f".ntf_info\t= {family['name']}_ntf_info,")
|
||||
cw.p(f".ntf_info_size\t= YNL_ARRAY_SIZE({family['name']}_ntf_info),")
|
||||
cw.p(f".ntf_info\t= {family.c_name}_ntf_info,")
|
||||
cw.p(f".ntf_info_size\t= YNL_ARRAY_SIZE({family.c_name}_ntf_info),")
|
||||
cw.block_end(line=';')
|
||||
|
||||
|
||||
@@ -2962,7 +2983,7 @@ def main():
|
||||
ri = RenderInfo(cw, parsed, args.mode, op, 'dump')
|
||||
print_req_type(ri)
|
||||
print_req_type_helpers(ri)
|
||||
if not ri.type_consistent:
|
||||
if not ri.type_consistent or ri.type_oneside:
|
||||
print_rsp_type(ri)
|
||||
print_wrapped_type(ri)
|
||||
print_dump_prototype(ri)
|
||||
@@ -3040,7 +3061,7 @@ def main():
|
||||
if 'dump' in op:
|
||||
cw.p(f"/* {op.enum_name} - dump */")
|
||||
ri = RenderInfo(cw, parsed, args.mode, op, "dump")
|
||||
if not ri.type_consistent:
|
||||
if not ri.type_consistent or ri.type_oneside:
|
||||
parse_rsp_msg(ri, deref=True)
|
||||
print_req_free(ri)
|
||||
print_dump_type_free(ri)
|
||||
|
||||
4
tools/net/ynl/samples/.gitignore
vendored
4
tools/net/ynl/samples/.gitignore
vendored
@@ -2,4 +2,6 @@ ethtool
|
||||
devlink
|
||||
netdev
|
||||
ovs
|
||||
page-pool
|
||||
page-pool
|
||||
rt-addr
|
||||
rt-route
|
||||
|
||||
80
tools/net/ynl/samples/rt-addr.c
Normal file
80
tools/net/ynl/samples/rt-addr.c
Normal file
@@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ynl.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "rt-addr-user.h"
|
||||
|
||||
static void rt_addr_print(struct rt_addr_getaddr_rsp *a)
|
||||
{
|
||||
char ifname[IF_NAMESIZE];
|
||||
char addr_str[64];
|
||||
const char *addr;
|
||||
const char *name;
|
||||
|
||||
name = if_indextoname(a->_hdr.ifa_index, ifname);
|
||||
if (name)
|
||||
printf("%16s: ", name);
|
||||
|
||||
switch (a->_present.address_len) {
|
||||
case 4:
|
||||
addr = inet_ntop(AF_INET, a->address,
|
||||
addr_str, sizeof(addr_str));
|
||||
break;
|
||||
case 16:
|
||||
addr = inet_ntop(AF_INET6, a->address,
|
||||
addr_str, sizeof(addr_str));
|
||||
break;
|
||||
default:
|
||||
addr = NULL;
|
||||
break;
|
||||
}
|
||||
if (addr)
|
||||
printf("%s", addr);
|
||||
else
|
||||
printf("[%d]", a->_present.address_len);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct rt_addr_getaddr_list *rsp;
|
||||
struct rt_addr_getaddr_req *req;
|
||||
struct ynl_error yerr;
|
||||
struct ynl_sock *ys;
|
||||
|
||||
ys = ynl_sock_create(&ynl_rt_addr_family, &yerr);
|
||||
if (!ys) {
|
||||
fprintf(stderr, "YNL: %s\n", yerr.msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
req = rt_addr_getaddr_req_alloc();
|
||||
if (!req)
|
||||
goto err_destroy;
|
||||
|
||||
rsp = rt_addr_getaddr_dump(ys, req);
|
||||
rt_addr_getaddr_req_free(req);
|
||||
if (!rsp)
|
||||
goto err_close;
|
||||
|
||||
if (ynl_dump_empty(rsp))
|
||||
fprintf(stderr, "Error: no addresses reported\n");
|
||||
ynl_dump_foreach(rsp, addr)
|
||||
rt_addr_print(addr);
|
||||
rt_addr_getaddr_list_free(rsp);
|
||||
|
||||
ynl_sock_destroy(ys);
|
||||
return 0;
|
||||
|
||||
err_close:
|
||||
fprintf(stderr, "YNL: %s\n", ys->err.msg);
|
||||
err_destroy:
|
||||
ynl_sock_destroy(ys);
|
||||
return 2;
|
||||
}
|
||||
80
tools/net/ynl/samples/rt-route.c
Normal file
80
tools/net/ynl/samples/rt-route.c
Normal file
@@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ynl.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "rt-route-user.h"
|
||||
|
||||
static void rt_route_print(struct rt_route_getroute_rsp *r)
|
||||
{
|
||||
char ifname[IF_NAMESIZE];
|
||||
char route_str[64];
|
||||
const char *route;
|
||||
const char *name;
|
||||
|
||||
/* Ignore local */
|
||||
if (r->_hdr.rtm_table == RT_TABLE_LOCAL)
|
||||
return;
|
||||
|
||||
if (r->_present.oif) {
|
||||
name = if_indextoname(r->oif, ifname);
|
||||
if (name)
|
||||
printf("oif: %-16s ", name);
|
||||
}
|
||||
|
||||
if (r->_present.dst_len) {
|
||||
route = inet_ntop(r->_hdr.rtm_family, r->dst,
|
||||
route_str, sizeof(route_str));
|
||||
printf("dst: %s/%d", route, r->_hdr.rtm_dst_len);
|
||||
}
|
||||
|
||||
if (r->_present.gateway_len) {
|
||||
route = inet_ntop(r->_hdr.rtm_family, r->gateway,
|
||||
route_str, sizeof(route_str));
|
||||
printf("gateway: %s ", route);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct rt_route_getroute_req_dump *req;
|
||||
struct rt_route_getroute_list *rsp;
|
||||
struct ynl_error yerr;
|
||||
struct ynl_sock *ys;
|
||||
|
||||
ys = ynl_sock_create(&ynl_rt_route_family, &yerr);
|
||||
if (!ys) {
|
||||
fprintf(stderr, "YNL: %s\n", yerr.msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
req = rt_route_getroute_req_dump_alloc();
|
||||
if (!req)
|
||||
goto err_destroy;
|
||||
|
||||
rsp = rt_route_getroute_dump(ys, req);
|
||||
rt_route_getroute_req_dump_free(req);
|
||||
if (!rsp)
|
||||
goto err_close;
|
||||
|
||||
if (ynl_dump_empty(rsp))
|
||||
fprintf(stderr, "Error: no routeesses reported\n");
|
||||
ynl_dump_foreach(rsp, route)
|
||||
rt_route_print(route);
|
||||
rt_route_getroute_list_free(rsp);
|
||||
|
||||
ynl_sock_destroy(ys);
|
||||
return 0;
|
||||
|
||||
err_close:
|
||||
fprintf(stderr, "YNL: %s\n", ys->err.msg);
|
||||
err_destroy:
|
||||
ynl_sock_destroy(ys);
|
||||
return 2;
|
||||
}
|
||||
@@ -39,12 +39,12 @@ class EthtoolFamily(YnlFamily):
|
||||
|
||||
class RtnlFamily(YnlFamily):
|
||||
def __init__(self, recv_size=0):
|
||||
super().__init__((SPEC_PATH / Path('rt_link.yaml')).as_posix(),
|
||||
super().__init__((SPEC_PATH / Path('rt-link.yaml')).as_posix(),
|
||||
schema='', recv_size=recv_size)
|
||||
|
||||
class RtnlAddrFamily(YnlFamily):
|
||||
def __init__(self, recv_size=0):
|
||||
super().__init__((SPEC_PATH / Path('rt_addr.yaml')).as_posix(),
|
||||
super().__init__((SPEC_PATH / Path('rt-addr.yaml')).as_posix(),
|
||||
schema='', recv_size=recv_size)
|
||||
|
||||
class NetdevFamily(YnlFamily):
|
||||
|
||||
Reference in New Issue
Block a user