1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
24 #include <sys/socket.h>
25 #include <linux/netlink.h>
26 #include <linux/rtnetlink.h>
27 #include <linux/in6.h>
28 #include <linux/veth.h>
29 #include <linux/if_bridge.h>
30 #include <linux/if_addr.h>
34 #include <linux/if_tunnel.h>
39 #include "rtnl-types.h"
41 static const NLTypeSystem rtnl_link_type_system;
43 static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
44 [VETH_INFO_PEER] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
48 static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
49 [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
50 [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
53 static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
54 [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 },
55 [IFLA_BRIDGE_MODE] = { .type = NLA_U16 },
57 [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
58 .len = sizeof(struct bridge_vlan_info), },
62 static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
63 [IFLA_VLAN_ID] = { .type = NLA_U16 },
65 [IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
66 [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
67 [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
69 [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 },
72 static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
73 [IFLA_BOND_MODE] = { .type = NLA_U8 },
74 [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 },
75 #ifdef IFLA_BOND_MIIMON
76 [IFLA_BOND_MIIMON] = { .type = NLA_U32 },
77 [IFLA_BOND_UPDELAY] = { .type = NLA_U32 },
78 [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 },
79 [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 },
80 [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 },
82 [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED },
84 [IFLA_BOND_ARP_VALIDATE] = { .type = NLA_U32 },
85 [IFLA_BOND_ARP_ALL_TARGETS] = { .type = NLA_U32 },
86 [IFLA_BOND_PRIMARY] = { .type = NLA_U32 },
87 [IFLA_BOND_PRIMARY_RESELECT] = { .type = NLA_U8 },
88 [IFLA_BOND_FAIL_OVER_MAC] = { .type = NLA_U8 },
89 [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NLA_U8 },
90 [IFLA_BOND_RESEND_IGMP] = { .type = NLA_U32 },
91 [IFLA_BOND_NUM_PEER_NOTIF] = { .type = NLA_U8 },
92 [IFLA_BOND_ALL_SLAVES_ACTIVE] = { .type = NLA_U8 },
93 [IFLA_BOND_MIN_LINKS] = { .type = NLA_U32 },
94 [IFLA_BOND_LP_INTERVAL] = { .type = NLA_U32 },
95 [IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NLA_U32 },
96 [IFLA_BOND_AD_LACP_RATE] = { .type = NLA_U8 },
97 [IFLA_BOND_AD_SELECT] = { .type = NLA_U8 },
99 [IFLA_BOND_AD_INFO] = { .type = NLA_NESTED },
104 static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
105 [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
106 [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
107 [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
108 [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
109 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
110 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
111 [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 },
112 [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
113 [IFLA_IPTUN_6RD_PREFIX] = { .type = NLA_IN_ADDR },
114 [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 },
115 [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 },
116 [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
119 typedef enum NLUnionLinkInfoData {
120 NL_UNION_LINK_INFO_DATA_BOND,
121 NL_UNION_LINK_INFO_DATA_BRIDGE,
122 NL_UNION_LINK_INFO_DATA_VLAN,
123 NL_UNION_LINK_INFO_DATA_VETH,
124 NL_UNION_LINK_INFO_DATA_MACVLAN,
125 NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL,
126 NL_UNION_LINK_INFO_DATA_SIT_TUNNEL,
127 _NL_UNION_LINK_INFO_DATA_MAX,
128 _NL_UNION_LINK_INFO_DATA_INVALID = -1
129 } NLUnionLinkInfoData;
131 const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_;
132 NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
134 /* these strings must match the .kind entries in the kernel */
135 static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
136 [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
137 [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
138 [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
139 [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
140 [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
141 [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
142 [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
145 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
147 static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
148 [NL_UNION_LINK_INFO_DATA_BOND] = { .max = ELEMENTSOF(rtnl_link_info_data_bond_types) - 1,
149 .types = rtnl_link_info_data_bond_types },
150 [NL_UNION_LINK_INFO_DATA_BRIDGE] = { .max = ELEMENTSOF(rtnl_link_info_data_bridge_types) - 1,
151 .types = rtnl_link_info_data_bridge_types },
152 [NL_UNION_LINK_INFO_DATA_VLAN] = { .max = ELEMENTSOF(rtnl_link_info_data_vlan_types) - 1,
153 .types = rtnl_link_info_data_vlan_types },
154 [NL_UNION_LINK_INFO_DATA_VETH] = { .max = ELEMENTSOF(rtnl_link_info_data_veth_types) - 1,
155 .types = rtnl_link_info_data_veth_types },
156 [NL_UNION_LINK_INFO_DATA_MACVLAN] = { .max = ELEMENTSOF(rtnl_link_info_data_macvlan_types) - 1,
157 .types = rtnl_link_info_data_macvlan_types },
158 [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
159 .types = rtnl_link_info_data_iptun_types },
160 [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
161 .types = rtnl_link_info_data_iptun_types },
164 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
165 .num = _NL_UNION_LINK_INFO_DATA_MAX,
166 .lookup = nl_union_link_info_data_from_string,
167 .type_systems = rtnl_link_info_data_type_systems,
168 .match = IFLA_INFO_KIND,
171 static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
172 [IFLA_INFO_KIND] = { .type = NLA_STRING },
173 [IFLA_INFO_DATA] = { .type = NLA_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
176 [IFLA_INFO_SLAVE_KIND] = { .type = NLA_STRING },
177 [IFLA_INFO_SLAVE_DATA] = { .type = NLA_NESTED },
181 static const NLTypeSystem rtnl_link_info_type_system = {
182 .max = ELEMENTSOF(rtnl_link_info_types) - 1,
183 .types = rtnl_link_info_types,
186 static const NLType rtnl_link_types[IFLA_MAX + 1] = {
187 [IFLA_ADDRESS] = { .type = NLA_ETHER_ADDR, },
188 [IFLA_BROADCAST] = { .type = NLA_ETHER_ADDR, },
189 [IFLA_IFNAME] = { .type = NLA_STRING, .size = IFNAMSIZ - 1, },
190 [IFLA_MTU] = { .type = NLA_U32 },
191 [IFLA_LINK] = { .type = NLA_U32 },
198 [IFLA_MASTER] = { .type = NLA_U32 },
203 [IFLA_TXQLEN] = { .type = NLA_U32 },
205 [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
207 [IFLA_WEIGHT] = { .type = NLA_U32 },
208 [IFLA_OPERSTATE] = { .type = NLA_U8 },
209 [IFLA_LINKMODE] = { .type = NLA_U8 },
210 [IFLA_LINKINFO] = { .type = NLA_NESTED, .type_system = &rtnl_link_info_type_system },
211 [IFLA_NET_NS_PID] = { .type = NLA_U32 },
212 [IFLA_IFALIAS] = { .type = NLA_STRING, .size = IFALIASZ - 1 },
215 [IFLA_VFINFO_LIST] = {. type = NLA_NESTED, },
217 [IFLA_VF_PORTS] = { .type = NLA_NESTED },
218 [IFLA_PORT_SELF] = { .type = NLA_NESTED },
219 [IFLA_AF_SPEC] = { .type = NLA_NESTED },
224 [IFLA_GROUP] = { .type = NLA_U32 },
225 [IFLA_NET_NS_FD] = { .type = NLA_U32 },
226 [IFLA_EXT_MASK] = { .type = NLA_U32 },
227 [IFLA_PROMISCUITY] = { .type = NLA_U32 },
228 [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
229 [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
230 [IFLA_CARRIER] = { .type = NLA_U8 },
232 [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
236 static const NLTypeSystem rtnl_link_type_system = {
237 .max = ELEMENTSOF(rtnl_link_types) - 1,
238 .types = rtnl_link_types,
241 static const NLType rtnl_address_types[IFA_MAX + 1] = {
242 [IFA_ADDRESS] = { .type = NLA_IN_ADDR },
243 [IFA_LOCAL] = { .type = NLA_IN_ADDR },
244 [IFA_LABEL] = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
245 [IFA_BROADCAST] = { .type = NLA_IN_ADDR }, /* 6? */
246 [IFA_CACHEINFO] = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
252 [IFA_FLAGS] = { .type = NLA_U32 },
256 static const NLTypeSystem rtnl_address_type_system = {
257 .max = ELEMENTSOF(rtnl_address_types) - 1,
258 .types = rtnl_address_types,
261 static const NLType rtnl_route_types[RTA_MAX + 1] = {
262 [RTA_DST] = { .type = NLA_IN_ADDR }, /* 6? */
263 [RTA_SRC] = { .type = NLA_IN_ADDR }, /* 6? */
264 [RTA_IIF] = { .type = NLA_U32 },
265 [RTA_OIF] = { .type = NLA_U32 },
266 [RTA_GATEWAY] = { .type = NLA_IN_ADDR },
267 [RTA_PRIORITY] = { .type = NLA_U32 },
268 [RTA_PREFSRC] = { .type = NLA_IN_ADDR }, /* 6? */
270 [RTA_METRICS] = { .type = NLA_NESTED },
271 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
273 [RTA_FLOW] = { .type = NLA_U32 }, /* 6? */
282 static const NLTypeSystem rtnl_route_type_system = {
283 .max = ELEMENTSOF(rtnl_route_types) - 1,
284 .types = rtnl_route_types,
287 static const NLType rtnl_types[RTM_MAX + 1] = {
288 [NLMSG_ERROR] = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
289 [RTM_NEWLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
290 [RTM_DELLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
291 [RTM_GETLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
292 [RTM_SETLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
293 [RTM_NEWADDR] = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
294 [RTM_DELADDR] = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
295 [RTM_GETADDR] = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
296 [RTM_NEWROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
297 [RTM_DELROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
298 [RTM_GETROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
301 const NLTypeSystem rtnl_type_system = {
302 .max = ELEMENTSOF(rtnl_types) - 1,
306 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
307 const NLType *nl_type;
312 type_system = &rtnl_type_system;
314 assert(type_system->types);
316 if (type > type_system->max)
319 nl_type = &type_system->types[type];
321 if (nl_type->type == NLA_UNSPEC)
329 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
330 const NLType *nl_type;
335 r = type_system_get_type(type_system, &nl_type, type);
339 assert_return(nl_type->type == NLA_NESTED, -EINVAL);
341 assert(nl_type->type_system);
343 *ret = nl_type->type_system;
348 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
349 const NLType *nl_type;
354 r = type_system_get_type(type_system, &nl_type, type);
358 assert_return(nl_type->type == NLA_UNION, -EINVAL);
360 assert(nl_type->type_system_union);
362 *ret = nl_type->type_system_union;
367 int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
370 assert(type_system_union);
371 assert(type_system_union->lookup);
372 assert(type_system_union->type_systems);
376 type = type_system_union->lookup(key);
380 assert(type < type_system_union->num);
382 *ret = &type_system_union->type_systems[type];