chiark / gitweb /
networkd: Add support for bond option.
[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_IP6TNL_TUNNEL] = "ip6tnl",
208 };
209
210 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
211
212 static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
213         [NL_UNION_LINK_INFO_DATA_BOND] =        { .max = ELEMENTSOF(rtnl_link_info_data_bond_types) - 1,
214                                                   .types = rtnl_link_info_data_bond_types },
215         [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .max = ELEMENTSOF(rtnl_link_info_data_bridge_types) - 1,
216                                                   .types = rtnl_link_info_data_bridge_types },
217         [NL_UNION_LINK_INFO_DATA_VLAN] =        { .max = ELEMENTSOF(rtnl_link_info_data_vlan_types) - 1,
218                                                   .types = rtnl_link_info_data_vlan_types },
219         [NL_UNION_LINK_INFO_DATA_VETH] =        { .max = ELEMENTSOF(rtnl_link_info_data_veth_types) - 1,
220                                                   .types = rtnl_link_info_data_veth_types },
221         [NL_UNION_LINK_INFO_DATA_MACVLAN] =     { .max = ELEMENTSOF(rtnl_link_info_data_macvlan_types) - 1,
222                                                   .types = rtnl_link_info_data_macvlan_types },
223         [NL_UNION_LINK_INFO_DATA_IPVLAN] =      { .max = ELEMENTSOF(rtnl_link_info_data_ipvlan_types) - 1,
224                                                   .types = rtnl_link_info_data_ipvlan_types },
225         [NL_UNION_LINK_INFO_DATA_VXLAN] =       { .max = ELEMENTSOF(rtnl_link_info_data_vxlan_types) - 1,
226                                                   .types = rtnl_link_info_data_vxlan_types },
227         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
228                                                   .types = rtnl_link_info_data_iptun_types },
229         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
230                                                     .types = rtnl_link_info_data_ipgre_types },
231         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
232                                                     .types = rtnl_link_info_data_ipgre_types },
233         [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
234                                                     .types = rtnl_link_info_data_ipgre_types },
235         [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
236                                                     .types = rtnl_link_info_data_ipgre_types },
237         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
238                                                   .types = rtnl_link_info_data_iptun_types },
239         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
240                                                   .types = rtnl_link_info_data_ipvti_types },
241         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types) - 1,
242                                                      .types = rtnl_link_info_data_ip6tnl_types },
243
244 };
245
246 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
247         .num = _NL_UNION_LINK_INFO_DATA_MAX,
248         .lookup = nl_union_link_info_data_from_string,
249         .type_systems = rtnl_link_info_data_type_systems,
250         .match_type = NL_MATCH_SIBLING,
251         .match = IFLA_INFO_KIND,
252 };
253
254 static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
255         [IFLA_INFO_KIND]        = { .type = NLA_STRING },
256         [IFLA_INFO_DATA]        = { .type = NLA_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
257 /*
258         [IFLA_INFO_XSTATS],
259         [IFLA_INFO_SLAVE_KIND]  = { .type = NLA_STRING },
260         [IFLA_INFO_SLAVE_DATA]  = { .type = NLA_NESTED },
261 */
262 };
263
264 static const NLTypeSystem rtnl_link_info_type_system = {
265         .max = ELEMENTSOF(rtnl_link_info_types) - 1,
266         .types = rtnl_link_info_types,
267 };
268
269 static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
270         [IFLA_BRPORT_STATE]     = { .type = NLA_U8 },
271         [IFLA_BRPORT_COST]      = { .type = NLA_U32 },
272         [IFLA_BRPORT_PRIORITY]  = { .type = NLA_U16 },
273         [IFLA_BRPORT_MODE]      = { .type = NLA_U8 },
274         [IFLA_BRPORT_GUARD]     = { .type = NLA_U8 },
275         [IFLA_BRPORT_PROTECT]   = { .type = NLA_U8 },
276         [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
277         [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
278 };
279
280 static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
281         [AF_BRIDGE] =   { .max = ELEMENTSOF(rtnl_prot_info_bridge_port_types) - 1,
282                           .types = rtnl_prot_info_bridge_port_types },
283 };
284
285 static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
286         .num = AF_MAX,
287         .type_systems = rtnl_prot_info_type_systems,
288         .match_type = NL_MATCH_PROTOCOL,
289 };
290
291 static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
292         [IFLA_INET6_FLAGS]              = { .type = NLA_U32 },
293 /*
294         IFLA_INET6_CONF,
295         IFLA_INET6_STATS,
296         IFLA_INET6_MCAST,
297         IFLA_INET6_CACHEINFO,
298         IFLA_INET6_ICMP6STATS,
299 */
300         [IFLA_INET6_TOKEN]              = { .type = NLA_IN_ADDR },
301         [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NLA_U8 },
302 };
303
304 static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
305         .max = ELEMENTSOF(rtnl_af_spec_inet6_types) - 1,
306         .types = rtnl_af_spec_inet6_types,
307 };
308
309 static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
310         [AF_INET6] =    { .type = NLA_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
311 };
312
313 static const NLTypeSystem rtnl_af_spec_type_system = {
314         .max = ELEMENTSOF(rtnl_af_spec_types) - 1,
315         .types = rtnl_af_spec_types,
316 };
317
318 static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
319         [IFLA_ADDRESS]          = { .type = NLA_ETHER_ADDR, },
320         [IFLA_BROADCAST]        = { .type = NLA_ETHER_ADDR, },
321         [IFLA_IFNAME]           = { .type = NLA_STRING, .size = IFNAMSIZ - 1, },
322         [IFLA_MTU]              = { .type = NLA_U32 },
323         [IFLA_LINK]             = { .type = NLA_U32 },
324 /*
325         [IFLA_QDISC],
326         [IFLA_STATS],
327         [IFLA_COST],
328         [IFLA_PRIORITY],
329 */
330         [IFLA_MASTER]           = { .type = NLA_U32 },
331 /*
332         [IFLA_WIRELESS],
333 */
334         [IFLA_PROTINFO]         = { .type = NLA_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
335         [IFLA_TXQLEN]           = { .type = NLA_U32 },
336 /*
337         [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
338 */
339         [IFLA_WEIGHT]           = { .type = NLA_U32 },
340         [IFLA_OPERSTATE]        = { .type = NLA_U8 },
341         [IFLA_LINKMODE]         = { .type = NLA_U8 },
342         [IFLA_LINKINFO]         = { .type = NLA_NESTED, .type_system = &rtnl_link_info_type_system },
343         [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
344         [IFLA_IFALIAS]          = { .type = NLA_STRING, .size = IFALIASZ - 1 },
345 /*
346         [IFLA_NUM_VF],
347         [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED, },
348         [IFLA_STATS64],
349         [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
350         [IFLA_PORT_SELF]        = { .type = NLA_NESTED },
351 */
352         [IFLA_AF_SPEC]          = { .type = NLA_NESTED, .type_system = &rtnl_af_spec_type_system },
353 /*
354         [IFLA_VF_PORTS],
355         [IFLA_PORT_SELF],
356         [IFLA_AF_SPEC],
357 */
358         [IFLA_GROUP]            = { .type = NLA_U32 },
359         [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
360         [IFLA_EXT_MASK]         = { .type = NLA_U32 },
361         [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
362         [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
363         [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
364         [IFLA_CARRIER]          = { .type = NLA_U8 },
365 /*
366         [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
367 */
368 };
369
370 static const NLTypeSystem rtnl_link_type_system = {
371         .max = ELEMENTSOF(rtnl_link_types) - 1,
372         .types = rtnl_link_types,
373 };
374
375 static const NLType rtnl_address_types[IFA_MAX + 1] = {
376         [IFA_ADDRESS]           = { .type = NLA_IN_ADDR },
377         [IFA_LOCAL]             = { .type = NLA_IN_ADDR },
378         [IFA_LABEL]             = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
379         [IFA_BROADCAST]         = { .type = NLA_IN_ADDR }, /* 6? */
380         [IFA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
381 /*
382         [IFA_ANYCAST],
383         [IFA_MULTICAST],
384         [IFA_FLAGS]             = { .type = NLA_U32 },
385 */
386 };
387
388 static const NLTypeSystem rtnl_address_type_system = {
389         .max = ELEMENTSOF(rtnl_address_types) - 1,
390         .types = rtnl_address_types,
391 };
392
393 static const NLType rtnl_route_types[RTA_MAX + 1] = {
394         [RTA_DST]               = { .type = NLA_IN_ADDR }, /* 6? */
395         [RTA_SRC]               = { .type = NLA_IN_ADDR }, /* 6? */
396         [RTA_IIF]               = { .type = NLA_U32 },
397         [RTA_OIF]               = { .type = NLA_U32 },
398         [RTA_GATEWAY]           = { .type = NLA_IN_ADDR },
399         [RTA_PRIORITY]          = { .type = NLA_U32 },
400         [RTA_PREFSRC]           = { .type = NLA_IN_ADDR }, /* 6? */
401 /*
402         [RTA_METRICS]           = { .type = NLA_NESTED },
403         [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
404 */
405         [RTA_FLOW]              = { .type = NLA_U32 }, /* 6? */
406 /*
407         RTA_CACHEINFO,
408         RTA_TABLE,
409         RTA_MARK,
410         RTA_MFC_STATS,
411 */
412 };
413
414 static const NLTypeSystem rtnl_route_type_system = {
415         .max = ELEMENTSOF(rtnl_route_types) - 1,
416         .types = rtnl_route_types,
417 };
418
419 static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
420         [NDA_DST]               = { .type = NLA_IN_ADDR },
421         [NDA_LLADDR]            = { .type = NLA_ETHER_ADDR },
422         [NDA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
423         [NDA_PROBES]            = { .type = NLA_U32 },
424         [NDA_VLAN]              = { .type = NLA_U16 },
425         [NDA_PORT]              = { .type = NLA_U16 },
426         [NDA_VNI]               = { .type = NLA_U32 },
427         [NDA_IFINDEX]           = { .type = NLA_U32 },
428 };
429
430 static const NLTypeSystem rtnl_neigh_type_system = {
431         .max = ELEMENTSOF(rtnl_neigh_types) - 1,
432         .types = rtnl_neigh_types,
433 };
434
435 static const NLType rtnl_types[RTM_MAX + 1] = {
436         [NLMSG_DONE]   = { .type = NLA_META, .size = 0 },
437         [NLMSG_ERROR]  = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
438         [RTM_NEWLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
439         [RTM_DELLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
440         [RTM_GETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
441         [RTM_SETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
442         [RTM_NEWADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
443         [RTM_DELADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
444         [RTM_GETADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
445         [RTM_NEWROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
446         [RTM_DELROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
447         [RTM_GETROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
448         [RTM_NEWNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
449         [RTM_DELNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
450         [RTM_GETNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
451 };
452
453 const NLTypeSystem rtnl_type_system = {
454         .max = ELEMENTSOF(rtnl_types) - 1,
455         .types = rtnl_types,
456 };
457
458 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
459         const NLType *nl_type;
460
461         assert(ret);
462
463         if (!type_system)
464                 type_system = &rtnl_type_system;
465
466         assert(type_system->types);
467
468         if (type > type_system->max)
469                 return -EOPNOTSUPP;
470
471         nl_type = &type_system->types[type];
472
473         if (nl_type->type == NLA_UNSPEC)
474                 return -EOPNOTSUPP;
475
476         *ret = nl_type;
477
478         return 0;
479 }
480
481 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
482         const NLType *nl_type;
483         int r;
484
485         assert(ret);
486
487         r = type_system_get_type(type_system, &nl_type, type);
488         if (r < 0)
489                 return r;
490
491         assert(nl_type->type == NLA_NESTED);
492         assert(nl_type->type_system);
493
494         *ret = nl_type->type_system;
495
496         return 0;
497 }
498
499 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
500         const NLType *nl_type;
501         int r;
502
503         assert(ret);
504
505         r = type_system_get_type(type_system, &nl_type, type);
506         if (r < 0)
507                 return r;
508
509         assert(nl_type->type == NLA_UNION);
510         assert(nl_type->type_system_union);
511
512         *ret = nl_type->type_system_union;
513
514         return 0;
515 }
516
517 int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
518         int type;
519
520         assert(type_system_union);
521         assert(type_system_union->match_type == NL_MATCH_SIBLING);
522         assert(type_system_union->lookup);
523         assert(type_system_union->type_systems);
524         assert(ret);
525         assert(key);
526
527         type = type_system_union->lookup(key);
528         if (type < 0)
529                 return -EOPNOTSUPP;
530
531         assert(type < type_system_union->num);
532
533         *ret = &type_system_union->type_systems[type];
534
535         return 0;
536 }
537
538 int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
539         const NLTypeSystem *type_system;
540
541         assert(type_system_union);
542         assert(type_system_union->type_systems);
543         assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
544         assert(ret);
545
546         if (protocol >= type_system_union->num)
547                 return -EOPNOTSUPP;
548
549         type_system = &type_system_union->type_systems[protocol];
550         if (type_system->max == 0)
551                 return -EOPNOTSUPP;
552
553         *ret = type_system;
554
555         return 0;
556 }