]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ipv4ll.c
core: Record ExecMainStartTimestamp before forking
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/in.h>
4 #include <linux/if.h>
5
6 #include "netif-util.h"
7 #include "networkd-address.h"
8 #include "networkd-ipv4acd.h"
9 #include "networkd-ipv4ll.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-queue.h"
13 #include "parse-util.h"
14
15 bool link_ipv4ll_enabled(Link *link) {
16 assert(link);
17
18 if (!link_ipv4acd_supported(link))
19 return false;
20
21 if (!link->network)
22 return false;
23
24 if (link->network->bond)
25 return false;
26
27 return link->network->link_local & ADDRESS_FAMILY_IPV4;
28 }
29
30 static int address_new_from_ipv4ll(Link *link, Address **ret) {
31 _cleanup_(address_unrefp) Address *address = NULL;
32 struct in_addr addr;
33 int r;
34
35 assert(link);
36 assert(link->ipv4ll);
37 assert(ret);
38
39 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
40 if (r < 0)
41 return r;
42
43 r = address_new(&address);
44 if (r < 0)
45 return -ENOMEM;
46
47 address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
48 address->family = AF_INET;
49 address->in_addr.in = addr;
50 address->prefixlen = 16;
51 address->scope = RT_SCOPE_LINK;
52 address->route_metric = IPV4LL_ROUTE_METRIC;
53
54 *ret = TAKE_PTR(address);
55 return 0;
56 }
57
58 static int ipv4ll_address_lost(Link *link) {
59 _cleanup_(address_unrefp) Address *address = NULL;
60 int r;
61
62 assert(link);
63
64 link->ipv4ll_address_configured = false;
65
66 r = address_new_from_ipv4ll(link, &address);
67 if (r == -ENOENT)
68 return 0;
69 if (r < 0)
70 return r;
71
72 log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
73 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
74
75 return address_remove_and_cancel(address, link);
76 }
77
78 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
79 int r;
80
81 assert(link);
82 assert(!link->ipv4ll_address_configured);
83
84 r = address_configure_handler_internal(rtnl, m, link, "Could not set ipv4ll address");
85 if (r <= 0)
86 return r;
87
88 link->ipv4ll_address_configured = true;
89 link_check_ready(link);
90
91 return 1;
92 }
93
94 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
95 _cleanup_(address_unrefp) Address *address = NULL;
96 int r;
97
98 assert(ll);
99 assert(link);
100
101 link->ipv4ll_address_configured = false;
102
103 r = address_new_from_ipv4ll(link, &address);
104 if (r == -ENOENT)
105 return 0;
106 if (r < 0)
107 return r;
108
109 log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
110 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
111
112 return link_request_address(link, address, NULL, ipv4ll_address_handler, NULL);
113 }
114
115 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
116 Link *link = ASSERT_PTR(userdata);
117 int r;
118
119 assert(link->network);
120
121 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
122 return;
123
124 switch (event) {
125 case SD_IPV4LL_EVENT_STOP:
126 r = ipv4ll_address_lost(link);
127 if (r < 0) {
128 link_enter_failed(link);
129 return;
130 }
131 break;
132 case SD_IPV4LL_EVENT_CONFLICT:
133 r = ipv4ll_address_lost(link);
134 if (r < 0) {
135 link_enter_failed(link);
136 return;
137 }
138
139 r = sd_ipv4ll_restart(ll);
140 if (r < 0) {
141 log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
142 link_enter_failed(link);
143 }
144 break;
145 case SD_IPV4LL_EVENT_BIND:
146 r = ipv4ll_address_claimed(ll, link);
147 if (r < 0) {
148 log_link_error(link, "Failed to configure ipv4ll address: %m");
149 link_enter_failed(link);
150 return;
151 }
152 break;
153 default:
154 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
155 break;
156 }
157 }
158
159 static int ipv4ll_check_mac(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata) {
160 Manager *m = ASSERT_PTR(userdata);
161 struct hw_addr_data hw_addr;
162
163 assert(mac);
164
165 hw_addr = (struct hw_addr_data) {
166 .length = ETH_ALEN,
167 .ether = *mac,
168 };
169
170 return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
171 }
172
173 int ipv4ll_configure(Link *link) {
174 uint64_t seed;
175 int r;
176
177 assert(link);
178
179 if (!link_ipv4ll_enabled(link))
180 return 0;
181
182 if (link->ipv4ll)
183 return -EBUSY;
184
185 r = sd_ipv4ll_new(&link->ipv4ll);
186 if (r < 0)
187 return r;
188
189 r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
190 if (r < 0)
191 return r;
192
193 if (link->dev &&
194 net_get_unique_predictable_data(link->dev, true, &seed) >= 0) {
195 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
196 if (r < 0)
197 return r;
198 }
199
200 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
201 if (r < 0)
202 return r;
203
204 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
205 if (r < 0)
206 return r;
207
208 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
209 if (r < 0)
210 return r;
211
212 return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager);
213 }
214
215 int ipv4ll_update_mac(Link *link) {
216 assert(link);
217
218 if (link->hw_addr.length != ETH_ALEN)
219 return 0;
220 if (ether_addr_is_null(&link->hw_addr.ether))
221 return 0;
222 if (!link->ipv4ll)
223 return 0;
224
225 return sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
226 }
227
228 int config_parse_ipv4ll(
229 const char* unit,
230 const char *filename,
231 unsigned line,
232 const char *section,
233 unsigned section_line,
234 const char *lvalue,
235 int ltype,
236 const char *rvalue,
237 void *data,
238 void *userdata) {
239
240 AddressFamily *link_local = ASSERT_PTR(data);
241 int r;
242
243 assert(filename);
244 assert(lvalue);
245 assert(rvalue);
246
247 /* Note that this is mostly like
248 * config_parse_address_family(), except that it
249 * applies only to IPv4 */
250
251 r = parse_boolean(rvalue);
252 if (r < 0) {
253 log_syntax(unit, LOG_WARNING, filename, line, r,
254 "Failed to parse %s=%s, ignoring assignment. "
255 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
256 lvalue, rvalue, lvalue);
257 return 0;
258 }
259
260 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
261
262 log_syntax(unit, LOG_WARNING, filename, line, 0,
263 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
264 lvalue, rvalue, address_family_to_string(*link_local));
265
266 return 0;
267 }
268
269 int config_parse_ipv4ll_address(
270 const char* unit,
271 const char *filename,
272 unsigned line,
273 const char *section,
274 unsigned section_line,
275 const char *lvalue,
276 int ltype,
277 const char *rvalue,
278 void *data,
279 void *userdata) {
280
281 union in_addr_union a;
282 struct in_addr *ipv4ll_address = ASSERT_PTR(data);
283 int r;
284
285 assert(filename);
286 assert(lvalue);
287 assert(rvalue);
288
289 if (isempty(rvalue)) {
290 *ipv4ll_address = (struct in_addr) {};
291 return 0;
292 }
293
294 r = in_addr_from_string(AF_INET, rvalue, &a);
295 if (r < 0) {
296 log_syntax(unit, LOG_WARNING, filename, line, r,
297 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
298 return 0;
299 }
300 if (!in4_addr_is_link_local_dynamic(&a.in)) {
301 log_syntax(unit, LOG_WARNING, filename, line, 0,
302 "Specified address cannot be used as an IPv4 link local address, ignoring assignment: %s",
303 rvalue);
304 return 0;
305 }
306
307 *ipv4ll_address = a.in;
308 return 0;
309 }