]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/nexthop: serialize/deserialize nexthops
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 11 Nov 2024 16:52:07 +0000 (01:52 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 14 Nov 2024 02:59:59 +0000 (11:59 +0900)
src/network/networkd-json.c
src/network/networkd-json.h
src/network/networkd-serialize.c

index 460fbe59685d8855d75c119b5896e3823552d928..160bcbdccadc0c8ec79906871c2d97c1c7da654a 100644 (file)
@@ -164,45 +164,58 @@ static int nexthop_group_build_json(NextHop *nexthop, sd_json_variant **ret) {
         return 0;
 }
 
-static int nexthop_append_json(NextHop *n, sd_json_variant **array) {
-        _cleanup_(sd_json_variant_unrefp) sd_json_variant *group = NULL;
-        _cleanup_free_ char *flags = NULL, *protocol = NULL, *state = NULL;
+static int nexthop_append_json(NextHop *n, bool serializing, sd_json_variant **array) {
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
         int r;
 
         assert(n);
         assert(array);
 
-        r = route_flags_to_string_alloc(n->flags, &flags);
+        r = sd_json_buildo(
+                        &v,
+                        SD_JSON_BUILD_PAIR_UNSIGNED("ID", n->id),
+                        SD_JSON_BUILD_PAIR_INTEGER("Family", n->family),
+                        SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)),
+                        JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &n->provider, n->family));
         if (r < 0)
                 return r;
 
-        r = route_protocol_to_string_alloc(n->protocol, &protocol);
-        if (r < 0)
-                return r;
+        if (!serializing) {
+                _cleanup_(sd_json_variant_unrefp) sd_json_variant *group = NULL;
+                _cleanup_free_ char *flags = NULL, *protocol = NULL, *state = NULL;
 
-        r = network_config_state_to_string_alloc(n->state, &state);
-        if (r < 0)
-                return r;
+                r = route_flags_to_string_alloc(n->flags, &flags);
+                if (r < 0)
+                        return r;
 
-        r = nexthop_group_build_json(n, &group);
-        if (r < 0)
-                return r;
+                r = route_protocol_to_string_alloc(n->protocol, &protocol);
+                if (r < 0)
+                        return r;
 
-        return sd_json_variant_append_arraybo(
-                        array,
-                        SD_JSON_BUILD_PAIR_UNSIGNED("ID", n->id),
-                        JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw.address, n->family),
-                        SD_JSON_BUILD_PAIR_UNSIGNED("Flags", n->flags),
-                        SD_JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
-                        SD_JSON_BUILD_PAIR_UNSIGNED("Protocol", n->protocol),
-                        SD_JSON_BUILD_PAIR_STRING("ProtocolString", protocol),
-                        SD_JSON_BUILD_PAIR_BOOLEAN("Blackhole", n->blackhole),
-                        JSON_BUILD_PAIR_VARIANT_NON_NULL("Group", group),
-                        SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)),
-                        SD_JSON_BUILD_PAIR_STRING("ConfigState", state));
+                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 = sd_json_variant_merge_objectbo(
+                                &v,
+                                JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw.address, n->family),
+                                SD_JSON_BUILD_PAIR_UNSIGNED("Flags", n->flags),
+                                SD_JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
+                                SD_JSON_BUILD_PAIR_UNSIGNED("Protocol", n->protocol),
+                                SD_JSON_BUILD_PAIR_STRING("ProtocolString", protocol),
+                                SD_JSON_BUILD_PAIR_BOOLEAN("Blackhole", n->blackhole),
+                                JSON_BUILD_PAIR_VARIANT_NON_NULL("Group", group),
+                                SD_JSON_BUILD_PAIR_STRING("ConfigState", state));
+        }
+
+        return sd_json_variant_append_array(array, v);
 }
 
-static int nexthops_append_json(Manager *manager, int ifindex, sd_json_variant **v) {
+int nexthops_append_json(Manager *manager, int ifindex, sd_json_variant **v) {
         _cleanup_(sd_json_variant_unrefp) sd_json_variant *array = NULL;
         NextHop *nexthop;
         int r;
@@ -211,10 +224,21 @@ static int nexthops_append_json(Manager *manager, int ifindex, sd_json_variant *
         assert(v);
 
         HASHMAP_FOREACH(nexthop, manager->nexthops_by_id) {
-                if (nexthop->ifindex != ifindex)
-                        continue;
+                if (ifindex >= 0) {
+                        if (nexthop->ifindex != ifindex)
+                                continue;
+                } else {
+                        /* negative ifindex means we are serializing now. */
+
+                        if (nexthop->source == NETWORK_CONFIG_SOURCE_FOREIGN)
+                                continue;
+                        if (!nexthop_exists(nexthop))
+                                continue;
+
+                        log_nexthop_debug(nexthop, "Serializing", manager);
+                }
 
-                r = nexthop_append_json(nexthop, &array);
+                r = nexthop_append_json(nexthop, /* serializing = */ ifindex < 0, &array);
                 if (r < 0)
                         return r;
         }
index e8be60458f3dc48ad02ce068d452ab9d2e612a8f..ada2500e392c218b2a489d06a15d045f5bc0fa86 100644 (file)
@@ -9,6 +9,7 @@ typedef struct Link Link;
 typedef struct Manager Manager;
 
 int addresses_append_json(Link *link, bool serializing, sd_json_variant **v);
+int nexthops_append_json(Manager *manager, int ifindex, sd_json_variant **v);
 int routes_append_json(Manager *manager, int ifindex, sd_json_variant **v);
 int link_build_json(Link *link, sd_json_variant **ret);
 int manager_build_json(Manager *manager, sd_json_variant **ret);
index 8cc74baae9ae3b385195a4673067145885e2d2a1..26a38bd4dde885e8ecaee195ace2d0a4c9c307d2 100644 (file)
@@ -11,6 +11,7 @@
 #include "networkd-json.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
+#include "networkd-nexthop.h"
 #include "networkd-route.h"
 #include "networkd-serialize.h"
 
@@ -49,6 +50,10 @@ int manager_serialize(Manager *manager) {
         if (r < 0)
                 return r;
 
+        r = nexthops_append_json(manager, /* ifindex = */ -1, &v);
+        if (r < 0)
+                return r;
+
         r = routes_append_json(manager, /* ifindex = */ -1, &v);
         if (r < 0)
                 return r;
@@ -230,6 +235,63 @@ static int manager_deserialize_link(Manager *manager, sd_json_variant *v) {
         return ret;
 }
 
+typedef struct NextHopParam {
+        uint32_t id;
+        int family;
+        NetworkConfigSource source;
+        struct iovec provider;
+} NextHopParam;
+
+static void nexthop_param_done(NextHopParam *p) {
+        assert(p);
+
+        iovec_done(&p->provider);
+}
+
+static int manager_deserialize_nexthop(Manager *manager, sd_json_variant *v) {
+        static const sd_json_dispatch_field dispatch_table[] = {
+                { "ID",             _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32,             offsetof(NextHopParam, id),        SD_JSON_MANDATORY },
+                { "Family",         _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family,        offsetof(NextHopParam, family),    SD_JSON_MANDATORY },
+                { "ConfigSource",   SD_JSON_VARIANT_STRING,        json_dispatch_network_config_source, offsetof(NextHopParam, source),    SD_JSON_MANDATORY },
+                { "ConfigProvider", SD_JSON_VARIANT_ARRAY,         json_dispatch_byte_array_iovec,      offsetof(NextHopParam, provider),  0                 },
+                {},
+        };
+
+        int r;
+
+        assert(manager);
+        assert(v);
+
+        _cleanup_(nexthop_param_done) NextHopParam p = {};
+        r = sd_json_dispatch(v, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to dispatch nexthop from json variant: %m");
+
+        if (p.id == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Dispatched nexthop ID is zero.");
+
+        if (p.provider.iov_len != 0 && p.provider.iov_len != FAMILY_ADDRESS_SIZE(p.family))
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Dispatched provider address size (%zu) is incompatible with the family (%s).",
+                                       p.provider.iov_len, af_to_ipv4_ipv6(p.family));
+
+        NextHop *nexthop;
+        r = nexthop_get_by_id(manager, p.id, &nexthop);
+        if (r < 0) {
+                log_debug_errno(r, "Cannot find deserialized nexthop (ID=%"PRIu32"): %m", p.id);
+                return 0; /* Already removed? */
+        }
+
+        if (nexthop->source != NETWORK_CONFIG_SOURCE_FOREIGN)
+                return 0; /* Huh?? Already deserialized?? */
+
+        nexthop->source = p.source;
+        memcpy_safe(&nexthop->provider, p.provider.iov_base, p.provider.iov_len);
+
+        log_nexthop_debug(nexthop, "Deserialized", manager);
+        return 0;
+}
+
 typedef struct RouteParam {
         Route route;
 
@@ -395,6 +457,9 @@ int manager_deserialize(Manager *manager) {
         JSON_VARIANT_ARRAY_FOREACH(i, sd_json_variant_by_key(v, "Interfaces"))
                 RET_GATHER(ret, manager_deserialize_link(manager, i));
 
+        JSON_VARIANT_ARRAY_FOREACH(i, sd_json_variant_by_key(v, "NextHops"))
+                RET_GATHER(ret, manager_deserialize_nexthop(manager, i));
+
         JSON_VARIANT_ARRAY_FOREACH(i, sd_json_variant_by_key(v, "Routes"))
                 RET_GATHER(ret, manager_deserialize_route(manager, i));