chiark / gitweb /
fe9e5f9826dc5e99688ed4cf37c673666014edc0
[elogind.git] / src / libsystemd / sd-netlink / netlink-types.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdint.h>
23 #include <sys/socket.h>
24 #include <linux/netlink.h>
25 #include <linux/rtnetlink.h>
26 #include <linux/in6.h>
27 #include <linux/veth.h>
28 #include <linux/if_bridge.h>
29 #include <linux/if_addr.h>
30 #include <linux/if.h>
31
32 #include <linux/ip.h>
33 #include <linux/if_link.h>
34 #include <linux/if_tunnel.h>
35
36 #include "macro.h"
37 #include "util.h"
38
39 #include "netlink-types.h"
40 #include "missing.h"
41
42 static const NLTypeSystem rtnl_link_type_system;
43
44 static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
45         [VETH_INFO_PEER]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
46 };
47
48 static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
49         [IFLA_IPVLAN_MODE]  = { .type = NETLINK_TYPE_U16 },
50 };
51
52 static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
53         [IFLA_MACVLAN_MODE]  = { .type = NETLINK_TYPE_U32 },
54         [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
55 };
56
57 static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
58         [IFLA_BRIDGE_FLAGS]     = { .type = NETLINK_TYPE_U16 },
59         [IFLA_BRIDGE_MODE]      = { .type = NETLINK_TYPE_U16 },
60 /*
61         [IFLA_BRIDGE_VLAN_INFO] = { .type = NETLINK_TYPE_BINARY,
62                                     .len = sizeof(struct bridge_vlan_info), },
63 */
64 };
65
66 static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
67         [IFLA_VLAN_ID]          = { .type = NETLINK_TYPE_U16 },
68 /*
69         [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
70         [IFLA_VLAN_EGRESS_QOS]  = { .type = NETLINK_TYPE_NESTED },
71         [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED },
72 */
73         [IFLA_VLAN_PROTOCOL]    = { .type = NETLINK_TYPE_U16 },
74 };
75
76 static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
77         [IFLA_VXLAN_ID]         = { .type = NETLINK_TYPE_U32 },
78         [IFLA_VXLAN_GROUP]      = { .type = NETLINK_TYPE_IN_ADDR },
79         [IFLA_VXLAN_LINK]       = { .type = NETLINK_TYPE_U32 },
80         [IFLA_VXLAN_LOCAL]      = { .type = NETLINK_TYPE_U32},
81         [IFLA_VXLAN_TTL]        = { .type = NETLINK_TYPE_U8 },
82         [IFLA_VXLAN_TOS]        = { .type = NETLINK_TYPE_U8 },
83         [IFLA_VXLAN_LEARNING]   = { .type = NETLINK_TYPE_U8 },
84         [IFLA_VXLAN_AGEING]     = { .type = NETLINK_TYPE_U32 },
85         [IFLA_VXLAN_LIMIT]      = { .type = NETLINK_TYPE_U32 },
86         [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32},
87         [IFLA_VXLAN_PROXY]      = { .type = NETLINK_TYPE_U8 },
88         [IFLA_VXLAN_RSC]        = { .type = NETLINK_TYPE_U8 },
89         [IFLA_VXLAN_L2MISS]     = { .type = NETLINK_TYPE_U8 },
90         [IFLA_VXLAN_L3MISS]     = { .type = NETLINK_TYPE_U8 },
91 };
92
93 static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
94         [BOND_ARP_TARGETS_0]        = { .type = NETLINK_TYPE_U32 },
95         [BOND_ARP_TARGETS_1]        = { .type = NETLINK_TYPE_U32 },
96         [BOND_ARP_TARGETS_2]        = { .type = NETLINK_TYPE_U32 },
97         [BOND_ARP_TARGETS_3]        = { .type = NETLINK_TYPE_U32 },
98         [BOND_ARP_TARGETS_4]        = { .type = NETLINK_TYPE_U32 },
99         [BOND_ARP_TARGETS_5]        = { .type = NETLINK_TYPE_U32 },
100         [BOND_ARP_TARGETS_6]        = { .type = NETLINK_TYPE_U32 },
101         [BOND_ARP_TARGETS_7]        = { .type = NETLINK_TYPE_U32 },
102         [BOND_ARP_TARGETS_8]        = { .type = NETLINK_TYPE_U32 },
103         [BOND_ARP_TARGETS_9]        = { .type = NETLINK_TYPE_U32 },
104         [BOND_ARP_TARGETS_10]       = { .type = NETLINK_TYPE_U32 },
105         [BOND_ARP_TARGETS_11]       = { .type = NETLINK_TYPE_U32 },
106         [BOND_ARP_TARGETS_12]       = { .type = NETLINK_TYPE_U32 },
107         [BOND_ARP_TARGETS_13]       = { .type = NETLINK_TYPE_U32 },
108         [BOND_ARP_TARGETS_14]       = { .type = NETLINK_TYPE_U32 },
109         [BOND_ARP_TARGETS_MAX]      = { .type = NETLINK_TYPE_U32 },
110 };
111
112 static const NLTypeSystem rtnl_bond_arp_type_system = {
113         .max = ELEMENTSOF(rtnl_bond_arp_target_types) - 1,
114         .types = rtnl_bond_arp_target_types,
115 };
116
117 static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
118         [IFLA_BOND_MODE]                = { .type = NETLINK_TYPE_U8 },
119         [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NETLINK_TYPE_U32 },
120         [IFLA_BOND_MIIMON]              = { .type = NETLINK_TYPE_U32 },
121         [IFLA_BOND_UPDELAY]             = { .type = NETLINK_TYPE_U32 },
122         [IFLA_BOND_DOWNDELAY]           = { .type = NETLINK_TYPE_U32 },
123         [IFLA_BOND_USE_CARRIER]         = { .type = NETLINK_TYPE_U8 },
124         [IFLA_BOND_ARP_INTERVAL]        = { .type = NETLINK_TYPE_U32 },
125         [IFLA_BOND_ARP_IP_TARGET]       = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_bond_arp_type_system },
126         [IFLA_BOND_ARP_VALIDATE]        = { .type = NETLINK_TYPE_U32 },
127         [IFLA_BOND_ARP_ALL_TARGETS]     = { .type = NETLINK_TYPE_U32 },
128         [IFLA_BOND_PRIMARY]             = { .type = NETLINK_TYPE_U32 },
129         [IFLA_BOND_PRIMARY_RESELECT]    = { .type = NETLINK_TYPE_U8 },
130         [IFLA_BOND_FAIL_OVER_MAC]       = { .type = NETLINK_TYPE_U8 },
131         [IFLA_BOND_XMIT_HASH_POLICY]    = { .type = NETLINK_TYPE_U8 },
132         [IFLA_BOND_RESEND_IGMP]         = { .type = NETLINK_TYPE_U32 },
133         [IFLA_BOND_NUM_PEER_NOTIF]      = { .type = NETLINK_TYPE_U8 },
134         [IFLA_BOND_ALL_SLAVES_ACTIVE]   = { .type = NETLINK_TYPE_U8 },
135         [IFLA_BOND_MIN_LINKS]           = { .type = NETLINK_TYPE_U32 },
136         [IFLA_BOND_LP_INTERVAL]         = { .type = NETLINK_TYPE_U32 },
137         [IFLA_BOND_PACKETS_PER_SLAVE]   = { .type = NETLINK_TYPE_U32 },
138         [IFLA_BOND_AD_LACP_RATE]        = { .type = NETLINK_TYPE_U8 },
139         [IFLA_BOND_AD_SELECT]           = { .type = NETLINK_TYPE_U8 },
140         [IFLA_BOND_AD_INFO]             = { .type = NETLINK_TYPE_NESTED },
141 };
142
143 static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
144         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
145         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
146         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
147         [IFLA_IPTUN_TTL]                 = { .type = NETLINK_TYPE_U8 },
148         [IFLA_IPTUN_TOS]                 = { .type = NETLINK_TYPE_U8 },
149         [IFLA_IPTUN_PMTUDISC]            = { .type = NETLINK_TYPE_U8 },
150         [IFLA_IPTUN_FLAGS]               = { .type = NETLINK_TYPE_U16 },
151         [IFLA_IPTUN_PROTO]               = { .type = NETLINK_TYPE_U8 },
152         [IFLA_IPTUN_6RD_PREFIX]          = { .type = NETLINK_TYPE_IN_ADDR },
153         [IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NETLINK_TYPE_U32 },
154         [IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NETLINK_TYPE_U16 },
155         [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
156 };
157
158 static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
159         [IFLA_GRE_LINK]     = { .type = NETLINK_TYPE_U32 },
160         [IFLA_GRE_IFLAGS]   = { .type = NETLINK_TYPE_U16 },
161         [IFLA_GRE_OFLAGS]   = { .type = NETLINK_TYPE_U16 },
162         [IFLA_GRE_IKEY]     = { .type = NETLINK_TYPE_U32 },
163         [IFLA_GRE_OKEY]     = { .type = NETLINK_TYPE_U32 },
164         [IFLA_GRE_LOCAL]    = { .type = NETLINK_TYPE_IN_ADDR },
165         [IFLA_GRE_REMOTE]   = { .type = NETLINK_TYPE_IN_ADDR },
166         [IFLA_GRE_TTL]      = { .type = NETLINK_TYPE_U8 },
167         [IFLA_GRE_TOS]      = { .type = NETLINK_TYPE_U8 },
168         [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
169 };
170
171 static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
172         [IFLA_VTI_LINK]         = { .type = NETLINK_TYPE_U32 },
173         [IFLA_VTI_IKEY]         = { .type = NETLINK_TYPE_U32 },
174         [IFLA_VTI_OKEY]         = { .type = NETLINK_TYPE_U32 },
175         [IFLA_VTI_LOCAL]        = { .type = NETLINK_TYPE_IN_ADDR  },
176         [IFLA_VTI_REMOTE]       = { .type = NETLINK_TYPE_IN_ADDR  },
177 };
178
179 static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
180         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
181         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
182         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
183         [IFLA_IPTUN_TTL]                 = { .type = NETLINK_TYPE_U8 },
184         [IFLA_IPTUN_FLAGS]               = { .type = NETLINK_TYPE_U32 },
185         [IFLA_IPTUN_PROTO]               = { .type = NETLINK_TYPE_U8 },
186         [IFLA_IPTUN_ENCAP_LIMIT]         = { .type = NETLINK_TYPE_U8 },
187         [IFLA_IPTUN_FLOWINFO]            = { .type = NETLINK_TYPE_U32},
188 };
189
190 /* these strings must match the .kind entries in the kernel */
191 static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
192         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
193         [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
194         [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
195         [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
196         [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
197         [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
198         [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
199         [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
200         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
201         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
202         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
203         [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = "ip6gre",
204         [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap",
205         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
206         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
207         [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
208         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
209 };
210
211 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
212
213 static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
214         [NL_UNION_LINK_INFO_DATA_BOND] =        { .max = ELEMENTSOF(rtnl_link_info_data_bond_types) - 1,
215                                                   .types = rtnl_link_info_data_bond_types },
216         [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .max = ELEMENTSOF(rtnl_link_info_data_bridge_types) - 1,
217                                                   .types = rtnl_link_info_data_bridge_types },
218         [NL_UNION_LINK_INFO_DATA_VLAN] =        { .max = ELEMENTSOF(rtnl_link_info_data_vlan_types) - 1,
219                                                   .types = rtnl_link_info_data_vlan_types },
220         [NL_UNION_LINK_INFO_DATA_VETH] =        { .max = ELEMENTSOF(rtnl_link_info_data_veth_types) - 1,
221                                                   .types = rtnl_link_info_data_veth_types },
222         [NL_UNION_LINK_INFO_DATA_MACVLAN] =     { .max = ELEMENTSOF(rtnl_link_info_data_macvlan_types) - 1,
223                                                   .types = rtnl_link_info_data_macvlan_types },
224         [NL_UNION_LINK_INFO_DATA_IPVLAN] =      { .max = ELEMENTSOF(rtnl_link_info_data_ipvlan_types) - 1,
225                                                   .types = rtnl_link_info_data_ipvlan_types },
226         [NL_UNION_LINK_INFO_DATA_VXLAN] =       { .max = ELEMENTSOF(rtnl_link_info_data_vxlan_types) - 1,
227                                                   .types = rtnl_link_info_data_vxlan_types },
228         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
229                                                   .types = rtnl_link_info_data_iptun_types },
230         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
231                                                     .types = rtnl_link_info_data_ipgre_types },
232         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
233                                                     .types = rtnl_link_info_data_ipgre_types },
234         [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
235                                                     .types = rtnl_link_info_data_ipgre_types },
236         [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
237                                                     .types = rtnl_link_info_data_ipgre_types },
238         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
239                                                   .types = rtnl_link_info_data_iptun_types },
240         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
241                                                   .types = rtnl_link_info_data_ipvti_types },
242         [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
243                                                   .types = rtnl_link_info_data_ipvti_types },
244         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types) - 1,
245                                                      .types = rtnl_link_info_data_ip6tnl_types },
246
247 };
248
249 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
250         .num = _NL_UNION_LINK_INFO_DATA_MAX,
251         .lookup = nl_union_link_info_data_from_string,
252         .type_systems = rtnl_link_info_data_type_systems,
253         .match_type = NL_MATCH_SIBLING,
254         .match = IFLA_INFO_KIND,
255 };
256
257 static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
258         [IFLA_INFO_KIND]        = { .type = NETLINK_TYPE_STRING },
259         [IFLA_INFO_DATA]        = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
260 /*
261         [IFLA_INFO_XSTATS],
262         [IFLA_INFO_SLAVE_KIND]  = { .type = NETLINK_TYPE_STRING },
263         [IFLA_INFO_SLAVE_DATA]  = { .type = NETLINK_TYPE_NESTED },
264 */
265 };
266
267 static const NLTypeSystem rtnl_link_info_type_system = {
268         .max = ELEMENTSOF(rtnl_link_info_types) - 1,
269         .types = rtnl_link_info_types,
270 };
271
272 static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
273         [IFLA_BRPORT_STATE]             = { .type = NETLINK_TYPE_U8 },
274         [IFLA_BRPORT_COST]              = { .type = NETLINK_TYPE_U32 },
275         [IFLA_BRPORT_PRIORITY]          = { .type = NETLINK_TYPE_U16 },
276         [IFLA_BRPORT_MODE]              = { .type = NETLINK_TYPE_U8 },
277         [IFLA_BRPORT_GUARD]             = { .type = NETLINK_TYPE_U8 },
278         [IFLA_BRPORT_PROTECT]           = { .type = NETLINK_TYPE_U8 },
279         [IFLA_BRPORT_LEARNING]          = { .type = NETLINK_TYPE_U8 },
280         [IFLA_BRPORT_UNICAST_FLOOD]     = { .type = NETLINK_TYPE_U8 },
281 };
282
283 static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
284         [AF_BRIDGE] =   { .max = ELEMENTSOF(rtnl_prot_info_bridge_port_types) - 1,
285                           .types = rtnl_prot_info_bridge_port_types },
286 };
287
288 static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
289         .num = AF_MAX,
290         .type_systems = rtnl_prot_info_type_systems,
291         .match_type = NL_MATCH_PROTOCOL,
292 };
293
294 static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
295         [IFLA_INET6_FLAGS]              = { .type = NETLINK_TYPE_U32 },
296 /*
297         IFLA_INET6_CONF,
298         IFLA_INET6_STATS,
299         IFLA_INET6_MCAST,
300         IFLA_INET6_CACHEINFO,
301         IFLA_INET6_ICMP6STATS,
302 */
303         [IFLA_INET6_TOKEN]              = { .type = NETLINK_TYPE_IN_ADDR },
304         [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NETLINK_TYPE_U8 },
305 };
306
307 static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
308         .max = ELEMENTSOF(rtnl_af_spec_inet6_types) - 1,
309         .types = rtnl_af_spec_inet6_types,
310 };
311
312 static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
313         [AF_INET6] =    { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
314 };
315
316 static const NLTypeSystem rtnl_af_spec_type_system = {
317         .max = ELEMENTSOF(rtnl_af_spec_types) - 1,
318         .types = rtnl_af_spec_types,
319 };
320
321 static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
322         [IFLA_ADDRESS]          = { .type = NETLINK_TYPE_ETHER_ADDR, },
323         [IFLA_BROADCAST]        = { .type = NETLINK_TYPE_ETHER_ADDR, },
324         [IFLA_IFNAME]           = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1, },
325         [IFLA_MTU]              = { .type = NETLINK_TYPE_U32 },
326         [IFLA_LINK]             = { .type = NETLINK_TYPE_U32 },
327 /*
328         [IFLA_QDISC],
329         [IFLA_STATS],
330         [IFLA_COST],
331         [IFLA_PRIORITY],
332 */
333         [IFLA_MASTER]           = { .type = NETLINK_TYPE_U32 },
334 /*
335         [IFLA_WIRELESS],
336 */
337         [IFLA_PROTINFO]         = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
338         [IFLA_TXQLEN]           = { .type = NETLINK_TYPE_U32 },
339 /*
340         [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
341 */
342         [IFLA_WEIGHT]           = { .type = NETLINK_TYPE_U32 },
343         [IFLA_OPERSTATE]        = { .type = NETLINK_TYPE_U8 },
344         [IFLA_LINKMODE]         = { .type = NETLINK_TYPE_U8 },
345         [IFLA_LINKINFO]         = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system },
346         [IFLA_NET_NS_PID]       = { .type = NETLINK_TYPE_U32 },
347         [IFLA_IFALIAS]          = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 },
348 /*
349         [IFLA_NUM_VF],
350         [IFLA_VFINFO_LIST]      = {. type = NETLINK_TYPE_NESTED, },
351         [IFLA_STATS64],
352         [IFLA_VF_PORTS]         = { .type = NETLINK_TYPE_NESTED },
353         [IFLA_PORT_SELF]        = { .type = NETLINK_TYPE_NESTED },
354 */
355         [IFLA_AF_SPEC]          = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_type_system },
356 /*
357         [IFLA_VF_PORTS],
358         [IFLA_PORT_SELF],
359         [IFLA_AF_SPEC],
360 */
361         [IFLA_GROUP]            = { .type = NETLINK_TYPE_U32 },
362         [IFLA_NET_NS_FD]        = { .type = NETLINK_TYPE_U32 },
363         [IFLA_EXT_MASK]         = { .type = NETLINK_TYPE_U32 },
364         [IFLA_PROMISCUITY]      = { .type = NETLINK_TYPE_U32 },
365         [IFLA_NUM_TX_QUEUES]    = { .type = NETLINK_TYPE_U32 },
366         [IFLA_NUM_RX_QUEUES]    = { .type = NETLINK_TYPE_U32 },
367         [IFLA_CARRIER]          = { .type = NETLINK_TYPE_U8 },
368 /*
369         [IFLA_PHYS_PORT_ID]     = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
370 */
371 };
372
373 static const NLTypeSystem rtnl_link_type_system = {
374         .max = ELEMENTSOF(rtnl_link_types) - 1,
375         .types = rtnl_link_types,
376 };
377
378 /* IFA_FLAGS was defined in kernel 3.14, but we still support older
379  * kernels where IFA_MAX is lower. */
380 static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
381         [IFA_ADDRESS]           = { .type = NETLINK_TYPE_IN_ADDR },
382         [IFA_LOCAL]             = { .type = NETLINK_TYPE_IN_ADDR },
383         [IFA_LABEL]             = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
384         [IFA_BROADCAST]         = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
385         [IFA_CACHEINFO]         = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
386 /*
387         [IFA_ANYCAST],
388         [IFA_MULTICAST],
389 */
390         [IFA_FLAGS]             = { .type = NETLINK_TYPE_U32 },
391 };
392
393 static const NLTypeSystem rtnl_address_type_system = {
394         .max = ELEMENTSOF(rtnl_address_types) - 1,
395         .types = rtnl_address_types,
396 };
397
398 static const NLType rtnl_route_types[RTA_MAX + 1] = {
399         [RTA_DST]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
400         [RTA_SRC]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
401         [RTA_IIF]               = { .type = NETLINK_TYPE_U32 },
402         [RTA_OIF]               = { .type = NETLINK_TYPE_U32 },
403         [RTA_GATEWAY]           = { .type = NETLINK_TYPE_IN_ADDR },
404         [RTA_PRIORITY]          = { .type = NETLINK_TYPE_U32 },
405         [RTA_PREFSRC]           = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
406 /*
407         [RTA_METRICS]           = { .type = NETLINK_TYPE_NESTED },
408         [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
409 */
410         [RTA_FLOW]              = { .type = NETLINK_TYPE_U32 }, /* 6? */
411 /*
412         RTA_CACHEINFO,
413         RTA_TABLE,
414         RTA_MARK,
415         RTA_MFC_STATS,
416 */
417 };
418
419 static const NLTypeSystem rtnl_route_type_system = {
420         .max = ELEMENTSOF(rtnl_route_types) - 1,
421         .types = rtnl_route_types,
422 };
423
424 static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
425         [NDA_DST]               = { .type = NETLINK_TYPE_IN_ADDR },
426         [NDA_LLADDR]            = { .type = NETLINK_TYPE_ETHER_ADDR },
427         [NDA_CACHEINFO]         = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
428         [NDA_PROBES]            = { .type = NETLINK_TYPE_U32 },
429         [NDA_VLAN]              = { .type = NETLINK_TYPE_U16 },
430         [NDA_PORT]              = { .type = NETLINK_TYPE_U16 },
431         [NDA_VNI]               = { .type = NETLINK_TYPE_U32 },
432         [NDA_IFINDEX]           = { .type = NETLINK_TYPE_U32 },
433 };
434
435 static const NLTypeSystem rtnl_neigh_type_system = {
436         .max = ELEMENTSOF(rtnl_neigh_types) - 1,
437         .types = rtnl_neigh_types,
438 };
439
440 static const NLType rtnl_types[RTM_MAX + 1] = {
441         [NLMSG_DONE]   = { .type = NETLINK_TYPE_META, .size = 0 },
442         [NLMSG_ERROR]  = { .type = NETLINK_TYPE_META, .size = sizeof(struct nlmsgerr) },
443         [RTM_NEWLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
444         [RTM_DELLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
445         [RTM_GETLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
446         [RTM_SETLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
447         [RTM_NEWADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
448         [RTM_DELADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
449         [RTM_GETADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
450         [RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
451         [RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
452         [RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
453         [RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
454         [RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
455         [RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
456 };
457
458 const NLTypeSystem rtnl_type_system = {
459         .max = ELEMENTSOF(rtnl_types) - 1,
460         .types = rtnl_types,
461 };
462
463 void type_get_type_system(const NLType *nl_type, const NLTypeSystem **ret) {
464         assert(nl_type);
465         assert(ret);
466         assert(nl_type->type == NETLINK_TYPE_NESTED);
467         assert(nl_type->type_system);
468
469         *ret = nl_type->type_system;
470 }
471
472 void type_get_type_system_union(const NLType *nl_type, const NLTypeSystemUnion **ret) {
473         assert(nl_type);
474         assert(ret);
475         assert(nl_type->type == NETLINK_TYPE_UNION);
476         assert(nl_type->type_system_union);
477
478         *ret = nl_type->type_system_union;
479 }
480
481 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
482         const NLType *nl_type;
483
484         assert(ret);
485
486         if (!type_system)
487                 type_system = &rtnl_type_system;
488
489         assert(type_system->types);
490
491         if (type > type_system->max)
492                 return -EOPNOTSUPP;
493
494         nl_type = &type_system->types[type];
495
496         if (nl_type->type == NETLINK_TYPE_UNSPEC)
497                 return -EOPNOTSUPP;
498
499         *ret = nl_type;
500
501         return 0;
502 }
503
504 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
505         const NLType *nl_type;
506         int r;
507
508         assert(ret);
509
510         r = type_system_get_type(type_system, &nl_type, type);
511         if (r < 0)
512                 return r;
513
514         type_get_type_system(nl_type, ret);
515         return 0;
516 }
517
518 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
519         const NLType *nl_type;
520         int r;
521
522         assert(ret);
523
524         r = type_system_get_type(type_system, &nl_type, type);
525         if (r < 0)
526                 return r;
527
528         type_get_type_system_union(nl_type, ret);
529         return 0;
530 }
531
532 int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
533         int type;
534
535         assert(type_system_union);
536         assert(type_system_union->match_type == NL_MATCH_SIBLING);
537         assert(type_system_union->lookup);
538         assert(type_system_union->type_systems);
539         assert(ret);
540         assert(key);
541
542         type = type_system_union->lookup(key);
543         if (type < 0)
544                 return -EOPNOTSUPP;
545
546         assert(type < type_system_union->num);
547
548         *ret = &type_system_union->type_systems[type];
549
550         return 0;
551 }
552
553 int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
554         const NLTypeSystem *type_system;
555
556         assert(type_system_union);
557         assert(type_system_union->type_systems);
558         assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
559         assert(ret);
560
561         if (protocol >= type_system_union->num)
562                 return -EOPNOTSUPP;
563
564         type_system = &type_system_union->type_systems[protocol];
565         if (type_system->max == 0)
566                 return -EOPNOTSUPP;
567
568         *ret = type_system;
569
570         return 0;
571 }