]> git.proxmox.com Git - systemd.git/blame - src/network/networkd-ipv4ll.c
Merge tag 'upstream/229'
[systemd.git] / src / network / networkd-ipv4ll.c
CommitLineData
5eef597e
MP
1/***
2 This file is part of systemd.
3
4 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <netinet/ether.h>
21#include <linux/if.h>
22
5eef597e 23#include "network-internal.h"
db2df898 24#include "networkd-link.h"
5eef597e
MP
25
26static int ipv4ll_address_lost(Link *link) {
27 _cleanup_address_free_ Address *address = NULL;
28 _cleanup_route_free_ Route *route = NULL;
29 struct in_addr addr;
30 int r;
31
32 assert(link);
33
34 link->ipv4ll_route = false;
86f210e9 35 link->ipv4ll_address = false;
5eef597e
MP
36
37 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
38 if (r < 0)
39 return 0;
40
f47781d8 41 log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
5eef597e 42
db2df898 43 r = address_new(&address);
5eef597e 44 if (r < 0) {
6300502b 45 log_link_error_errno(link, r, "Could not allocate address: %m");
5eef597e
MP
46 return r;
47 }
48
49 address->family = AF_INET;
50 address->in_addr.in = addr;
51 address->prefixlen = 16;
52 address->scope = RT_SCOPE_LINK;
53
db2df898 54 address_remove(address, link, &link_address_remove_handler);
5eef597e 55
db2df898 56 r = route_new(&route);
5eef597e 57 if (r < 0) {
6300502b 58 log_link_error_errno(link, r, "Could not allocate route: %m");
5eef597e
MP
59 return r;
60 }
61
62 route->family = AF_INET;
63 route->scope = RT_SCOPE_LINK;
db2df898 64 route->priority = IPV4LL_ROUTE_METRIC;
5eef597e 65
db2df898 66 route_remove(route, link, &link_route_remove_handler);
5eef597e 67
db2df898 68 link_check_ready(link);
5eef597e
MP
69
70 return 0;
71}
72
86f210e9 73static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
5eef597e
MP
74 _cleanup_link_unref_ Link *link = userdata;
75 int r;
76
77 assert(link);
78 assert(!link->ipv4ll_route);
79
86f210e9 80 r = sd_netlink_message_get_errno(m);
5eef597e 81 if (r < 0 && r != -EEXIST) {
6300502b 82 log_link_error_errno(link, r, "could not set ipv4ll route: %m");
5eef597e
MP
83 link_enter_failed(link);
84 }
85
86 link->ipv4ll_route = true;
87
88 if (link->ipv4ll_address == true)
db2df898 89 link_check_ready(link);
5eef597e
MP
90
91 return 1;
92}
93
86f210e9 94static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
5eef597e
MP
95 _cleanup_link_unref_ Link *link = userdata;
96 int r;
97
98 assert(link);
99 assert(!link->ipv4ll_address);
100
86f210e9 101 r = sd_netlink_message_get_errno(m);
5eef597e 102 if (r < 0 && r != -EEXIST) {
6300502b 103 log_link_error_errno(link, r, "could not set ipv4ll address: %m");
5eef597e 104 link_enter_failed(link);
f47781d8 105 } else if (r >= 0)
db2df898 106 manager_rtnl_process_address(rtnl, m, link->manager);
5eef597e
MP
107
108 link->ipv4ll_address = true;
109
110 if (link->ipv4ll_route == true)
db2df898 111 link_check_ready(link);
5eef597e
MP
112
113 return 1;
114}
115
116static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
117 _cleanup_address_free_ Address *ll_addr = NULL;
118 _cleanup_route_free_ Route *route = NULL;
119 struct in_addr address;
120 int r;
121
122 assert(ll);
123 assert(link);
124
125 r = sd_ipv4ll_get_address(ll, &address);
126 if (r == -ENOENT)
127 return 0;
128 else if (r < 0)
129 return r;
130
f47781d8 131 log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
5eef597e
MP
132 ADDRESS_FMT_VAL(address));
133
db2df898 134 r = address_new(&ll_addr);
5eef597e
MP
135 if (r < 0)
136 return r;
137
138 ll_addr->family = AF_INET;
139 ll_addr->in_addr.in = address;
140 ll_addr->prefixlen = 16;
141 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
142 ll_addr->scope = RT_SCOPE_LINK;
143
db2df898 144 r = address_configure(ll_addr, link, ipv4ll_address_handler, false);
5eef597e
MP
145 if (r < 0)
146 return r;
147
148 link->ipv4ll_address = false;
149
db2df898 150 r = route_new(&route);
5eef597e
MP
151 if (r < 0)
152 return r;
153
154 route->family = AF_INET;
155 route->scope = RT_SCOPE_LINK;
db2df898
MP
156 route->protocol = RTPROT_STATIC;
157 route->priority = IPV4LL_ROUTE_METRIC;
5eef597e
MP
158
159 r = route_configure(route, link, ipv4ll_route_handler);
160 if (r < 0)
161 return r;
162
163 link->ipv4ll_route = false;
164
165 return 0;
166}
167
168static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
169 Link *link = userdata;
170 int r;
171
172 assert(link);
173 assert(link->network);
174 assert(link->manager);
175
176 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
177 return;
178
179 switch(event) {
6300502b
MP
180 case SD_IPV4LL_EVENT_STOP:
181 case SD_IPV4LL_EVENT_CONFLICT:
5eef597e
MP
182 r = ipv4ll_address_lost(link);
183 if (r < 0) {
184 link_enter_failed(link);
185 return;
186 }
187 break;
6300502b 188 case SD_IPV4LL_EVENT_BIND:
5eef597e
MP
189 r = ipv4ll_address_claimed(ll, link);
190 if (r < 0) {
191 link_enter_failed(link);
192 return;
193 }
194 break;
195 default:
6300502b 196 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
5eef597e
MP
197 break;
198 }
199}
200
201int ipv4ll_configure(Link *link) {
db2df898 202 uint64_t seed;
5eef597e
MP
203 int r;
204
205 assert(link);
206 assert(link->network);
86f210e9 207 assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
5eef597e 208
db2df898
MP
209 if (!link->ipv4ll) {
210 r = sd_ipv4ll_new(&link->ipv4ll);
211 if (r < 0)
212 return r;
213 }
5eef597e
MP
214
215 if (link->udev_device) {
db2df898 216 r = net_get_unique_predictable_data(link->udev_device, &seed);
5eef597e 217 if (r >= 0) {
6300502b
MP
218 assert_cc(sizeof(unsigned) <= 8);
219
db2df898 220 r = sd_ipv4ll_set_address_seed(link->ipv4ll, (unsigned)seed);
5eef597e
MP
221 if (r < 0)
222 return r;
223 }
224 }
225
226 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
227 if (r < 0)
228 return r;
229
230 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
231 if (r < 0)
232 return r;
233
234 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
235 if (r < 0)
236 return r;
237
238 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
239 if (r < 0)
240 return r;
241
242 return 0;
243}