chiark / gitweb /
sd-netlink: add tunnel NL parameters
[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 /* Maximum ARP IP target defined in kernel */
43 #define BOND_MAX_ARP_TARGETS    16
44
45 typedef enum {
46         BOND_ARP_TARGETS_0,
47         BOND_ARP_TARGETS_1,
48         BOND_ARP_TARGETS_2,
49         BOND_ARP_TARGETS_3,
50         BOND_ARP_TARGETS_4,
51         BOND_ARP_TARGETS_5,
52         BOND_ARP_TARGETS_6,
53         BOND_ARP_TARGETS_7,
54         BOND_ARP_TARGETS_8,
55         BOND_ARP_TARGETS_9,
56         BOND_ARP_TARGETS_10,
57         BOND_ARP_TARGETS_11,
58         BOND_ARP_TARGETS_12,
59         BOND_ARP_TARGETS_13,
60         BOND_ARP_TARGETS_14,
61         BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS,
62 } BondArpTargets;
63
64 struct NLType {
65         uint16_t type;
66         size_t size;
67         const NLTypeSystem *type_system;
68         const NLTypeSystemUnion *type_system_union;
69 };
70
71 struct NLTypeSystem {
72         uint16_t count;
73         const NLType *types;
74 };
75
76 static const NLTypeSystem rtnl_link_type_system;
77
78 static const NLType empty_types[1] = {
79         /* fake array to avoid .types==NULL, which denotes invalid type-systems */
80 };
81
82 static const NLTypeSystem empty_type_system = {
83         .count = 0,
84         .types = empty_types,
85 };
86
87 static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
88         [VETH_INFO_PEER]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
89 };
90
91 static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
92         [IFLA_IPVLAN_MODE]  = { .type = NETLINK_TYPE_U16 },
93 };
94
95 static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
96         [IFLA_MACVLAN_MODE]  = { .type = NETLINK_TYPE_U32 },
97         [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
98 };
99
100 static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
101         [IFLA_BRIDGE_FLAGS]     = { .type = NETLINK_TYPE_U16 },
102         [IFLA_BRIDGE_MODE]      = { .type = NETLINK_TYPE_U16 },
103 /*
104         [IFLA_BRIDGE_VLAN_INFO] = { .type = NETLINK_TYPE_BINARY,
105                                     .len = sizeof(struct bridge_vlan_info), },
106 */
107 };
108
109 static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
110         [IFLA_VLAN_ID]          = { .type = NETLINK_TYPE_U16 },
111 /*
112         [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
113         [IFLA_VLAN_EGRESS_QOS]  = { .type = NETLINK_TYPE_NESTED },
114         [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED },
115 */
116         [IFLA_VLAN_PROTOCOL]    = { .type = NETLINK_TYPE_U16 },
117 };
118
119 static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
120         [IFLA_VXLAN_ID]         = { .type = NETLINK_TYPE_U32 },
121         [IFLA_VXLAN_GROUP]      = { .type = NETLINK_TYPE_IN_ADDR },
122         [IFLA_VXLAN_LINK]       = { .type = NETLINK_TYPE_U32 },
123         [IFLA_VXLAN_LOCAL]      = { .type = NETLINK_TYPE_U32},
124         [IFLA_VXLAN_TTL]        = { .type = NETLINK_TYPE_U8 },
125         [IFLA_VXLAN_TOS]        = { .type = NETLINK_TYPE_U8 },
126         [IFLA_VXLAN_LEARNING]   = { .type = NETLINK_TYPE_U8 },
127         [IFLA_VXLAN_AGEING]     = { .type = NETLINK_TYPE_U32 },
128         [IFLA_VXLAN_LIMIT]      = { .type = NETLINK_TYPE_U32 },
129         [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32},
130         [IFLA_VXLAN_PROXY]      = { .type = NETLINK_TYPE_U8 },
131         [IFLA_VXLAN_RSC]        = { .type = NETLINK_TYPE_U8 },
132         [IFLA_VXLAN_L2MISS]     = { .type = NETLINK_TYPE_U8 },
133         [IFLA_VXLAN_L3MISS]     = { .type = NETLINK_TYPE_U8 },
134 };
135
136 static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
137         [BOND_ARP_TARGETS_0]        = { .type = NETLINK_TYPE_U32 },
138         [BOND_ARP_TARGETS_1]        = { .type = NETLINK_TYPE_U32 },
139         [BOND_ARP_TARGETS_2]        = { .type = NETLINK_TYPE_U32 },
140         [BOND_ARP_TARGETS_3]        = { .type = NETLINK_TYPE_U32 },
141         [BOND_ARP_TARGETS_4]        = { .type = NETLINK_TYPE_U32 },
142         [BOND_ARP_TARGETS_5]        = { .type = NETLINK_TYPE_U32 },
143         [BOND_ARP_TARGETS_6]        = { .type = NETLINK_TYPE_U32 },
144         [BOND_ARP_TARGETS_7]        = { .type = NETLINK_TYPE_U32 },
145         [BOND_ARP_TARGETS_8]        = { .type = NETLINK_TYPE_U32 },
146         [BOND_ARP_TARGETS_9]        = { .type = NETLINK_TYPE_U32 },
147         [BOND_ARP_TARGETS_10]       = { .type = NETLINK_TYPE_U32 },
148         [BOND_ARP_TARGETS_11]       = { .type = NETLINK_TYPE_U32 },
149         [BOND_ARP_TARGETS_12]       = { .type = NETLINK_TYPE_U32 },
150         [BOND_ARP_TARGETS_13]       = { .type = NETLINK_TYPE_U32 },
151         [BOND_ARP_TARGETS_14]       = { .type = NETLINK_TYPE_U32 },
152         [BOND_ARP_TARGETS_MAX]      = { .type = NETLINK_TYPE_U32 },
153 };
154
155 static const NLTypeSystem rtnl_bond_arp_type_system = {
156         .count = ELEMENTSOF(rtnl_bond_arp_target_types),
157         .types = rtnl_bond_arp_target_types,
158 };
159
160 static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
161         [IFLA_BOND_MODE]                = { .type = NETLINK_TYPE_U8 },
162         [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NETLINK_TYPE_U32 },
163         [IFLA_BOND_MIIMON]              = { .type = NETLINK_TYPE_U32 },
164         [IFLA_BOND_UPDELAY]             = { .type = NETLINK_TYPE_U32 },
165         [IFLA_BOND_DOWNDELAY]           = { .type = NETLINK_TYPE_U32 },
166         [IFLA_BOND_USE_CARRIER]         = { .type = NETLINK_TYPE_U8 },
167         [IFLA_BOND_ARP_INTERVAL]        = { .type = NETLINK_TYPE_U32 },
168         [IFLA_BOND_ARP_IP_TARGET]       = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_bond_arp_type_system },
169         [IFLA_BOND_ARP_VALIDATE]        = { .type = NETLINK_TYPE_U32 },
170         [IFLA_BOND_ARP_ALL_TARGETS]     = { .type = NETLINK_TYPE_U32 },
171         [IFLA_BOND_PRIMARY]             = { .type = NETLINK_TYPE_U32 },
172         [IFLA_BOND_PRIMARY_RESELECT]    = { .type = NETLINK_TYPE_U8 },
173         [IFLA_BOND_FAIL_OVER_MAC]       = { .type = NETLINK_TYPE_U8 },
174         [IFLA_BOND_XMIT_HASH_POLICY]    = { .type = NETLINK_TYPE_U8 },
175         [IFLA_BOND_RESEND_IGMP]         = { .type = NETLINK_TYPE_U32 },
176         [IFLA_BOND_NUM_PEER_NOTIF]      = { .type = NETLINK_TYPE_U8 },
177         [IFLA_BOND_ALL_SLAVES_ACTIVE]   = { .type = NETLINK_TYPE_U8 },
178         [IFLA_BOND_MIN_LINKS]           = { .type = NETLINK_TYPE_U32 },
179         [IFLA_BOND_LP_INTERVAL]         = { .type = NETLINK_TYPE_U32 },
180         [IFLA_BOND_PACKETS_PER_SLAVE]   = { .type = NETLINK_TYPE_U32 },
181         [IFLA_BOND_AD_LACP_RATE]        = { .type = NETLINK_TYPE_U8 },
182         [IFLA_BOND_AD_SELECT]           = { .type = NETLINK_TYPE_U8 },
183         [IFLA_BOND_AD_INFO]             = { .type = NETLINK_TYPE_NESTED },
184 };
185
186 static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
187         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
188         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
189         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
190         [IFLA_IPTUN_TTL]                 = { .type = NETLINK_TYPE_U8 },
191         [IFLA_IPTUN_TOS]                 = { .type = NETLINK_TYPE_U8 },
192         [IFLA_IPTUN_PMTUDISC]            = { .type = NETLINK_TYPE_U8 },
193         [IFLA_IPTUN_FLAGS]               = { .type = NETLINK_TYPE_U16 },
194         [IFLA_IPTUN_PROTO]               = { .type = NETLINK_TYPE_U8 },
195         [IFLA_IPTUN_6RD_PREFIX]          = { .type = NETLINK_TYPE_IN_ADDR },
196         [IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NETLINK_TYPE_U32 },
197         [IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NETLINK_TYPE_U16 },
198         [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
199         [IFLA_IPTUN_ENCAP_TYPE]          = { .type = NETLINK_TYPE_U16},
200         [IFLA_IPTUN_ENCAP_FLAGS]         = { .type = NETLINK_TYPE_U16},
201         [IFLA_IPTUN_ENCAP_SPORT]         = { .type = NETLINK_TYPE_U16},
202         [IFLA_IPTUN_ENCAP_DPORT]         = { .type = NETLINK_TYPE_U16},
203 };
204
205 static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
206         [IFLA_GRE_LINK]     = { .type = NETLINK_TYPE_U32 },
207         [IFLA_GRE_IFLAGS]   = { .type = NETLINK_TYPE_U16 },
208         [IFLA_GRE_OFLAGS]   = { .type = NETLINK_TYPE_U16 },
209         [IFLA_GRE_IKEY]     = { .type = NETLINK_TYPE_U32 },
210         [IFLA_GRE_OKEY]     = { .type = NETLINK_TYPE_U32 },
211         [IFLA_GRE_LOCAL]    = { .type = NETLINK_TYPE_IN_ADDR },
212         [IFLA_GRE_REMOTE]   = { .type = NETLINK_TYPE_IN_ADDR },
213         [IFLA_GRE_TTL]      = { .type = NETLINK_TYPE_U8 },
214         [IFLA_GRE_TOS]      = { .type = NETLINK_TYPE_U8 },
215         [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
216 };
217
218 static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
219         [IFLA_VTI_LINK]         = { .type = NETLINK_TYPE_U32 },
220         [IFLA_VTI_IKEY]         = { .type = NETLINK_TYPE_U32 },
221         [IFLA_VTI_OKEY]         = { .type = NETLINK_TYPE_U32 },
222         [IFLA_VTI_LOCAL]        = { .type = NETLINK_TYPE_IN_ADDR  },
223         [IFLA_VTI_REMOTE]       = { .type = NETLINK_TYPE_IN_ADDR  },
224 };
225
226 static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
227         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
228         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
229         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
230         [IFLA_IPTUN_TTL]                 = { .type = NETLINK_TYPE_U8 },
231         [IFLA_IPTUN_FLAGS]               = { .type = NETLINK_TYPE_U32 },
232         [IFLA_IPTUN_PROTO]               = { .type = NETLINK_TYPE_U8 },
233         [IFLA_IPTUN_ENCAP_LIMIT]         = { .type = NETLINK_TYPE_U8 },
234         [IFLA_IPTUN_FLOWINFO]            = { .type = NETLINK_TYPE_U32},
235 };
236
237 /* these strings must match the .kind entries in the kernel */
238 static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
239         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
240         [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
241         [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
242         [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
243         [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
244         [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
245         [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
246         [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
247         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
248         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
249         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
250         [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = "ip6gre",
251         [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap",
252         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
253         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
254         [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
255         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
256 };
257
258 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
259
260 static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
261         [NL_UNION_LINK_INFO_DATA_BOND] =        { .count = ELEMENTSOF(rtnl_link_info_data_bond_types),
262                                                   .types = rtnl_link_info_data_bond_types },
263         [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .count = ELEMENTSOF(rtnl_link_info_data_bridge_types),
264                                                   .types = rtnl_link_info_data_bridge_types },
265         [NL_UNION_LINK_INFO_DATA_VLAN] =        { .count = ELEMENTSOF(rtnl_link_info_data_vlan_types),
266                                                   .types = rtnl_link_info_data_vlan_types },
267         [NL_UNION_LINK_INFO_DATA_VETH] =        { .count = ELEMENTSOF(rtnl_link_info_data_veth_types),
268                                                   .types = rtnl_link_info_data_veth_types },
269         [NL_UNION_LINK_INFO_DATA_MACVLAN] =     { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types),
270                                                   .types = rtnl_link_info_data_macvlan_types },
271         [NL_UNION_LINK_INFO_DATA_IPVLAN] =      { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types),
272                                                   .types = rtnl_link_info_data_ipvlan_types },
273         [NL_UNION_LINK_INFO_DATA_VXLAN] =       { .count = ELEMENTSOF(rtnl_link_info_data_vxlan_types),
274                                                   .types = rtnl_link_info_data_vxlan_types },
275         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
276                                                   .types = rtnl_link_info_data_iptun_types },
277         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
278                                                     .types = rtnl_link_info_data_ipgre_types },
279         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
280                                                     .types = rtnl_link_info_data_ipgre_types },
281         [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
282                                                     .types = rtnl_link_info_data_ipgre_types },
283         [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
284                                                     .types = rtnl_link_info_data_ipgre_types },
285         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
286                                                   .types = rtnl_link_info_data_iptun_types },
287         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
288                                                   .types = rtnl_link_info_data_ipvti_types },
289         [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
290                                                   .types = rtnl_link_info_data_ipvti_types },
291         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] =  { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types),
292                                                      .types = rtnl_link_info_data_ip6tnl_types },
293
294 };
295
296 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
297         .num = _NL_UNION_LINK_INFO_DATA_MAX,
298         .lookup = nl_union_link_info_data_from_string,
299         .type_systems = rtnl_link_info_data_type_systems,
300         .match_type = NL_MATCH_SIBLING,
301         .match = IFLA_INFO_KIND,
302 };
303
304 static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
305         [IFLA_INFO_KIND]        = { .type = NETLINK_TYPE_STRING },
306         [IFLA_INFO_DATA]        = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
307 /*
308         [IFLA_INFO_XSTATS],
309         [IFLA_INFO_SLAVE_KIND]  = { .type = NETLINK_TYPE_STRING },
310         [IFLA_INFO_SLAVE_DATA]  = { .type = NETLINK_TYPE_NESTED },
311 */
312 };
313
314 static const NLTypeSystem rtnl_link_info_type_system = {
315         .count = ELEMENTSOF(rtnl_link_info_types),
316         .types = rtnl_link_info_types,
317 };
318
319 static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
320         [IFLA_BRPORT_STATE]             = { .type = NETLINK_TYPE_U8 },
321         [IFLA_BRPORT_COST]              = { .type = NETLINK_TYPE_U32 },
322         [IFLA_BRPORT_PRIORITY]          = { .type = NETLINK_TYPE_U16 },
323         [IFLA_BRPORT_MODE]              = { .type = NETLINK_TYPE_U8 },
324         [IFLA_BRPORT_GUARD]             = { .type = NETLINK_TYPE_U8 },
325         [IFLA_BRPORT_PROTECT]           = { .type = NETLINK_TYPE_U8 },
326         [IFLA_BRPORT_LEARNING]          = { .type = NETLINK_TYPE_U8 },
327         [IFLA_BRPORT_UNICAST_FLOOD]     = { .type = NETLINK_TYPE_U8 },
328 };
329
330 static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
331         [AF_BRIDGE] =   { .count = ELEMENTSOF(rtnl_prot_info_bridge_port_types),
332                           .types = rtnl_prot_info_bridge_port_types },
333 };
334
335 static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
336         .num = AF_MAX,
337         .type_systems = rtnl_prot_info_type_systems,
338         .match_type = NL_MATCH_PROTOCOL,
339 };
340
341 static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
342         [IFLA_INET6_FLAGS]              = { .type = NETLINK_TYPE_U32 },
343 /*
344         IFLA_INET6_CONF,
345         IFLA_INET6_STATS,
346         IFLA_INET6_MCAST,
347         IFLA_INET6_CACHEINFO,
348         IFLA_INET6_ICMP6STATS,
349 */
350         [IFLA_INET6_TOKEN]              = { .type = NETLINK_TYPE_IN_ADDR },
351         [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NETLINK_TYPE_U8 },
352 };
353
354 static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
355         .count = ELEMENTSOF(rtnl_af_spec_inet6_types),
356         .types = rtnl_af_spec_inet6_types,
357 };
358
359 static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
360         [AF_INET6] =    { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
361 };
362
363 static const NLTypeSystem rtnl_af_spec_type_system = {
364         .count = ELEMENTSOF(rtnl_af_spec_types),
365         .types = rtnl_af_spec_types,
366 };
367
368 static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
369         [IFLA_ADDRESS]          = { .type = NETLINK_TYPE_ETHER_ADDR, },
370         [IFLA_BROADCAST]        = { .type = NETLINK_TYPE_ETHER_ADDR, },
371         [IFLA_IFNAME]           = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1, },
372         [IFLA_MTU]              = { .type = NETLINK_TYPE_U32 },
373         [IFLA_LINK]             = { .type = NETLINK_TYPE_U32 },
374 /*
375         [IFLA_QDISC],
376         [IFLA_STATS],
377         [IFLA_COST],
378         [IFLA_PRIORITY],
379 */
380         [IFLA_MASTER]           = { .type = NETLINK_TYPE_U32 },
381 /*
382         [IFLA_WIRELESS],
383 */
384         [IFLA_PROTINFO]         = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
385         [IFLA_TXQLEN]           = { .type = NETLINK_TYPE_U32 },
386 /*
387         [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
388 */
389         [IFLA_WEIGHT]           = { .type = NETLINK_TYPE_U32 },
390         [IFLA_OPERSTATE]        = { .type = NETLINK_TYPE_U8 },
391         [IFLA_LINKMODE]         = { .type = NETLINK_TYPE_U8 },
392         [IFLA_LINKINFO]         = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system },
393         [IFLA_NET_NS_PID]       = { .type = NETLINK_TYPE_U32 },
394         [IFLA_IFALIAS]          = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 },
395 /*
396         [IFLA_NUM_VF],
397         [IFLA_VFINFO_LIST]      = {. type = NETLINK_TYPE_NESTED, },
398         [IFLA_STATS64],
399         [IFLA_VF_PORTS]         = { .type = NETLINK_TYPE_NESTED },
400         [IFLA_PORT_SELF]        = { .type = NETLINK_TYPE_NESTED },
401 */
402         [IFLA_AF_SPEC]          = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_type_system },
403 /*
404         [IFLA_VF_PORTS],
405         [IFLA_PORT_SELF],
406         [IFLA_AF_SPEC],
407 */
408         [IFLA_GROUP]            = { .type = NETLINK_TYPE_U32 },
409         [IFLA_NET_NS_FD]        = { .type = NETLINK_TYPE_U32 },
410         [IFLA_EXT_MASK]         = { .type = NETLINK_TYPE_U32 },
411         [IFLA_PROMISCUITY]      = { .type = NETLINK_TYPE_U32 },
412         [IFLA_NUM_TX_QUEUES]    = { .type = NETLINK_TYPE_U32 },
413         [IFLA_NUM_RX_QUEUES]    = { .type = NETLINK_TYPE_U32 },
414         [IFLA_CARRIER]          = { .type = NETLINK_TYPE_U8 },
415 /*
416         [IFLA_PHYS_PORT_ID]     = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
417 */
418 };
419
420 static const NLTypeSystem rtnl_link_type_system = {
421         .count = ELEMENTSOF(rtnl_link_types),
422         .types = rtnl_link_types,
423 };
424
425 /* IFA_FLAGS was defined in kernel 3.14, but we still support older
426  * kernels where IFA_MAX is lower. */
427 static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
428         [IFA_ADDRESS]           = { .type = NETLINK_TYPE_IN_ADDR },
429         [IFA_LOCAL]             = { .type = NETLINK_TYPE_IN_ADDR },
430         [IFA_LABEL]             = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
431         [IFA_BROADCAST]         = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
432         [IFA_CACHEINFO]         = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
433 /*
434         [IFA_ANYCAST],
435         [IFA_MULTICAST],
436 */
437         [IFA_FLAGS]             = { .type = NETLINK_TYPE_U32 },
438 };
439
440 static const NLTypeSystem rtnl_address_type_system = {
441         .count = ELEMENTSOF(rtnl_address_types),
442         .types = rtnl_address_types,
443 };
444
445 static const NLType rtnl_route_types[RTA_MAX + 1] = {
446         [RTA_DST]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
447         [RTA_SRC]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
448         [RTA_IIF]               = { .type = NETLINK_TYPE_U32 },
449         [RTA_OIF]               = { .type = NETLINK_TYPE_U32 },
450         [RTA_GATEWAY]           = { .type = NETLINK_TYPE_IN_ADDR },
451         [RTA_PRIORITY]          = { .type = NETLINK_TYPE_U32 },
452         [RTA_PREFSRC]           = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
453 /*
454         [RTA_METRICS]           = { .type = NETLINK_TYPE_NESTED },
455         [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
456 */
457         [RTA_FLOW]              = { .type = NETLINK_TYPE_U32 }, /* 6? */
458 /*
459         RTA_CACHEINFO,
460         RTA_TABLE,
461         RTA_MARK,
462         RTA_MFC_STATS,
463 */
464 };
465
466 static const NLTypeSystem rtnl_route_type_system = {
467         .count = ELEMENTSOF(rtnl_route_types),
468         .types = rtnl_route_types,
469 };
470
471 static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
472         [NDA_DST]               = { .type = NETLINK_TYPE_IN_ADDR },
473         [NDA_LLADDR]            = { .type = NETLINK_TYPE_ETHER_ADDR },
474         [NDA_CACHEINFO]         = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
475         [NDA_PROBES]            = { .type = NETLINK_TYPE_U32 },
476         [NDA_VLAN]              = { .type = NETLINK_TYPE_U16 },
477         [NDA_PORT]              = { .type = NETLINK_TYPE_U16 },
478         [NDA_VNI]               = { .type = NETLINK_TYPE_U32 },
479         [NDA_IFINDEX]           = { .type = NETLINK_TYPE_U32 },
480 };
481
482 static const NLTypeSystem rtnl_neigh_type_system = {
483         .count = ELEMENTSOF(rtnl_neigh_types),
484         .types = rtnl_neigh_types,
485 };
486
487 static const NLType rtnl_types[RTM_MAX + 1] = {
488         [NLMSG_DONE]   = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
489         [NLMSG_ERROR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
490         [RTM_NEWLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
491         [RTM_DELLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
492         [RTM_GETLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
493         [RTM_SETLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
494         [RTM_NEWADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
495         [RTM_DELADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
496         [RTM_GETADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
497         [RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
498         [RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
499         [RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
500         [RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
501         [RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
502         [RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
503 };
504
505 const NLTypeSystem type_system_root = {
506         .count = ELEMENTSOF(rtnl_types),
507         .types = rtnl_types,
508 };
509
510 uint16_t type_get_type(const NLType *type) {
511         assert(type);
512         return type->type;
513 }
514
515 size_t type_get_size(const NLType *type) {
516         assert(type);
517         return type->size;
518 }
519
520 void type_get_type_system(const NLType *nl_type, const NLTypeSystem **ret) {
521         assert(nl_type);
522         assert(ret);
523         assert(nl_type->type == NETLINK_TYPE_NESTED);
524         assert(nl_type->type_system);
525
526         *ret = nl_type->type_system;
527 }
528
529 void type_get_type_system_union(const NLType *nl_type, const NLTypeSystemUnion **ret) {
530         assert(nl_type);
531         assert(ret);
532         assert(nl_type->type == NETLINK_TYPE_UNION);
533         assert(nl_type->type_system_union);
534
535         *ret = nl_type->type_system_union;
536 }
537
538 uint16_t type_system_get_count(const NLTypeSystem *type_system) {
539         assert(type_system);
540         return type_system->count;
541 }
542
543 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
544         const NLType *nl_type;
545
546         assert(ret);
547         assert(type_system);
548         assert(type_system->types);
549
550         if (type >= type_system->count)
551                 return -EOPNOTSUPP;
552
553         nl_type = &type_system->types[type];
554
555         if (nl_type->type == NETLINK_TYPE_UNSPEC)
556                 return -EOPNOTSUPP;
557
558         *ret = nl_type;
559
560         return 0;
561 }
562
563 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
564         const NLType *nl_type;
565         int r;
566
567         assert(ret);
568
569         r = type_system_get_type(type_system, &nl_type, type);
570         if (r < 0)
571                 return r;
572
573         type_get_type_system(nl_type, ret);
574         return 0;
575 }
576
577 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
578         const NLType *nl_type;
579         int r;
580
581         assert(ret);
582
583         r = type_system_get_type(type_system, &nl_type, type);
584         if (r < 0)
585                 return r;
586
587         type_get_type_system_union(nl_type, ret);
588         return 0;
589 }
590
591 int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
592         int type;
593
594         assert(type_system_union);
595         assert(type_system_union->match_type == NL_MATCH_SIBLING);
596         assert(type_system_union->lookup);
597         assert(type_system_union->type_systems);
598         assert(ret);
599         assert(key);
600
601         type = type_system_union->lookup(key);
602         if (type < 0)
603                 return -EOPNOTSUPP;
604
605         assert(type < type_system_union->num);
606
607         *ret = &type_system_union->type_systems[type];
608
609         return 0;
610 }
611
612 int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
613         const NLTypeSystem *type_system;
614
615         assert(type_system_union);
616         assert(type_system_union->type_systems);
617         assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
618         assert(ret);
619
620         if (protocol >= type_system_union->num)
621                 return -EOPNOTSUPP;
622
623         type_system = &type_system_union->type_systems[protocol];
624         if (!type_system->types)
625                 return -EOPNOTSUPP;
626
627         *ret = type_system;
628
629         return 0;
630 }