]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | ||
3 | #include <linux/fib_rules.h> | |
4 | #include <linux/if_addrlabel.h> | |
5 | #include <linux/if_bridge.h> | |
6 | #include <linux/nexthop.h> | |
7 | ||
8 | #include "sd-netlink.h" | |
9 | ||
10 | #include "in-addr-util.h" | |
11 | #include "netlink-internal.h" | |
12 | ||
13 | static bool rtnl_message_type_is_neigh(uint16_t type) { | |
14 | return IN_SET(type, RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH); | |
15 | } | |
16 | ||
17 | static bool rtnl_message_type_is_route(uint16_t type) { | |
18 | return IN_SET(type, RTM_NEWROUTE, RTM_GETROUTE, RTM_DELROUTE); | |
19 | } | |
20 | ||
21 | static bool rtnl_message_type_is_nexthop(uint16_t type) { | |
22 | return IN_SET(type, RTM_NEWNEXTHOP, RTM_GETNEXTHOP, RTM_DELNEXTHOP); | |
23 | } | |
24 | ||
25 | static bool rtnl_message_type_is_link(uint16_t type) { | |
26 | return IN_SET(type, | |
27 | RTM_NEWLINK, RTM_SETLINK, RTM_GETLINK, RTM_DELLINK, | |
28 | RTM_NEWLINKPROP, RTM_DELLINKPROP, RTM_GETLINKPROP); | |
29 | } | |
30 | ||
31 | static bool rtnl_message_type_is_addr(uint16_t type) { | |
32 | return IN_SET(type, RTM_NEWADDR, RTM_GETADDR, RTM_DELADDR); | |
33 | } | |
34 | ||
35 | static bool rtnl_message_type_is_addrlabel(uint16_t type) { | |
36 | return IN_SET(type, RTM_NEWADDRLABEL, RTM_DELADDRLABEL, RTM_GETADDRLABEL); | |
37 | } | |
38 | ||
39 | static bool rtnl_message_type_is_routing_policy_rule(uint16_t type) { | |
40 | return IN_SET(type, RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE); | |
41 | } | |
42 | ||
43 | static bool rtnl_message_type_is_traffic_control(uint16_t type) { | |
44 | return IN_SET(type, | |
45 | RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC, | |
46 | RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS); | |
47 | } | |
48 | ||
49 | static bool rtnl_message_type_is_mdb(uint16_t type) { | |
50 | return IN_SET(type, RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB); | |
51 | } | |
52 | ||
53 | static bool rtnl_message_type_is_nsid(uint16_t type) { | |
54 | return IN_SET(type, RTM_NEWNSID, RTM_DELNSID, RTM_GETNSID); | |
55 | } | |
56 | ||
57 | #define DEFINE_RTNL_MESSAGE_SETTER(class, header_type, element, name, value_type) \ | |
58 | int sd_rtnl_message_##class##_set_##name(sd_netlink_message *m, value_type value) { \ | |
59 | assert_return(m, -EINVAL); \ | |
60 | assert_return(m->hdr, -EINVAL); \ | |
61 | assert_return(rtnl_message_type_is_##class(m->hdr->nlmsg_type), -EINVAL); \ | |
62 | \ | |
63 | header_type *hdr = NLMSG_DATA(m->hdr); \ | |
64 | hdr->element = value; \ | |
65 | return 0; \ | |
66 | } | |
67 | ||
68 | #define DEFINE_RTNL_MESSAGE_PREFIXLEN_SETTER(class, header_type, family_element, element, name, value_type) \ | |
69 | int sd_rtnl_message_##class##_set_##name(sd_netlink_message *m, value_type value) { \ | |
70 | assert_return(m, -EINVAL); \ | |
71 | assert_return(m->hdr, -EINVAL); \ | |
72 | assert_return(rtnl_message_type_is_##class(m->hdr->nlmsg_type), -EINVAL); \ | |
73 | \ | |
74 | header_type *hdr = NLMSG_DATA(m->hdr); \ | |
75 | \ | |
76 | if (value > FAMILY_ADDRESS_SIZE_SAFE(hdr->family_element) * 8) \ | |
77 | return -ERANGE; \ | |
78 | \ | |
79 | hdr->element = value; \ | |
80 | return 0; \ | |
81 | } | |
82 | ||
83 | #define DEFINE_RTNL_MESSAGE_ADDR_SETTER(element, name, value_type) \ | |
84 | DEFINE_RTNL_MESSAGE_SETTER(addr, struct ifaddrmsg, element, name, value_type) | |
85 | #define DEFINE_RTNL_MESSAGE_LINK_SETTER(element, name, value_type) \ | |
86 | DEFINE_RTNL_MESSAGE_SETTER(link, struct ifinfomsg, element, name, value_type) | |
87 | #define DEFINE_RTNL_MESSAGE_ROUTE_SETTER(element, name, value_type) \ | |
88 | DEFINE_RTNL_MESSAGE_SETTER(route, struct rtmsg, element, name, value_type) | |
89 | #define DEFINE_RTNL_MESSAGE_NEXTHOP_SETTER(element, name, value_type) \ | |
90 | DEFINE_RTNL_MESSAGE_SETTER(nexthop, struct nhmsg, element, name, value_type) | |
91 | #define DEFINE_RTNL_MESSAGE_NEIGH_SETTER(element, name, value_type) \ | |
92 | DEFINE_RTNL_MESSAGE_SETTER(neigh, struct ndmsg, element, name, value_type) | |
93 | #define DEFINE_RTNL_MESSAGE_ADDRLABEL_SETTER(element, name, value_type) \ | |
94 | DEFINE_RTNL_MESSAGE_SETTER(addrlabel, struct ifaddrlblmsg, element, name, value_type) | |
95 | #define DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_SETTER(element, name, value_type) \ | |
96 | DEFINE_RTNL_MESSAGE_SETTER(routing_policy_rule, struct fib_rule_hdr, element, name, value_type) | |
97 | #define DEFINE_RTNL_MESSAGE_TRAFFIC_CONTROL_SETTER(element, name, value_type) \ | |
98 | DEFINE_RTNL_MESSAGE_SETTER(traffic_control, struct tcmsg, element, name, value_type) | |
99 | ||
100 | #define DEFINE_RTNL_MESSAGE_GETTER(class, header_type, element, name, value_type) \ | |
101 | int sd_rtnl_message_##class##_get_##name(sd_netlink_message *m, value_type *ret) { \ | |
102 | assert_return(m, -EINVAL); \ | |
103 | assert_return(m->hdr, -EINVAL); \ | |
104 | assert_return(rtnl_message_type_is_##class(m->hdr->nlmsg_type), -EINVAL); \ | |
105 | assert_return(ret, -EINVAL); \ | |
106 | \ | |
107 | header_type *hdr = NLMSG_DATA(m->hdr); \ | |
108 | *ret = hdr->element; \ | |
109 | return 0; \ | |
110 | } | |
111 | ||
112 | #define DEFINE_RTNL_MESSAGE_ADDR_GETTER(element, name, value_type) \ | |
113 | DEFINE_RTNL_MESSAGE_GETTER(addr, struct ifaddrmsg, element, name, value_type) | |
114 | #define DEFINE_RTNL_MESSAGE_LINK_GETTER(element, name, value_type) \ | |
115 | DEFINE_RTNL_MESSAGE_GETTER(link, struct ifinfomsg, element, name, value_type) | |
116 | #define DEFINE_RTNL_MESSAGE_ROUTE_GETTER(element, name, value_type) \ | |
117 | DEFINE_RTNL_MESSAGE_GETTER(route, struct rtmsg, element, name, value_type) | |
118 | #define DEFINE_RTNL_MESSAGE_NEXTHOP_GETTER(element, name, value_type) \ | |
119 | DEFINE_RTNL_MESSAGE_GETTER(nexthop, struct nhmsg, element, name, value_type) | |
120 | #define DEFINE_RTNL_MESSAGE_NEIGH_GETTER(element, name, value_type) \ | |
121 | DEFINE_RTNL_MESSAGE_GETTER(neigh, struct ndmsg, element, name, value_type) | |
122 | #define DEFINE_RTNL_MESSAGE_ADDRLABEL_GETTER(element, name, value_type) \ | |
123 | DEFINE_RTNL_MESSAGE_GETTER(addrlabel, struct ifaddrlblmsg, element, name, value_type) | |
124 | #define DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(element, name, value_type) \ | |
125 | DEFINE_RTNL_MESSAGE_GETTER(routing_policy_rule, struct fib_rule_hdr, element, name, value_type) | |
126 | #define DEFINE_RTNL_MESSAGE_TRAFFIC_CONTROL_GETTER(element, name, value_type) \ | |
127 | DEFINE_RTNL_MESSAGE_GETTER(traffic_control, struct tcmsg, element, name, value_type) | |
128 | ||
129 | DEFINE_RTNL_MESSAGE_ADDR_GETTER(ifa_index, ifindex, int); | |
130 | DEFINE_RTNL_MESSAGE_ADDR_GETTER(ifa_family, family, int); | |
131 | DEFINE_RTNL_MESSAGE_PREFIXLEN_SETTER(addr, struct ifaddrmsg, ifa_family, ifa_prefixlen, prefixlen, uint8_t); | |
132 | DEFINE_RTNL_MESSAGE_ADDR_GETTER(ifa_prefixlen, prefixlen, uint8_t); | |
133 | DEFINE_RTNL_MESSAGE_ADDR_SETTER(ifa_scope, scope, uint8_t); | |
134 | DEFINE_RTNL_MESSAGE_ADDR_GETTER(ifa_scope, scope, uint8_t); | |
135 | ||
136 | DEFINE_RTNL_MESSAGE_LINK_GETTER(ifi_index, ifindex, int); | |
137 | DEFINE_RTNL_MESSAGE_LINK_SETTER(ifi_family, family, int); | |
138 | DEFINE_RTNL_MESSAGE_LINK_GETTER(ifi_family, family, int); | |
139 | DEFINE_RTNL_MESSAGE_LINK_SETTER(ifi_type, type, uint16_t); | |
140 | DEFINE_RTNL_MESSAGE_LINK_GETTER(ifi_type, type, uint16_t); | |
141 | DEFINE_RTNL_MESSAGE_LINK_GETTER(ifi_flags, flags, uint32_t); | |
142 | ||
143 | int sd_rtnl_message_link_set_flags(sd_netlink_message *m, uint32_t flags, uint32_t change) { | |
144 | struct ifinfomsg *ifi; | |
145 | ||
146 | assert_return(m, -EINVAL); | |
147 | assert_return(m->hdr, -EINVAL); | |
148 | assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); | |
149 | assert_return(change != 0, -EINVAL); | |
150 | ||
151 | ifi = NLMSG_DATA(m->hdr); | |
152 | ||
153 | ifi->ifi_flags = flags; | |
154 | ifi->ifi_change = change; | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_family, family, int); | |
160 | DEFINE_RTNL_MESSAGE_PREFIXLEN_SETTER(route, struct rtmsg, rtm_family, rtm_dst_len, dst_prefixlen, uint8_t); | |
161 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_dst_len, dst_prefixlen, uint8_t); | |
162 | DEFINE_RTNL_MESSAGE_PREFIXLEN_SETTER(route, struct rtmsg, rtm_family, rtm_src_len, src_prefixlen, uint8_t); | |
163 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_src_len, src_prefixlen, uint8_t); | |
164 | DEFINE_RTNL_MESSAGE_ROUTE_SETTER(rtm_tos, tos, uint8_t); | |
165 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_tos, tos, uint8_t); | |
166 | DEFINE_RTNL_MESSAGE_ROUTE_SETTER(rtm_table, table, uint8_t); | |
167 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_table, table, uint8_t); | |
168 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_protocol, protocol, uint8_t); | |
169 | DEFINE_RTNL_MESSAGE_ROUTE_SETTER(rtm_scope, scope, uint8_t); | |
170 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_scope, scope, uint8_t); | |
171 | DEFINE_RTNL_MESSAGE_ROUTE_SETTER(rtm_type, type, uint8_t); | |
172 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_type, type, uint8_t); | |
173 | DEFINE_RTNL_MESSAGE_ROUTE_SETTER(rtm_flags, flags, uint32_t); | |
174 | DEFINE_RTNL_MESSAGE_ROUTE_GETTER(rtm_flags, flags, uint32_t); | |
175 | ||
176 | DEFINE_RTNL_MESSAGE_NEXTHOP_GETTER(nh_family, family, int); | |
177 | DEFINE_RTNL_MESSAGE_NEXTHOP_SETTER(nh_flags, flags, uint32_t); | |
178 | DEFINE_RTNL_MESSAGE_NEXTHOP_GETTER(nh_flags, flags, uint32_t); | |
179 | DEFINE_RTNL_MESSAGE_NEXTHOP_GETTER(nh_protocol, protocol, uint8_t); | |
180 | ||
181 | DEFINE_RTNL_MESSAGE_NEIGH_GETTER(ndm_ifindex, ifindex, int); | |
182 | DEFINE_RTNL_MESSAGE_NEIGH_GETTER(ndm_family, family, int); | |
183 | DEFINE_RTNL_MESSAGE_NEIGH_SETTER(ndm_state, state, uint16_t); | |
184 | DEFINE_RTNL_MESSAGE_NEIGH_GETTER(ndm_state, state, uint16_t); | |
185 | DEFINE_RTNL_MESSAGE_NEIGH_SETTER(ndm_flags, flags, uint8_t); | |
186 | DEFINE_RTNL_MESSAGE_NEIGH_GETTER(ndm_flags, flags, uint8_t); | |
187 | ||
188 | DEFINE_RTNL_MESSAGE_ADDRLABEL_GETTER(ifal_prefixlen, prefixlen, uint8_t); | |
189 | ||
190 | int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, uint8_t prefixlen) { | |
191 | struct ifaddrlblmsg *addrlabel; | |
192 | ||
193 | assert_return(m, -EINVAL); | |
194 | assert_return(m->hdr, -EINVAL); | |
195 | assert_return(rtnl_message_type_is_addrlabel(m->hdr->nlmsg_type), -EINVAL); | |
196 | ||
197 | addrlabel = NLMSG_DATA(m->hdr); | |
198 | ||
199 | if (prefixlen > 128) | |
200 | return -ERANGE; | |
201 | ||
202 | addrlabel->ifal_prefixlen = prefixlen; | |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
207 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(family, family, int); | |
208 | DEFINE_RTNL_MESSAGE_PREFIXLEN_SETTER(routing_policy_rule, struct fib_rule_hdr, family, dst_len, dst_prefixlen, uint8_t); | |
209 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(dst_len, dst_prefixlen, uint8_t); | |
210 | DEFINE_RTNL_MESSAGE_PREFIXLEN_SETTER(routing_policy_rule, struct fib_rule_hdr, family, src_len, src_prefixlen, uint8_t); | |
211 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(src_len, src_prefixlen, uint8_t); | |
212 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_SETTER(tos, tos, uint8_t); | |
213 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(tos, tos, uint8_t); | |
214 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_SETTER(table, table, uint8_t); | |
215 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(table, table, uint8_t); | |
216 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_SETTER(action, action, uint8_t); | |
217 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(action, action, uint8_t); | |
218 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_SETTER(flags, flags, uint32_t); | |
219 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(flags, flags, uint32_t); | |
220 | ||
221 | DEFINE_RTNL_MESSAGE_TRAFFIC_CONTROL_GETTER(tcm_ifindex, ifindex, int); | |
222 | DEFINE_RTNL_MESSAGE_TRAFFIC_CONTROL_GETTER(tcm_handle, handle, uint32_t); | |
223 | DEFINE_RTNL_MESSAGE_TRAFFIC_CONTROL_GETTER(tcm_parent, parent, uint32_t); | |
224 | ||
225 | int sd_rtnl_message_new_route( | |
226 | sd_netlink *rtnl, | |
227 | sd_netlink_message **ret, | |
228 | uint16_t nlmsg_type, | |
229 | int family, | |
230 | uint8_t protocol) { | |
231 | ||
232 | struct rtmsg *rtm; | |
233 | int r; | |
234 | ||
235 | assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL); | |
236 | assert_return((nlmsg_type == RTM_GETROUTE && family == AF_UNSPEC) || | |
237 | IN_SET(family, AF_INET, AF_INET6), -EINVAL); | |
238 | assert_return(ret, -EINVAL); | |
239 | ||
240 | r = message_new(rtnl, | |
241 | ret, | |
242 | nlmsg_type, | |
243 | NLM_F_REQUEST|NLM_F_ACK|(nlmsg_type == RTM_NEWROUTE ? NLM_F_CREATE | NLM_F_APPEND : 0)); | |
244 | if (r < 0) | |
245 | return r; | |
246 | ||
247 | rtm = NLMSG_DATA((*ret)->hdr); | |
248 | ||
249 | rtm->rtm_family = family; | |
250 | rtm->rtm_protocol = protocol; | |
251 | ||
252 | return 0; | |
253 | } | |
254 | ||
255 | int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, | |
256 | uint16_t nlmsg_type, int family, | |
257 | uint8_t protocol) { | |
258 | struct nhmsg *nhm; | |
259 | int r; | |
260 | ||
261 | assert_return(rtnl_message_type_is_nexthop(nlmsg_type), -EINVAL); | |
262 | switch (nlmsg_type) { | |
263 | case RTM_DELNEXTHOP: | |
264 | assert_return(family == AF_UNSPEC, -EINVAL); | |
265 | _fallthrough_; | |
266 | case RTM_GETNEXTHOP: | |
267 | assert_return(protocol == RTPROT_UNSPEC, -EINVAL); | |
268 | break; | |
269 | case RTM_NEWNEXTHOP: | |
270 | assert_return(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6), -EINVAL); | |
271 | break; | |
272 | default: | |
273 | assert_not_reached(); | |
274 | } | |
275 | assert_return(ret, -EINVAL); | |
276 | ||
277 | r = message_new(rtnl, | |
278 | ret, | |
279 | nlmsg_type, | |
280 | NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWNEXTHOP ? NLM_F_CREATE | NLM_F_REPLACE : 0)); | |
281 | if (r < 0) | |
282 | return r; | |
283 | ||
284 | nhm = NLMSG_DATA((*ret)->hdr); | |
285 | ||
286 | nhm->nh_family = family; | |
287 | nhm->nh_scope = RT_SCOPE_UNIVERSE; | |
288 | nhm->nh_protocol = protocol; | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
293 | int sd_rtnl_message_new_neigh( | |
294 | sd_netlink *rtnl, | |
295 | sd_netlink_message **ret, | |
296 | uint16_t nlmsg_type, | |
297 | int ifindex, | |
298 | int family) { | |
299 | ||
300 | struct ndmsg *ndm; | |
301 | int r; | |
302 | ||
303 | assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL); | |
304 | assert_return(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE), -EINVAL); | |
305 | assert_return(ret, -EINVAL); | |
306 | ||
307 | uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; | |
308 | if (nlmsg_type == RTM_NEWNEIGH) { | |
309 | if (family == AF_BRIDGE) | |
310 | flags |= NLM_F_CREATE | NLM_F_APPEND; | |
311 | else | |
312 | flags |= NLM_F_CREATE | NLM_F_REPLACE; | |
313 | } | |
314 | ||
315 | r = message_new(rtnl, ret, nlmsg_type, flags); | |
316 | if (r < 0) | |
317 | return r; | |
318 | ||
319 | ndm = NLMSG_DATA((*ret)->hdr); | |
320 | ||
321 | ndm->ndm_family = family; | |
322 | ndm->ndm_ifindex = ifindex; | |
323 | ||
324 | return 0; | |
325 | } | |
326 | ||
327 | int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifindex) { | |
328 | struct ifinfomsg *ifi; | |
329 | int r; | |
330 | ||
331 | assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); | |
332 | assert_return(ret, -EINVAL); | |
333 | ||
334 | uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; | |
335 | if (nlmsg_type == RTM_NEWLINK && ifindex == 0) | |
336 | flags |= NLM_F_CREATE | NLM_F_EXCL; | |
337 | else if (nlmsg_type == RTM_NEWLINKPROP) | |
338 | flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND; | |
339 | ||
340 | r = message_new(rtnl, ret, nlmsg_type, flags); | |
341 | if (r < 0) | |
342 | return r; | |
343 | ||
344 | ifi = NLMSG_DATA((*ret)->hdr); | |
345 | ||
346 | ifi->ifi_family = AF_UNSPEC; | |
347 | ifi->ifi_index = ifindex; | |
348 | ||
349 | return 0; | |
350 | } | |
351 | ||
352 | int sd_rtnl_message_new_addr( | |
353 | sd_netlink *rtnl, | |
354 | sd_netlink_message **ret, | |
355 | uint16_t nlmsg_type, | |
356 | int ifindex, | |
357 | int family) { | |
358 | ||
359 | struct ifaddrmsg *ifa; | |
360 | int r; | |
361 | ||
362 | assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL); | |
363 | assert_return((nlmsg_type == RTM_GETADDR && ifindex == 0) || | |
364 | ifindex > 0, -EINVAL); | |
365 | assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) || | |
366 | IN_SET(family, AF_INET, AF_INET6), -EINVAL); | |
367 | assert_return(ret, -EINVAL); | |
368 | ||
369 | r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK); | |
370 | if (r < 0) | |
371 | return r; | |
372 | ||
373 | ifa = NLMSG_DATA((*ret)->hdr); | |
374 | ||
375 | ifa->ifa_index = ifindex; | |
376 | ifa->ifa_family = family; | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
381 | int sd_rtnl_message_new_addr_update( | |
382 | sd_netlink *rtnl, | |
383 | sd_netlink_message **ret, | |
384 | int ifindex, | |
385 | int family) { | |
386 | int r; | |
387 | ||
388 | r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, ifindex, family); | |
389 | if (r < 0) | |
390 | return r; | |
391 | ||
392 | (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE; | |
393 | ||
394 | return 0; | |
395 | } | |
396 | ||
397 | int sd_rtnl_message_get_family(sd_netlink_message *m, int *ret) { | |
398 | assert_return(m, -EINVAL); | |
399 | assert_return(ret, -EINVAL); | |
400 | ||
401 | assert(m->hdr); | |
402 | ||
403 | if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) | |
404 | return sd_rtnl_message_link_get_family(m, ret); | |
405 | ||
406 | if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) | |
407 | return sd_rtnl_message_route_get_family(m, ret); | |
408 | ||
409 | if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) | |
410 | return sd_rtnl_message_neigh_get_family(m, ret); | |
411 | ||
412 | if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) | |
413 | return sd_rtnl_message_addr_get_family(m, ret); | |
414 | ||
415 | if (rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type)) | |
416 | return sd_rtnl_message_routing_policy_rule_get_family(m, ret); | |
417 | ||
418 | if (rtnl_message_type_is_nexthop(m->hdr->nlmsg_type)) | |
419 | return sd_rtnl_message_nexthop_get_family(m, ret); | |
420 | ||
421 | return -EOPNOTSUPP; | |
422 | } | |
423 | ||
424 | int sd_rtnl_message_new_addrlabel( | |
425 | sd_netlink *rtnl, | |
426 | sd_netlink_message **ret, | |
427 | uint16_t nlmsg_type, | |
428 | int ifindex, | |
429 | int family) { | |
430 | ||
431 | struct ifaddrlblmsg *addrlabel; | |
432 | int r; | |
433 | ||
434 | assert_return(rtnl_message_type_is_addrlabel(nlmsg_type), -EINVAL); | |
435 | assert_return(ret, -EINVAL); | |
436 | ||
437 | r = message_new(rtnl, | |
438 | ret, | |
439 | nlmsg_type, | |
440 | NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWADDRLABEL ? NLM_F_CREATE | NLM_F_REPLACE : 0)); | |
441 | if (r < 0) | |
442 | return r; | |
443 | ||
444 | addrlabel = NLMSG_DATA((*ret)->hdr); | |
445 | ||
446 | addrlabel->ifal_family = family; | |
447 | addrlabel->ifal_index = ifindex; | |
448 | ||
449 | return 0; | |
450 | } | |
451 | ||
452 | int sd_rtnl_message_new_routing_policy_rule( | |
453 | sd_netlink *rtnl, | |
454 | sd_netlink_message **ret, | |
455 | uint16_t nlmsg_type, | |
456 | int family) { | |
457 | ||
458 | struct fib_rule_hdr *frh; | |
459 | int r; | |
460 | ||
461 | assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL); | |
462 | assert_return(ret, -EINVAL); | |
463 | ||
464 | r = message_new(rtnl, | |
465 | ret, | |
466 | nlmsg_type, | |
467 | NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWRULE ? NLM_F_CREATE | NLM_F_EXCL : 0)); | |
468 | if (r < 0) | |
469 | return r; | |
470 | ||
471 | frh = NLMSG_DATA((*ret)->hdr); | |
472 | frh->family = family; | |
473 | ||
474 | return 0; | |
475 | } | |
476 | ||
477 | int sd_rtnl_message_new_traffic_control( | |
478 | sd_netlink *rtnl, | |
479 | sd_netlink_message **ret, | |
480 | uint16_t nlmsg_type, | |
481 | int ifindex, | |
482 | uint32_t handle, | |
483 | uint32_t parent) { | |
484 | ||
485 | struct tcmsg *tcm; | |
486 | int r; | |
487 | ||
488 | assert_return(rtnl_message_type_is_traffic_control(nlmsg_type), -EINVAL); | |
489 | assert_return(ret, -EINVAL); | |
490 | ||
491 | r = message_new(rtnl, | |
492 | ret, | |
493 | nlmsg_type, | |
494 | NLM_F_REQUEST | NLM_F_ACK | (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS) ? NLM_F_CREATE | NLM_F_REPLACE : 0)); | |
495 | if (r < 0) | |
496 | return r; | |
497 | ||
498 | tcm = NLMSG_DATA((*ret)->hdr); | |
499 | tcm->tcm_ifindex = ifindex; | |
500 | tcm->tcm_handle = handle; | |
501 | tcm->tcm_parent = parent; | |
502 | ||
503 | return 0; | |
504 | } | |
505 | ||
506 | int sd_rtnl_message_new_mdb( | |
507 | sd_netlink *rtnl, | |
508 | sd_netlink_message **ret, | |
509 | uint16_t nlmsg_type, | |
510 | int ifindex) { | |
511 | ||
512 | struct br_port_msg *bpm; | |
513 | int r; | |
514 | ||
515 | assert_return(rtnl_message_type_is_mdb(nlmsg_type), -EINVAL); | |
516 | assert_return(ret, -EINVAL); | |
517 | ||
518 | r = message_new(rtnl, | |
519 | ret, | |
520 | nlmsg_type, | |
521 | NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWMDB ? NLM_F_CREATE | NLM_F_REPLACE : 0)); | |
522 | if (r < 0) | |
523 | return r; | |
524 | ||
525 | bpm = NLMSG_DATA((*ret)->hdr); | |
526 | bpm->family = AF_BRIDGE; | |
527 | bpm->ifindex = ifindex; | |
528 | ||
529 | return 0; | |
530 | } | |
531 | ||
532 | int sd_rtnl_message_new_nsid( | |
533 | sd_netlink *rtnl, | |
534 | sd_netlink_message **ret, | |
535 | uint16_t nlmsg_type) { | |
536 | ||
537 | struct rtgenmsg *rt; | |
538 | int r; | |
539 | ||
540 | assert_return(rtnl_message_type_is_nsid(nlmsg_type), -EINVAL); | |
541 | assert_return(ret, -EINVAL); | |
542 | ||
543 | r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK); | |
544 | if (r < 0) | |
545 | return r; | |
546 | ||
547 | rt = NLMSG_DATA((*ret)->hdr); | |
548 | rt->rtgen_family = AF_UNSPEC; | |
549 | ||
550 | return 0; | |
551 | } |