Branch data Line data Source code
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 : 0 : static int ipv4ll_address_lost(Link *link) {
14 : 0 : _cleanup_(address_freep) Address *address = NULL;
15 : 0 : _cleanup_(route_freep) Route *route = NULL;
16 : : struct in_addr addr;
17 : : int r;
18 : :
19 [ # # ]: 0 : assert(link);
20 : :
21 : 0 : link->ipv4ll_route = false;
22 : 0 : link->ipv4ll_address = false;
23 : :
24 : 0 : r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
25 [ # # ]: 0 : if (r < 0)
26 : 0 : return 0;
27 : :
28 [ # # # # ]: 0 : log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
29 : :
30 : 0 : r = address_new(&address);
31 [ # # ]: 0 : if (r < 0)
32 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not allocate address: %m");
33 : :
34 : 0 : address->family = AF_INET;
35 : 0 : address->in_addr.in = addr;
36 : 0 : address->prefixlen = 16;
37 : 0 : address->scope = RT_SCOPE_LINK;
38 : :
39 : 0 : r = address_remove(address, link, NULL);
40 [ # # ]: 0 : if (r < 0)
41 : 0 : return r;
42 : :
43 : 0 : r = route_new(&route);
44 [ # # ]: 0 : if (r < 0)
45 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not allocate route: %m");
46 : :
47 : 0 : route->family = AF_INET;
48 : 0 : route->scope = RT_SCOPE_LINK;
49 : 0 : route->priority = IPV4LL_ROUTE_METRIC;
50 : :
51 : 0 : r = route_remove(route, link, NULL);
52 [ # # ]: 0 : if (r < 0)
53 : 0 : return r;
54 : :
55 : 0 : link_check_ready(link);
56 : :
57 : 0 : return 0;
58 : : }
59 : :
60 : 0 : static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
61 : : int r;
62 : :
63 [ # # ]: 0 : assert(link);
64 [ # # ]: 0 : assert(!link->ipv4ll_route);
65 : :
66 : 0 : r = sd_netlink_message_get_errno(m);
67 [ # # # # ]: 0 : if (r < 0 && r != -EEXIST) {
68 [ # # # # ]: 0 : log_link_error_errno(link, r, "could not set ipv4ll route: %m");
69 : 0 : link_enter_failed(link);
70 : 0 : return 1;
71 : : }
72 : :
73 : 0 : link->ipv4ll_route = true;
74 : :
75 : 0 : link_check_ready(link);
76 : :
77 : 0 : return 1;
78 : : }
79 : :
80 : 0 : static int ipv4ll_route_configure(Link *link) {
81 : 0 : _cleanup_(route_freep) Route *route = NULL;
82 : : int r;
83 : :
84 : 0 : r = route_new(&route);
85 [ # # ]: 0 : if (r < 0)
86 : 0 : return r;
87 : :
88 : 0 : route->family = AF_INET;
89 : 0 : route->scope = RT_SCOPE_LINK;
90 : 0 : route->protocol = RTPROT_STATIC;
91 : 0 : route->priority = IPV4LL_ROUTE_METRIC;
92 : 0 : route->table = link_get_vrf_table(link);
93 : :
94 : 0 : return route_configure(route, link, ipv4ll_route_handler);
95 : : }
96 : :
97 : 0 : static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
98 : : int r;
99 : :
100 [ # # ]: 0 : assert(link);
101 [ # # ]: 0 : assert(!link->ipv4ll_address);
102 : :
103 : 0 : r = sd_netlink_message_get_errno(m);
104 [ # # # # ]: 0 : if (r < 0 && r != -EEXIST) {
105 [ # # # # ]: 0 : log_link_error_errno(link, r, "could not set ipv4ll address: %m");
106 : 0 : link_enter_failed(link);
107 : 0 : return 1;
108 [ # # ]: 0 : } else if (r >= 0)
109 : 0 : (void) manager_rtnl_process_address(rtnl, m, link->manager);
110 : :
111 : 0 : link->ipv4ll_address = true;
112 : :
113 : 0 : r = ipv4ll_route_configure(link);
114 [ # # ]: 0 : if (r < 0) {
115 [ # # # # ]: 0 : log_link_error_errno(link, r, "Failed to configure ipv4ll route: %m");
116 : 0 : link_enter_failed(link);
117 : : }
118 : :
119 : 0 : return 1;
120 : : }
121 : :
122 : 0 : static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
123 : 0 : _cleanup_(address_freep) Address *ll_addr = NULL;
124 : : struct in_addr address;
125 : : int r;
126 : :
127 [ # # ]: 0 : assert(ll);
128 [ # # ]: 0 : assert(link);
129 : :
130 : 0 : link->ipv4ll_address = false;
131 : 0 : link->ipv4ll_route = false;
132 : :
133 : 0 : r = sd_ipv4ll_get_address(ll, &address);
134 [ # # ]: 0 : if (r == -ENOENT)
135 : 0 : return 0;
136 [ # # ]: 0 : else if (r < 0)
137 : 0 : return r;
138 : :
139 [ # # # # ]: 0 : log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
140 : : ADDRESS_FMT_VAL(address));
141 : :
142 : 0 : r = address_new(&ll_addr);
143 [ # # ]: 0 : if (r < 0)
144 : 0 : return r;
145 : :
146 : 0 : ll_addr->family = AF_INET;
147 : 0 : ll_addr->in_addr.in = address;
148 : 0 : ll_addr->prefixlen = 16;
149 : 0 : ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen);
150 : 0 : ll_addr->scope = RT_SCOPE_LINK;
151 : :
152 : 0 : r = address_configure(ll_addr, link, ipv4ll_address_handler, false);
153 [ # # ]: 0 : if (r < 0)
154 : 0 : return r;
155 : :
156 : 0 : return 0;
157 : : }
158 : :
159 : 0 : static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
160 : 0 : Link *link = userdata;
161 : : int r;
162 : :
163 [ # # ]: 0 : assert(link);
164 [ # # ]: 0 : assert(link->network);
165 : :
166 [ # # # # ]: 0 : if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
167 : 0 : return;
168 : :
169 [ # # # # ]: 0 : switch(event) {
170 : 0 : case SD_IPV4LL_EVENT_STOP:
171 : 0 : r = ipv4ll_address_lost(link);
172 [ # # ]: 0 : if (r < 0) {
173 : 0 : link_enter_failed(link);
174 : 0 : return;
175 : : }
176 : 0 : break;
177 : 0 : case SD_IPV4LL_EVENT_CONFLICT:
178 : 0 : r = ipv4ll_address_lost(link);
179 [ # # ]: 0 : if (r < 0) {
180 : 0 : link_enter_failed(link);
181 : 0 : return;
182 : : }
183 : :
184 : 0 : r = sd_ipv4ll_restart(ll);
185 [ # # ]: 0 : if (r < 0)
186 [ # # # # ]: 0 : log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
187 : 0 : break;
188 : 0 : case SD_IPV4LL_EVENT_BIND:
189 : 0 : r = ipv4ll_address_claimed(ll, link);
190 [ # # ]: 0 : if (r < 0) {
191 [ # # # # ]: 0 : log_link_error(link, "Failed to configure ipv4ll address: %m");
192 : 0 : link_enter_failed(link);
193 : 0 : return;
194 : : }
195 : 0 : break;
196 : 0 : default:
197 [ # # # # ]: 0 : log_link_warning(link, "IPv4 link-local unknown event: %d", event);
198 : 0 : break;
199 : : }
200 : : }
201 : :
202 : 0 : int ipv4ll_configure(Link *link) {
203 : : uint64_t seed;
204 : : int r;
205 : :
206 [ # # ]: 0 : assert(link);
207 [ # # ]: 0 : assert(link->network);
208 [ # # ]: 0 : assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4));
209 : :
210 [ # # ]: 0 : if (!link->ipv4ll) {
211 : 0 : r = sd_ipv4ll_new(&link->ipv4ll);
212 [ # # ]: 0 : if (r < 0)
213 : 0 : return r;
214 : : }
215 : :
216 [ # # # # ]: 0 : if (link->sd_device &&
217 : 0 : net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
218 : 0 : r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
219 [ # # ]: 0 : if (r < 0)
220 : 0 : return r;
221 : : }
222 : :
223 : 0 : r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
224 [ # # ]: 0 : if (r < 0)
225 : 0 : return r;
226 : :
227 : 0 : r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
228 [ # # ]: 0 : if (r < 0)
229 : 0 : return r;
230 : :
231 : 0 : r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
232 [ # # ]: 0 : if (r < 0)
233 : 0 : return r;
234 : :
235 : 0 : r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
236 [ # # ]: 0 : if (r < 0)
237 : 0 : return r;
238 : :
239 : 0 : return 0;
240 : : }
241 : :
242 : 0 : int config_parse_ipv4ll(
243 : : const char* unit,
244 : : const char *filename,
245 : : unsigned line,
246 : : const char *section,
247 : : unsigned section_line,
248 : : const char *lvalue,
249 : : int ltype,
250 : : const char *rvalue,
251 : : void *data,
252 : : void *userdata) {
253 : :
254 : 0 : AddressFamily *link_local = data;
255 : : int r;
256 : :
257 [ # # ]: 0 : assert(filename);
258 [ # # ]: 0 : assert(lvalue);
259 [ # # ]: 0 : assert(rvalue);
260 [ # # ]: 0 : assert(data);
261 : :
262 : : /* Note that this is mostly like
263 : : * config_parse_address_family(), except that it
264 : : * applies only to IPv4 */
265 : :
266 : 0 : r = parse_boolean(rvalue);
267 [ # # ]: 0 : if (r < 0) {
268 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
269 : : "Failed to parse %s=%s, ignoring assignment. "
270 : : "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
271 : : lvalue, rvalue, lvalue);
272 : 0 : return 0;
273 : : }
274 : :
275 [ # # ]: 0 : SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
276 : :
277 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
278 : : "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
279 : : lvalue, rvalue, address_family_to_string(*link_local));
280 : :
281 : 0 : return 0;
282 : : }
|