1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/nexthop.h>
5 #include "dhcp-server-internal.h"
6 #include "dhcp6-lease-internal.h"
7 #include "dns-domain.h"
8 #include "ip-protocol-list.h"
9 #include "netif-util.h"
10 #include "networkd-address.h"
11 #include "networkd-dhcp-common.h"
12 #include "networkd-dhcp-prefix-delegation.h"
13 #include "networkd-json.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "networkd-neighbor.h"
17 #include "networkd-nexthop.h"
18 #include "networkd-network.h"
19 #include "networkd-route-util.h"
20 #include "networkd-route.h"
21 #include "networkd-routing-policy-rule.h"
22 #include "sort-util.h"
23 #include "user-util.h"
24 #include "wifi-util.h"
26 static int json_append_one(JsonVariant
**v
, const char *name
, JsonVariant
*w
) {
30 return json_variant_merge_objectb(v
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_VARIANT_NON_NULL(name
, w
)));
33 static int address_build_json(Address
*address
, JsonVariant
**ret
) {
34 _cleanup_free_
char *scope
= NULL
, *flags
= NULL
, *state
= NULL
;
40 r
= route_scope_to_string_alloc(address
->scope
, &scope
);
44 r
= address_flags_to_string_alloc(address
->flags
, address
->family
, &flags
);
48 r
= network_config_state_to_string_alloc(address
->state
, &state
);
52 return json_build(ret
, JSON_BUILD_OBJECT(
53 JSON_BUILD_PAIR_INTEGER("Family", address
->family
),
54 JSON_BUILD_PAIR_IN_ADDR("Address", &address
->in_addr
, address
->family
),
55 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Peer", &address
->in_addr_peer
, address
->family
),
56 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Broadcast", &address
->broadcast
),
57 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", address
->prefixlen
),
58 JSON_BUILD_PAIR_UNSIGNED("Scope", address
->scope
),
59 JSON_BUILD_PAIR_STRING("ScopeString", scope
),
60 JSON_BUILD_PAIR_UNSIGNED("Flags", address
->flags
),
61 JSON_BUILD_PAIR_STRING("FlagsString", flags
),
62 JSON_BUILD_PAIR_STRING_NON_EMPTY("Label", address
->label
),
63 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUSec", address
->lifetime_preferred_usec
),
64 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUsec", address
->lifetime_preferred_usec
), /* for backward compat */
65 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUSec", address
->lifetime_valid_usec
),
66 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUsec", address
->lifetime_valid_usec
), /* for backward compat */
67 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(address
->source
)),
68 JSON_BUILD_PAIR_STRING("ConfigState", state
),
69 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &address
->provider
, address
->family
)));
72 static int addresses_append_json(Set
*addresses
, JsonVariant
**v
) {
73 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
79 SET_FOREACH(address
, addresses
) {
80 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
82 r
= address_build_json(address
, &e
);
86 r
= json_variant_append_array(&array
, e
);
91 return json_append_one(v
, "Addresses", array
);
94 static int neighbor_build_json(Neighbor
*n
, JsonVariant
**ret
) {
95 _cleanup_free_
char *state
= NULL
;
101 r
= network_config_state_to_string_alloc(n
->state
, &state
);
105 return json_build(ret
, JSON_BUILD_OBJECT(
106 JSON_BUILD_PAIR_INTEGER("Family", n
->family
),
107 JSON_BUILD_PAIR_IN_ADDR("Destination", &n
->in_addr
, n
->family
),
108 JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n
->ll_addr
),
109 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n
->source
)),
110 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
113 static int neighbors_append_json(Set
*neighbors
, JsonVariant
**v
) {
114 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
120 SET_FOREACH(neighbor
, neighbors
) {
121 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
123 r
= neighbor_build_json(neighbor
, &e
);
127 r
= json_variant_append_array(&array
, e
);
132 return json_append_one(v
, "Neighbors", array
);
135 static int nexthop_group_build_json(NextHop
*nexthop
, JsonVariant
**ret
) {
136 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
137 struct nexthop_grp
*g
;
143 HASHMAP_FOREACH(g
, nexthop
->group
) {
144 r
= json_variant_append_arrayb(
147 JSON_BUILD_PAIR_UNSIGNED("ID", g
->id
),
148 JSON_BUILD_PAIR_UNSIGNED("Weight", g
->weight
+1)));
153 *ret
= TAKE_PTR(array
);
157 static int nexthop_build_json(NextHop
*n
, JsonVariant
**ret
) {
158 _cleanup_(json_variant_unrefp
) JsonVariant
*group
= NULL
;
159 _cleanup_free_
char *flags
= NULL
, *protocol
= NULL
, *state
= NULL
;
165 r
= route_flags_to_string_alloc(n
->flags
, &flags
);
169 r
= route_protocol_to_string_alloc(n
->protocol
, &protocol
);
173 r
= network_config_state_to_string_alloc(n
->state
, &state
);
177 r
= nexthop_group_build_json(n
, &group
);
181 return json_build(ret
, JSON_BUILD_OBJECT(
182 JSON_BUILD_PAIR_UNSIGNED("ID", n
->id
),
183 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n
->gw
, n
->family
),
184 JSON_BUILD_PAIR_UNSIGNED("Flags", n
->flags
),
185 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags
)),
186 JSON_BUILD_PAIR_UNSIGNED("Protocol", n
->protocol
),
187 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
188 JSON_BUILD_PAIR_BOOLEAN("Blackhole", n
->blackhole
),
189 JSON_BUILD_PAIR_VARIANT_NON_NULL("Group", group
),
190 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n
->source
)),
191 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
194 static int nexthops_append_json(Set
*nexthops
, JsonVariant
**v
) {
195 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
201 SET_FOREACH(nexthop
, nexthops
) {
202 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
204 r
= nexthop_build_json(nexthop
, &e
);
208 r
= json_variant_append_array(&array
, e
);
213 return json_append_one(v
, "NextHops", array
);
216 static int route_build_json(Route
*route
, JsonVariant
**ret
) {
217 _cleanup_free_
char *scope
= NULL
, *protocol
= NULL
, *table
= NULL
, *flags
= NULL
, *state
= NULL
;
224 manager
= route
->link
? route
->link
->manager
: route
->manager
;
228 r
= route_scope_to_string_alloc(route
->scope
, &scope
);
232 r
= route_protocol_to_string_alloc(route
->protocol
, &protocol
);
236 r
= manager_get_route_table_to_string(manager
, route
->table
, /* append_num = */ false, &table
);
240 r
= route_flags_to_string_alloc(route
->flags
, &flags
);
244 r
= network_config_state_to_string_alloc(route
->state
, &state
);
248 return json_build(ret
, JSON_BUILD_OBJECT(
249 JSON_BUILD_PAIR_INTEGER("Family", route
->family
),
250 JSON_BUILD_PAIR_IN_ADDR("Destination", &route
->dst
, route
->family
),
251 JSON_BUILD_PAIR_UNSIGNED("DestinationPrefixLength", route
->dst_prefixlen
),
252 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &route
->gw
, route
->gw_family
),
253 JSON_BUILD_PAIR_CONDITION(route
->src_prefixlen
> 0,
254 "Source", JSON_BUILD_IN_ADDR(&route
->src
, route
->family
)),
255 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("SourcePrefixLength", route
->src_prefixlen
),
256 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("PreferredSource", &route
->prefsrc
, route
->family
),
257 JSON_BUILD_PAIR_UNSIGNED("Scope", route
->scope
),
258 JSON_BUILD_PAIR_STRING("ScopeString", scope
),
259 JSON_BUILD_PAIR_UNSIGNED("Protocol", route
->protocol
),
260 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
261 JSON_BUILD_PAIR_UNSIGNED("Type", route
->type
),
262 JSON_BUILD_PAIR_STRING("TypeString", route_type_to_string(route
->type
)),
263 JSON_BUILD_PAIR_UNSIGNED("Priority", route
->priority
),
264 JSON_BUILD_PAIR_UNSIGNED("Table", route
->table
),
265 JSON_BUILD_PAIR_STRING("TableString", table
),
266 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route
->mtu
),
267 JSON_BUILD_PAIR_UNSIGNED("Preference", route
->pref
),
268 JSON_BUILD_PAIR_UNSIGNED("Flags", route
->flags
),
269 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags
)),
270 JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", route
->lifetime_usec
),
271 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(route
->source
)),
272 JSON_BUILD_PAIR_STRING("ConfigState", state
),
273 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &route
->provider
, route
->family
)));
276 static int routes_append_json(Set
*routes
, JsonVariant
**v
) {
277 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
283 SET_FOREACH(route
, routes
) {
284 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
286 r
= route_build_json(route
, &e
);
290 r
= json_variant_append_array(&array
, e
);
295 return json_append_one(v
, "Routes", array
);
298 static int routing_policy_rule_build_json(RoutingPolicyRule
*rule
, JsonVariant
**ret
) {
299 _cleanup_free_
char *table
= NULL
, *protocol
= NULL
, *state
= NULL
;
303 assert(rule
->manager
);
306 r
= manager_get_route_table_to_string(rule
->manager
, rule
->table
, /* append_num = */ false, &table
);
307 if (r
< 0 && r
!= -EINVAL
)
310 r
= route_protocol_to_string_alloc(rule
->protocol
, &protocol
);
314 r
= network_config_state_to_string_alloc(rule
->state
, &state
);
318 return json_build(ret
, JSON_BUILD_OBJECT(
319 JSON_BUILD_PAIR_INTEGER("Family", rule
->family
),
320 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("FromPrefix", &rule
->from
, rule
->family
),
321 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule
->family
, &rule
->from
),
322 "FromPrefixLength", JSON_BUILD_UNSIGNED(rule
->from_prefixlen
)),
323 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ToPrefix", &rule
->to
, rule
->family
),
324 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule
->family
, &rule
->to
),
325 "ToPrefixLength", JSON_BUILD_UNSIGNED(rule
->to_prefixlen
)),
326 JSON_BUILD_PAIR_UNSIGNED("Protocol", rule
->protocol
),
327 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
328 JSON_BUILD_PAIR_UNSIGNED("TOS", rule
->tos
),
329 JSON_BUILD_PAIR_UNSIGNED("Type", rule
->type
),
330 JSON_BUILD_PAIR_STRING("TypeString", fr_act_type_full_to_string(rule
->type
)),
331 JSON_BUILD_PAIR_UNSIGNED("IPProtocol", rule
->ipproto
),
332 JSON_BUILD_PAIR_STRING("IPProtocolString", ip_protocol_to_name(rule
->ipproto
)),
333 JSON_BUILD_PAIR_UNSIGNED("Priority", rule
->priority
),
334 JSON_BUILD_PAIR_UNSIGNED("FirewallMark", rule
->fwmark
),
335 JSON_BUILD_PAIR_UNSIGNED("FirewallMask", rule
->fwmask
),
336 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Table", rule
->table
),
337 JSON_BUILD_PAIR_STRING_NON_EMPTY("TableString", table
),
338 JSON_BUILD_PAIR_BOOLEAN("Invert", rule
->invert_rule
),
339 JSON_BUILD_PAIR_CONDITION(rule
->suppress_prefixlen
>= 0,
340 "SuppressPrefixLength", JSON_BUILD_UNSIGNED(rule
->suppress_prefixlen
)),
341 JSON_BUILD_PAIR_CONDITION(rule
->suppress_ifgroup
>= 0,
342 "SuppressInterfaceGroup", JSON_BUILD_UNSIGNED(rule
->suppress_ifgroup
)),
343 JSON_BUILD_PAIR_CONDITION(rule
->sport
.start
!= 0 || rule
->sport
.end
!= 0, "SourcePort",
344 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->sport
.start
), JSON_BUILD_UNSIGNED(rule
->sport
.end
))),
345 JSON_BUILD_PAIR_CONDITION(rule
->dport
.start
!= 0 || rule
->dport
.end
!= 0, "DestinationPort",
346 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->dport
.start
), JSON_BUILD_UNSIGNED(rule
->dport
.end
))),
347 JSON_BUILD_PAIR_CONDITION(rule
->uid_range
.start
!= UID_INVALID
&& rule
->uid_range
.end
!= UID_INVALID
, "User",
348 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->uid_range
.start
), JSON_BUILD_UNSIGNED(rule
->uid_range
.end
))),
349 JSON_BUILD_PAIR_STRING_NON_EMPTY("IncomingInterface", rule
->iif
),
350 JSON_BUILD_PAIR_STRING_NON_EMPTY("OutgoingInterface", rule
->oif
),
351 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(rule
->source
)),
352 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
355 static int routing_policy_rules_append_json(Set
*rules
, JsonVariant
**v
) {
356 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
357 RoutingPolicyRule
*rule
;
362 SET_FOREACH(rule
, rules
) {
363 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
365 r
= routing_policy_rule_build_json(rule
, &e
);
369 r
= json_variant_append_array(&array
, e
);
374 return json_append_one(v
, "RoutingPolicyRules", array
);
377 static int network_append_json(Network
*network
, JsonVariant
**v
) {
383 return json_variant_merge_objectb(
384 v
, JSON_BUILD_OBJECT(
385 JSON_BUILD_PAIR_STRING("NetworkFile", network
->filename
),
386 JSON_BUILD_PAIR_STRV("NetworkFileDropins", network
->dropins
),
387 JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network
->required_for_online
),
388 JSON_BUILD_PAIR("RequiredOperationalStateForOnline",
389 JSON_BUILD_ARRAY(JSON_BUILD_STRING(link_operstate_to_string(network
->required_operstate_for_online
.min
)),
390 JSON_BUILD_STRING(link_operstate_to_string(network
->required_operstate_for_online
.max
)))),
391 JSON_BUILD_PAIR_STRING("RequiredFamilyForOnline",
392 link_required_address_family_to_string(network
->required_family_for_online
)),
393 JSON_BUILD_PAIR_STRING("ActivationPolicy",
394 activation_policy_to_string(network
->activation_policy
))));
397 static int device_append_json(sd_device
*device
, JsonVariant
**v
) {
398 _cleanup_strv_free_
char **link_dropins
= NULL
;
399 const char *link
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *joined
;
407 (void) sd_device_get_property_value(device
, "ID_NET_LINK_FILE", &link
);
409 if (sd_device_get_property_value(device
, "ID_NET_LINK_FILE_DROPINS", &joined
) >= 0) {
410 r
= strv_split_full(&link_dropins
, joined
, ":", EXTRACT_CUNESCAPE
);
415 (void) sd_device_get_property_value(device
, "ID_PATH", &path
);
417 if (sd_device_get_property_value(device
, "ID_VENDOR_FROM_DATABASE", &vendor
) < 0)
418 (void) sd_device_get_property_value(device
, "ID_VENDOR", &vendor
);
420 if (sd_device_get_property_value(device
, "ID_MODEL_FROM_DATABASE", &model
) < 0)
421 (void) sd_device_get_property_value(device
, "ID_MODEL", &model
);
423 return json_variant_merge_objectb(
426 JSON_BUILD_PAIR_STRING_NON_EMPTY("LinkFile", link
),
427 JSON_BUILD_PAIR_STRV_NON_EMPTY("LinkFileDropins", link_dropins
),
428 JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", path
),
429 JSON_BUILD_PAIR_STRING_NON_EMPTY("Vendor", vendor
),
430 JSON_BUILD_PAIR_STRING_NON_EMPTY("Model", model
)));
433 static int dns_append_json_one(Link
*link
, const struct in_addr_full
*a
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
438 if (a
->ifindex
!= 0 && a
->ifindex
!= link
->ifindex
)
441 return json_variant_append_arrayb(
444 JSON_BUILD_PAIR_INTEGER("Family", a
->family
),
445 JSON_BUILD_PAIR_IN_ADDR("Address", &a
->address
, a
->family
),
446 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Port", a
->port
),
447 JSON_BUILD_PAIR_CONDITION(a
->ifindex
!= 0, "InterfaceIndex", JSON_BUILD_INTEGER(a
->ifindex
)),
448 JSON_BUILD_PAIR_STRING_NON_EMPTY("ServerName", a
->server_name
),
449 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
450 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, a
->family
)));
453 static int dns_append_json(Link
*link
, JsonVariant
**v
) {
454 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
463 if (link
->n_dns
!= UINT_MAX
)
464 for (unsigned i
= 0; i
< link
->n_dns
; i
++) {
465 r
= dns_append_json_one(link
, link
->dns
[i
], NETWORK_CONFIG_SOURCE_RUNTIME
, NULL
, &array
);
470 for (unsigned i
= 0; i
< link
->network
->n_dns
; i
++) {
471 r
= dns_append_json_one(link
, link
->network
->dns
[i
], NETWORK_CONFIG_SOURCE_STATIC
, NULL
, &array
);
476 if (link
->dhcp_lease
&& link
->network
->dhcp_use_dns
) {
477 const struct in_addr
*dns
;
478 union in_addr_union s
;
481 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
485 n_dns
= sd_dhcp_lease_get_dns(link
->dhcp_lease
, &dns
);
486 for (int i
= 0; i
< n_dns
; i
++) {
487 r
= dns_append_json_one(link
,
488 &(struct in_addr_full
) { .family
= AF_INET
, .address
.in
= dns
[i
], },
489 NETWORK_CONFIG_SOURCE_DHCP4
,
497 if (link
->dhcp6_lease
&& link
->network
->dhcp6_use_dns
) {
498 const struct in6_addr
*dns
;
499 union in_addr_union s
;
502 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
506 n_dns
= sd_dhcp6_lease_get_dns(link
->dhcp6_lease
, &dns
);
507 for (int i
= 0; i
< n_dns
; i
++) {
508 r
= dns_append_json_one(link
,
509 &(struct in_addr_full
) { .family
= AF_INET6
, .address
.in6
= dns
[i
], },
510 NETWORK_CONFIG_SOURCE_DHCP6
,
518 if (link
->network
->ipv6_accept_ra_use_dns
) {
521 SET_FOREACH(a
, link
->ndisc_rdnss
) {
522 r
= dns_append_json_one(link
,
523 &(struct in_addr_full
) { .family
= AF_INET6
, .address
.in6
= a
->address
, },
524 NETWORK_CONFIG_SOURCE_NDISC
,
525 &(union in_addr_union
) { .in6
= a
->router
},
533 return json_append_one(v
, "DNS", array
);
536 static int server_append_json_one_addr(int family
, const union in_addr_union
*a
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
537 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
540 assert(IN_SET(family
, AF_INET
, AF_INET6
));
544 r
= json_build(&v
, JSON_BUILD_OBJECT(
545 JSON_BUILD_PAIR_INTEGER("Family", family
),
546 JSON_BUILD_PAIR_IN_ADDR("Address", a
, family
),
547 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
548 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
552 return json_variant_append_array(array
, v
);
555 static int server_append_json_one_fqdn(int family
, const char *fqdn
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
556 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
559 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
563 r
= json_build(&v
, JSON_BUILD_OBJECT(
564 JSON_BUILD_PAIR_STRING("Server", fqdn
),
565 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
566 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
570 return json_variant_append_array(array
, v
);
573 static int server_append_json_one_string(const char *str
, NetworkConfigSource s
, JsonVariant
**array
) {
574 union in_addr_union a
;
579 if (in_addr_from_string_auto(str
, &family
, &a
) >= 0)
580 return server_append_json_one_addr(family
, &a
, s
, NULL
, array
);
582 return server_append_json_one_fqdn(AF_UNSPEC
, str
, s
, NULL
, array
);
585 static int ntp_append_json(Link
*link
, JsonVariant
**v
) {
586 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
595 STRV_FOREACH(p
, link
->ntp
?: link
->network
->ntp
) {
596 r
= server_append_json_one_string(*p
, NETWORK_CONFIG_SOURCE_RUNTIME
, &array
);
602 if (link
->dhcp_lease
&& link
->network
->dhcp_use_ntp
) {
603 const struct in_addr
*ntp
;
604 union in_addr_union s
;
607 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
611 n_ntp
= sd_dhcp_lease_get_ntp(link
->dhcp_lease
, &ntp
);
612 for (int i
= 0; i
< n_ntp
; i
++) {
613 r
= server_append_json_one_addr(AF_INET
,
614 &(union in_addr_union
) { .in
= ntp
[i
], },
615 NETWORK_CONFIG_SOURCE_DHCP4
,
623 if (link
->dhcp6_lease
&& link
->network
->dhcp6_use_ntp
) {
624 const struct in6_addr
*ntp_addr
;
625 union in_addr_union s
;
629 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
633 n_ntp
= sd_dhcp6_lease_get_ntp_addrs(link
->dhcp6_lease
, &ntp_addr
);
634 for (int i
= 0; i
< n_ntp
; i
++) {
635 r
= server_append_json_one_addr(AF_INET6
,
636 &(union in_addr_union
) { .in6
= ntp_addr
[i
], },
637 NETWORK_CONFIG_SOURCE_DHCP6
,
644 n_ntp
= sd_dhcp6_lease_get_ntp_fqdn(link
->dhcp6_lease
, &ntp_fqdn
);
645 for (int i
= 0; i
< n_ntp
; i
++) {
646 r
= server_append_json_one_fqdn(AF_INET6
,
648 NETWORK_CONFIG_SOURCE_DHCP6
,
657 return json_append_one(v
, "NTP", array
);
660 static int sip_append_json(Link
*link
, JsonVariant
**v
) {
661 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
662 const struct in_addr
*sip
;
663 union in_addr_union s
;
669 if (!link
->network
|| !link
->network
->dhcp_use_sip
|| !link
->dhcp_lease
)
672 n_sip
= sd_dhcp_lease_get_sip(link
->dhcp_lease
, &sip
);
676 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
680 for (int i
= 0; i
< n_sip
; i
++) {
681 r
= server_append_json_one_addr(AF_INET
,
682 &(union in_addr_union
) { .in
= sip
[i
], },
683 NETWORK_CONFIG_SOURCE_DHCP4
,
690 return json_append_one(v
, "SIP", array
);
693 static int domain_append_json(int family
, const char *domain
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
694 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
697 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
701 r
= json_build(&v
, JSON_BUILD_OBJECT(
702 JSON_BUILD_PAIR_STRING("Domain", domain
),
703 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
704 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
708 return json_variant_append_array(array
, v
);
711 static int domains_append_json(Link
*link
, bool is_route
, JsonVariant
**v
) {
712 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
713 OrderedSet
*link_domains
, *network_domains
;
714 DHCPUseDomains use_domains
;
715 union in_addr_union s
;
726 link_domains
= is_route
? link
->route_domains
: link
->search_domains
;
727 network_domains
= is_route
? link
->network
->route_domains
: link
->network
->search_domains
;
728 use_domains
= is_route
? DHCP_USE_DOMAINS_ROUTE
: DHCP_USE_DOMAINS_YES
;
730 ORDERED_SET_FOREACH(domain
, link_domains
?: network_domains
) {
731 r
= domain_append_json(AF_UNSPEC
, domain
,
732 link_domains
? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
,
739 if (link
->dhcp_lease
&&
740 link
->network
->dhcp_use_domains
== use_domains
) {
741 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
745 if (sd_dhcp_lease_get_domainname(link
->dhcp_lease
, &domain
) >= 0) {
746 r
= domain_append_json(AF_INET
, domain
, NETWORK_CONFIG_SOURCE_DHCP4
, &s
, &array
);
751 if (sd_dhcp_lease_get_search_domains(link
->dhcp_lease
, &domains
) >= 0)
752 STRV_FOREACH(p
, domains
) {
753 r
= domain_append_json(AF_INET
, *p
, NETWORK_CONFIG_SOURCE_DHCP4
, &s
, &array
);
759 if (link
->dhcp6_lease
&&
760 link
->network
->dhcp6_use_domains
== use_domains
) {
761 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
765 if (sd_dhcp6_lease_get_domains(link
->dhcp6_lease
, &domains
) >= 0)
766 STRV_FOREACH(p
, domains
) {
767 r
= domain_append_json(AF_INET6
, *p
, NETWORK_CONFIG_SOURCE_DHCP6
, &s
, &array
);
773 if (link
->network
->ipv6_accept_ra_use_domains
== use_domains
) {
776 SET_FOREACH(a
, link
->ndisc_dnssl
) {
777 r
= domain_append_json(AF_INET6
, NDISC_DNSSL_DOMAIN(a
), NETWORK_CONFIG_SOURCE_NDISC
,
778 &(union in_addr_union
) { .in6
= a
->router
},
786 return json_append_one(v
, is_route
? "RouteDomains" : "SearchDomains", array
);
789 static int nta_append_json(const char *nta
, NetworkConfigSource s
, JsonVariant
**array
) {
790 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
796 r
= json_build(&v
, JSON_BUILD_OBJECT(
797 JSON_BUILD_PAIR_STRING("DNSSECNegativeTrustAnchor", nta
),
798 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
))));
802 return json_variant_append_array(array
, v
);
805 static int ntas_append_json(Link
*link
, JsonVariant
**v
) {
806 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
816 SET_FOREACH(nta
, link
->dnssec_negative_trust_anchors
?: link
->network
->dnssec_negative_trust_anchors
) {
817 r
= nta_append_json(nta
,
818 link
->dnssec_negative_trust_anchors
? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
,
824 return json_append_one(v
, "DNSSECNegativeTrustAnchors", array
);
827 static int dns_misc_append_json(Link
*link
, JsonVariant
**v
) {
828 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
829 ResolveSupport resolve_support
;
830 NetworkConfigSource source
;
840 resolve_support
= link
->llmnr
>= 0 ? link
->llmnr
: link
->network
->llmnr
;
841 if (resolve_support
>= 0) {
842 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
844 source
= link
->llmnr
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
846 r
= json_build(&e
, JSON_BUILD_OBJECT(
847 JSON_BUILD_PAIR_STRING("LLMNR", resolve_support_to_string(resolve_support
)),
848 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
852 r
= json_variant_append_array(&array
, e
);
857 resolve_support
= link
->mdns
>= 0 ? link
->mdns
: link
->network
->mdns
;
858 if (resolve_support
>= 0) {
859 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
861 source
= link
->mdns
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
863 r
= json_build(&e
, JSON_BUILD_OBJECT(
864 JSON_BUILD_PAIR_STRING("MDNS", resolve_support_to_string(resolve_support
)),
865 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
869 r
= json_variant_append_array(&array
, e
);
874 t
= link
->dns_default_route
>= 0 ? link
->dns_default_route
: link
->network
->dns_default_route
;
876 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
878 source
= link
->dns_default_route
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
880 r
= json_build(&e
, JSON_BUILD_OBJECT(
881 JSON_BUILD_PAIR_BOOLEAN("DNSDefaultRoute", t
),
882 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
886 r
= json_variant_append_array(&array
, e
);
891 mode
= link
->dns_over_tls_mode
>= 0 ? link
->dns_over_tls_mode
: link
->network
->dns_over_tls_mode
;
893 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
895 source
= link
->dns_over_tls_mode
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
897 r
= json_build(&e
, JSON_BUILD_OBJECT(
898 JSON_BUILD_PAIR_STRING("DNSOverTLS", dns_over_tls_mode_to_string(mode
)),
899 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
903 r
= json_variant_append_array(&array
, e
);
908 return json_append_one(v
, "DNSSettings", array
);
911 static int captive_portal_append_json(Link
*link
, JsonVariant
**v
) {
912 const char *captive_portal
;
918 r
= link_get_captive_portal(link
, &captive_portal
);
922 return json_variant_merge_objectb(v
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_STRING("CaptivePortal", captive_portal
)));
925 static int pref64_append_json(Link
*link
, JsonVariant
**v
) {
926 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
, *w
= NULL
;
933 if (!link
->network
|| !link
->network
->ipv6_accept_ra_use_pref64
)
936 SET_FOREACH(i
, link
->ndisc_pref64
) {
937 r
= json_variant_append_arrayb(&array
,
939 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("Prefix", &i
->prefix
),
940 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", i
->prefix_len
),
941 JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", i
->lifetime_usec
),
942 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("ConfigProvider", &i
->router
)));
947 r
= json_append_one(&w
, "PREF64", array
);
951 return json_append_one(v
, "NDisc", w
);
954 static int dhcp_server_offered_leases_append_json(Link
*link
, JsonVariant
**v
) {
955 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
962 if (!link
->dhcp_server
)
965 HASHMAP_FOREACH(lease
, link
->dhcp_server
->bound_leases_by_client_id
) {
966 struct in_addr address
= { .s_addr
= lease
->address
};
968 r
= json_variant_append_arrayb(
971 JSON_BUILD_PAIR_BYTE_ARRAY(
973 lease
->client_id
.data
,
974 lease
->client_id
.length
),
975 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address
),
976 JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease
->hostname
),
977 JSON_BUILD_PAIR_FINITE_USEC(
978 "ExpirationUSec", lease
->expiration
)));
983 return json_append_one(v
, "Leases", array
);
986 static int dhcp_server_static_leases_append_json(Link
*link
, JsonVariant
**v
) {
987 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
994 if (!link
->dhcp_server
)
997 HASHMAP_FOREACH(lease
, link
->dhcp_server
->static_leases_by_client_id
) {
998 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
999 struct in_addr address
= { .s_addr
= lease
->address
};
1003 JSON_BUILD_PAIR_BYTE_ARRAY(
1005 lease
->client_id
.data
,
1006 lease
->client_id
.length
),
1007 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address
)));
1011 r
= json_variant_append_array(&array
, e
);
1016 return json_append_one(v
, "StaticLeases", array
);
1019 static int dhcp_server_append_json(Link
*link
, JsonVariant
**v
) {
1020 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1026 if (!link
->dhcp_server
)
1031 JSON_BUILD_PAIR_UNSIGNED("PoolOffset", link
->dhcp_server
->pool_offset
),
1032 JSON_BUILD_PAIR_UNSIGNED("PoolSize", link
->dhcp_server
->pool_size
)));
1036 r
= dhcp_server_offered_leases_append_json(link
, &w
);
1040 r
= dhcp_server_static_leases_append_json(link
, &w
);
1044 return json_append_one(v
, "DHCPServer", w
);
1047 static int dhcp6_client_lease_append_json(Link
*link
, JsonVariant
**v
) {
1048 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1049 uint64_t lease_timestamp_usec
;
1055 if (!link
->dhcp6_lease
)
1058 r
= sd_dhcp6_lease_get_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &lease_timestamp_usec
);
1062 r
= json_build(&w
, JSON_BUILD_OBJECT(
1063 JSON_BUILD_PAIR_FINITE_USEC("Timeout1USec",
1064 link
->dhcp6_lease
->lifetime_t1
+ lease_timestamp_usec
),
1065 JSON_BUILD_PAIR_FINITE_USEC("Timeout2USec",
1066 link
->dhcp6_lease
->lifetime_t2
+ lease_timestamp_usec
),
1067 JSON_BUILD_PAIR_FINITE_USEC("LeaseTimestampUSec",
1068 lease_timestamp_usec
)));
1072 return json_append_one(v
, "Lease", w
);
1075 static int dhcp6_client_pd_append_json(Link
*link
, JsonVariant
**v
) {
1076 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1077 struct in6_addr prefix
;
1078 uint32_t lifetime_preferred
, lifetime_valid
;
1080 uint64_t lease_timestamp_usec
;
1084 assert(link
->network
);
1087 if (!link
->network
->dhcp6_use_pd_prefix
|| !link
->dhcp6_lease
|| !dhcp6_lease_has_pd_prefix(link
->dhcp6_lease
))
1090 sd_dhcp6_lease_reset_pd_prefix_iter(link
->dhcp6_lease
);
1092 r
= sd_dhcp6_lease_get_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &lease_timestamp_usec
);
1096 while (sd_dhcp6_lease_get_pd(link
->dhcp6_lease
, &prefix
, &prefix_len
, &lifetime_preferred
, &lifetime_valid
) >= 0) {
1097 r
= json_variant_append_arrayb(&array
, JSON_BUILD_OBJECT(
1098 JSON_BUILD_PAIR_IN6_ADDR("Prefix", &prefix
),
1099 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", prefix_len
),
1100 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUSec",
1101 sec_to_usec(lifetime_preferred
, lease_timestamp_usec
)),
1102 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUSec",
1103 sec_to_usec(lifetime_valid
, lease_timestamp_usec
))));
1108 return json_append_one(v
, "Prefixes", array
);
1111 static int dhcp6_client_append_json(Link
*link
, JsonVariant
**v
) {
1112 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1118 if (!link
->dhcp6_client
)
1121 r
= dhcp6_client_lease_append_json(link
, &w
);
1125 r
= dhcp6_client_pd_append_json(link
, &w
);
1129 return json_append_one(v
, "DHCPv6Client", w
);
1132 static int dhcp_client_lease_append_json(Link
*link
, JsonVariant
**v
) {
1133 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1134 usec_t lease_timestamp_usec
, t1
, t2
;
1140 if (!link
->dhcp_client
|| !link
->dhcp_lease
)
1143 r
= sd_dhcp_lease_get_t1(link
->dhcp_lease
, &t1
);
1147 r
= sd_dhcp_lease_get_t2(link
->dhcp_lease
, &t2
);
1151 r
= sd_dhcp_client_get_lease_timestamp(link
->dhcp_client
, &lease_timestamp_usec
);
1155 r
= json_build(&w
, JSON_BUILD_OBJECT(
1156 JSON_BUILD_PAIR_FINITE_USEC("Timeout1USec",
1157 usec_add(t1
, lease_timestamp_usec
)),
1158 JSON_BUILD_PAIR_FINITE_USEC("Timeout2USec",
1159 usec_add(t2
, lease_timestamp_usec
)),
1160 JSON_BUILD_PAIR_FINITE_USEC("LeaseTimestampUSec", lease_timestamp_usec
)));
1164 return json_append_one(v
, "Lease", w
);
1167 static int dhcp_client_pd_append_json(Link
*link
, JsonVariant
**v
) {
1168 _cleanup_(json_variant_unrefp
) JsonVariant
*addresses
= NULL
, *array
= NULL
;
1169 uint8_t ipv4masklen
, sixrd_prefixlen
;
1170 struct in6_addr sixrd_prefix
;
1171 const struct in_addr
*br_addresses
;
1172 size_t n_br_addresses
= 0;
1176 assert(link
->network
);
1179 if (!link
->network
->dhcp_use_6rd
|| !link
->dhcp_lease
|| !dhcp4_lease_has_pd_prefix(link
->dhcp_lease
))
1182 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, &br_addresses
, &n_br_addresses
);
1186 FOREACH_ARRAY(br_address
, br_addresses
, n_br_addresses
) {
1187 r
= json_variant_append_arrayb(&addresses
, JSON_BUILD_IN4_ADDR(br_address
));
1192 r
= json_build(&array
, JSON_BUILD_OBJECT(
1193 JSON_BUILD_PAIR_IN6_ADDR("Prefix", &sixrd_prefix
),
1194 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", sixrd_prefixlen
),
1195 JSON_BUILD_PAIR_UNSIGNED("IPv4MaskLength", ipv4masklen
),
1196 JSON_BUILD_PAIR_VARIANT_NON_NULL("BorderRouters", addresses
)));
1200 return json_append_one(v
, "6rdPrefix", array
);
1203 static int dhcp_client_append_json(Link
*link
, JsonVariant
**v
) {
1204 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1210 if (!link
->dhcp_client
)
1213 r
= dhcp_client_lease_append_json(link
, &w
);
1217 r
= dhcp_client_pd_append_json(link
, &w
);
1221 return json_append_one(v
, "DHCPv4Client", w
);
1224 int link_build_json(Link
*link
, JsonVariant
**ret
) {
1225 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1226 _cleanup_free_
char *type
= NULL
, *flags
= NULL
;
1232 r
= net_get_type_string(link
->dev
, link
->iftype
, &type
);
1236 r
= link_flags_to_string_alloc(link
->flags
, &flags
);
1240 r
= json_build(&v
, JSON_BUILD_OBJECT(
1241 /* basic information */
1242 JSON_BUILD_PAIR_INTEGER("Index", link
->ifindex
),
1243 JSON_BUILD_PAIR_STRING("Name", link
->ifname
),
1244 JSON_BUILD_PAIR_STRV_NON_EMPTY("AlternativeNames", link
->alternative_names
),
1245 JSON_BUILD_PAIR_CONDITION(link
->master_ifindex
> 0,
1246 "MasterInterfaceIndex", JSON_BUILD_INTEGER(link
->master_ifindex
)),
1247 JSON_BUILD_PAIR_STRING_NON_EMPTY("Kind", link
->kind
),
1248 JSON_BUILD_PAIR_STRING("Type", type
),
1249 JSON_BUILD_PAIR_STRING_NON_EMPTY("Driver", link
->driver
),
1250 JSON_BUILD_PAIR_UNSIGNED("Flags", link
->flags
),
1251 JSON_BUILD_PAIR_STRING("FlagsString", flags
),
1252 JSON_BUILD_PAIR_UNSIGNED("KernelOperationalState", link
->kernel_operstate
),
1253 JSON_BUILD_PAIR_STRING("KernelOperationalStateString", kernel_operstate_to_string(link
->kernel_operstate
)),
1254 JSON_BUILD_PAIR_UNSIGNED("MTU", link
->mtu
),
1255 JSON_BUILD_PAIR_UNSIGNED("MinimumMTU", link
->min_mtu
),
1256 JSON_BUILD_PAIR_UNSIGNED("MaximumMTU", link
->max_mtu
),
1257 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("HardwareAddress", &link
->hw_addr
),
1258 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("PermanentHardwareAddress", &link
->permanent_hw_addr
),
1259 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("BroadcastAddress", &link
->bcast_addr
),
1260 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("IPv6LinkLocalAddress", &link
->ipv6ll_address
),
1261 /* wlan information */
1262 JSON_BUILD_PAIR_CONDITION(link
->wlan_iftype
> 0, "WirelessLanInterfaceType",
1263 JSON_BUILD_UNSIGNED(link
->wlan_iftype
)),
1264 JSON_BUILD_PAIR_CONDITION(link
->wlan_iftype
> 0, "WirelessLanInterfaceTypeString",
1265 JSON_BUILD_STRING(nl80211_iftype_to_string(link
->wlan_iftype
))),
1266 JSON_BUILD_PAIR_STRING_NON_EMPTY("SSID", link
->ssid
),
1267 JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL("BSSID", &link
->bssid
),
1269 JSON_BUILD_PAIR_STRING("AdministrativeState", link_state_to_string(link
->state
)),
1270 JSON_BUILD_PAIR_STRING("OperationalState", link_operstate_to_string(link
->operstate
)),
1271 JSON_BUILD_PAIR_STRING("CarrierState", link_carrier_state_to_string(link
->carrier_state
)),
1272 JSON_BUILD_PAIR_STRING("AddressState", link_address_state_to_string(link
->address_state
)),
1273 JSON_BUILD_PAIR_STRING("IPv4AddressState", link_address_state_to_string(link
->ipv4_address_state
)),
1274 JSON_BUILD_PAIR_STRING("IPv6AddressState", link_address_state_to_string(link
->ipv6_address_state
)),
1275 JSON_BUILD_PAIR_STRING("OnlineState", link_online_state_to_string(link
->online_state
))));
1279 r
= network_append_json(link
->network
, &v
);
1283 r
= device_append_json(link
->dev
, &v
);
1287 r
= dns_append_json(link
, &v
);
1291 r
= ntp_append_json(link
, &v
);
1295 r
= sip_append_json(link
, &v
);
1299 r
= domains_append_json(link
, /* is_route = */ false, &v
);
1303 r
= domains_append_json(link
, /* is_route = */ true, &v
);
1307 r
= ntas_append_json(link
, &v
);
1311 r
= dns_misc_append_json(link
, &v
);
1315 r
= captive_portal_append_json(link
, &v
);
1319 r
= pref64_append_json(link
, &v
);
1323 r
= addresses_append_json(link
->addresses
, &v
);
1327 r
= neighbors_append_json(link
->neighbors
, &v
);
1331 r
= nexthops_append_json(link
->nexthops
, &v
);
1335 r
= routes_append_json(link
->routes
, &v
);
1339 r
= dhcp_server_append_json(link
, &v
);
1343 r
= dhcp_client_append_json(link
, &v
);
1347 r
= dhcp6_client_append_json(link
, &v
);
1355 static int links_append_json(Manager
*manager
, JsonVariant
**v
) {
1356 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1357 _cleanup_free_ Link
**links
= NULL
;
1364 r
= hashmap_dump_sorted(manager
->links_by_index
, (void***) &links
, &n_links
);
1368 FOREACH_ARRAY(link
, links
, n_links
) {
1369 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
1371 r
= link_build_json(*link
, &e
);
1375 r
= json_variant_append_array(&array
, e
);
1380 return json_append_one(v
, "Interfaces", array
);
1383 int manager_build_json(Manager
*manager
, JsonVariant
**ret
) {
1384 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1390 r
= links_append_json(manager
, &v
);
1394 r
= nexthops_append_json(manager
->nexthops
, &v
);
1398 r
= routes_append_json(manager
->routes
, &v
);
1402 r
= routing_policy_rules_append_json(manager
->rules
, &v
);