diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 97715a230cd..0178391e5f2 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -114,6 +114,13 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) { return family == AF_INET6 ? 16 : 4; } +#define FAMILY_ADDRESS_SIZE_SAFE(f) \ + ({ \ + int _f = (f); \ + _f == AF_INET ? sizeof(struct in_addr) : \ + _f == AF_INET6 ? sizeof(struct in6_addr) : 0; \ + }) + /* Workaround for clang, explicitly specify the maximum-size element here. * See also oss-fuzz#11344. */ #define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} }) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index a78ad6d93bf..701bffe5ee3 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -24,7 +24,7 @@ #define ADDRESSES_PER_LINK_MAX 2048U #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U -static int address_flags_to_string_alloc(uint32_t flags, int family, char **ret) { +int address_flags_to_string_alloc(uint32_t flags, int family, char **ret) { _cleanup_free_ char *str = NULL; static const struct { uint32_t flag; diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 64ed6164b5d..41c4ce6fa4d 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -61,6 +61,8 @@ const char* format_lifetime(char *buf, size_t l, usec_t lifetime_usec) _warn_unu #define FORMAT_LIFETIME(lifetime) \ format_lifetime((char[FORMAT_TIMESPAN_MAX+STRLEN("for ")]){}, FORMAT_TIMESPAN_MAX+STRLEN("for "), lifetime) +int address_flags_to_string_alloc(uint32_t flags, int family, char **ret); + int address_new(Address **ret); Address* address_free(Address *address); int address_get(Link *link, const Address *in, Address **ret); diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index 4828a0ed50c..daf4f0085ab 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -1,26 +1,480 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include + +#include "ip-protocol-list.h" #include "netif-util.h" +#include "networkd-address.h" #include "networkd-json.h" #include "networkd-link.h" #include "networkd-manager.h" +#include "networkd-neighbor.h" +#include "networkd-nexthop.h" #include "networkd-network.h" +#include "networkd-route-util.h" +#include "networkd-route.h" +#include "networkd-routing-policy-rule.h" #include "sort-util.h" +#include "user-util.h" +#include "wifi-util.h" -static int network_build_json(Network *network, JsonVariant **ret) { - assert(network); +static int address_build_json(Address *address, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ char *scope = NULL, *flags = NULL, *state = NULL; + int r; + + assert(address); assert(ret); + r = route_scope_to_string_alloc(address->scope, &scope); + if (r < 0) + return r; + + r = address_flags_to_string_alloc(address->flags, address->family, &flags); + if (r < 0) + return r; + + r = network_config_state_to_string_alloc(address->state, &state); + if (r < 0) + return r; + + r = json_build(&v, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_INTEGER("Family", address->family), + JSON_BUILD_PAIR_IN_ADDR("Address", &address->in_addr, address->family), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Peer", &address->in_addr_peer, address->family), + JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Broadcast", &address->broadcast), + JSON_BUILD_PAIR_UNSIGNED("PrefixLength", address->prefixlen), + JSON_BUILD_PAIR_UNSIGNED("Scope", address->scope), + JSON_BUILD_PAIR_STRING("ScopeString", scope), + JSON_BUILD_PAIR_UNSIGNED("Flags", address->flags), + JSON_BUILD_PAIR_STRING("FlagsString", flags), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Label", address->label), + JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUsec", address->lifetime_preferred_usec), + JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUsec", address->lifetime_valid_usec), + JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(address->source)), + JSON_BUILD_PAIR_STRING("ConfigState", state), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &address->provider, address->family))); + if (r < 0) + return r; + + *ret = TAKE_PTR(v); + return 0; +} + +static int addresses_build_json(Set *addresses, JsonVariant **ret) { + JsonVariant **elements; + Address *address; + size_t n = 0; + int r; + + assert(ret); + + if (set_isempty(addresses)) { + *ret = NULL; + return 0; + } + + elements = new(JsonVariant*, set_size(addresses)); + if (!elements) + return -ENOMEM; + + SET_FOREACH(address, addresses) { + r = address_build_json(address, elements + n); + if (r < 0) + goto finalize; + n++; + } + + r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("Addresses", JSON_BUILD_VARIANT_ARRAY(elements, n)))); + +finalize: + json_variant_unref_many(elements, n); + free(elements); + return r; +} + +static int neighbor_build_json(Neighbor *n, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ char *state = NULL; + int r; + + assert(n); + assert(ret); + + r = network_config_state_to_string_alloc(n->state, &state); + if (r < 0) + return r; + + r = json_build(&v, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_INTEGER("Family", n->family), + JSON_BUILD_PAIR_IN_ADDR("Destination", &n->in_addr, n->family), + JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n->ll_addr), + JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)), + JSON_BUILD_PAIR_STRING("ConfigState", state))); + if (r < 0) + return r; + + *ret = TAKE_PTR(v); + return 0; +} + +static int neighbors_build_json(Set *neighbors, JsonVariant **ret) { + JsonVariant **elements; + Neighbor *neighbor; + size_t n = 0; + int r; + + assert(ret); + + if (set_isempty(neighbors)) { + *ret = NULL; + return 0; + } + + elements = new(JsonVariant*, set_size(neighbors)); + if (!elements) + return -ENOMEM; + + SET_FOREACH(neighbor, neighbors) { + r = neighbor_build_json(neighbor, elements + n); + if (r < 0) + goto finalize; + n++; + } + + r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("Neighbors", JSON_BUILD_VARIANT_ARRAY(elements, n)))); + +finalize: + json_variant_unref_many(elements, n); + free(elements); + return r; +} + +static int nexthop_group_build_json(NextHop *nexthop, JsonVariant **ret) { + JsonVariant **elements; + struct nexthop_grp *g; + size_t n = 0; + int r; + + assert(nexthop); + assert(ret); + + if (hashmap_isempty(nexthop->group)) { + *ret = NULL; + return 0; + } + + elements = new(JsonVariant*, hashmap_size(nexthop->group)); + if (!elements) + return -ENOMEM; + + HASHMAP_FOREACH(g, nexthop->group) { + r = json_build(elements + n, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_UNSIGNED("ID", g->id), + JSON_BUILD_PAIR_UNSIGNED("Weight", g->weight+1))); + if (r < 0) + goto failure; + + n++; + } + + r = json_variant_new_array(ret, elements, n); + +failure: + json_variant_unref_many(elements, n); + free(elements); + return r; +} + +static int nexthop_build_json(NextHop *n, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *group = NULL; + _cleanup_free_ char *flags = NULL, *protocol = NULL, *state = NULL; + int r; + + assert(n); + assert(ret); + + r = route_flags_to_string_alloc(n->flags, &flags); + if (r < 0) + return r; + + r = route_protocol_to_string_alloc(n->protocol, &protocol); + if (r < 0) + return r; + + r = network_config_state_to_string_alloc(n->state, &state); + if (r < 0) + return r; + + r = nexthop_group_build_json(n, &group); + if (r < 0) + return r; + + r = json_build(&v, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_UNSIGNED("ID", n->id), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw, n->family), + JSON_BUILD_PAIR_UNSIGNED("Flags", n->flags), + JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)), + JSON_BUILD_PAIR_UNSIGNED("Protocol", n->protocol), + JSON_BUILD_PAIR_STRING("ProtocolString", protocol), + JSON_BUILD_PAIR_BOOLEAN("Blackhole", n->blackhole), + JSON_BUILD_PAIR_VARIANT_NON_NULL("Group", group), + JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)), + JSON_BUILD_PAIR_STRING("ConfigState", state))); + if (r < 0) + return r; + + *ret = TAKE_PTR(v); + return 0; +} + +static int nexthops_build_json(Set *nexthops, JsonVariant **ret) { + JsonVariant **elements; + NextHop *nexthop; + size_t n = 0; + int r; + + assert(ret); + + if (set_isempty(nexthops)) { + *ret = NULL; + return 0; + } + + elements = new(JsonVariant*, set_size(nexthops)); + if (!elements) + return -ENOMEM; + + SET_FOREACH(nexthop, nexthops) { + r = nexthop_build_json(nexthop, elements + n); + if (r < 0) + goto finalize; + n++; + } + + r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("NextHops", JSON_BUILD_VARIANT_ARRAY(elements, n)))); + +finalize: + json_variant_unref_many(elements, n); + free(elements); + return r; +} + +static int route_build_json(Route *route, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ char *scope = NULL, *protocol = NULL, *table = NULL, *flags = NULL, *state = NULL; + Manager *manager; + int r; + + assert(route); + assert(ret); + + manager = route->link ? route->link->manager : route->manager; + + assert(manager); + + r = route_scope_to_string_alloc(route->scope, &scope); + if (r < 0) + return r; + + r = route_protocol_to_string_alloc(route->protocol, &protocol); + if (r < 0) + return r; + + r = manager_get_route_table_to_string(manager, route->table, &table); + if (r < 0) + return r; + + r = route_flags_to_string_alloc(route->flags, &flags); + if (r < 0) + return r; + + r = network_config_state_to_string_alloc(route->state, &state); + if (r < 0) + return r; + + r = json_build(&v, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_INTEGER("Family", route->family), + JSON_BUILD_PAIR_IN_ADDR("Destination", &route->dst, route->family), + JSON_BUILD_PAIR_UNSIGNED("DestinationPrefixLength", route->dst_prefixlen), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &route->gw, route->gw_family), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Source", &route->src, route->family), + JSON_BUILD_PAIR_CONDITION(in_addr_is_set(route->family, &route->src), + "SourcePrefixLength", JSON_BUILD_UNSIGNED(route->src_prefixlen)), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("PreferredSource", &route->prefsrc, route->family), + JSON_BUILD_PAIR_UNSIGNED("Scope", route->scope), + JSON_BUILD_PAIR_STRING("ScopeString", scope), + JSON_BUILD_PAIR_UNSIGNED("Protocol", route->protocol), + JSON_BUILD_PAIR_STRING("ProtocolString", protocol), + JSON_BUILD_PAIR_UNSIGNED("Type", route->type), + JSON_BUILD_PAIR_STRING("TypeString", route_type_to_string(route->type)), + JSON_BUILD_PAIR_UNSIGNED("Priority", route->priority), + JSON_BUILD_PAIR_UNSIGNED("Table", route->table), + JSON_BUILD_PAIR_STRING("TableString", table), + JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route->mtu), + JSON_BUILD_PAIR_UNSIGNED("Preference", route->pref), + JSON_BUILD_PAIR_UNSIGNED("Flags", route->flags), + JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)), + JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", route->lifetime_usec), + JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(route->source)), + JSON_BUILD_PAIR_STRING("ConfigState", state), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &route->provider, route->family))); + if (r < 0) + return r; + + *ret = TAKE_PTR(v); + return 0; +} + +static int routes_build_json(Set *routes, JsonVariant **ret) { + JsonVariant **elements; + Route *route; + size_t n = 0; + int r; + + assert(ret); + + if (set_isempty(routes)) { + *ret = NULL; + return 0; + } + + elements = new(JsonVariant*, set_size(routes)); + if (!elements) + return -ENOMEM; + + SET_FOREACH(route, routes) { + r = route_build_json(route, elements + n); + if (r < 0) + goto finalize; + n++; + } + + r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("Routes", JSON_BUILD_VARIANT_ARRAY(elements, n)))); + +finalize: + json_variant_unref_many(elements, n); + free(elements); + return r; +} + +static int routing_policy_rule_build_json(RoutingPolicyRule *rule, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ char *table = NULL, *protocol = NULL, *state = NULL; + int r; + + assert(rule); + assert(rule->manager); + assert(ret); + + r = manager_get_route_table_to_string(rule->manager, rule->table, &table); + if (r < 0 && r != -EINVAL) + return r; + + r = route_protocol_to_string_alloc(rule->protocol, &protocol); + if (r < 0) + return r; + + r = network_config_state_to_string_alloc(rule->state, &state); + if (r < 0) + return r; + + r = json_build(&v, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_INTEGER("Family", rule->family), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("FromPrefix", &rule->from, rule->family), + JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule->family, &rule->from), + "FromPrefixLength", JSON_BUILD_UNSIGNED(rule->from_prefixlen)), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ToPrefix", &rule->to, rule->family), + JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule->family, &rule->to), + "ToPrefixLength", JSON_BUILD_UNSIGNED(rule->to_prefixlen)), + JSON_BUILD_PAIR_UNSIGNED("Protocol", rule->protocol), + JSON_BUILD_PAIR_STRING("ProtocolString", protocol), + JSON_BUILD_PAIR_UNSIGNED("TOS", rule->tos), + JSON_BUILD_PAIR_UNSIGNED("Type", rule->type), + JSON_BUILD_PAIR_STRING("TypeString", fr_act_type_full_to_string(rule->type)), + JSON_BUILD_PAIR_UNSIGNED("IPProtocol", rule->ipproto), + JSON_BUILD_PAIR_STRING("IPProtocolString", ip_protocol_to_name(rule->ipproto)), + JSON_BUILD_PAIR_UNSIGNED("Priority", rule->priority), + JSON_BUILD_PAIR_UNSIGNED("FirewallMark", rule->fwmark), + JSON_BUILD_PAIR_UNSIGNED("FirewallMask", rule->fwmask), + JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Table", rule->table), + JSON_BUILD_PAIR_STRING_NON_EMPTY("TableString", table), + JSON_BUILD_PAIR_BOOLEAN("Invert", rule->invert_rule), + JSON_BUILD_PAIR_CONDITION(rule->suppress_prefixlen >= 0, + "SuppressPrefixLength", JSON_BUILD_UNSIGNED(rule->suppress_prefixlen)), + JSON_BUILD_PAIR_CONDITION(rule->suppress_ifgroup >= 0, + "SuppressInterfaceGroup", JSON_BUILD_UNSIGNED(rule->suppress_ifgroup)), + JSON_BUILD_PAIR_CONDITION(rule->sport.start != 0 || rule->sport.end != 0, "SourcePort", + JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule->sport.start), JSON_BUILD_UNSIGNED(rule->sport.end))), + JSON_BUILD_PAIR_CONDITION(rule->dport.start != 0 || rule->dport.end != 0, "DestinationPort", + JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule->dport.start), JSON_BUILD_UNSIGNED(rule->dport.end))), + JSON_BUILD_PAIR_CONDITION(rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID, "User", + JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule->uid_range.start), JSON_BUILD_UNSIGNED(rule->uid_range.end))), + JSON_BUILD_PAIR_STRING_NON_EMPTY("IncomingInterface", rule->iif), + JSON_BUILD_PAIR_STRING_NON_EMPTY("OutgoingInterface", rule->oif), + JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(rule->source)), + JSON_BUILD_PAIR_STRING("ConfigState", state))); + if (r < 0) + return r; + + *ret = TAKE_PTR(v); + return 0; +} + +static int routing_policy_rules_build_json(Set *rules, JsonVariant **ret) { + JsonVariant **elements; + RoutingPolicyRule *rule; + size_t n = 0; + int r; + + assert(ret); + + if (set_isempty(rules)) { + *ret = NULL; + return 0; + } + + elements = new(JsonVariant*, set_size(rules)); + if (!elements) + return -ENOMEM; + + SET_FOREACH(rule, rules) { + r = routing_policy_rule_build_json(rule, elements + n); + if (r < 0) + goto finalize; + n++; + } + + r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("RoutingPolicyRules", JSON_BUILD_VARIANT_ARRAY(elements, n)))); + +finalize: + json_variant_unref_many(elements, n); + free(elements); + return r; +} + +static int network_build_json(Network *network, JsonVariant **ret) { + assert(ret); + + if (!network) { + *ret = NULL; + return 0; + } + return json_build(ret, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("NetworkFile", JSON_BUILD_STRING(network->filename)))); + JSON_BUILD_PAIR_STRING("NetworkFile", network->filename))); } static int device_build_json(sd_device *device, JsonVariant **ret) { const char *link = NULL, *path = NULL, *vendor = NULL, *model = NULL; - assert(device); assert(ret); + if (!device) { + *ret = NULL; + return 0; + } + (void) sd_device_get_property_value(device, "ID_NET_LINK_FILE", &link); (void) sd_device_get_property_value(device, "ID_PATH", &path); @@ -31,15 +485,15 @@ static int device_build_json(sd_device *device, JsonVariant **ret) { (void) sd_device_get_property_value(device, "ID_MODEL", &model); return json_build(ret, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("LinkFile", JSON_BUILD_STRING(link)), - JSON_BUILD_PAIR("Path", JSON_BUILD_STRING(path)), - JSON_BUILD_PAIR("Vendor", JSON_BUILD_STRING(vendor)), - JSON_BUILD_PAIR("Model", JSON_BUILD_STRING(model)))); + JSON_BUILD_PAIR_STRING_NON_EMPTY("LinkFile", link), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", path), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Vendor", vendor), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Model", model))); } int link_build_json(Link *link, JsonVariant **ret) { - _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; - _cleanup_free_ char *type = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; + _cleanup_free_ char *type = NULL, *flags = NULL; int r; assert(link); @@ -49,45 +503,106 @@ int link_build_json(Link *link, JsonVariant **ret) { if (r == -ENOMEM) return r; - r = json_build(&v, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("Index", JSON_BUILD_INTEGER(link->ifindex)), - JSON_BUILD_PAIR("Name", JSON_BUILD_STRING(link->ifname)), - JSON_BUILD_PAIR("AlternativeNames", JSON_BUILD_STRV(link->alternative_names)), - JSON_BUILD_PAIR("Type", JSON_BUILD_STRING(type)), - JSON_BUILD_PAIR("Driver", JSON_BUILD_STRING(link->driver)), - JSON_BUILD_PAIR("SetupState", JSON_BUILD_STRING(link_state_to_string(link->state))), - JSON_BUILD_PAIR("OperationalState", JSON_BUILD_STRING(link_operstate_to_string(link->operstate))), - JSON_BUILD_PAIR("CarrierState", JSON_BUILD_STRING(link_carrier_state_to_string(link->carrier_state))), - JSON_BUILD_PAIR("AddressState", JSON_BUILD_STRING(link_address_state_to_string(link->address_state))), - JSON_BUILD_PAIR("IPv4AddressState", JSON_BUILD_STRING(link_address_state_to_string(link->ipv4_address_state))), - JSON_BUILD_PAIR("IPv6AddressState", JSON_BUILD_STRING(link_address_state_to_string(link->ipv6_address_state))), - JSON_BUILD_PAIR("OnlineState", JSON_BUILD_STRING(link_online_state_to_string(link->online_state))))); + r = link_flags_to_string_alloc(link->flags, &flags); if (r < 0) return r; - if (link->network) { - _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + r = json_build(&v, JSON_BUILD_OBJECT( + /* basic information */ + JSON_BUILD_PAIR_INTEGER("Index", link->ifindex), + JSON_BUILD_PAIR_STRING("Name", link->ifname), + JSON_BUILD_PAIR_STRV_NON_EMPTY("AlternativeNames", link->alternative_names), + JSON_BUILD_PAIR_CONDITION(link->master_ifindex > 0, + "MasterInterfaceIndex", JSON_BUILD_INTEGER(link->master_ifindex)), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Kind", link->kind), + JSON_BUILD_PAIR_STRING("Type", type), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Driver", link->driver), + JSON_BUILD_PAIR_UNSIGNED("Flags", link->flags), + JSON_BUILD_PAIR_STRING("FlagsString", flags), + JSON_BUILD_PAIR_UNSIGNED("KernelOperationalState", link->kernel_operstate), + JSON_BUILD_PAIR_STRING("KernelOperationalStateString", kernel_operstate_to_string(link->kernel_operstate)), + JSON_BUILD_PAIR_UNSIGNED("MTU", link->mtu), + JSON_BUILD_PAIR_UNSIGNED("MinimumMTU", link->min_mtu), + JSON_BUILD_PAIR_UNSIGNED("MaximumMTU", link->max_mtu), + JSON_BUILD_PAIR_HW_ADDR_NON_NULL("HardwareAddress", &link->hw_addr), + JSON_BUILD_PAIR_HW_ADDR_NON_NULL("PermanentHardwareAddress", &link->permanent_hw_addr), + JSON_BUILD_PAIR_HW_ADDR_NON_NULL("BroadcastAddress", &link->bcast_addr), + JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("IPv6LinkLocalAddress", &link->ipv6ll_address), + /* wlan information */ + JSON_BUILD_PAIR_CONDITION(link->wlan_iftype > 0, "WirelessLanInterfaceType", + JSON_BUILD_UNSIGNED(link->wlan_iftype)), + JSON_BUILD_PAIR_CONDITION(link->wlan_iftype > 0, "WirelessLanInterfaceTypeString", + JSON_BUILD_STRING(nl80211_iftype_to_string(link->wlan_iftype))), + JSON_BUILD_PAIR_STRING_NON_EMPTY("SSID", link->ssid), + JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL("BSSID", &link->bssid), + /* link state */ + JSON_BUILD_PAIR_STRING("SetupState", link_state_to_string(link->state)), + JSON_BUILD_PAIR_STRING("OperationalState", link_operstate_to_string(link->operstate)), + JSON_BUILD_PAIR_STRING("CarrierState", link_carrier_state_to_string(link->carrier_state)), + JSON_BUILD_PAIR_STRING("AddressState", link_address_state_to_string(link->address_state)), + JSON_BUILD_PAIR_STRING("IPv4AddressState", link_address_state_to_string(link->ipv4_address_state)), + JSON_BUILD_PAIR_STRING("IPv6AddressState", link_address_state_to_string(link->ipv6_address_state)), + JSON_BUILD_PAIR_STRING("OnlineState", link_online_state_to_string(link->online_state)))); + if (r < 0) + return r; - r = network_build_json(link->network, &w); - if (r < 0) - return r; + r = network_build_json(link->network, &w); + if (r < 0) + return r; - r = json_variant_merge(&v, w); - if (r < 0) - return r; - } + r = json_variant_merge(&v, w); + if (r < 0) + return r; - if (link->sd_device) { - _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + w = json_variant_unref(w); - r = device_build_json(link->sd_device, &w); - if (r < 0) - return r; + r = device_build_json(link->sd_device, &w); + if (r < 0) + return r; - r = json_variant_merge(&v, w); - if (r < 0) - return r; - } + r = json_variant_merge(&v, w); + if (r < 0) + return r; + + w = json_variant_unref(w); + + r = addresses_build_json(link->addresses, &w); + if (r < 0) + return r; + + r = json_variant_merge(&v, w); + if (r < 0) + return r; + + w = json_variant_unref(w); + + r = neighbors_build_json(link->neighbors, &w); + if (r < 0) + return r; + + r = json_variant_merge(&v, w); + if (r < 0) + return r; + + w = json_variant_unref(w); + + r = nexthops_build_json(link->nexthops, &w); + if (r < 0) + return r; + + r = json_variant_merge(&v, w); + if (r < 0) + return r; + + w = json_variant_unref(w); + + r = routes_build_json(link->routes, &w); + if (r < 0) + return r; + + r = json_variant_merge(&v, w); + if (r < 0) + return r; *ret = TAKE_PTR(v); return 0; @@ -105,7 +620,7 @@ static int link_json_compare(JsonVariant * const *a, JsonVariant * const *b) { return CMP(index_a, index_b); } -int manager_build_json(Manager *manager, JsonVariant **ret) { +static int links_build_json(Manager *manager, JsonVariant **ret) { JsonVariant **elements; Link *link; size_t n = 0; @@ -134,3 +649,46 @@ finalize: free(elements); return r; } + +int manager_build_json(Manager *manager, JsonVariant **ret) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; + int r; + + assert(manager); + assert(ret); + + r = links_build_json(manager, &v); + if (r < 0) + return r; + + r = nexthops_build_json(manager->nexthops, &w); + if (r < 0) + return r; + + r = json_variant_merge(&v, w); + if (r < 0) + return r; + + w = json_variant_unref(w); + + r = routes_build_json(manager->routes, &w); + if (r < 0) + return r; + + r = json_variant_merge(&v, w); + if (r < 0) + return r; + + w = json_variant_unref(w); + + r = routing_policy_rules_build_json(manager->rules, &w); + if (r < 0) + return r; + + r = json_variant_merge(&v, w); + if (r < 0) + return r; + + *ret = TAKE_PTR(v); + return 0; +} diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 174e695c379..3489dfa0d2d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2670,3 +2670,53 @@ static const char* const link_state_table[_LINK_STATE_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState); + +int link_flags_to_string_alloc(uint32_t flags, char **ret) { + _cleanup_free_ char *str = NULL; + static const struct { + uint32_t flag; + const char *name; + } map[] = { + { IFF_UP, "up" }, /* interface is up. */ + { IFF_BROADCAST, "broadcast" }, /* broadcast address valid.*/ + { IFF_DEBUG, "debug" }, /* turn on debugging. */ + { IFF_LOOPBACK, "loopback" }, /* interface is a loopback net. */ + { IFF_POINTOPOINT, "point-to-point" }, /* interface has p-p link. */ + { IFF_NOTRAILERS, "no-trailers" }, /* avoid use of trailers. */ + { IFF_RUNNING, "running" }, /* interface RFC2863 OPER_UP. */ + { IFF_NOARP, "no-arp" }, /* no ARP protocol. */ + { IFF_PROMISC, "promiscuous" }, /* receive all packets. */ + { IFF_ALLMULTI, "all-multicast" }, /* receive all multicast packets. */ + { IFF_MASTER, "master" }, /* master of a load balancer. */ + { IFF_SLAVE, "slave" }, /* slave of a load balancer. */ + { IFF_MULTICAST, "multicast" }, /* supports multicast.*/ + { IFF_PORTSEL, "portsel" }, /* can set media type. */ + { IFF_AUTOMEDIA, "auto-media" }, /* auto media select active. */ + { IFF_DYNAMIC, "dynamic" }, /* dialup device with changing addresses. */ + { IFF_LOWER_UP, "lower-up" }, /* driver signals L1 up. */ + { IFF_DORMANT, "dormant" }, /* driver signals dormant. */ + { IFF_ECHO, "echo" }, /* echo sent packets. */ + }; + + assert(ret); + + for (size_t i = 0; i < ELEMENTSOF(map); i++) + if (flags & map[i].flag && + !strextend_with_separator(&str, ",", map[i].name)) + return -ENOMEM; + + *ret = TAKE_PTR(str); + return 0; +} + +static const char * const kernel_operstate_table[] = { + [IF_OPER_UNKNOWN] = "unknown", + [IF_OPER_NOTPRESENT] = "not-present", + [IF_OPER_DOWN] = "down", + [IF_OPER_LOWERLAYERDOWN] = "lower-layer-down", + [IF_OPER_TESTING] = "testing", + [IF_OPER_DORMANT] = "dormant", + [IF_OPER_UP] = "up", +}; + +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(kernel_operstate, int); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 072c39f387c..4f746db1107 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -227,3 +227,6 @@ int link_reconfigure_after_sleep(Link *link); int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata); int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); + +int link_flags_to_string_alloc(uint32_t flags, char **ret); +const char *kernel_operstate_to_string(int t) _const_; diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 72ef39f4579..90086f35a75 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -29,8 +29,18 @@ static const char *const fr_act_type_table[__FR_ACT_MAX] = { [FR_ACT_PROHIBIT] = "prohibit", }; +static const char *const fr_act_type_full_table[__FR_ACT_MAX] = { + [FR_ACT_TO_TBL] = "table", + [FR_ACT_GOTO] = "goto", + [FR_ACT_NOP] = "nop", + [FR_ACT_BLACKHOLE] = "blackhole", + [FR_ACT_UNREACHABLE] = "unreachable", + [FR_ACT_PROHIBIT] = "prohibit", +}; + assert_cc(__FR_ACT_MAX <= UINT8_MAX); DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fr_act_type, int); +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(fr_act_type_full, int); RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) { if (!rule) diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index ac65fe8af48..f52943bd2e6 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -54,6 +54,8 @@ typedef struct RoutingPolicyRule { int32_t suppress_ifgroup; } RoutingPolicyRule; +const char *fr_act_type_full_to_string(int t) _const_; + RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule); void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state); diff --git a/src/shared/json.c b/src/shared/json.c index 58d6117ac90..8d9a90203ae 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -3242,7 +3242,7 @@ int json_buildv(JsonVariant **ret, va_list ap) { }; for (;;) { - _cleanup_(json_variant_unrefp) JsonVariant *add = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *add = NULL, *add_more = NULL; size_t n_subtract = 0; /* how much to subtract from current->n_suppress, i.e. how many elements would * have been added to the current variant */ JsonStack *current; @@ -3707,6 +3707,34 @@ int json_buildv(JsonVariant **ret, va_list ap) { break; } + case _JSON_BUILD_HW_ADDR: { + const struct hw_addr_data *hw_addr; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + assert_se(hw_addr = va_arg(ap, struct hw_addr_data*)); + + if (current->n_suppress == 0) { + r = json_variant_new_array_bytes(&add, hw_addr->bytes, hw_addr->length); + if (r < 0) + goto finish; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + case _JSON_BUILD_OBJECT_BEGIN: if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { @@ -3806,16 +3834,298 @@ int json_buildv(JsonVariant **ret, va_list ap) { current->expect = EXPECT_OBJECT_VALUE; break; - }} + } - /* If a variant was generated, add it to our current variant, but only if we are not supposed to suppress additions */ + case _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO: { + const char *n; + uint64_t u; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + u = va_arg(ap, uint64_t); + + if (u != 0 && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_unsigned(&add_more, u); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_FINITE_USEC: { + const char *n; + usec_t u; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + u = va_arg(ap, usec_t); + + if (u != USEC_INFINITY && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_unsigned(&add_more, u); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_STRING_NON_EMPTY: { + const char *n, *s; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + s = va_arg(ap, const char *); + + if (!isempty(s) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_string(&add_more, s); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_STRV_NON_EMPTY: { + const char *n; + char **l; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + l = va_arg(ap, char **); + + if (!strv_isempty(l) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_strv(&add_more, l); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_VARIANT_NON_NULL: { + JsonVariant *v; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + v = va_arg(ap, JsonVariant *); + + if (v && !json_variant_is_null(v) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + add_more = json_variant_ref(v); + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL: { + const struct in_addr *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct in_addr *); + + if (in4_addr_is_set(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a, sizeof(struct in_addr)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL: { + const struct in6_addr *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct in6_addr *); + + if (in6_addr_is_set(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a, sizeof(struct in6_addr)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_IN_ADDR_NON_NULL: { + const union in_addr_union *a; + const char *n; + int f; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const union in_addr_union *); + f = va_arg(ap, int); + + if (in_addr_is_set(f, a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a->bytes, FAMILY_ADDRESS_SIZE(f)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL: { + const struct ether_addr *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct ether_addr *); + + if (!ether_addr_is_null(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a->ether_addr_octet, sizeof(struct ether_addr)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_HW_ADDR_NON_NULL: { + const struct hw_addr_data *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct hw_addr_data *); + + if (!hw_addr_is_null(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a->bytes, a->length); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + } + + /* If variants were generated, add them to our current variant, but only if we are not supposed to suppress additions */ if (add && current->n_suppress == 0) { - if (!GREEDY_REALLOC(current->elements, current->n_elements + 1)) { + if (!GREEDY_REALLOC(current->elements, current->n_elements + 1 + !!add_more)) { r = -ENOMEM; goto finish; } current->elements[current->n_elements++] = TAKE_PTR(add); + if (add_more) + current->elements[current->n_elements++] = TAKE_PTR(add_more); } /* If we are supposed to suppress items, let's subtract how many items where generated from that diff --git a/src/shared/json.h b/src/shared/json.h index 2248515ef77..8760354b661 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -9,9 +9,13 @@ #include "sd-id128.h" +#include "ether-addr-util.h" +#include "in-addr-util.h" +#include "log.h" #include "macro.h" #include "string-util.h" -#include "log.h" +#include "strv.h" +#include "time-util.h" /* In case you wonder why we have our own JSON implementation, here are a couple of reasons why this implementation has @@ -236,6 +240,18 @@ enum { _JSON_BUILD_HEX, _JSON_BUILD_ID128, _JSON_BUILD_BYTE_ARRAY, + _JSON_BUILD_HW_ADDR, + _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, + _JSON_BUILD_PAIR_FINITE_USEC, + _JSON_BUILD_PAIR_STRING_NON_EMPTY, + _JSON_BUILD_PAIR_STRV_NON_EMPTY, + _JSON_BUILD_PAIR_VARIANT_NON_NULL, + _JSON_BUILD_PAIR_VARIANT_ARRAY_NON_EMPTY, + _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, + _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, + _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, + _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, + _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, _JSON_BUILD_MAX, }; @@ -260,6 +276,46 @@ enum { #define JSON_BUILD_ID128(id) _JSON_BUILD_ID128, (const sd_id128_t*) { &(id) } #define JSON_BUILD_BYTE_ARRAY(v, n) _JSON_BUILD_BYTE_ARRAY, (const void*) { v }, (size_t) { n } #define JSON_BUILD_CONST_STRING(s) _JSON_BUILD_VARIANT, JSON_VARIANT_STRING_CONST(s) +#define JSON_BUILD_IN4_ADDR(v) JSON_BUILD_BYTE_ARRAY((const struct in_addr*) { v }, sizeof(struct in_addr)) +#define JSON_BUILD_IN6_ADDR(v) JSON_BUILD_BYTE_ARRAY((const struct in6_addr*) { v }, sizeof(struct in6_addr)) +#define JSON_BUILD_IN_ADDR(v, f) JSON_BUILD_BYTE_ARRAY(((const union in_addr_union*) { v })->bytes, FAMILY_ADDRESS_SIZE_SAFE(f)) +#define JSON_BUILD_ETHER_ADDR(v) JSON_BUILD_BYTE_ARRAY(((const struct ether_addr*) { v })->ether_addr_octet, sizeof(struct ether_addr)) +#define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v } + +#define JSON_BUILD_PAIR_STRING(name, s) JSON_BUILD_PAIR(name, JSON_BUILD_STRING(s)) +#define JSON_BUILD_PAIR_INTEGER(name, i) JSON_BUILD_PAIR(name, JSON_BUILD_INTEGER(i)) +#define JSON_BUILD_PAIR_UNSIGNED(name, u) JSON_BUILD_PAIR(name, JSON_BUILD_UNSIGNED(u)) +#define JSON_BUILD_PAIR_REAL(name, d) JSON_BUILD_PAIR(name, JSON_BUILD_REAL(d)) +#define JSON_BUILD_PAIR_BOOLEAN(name, b) JSON_BUILD_PAIR(name, JSON_BUILD_BOOLEAN(b)) +#define JSON_BUILD_PAIR_ARRAY(name, ...) JSON_BUILD_PAIR(name, JSON_BUILD_ARRAY(__VA_ARGS__)) +#define JSON_BUILD_PAIR_EMPTY_ARRAY(name) JSON_BUILD_PAIR(name, JSON_BUILD_EMPTY_ARRAY) +#define JSON_BUILD_PAIR_OBJECT(name, ...) JSON_BUILD_PAIR(name, JSON_BUILD_OBJECT(__VA_ARGS__)) +#define JSON_BUILD_PAIR_EMPTY_OBJECT(name) JSON_BUILD_PAIR(name, JSON_BUILD_EMPTY_OBJECT) +#define JSON_BUILD_PAIR_NULL(name) JSON_BUILD_PAIR(name, JSON_BUILD_NULL) +#define JSON_BUILD_PAIR_VARIANT(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_VARIANT(v)) +#define JSON_BUILD_PAIR_VARIANT_ARRAY(name, v, n) JSON_BUILD_PAIR(name, JSON_BUILD_VARIANT_ARRAY(v, n)) +#define JSON_BUILD_PAIR_LITERAL(name, l) JSON_BUILD_PAIR(name, JSON_BUILD_LITERAL(l)) +#define JSON_BUILD_PAIR_STRV(name, l) JSON_BUILD_PAIR(name, JSON_BUILD_STRV(l)) +#define JSON_BUILD_PAIR_BASE64(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_BASE64(p, n)) +#define JSON_BUILD_PAIR_HEX(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_HEX(p, n)) +#define JSON_BUILD_PAIR_ID128(name, id) JSON_BUILD_PAIR(name, JSON_BUILD_ID128(id)) +#define JSON_BUILD_PAIR_BYTE_ARRAY(name, v, n) JSON_BUILD_PAIR(name, JSON_BUILD_BYTE_ARRAY(v, n)) +#define JSON_BUILD_PAIR_IN4_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_IN4_ADDR(v)) +#define JSON_BUILD_PAIR_IN6_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_IN6_ADDR(v)) +#define JSON_BUILD_PAIR_IN_ADDR(name, v, f) JSON_BUILD_PAIR(name, JSON_BUILD_IN_ADDR(v, f)) +#define JSON_BUILD_PAIR_ETHER_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_ETHER_ADDR(v)) +#define JSON_BUILD_PAIR_HW_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_HW_ADDR(v)) + +#define JSON_BUILD_PAIR_UNSIGNED_NON_ZERO(name, u) _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, (const char*) { name }, (uint64_t) { u } +#define JSON_BUILD_PAIR_FINITE_USEC(name, u) _JSON_BUILD_PAIR_FINITE_USEC, (const char*) { name }, (usec_t) { u } +#define JSON_BUILD_PAIR_STRING_NON_EMPTY(name, s) _JSON_BUILD_PAIR_STRING_NON_EMPTY, (const char*) { name }, (const char*) { s } +#define JSON_BUILD_PAIR_STRV_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_NON_EMPTY, (const char*) { name }, (char**) { l } +#define JSON_BUILD_PAIR_VARIANT_NON_NULL(name, v) _JSON_BUILD_PAIR_VARIANT_NON_NULL, (const char*) { name }, (JsonVariant*) { v } +#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, (const char*) { name }, (const struct in_addr*) { v } +#define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v } +#define JSON_BUILD_PAIR_IN_ADDR_NON_NULL(name, v, f) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, (const union in_addr_union*) { v }, (int) { f } +#define JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, (const char*) { name }, (const struct ether_addr*) { v } +#define JSON_BUILD_PAIR_HW_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, (const char*) { name }, (const struct hw_addr_data*) { v } int json_build(JsonVariant **ret, ...); int json_buildv(JsonVariant **ret, va_list ap); diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index d7ec7e9e25c..943582afead 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2091,6 +2091,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): for i in range(1,254): self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) + # TODO: check json string + check_output(*networkctl_cmd, '--json=short', 'status', env=env) + def test_address_ipv4acd(self): check_output('ip netns add ns99') check_output('ip link add veth99 type veth peer veth-peer') @@ -2288,6 +2291,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, 'iif test1') self.assertRegex(output, 'lookup 10') + # TODO: check json string + check_output(*networkctl_cmd, '--json=short', 'status', env=env) + def test_routing_policy_rule_issue_11280(self): copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev', 'routing-policy-rule-dummy98.network', '12-dummy.netdev') @@ -2513,6 +2519,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output) self.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output) + # TODO: check json string + check_output(*networkctl_cmd, '--json=short', 'status', env=env) + copy_unit_to_networkd_unit_path('25-address-static.network') check_output(*networkctl_cmd, 'reload', env=env) time.sleep(1) @@ -2746,6 +2755,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT') self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT') + # TODO: check json string + check_output(*networkctl_cmd, '--json=short', 'status', env=env) + def test_neighbor_reconfigure(self): copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev') start_networkd() @@ -2782,6 +2794,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT') + # TODO: check json string + check_output(*networkctl_cmd, '--json=short', 'status', env=env) + def test_link_local_addressing(self): copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev', '25-link-local-addressing-no.network', '12-dummy.netdev') @@ -3124,6 +3139,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output) self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output) + # TODO: check json string + check_output(*networkctl_cmd, '--json=short', 'status', env=env) + copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network', '12-dummy.netdev', '25-nexthop-dummy.network') start_networkd()