]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
b22d8a00 | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
b22d8a00 TG |
4 | #include <linux/if.h> |
5 | ||
b22d8a00 | 6 | #include "network-internal.h" |
23f53b99 | 7 | #include "networkd-address.h" |
ca5ad760 | 8 | #include "networkd-ipv4ll.h" |
23f53b99 | 9 | #include "networkd-link.h" |
ca5ad760 YW |
10 | #include "networkd-manager.h" |
11 | #include "parse-util.h" | |
b22d8a00 TG |
12 | |
13 | static int ipv4ll_address_lost(Link *link) { | |
8e766630 | 14 | _cleanup_(address_freep) Address *address = NULL; |
b22d8a00 TG |
15 | struct in_addr addr; |
16 | int r; | |
17 | ||
18 | assert(link); | |
19 | ||
1c09d84e | 20 | link->ipv4ll_address_configured = false; |
b22d8a00 TG |
21 | |
22 | r = sd_ipv4ll_get_address(link->ipv4ll, &addr); | |
23 | if (r < 0) | |
24 | return 0; | |
25 | ||
ceea6c1a | 26 | log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(addr)); |
b22d8a00 | 27 | |
f0213e37 | 28 | r = address_new(&address); |
fc95c359 YW |
29 | if (r < 0) |
30 | return log_link_error_errno(link, r, "Could not allocate address: %m"); | |
b22d8a00 TG |
31 | |
32 | address->family = AF_INET; | |
33 | address->in_addr.in = addr; | |
34 | address->prefixlen = 16; | |
35 | address->scope = RT_SCOPE_LINK; | |
36 | ||
807341ec YW |
37 | r = address_remove(address, link, NULL); |
38 | if (r < 0) | |
39 | return r; | |
b22d8a00 | 40 | |
8012cd39 | 41 | link_check_ready(link); |
b22d8a00 TG |
42 | |
43 | return 0; | |
44 | } | |
45 | ||
302a796f | 46 | static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { |
b22d8a00 TG |
47 | int r; |
48 | ||
49 | assert(link); | |
1c09d84e | 50 | assert(!link->ipv4ll_address_configured); |
b22d8a00 | 51 | |
1c4baffc | 52 | r = sd_netlink_message_get_errno(m); |
b22d8a00 | 53 | if (r < 0 && r != -EEXIST) { |
5ecb131d | 54 | log_link_message_warning_errno(link, m, r, "could not set ipv4ll address"); |
b22d8a00 | 55 | link_enter_failed(link); |
4ff296b0 | 56 | return 1; |
45af44d4 | 57 | } else if (r >= 0) |
4ff296b0 | 58 | (void) manager_rtnl_process_address(rtnl, m, link->manager); |
b22d8a00 | 59 | |
1c09d84e | 60 | link->ipv4ll_address_configured = true; |
2aa7d367 | 61 | link_check_ready(link); |
b22d8a00 TG |
62 | |
63 | return 1; | |
64 | } | |
65 | ||
66 | static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { | |
8e766630 | 67 | _cleanup_(address_freep) Address *ll_addr = NULL; |
b22d8a00 TG |
68 | struct in_addr address; |
69 | int r; | |
70 | ||
71 | assert(ll); | |
72 | assert(link); | |
73 | ||
1c09d84e | 74 | link->ipv4ll_address_configured = false; |
79316750 | 75 | |
b22d8a00 TG |
76 | r = sd_ipv4ll_get_address(ll, &address); |
77 | if (r == -ENOENT) | |
78 | return 0; | |
79 | else if (r < 0) | |
80 | return r; | |
81 | ||
ceea6c1a YW |
82 | log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR, |
83 | IPV4_ADDRESS_FMT_VAL(address)); | |
b22d8a00 | 84 | |
f0213e37 | 85 | r = address_new(&ll_addr); |
b22d8a00 TG |
86 | if (r < 0) |
87 | return r; | |
88 | ||
89 | ll_addr->family = AF_INET; | |
90 | ll_addr->in_addr.in = address; | |
91 | ll_addr->prefixlen = 16; | |
8e38570e | 92 | ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen); |
b22d8a00 TG |
93 | ll_addr->scope = RT_SCOPE_LINK; |
94 | ||
80b0e860 | 95 | r = address_configure(ll_addr, link, ipv4ll_address_handler, false, NULL); |
b22d8a00 TG |
96 | if (r < 0) |
97 | return r; | |
98 | ||
b22d8a00 TG |
99 | return 0; |
100 | } | |
101 | ||
9ed794a3 | 102 | static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) { |
b22d8a00 TG |
103 | Link *link = userdata; |
104 | int r; | |
105 | ||
106 | assert(link); | |
107 | assert(link->network); | |
b22d8a00 TG |
108 | |
109 | if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) | |
110 | return; | |
111 | ||
112 | switch(event) { | |
be19c5b5 | 113 | case SD_IPV4LL_EVENT_STOP: |
0698ff41 JR |
114 | r = ipv4ll_address_lost(link); |
115 | if (r < 0) { | |
116 | link_enter_failed(link); | |
117 | return; | |
118 | } | |
119 | break; | |
be19c5b5 | 120 | case SD_IPV4LL_EVENT_CONFLICT: |
b22d8a00 TG |
121 | r = ipv4ll_address_lost(link); |
122 | if (r < 0) { | |
123 | link_enter_failed(link); | |
124 | return; | |
125 | } | |
0698ff41 JR |
126 | |
127 | r = sd_ipv4ll_restart(ll); | |
128 | if (r < 0) | |
aa5f4c77 | 129 | log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); |
b22d8a00 | 130 | break; |
be19c5b5 | 131 | case SD_IPV4LL_EVENT_BIND: |
b22d8a00 TG |
132 | r = ipv4ll_address_claimed(ll, link); |
133 | if (r < 0) { | |
79316750 | 134 | log_link_error(link, "Failed to configure ipv4ll address: %m"); |
b22d8a00 TG |
135 | link_enter_failed(link); |
136 | return; | |
137 | } | |
138 | break; | |
139 | default: | |
b45e4eb6 | 140 | log_link_warning(link, "IPv4 link-local unknown event: %d", event); |
b22d8a00 TG |
141 | break; |
142 | } | |
143 | } | |
144 | ||
daad60d1 YW |
145 | static int ipv4ll_init(Link *link) { |
146 | int r; | |
147 | ||
148 | assert(link); | |
149 | ||
150 | if (link->ipv4ll) | |
151 | return 0; | |
152 | ||
153 | r = sd_ipv4ll_new(&link->ipv4ll); | |
154 | if (r < 0) | |
155 | return r; | |
156 | ||
157 | r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0); | |
158 | if (r < 0) | |
159 | return r; | |
160 | ||
161 | return 0; | |
162 | } | |
163 | ||
b22d8a00 | 164 | int ipv4ll_configure(Link *link) { |
dbe81cbd | 165 | uint64_t seed; |
b22d8a00 TG |
166 | int r; |
167 | ||
168 | assert(link); | |
2ffd6d73 YW |
169 | |
170 | if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) | |
171 | return 0; | |
b22d8a00 | 172 | |
daad60d1 YW |
173 | r = ipv4ll_init(link); |
174 | if (r < 0) | |
175 | return r; | |
b22d8a00 | 176 | |
51517f9e | 177 | if (link->sd_device && |
96848152 | 178 | net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) { |
51517f9e YW |
179 | r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); |
180 | if (r < 0) | |
181 | return r; | |
b22d8a00 TG |
182 | } |
183 | ||
b22d8a00 TG |
184 | r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac); |
185 | if (r < 0) | |
186 | return r; | |
187 | ||
2f8e7633 | 188 | r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex); |
b22d8a00 TG |
189 | if (r < 0) |
190 | return r; | |
191 | ||
192 | r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link); | |
193 | if (r < 0) | |
194 | return r; | |
195 | ||
196 | return 0; | |
197 | } | |
ca5ad760 | 198 | |
a3adb4a6 YW |
199 | int ipv4ll_update_mac(Link *link) { |
200 | bool restart; | |
201 | int r; | |
202 | ||
203 | assert(link); | |
204 | ||
205 | if (!link->ipv4ll) | |
206 | return 0; | |
207 | ||
208 | restart = sd_ipv4ll_is_running(link->ipv4ll) > 0; | |
209 | ||
a391901e YW |
210 | r = sd_ipv4ll_stop(link->ipv4ll); |
211 | if (r < 0) | |
212 | return r; | |
a3adb4a6 YW |
213 | |
214 | r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac); | |
215 | if (r < 0) | |
216 | return r; | |
217 | ||
218 | if (restart) { | |
219 | r = sd_ipv4ll_start(link->ipv4ll); | |
220 | if (r < 0) | |
221 | return r; | |
222 | } | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
ca21a19a YW |
227 | int link_serialize_ipv4ll(Link *link, FILE *f) { |
228 | struct in_addr address; | |
229 | int r; | |
230 | ||
231 | assert(link); | |
232 | ||
233 | if (!link->ipv4ll) | |
234 | return 0; | |
235 | ||
236 | r = sd_ipv4ll_get_address(link->ipv4ll, &address); | |
237 | if (r == -ENOENT) | |
238 | return 0; | |
239 | if (r < 0) | |
240 | return r; | |
241 | ||
242 | fputs("IPV4LL_ADDRESS=", f); | |
243 | serialize_in_addrs(f, &address, 1, false, NULL); | |
244 | fputc('\n', f); | |
245 | ||
246 | return 0; | |
247 | } | |
248 | ||
daad60d1 YW |
249 | int link_deserialize_ipv4ll(Link *link, const char *ipv4ll_address) { |
250 | union in_addr_union address; | |
251 | int r; | |
252 | ||
253 | assert(link); | |
254 | ||
255 | if (isempty(ipv4ll_address)) | |
256 | return 0; | |
257 | ||
258 | r = in_addr_from_string(AF_INET, ipv4ll_address, &address); | |
259 | if (r < 0) | |
260 | return log_link_debug_errno(link, r, "Failed to parse IPv4LL address: %s", ipv4ll_address); | |
261 | ||
262 | r = ipv4ll_init(link); | |
263 | if (r < 0) | |
264 | return log_link_debug_errno(link, r, "Failed to initialize IPv4LL client: %m"); | |
265 | ||
266 | r = sd_ipv4ll_set_address(link->ipv4ll, &address.in); | |
267 | if (r < 0) | |
268 | return log_link_debug_errno(link, r, "Failed to set initial IPv4LL address %s: %m", ipv4ll_address); | |
269 | ||
270 | return 0; | |
271 | } | |
272 | ||
ca5ad760 YW |
273 | int config_parse_ipv4ll( |
274 | const char* unit, | |
275 | const char *filename, | |
276 | unsigned line, | |
277 | const char *section, | |
278 | unsigned section_line, | |
279 | const char *lvalue, | |
280 | int ltype, | |
281 | const char *rvalue, | |
282 | void *data, | |
283 | void *userdata) { | |
284 | ||
2d792895 | 285 | AddressFamily *link_local = data; |
ca5ad760 YW |
286 | int r; |
287 | ||
288 | assert(filename); | |
289 | assert(lvalue); | |
290 | assert(rvalue); | |
291 | assert(data); | |
292 | ||
293 | /* Note that this is mostly like | |
2d792895 | 294 | * config_parse_address_family(), except that it |
ca5ad760 YW |
295 | * applies only to IPv4 */ |
296 | ||
297 | r = parse_boolean(rvalue); | |
298 | if (r < 0) { | |
d96edb2c | 299 | log_syntax(unit, LOG_WARNING, filename, line, r, |
ca5ad760 YW |
300 | "Failed to parse %s=%s, ignoring assignment. " |
301 | "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.", | |
302 | lvalue, rvalue, lvalue); | |
303 | return 0; | |
304 | } | |
305 | ||
306 | SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r); | |
307 | ||
308 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
309 | "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.", | |
2d792895 | 310 | lvalue, rvalue, address_family_to_string(*link_local)); |
ca5ad760 YW |
311 | |
312 | return 0; | |
313 | } |