chiark / gitweb /
Prep v220: Apply "Fixes to user and session saving"
[elogind.git] / src / libelogind / sd-rtnl / rtnl-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 "rtnl-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 = NLA_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 = NLA_U16 },
50 };
51
52 static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
53         [IFLA_MACVLAN_MODE]  = { .type = NLA_U32 },
54         [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
55 };
56
57 static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
58         [IFLA_BRIDGE_FLAGS]     = { .type = NLA_U16 },
59         [IFLA_BRIDGE_MODE]      = { .type = NLA_U16 },
60 /*
61         [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_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 = NLA_U16 },
68 /*
69         [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
70         [IFLA_VLAN_EGRESS_QOS]  = { .type = NLA_NESTED },
71         [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
72 */
73         [IFLA_VLAN_PROTOCOL]    = { .type = NLA_U16 },
74 };
75
76 static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
77         [IFLA_VXLAN_ID] = { .type = NLA_U32 },
78         [IFLA_VXLAN_GROUP] = {.type = NLA_IN_ADDR },
79         [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
80         [IFLA_VXLAN_LOCAL] = { .type = NLA_U32},
81         [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
82         [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
83         [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
84         [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
85         [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
86         [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_U32},
87         [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
88         [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
89         [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
90         [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
91 };
92
93 static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
94         [BOND_ARP_TARGETS_0]        = { .type = NLA_U32 },
95         [BOND_ARP_TARGETS_1]        = { .type = NLA_U32 },
96         [BOND_ARP_TARGETS_2]        = { .type = NLA_U32 },
97         [BOND_ARP_TARGETS_3]        = { .type = NLA_U32 },
98         [BOND_ARP_TARGETS_4]        = { .type = NLA_U32 },
99         [BOND_ARP_TARGETS_5]        = { .type = NLA_U32 },
100         [BOND_ARP_TARGETS_6]        = { .type = NLA_U32 },
101         [BOND_ARP_TARGETS_7]        = { .type = NLA_U32 },
102         [BOND_ARP_TARGETS_8]        = { .type = NLA_U32 },
103         [BOND_ARP_TARGETS_9]        = { .type = NLA_U32 },
104         [BOND_ARP_TARGETS_10]       = { .type = NLA_U32 },
105         [BOND_ARP_TARGETS_11]       = { .type = NLA_U32 },
106         [BOND_ARP_TARGETS_12]       = { .type = NLA_U32 },
107         [BOND_ARP_TARGETS_13]       = { .type = NLA_U32 },
108         [BOND_ARP_TARGETS_14]       = { .type = NLA_U32 },
109         [BOND_ARP_TARGETS_MAX]      = { .type = NLA_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 = NLA_U8 },
119         [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NLA_U32 },
120         [IFLA_BOND_MIIMON]              = { .type = NLA_U32 },
121         [IFLA_BOND_UPDELAY]             = { .type = NLA_U32 },
122         [IFLA_BOND_DOWNDELAY]           = { .type = NLA_U32 },
123         [IFLA_BOND_USE_CARRIER]         = { .type = NLA_U8 },
124         [IFLA_BOND_ARP_INTERVAL]        = { .type = NLA_U32 },
125         [IFLA_BOND_ARP_IP_TARGET]       = { .type = NLA_NESTED, .type_system = &rtnl_bond_arp_type_system },
126         [IFLA_BOND_ARP_VALIDATE]        = { .type = NLA_U32 },
127         [IFLA_BOND_ARP_ALL_TARGETS]     = { .type = NLA_U32 },
128         [IFLA_BOND_PRIMARY]             = { .type = NLA_U32 },
129         [IFLA_BOND_PRIMARY_RESELECT]    = { .type = NLA_U8 },
130         [IFLA_BOND_FAIL_OVER_MAC]       = { .type = NLA_U8 },
131         [IFLA_BOND_XMIT_HASH_POLICY]    = { .type = NLA_U8 },
132         [IFLA_BOND_RESEND_IGMP]         = { .type = NLA_U32 },
133         [IFLA_BOND_NUM_PEER_NOTIF]      = { .type = NLA_U8 },
134         [IFLA_BOND_ALL_SLAVES_ACTIVE]   = { .type = NLA_U8 },
135         [IFLA_BOND_MIN_LINKS]           = { .type = NLA_U32 },
136         [IFLA_BOND_LP_INTERVAL]         = { .type = NLA_U32 },
137         [IFLA_BOND_PACKETS_PER_SLAVE]   = { .type = NLA_U32 },
138         [IFLA_BOND_AD_LACP_RATE]        = { .type = NLA_U8 },
139         [IFLA_BOND_AD_SELECT]           = { .type = NLA_U8 },
140         [IFLA_BOND_AD_INFO]             = { .type = NLA_NESTED },
141 };
142
143 static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
144         [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
145         [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
146         [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
147         [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
148         [IFLA_IPTUN_TOS]                 = { .type = NLA_U8 },
149         [IFLA_IPTUN_PMTUDISC]            = { .type = NLA_U8 },
150         [IFLA_IPTUN_FLAGS]               = { .type = NLA_U16 },
151         [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
152         [IFLA_IPTUN_6RD_PREFIX]          = { .type = NLA_IN_ADDR },
153         [IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NLA_U32 },
154         [IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NLA_U16 },
155         [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
156 };
157
158 static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
159         [IFLA_GRE_LINK]     = { .type = NLA_U32 },
160         [IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
161         [IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
162         [IFLA_GRE_IKEY]     = { .type = NLA_U32 },
163         [IFLA_GRE_OKEY]     = { .type = NLA_U32 },
164         [IFLA_GRE_LOCAL]    = { .type = NLA_IN_ADDR },
165         [IFLA_GRE_REMOTE]   = { .type = NLA_IN_ADDR },
166         [IFLA_GRE_TTL]      = { .type = NLA_U8 },
167         [IFLA_GRE_TOS]      = { .type = NLA_U8 },
168         [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
169 };
170
171 static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
172         [IFLA_VTI_LINK]         = { .type = NLA_U32 },
173         [IFLA_VTI_IKEY]         = { .type = NLA_U32 },
174         [IFLA_VTI_OKEY]         = { .type = NLA_U32 },
175         [IFLA_VTI_LOCAL]        = { .type = NLA_IN_ADDR  },
176         [IFLA_VTI_REMOTE]       = { .type = NLA_IN_ADDR  },
177 };
178
179 static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
180         [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
181         [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
182         [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
183         [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
184         [IFLA_IPTUN_FLAGS]               = { .type = NLA_U32 },
185         [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
186         [IFLA_IPTUN_ENCAP_LIMIT]         = { .type = NLA_U8 },
187         [IFLA_IPTUN_FLOWINFO]            = { .type = NLA_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 = NLA_STRING },
259         [IFLA_INFO_DATA]        = { .type = NLA_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
260 /*
261         [IFLA_INFO_XSTATS],
262         [IFLA_INFO_SLAVE_KIND]  = { .type = NLA_STRING },
263         [IFLA_INFO_SLAVE_DATA]  = { .type = NLA_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 = NLA_U8 },
274         [IFLA_BRPORT_COST]      = { .type = NLA_U32 },
275         [IFLA_BRPORT_PRIORITY]  = { .type = NLA_U16 },
276         [IFLA_BRPORT_MODE]      = { .type = NLA_U8 },
277         [IFLA_BRPORT_GUARD]     = { .type = NLA_U8 },
278         [IFLA_BRPORT_PROTECT]   = { .type = NLA_U8 },
279         [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
280         [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_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 = NLA_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 = NLA_IN_ADDR },
304         [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NLA_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 = NLA_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 = NLA_ETHER_ADDR, },
323         [IFLA_BROADCAST]        = { .type = NLA_ETHER_ADDR, },
324         [IFLA_IFNAME]           = { .type = NLA_STRING, .size = IFNAMSIZ - 1, },
325         [IFLA_MTU]              = { .type = NLA_U32 },
326         [IFLA_LINK]             = { .type = NLA_U32 },
327 /*
328         [IFLA_QDISC],
329         [IFLA_STATS],
330         [IFLA_COST],
331         [IFLA_PRIORITY],
332 */
333         [IFLA_MASTER]           = { .type = NLA_U32 },
334 /*
335         [IFLA_WIRELESS],
336 */
337         [IFLA_PROTINFO]         = { .type = NLA_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
338         [IFLA_TXQLEN]           = { .type = NLA_U32 },
339 /*
340         [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
341 */
342         [IFLA_WEIGHT]           = { .type = NLA_U32 },
343         [IFLA_OPERSTATE]        = { .type = NLA_U8 },
344         [IFLA_LINKMODE]         = { .type = NLA_U8 },
345         [IFLA_LINKINFO]         = { .type = NLA_NESTED, .type_system = &rtnl_link_info_type_system },
346         [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
347         [IFLA_IFALIAS]          = { .type = NLA_STRING, .size = IFALIASZ - 1 },
348 /*
349         [IFLA_NUM_VF],
350         [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED, },
351         [IFLA_STATS64],
352         [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
353         [IFLA_PORT_SELF]        = { .type = NLA_NESTED },
354 */
355         [IFLA_AF_SPEC]          = { .type = NLA_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 = NLA_U32 },
362         [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
363         [IFLA_EXT_MASK]         = { .type = NLA_U32 },
364         [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
365         [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
366         [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
367         [IFLA_CARRIER]          = { .type = NLA_U8 },
368 /*
369         [IFLA_PHYS_PORT_ID]     = { .type = NLA_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 = NLA_IN_ADDR },
382         [IFA_LOCAL]             = { .type = NLA_IN_ADDR },
383         [IFA_LABEL]             = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
384         [IFA_BROADCAST]         = { .type = NLA_IN_ADDR }, /* 6? */
385         [IFA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
386 /*
387         [IFA_ANYCAST],
388         [IFA_MULTICAST],
389         [IFA_FLAGS]             = { .type = NLA_U32 },
390 */
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 = NLA_IN_ADDR }, /* 6? */
400         [RTA_SRC]               = { .type = NLA_IN_ADDR }, /* 6? */
401         [RTA_IIF]               = { .type = NLA_U32 },
402         [RTA_OIF]               = { .type = NLA_U32 },
403         [RTA_GATEWAY]           = { .type = NLA_IN_ADDR },
404         [RTA_PRIORITY]          = { .type = NLA_U32 },
405         [RTA_PREFSRC]           = { .type = NLA_IN_ADDR }, /* 6? */
406 /*
407         [RTA_METRICS]           = { .type = NLA_NESTED },
408         [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
409 */
410         [RTA_FLOW]              = { .type = NLA_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 = NLA_IN_ADDR },
426         [NDA_LLADDR]            = { .type = NLA_ETHER_ADDR },
427         [NDA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
428         [NDA_PROBES]            = { .type = NLA_U32 },
429         [NDA_VLAN]              = { .type = NLA_U16 },
430         [NDA_PORT]              = { .type = NLA_U16 },
431         [NDA_VNI]               = { .type = NLA_U32 },
432         [NDA_IFINDEX]           = { .type = NLA_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 = NLA_META, .size = 0 },
442         [NLMSG_ERROR]  = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
443         [RTM_NEWLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
444         [RTM_DELLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
445         [RTM_GETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
446         [RTM_SETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
447         [RTM_NEWADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
448         [RTM_DELADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
449         [RTM_GETADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
450         [RTM_NEWROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
451         [RTM_DELROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
452         [RTM_GETROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
453         [RTM_NEWNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
454         [RTM_DELNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
455         [RTM_GETNEIGH] = { .type = NLA_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 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
464         const NLType *nl_type;
465
466         assert(ret);
467
468         if (!type_system)
469                 type_system = &rtnl_type_system;
470
471         assert(type_system->types);
472
473         if (type > type_system->max)
474                 return -EOPNOTSUPP;
475
476         nl_type = &type_system->types[type];
477
478         if (nl_type->type == NLA_UNSPEC)
479                 return -EOPNOTSUPP;
480
481         *ret = nl_type;
482
483         return 0;
484 }
485
486 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
487         const NLType *nl_type;
488         int r;
489
490         assert(ret);
491
492         r = type_system_get_type(type_system, &nl_type, type);
493         if (r < 0)
494                 return r;
495
496         assert(nl_type->type == NLA_NESTED);
497         assert(nl_type->type_system);
498
499         *ret = nl_type->type_system;
500
501         return 0;
502 }
503
504 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **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         assert(nl_type->type == NLA_UNION);
515         assert(nl_type->type_system_union);
516
517         *ret = nl_type->type_system_union;
518
519         return 0;
520 }
521
522 int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
523         int type;
524
525         assert(type_system_union);
526         assert(type_system_union->match_type == NL_MATCH_SIBLING);
527         assert(type_system_union->lookup);
528         assert(type_system_union->type_systems);
529         assert(ret);
530         assert(key);
531
532         type = type_system_union->lookup(key);
533         if (type < 0)
534                 return -EOPNOTSUPP;
535
536         assert(type < type_system_union->num);
537
538         *ret = &type_system_union->type_systems[type];
539
540         return 0;
541 }
542
543 int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
544         const NLTypeSystem *type_system;
545
546         assert(type_system_union);
547         assert(type_system_union->type_systems);
548         assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
549         assert(ret);
550
551         if (protocol >= type_system_union->num)
552                 return -EOPNOTSUPP;
553
554         type_system = &type_system_union->type_systems[protocol];
555         if (type_system->max == 0)
556                 return -EOPNOTSUPP;
557
558         *ret = type_system;
559
560         return 0;
561 }