/src/systemd/src/network/networkd-serialize.c
Line | Count | Source |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | |
3 | | #include "af-list.h" |
4 | | #include "alloc-util.h" |
5 | | #include "daemon-util.h" |
6 | | #include "errno-util.h" |
7 | | #include "fd-util.h" |
8 | | #include "hashmap.h" |
9 | | #include "iovec-util.h" |
10 | | #include "json-util.h" |
11 | | #include "memfd-util.h" |
12 | | #include "networkd-address.h" |
13 | | #include "networkd-json.h" |
14 | | #include "networkd-link.h" |
15 | | #include "networkd-manager.h" |
16 | | #include "networkd-nexthop.h" |
17 | | #include "networkd-route.h" |
18 | | #include "networkd-serialize.h" |
19 | | #include "string-util.h" |
20 | | |
21 | | int manager_serialize(Manager *manager) { |
22 | | _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *array = NULL; |
23 | | int r; |
24 | | |
25 | | assert(manager); |
26 | | |
27 | | log_debug("Serializing..."); |
28 | | |
29 | | Link *link; |
30 | | HASHMAP_FOREACH(link, manager->links_by_index) { |
31 | | _cleanup_(sd_json_variant_unrefp) sd_json_variant *e = NULL; |
32 | | |
33 | | /* ignore unmanaged, failed, or removed interfaces. */ |
34 | | if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) |
35 | | continue; |
36 | | |
37 | | r = sd_json_buildo( |
38 | | &e, |
39 | | SD_JSON_BUILD_PAIR_INTEGER("Index", link->ifindex)); |
40 | | if (r < 0) |
41 | | return r; |
42 | | |
43 | | r = addresses_append_json(link, /* serializing= */ true, &e); |
44 | | if (r < 0) |
45 | | return r; |
46 | | |
47 | | r = sd_json_variant_append_array(&array, e); |
48 | | if (r < 0) |
49 | | return r; |
50 | | } |
51 | | |
52 | | r = json_variant_set_field_non_null(&v, "Interfaces", array); |
53 | | if (r < 0) |
54 | | return r; |
55 | | |
56 | | r = nexthops_append_json(manager, /* ifindex= */ -1, &v); |
57 | | if (r < 0) |
58 | | return r; |
59 | | |
60 | | r = routes_append_json(manager, /* ifindex= */ -1, &v); |
61 | | if (r < 0) |
62 | | return r; |
63 | | |
64 | | if (!v) { |
65 | | log_debug("There is nothing to serialize."); |
66 | | (void) notify_remove_fd_warn("manager-serialization"); |
67 | | return 0; |
68 | | } |
69 | | |
70 | | _cleanup_free_ char *dump = NULL; |
71 | | r = sd_json_variant_format(v, /* flags= */ 0, &dump); |
72 | | if (r < 0) |
73 | | return r; |
74 | | |
75 | | _cleanup_close_ int fd = -EBADF; |
76 | | fd = memfd_new_and_seal_string("serialization", dump); |
77 | | if (fd < 0) |
78 | | return fd; |
79 | | |
80 | | r = notify_push_fd(fd, "manager-serialization"); |
81 | | if (r < 0) |
82 | | return log_debug_errno(r, "Failed to push serialization file descriptor: %m"); |
83 | | |
84 | | log_debug("Serialization completed."); |
85 | | return 0; |
86 | | } |
87 | | |
88 | 0 | int manager_set_serialization_fd(Manager *manager, int fd, const char *name) { |
89 | 0 | assert(manager); |
90 | 0 | assert(fd >= 0); |
91 | 0 | assert(name); |
92 | |
|
93 | 0 | if (!startswith(name, "manager-serialization")) |
94 | 0 | return -EINVAL; |
95 | | |
96 | 0 | if (manager->serialization_fd >= 0) |
97 | 0 | return -EEXIST; |
98 | | |
99 | 0 | manager->serialization_fd = fd; |
100 | 0 | return 0; |
101 | 0 | } |
102 | | |
103 | 0 | static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_network_config_source, NetworkConfigSource, network_config_source_from_string); |
104 | | |
105 | | typedef struct AddressParam { |
106 | | int family; |
107 | | struct iovec address; |
108 | | struct iovec peer; |
109 | | uint8_t prefixlen; |
110 | | NetworkConfigSource source; |
111 | | struct iovec provider; |
112 | | } AddressParam; |
113 | | |
114 | 0 | static void address_param_done(AddressParam *p) { |
115 | 0 | assert(p); |
116 | |
|
117 | 0 | iovec_done(&p->address); |
118 | 0 | iovec_done(&p->peer); |
119 | 0 | iovec_done(&p->provider); |
120 | 0 | } |
121 | | |
122 | 0 | static int link_deserialize_address(Link *link, sd_json_variant *v) { |
123 | 0 | static const sd_json_dispatch_field dispatch_table[] = { |
124 | 0 | { "Family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(AddressParam, family), SD_JSON_MANDATORY }, |
125 | 0 | { "Address", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(AddressParam, address), SD_JSON_MANDATORY }, |
126 | 0 | { "Peer", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(AddressParam, peer), 0 }, |
127 | 0 | { "PrefixLength", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(AddressParam, prefixlen), SD_JSON_MANDATORY }, |
128 | 0 | { "ConfigSource", SD_JSON_VARIANT_STRING, json_dispatch_network_config_source, offsetof(AddressParam, source), SD_JSON_MANDATORY }, |
129 | 0 | { "ConfigProvider", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(AddressParam, provider), 0 }, |
130 | 0 | {}, |
131 | 0 | }; |
132 | |
|
133 | 0 | int r; |
134 | |
|
135 | 0 | assert(link); |
136 | 0 | assert(v); |
137 | |
|
138 | 0 | _cleanup_(address_param_done) AddressParam p = {}; |
139 | 0 | r = sd_json_dispatch(v, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p); |
140 | 0 | if (r < 0) |
141 | 0 | return log_link_debug_errno(link, r, "Failed to dispatch address from json variant: %m"); |
142 | | |
143 | 0 | if (p.address.iov_len != FAMILY_ADDRESS_SIZE(p.family)) |
144 | 0 | return log_link_debug_errno(link, SYNTHETIC_ERRNO(EINVAL), |
145 | 0 | "Dispatched address size (%zu) is incompatible with the family (%s).", |
146 | 0 | p.address.iov_len, af_to_ipv4_ipv6(p.family)); |
147 | | |
148 | 0 | if (p.peer.iov_len != 0 && p.peer.iov_len != FAMILY_ADDRESS_SIZE(p.family)) |
149 | 0 | return log_link_debug_errno(link, SYNTHETIC_ERRNO(EINVAL), |
150 | 0 | "Dispatched peer address size (%zu) is incompatible with the family (%s).", |
151 | 0 | p.peer.iov_len, af_to_ipv4_ipv6(p.family)); |
152 | | |
153 | 0 | if (p.provider.iov_len != 0 && p.provider.iov_len != FAMILY_ADDRESS_SIZE(p.family)) |
154 | 0 | return log_link_debug_errno(link, SYNTHETIC_ERRNO(EINVAL), |
155 | 0 | "Dispatched provider address size (%zu) is incompatible with the family (%s).", |
156 | 0 | p.provider.iov_len, af_to_ipv4_ipv6(p.family)); |
157 | | |
158 | 0 | Address tmp = { |
159 | 0 | .family = p.family, |
160 | 0 | .prefixlen = p.prefixlen, |
161 | 0 | }; |
162 | |
|
163 | 0 | memcpy_safe(&tmp.in_addr, p.address.iov_base, p.address.iov_len); |
164 | 0 | memcpy_safe(&tmp.in_addr_peer, p.peer.iov_base, p.peer.iov_len); |
165 | |
|
166 | 0 | Address *address; |
167 | 0 | r = address_get(link, &tmp, &address); |
168 | 0 | if (r < 0) { |
169 | 0 | log_link_debug_errno(link, r, "Cannot find deserialized address %s: %m", |
170 | 0 | IN_ADDR_PREFIX_TO_STRING(tmp.family, &tmp.in_addr, tmp.prefixlen)); |
171 | 0 | return 0; /* Already removed? */ |
172 | 0 | } |
173 | | |
174 | 0 | if (address->source != NETWORK_CONFIG_SOURCE_FOREIGN) |
175 | 0 | return 0; /* Huh?? Already deserialized?? */ |
176 | | |
177 | 0 | address->source = p.source; |
178 | 0 | memcpy_safe(&address->provider, p.provider.iov_base, p.provider.iov_len); |
179 | |
|
180 | 0 | log_address_debug(address, "Deserialized", link); |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | 0 | static int manager_deserialize_link(Manager *manager, sd_json_variant *v) { |
185 | 0 | typedef struct LinkParam { |
186 | 0 | int ifindex; |
187 | 0 | sd_json_variant *addresses; |
188 | 0 | } LinkParam; |
189 | |
|
190 | 0 | static const sd_json_dispatch_field dispatch_table[] = { |
191 | 0 | { "Index", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(LinkParam, ifindex), SD_JSON_MANDATORY | SD_JSON_REFUSE_NULL }, |
192 | 0 | { "Addresses", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant_noref, offsetof(LinkParam, addresses), 0 }, |
193 | 0 | {}, |
194 | 0 | }; |
195 | |
|
196 | 0 | int r, ret = 0; |
197 | |
|
198 | 0 | assert(manager); |
199 | 0 | assert(v); |
200 | |
|
201 | 0 | LinkParam p = {}; |
202 | 0 | r = sd_json_dispatch(v, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p); |
203 | 0 | if (r < 0) |
204 | 0 | return log_debug_errno(r, "Failed to dispatch interface from json variant: %m"); |
205 | | |
206 | 0 | Link *link; |
207 | 0 | r = link_get_by_index(manager, p.ifindex, &link); |
208 | 0 | if (r < 0) { |
209 | 0 | log_debug_errno(r, "No interface with deserialized ifindex (%i) found: %m", p.ifindex); |
210 | 0 | return 0; /* Already removed? */ |
211 | 0 | } |
212 | | |
213 | 0 | sd_json_variant *i; |
214 | 0 | JSON_VARIANT_ARRAY_FOREACH(i, p.addresses) |
215 | 0 | RET_GATHER(ret, link_deserialize_address(link, i)); |
216 | |
|
217 | 0 | return ret; |
218 | 0 | } |
219 | | |
220 | | typedef struct NextHopParam { |
221 | | uint32_t id; |
222 | | int family; |
223 | | NetworkConfigSource source; |
224 | | struct iovec provider; |
225 | | } NextHopParam; |
226 | | |
227 | 0 | static void nexthop_param_done(NextHopParam *p) { |
228 | 0 | assert(p); |
229 | |
|
230 | 0 | iovec_done(&p->provider); |
231 | 0 | } |
232 | | |
233 | 0 | static int manager_deserialize_nexthop(Manager *manager, sd_json_variant *v) { |
234 | 0 | static const sd_json_dispatch_field dispatch_table[] = { |
235 | 0 | { "ID", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, offsetof(NextHopParam, id), SD_JSON_MANDATORY }, |
236 | 0 | { "Family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(NextHopParam, family), SD_JSON_MANDATORY }, |
237 | 0 | { "ConfigSource", SD_JSON_VARIANT_STRING, json_dispatch_network_config_source, offsetof(NextHopParam, source), SD_JSON_MANDATORY }, |
238 | 0 | { "ConfigProvider", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(NextHopParam, provider), 0 }, |
239 | 0 | {}, |
240 | 0 | }; |
241 | |
|
242 | 0 | int r; |
243 | |
|
244 | 0 | assert(manager); |
245 | 0 | assert(v); |
246 | |
|
247 | 0 | _cleanup_(nexthop_param_done) NextHopParam p = {}; |
248 | 0 | r = sd_json_dispatch(v, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p); |
249 | 0 | if (r < 0) |
250 | 0 | return log_debug_errno(r, "Failed to dispatch nexthop from json variant: %m"); |
251 | | |
252 | 0 | if (p.id == 0) |
253 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Dispatched nexthop ID is zero."); |
254 | | |
255 | 0 | if (p.provider.iov_len != 0 && p.provider.iov_len != FAMILY_ADDRESS_SIZE(p.family)) |
256 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
257 | 0 | "Dispatched provider address size (%zu) is incompatible with the family (%s).", |
258 | 0 | p.provider.iov_len, af_to_ipv4_ipv6(p.family)); |
259 | | |
260 | 0 | NextHop *nexthop; |
261 | 0 | r = nexthop_get_by_id(manager, p.id, &nexthop); |
262 | 0 | if (r < 0) { |
263 | 0 | log_debug_errno(r, "Cannot find deserialized nexthop (ID=%"PRIu32"): %m", p.id); |
264 | 0 | return 0; /* Already removed? */ |
265 | 0 | } |
266 | | |
267 | 0 | if (nexthop->source != NETWORK_CONFIG_SOURCE_FOREIGN) |
268 | 0 | return 0; /* Huh?? Already deserialized?? */ |
269 | | |
270 | 0 | nexthop->source = p.source; |
271 | 0 | memcpy_safe(&nexthop->provider, p.provider.iov_base, p.provider.iov_len); |
272 | |
|
273 | 0 | log_nexthop_debug(nexthop, "Deserialized", manager); |
274 | 0 | return 0; |
275 | 0 | } |
276 | | |
277 | | typedef struct RouteParam { |
278 | | Route route; |
279 | | |
280 | | struct iovec dst; |
281 | | struct iovec src; |
282 | | struct iovec prefsrc; |
283 | | struct iovec gw; |
284 | | struct iovec metrics; |
285 | | struct iovec provider; |
286 | | } RouteParam; |
287 | | |
288 | 0 | static void route_param_done(RouteParam *p) { |
289 | 0 | assert(p); |
290 | |
|
291 | 0 | free(p->route.metric.metrics); |
292 | |
|
293 | 0 | iovec_done(&p->dst); |
294 | 0 | iovec_done(&p->src); |
295 | 0 | iovec_done(&p->prefsrc); |
296 | 0 | iovec_done(&p->gw); |
297 | 0 | iovec_done(&p->metrics); |
298 | 0 | iovec_done(&p->provider); |
299 | 0 | } |
300 | | |
301 | 0 | static int manager_deserialize_route(Manager *manager, sd_json_variant *v) { |
302 | 0 | static const sd_json_dispatch_field dispatch_table[] = { |
303 | | /* rtmsg header */ |
304 | 0 | { "Family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(RouteParam, route.family), SD_JSON_MANDATORY }, |
305 | 0 | { "DestinationPrefixLength", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(RouteParam, route.dst_prefixlen), SD_JSON_MANDATORY }, |
306 | 0 | { "SourcePrefixLength", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(RouteParam, route.src_prefixlen), 0 }, |
307 | 0 | { "TOS", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(RouteParam, route.tos), SD_JSON_MANDATORY }, |
308 | 0 | { "Protocol", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(RouteParam, route.protocol), SD_JSON_MANDATORY }, |
309 | 0 | { "Scope", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(RouteParam, route.scope), SD_JSON_MANDATORY }, |
310 | 0 | { "Type", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint8, offsetof(RouteParam, route.type), SD_JSON_MANDATORY }, |
311 | 0 | { "Flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, offsetof(RouteParam, route.flags), SD_JSON_MANDATORY }, |
312 | | /* attributes */ |
313 | 0 | { "Destination", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(RouteParam, dst), SD_JSON_MANDATORY }, |
314 | 0 | { "Source", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(RouteParam, src), 0 }, |
315 | 0 | { "Priority", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, offsetof(RouteParam, route.priority), SD_JSON_MANDATORY }, |
316 | 0 | { "PreferredSource", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(RouteParam, prefsrc), 0 }, |
317 | 0 | { "Table", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, offsetof(RouteParam, route.table), SD_JSON_MANDATORY }, |
318 | | /* nexthops */ |
319 | 0 | { "Gateway", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(RouteParam, gw), 0 }, |
320 | 0 | { "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(RouteParam, route.nexthop.ifindex), SD_JSON_MANDATORY | SD_JSON_RELAX }, |
321 | 0 | { "NextHopID", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, offsetof(RouteParam, route.nexthop_id), 0 }, |
322 | | /* metrics */ |
323 | 0 | { "Metrics", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(RouteParam, metrics), 0 }, |
324 | 0 | { "TCPCongestionControlAlgorithm", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(RouteParam, route.metric.tcp_congestion_control_algo), 0 }, |
325 | | /* config */ |
326 | 0 | { "ConfigSource", SD_JSON_VARIANT_STRING, json_dispatch_network_config_source, offsetof(RouteParam, route.source), SD_JSON_MANDATORY }, |
327 | 0 | { "ConfigProvider", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(RouteParam, provider), 0 }, |
328 | 0 | {}, |
329 | 0 | }; |
330 | |
|
331 | 0 | int r; |
332 | |
|
333 | 0 | assert(manager); |
334 | 0 | assert(v); |
335 | |
|
336 | 0 | _cleanup_(route_param_done) RouteParam p = {}; |
337 | 0 | r = sd_json_dispatch(v, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p); |
338 | 0 | if (r < 0) |
339 | 0 | return log_debug_errno(r, "Failed to dispatch route from json variant: %m"); |
340 | | |
341 | 0 | if (p.dst.iov_len != FAMILY_ADDRESS_SIZE(p.route.family)) |
342 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
343 | 0 | "Dispatched destination address size (%zu) is incompatible with the family (%s).", |
344 | 0 | p.dst.iov_len, af_to_ipv4_ipv6(p.route.family)); |
345 | | |
346 | 0 | if (p.src.iov_len != 0 && p.src.iov_len != FAMILY_ADDRESS_SIZE(p.route.family)) |
347 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
348 | 0 | "Dispatched source address size (%zu) is incompatible with the family (%s).", |
349 | 0 | p.src.iov_len, af_to_ipv4_ipv6(p.route.family)); |
350 | | |
351 | 0 | if (p.prefsrc.iov_len != 0 && p.prefsrc.iov_len != FAMILY_ADDRESS_SIZE(p.route.family)) |
352 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
353 | 0 | "Dispatched preferred source address size (%zu) is incompatible with the family (%s).", |
354 | 0 | p.prefsrc.iov_len, af_to_ipv4_ipv6(p.route.family)); |
355 | | |
356 | 0 | switch (p.gw.iov_len) { |
357 | 0 | case 0: |
358 | 0 | p.route.nexthop.family = AF_UNSPEC; |
359 | 0 | break; |
360 | 0 | case sizeof(struct in_addr): |
361 | 0 | p.route.nexthop.family = AF_INET; |
362 | 0 | break; |
363 | 0 | case sizeof(struct in6_addr): |
364 | 0 | p.route.nexthop.family = AF_INET6; |
365 | 0 | break; |
366 | 0 | default: |
367 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
368 | 0 | "Dispatched gateway address size (%zu) is invalid.", |
369 | 0 | p.prefsrc.iov_len); |
370 | 0 | } |
371 | | |
372 | 0 | if (p.metrics.iov_len % sizeof(uint32_t) != 0) |
373 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
374 | 0 | "Dispatched route metric size (%zu) is invalid.", |
375 | 0 | p.metrics.iov_len); |
376 | | |
377 | 0 | if (p.provider.iov_len != 0 && p.provider.iov_len != FAMILY_ADDRESS_SIZE(p.route.family)) |
378 | 0 | return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), |
379 | 0 | "Dispatched provider address size (%zu) is incompatible with the family (%s).", |
380 | 0 | p.provider.iov_len, af_to_ipv4_ipv6(p.route.family)); |
381 | | |
382 | 0 | memcpy_safe(&p.route.dst, p.dst.iov_base, p.dst.iov_len); |
383 | 0 | memcpy_safe(&p.route.src, p.src.iov_base, p.src.iov_len); |
384 | 0 | memcpy_safe(&p.route.prefsrc, p.prefsrc.iov_base, p.prefsrc.iov_len); |
385 | 0 | memcpy_safe(&p.route.nexthop.gw, p.gw.iov_base, p.gw.iov_len); |
386 | |
|
387 | 0 | p.route.metric.n_metrics = p.metrics.iov_len / sizeof(uint32_t); |
388 | 0 | p.route.metric.metrics = new(uint32_t, p.route.metric.n_metrics); |
389 | 0 | if (!p.route.metric.metrics) |
390 | 0 | return log_oom_debug(); |
391 | | |
392 | 0 | memcpy_safe(p.route.metric.metrics, p.metrics.iov_base, p.metrics.iov_len); |
393 | |
|
394 | 0 | Route *route; |
395 | 0 | r = route_get(manager, &p.route, &route); |
396 | 0 | if (r < 0) { |
397 | 0 | log_route_debug(&p.route, "Cannot find deserialized", manager); |
398 | 0 | return 0; /* Already removed? */ |
399 | 0 | } |
400 | | |
401 | 0 | if (route->source != NETWORK_CONFIG_SOURCE_FOREIGN) |
402 | 0 | return 0; /* Huh?? Already deserialized?? */ |
403 | | |
404 | 0 | route->source = p.route.source; |
405 | 0 | memcpy_safe(&route->provider, p.provider.iov_base, p.provider.iov_len); |
406 | |
|
407 | 0 | log_route_debug(route, "Deserialized", manager); |
408 | 0 | return 0; |
409 | 0 | } |
410 | | |
411 | 0 | int manager_deserialize(Manager *manager) { |
412 | 0 | int r, ret = 0; |
413 | |
|
414 | 0 | assert(manager); |
415 | |
|
416 | 0 | _cleanup_close_ int fd = TAKE_FD(manager->serialization_fd); |
417 | 0 | if (fd < 0) |
418 | 0 | return 0; |
419 | | |
420 | 0 | log_debug("Deserializing..."); |
421 | |
|
422 | 0 | _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; |
423 | 0 | unsigned err_line = 0, err_column = 0; |
424 | 0 | r = sd_json_parse_fd( |
425 | 0 | /* path= */ NULL, |
426 | 0 | TAKE_FD(fd), |
427 | 0 | SD_JSON_PARSE_DONATE_FD, |
428 | 0 | &v, |
429 | 0 | &err_line, |
430 | 0 | &err_column); |
431 | 0 | if (r < 0) |
432 | 0 | return log_debug_errno(r, "Failed to parse json (line=%u, column=%u): %m", err_line, err_column); |
433 | | |
434 | 0 | sd_json_variant *i; |
435 | 0 | JSON_VARIANT_ARRAY_FOREACH(i, sd_json_variant_by_key(v, "Interfaces")) |
436 | 0 | RET_GATHER(ret, manager_deserialize_link(manager, i)); |
437 | |
|
438 | 0 | JSON_VARIANT_ARRAY_FOREACH(i, sd_json_variant_by_key(v, "NextHops")) |
439 | 0 | RET_GATHER(ret, manager_deserialize_nexthop(manager, i)); |
440 | |
|
441 | 0 | JSON_VARIANT_ARRAY_FOREACH(i, sd_json_variant_by_key(v, "Routes")) |
442 | 0 | RET_GATHER(ret, manager_deserialize_route(manager, i)); |
443 | |
|
444 | 0 | log_debug("Deserialization completed."); |
445 | 0 | return ret; |
446 | 0 | } |