Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+262 -76
+7 -17
Documentation/netlink/specs/rt_addr.yaml Documentation/netlink/specs/rt-addr.yaml
··· 2 2 3 3 name: rt-addr 4 4 protocol: netlink-raw 5 + uapi-header: linux/rtnetlink.h 5 6 protonum: 0 6 7 7 8 doc: ··· 50 49 - 51 50 name: ifa-flags 52 51 type: flags 52 + name-prefix: ifa-f- 53 + enum-name: 53 54 entries: 54 55 - 55 56 name: secondary ··· 127 124 operations: 128 125 fixed-header: ifaddrmsg 129 126 enum-model: directional 127 + name-prefix: rtm- 130 128 list: 131 129 - 132 130 name: newaddr ··· 137 133 request: 138 134 value: 20 139 135 attributes: &ifaddr-all 140 - - ifa-family 141 - - ifa-flags 142 - - ifa-prefixlen 143 - - ifa-scope 144 - - ifa-index 145 136 - address 146 137 - label 147 138 - local ··· 149 150 request: 150 151 value: 21 151 152 attributes: 152 - - ifa-family 153 - - ifa-flags 154 - - ifa-prefixlen 155 - - ifa-scope 156 - - ifa-index 157 153 - address 158 154 - local 159 155 - ··· 158 164 dump: 159 165 request: 160 166 value: 22 161 - attributes: 162 - - ifa-index 167 + attributes: [] 163 168 reply: 164 169 value: 20 165 170 attributes: *ifaddr-all ··· 170 177 do: 171 178 request: 172 179 value: 58 173 - attributes: 174 - - ifa-family 175 - - ifa-index 180 + attributes: [] 176 181 reply: 177 182 value: 58 178 183 attributes: &mcaddr-attrs ··· 179 188 dump: 180 189 request: 181 190 value: 58 182 - attributes: 183 - - ifa-family 191 + attributes: [] 184 192 reply: 185 193 value: 58 186 194 attributes: *mcaddr-attrs
Documentation/netlink/specs/rt_link.yaml Documentation/netlink/specs/rt-link.yaml
Documentation/netlink/specs/rt_neigh.yaml Documentation/netlink/specs/rt-neigh.yaml
+5 -17
Documentation/netlink/specs/rt_route.yaml Documentation/netlink/specs/rt-route.yaml
··· 2 2 3 3 name: rt-route 4 4 protocol: netlink-raw 5 + uapi-header: linux/rtnetlink.h 5 6 protonum: 0 6 7 7 8 doc: ··· 12 11 - 13 12 name: rtm-type 14 13 name-prefix: rtn- 14 + enum-name: 15 15 type: enum 16 16 entries: 17 17 - unspec ··· 247 245 248 246 operations: 249 247 enum-model: directional 248 + fixed-header: rtmsg 249 + name-prefix: rtm- 250 250 list: 251 251 - 252 252 name: getroute 253 253 doc: Dump route information. 254 254 attribute-set: route-attrs 255 - fixed-header: rtmsg 256 255 do: 257 256 request: 258 257 value: 26 259 258 attributes: 260 - - rtm-family 261 259 - src 262 - - rtm-src-len 263 260 - dst 264 - - rtm-dst-len 265 261 - iif 266 262 - oif 267 263 - ip-proto ··· 271 271 reply: 272 272 value: 24 273 273 attributes: &all-route-attrs 274 - - rtm-family 275 - - rtm-dst-len 276 - - rtm-src-len 277 - - rtm-tos 278 - - rtm-table 279 - - rtm-protocol 280 - - rtm-scope 281 - - rtm-type 282 - - rtm-flags 283 274 - dst 284 275 - src 285 276 - iif ··· 302 311 dump: 303 312 request: 304 313 value: 26 305 - attributes: 306 - - rtm-family 314 + attributes: [] 307 315 reply: 308 316 value: 24 309 317 attributes: *all-route-attrs ··· 310 320 name: newroute 311 321 doc: Create a new route 312 322 attribute-set: route-attrs 313 - fixed-header: rtmsg 314 323 do: 315 324 request: 316 325 value: 24 ··· 318 329 name: delroute 319 330 doc: Delete an existing route 320 331 attribute-set: route-attrs 321 - fixed-header: rtmsg 322 332 do: 323 333 request: 324 334 value: 25
Documentation/netlink/specs/rt_rule.yaml Documentation/netlink/specs/rt-rule.yaml
+2
tools/net/ynl/Makefile.deps
··· 29 29 CFLAGS_ovs_datapath:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) 30 30 CFLAGS_ovs_flow:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) 31 31 CFLAGS_ovs_vport:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) 32 + CFLAGS_rt-addr:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) 33 + CFLAGS_rt-route:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) 32 34 CFLAGS_tcp_metrics:=$(call get_hdr_inc,_LINUX_TCP_METRICS_H,tcp_metrics.h)
+1 -1
tools/net/ynl/generated/Makefile
··· 25 25 GENS_PATHS=$(shell grep -nrI --files-without-match \ 26 26 'protocol: netlink' \ 27 27 $(SPECS_DIR)) 28 - GENS=$(patsubst $(SPECS_DIR)/%.yaml,%,${GENS_PATHS}) 28 + GENS=$(patsubst $(SPECS_DIR)/%.yaml,%,${GENS_PATHS}) rt-addr rt-route 29 29 SRCS=$(patsubst %,%-user.c,${GENS}) 30 30 HDRS=$(patsubst %,%-user.h,${GENS}) 31 31 OBJS=$(patsubst %,%-user.o,${GENS})
+3
tools/net/ynl/lib/ynl-priv.h
··· 94 94 unsigned char data[] __attribute__((aligned(8))); 95 95 }; 96 96 97 + struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id); 98 + struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id); 99 + 97 100 struct nlmsghdr * 98 101 ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); 99 102 struct nlmsghdr *
+38 -21
tools/net/ynl/lib/ynl.c
··· 451 451 return nlh; 452 452 } 453 453 454 - void ynl_msg_start_req(struct ynl_sock *ys, __u32 id) 454 + struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id) 455 455 { 456 - ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK); 456 + return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK); 457 457 } 458 458 459 - void ynl_msg_start_dump(struct ynl_sock *ys, __u32 id) 459 + struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id) 460 460 { 461 - ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); 461 + return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); 462 462 } 463 463 464 464 struct nlmsghdr * ··· 663 663 struct sockaddr_nl addr; 664 664 struct ynl_sock *ys; 665 665 socklen_t addrlen; 666 + int sock_type; 666 667 int one = 1; 667 668 668 669 ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE); ··· 676 675 ys->rx_buf = &ys->raw_buf[YNL_SOCKET_BUFFER_SIZE]; 677 676 ys->ntf_last_next = &ys->ntf_first; 678 677 679 - ys->socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 678 + sock_type = yf->is_classic ? yf->classic_id : NETLINK_GENERIC; 679 + 680 + ys->socket = socket(AF_NETLINK, SOCK_RAW, sock_type); 680 681 if (ys->socket < 0) { 681 682 __perr(yse, "failed to create a netlink socket"); 682 683 goto err_free_sock; ··· 711 708 ys->portid = addr.nl_pid; 712 709 ys->seq = random(); 713 710 714 - 715 - if (ynl_sock_read_family(ys, yf->name)) { 711 + if (yf->is_classic) { 712 + ys->family_id = yf->classic_id; 713 + } else if (ynl_sock_read_family(ys, yf->name)) { 716 714 if (yse) 717 715 memcpy(yse, &ys->err, sizeof(*yse)); 718 716 goto err_close_sock; ··· 795 791 struct ynl_parse_arg yarg = { .ys = ys, }; 796 792 const struct ynl_ntf_info *info; 797 793 struct ynl_ntf_base_type *rsp; 798 - struct genlmsghdr *gehdr; 794 + __u32 cmd; 799 795 int ret; 800 796 801 - gehdr = ynl_nlmsg_data(nlh); 802 - if (gehdr->cmd >= ys->family->ntf_info_size) 797 + if (ys->family->is_classic) { 798 + cmd = nlh->nlmsg_type; 799 + } else { 800 + struct genlmsghdr *gehdr; 801 + 802 + gehdr = ynl_nlmsg_data(nlh); 803 + cmd = gehdr->cmd; 804 + } 805 + 806 + if (cmd >= ys->family->ntf_info_size) 803 807 return YNL_PARSE_CB_ERROR; 804 - info = &ys->family->ntf_info[gehdr->cmd]; 808 + info = &ys->family->ntf_info[cmd]; 805 809 if (!info->cb) 806 810 return YNL_PARSE_CB_ERROR; 807 811 ··· 823 811 goto err_free; 824 812 825 813 rsp->family = nlh->nlmsg_type; 826 - rsp->cmd = gehdr->cmd; 814 + rsp->cmd = cmd; 827 815 828 816 *ys->ntf_last_next = rsp; 829 817 ys->ntf_last_next = &rsp->next; ··· 875 863 static int 876 864 ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd) 877 865 { 878 - struct genlmsghdr *gehdr; 866 + if (ys->family->is_classic) { 867 + if (nlh->nlmsg_type != rsp_cmd) 868 + return ynl_ntf_parse(ys, nlh); 869 + } else { 870 + struct genlmsghdr *gehdr; 879 871 880 - if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) { 881 - yerr(ys, YNL_ERROR_INV_RESP, 882 - "Kernel responded with truncated message"); 883 - return -1; 872 + if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) { 873 + yerr(ys, YNL_ERROR_INV_RESP, 874 + "Kernel responded with truncated message"); 875 + return -1; 876 + } 877 + 878 + gehdr = ynl_nlmsg_data(nlh); 879 + if (gehdr->cmd != rsp_cmd) 880 + return ynl_ntf_parse(ys, nlh); 884 881 } 885 - 886 - gehdr = ynl_nlmsg_data(nlh); 887 - if (gehdr->cmd != rsp_cmd) 888 - return ynl_ntf_parse(ys, nlh); 889 882 890 883 return 0; 891 884 }
+3
tools/net/ynl/lib/ynl.h
··· 2 2 #ifndef __YNL_C_H 3 3 #define __YNL_C_H 1 4 4 5 + #include <stdbool.h> 5 6 #include <stddef.h> 6 7 #include <linux/genetlink.h> 7 8 #include <linux/types.h> ··· 49 48 /* private: */ 50 49 const char *name; 51 50 size_t hdr_len; 51 + bool is_classic; 52 + __u16 classic_id; 52 53 const struct ynl_ntf_info *ntf_info; 53 54 unsigned int ntf_info_size; 54 55 };
+38 -17
tools/net/ynl/pyynl/ynl_gen_c.py
··· 971 971 def resolve(self): 972 972 self.resolve_up(super()) 973 973 974 - if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}: 975 - raise Exception("Codegen only supported for genetlink") 976 - 977 974 self.c_name = c_lower(self.ident_name) 978 975 if 'name-prefix' in self.yaml['operations']: 979 976 self.op_prefix = c_upper(self.yaml['operations']['name-prefix']) ··· 1016 1019 1017 1020 def new_operation(self, elem, req_value, rsp_value): 1018 1021 return Operation(self, elem, req_value, rsp_value) 1022 + 1023 + def is_classic(self): 1024 + return self.proto == 'netlink-raw' 1019 1025 1020 1026 def _mark_notify(self): 1021 1027 for op in self.msgs.values(): ··· 1212 1212 1213 1213 # 'do' and 'dump' response parsing is identical 1214 1214 self.type_consistent = True 1215 + self.type_oneside = False 1215 1216 if op_mode != 'do' and 'dump' in op: 1216 1217 if 'do' in op: 1217 1218 if ('reply' in op['do']) != ('reply' in op["dump"]): ··· 1220 1219 elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]: 1221 1220 self.type_consistent = False 1222 1221 else: 1223 - self.type_consistent = False 1222 + self.type_consistent = True 1223 + self.type_oneside = True 1224 1224 1225 1225 self.attr_set = attr_set 1226 1226 if not self.attr_set: ··· 1248 1246 self.struct[op_dir] = Struct(family, self.attr_set, type_list=type_list) 1249 1247 if op_mode == 'event': 1250 1248 self.struct['reply'] = Struct(family, self.attr_set, type_list=op['event']['attributes']) 1249 + 1250 + def type_empty(self, key): 1251 + return len(self.struct[key].attr_list) == 0 and self.fixed_hdr is None 1251 1252 1252 1253 1253 1254 class CodeWriter: ··· 1518 1513 suffix += f"{direction_to_suffix[direction]}" 1519 1514 else: 1520 1515 if direction == 'request': 1521 - suffix += '_req_dump' 1516 + suffix += '_req' 1517 + if not ri.type_oneside: 1518 + suffix += '_dump' 1522 1519 else: 1523 1520 if ri.type_consistent: 1524 1521 if deref: ··· 1714 1707 ri.cw.p(f'dst->{arg} = {arg};') 1715 1708 1716 1709 if ri.fixed_hdr: 1717 - ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));') 1710 + if ri.family.is_classic(): 1711 + ri.cw.p('hdr = ynl_nlmsg_data(nlh);') 1712 + else: 1713 + ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));') 1718 1714 ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));") 1719 1715 for anest in sorted(all_multi): 1720 1716 aspec = struct[anest] ··· 1864 1854 ri.cw.block_start() 1865 1855 ri.cw.write_func_lvar(local_vars) 1866 1856 1867 - ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") 1857 + if ri.family.is_classic(): 1858 + ri.cw.p(f"nlh = ynl_msg_start_req(ys, {ri.op.enum_name});") 1859 + else: 1860 + ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") 1868 1861 1869 1862 ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") 1870 1863 if 'reply' in ri.op[ri.op_mode]: ··· 1936 1923 else: 1937 1924 ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};') 1938 1925 ri.cw.nl() 1939 - ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") 1926 + if ri.family.is_classic(): 1927 + ri.cw.p(f"nlh = ynl_msg_start_dump(ys, {ri.op.enum_name});") 1928 + else: 1929 + ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") 1940 1930 1941 1931 if ri.fixed_hdr: 1942 1932 ri.cw.p("hdr_len = sizeof(req->_hdr);") ··· 1999 1983 if not direction and ri.type_name_conflict: 2000 1984 suffix += '_' 2001 1985 2002 - if ri.op_mode == 'dump': 1986 + if ri.op_mode == 'dump' and not ri.type_oneside: 2003 1987 suffix += '_dump' 2004 1988 2005 1989 ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}") ··· 2050 2034 2051 2035 2052 2036 def print_req_type_helpers(ri): 2053 - if len(ri.struct["request"].attr_list) == 0: 2037 + if ri.type_empty("request"): 2054 2038 return 2055 2039 print_alloc_wrapper(ri, "request") 2056 2040 print_type_helpers(ri, "request") ··· 2073 2057 2074 2058 2075 2059 def print_req_type(ri): 2076 - if len(ri.struct["request"].attr_list) == 0: 2060 + if ri.type_empty("request"): 2077 2061 return 2078 2062 print_type(ri, "request") 2079 2063 ··· 2726 2710 return 2727 2711 2728 2712 if family.ntfs: 2729 - cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ") 2713 + cw.block_start(line=f"static const struct ynl_ntf_info {family.c_name}_ntf_info[] = ") 2730 2714 for ntf_op_name, ntf_op in family.ntfs.items(): 2731 2715 if 'notify' in ntf_op: 2732 2716 op = family.ops[ntf_op['notify']] ··· 2746 2730 2747 2731 cw.block_start(f'{symbol} = ') 2748 2732 cw.p(f'.name\t\t= "{family.c_name}",') 2749 - if family.fixed_header: 2733 + if family.is_classic(): 2734 + cw.p(f'.is_classic\t= true,') 2735 + cw.p(f'.classic_id\t= {family.get("protonum")},') 2736 + if family.is_classic(): 2737 + cw.p(f'.hdr_len\t= sizeof(struct {c_lower(family.fixed_header)}),') 2738 + elif family.fixed_header: 2750 2739 cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),') 2751 2740 else: 2752 2741 cw.p('.hdr_len\t= sizeof(struct genlmsghdr),') 2753 2742 if family.ntfs: 2754 - cw.p(f".ntf_info\t= {family['name']}_ntf_info,") 2755 - cw.p(f".ntf_info_size\t= YNL_ARRAY_SIZE({family['name']}_ntf_info),") 2743 + cw.p(f".ntf_info\t= {family.c_name}_ntf_info,") 2744 + cw.p(f".ntf_info_size\t= YNL_ARRAY_SIZE({family.c_name}_ntf_info),") 2756 2745 cw.block_end(line=';') 2757 2746 2758 2747 ··· 2983 2962 ri = RenderInfo(cw, parsed, args.mode, op, 'dump') 2984 2963 print_req_type(ri) 2985 2964 print_req_type_helpers(ri) 2986 - if not ri.type_consistent: 2965 + if not ri.type_consistent or ri.type_oneside: 2987 2966 print_rsp_type(ri) 2988 2967 print_wrapped_type(ri) 2989 2968 print_dump_prototype(ri) ··· 3061 3040 if 'dump' in op: 3062 3041 cw.p(f"/* {op.enum_name} - dump */") 3063 3042 ri = RenderInfo(cw, parsed, args.mode, op, "dump") 3064 - if not ri.type_consistent: 3043 + if not ri.type_consistent or ri.type_oneside: 3065 3044 parse_rsp_msg(ri, deref=True) 3066 3045 print_req_free(ri) 3067 3046 print_dump_type_free(ri)
+2
tools/net/ynl/samples/.gitignore
··· 3 3 netdev 4 4 ovs 5 5 page-pool 6 + rt-addr 7 + rt-route
+80
tools/net/ynl/samples/rt-addr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <arpa/inet.h> 8 + #include <net/if.h> 9 + 10 + #include "rt-addr-user.h" 11 + 12 + static void rt_addr_print(struct rt_addr_getaddr_rsp *a) 13 + { 14 + char ifname[IF_NAMESIZE]; 15 + char addr_str[64]; 16 + const char *addr; 17 + const char *name; 18 + 19 + name = if_indextoname(a->_hdr.ifa_index, ifname); 20 + if (name) 21 + printf("%16s: ", name); 22 + 23 + switch (a->_present.address_len) { 24 + case 4: 25 + addr = inet_ntop(AF_INET, a->address, 26 + addr_str, sizeof(addr_str)); 27 + break; 28 + case 16: 29 + addr = inet_ntop(AF_INET6, a->address, 30 + addr_str, sizeof(addr_str)); 31 + break; 32 + default: 33 + addr = NULL; 34 + break; 35 + } 36 + if (addr) 37 + printf("%s", addr); 38 + else 39 + printf("[%d]", a->_present.address_len); 40 + 41 + printf("\n"); 42 + } 43 + 44 + int main(int argc, char **argv) 45 + { 46 + struct rt_addr_getaddr_list *rsp; 47 + struct rt_addr_getaddr_req *req; 48 + struct ynl_error yerr; 49 + struct ynl_sock *ys; 50 + 51 + ys = ynl_sock_create(&ynl_rt_addr_family, &yerr); 52 + if (!ys) { 53 + fprintf(stderr, "YNL: %s\n", yerr.msg); 54 + return 1; 55 + } 56 + 57 + req = rt_addr_getaddr_req_alloc(); 58 + if (!req) 59 + goto err_destroy; 60 + 61 + rsp = rt_addr_getaddr_dump(ys, req); 62 + rt_addr_getaddr_req_free(req); 63 + if (!rsp) 64 + goto err_close; 65 + 66 + if (ynl_dump_empty(rsp)) 67 + fprintf(stderr, "Error: no addresses reported\n"); 68 + ynl_dump_foreach(rsp, addr) 69 + rt_addr_print(addr); 70 + rt_addr_getaddr_list_free(rsp); 71 + 72 + ynl_sock_destroy(ys); 73 + return 0; 74 + 75 + err_close: 76 + fprintf(stderr, "YNL: %s\n", ys->err.msg); 77 + err_destroy: 78 + ynl_sock_destroy(ys); 79 + return 2; 80 + }
+80
tools/net/ynl/samples/rt-route.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <arpa/inet.h> 8 + #include <net/if.h> 9 + 10 + #include "rt-route-user.h" 11 + 12 + static void rt_route_print(struct rt_route_getroute_rsp *r) 13 + { 14 + char ifname[IF_NAMESIZE]; 15 + char route_str[64]; 16 + const char *route; 17 + const char *name; 18 + 19 + /* Ignore local */ 20 + if (r->_hdr.rtm_table == RT_TABLE_LOCAL) 21 + return; 22 + 23 + if (r->_present.oif) { 24 + name = if_indextoname(r->oif, ifname); 25 + if (name) 26 + printf("oif: %-16s ", name); 27 + } 28 + 29 + if (r->_present.dst_len) { 30 + route = inet_ntop(r->_hdr.rtm_family, r->dst, 31 + route_str, sizeof(route_str)); 32 + printf("dst: %s/%d", route, r->_hdr.rtm_dst_len); 33 + } 34 + 35 + if (r->_present.gateway_len) { 36 + route = inet_ntop(r->_hdr.rtm_family, r->gateway, 37 + route_str, sizeof(route_str)); 38 + printf("gateway: %s ", route); 39 + } 40 + 41 + printf("\n"); 42 + } 43 + 44 + int main(int argc, char **argv) 45 + { 46 + struct rt_route_getroute_req_dump *req; 47 + struct rt_route_getroute_list *rsp; 48 + struct ynl_error yerr; 49 + struct ynl_sock *ys; 50 + 51 + ys = ynl_sock_create(&ynl_rt_route_family, &yerr); 52 + if (!ys) { 53 + fprintf(stderr, "YNL: %s\n", yerr.msg); 54 + return 1; 55 + } 56 + 57 + req = rt_route_getroute_req_dump_alloc(); 58 + if (!req) 59 + goto err_destroy; 60 + 61 + rsp = rt_route_getroute_dump(ys, req); 62 + rt_route_getroute_req_dump_free(req); 63 + if (!rsp) 64 + goto err_close; 65 + 66 + if (ynl_dump_empty(rsp)) 67 + fprintf(stderr, "Error: no routeesses reported\n"); 68 + ynl_dump_foreach(rsp, route) 69 + rt_route_print(route); 70 + rt_route_getroute_list_free(rsp); 71 + 72 + ynl_sock_destroy(ys); 73 + return 0; 74 + 75 + err_close: 76 + fprintf(stderr, "YNL: %s\n", ys->err.msg); 77 + err_destroy: 78 + ynl_sock_destroy(ys); 79 + return 2; 80 + }
+2 -2
tools/testing/selftests/net/lib/py/ynl.py
··· 39 39 40 40 class RtnlFamily(YnlFamily): 41 41 def __init__(self, recv_size=0): 42 - super().__init__((SPEC_PATH / Path('rt_link.yaml')).as_posix(), 42 + super().__init__((SPEC_PATH / Path('rt-link.yaml')).as_posix(), 43 43 schema='', recv_size=recv_size) 44 44 45 45 class RtnlAddrFamily(YnlFamily): 46 46 def __init__(self, recv_size=0): 47 - super().__init__((SPEC_PATH / Path('rt_addr.yaml')).as_posix(), 47 + super().__init__((SPEC_PATH / Path('rt-addr.yaml')).as_posix(), 48 48 schema='', recv_size=recv_size) 49 49 50 50 class NetdevFamily(YnlFamily):