]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ipv4ll.c
Merge pull request #17185 from yuwata/ethtool-update
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <netinet/in.h>
4 #include <linux/if.h>
5
6 #include "network-internal.h"
7 #include "networkd-address.h"
8 #include "networkd-ipv4ll.h"
9 #include "networkd-link.h"
10 #include "networkd-manager.h"
11 #include "parse-util.h"
12
13 static int ipv4ll_address_lost(Link *link) {
14 _cleanup_(address_freep) Address *address = NULL;
15 struct in_addr addr;
16 int r;
17
18 assert(link);
19
20 link->ipv4ll_address_configured = false;
21
22 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
23 if (r < 0)
24 return 0;
25
26 log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(addr));
27
28 r = address_new(&address);
29 if (r < 0)
30 return log_link_error_errno(link, r, "Could not allocate address: %m");
31
32 address->family = AF_INET;
33 address->in_addr.in = addr;
34 address->prefixlen = 16;
35 address->scope = RT_SCOPE_LINK;
36
37 r = address_remove(address, link, NULL);
38 if (r < 0)
39 return r;
40
41 link_check_ready(link);
42
43 return 0;
44 }
45
46 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
47 int r;
48
49 assert(link);
50 assert(!link->ipv4ll_address_configured);
51
52 r = sd_netlink_message_get_errno(m);
53 if (r < 0 && r != -EEXIST) {
54 log_link_message_warning_errno(link, m, r, "could not set ipv4ll address");
55 link_enter_failed(link);
56 return 1;
57 } else if (r >= 0)
58 (void) manager_rtnl_process_address(rtnl, m, link->manager);
59
60 link->ipv4ll_address_configured = true;
61 link_check_ready(link);
62
63 return 1;
64 }
65
66 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
67 _cleanup_(address_freep) Address *ll_addr = NULL;
68 struct in_addr address;
69 int r;
70
71 assert(ll);
72 assert(link);
73
74 link->ipv4ll_address_configured = false;
75
76 r = sd_ipv4ll_get_address(ll, &address);
77 if (r == -ENOENT)
78 return 0;
79 else if (r < 0)
80 return r;
81
82 log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
83 IPV4_ADDRESS_FMT_VAL(address));
84
85 r = address_new(&ll_addr);
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;
92 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
93 ll_addr->scope = RT_SCOPE_LINK;
94
95 r = address_configure(ll_addr, link, ipv4ll_address_handler, false, NULL);
96 if (r < 0)
97 return r;
98
99 return 0;
100 }
101
102 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
103 Link *link = userdata;
104 int r;
105
106 assert(link);
107 assert(link->network);
108
109 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
110 return;
111
112 switch(event) {
113 case SD_IPV4LL_EVENT_STOP:
114 r = ipv4ll_address_lost(link);
115 if (r < 0) {
116 link_enter_failed(link);
117 return;
118 }
119 break;
120 case SD_IPV4LL_EVENT_CONFLICT:
121 r = ipv4ll_address_lost(link);
122 if (r < 0) {
123 link_enter_failed(link);
124 return;
125 }
126
127 r = sd_ipv4ll_restart(ll);
128 if (r < 0)
129 log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
130 break;
131 case SD_IPV4LL_EVENT_BIND:
132 r = ipv4ll_address_claimed(ll, link);
133 if (r < 0) {
134 log_link_error(link, "Failed to configure ipv4ll address: %m");
135 link_enter_failed(link);
136 return;
137 }
138 break;
139 default:
140 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
141 break;
142 }
143 }
144
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
164 int ipv4ll_configure(Link *link) {
165 uint64_t seed;
166 int r;
167
168 assert(link);
169
170 if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4))
171 return 0;
172
173 r = ipv4ll_init(link);
174 if (r < 0)
175 return r;
176
177 if (link->sd_device &&
178 net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
179 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
180 if (r < 0)
181 return r;
182 }
183
184 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
185 if (r < 0)
186 return r;
187
188 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
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 }
198
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
210 r = sd_ipv4ll_stop(link->ipv4ll);
211 if (r < 0)
212 return r;
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
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
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
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
285 AddressFamily *link_local = data;
286 int r;
287
288 assert(filename);
289 assert(lvalue);
290 assert(rvalue);
291 assert(data);
292
293 /* Note that this is mostly like
294 * config_parse_address_family(), except that it
295 * applies only to IPv4 */
296
297 r = parse_boolean(rvalue);
298 if (r < 0) {
299 log_syntax(unit, LOG_WARNING, filename, line, r,
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.",
310 lvalue, rvalue, address_family_to_string(*link_local));
311
312 return 0;
313 }