]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
89489ef7 | 2 | |
b43dfb6e | 3 | #include <linux/fib_rules.h> |
30746d60 | 4 | #include <linux/if_addrlabel.h> |
1903c9bb | 5 | #include <linux/if_bridge.h> |
c16c7808 | 6 | #include <linux/nexthop.h> |
89489ef7 | 7 | |
07630cea LP |
8 | #include "sd-netlink.h" |
9 | ||
5cdf13c7 | 10 | #include "in-addr-util.h" |
89489ef7 | 11 | #include "netlink-internal.h" |
89489ef7 | 12 | |
13c026ca YW |
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 | ||
10786280 LP |
53 | static bool rtnl_message_type_is_nsid(uint16_t type) { |
54 | return IN_SET(type, RTM_NEWNSID, RTM_DELNSID, RTM_GETNSID); | |
55 | } | |
56 | ||
2bc1d783 YW |
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 | } | |
ad70f789 | 67 | |
2bc1d783 YW |
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 | } | |
ad70f789 | 82 | |
2bc1d783 YW |
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 | } | |
ad70f789 | 111 | |
2bc1d783 YW |
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); | |
2bc1d783 YW |
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); | |
ba8d48be | 138 | DEFINE_RTNL_MESSAGE_LINK_GETTER(ifi_family, family, int); |
2bc1d783 YW |
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); | |
ad70f789 | 142 | |
2bc1d783 YW |
143 | int sd_rtnl_message_link_set_flags(sd_netlink_message *m, uint32_t flags, uint32_t change) { |
144 | struct ifinfomsg *ifi; | |
ad70f789 TG |
145 | |
146 | assert_return(m, -EINVAL); | |
147 | assert_return(m->hdr, -EINVAL); | |
2bc1d783 YW |
148 | assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); |
149 | assert_return(change != 0, -EINVAL); | |
ad70f789 | 150 | |
2bc1d783 | 151 | ifi = NLMSG_DATA(m->hdr); |
ad70f789 | 152 | |
2bc1d783 YW |
153 | ifi->ifi_flags = flags; |
154 | ifi->ifi_change = change; | |
ad70f789 TG |
155 | |
156 | return 0; | |
157 | } | |
158 | ||
2bc1d783 YW |
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); | |
ad70f789 | 175 | |
2bc1d783 YW |
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); | |
ad70f789 | 180 | |
2bc1d783 YW |
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); | |
ad70f789 | 187 | |
2bc1d783 | 188 | DEFINE_RTNL_MESSAGE_ADDRLABEL_GETTER(ifal_prefixlen, prefixlen, uint8_t); |
ad70f789 | 189 | |
2bc1d783 YW |
190 | int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, uint8_t prefixlen) { |
191 | struct ifaddrlblmsg *addrlabel; | |
ad70f789 TG |
192 | |
193 | assert_return(m, -EINVAL); | |
194 | assert_return(m->hdr, -EINVAL); | |
2bc1d783 | 195 | assert_return(rtnl_message_type_is_addrlabel(m->hdr->nlmsg_type), -EINVAL); |
89489ef7 | 196 | |
2bc1d783 | 197 | addrlabel = NLMSG_DATA(m->hdr); |
89489ef7 | 198 | |
2bc1d783 YW |
199 | if (prefixlen > 128) |
200 | return -ERANGE; | |
89489ef7 | 201 | |
2bc1d783 | 202 | addrlabel->ifal_prefixlen = prefixlen; |
89489ef7 TG |
203 | |
204 | return 0; | |
205 | } | |
206 | ||
ba8d48be | 207 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(family, family, int); |
9b8cb789 YW |
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); | |
2bc1d783 YW |
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); | |
9b8cb789 YW |
216 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_SETTER(action, action, uint8_t); |
217 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(action, action, uint8_t); | |
2bc1d783 YW |
218 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_SETTER(flags, flags, uint32_t); |
219 | DEFINE_RTNL_MESSAGE_ROUTING_POLICY_RULE_GETTER(flags, flags, uint32_t); | |
89489ef7 | 220 | |
2bc1d783 YW |
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); | |
89489ef7 | 224 | |
ae298c93 YW |
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 | ||
89489ef7 TG |
232 | struct rtmsg *rtm; |
233 | int r; | |
234 | ||
235 | assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL); | |
ae298c93 YW |
236 | assert_return((nlmsg_type == RTM_GETROUTE && family == AF_UNSPEC) || |
237 | IN_SET(family, AF_INET, AF_INET6), -EINVAL); | |
89489ef7 TG |
238 | assert_return(ret, -EINVAL); |
239 | ||
6e196011 LP |
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)); | |
89489ef7 TG |
244 | if (r < 0) |
245 | return r; | |
246 | ||
89489ef7 TG |
247 | rtm = NLMSG_DATA((*ret)->hdr); |
248 | ||
ae298c93 YW |
249 | rtm->rtm_family = family; |
250 | rtm->rtm_protocol = protocol; | |
89489ef7 TG |
251 | |
252 | return 0; | |
253 | } | |
254 | ||
dd35a61c | 255 | int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, |
ae298c93 YW |
256 | uint16_t nlmsg_type, int family, |
257 | uint8_t protocol) { | |
c16c7808 SS |
258 | struct nhmsg *nhm; |
259 | int r; | |
260 | ||
409856d3 | 261 | assert_return(rtnl_message_type_is_nexthop(nlmsg_type), -EINVAL); |
79893116 | 262 | switch (nlmsg_type) { |
735a3d73 | 263 | case RTM_DELNEXTHOP: |
ae298c93 | 264 | assert_return(family == AF_UNSPEC, -EINVAL); |
735a3d73 YW |
265 | _fallthrough_; |
266 | case RTM_GETNEXTHOP: | |
ae298c93 | 267 | assert_return(protocol == RTPROT_UNSPEC, -EINVAL); |
735a3d73 YW |
268 | break; |
269 | case RTM_NEWNEXTHOP: | |
ae298c93 | 270 | assert_return(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6), -EINVAL); |
735a3d73 YW |
271 | break; |
272 | default: | |
04499a70 | 273 | assert_not_reached(); |
735a3d73 | 274 | } |
c16c7808 SS |
275 | assert_return(ret, -EINVAL); |
276 | ||
6e196011 LP |
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)); | |
c16c7808 SS |
281 | if (r < 0) |
282 | return r; | |
283 | ||
c16c7808 SS |
284 | nhm = NLMSG_DATA((*ret)->hdr); |
285 | ||
ae298c93 | 286 | nhm->nh_family = family; |
c16c7808 | 287 | nhm->nh_scope = RT_SCOPE_UNIVERSE; |
ae298c93 | 288 | nhm->nh_protocol = protocol; |
c16c7808 SS |
289 | |
290 | return 0; | |
291 | } | |
292 | ||
dd35a61c | 293 | int sd_rtnl_message_new_neigh( |
84e10015 ZJS |
294 | sd_netlink *rtnl, |
295 | sd_netlink_message **ret, | |
296 | uint16_t nlmsg_type, | |
ae298c93 YW |
297 | int ifindex, |
298 | int family) { | |
84e10015 | 299 | |
89489ef7 TG |
300 | struct ndmsg *ndm; |
301 | int r; | |
302 | ||
303 | assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL); | |
ae298c93 | 304 | assert_return(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE), -EINVAL); |
89489ef7 TG |
305 | assert_return(ret, -EINVAL); |
306 | ||
6e196011 | 307 | uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; |
74c1ab84 | 308 | if (nlmsg_type == RTM_NEWNEIGH) { |
ae298c93 | 309 | if (family == AF_BRIDGE) |
6e196011 | 310 | flags |= NLM_F_CREATE | NLM_F_APPEND; |
2bc1d783 | 311 | else |
6e196011 | 312 | flags |= NLM_F_CREATE | NLM_F_REPLACE; |
2bc1d783 | 313 | } |
89489ef7 | 314 | |
6e196011 LP |
315 | r = message_new(rtnl, ret, nlmsg_type, flags); |
316 | if (r < 0) | |
317 | return r; | |
318 | ||
2bc1d783 | 319 | ndm = NLMSG_DATA((*ret)->hdr); |
89489ef7 | 320 | |
2bc1d783 YW |
321 | ndm->ndm_family = family; |
322 | ndm->ndm_ifindex = ifindex; | |
89489ef7 TG |
323 | |
324 | return 0; | |
325 | } | |
326 | ||
2bc1d783 YW |
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; | |
89489ef7 | 330 | |
2bc1d783 | 331 | assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); |
ae298c93 | 332 | assert_return(ret, -EINVAL); |
89489ef7 | 333 | |
6e196011 | 334 | uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; |
7e322c3d | 335 | if (nlmsg_type == RTM_NEWLINK && ifindex == 0) |
6e196011 | 336 | flags |= NLM_F_CREATE | NLM_F_EXCL; |
2bc1d783 | 337 | else if (nlmsg_type == RTM_NEWLINKPROP) |
6e196011 LP |
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; | |
89489ef7 | 343 | |
2bc1d783 | 344 | ifi = NLMSG_DATA((*ret)->hdr); |
89489ef7 | 345 | |
2bc1d783 YW |
346 | ifi->ifi_family = AF_UNSPEC; |
347 | ifi->ifi_index = ifindex; | |
89489ef7 TG |
348 | |
349 | return 0; | |
350 | } | |
351 | ||
dd35a61c | 352 | int sd_rtnl_message_new_addr( |
84e10015 ZJS |
353 | sd_netlink *rtnl, |
354 | sd_netlink_message **ret, | |
355 | uint16_t nlmsg_type, | |
ae298c93 | 356 | int ifindex, |
84e10015 ZJS |
357 | int family) { |
358 | ||
89489ef7 TG |
359 | struct ifaddrmsg *ifa; |
360 | int r; | |
361 | ||
362 | assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL); | |
ae298c93 YW |
363 | assert_return((nlmsg_type == RTM_GETADDR && ifindex == 0) || |
364 | ifindex > 0, -EINVAL); | |
89489ef7 | 365 | assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) || |
945c2931 | 366 | IN_SET(family, AF_INET, AF_INET6), -EINVAL); |
89489ef7 TG |
367 | assert_return(ret, -EINVAL); |
368 | ||
6e196011 | 369 | r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK); |
89489ef7 TG |
370 | if (r < 0) |
371 | return r; | |
372 | ||
89489ef7 TG |
373 | ifa = NLMSG_DATA((*ret)->hdr); |
374 | ||
ae298c93 | 375 | ifa->ifa_index = ifindex; |
89489ef7 | 376 | ifa->ifa_family = family; |
89489ef7 TG |
377 | |
378 | return 0; | |
379 | } | |
380 | ||
dd35a61c | 381 | int sd_rtnl_message_new_addr_update( |
84e10015 ZJS |
382 | sd_netlink *rtnl, |
383 | sd_netlink_message **ret, | |
ae298c93 | 384 | int ifindex, |
84e10015 | 385 | int family) { |
89489ef7 TG |
386 | int r; |
387 | ||
ae298c93 | 388 | r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, ifindex, family); |
89489ef7 TG |
389 | if (r < 0) |
390 | return r; | |
391 | ||
392 | (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE; | |
393 | ||
394 | return 0; | |
395 | } | |
396 | ||
ae298c93 | 397 | int sd_rtnl_message_get_family(sd_netlink_message *m, int *ret) { |
89489ef7 | 398 | assert_return(m, -EINVAL); |
ae298c93 | 399 | assert_return(ret, -EINVAL); |
89489ef7 TG |
400 | |
401 | assert(m->hdr); | |
402 | ||
ba8d48be YW |
403 | if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) |
404 | return sd_rtnl_message_link_get_family(m, ret); | |
89489ef7 | 405 | |
ba8d48be YW |
406 | if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) |
407 | return sd_rtnl_message_route_get_family(m, ret); | |
89489ef7 | 408 | |
ba8d48be YW |
409 | if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) |
410 | return sd_rtnl_message_neigh_get_family(m, ret); | |
89489ef7 | 411 | |
ba8d48be YW |
412 | if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) |
413 | return sd_rtnl_message_addr_get_family(m, ret); | |
89489ef7 | 414 | |
ba8d48be YW |
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); | |
89489ef7 | 417 | |
ba8d48be YW |
418 | if (rtnl_message_type_is_nexthop(m->hdr->nlmsg_type)) |
419 | return sd_rtnl_message_nexthop_get_family(m, ret); | |
89489ef7 TG |
420 | |
421 | return -EOPNOTSUPP; | |
422 | } | |
30746d60 | 423 | |
dd35a61c | 424 | int sd_rtnl_message_new_addrlabel( |
84e10015 ZJS |
425 | sd_netlink *rtnl, |
426 | sd_netlink_message **ret, | |
427 | uint16_t nlmsg_type, | |
428 | int ifindex, | |
ae298c93 | 429 | int family) { |
84e10015 | 430 | |
30746d60 SS |
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 | ||
6e196011 LP |
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)); | |
30746d60 SS |
441 | if (r < 0) |
442 | return r; | |
443 | ||
30746d60 SS |
444 | addrlabel = NLMSG_DATA((*ret)->hdr); |
445 | ||
ae298c93 | 446 | addrlabel->ifal_family = family; |
30746d60 SS |
447 | addrlabel->ifal_index = ifindex; |
448 | ||
449 | return 0; | |
450 | } | |
451 | ||
dd35a61c | 452 | int sd_rtnl_message_new_routing_policy_rule( |
84e10015 ZJS |
453 | sd_netlink *rtnl, |
454 | sd_netlink_message **ret, | |
455 | uint16_t nlmsg_type, | |
ae298c93 | 456 | int family) { |
84e10015 | 457 | |
b43dfb6e | 458 | struct fib_rule_hdr *frh; |
bce67bbe SS |
459 | int r; |
460 | ||
461 | assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL); | |
462 | assert_return(ret, -EINVAL); | |
463 | ||
6e196011 LP |
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)); | |
bce67bbe SS |
468 | if (r < 0) |
469 | return r; | |
470 | ||
b43dfb6e | 471 | frh = NLMSG_DATA((*ret)->hdr); |
ae298c93 | 472 | frh->family = family; |
bce67bbe SS |
473 | |
474 | return 0; | |
475 | } | |
476 | ||
dd35a61c | 477 | int sd_rtnl_message_new_traffic_control( |
f50b93fe YW |
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) { | |
0f5bd7fe | 484 | |
0ebb76de YW |
485 | struct tcmsg *tcm; |
486 | int r; | |
487 | ||
f50b93fe | 488 | assert_return(rtnl_message_type_is_traffic_control(nlmsg_type), -EINVAL); |
0ebb76de YW |
489 | assert_return(ret, -EINVAL); |
490 | ||
6e196011 LP |
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)); | |
0ebb76de YW |
495 | if (r < 0) |
496 | return r; | |
497 | ||
0ebb76de | 498 | tcm = NLMSG_DATA((*ret)->hdr); |
f50b93fe | 499 | tcm->tcm_ifindex = ifindex; |
0ebb76de | 500 | tcm->tcm_handle = handle; |
f50b93fe | 501 | tcm->tcm_parent = parent; |
0ebb76de YW |
502 | |
503 | return 0; | |
504 | } | |
1903c9bb | 505 | |
dd35a61c | 506 | int sd_rtnl_message_new_mdb( |
84e10015 ZJS |
507 | sd_netlink *rtnl, |
508 | sd_netlink_message **ret, | |
509 | uint16_t nlmsg_type, | |
ae298c93 | 510 | int ifindex) { |
84e10015 | 511 | |
1903c9bb DM |
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 | ||
6e196011 LP |
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)); | |
1903c9bb DM |
522 | if (r < 0) |
523 | return r; | |
524 | ||
1903c9bb DM |
525 | bpm = NLMSG_DATA((*ret)->hdr); |
526 | bpm->family = AF_BRIDGE; | |
ae298c93 | 527 | bpm->ifindex = ifindex; |
1903c9bb DM |
528 | |
529 | return 0; | |
530 | } | |
10786280 LP |
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 | ||
6e196011 | 543 | r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK); |
10786280 LP |
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 | } |