1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/nexthop.h>
5 #include "dhcp-lease-internal.h"
6 #include "dhcp-server-lease-internal.h"
7 #include "dhcp6-internal.h"
8 #include "dhcp6-lease-internal.h"
9 #include "dns-domain.h"
10 #include "ip-protocol-list.h"
11 #include "netif-util.h"
12 #include "networkd-address.h"
13 #include "networkd-dhcp-common.h"
14 #include "networkd-json.h"
15 #include "networkd-link.h"
16 #include "networkd-manager.h"
17 #include "networkd-neighbor.h"
18 #include "networkd-network.h"
19 #include "networkd-nexthop.h"
20 #include "networkd-route-util.h"
21 #include "networkd-route.h"
22 #include "networkd-routing-policy-rule.h"
23 #include "sort-util.h"
24 #include "udev-util.h"
25 #include "user-util.h"
26 #include "wifi-util.h"
28 static int address_append_json(Address
*address
, JsonVariant
**array
) {
29 _cleanup_free_
char *scope
= NULL
, *flags
= NULL
, *state
= NULL
;
35 r
= route_scope_to_string_alloc(address
->scope
, &scope
);
39 r
= address_flags_to_string_alloc(address
->flags
, address
->family
, &flags
);
43 r
= network_config_state_to_string_alloc(address
->state
, &state
);
47 return json_variant_append_arrayb(
50 JSON_BUILD_PAIR_INTEGER("Family", address
->family
),
51 JSON_BUILD_PAIR_IN_ADDR("Address", &address
->in_addr
, address
->family
),
52 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Peer", &address
->in_addr_peer
, address
->family
),
53 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Broadcast", &address
->broadcast
),
54 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", address
->prefixlen
),
55 JSON_BUILD_PAIR_UNSIGNED("Scope", address
->scope
),
56 JSON_BUILD_PAIR_STRING("ScopeString", scope
),
57 JSON_BUILD_PAIR_UNSIGNED("Flags", address
->flags
),
58 JSON_BUILD_PAIR_STRING("FlagsString", flags
),
59 JSON_BUILD_PAIR_STRING_NON_EMPTY("Label", address
->label
),
60 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUSec", address
->lifetime_preferred_usec
),
61 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUsec", address
->lifetime_preferred_usec
), /* for backward compat */
62 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUSec", address
->lifetime_valid_usec
),
63 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUsec", address
->lifetime_valid_usec
), /* for backward compat */
64 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(address
->source
)),
65 JSON_BUILD_PAIR_STRING("ConfigState", state
),
66 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &address
->provider
, address
->family
)));
69 static int addresses_append_json(Set
*addresses
, JsonVariant
**v
) {
70 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
76 SET_FOREACH(address
, addresses
) {
77 r
= address_append_json(address
, &array
);
82 return json_variant_set_field_non_null(v
, "Addresses", array
);
85 static int neighbor_append_json(Neighbor
*n
, JsonVariant
**array
) {
86 _cleanup_free_
char *state
= NULL
;
92 r
= network_config_state_to_string_alloc(n
->state
, &state
);
96 return json_variant_append_arrayb(
99 JSON_BUILD_PAIR_INTEGER("Family", n
->family
),
100 JSON_BUILD_PAIR_IN_ADDR("Destination", &n
->in_addr
, n
->family
),
101 JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n
->ll_addr
),
102 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n
->source
)),
103 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
106 static int neighbors_append_json(Set
*neighbors
, JsonVariant
**v
) {
107 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
113 SET_FOREACH(neighbor
, neighbors
) {
114 r
= neighbor_append_json(neighbor
, &array
);
119 return json_variant_set_field_non_null(v
, "Neighbors", array
);
122 static int nexthop_group_build_json(NextHop
*nexthop
, JsonVariant
**ret
) {
123 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
124 struct nexthop_grp
*g
;
130 HASHMAP_FOREACH(g
, nexthop
->group
) {
131 r
= json_variant_append_arrayb(
134 JSON_BUILD_PAIR_UNSIGNED("ID", g
->id
),
135 JSON_BUILD_PAIR_UNSIGNED("Weight", g
->weight
+1)));
140 *ret
= TAKE_PTR(array
);
144 static int nexthop_append_json(NextHop
*n
, JsonVariant
**array
) {
145 _cleanup_(json_variant_unrefp
) JsonVariant
*group
= NULL
;
146 _cleanup_free_
char *flags
= NULL
, *protocol
= NULL
, *state
= NULL
;
152 r
= route_flags_to_string_alloc(n
->flags
, &flags
);
156 r
= route_protocol_to_string_alloc(n
->protocol
, &protocol
);
160 r
= network_config_state_to_string_alloc(n
->state
, &state
);
164 r
= nexthop_group_build_json(n
, &group
);
168 return json_variant_append_arrayb(
171 JSON_BUILD_PAIR_UNSIGNED("ID", n
->id
),
172 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n
->gw
, n
->family
),
173 JSON_BUILD_PAIR_UNSIGNED("Flags", n
->flags
),
174 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags
)),
175 JSON_BUILD_PAIR_UNSIGNED("Protocol", n
->protocol
),
176 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
177 JSON_BUILD_PAIR_BOOLEAN("Blackhole", n
->blackhole
),
178 JSON_BUILD_PAIR_VARIANT_NON_NULL("Group", group
),
179 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n
->source
)),
180 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
183 static int nexthops_append_json(Manager
*manager
, int ifindex
, JsonVariant
**v
) {
184 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
191 HASHMAP_FOREACH(nexthop
, manager
->nexthops_by_id
) {
192 if (nexthop
->ifindex
!= ifindex
)
195 r
= nexthop_append_json(nexthop
, &array
);
200 return json_variant_set_field_non_null(v
, "NextHops", array
);
203 static int route_append_json(Route
*route
, JsonVariant
**array
) {
204 _cleanup_free_
char *scope
= NULL
, *protocol
= NULL
, *table
= NULL
, *flags
= NULL
, *state
= NULL
;
210 r
= route_scope_to_string_alloc(route
->scope
, &scope
);
214 r
= route_protocol_to_string_alloc(route
->protocol
, &protocol
);
218 r
= manager_get_route_table_to_string(route
->manager
, route
->table
, /* append_num = */ false, &table
);
222 r
= route_flags_to_string_alloc(route
->flags
, &flags
);
226 r
= network_config_state_to_string_alloc(route
->state
, &state
);
230 return json_variant_append_arrayb(
233 JSON_BUILD_PAIR_INTEGER("Family", route
->family
),
234 JSON_BUILD_PAIR_IN_ADDR("Destination", &route
->dst
, route
->family
),
235 JSON_BUILD_PAIR_UNSIGNED("DestinationPrefixLength", route
->dst_prefixlen
),
236 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &route
->nexthop
.gw
, route
->nexthop
.family
),
237 JSON_BUILD_PAIR_CONDITION(route
->src_prefixlen
> 0,
238 "Source", JSON_BUILD_IN_ADDR(&route
->src
, route
->family
)),
239 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("SourcePrefixLength", route
->src_prefixlen
),
240 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("PreferredSource", &route
->prefsrc
, route
->family
),
241 JSON_BUILD_PAIR_UNSIGNED("Scope", route
->scope
),
242 JSON_BUILD_PAIR_STRING("ScopeString", scope
),
243 JSON_BUILD_PAIR_UNSIGNED("Protocol", route
->protocol
),
244 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
245 JSON_BUILD_PAIR_UNSIGNED("Type", route
->type
),
246 JSON_BUILD_PAIR_STRING("TypeString", route_type_to_string(route
->type
)),
247 JSON_BUILD_PAIR_UNSIGNED("Priority", route
->priority
),
248 JSON_BUILD_PAIR_UNSIGNED("Table", route
->table
),
249 JSON_BUILD_PAIR_STRING("TableString", table
),
250 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route_metric_get(&route
->metric
, RTAX_MTU
)),
251 JSON_BUILD_PAIR_UNSIGNED("Preference", route
->pref
),
252 JSON_BUILD_PAIR_UNSIGNED("Flags", route
->flags
),
253 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags
)),
254 JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", route
->lifetime_usec
),
255 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(route
->source
)),
256 JSON_BUILD_PAIR_STRING("ConfigState", state
),
257 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &route
->provider
, route
->family
)));
260 static int routes_append_json(Manager
*manager
, int ifindex
, JsonVariant
**v
) {
261 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
268 SET_FOREACH(route
, manager
->routes
) {
269 if (route
->nexthop
.ifindex
!= ifindex
)
272 r
= route_append_json(route
, &array
);
277 return json_variant_set_field_non_null(v
, "Routes", array
);
280 static int routing_policy_rule_append_json(RoutingPolicyRule
*rule
, JsonVariant
**array
) {
281 _cleanup_free_
char *table
= NULL
, *protocol
= NULL
, *state
= NULL
;
285 assert(rule
->manager
);
288 r
= manager_get_route_table_to_string(rule
->manager
, rule
->table
, /* append_num = */ false, &table
);
289 if (r
< 0 && r
!= -EINVAL
)
292 r
= route_protocol_to_string_alloc(rule
->protocol
, &protocol
);
296 r
= network_config_state_to_string_alloc(rule
->state
, &state
);
300 return json_variant_append_arrayb(
303 JSON_BUILD_PAIR_INTEGER("Family", rule
->family
),
304 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("FromPrefix", &rule
->from
, rule
->family
),
305 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule
->family
, &rule
->from
),
306 "FromPrefixLength", JSON_BUILD_UNSIGNED(rule
->from_prefixlen
)),
307 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ToPrefix", &rule
->to
, rule
->family
),
308 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule
->family
, &rule
->to
),
309 "ToPrefixLength", JSON_BUILD_UNSIGNED(rule
->to_prefixlen
)),
310 JSON_BUILD_PAIR_UNSIGNED("Protocol", rule
->protocol
),
311 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
312 JSON_BUILD_PAIR_UNSIGNED("TOS", rule
->tos
),
313 JSON_BUILD_PAIR_UNSIGNED("Type", rule
->type
),
314 JSON_BUILD_PAIR_STRING("TypeString", fr_act_type_full_to_string(rule
->type
)),
315 JSON_BUILD_PAIR_UNSIGNED("IPProtocol", rule
->ipproto
),
316 JSON_BUILD_PAIR_STRING("IPProtocolString", ip_protocol_to_name(rule
->ipproto
)),
317 JSON_BUILD_PAIR_UNSIGNED("Priority", rule
->priority
),
318 JSON_BUILD_PAIR_UNSIGNED("FirewallMark", rule
->fwmark
),
319 JSON_BUILD_PAIR_UNSIGNED("FirewallMask", rule
->fwmask
),
320 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Table", rule
->table
),
321 JSON_BUILD_PAIR_STRING_NON_EMPTY("TableString", table
),
322 JSON_BUILD_PAIR_BOOLEAN("Invert", rule
->invert_rule
),
323 JSON_BUILD_PAIR_CONDITION(rule
->suppress_prefixlen
>= 0,
324 "SuppressPrefixLength", JSON_BUILD_UNSIGNED(rule
->suppress_prefixlen
)),
325 JSON_BUILD_PAIR_CONDITION(rule
->suppress_ifgroup
>= 0,
326 "SuppressInterfaceGroup", JSON_BUILD_UNSIGNED(rule
->suppress_ifgroup
)),
327 JSON_BUILD_PAIR_CONDITION(rule
->sport
.start
!= 0 || rule
->sport
.end
!= 0, "SourcePort",
328 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->sport
.start
), JSON_BUILD_UNSIGNED(rule
->sport
.end
))),
329 JSON_BUILD_PAIR_CONDITION(rule
->dport
.start
!= 0 || rule
->dport
.end
!= 0, "DestinationPort",
330 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->dport
.start
), JSON_BUILD_UNSIGNED(rule
->dport
.end
))),
331 JSON_BUILD_PAIR_CONDITION(rule
->uid_range
.start
!= UID_INVALID
&& rule
->uid_range
.end
!= UID_INVALID
, "User",
332 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->uid_range
.start
), JSON_BUILD_UNSIGNED(rule
->uid_range
.end
))),
333 JSON_BUILD_PAIR_STRING_NON_EMPTY("IncomingInterface", rule
->iif
),
334 JSON_BUILD_PAIR_STRING_NON_EMPTY("OutgoingInterface", rule
->oif
),
335 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(rule
->source
)),
336 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
339 static int routing_policy_rules_append_json(Set
*rules
, JsonVariant
**v
) {
340 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
341 RoutingPolicyRule
*rule
;
346 SET_FOREACH(rule
, rules
) {
347 r
= routing_policy_rule_append_json(rule
, &array
);
352 return json_variant_set_field_non_null(v
, "RoutingPolicyRules", array
);
355 static int network_append_json(Network
*network
, JsonVariant
**v
) {
361 return json_variant_merge_objectb(
362 v
, JSON_BUILD_OBJECT(
363 JSON_BUILD_PAIR_STRING("NetworkFile", network
->filename
),
364 JSON_BUILD_PAIR_STRV("NetworkFileDropins", network
->dropins
),
365 JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network
->required_for_online
),
366 JSON_BUILD_PAIR("RequiredOperationalStateForOnline",
367 JSON_BUILD_ARRAY(JSON_BUILD_STRING(link_operstate_to_string(network
->required_operstate_for_online
.min
)),
368 JSON_BUILD_STRING(link_operstate_to_string(network
->required_operstate_for_online
.max
)))),
369 JSON_BUILD_PAIR_STRING("RequiredFamilyForOnline",
370 link_required_address_family_to_string(network
->required_family_for_online
)),
371 JSON_BUILD_PAIR_STRING("ActivationPolicy",
372 activation_policy_to_string(network
->activation_policy
))));
375 static int device_append_json(sd_device
*device
, JsonVariant
**v
) {
376 _cleanup_strv_free_
char **link_dropins
= NULL
;
377 const char *link
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *joined
;
385 (void) sd_device_get_property_value(device
, "ID_NET_LINK_FILE", &link
);
387 if (sd_device_get_property_value(device
, "ID_NET_LINK_FILE_DROPINS", &joined
) >= 0) {
388 r
= strv_split_full(&link_dropins
, joined
, ":", EXTRACT_CUNESCAPE
);
393 (void) sd_device_get_property_value(device
, "ID_PATH", &path
);
395 (void) device_get_vendor_string(device
, &vendor
);
396 (void) device_get_model_string(device
, &model
);
398 return json_variant_merge_objectb(
401 JSON_BUILD_PAIR_STRING_NON_EMPTY("LinkFile", link
),
402 JSON_BUILD_PAIR_STRV_NON_EMPTY("LinkFileDropins", link_dropins
),
403 JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", path
),
404 JSON_BUILD_PAIR_STRING_NON_EMPTY("Vendor", vendor
),
405 JSON_BUILD_PAIR_STRING_NON_EMPTY("Model", model
)));
408 static int dns_append_json_one(Link
*link
, const struct in_addr_full
*a
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
413 if (a
->ifindex
!= 0 && a
->ifindex
!= link
->ifindex
)
416 return json_variant_append_arrayb(
419 JSON_BUILD_PAIR_INTEGER("Family", a
->family
),
420 JSON_BUILD_PAIR_IN_ADDR("Address", &a
->address
, a
->family
),
421 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Port", a
->port
),
422 JSON_BUILD_PAIR_CONDITION(a
->ifindex
!= 0, "InterfaceIndex", JSON_BUILD_INTEGER(a
->ifindex
)),
423 JSON_BUILD_PAIR_STRING_NON_EMPTY("ServerName", a
->server_name
),
424 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
425 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, a
->family
)));
428 static int dns_append_json(Link
*link
, JsonVariant
**v
) {
429 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
438 if (link
->n_dns
!= UINT_MAX
)
439 for (unsigned i
= 0; i
< link
->n_dns
; i
++) {
440 r
= dns_append_json_one(link
, link
->dns
[i
], NETWORK_CONFIG_SOURCE_RUNTIME
, NULL
, &array
);
445 for (unsigned i
= 0; i
< link
->network
->n_dns
; i
++) {
446 r
= dns_append_json_one(link
, link
->network
->dns
[i
], NETWORK_CONFIG_SOURCE_STATIC
, NULL
, &array
);
451 if (link
->dhcp_lease
&& link
->network
->dhcp_use_dns
) {
452 const struct in_addr
*dns
;
453 union in_addr_union s
;
456 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
460 n_dns
= sd_dhcp_lease_get_dns(link
->dhcp_lease
, &dns
);
461 for (int i
= 0; i
< n_dns
; i
++) {
462 r
= dns_append_json_one(link
,
463 &(struct in_addr_full
) { .family
= AF_INET
, .address
.in
= dns
[i
], },
464 NETWORK_CONFIG_SOURCE_DHCP4
,
472 if (link
->dhcp6_lease
&& link
->network
->dhcp6_use_dns
) {
473 const struct in6_addr
*dns
;
474 union in_addr_union s
;
477 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
481 n_dns
= sd_dhcp6_lease_get_dns(link
->dhcp6_lease
, &dns
);
482 for (int i
= 0; i
< n_dns
; i
++) {
483 r
= dns_append_json_one(link
,
484 &(struct in_addr_full
) { .family
= AF_INET6
, .address
.in6
= dns
[i
], },
485 NETWORK_CONFIG_SOURCE_DHCP6
,
493 if (link
->network
->ipv6_accept_ra_use_dns
) {
496 SET_FOREACH(a
, link
->ndisc_rdnss
) {
497 r
= dns_append_json_one(link
,
498 &(struct in_addr_full
) { .family
= AF_INET6
, .address
.in6
= a
->address
, },
499 NETWORK_CONFIG_SOURCE_NDISC
,
500 &(union in_addr_union
) { .in6
= a
->router
},
508 return json_variant_set_field_non_null(v
, "DNS", array
);
511 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
) {
512 assert(IN_SET(family
, AF_INET
, AF_INET6
));
516 return json_variant_append_arrayb(
519 JSON_BUILD_PAIR_INTEGER("Family", family
),
520 JSON_BUILD_PAIR_IN_ADDR("Address", a
, family
),
521 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
522 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
525 static int server_append_json_one_fqdn(int family
, const char *fqdn
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
526 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
530 return json_variant_append_arrayb(
533 JSON_BUILD_PAIR_STRING("Server", fqdn
),
534 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
535 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
538 static int server_append_json_one_string(const char *str
, NetworkConfigSource s
, JsonVariant
**array
) {
539 union in_addr_union a
;
544 if (in_addr_from_string_auto(str
, &family
, &a
) >= 0)
545 return server_append_json_one_addr(family
, &a
, s
, NULL
, array
);
547 return server_append_json_one_fqdn(AF_UNSPEC
, str
, s
, NULL
, array
);
550 static int ntp_append_json(Link
*link
, JsonVariant
**v
) {
551 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
560 STRV_FOREACH(p
, link
->ntp
?: link
->network
->ntp
) {
561 r
= server_append_json_one_string(*p
, NETWORK_CONFIG_SOURCE_RUNTIME
, &array
);
567 if (link
->dhcp_lease
&& link
->network
->dhcp_use_ntp
) {
568 const struct in_addr
*ntp
;
569 union in_addr_union s
;
572 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
576 n_ntp
= sd_dhcp_lease_get_ntp(link
->dhcp_lease
, &ntp
);
577 for (int i
= 0; i
< n_ntp
; i
++) {
578 r
= server_append_json_one_addr(AF_INET
,
579 &(union in_addr_union
) { .in
= ntp
[i
], },
580 NETWORK_CONFIG_SOURCE_DHCP4
,
588 if (link
->dhcp6_lease
&& link
->network
->dhcp6_use_ntp
) {
589 const struct in6_addr
*ntp_addr
;
590 union in_addr_union s
;
594 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
598 n_ntp
= sd_dhcp6_lease_get_ntp_addrs(link
->dhcp6_lease
, &ntp_addr
);
599 for (int i
= 0; i
< n_ntp
; i
++) {
600 r
= server_append_json_one_addr(AF_INET6
,
601 &(union in_addr_union
) { .in6
= ntp_addr
[i
], },
602 NETWORK_CONFIG_SOURCE_DHCP6
,
609 n_ntp
= sd_dhcp6_lease_get_ntp_fqdn(link
->dhcp6_lease
, &ntp_fqdn
);
610 for (int i
= 0; i
< n_ntp
; i
++) {
611 r
= server_append_json_one_fqdn(AF_INET6
,
613 NETWORK_CONFIG_SOURCE_DHCP6
,
622 return json_variant_set_field_non_null(v
, "NTP", array
);
625 static int sip_append_json(Link
*link
, JsonVariant
**v
) {
626 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
627 const struct in_addr
*sip
;
628 union in_addr_union s
;
634 if (!link
->network
|| !link
->network
->dhcp_use_sip
|| !link
->dhcp_lease
)
637 n_sip
= sd_dhcp_lease_get_sip(link
->dhcp_lease
, &sip
);
641 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
645 for (int i
= 0; i
< n_sip
; i
++) {
646 r
= server_append_json_one_addr(AF_INET
,
647 &(union in_addr_union
) { .in
= sip
[i
], },
648 NETWORK_CONFIG_SOURCE_DHCP4
,
655 return json_variant_set_field_non_null(v
, "SIP", array
);
658 static int domain_append_json(int family
, const char *domain
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
659 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
663 return json_variant_append_arrayb(
666 JSON_BUILD_PAIR_STRING("Domain", domain
),
667 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
668 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
671 static int domains_append_json(Link
*link
, bool is_route
, JsonVariant
**v
) {
672 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
673 OrderedSet
*link_domains
, *network_domains
;
674 DHCPUseDomains use_domains
;
675 union in_addr_union s
;
686 link_domains
= is_route
? link
->route_domains
: link
->search_domains
;
687 network_domains
= is_route
? link
->network
->route_domains
: link
->network
->search_domains
;
688 use_domains
= is_route
? DHCP_USE_DOMAINS_ROUTE
: DHCP_USE_DOMAINS_YES
;
690 ORDERED_SET_FOREACH(domain
, link_domains
?: network_domains
) {
691 r
= domain_append_json(AF_UNSPEC
, domain
,
692 link_domains
? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
,
699 if (link
->dhcp_lease
&&
700 link
->network
->dhcp_use_domains
== use_domains
) {
701 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
705 if (sd_dhcp_lease_get_domainname(link
->dhcp_lease
, &domain
) >= 0) {
706 r
= domain_append_json(AF_INET
, domain
, NETWORK_CONFIG_SOURCE_DHCP4
, &s
, &array
);
711 if (sd_dhcp_lease_get_search_domains(link
->dhcp_lease
, &domains
) >= 0)
712 STRV_FOREACH(p
, domains
) {
713 r
= domain_append_json(AF_INET
, *p
, NETWORK_CONFIG_SOURCE_DHCP4
, &s
, &array
);
719 if (link
->dhcp6_lease
&&
720 link
->network
->dhcp6_use_domains
== use_domains
) {
721 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
725 if (sd_dhcp6_lease_get_domains(link
->dhcp6_lease
, &domains
) >= 0)
726 STRV_FOREACH(p
, domains
) {
727 r
= domain_append_json(AF_INET6
, *p
, NETWORK_CONFIG_SOURCE_DHCP6
, &s
, &array
);
733 if (link
->network
->ipv6_accept_ra_use_domains
== use_domains
) {
736 SET_FOREACH(a
, link
->ndisc_dnssl
) {
737 r
= domain_append_json(AF_INET6
, NDISC_DNSSL_DOMAIN(a
), NETWORK_CONFIG_SOURCE_NDISC
,
738 &(union in_addr_union
) { .in6
= a
->router
},
746 return json_variant_set_field_non_null(v
, is_route
? "RouteDomains" : "SearchDomains", array
);
749 static int nta_append_json(const char *nta
, NetworkConfigSource s
, JsonVariant
**array
) {
753 return json_variant_append_arrayb(
756 JSON_BUILD_PAIR_STRING("DNSSECNegativeTrustAnchor", nta
),
757 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
))));
760 static int ntas_append_json(Link
*link
, JsonVariant
**v
) {
761 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
771 SET_FOREACH(nta
, link
->dnssec_negative_trust_anchors
?: link
->network
->dnssec_negative_trust_anchors
) {
772 r
= nta_append_json(nta
,
773 link
->dnssec_negative_trust_anchors
? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
,
779 return json_variant_set_field_non_null(v
, "DNSSECNegativeTrustAnchors", array
);
782 static int dns_misc_append_json(Link
*link
, JsonVariant
**v
) {
783 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
784 ResolveSupport resolve_support
;
785 NetworkConfigSource source
;
795 resolve_support
= link
->llmnr
>= 0 ? link
->llmnr
: link
->network
->llmnr
;
796 if (resolve_support
>= 0) {
797 source
= link
->llmnr
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
799 r
= json_variant_append_arrayb(
802 JSON_BUILD_PAIR_STRING("LLMNR", resolve_support_to_string(resolve_support
)),
803 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
808 resolve_support
= link
->mdns
>= 0 ? link
->mdns
: link
->network
->mdns
;
809 if (resolve_support
>= 0) {
810 source
= link
->mdns
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
812 r
= json_variant_append_arrayb(
815 JSON_BUILD_PAIR_STRING("MDNS", resolve_support_to_string(resolve_support
)),
816 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
821 t
= link
->dns_default_route
>= 0 ? link
->dns_default_route
: link
->network
->dns_default_route
;
823 source
= link
->dns_default_route
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
825 r
= json_variant_append_arrayb(
828 JSON_BUILD_PAIR_BOOLEAN("DNSDefaultRoute", t
),
829 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
834 mode
= link
->dns_over_tls_mode
>= 0 ? link
->dns_over_tls_mode
: link
->network
->dns_over_tls_mode
;
836 source
= link
->dns_over_tls_mode
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
838 r
= json_variant_append_arrayb(
841 JSON_BUILD_PAIR_STRING("DNSOverTLS", dns_over_tls_mode_to_string(mode
)),
842 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
847 return json_variant_set_field_non_null(v
, "DNSSettings", array
);
850 static int captive_portal_append_json(Link
*link
, JsonVariant
**v
) {
851 const char *captive_portal
;
857 r
= link_get_captive_portal(link
, &captive_portal
);
861 return json_variant_merge_objectb(v
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_STRING("CaptivePortal", captive_portal
)));
864 static int pref64_append_json(Link
*link
, JsonVariant
**v
) {
865 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
, *w
= NULL
;
872 if (!link
->network
|| !link
->network
->ipv6_accept_ra_use_pref64
)
875 SET_FOREACH(i
, link
->ndisc_pref64
) {
876 r
= json_variant_append_arrayb(&array
,
878 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("Prefix", &i
->prefix
),
879 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", i
->prefix_len
),
880 JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", i
->lifetime_usec
),
881 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("ConfigProvider", &i
->router
)));
886 r
= json_variant_set_field_non_null(&w
, "PREF64", array
);
890 return json_variant_set_field_non_null(v
, "NDisc", w
);
893 static int dhcp_server_offered_leases_append_json(Link
*link
, JsonVariant
**v
) {
894 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
895 sd_dhcp_server_lease
*lease
;
901 if (!link
->dhcp_server
)
904 HASHMAP_FOREACH(lease
, link
->dhcp_server
->bound_leases_by_client_id
) {
905 struct in_addr address
= { .s_addr
= lease
->address
};
907 r
= json_variant_append_arrayb(
910 JSON_BUILD_PAIR_BYTE_ARRAY(
912 lease
->client_id
.raw
,
913 lease
->client_id
.size
),
914 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address
),
915 JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease
->hostname
),
916 JSON_BUILD_PAIR_FINITE_USEC(
917 "ExpirationUSec", lease
->expiration
)));
922 return json_variant_set_field_non_null(v
, "Leases", array
);
925 static int dhcp_server_static_leases_append_json(Link
*link
, JsonVariant
**v
) {
926 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
927 sd_dhcp_server_lease
*lease
;
933 if (!link
->dhcp_server
)
936 HASHMAP_FOREACH(lease
, link
->dhcp_server
->static_leases_by_client_id
) {
937 struct in_addr address
= { .s_addr
= lease
->address
};
939 r
= json_variant_append_arrayb(
942 JSON_BUILD_PAIR_BYTE_ARRAY(
944 lease
->client_id
.raw
,
945 lease
->client_id
.size
),
946 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address
)));
951 return json_variant_set_field_non_null(v
, "StaticLeases", array
);
954 static int dhcp_server_append_json(Link
*link
, JsonVariant
**v
) {
955 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
961 if (!link
->dhcp_server
)
966 JSON_BUILD_PAIR_UNSIGNED("PoolOffset", link
->dhcp_server
->pool_offset
),
967 JSON_BUILD_PAIR_UNSIGNED("PoolSize", link
->dhcp_server
->pool_size
)));
971 r
= dhcp_server_offered_leases_append_json(link
, &w
);
975 r
= dhcp_server_static_leases_append_json(link
, &w
);
979 return json_variant_set_field_non_null(v
, "DHCPServer", w
);
982 static int dhcp6_client_vendor_options_append_json(Link
*link
, JsonVariant
**v
) {
983 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
984 sd_dhcp6_option
**options
= NULL
;
985 int r
, n_vendor_options
;
990 if (!link
->dhcp6_lease
)
993 n_vendor_options
= sd_dhcp6_lease_get_vendor_options(link
->dhcp6_lease
, &options
);
995 FOREACH_ARRAY(option
, options
, n_vendor_options
) {
996 r
= json_variant_append_arrayb(&array
,
998 JSON_BUILD_PAIR_UNSIGNED("EnterpriseId", (*option
)->enterprise_identifier
),
999 JSON_BUILD_PAIR_UNSIGNED("SubOptionCode", (*option
)->option
),
1000 JSON_BUILD_PAIR_HEX("SubOptionData", (*option
)->data
, (*option
)->length
)));
1005 return json_variant_set_field_non_null(v
, "VendorSpecificOptions", array
);
1008 static int dhcp6_client_lease_append_json(Link
*link
, JsonVariant
**v
) {
1009 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1010 usec_t ts
= USEC_INFINITY
, t1
= USEC_INFINITY
, t2
= USEC_INFINITY
;
1016 if (!link
->dhcp6_lease
)
1019 r
= sd_dhcp6_lease_get_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &ts
);
1020 if (r
< 0 && r
!= -ENODATA
)
1023 r
= sd_dhcp6_lease_get_t1_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &t1
);
1024 if (r
< 0 && r
!= -ENODATA
)
1027 r
= sd_dhcp6_lease_get_t2_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &t2
);
1028 if (r
< 0 && r
!= -ENODATA
)
1031 r
= json_build(&w
, JSON_BUILD_OBJECT(
1032 JSON_BUILD_PAIR_FINITE_USEC("Timeout1USec", t1
),
1033 JSON_BUILD_PAIR_FINITE_USEC("Timeout2USec", t2
),
1034 JSON_BUILD_PAIR_FINITE_USEC("LeaseTimestampUSec", ts
)));
1038 return json_variant_set_field_non_null(v
, "Lease", w
);
1041 static int dhcp6_client_pd_append_json(Link
*link
, JsonVariant
**v
) {
1042 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1046 assert(link
->network
);
1049 if (!link
->network
->dhcp6_use_pd_prefix
||
1050 !sd_dhcp6_lease_has_pd_prefix(link
->dhcp6_lease
))
1053 FOREACH_DHCP6_PD_PREFIX(link
->dhcp6_lease
) {
1054 usec_t lifetime_preferred_usec
, lifetime_valid_usec
;
1055 struct in6_addr prefix
;
1058 r
= sd_dhcp6_lease_get_pd_prefix(link
->dhcp6_lease
, &prefix
, &prefix_len
);
1062 r
= sd_dhcp6_lease_get_pd_lifetime_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
,
1063 &lifetime_preferred_usec
, &lifetime_valid_usec
);
1067 r
= json_variant_append_arrayb(&array
, JSON_BUILD_OBJECT(
1068 JSON_BUILD_PAIR_IN6_ADDR("Prefix", &prefix
),
1069 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", prefix_len
),
1070 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUSec", lifetime_preferred_usec
),
1071 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUSec", lifetime_valid_usec
)));
1076 return json_variant_set_field_non_null(v
, "Prefixes", array
);
1079 static int dhcp6_client_append_json(Link
*link
, JsonVariant
**v
) {
1080 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1086 if (!link
->dhcp6_client
)
1089 r
= dhcp6_client_lease_append_json(link
, &w
);
1093 r
= dhcp6_client_pd_append_json(link
, &w
);
1097 r
= dhcp6_client_vendor_options_append_json(link
, &w
);
1101 return json_variant_set_field_non_null(v
, "DHCPv6Client", w
);
1104 static int dhcp_client_lease_append_json(Link
*link
, JsonVariant
**v
) {
1105 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1106 usec_t lease_timestamp_usec
= USEC_INFINITY
, t1
= USEC_INFINITY
, t2
= USEC_INFINITY
;
1112 if (!link
->dhcp_client
|| !link
->dhcp_lease
)
1115 r
= sd_dhcp_lease_get_timestamp(link
->dhcp_lease
, CLOCK_BOOTTIME
, &lease_timestamp_usec
);
1116 if (r
< 0 && r
!= -ENODATA
)
1119 r
= sd_dhcp_lease_get_t1_timestamp(link
->dhcp_lease
, CLOCK_BOOTTIME
, &t1
);
1120 if (r
< 0 && r
!= -ENODATA
)
1123 r
= sd_dhcp_lease_get_t2_timestamp(link
->dhcp_lease
, CLOCK_BOOTTIME
, &t2
);
1124 if (r
< 0 && r
!= -ENODATA
)
1127 r
= json_build(&w
, JSON_BUILD_OBJECT(
1128 JSON_BUILD_PAIR_FINITE_USEC("LeaseTimestampUSec", lease_timestamp_usec
),
1129 JSON_BUILD_PAIR_FINITE_USEC("Timeout1USec", t1
),
1130 JSON_BUILD_PAIR_FINITE_USEC("Timeout2USec", t2
)));
1134 return json_variant_set_field_non_null(v
, "Lease", w
);
1137 static int dhcp_client_pd_append_json(Link
*link
, JsonVariant
**v
) {
1138 _cleanup_(json_variant_unrefp
) JsonVariant
*addresses
= NULL
, *array
= NULL
;
1139 uint8_t ipv4masklen
, sixrd_prefixlen
;
1140 struct in6_addr sixrd_prefix
;
1141 const struct in_addr
*br_addresses
;
1142 size_t n_br_addresses
= 0;
1146 assert(link
->network
);
1149 if (!link
->network
->dhcp_use_6rd
|| !sd_dhcp_lease_has_6rd(link
->dhcp_lease
))
1152 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, &br_addresses
, &n_br_addresses
);
1156 FOREACH_ARRAY(br_address
, br_addresses
, n_br_addresses
) {
1157 r
= json_variant_append_arrayb(&addresses
, JSON_BUILD_IN4_ADDR(br_address
));
1162 r
= json_build(&array
, JSON_BUILD_OBJECT(
1163 JSON_BUILD_PAIR_IN6_ADDR("Prefix", &sixrd_prefix
),
1164 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", sixrd_prefixlen
),
1165 JSON_BUILD_PAIR_UNSIGNED("IPv4MaskLength", ipv4masklen
),
1166 JSON_BUILD_PAIR_VARIANT_NON_NULL("BorderRouters", addresses
)));
1170 return json_variant_set_field_non_null(v
, "6rdPrefix", array
);
1173 static int dhcp_client_private_options_append_json(Link
*link
, JsonVariant
**v
) {
1174 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1180 if (!link
->dhcp_lease
)
1183 LIST_FOREACH(options
, option
, link
->dhcp_lease
->private_options
) {
1185 r
= json_variant_append_arrayb(
1188 JSON_BUILD_PAIR_UNSIGNED("Option", option
->tag
),
1189 JSON_BUILD_PAIR_HEX("PrivateOptionData", option
->data
, option
->length
)));
1193 return json_variant_set_field_non_null(v
, "PrivateOptions", array
);
1196 static int dhcp_client_append_json(Link
*link
, JsonVariant
**v
) {
1197 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1203 if (!link
->dhcp_client
)
1206 r
= dhcp_client_lease_append_json(link
, &w
);
1210 r
= dhcp_client_pd_append_json(link
, &w
);
1214 r
= dhcp_client_private_options_append_json(link
, &w
);
1218 return json_variant_set_field_non_null(v
, "DHCPv4Client", w
);
1221 int link_build_json(Link
*link
, JsonVariant
**ret
) {
1222 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1223 _cleanup_free_
char *type
= NULL
, *flags
= NULL
;
1229 r
= net_get_type_string(link
->dev
, link
->iftype
, &type
);
1233 r
= link_flags_to_string_alloc(link
->flags
, &flags
);
1237 r
= json_build(&v
, JSON_BUILD_OBJECT(
1238 /* basic information */
1239 JSON_BUILD_PAIR_INTEGER("Index", link
->ifindex
),
1240 JSON_BUILD_PAIR_STRING("Name", link
->ifname
),
1241 JSON_BUILD_PAIR_STRV_NON_EMPTY("AlternativeNames", link
->alternative_names
),
1242 JSON_BUILD_PAIR_CONDITION(link
->master_ifindex
> 0,
1243 "MasterInterfaceIndex", JSON_BUILD_INTEGER(link
->master_ifindex
)),
1244 JSON_BUILD_PAIR_STRING_NON_EMPTY("Kind", link
->kind
),
1245 JSON_BUILD_PAIR_STRING("Type", type
),
1246 JSON_BUILD_PAIR_STRING_NON_EMPTY("Driver", link
->driver
),
1247 JSON_BUILD_PAIR_UNSIGNED("Flags", link
->flags
),
1248 JSON_BUILD_PAIR_STRING("FlagsString", flags
),
1249 JSON_BUILD_PAIR_UNSIGNED("KernelOperationalState", link
->kernel_operstate
),
1250 JSON_BUILD_PAIR_STRING("KernelOperationalStateString", kernel_operstate_to_string(link
->kernel_operstate
)),
1251 JSON_BUILD_PAIR_UNSIGNED("MTU", link
->mtu
),
1252 JSON_BUILD_PAIR_UNSIGNED("MinimumMTU", link
->min_mtu
),
1253 JSON_BUILD_PAIR_UNSIGNED("MaximumMTU", link
->max_mtu
),
1254 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("HardwareAddress", &link
->hw_addr
),
1255 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("PermanentHardwareAddress", &link
->permanent_hw_addr
),
1256 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("BroadcastAddress", &link
->bcast_addr
),
1257 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("IPv6LinkLocalAddress", &link
->ipv6ll_address
),
1258 /* wlan information */
1259 JSON_BUILD_PAIR_CONDITION(link
->wlan_iftype
> 0, "WirelessLanInterfaceType",
1260 JSON_BUILD_UNSIGNED(link
->wlan_iftype
)),
1261 JSON_BUILD_PAIR_CONDITION(link
->wlan_iftype
> 0, "WirelessLanInterfaceTypeString",
1262 JSON_BUILD_STRING(nl80211_iftype_to_string(link
->wlan_iftype
))),
1263 JSON_BUILD_PAIR_STRING_NON_EMPTY("SSID", link
->ssid
),
1264 JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL("BSSID", &link
->bssid
),
1266 JSON_BUILD_PAIR_STRING("AdministrativeState", link_state_to_string(link
->state
)),
1267 JSON_BUILD_PAIR_STRING("OperationalState", link_operstate_to_string(link
->operstate
)),
1268 JSON_BUILD_PAIR_STRING("CarrierState", link_carrier_state_to_string(link
->carrier_state
)),
1269 JSON_BUILD_PAIR_STRING("AddressState", link_address_state_to_string(link
->address_state
)),
1270 JSON_BUILD_PAIR_STRING("IPv4AddressState", link_address_state_to_string(link
->ipv4_address_state
)),
1271 JSON_BUILD_PAIR_STRING("IPv6AddressState", link_address_state_to_string(link
->ipv6_address_state
)),
1272 JSON_BUILD_PAIR_STRING("OnlineState", link_online_state_to_string(link
->online_state
))));
1276 r
= network_append_json(link
->network
, &v
);
1280 r
= device_append_json(link
->dev
, &v
);
1284 r
= dns_append_json(link
, &v
);
1288 r
= ntp_append_json(link
, &v
);
1292 r
= sip_append_json(link
, &v
);
1296 r
= domains_append_json(link
, /* is_route = */ false, &v
);
1300 r
= domains_append_json(link
, /* is_route = */ true, &v
);
1304 r
= ntas_append_json(link
, &v
);
1308 r
= dns_misc_append_json(link
, &v
);
1312 r
= captive_portal_append_json(link
, &v
);
1316 r
= pref64_append_json(link
, &v
);
1320 r
= addresses_append_json(link
->addresses
, &v
);
1324 r
= neighbors_append_json(link
->neighbors
, &v
);
1328 r
= nexthops_append_json(link
->manager
, link
->ifindex
, &v
);
1332 r
= routes_append_json(link
->manager
, link
->ifindex
, &v
);
1336 r
= dhcp_server_append_json(link
, &v
);
1340 r
= dhcp_client_append_json(link
, &v
);
1344 r
= dhcp6_client_append_json(link
, &v
);
1352 static int links_append_json(Manager
*manager
, JsonVariant
**v
) {
1353 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1354 _cleanup_free_ Link
**links
= NULL
;
1361 r
= hashmap_dump_sorted(manager
->links_by_index
, (void***) &links
, &n_links
);
1365 FOREACH_ARRAY(link
, links
, n_links
) {
1366 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
1368 r
= link_build_json(*link
, &e
);
1372 r
= json_variant_append_array(&array
, e
);
1377 return json_variant_set_field_non_null(v
, "Interfaces", array
);
1380 int manager_build_json(Manager
*manager
, JsonVariant
**ret
) {
1381 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1387 r
= links_append_json(manager
, &v
);
1391 r
= nexthops_append_json(manager
, /* ifindex = */ 0, &v
);
1395 r
= routes_append_json(manager
, /* ifindex = */ 0, &v
);
1399 r
= routing_policy_rules_append_json(manager
->rules
, &v
);