]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ipv4ll.c
network: drop duplicated address_set_broadcast()
[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_freep) 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_freep) Address *address = NULL;
60 Address *existing;
61 int r;
62
63 assert(link);
64
65 link->ipv4ll_address_configured = false;
66
67 r = address_new_from_ipv4ll(link, &address);
68 if (r == -ENOENT)
69 return 0;
70 if (r < 0)
71 return r;
72
73 if (address_get(link, address, &existing) < 0)
74 return 0;
75
76 if (existing->source != NETWORK_CONFIG_SOURCE_IPV4LL)
77 return 0;
78
79 if (!address_exists(existing))
80 return 0;
81
82 log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
83 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
84
85 return address_remove(existing);
86 }
87
88 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
89 int r;
90
91 assert(link);
92 assert(!link->ipv4ll_address_configured);
93
94 r = address_configure_handler_internal(rtnl, m, link, "Could not set ipv4ll address");
95 if (r <= 0)
96 return r;
97
98 link->ipv4ll_address_configured = true;
99 link_check_ready(link);
100
101 return 1;
102 }
103
104 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
105 _cleanup_(address_freep) Address *address = NULL;
106 int r;
107
108 assert(ll);
109 assert(link);
110
111 link->ipv4ll_address_configured = false;
112
113 r = address_new_from_ipv4ll(link, &address);
114 if (r == -ENOENT)
115 return 0;
116 if (r < 0)
117 return r;
118
119 log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
120 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
121
122 return link_request_address(link, address, NULL, ipv4ll_address_handler, NULL);
123 }
124
125 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
126 Link *link = ASSERT_PTR(userdata);
127 int r;
128
129 assert(link->network);
130
131 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
132 return;
133
134 switch (event) {
135 case SD_IPV4LL_EVENT_STOP:
136 r = ipv4ll_address_lost(link);
137 if (r < 0) {
138 link_enter_failed(link);
139 return;
140 }
141 break;
142 case SD_IPV4LL_EVENT_CONFLICT:
143 r = ipv4ll_address_lost(link);
144 if (r < 0) {
145 link_enter_failed(link);
146 return;
147 }
148
149 r = sd_ipv4ll_restart(ll);
150 if (r < 0) {
151 log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
152 link_enter_failed(link);
153 }
154 break;
155 case SD_IPV4LL_EVENT_BIND:
156 r = ipv4ll_address_claimed(ll, link);
157 if (r < 0) {
158 log_link_error(link, "Failed to configure ipv4ll address: %m");
159 link_enter_failed(link);
160 return;
161 }
162 break;
163 default:
164 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
165 break;
166 }
167 }
168
169 static int ipv4ll_check_mac(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata) {
170 Manager *m = ASSERT_PTR(userdata);
171 struct hw_addr_data hw_addr;
172
173 assert(mac);
174
175 hw_addr = (struct hw_addr_data) {
176 .length = ETH_ALEN,
177 .ether = *mac,
178 };
179
180 return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
181 }
182
183 int ipv4ll_configure(Link *link) {
184 uint64_t seed;
185 int r;
186
187 assert(link);
188
189 if (!link_ipv4ll_enabled(link))
190 return 0;
191
192 if (link->ipv4ll)
193 return -EBUSY;
194
195 r = sd_ipv4ll_new(&link->ipv4ll);
196 if (r < 0)
197 return r;
198
199 r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
200 if (r < 0)
201 return r;
202
203 if (link->dev &&
204 net_get_unique_predictable_data(link->dev, true, &seed) >= 0) {
205 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
206 if (r < 0)
207 return r;
208 }
209
210 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
211 if (r < 0)
212 return r;
213
214 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
215 if (r < 0)
216 return r;
217
218 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
219 if (r < 0)
220 return r;
221
222 return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager);
223 }
224
225 int ipv4ll_update_mac(Link *link) {
226 assert(link);
227
228 if (link->hw_addr.length != ETH_ALEN)
229 return 0;
230 if (ether_addr_is_null(&link->hw_addr.ether))
231 return 0;
232 if (!link->ipv4ll)
233 return 0;
234
235 return sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
236 }
237
238 int config_parse_ipv4ll(
239 const char* unit,
240 const char *filename,
241 unsigned line,
242 const char *section,
243 unsigned section_line,
244 const char *lvalue,
245 int ltype,
246 const char *rvalue,
247 void *data,
248 void *userdata) {
249
250 AddressFamily *link_local = ASSERT_PTR(data);
251 int r;
252
253 assert(filename);
254 assert(lvalue);
255 assert(rvalue);
256
257 /* Note that this is mostly like
258 * config_parse_address_family(), except that it
259 * applies only to IPv4 */
260
261 r = parse_boolean(rvalue);
262 if (r < 0) {
263 log_syntax(unit, LOG_WARNING, filename, line, r,
264 "Failed to parse %s=%s, ignoring assignment. "
265 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
266 lvalue, rvalue, lvalue);
267 return 0;
268 }
269
270 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
271
272 log_syntax(unit, LOG_WARNING, filename, line, 0,
273 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
274 lvalue, rvalue, address_family_to_string(*link_local));
275
276 return 0;
277 }
278
279 int config_parse_ipv4ll_address(
280 const char* unit,
281 const char *filename,
282 unsigned line,
283 const char *section,
284 unsigned section_line,
285 const char *lvalue,
286 int ltype,
287 const char *rvalue,
288 void *data,
289 void *userdata) {
290
291 union in_addr_union a;
292 struct in_addr *ipv4ll_address = ASSERT_PTR(data);
293 int r;
294
295 assert(filename);
296 assert(lvalue);
297 assert(rvalue);
298
299 if (isempty(rvalue)) {
300 *ipv4ll_address = (struct in_addr) {};
301 return 0;
302 }
303
304 r = in_addr_from_string(AF_INET, rvalue, &a);
305 if (r < 0) {
306 log_syntax(unit, LOG_WARNING, filename, line, r,
307 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
308 return 0;
309 }
310 if (!in4_addr_is_link_local_dynamic(&a.in)) {
311 log_syntax(unit, LOG_WARNING, filename, line, 0,
312 "Specified address cannot be used as an IPv4 link local address, ignoring assignment: %s",
313 rvalue);
314 return 0;
315 }
316
317 *ipv4ll_address = a.in;
318 return 0;
319 }