]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ipv4ll.c
network: make address/route_configure optionally return created Address/Route object
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
CommitLineData
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
13static 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
920b52e4 20 link->ipv4ll_address = false;
b22d8a00
TG
21
22 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
23 if (r < 0)
24 return 0;
25
79008bdd 26 log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", 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 46static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
b22d8a00
TG
47 int r;
48
49 assert(link);
50 assert(!link->ipv4ll_address);
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
TG
59
60 link->ipv4ll_address = true;
2aa7d367 61 link_check_ready(link);
b22d8a00
TG
62
63 return 1;
64}
65
66static 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
79316750 74 link->ipv4ll_address = 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
79008bdd 82 log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
b22d8a00
TG
83 ADDRESS_FMT_VAL(address));
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 102static 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
145int ipv4ll_configure(Link *link) {
dbe81cbd 146 uint64_t seed;
b22d8a00
TG
147 int r;
148
149 assert(link);
150 assert(link->network);
8bc17bb3 151 assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4));
b22d8a00 152
0bc70f1d
TG
153 if (!link->ipv4ll) {
154 r = sd_ipv4ll_new(&link->ipv4ll);
155 if (r < 0)
156 return r;
08c588d1
YW
157
158 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
159 if (r < 0)
160 return r;
0bc70f1d 161 }
b22d8a00 162
51517f9e 163 if (link->sd_device &&
96848152 164 net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
51517f9e
YW
165 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
166 if (r < 0)
167 return r;
b22d8a00
TG
168 }
169
b22d8a00
TG
170 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
171 if (r < 0)
172 return r;
173
2f8e7633 174 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
b22d8a00
TG
175 if (r < 0)
176 return r;
177
178 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
179 if (r < 0)
180 return r;
181
182 return 0;
183}
ca5ad760
YW
184
185int config_parse_ipv4ll(
186 const char* unit,
187 const char *filename,
188 unsigned line,
189 const char *section,
190 unsigned section_line,
191 const char *lvalue,
192 int ltype,
193 const char *rvalue,
194 void *data,
195 void *userdata) {
196
2d792895 197 AddressFamily *link_local = data;
ca5ad760
YW
198 int r;
199
200 assert(filename);
201 assert(lvalue);
202 assert(rvalue);
203 assert(data);
204
205 /* Note that this is mostly like
2d792895 206 * config_parse_address_family(), except that it
ca5ad760
YW
207 * applies only to IPv4 */
208
209 r = parse_boolean(rvalue);
210 if (r < 0) {
d96edb2c 211 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
212 "Failed to parse %s=%s, ignoring assignment. "
213 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
214 lvalue, rvalue, lvalue);
215 return 0;
216 }
217
218 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
219
220 log_syntax(unit, LOG_WARNING, filename, line, 0,
221 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
2d792895 222 lvalue, rvalue, address_family_to_string(*link_local));
ca5ad760
YW
223
224 return 0;
225}