]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ipv4ll.c
network: make address/route_configure optionally return created Address/Route object
[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 = 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 %u.%u.%u.%u", 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);
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 = 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 = 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 %u.%u.%u.%u",
83 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 int ipv4ll_configure(Link *link) {
146 uint64_t seed;
147 int r;
148
149 assert(link);
150 assert(link->network);
151 assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4));
152
153 if (!link->ipv4ll) {
154 r = sd_ipv4ll_new(&link->ipv4ll);
155 if (r < 0)
156 return r;
157
158 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
159 if (r < 0)
160 return r;
161 }
162
163 if (link->sd_device &&
164 net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
165 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
166 if (r < 0)
167 return r;
168 }
169
170 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
171 if (r < 0)
172 return r;
173
174 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
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 }
184
185 int 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
197 AddressFamily *link_local = data;
198 int r;
199
200 assert(filename);
201 assert(lvalue);
202 assert(rvalue);
203 assert(data);
204
205 /* Note that this is mostly like
206 * config_parse_address_family(), except that it
207 * applies only to IPv4 */
208
209 r = parse_boolean(rvalue);
210 if (r < 0) {
211 log_syntax(unit, LOG_WARNING, filename, line, r,
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.",
222 lvalue, rvalue, address_family_to_string(*link_local));
223
224 return 0;
225 }