]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: sd-radv - Introduce pref64 support (RFC8781)
authorSusant Sahani <ssahani@gmail.com>
Fri, 28 Jul 2023 17:21:50 +0000 (22:51 +0530)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 25 Aug 2023 13:13:06 +0000 (15:13 +0200)
Implements: https://datatracker.ietf.org/doc/html/rfc8781

```

[IPv6PREF64Prefix]
Prefix=2003:da8:1:0::/64
ValidLifetimeSec=30m

Frame 16: 126 bytes on wire (1008 bits), 126 bytes captured (1008 bits) on interface veth99, id 0
Ethernet II, Src: 06:c7:41:95:1d:7f (06:c7:41:95:1d:7f), Dst: IPv6mcast_01 (33:33:00:00:00:01)
Internet Protocol Version 6, Src: fe80::4c7:41ff:fe95:1d7f, Dst: ff02::1
Internet Control Message Protocol v6
    Type: Router Advertisement (134)
    Code: 0
    Checksum: 0x0ca0 [correct]
    [Checksum Status: Good]
    Cur hop limit: 0
    Flags: 0x00, Prf (Default Router Preference): Medium
    Router lifetime (s): 1800
    Reachable time (ms): 0
    Retrans timer (ms): 0
    ICMPv6 Option (Source link-layer address : 06:c7:41:95:1d:7f)
    ICMPv6 Option (Prefix information : 2002:da8:1::/64)
    ICMPv6 Option (PREF64 Option)
        Type: PREF64 Option (38)
        Length: 2 (16 bytes)
        0000 0111 0000 1... = Scaled Lifetime: 225
        .... .... .... .001 = PLC (Prefix Length Code): 64 bits prefix length (0x1)
        Prefix: 64:ff9b::

```

man/systemd.network.xml
src/libsystemd-network/radv-internal.h
src/libsystemd-network/sd-radv.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-radv.c
src/network/networkd-radv.h
src/systemd/sd-radv.h

index 93830b5935b1f323b6a2fbf1458ef7486cdf3608..87c6c60e296d68afea0e241811f0906ce6f552cf 100644 (file)
@@ -3249,6 +3249,31 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
     </variablelist>
     </refsect1>
 
+    <refsect1>
+    <title>[IPv6PREF64Prefix] Section Options</title>
+    <para>One or more [IPv6PREF64Prefix] sections contain the IPv6 PREF64 (or NAT64) prefixes that are announced via Router
+    Advertisements. See <ulink url="https://tools.ietf.org/html/rfc8781">RFC 8781</ulink> for further
+    details.</para>
+
+    <variablelist class='network-directives'>
+
+      <varlistentry>
+        <term><varname>Prefix=</varname></term>
+
+        <listitem><para>The IPv6 PREF64 (or NAT64) prefix that is to be distributed to hosts. The setting holds
+        an IPv6 prefix that should be set up for NAT64 translation (PLAT) to allow 464XLAT on the network segment.
+        Use multiple [IPv6PREF64Prefix] sections to configure multiple IPv6 prefixes since prefix lifetime may differ
+        from one prefix to another. The prefix is an address with a prefix length, separated by a slash
+        <literal>/</literal> character. Valid NAT64 prefix length are 96, 64, 56, 48, 40, and 32 bits.</para></listitem></varlistentry>
+
+      <varlistentry>
+        <term><varname>LifetimeSec=</varname></term>
+        <listitem><para>Lifetime for the prefix measured in seconds. Should be greater than or equal to <varname>RouterLifetimeSec=</varname>.
+        <varname>LifetimeSec=</varname> defaults to 1800 seconds.</para></listitem>
+      </varlistentry>
+    </variablelist>
+    </refsect1>
+
     <refsect1>
     <title>[Bridge] Section Options</title>
       <para>The [Bridge] section accepts the following keys:</para>
index 4bb32f21283d90093598c5803c6bb910cce57f0c..534d7959827d989f7159ba3969af3f8c5a885594 100644 (file)
 #define RADV_MAX_FINAL_RTR_ADVERTISEMENTS         3
 #define RADV_MIN_DELAY_BETWEEN_RAS                3
 #define RADV_MAX_RA_DELAY_TIME_USEC               (500 * USEC_PER_MSEC)
+/* From RFC 8781 section 4.1
+ * By default, the value of the Scaled Lifetime field SHOULD be set to the lesser of 3 x MaxRtrAdvInterval */
+#define RADV_DEFAULT_PRE64_LIFETIME_USEC          (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
 
 #define RADV_OPT_ROUTE_INFORMATION                24
 #define RADV_OPT_RDNSS                            25
 #define RADV_OPT_DNSSL                            31
+/* Pref64 option type (RFC8781, section 4) */
+#define RADV_OPT_PREF64                           38
 
 enum RAdvState {
         RADV_STATE_IDLE                      = 0,
@@ -101,6 +106,9 @@ struct sd_radv {
         unsigned n_route_prefixes;
         LIST_HEAD(sd_radv_route_prefix, route_prefixes);
 
+        unsigned n_pref64_prefixes;
+        LIST_HEAD(sd_radv_pref64_prefix, pref64_prefixes);
+
         size_t n_rdnss;
         struct sd_radv_opt_dns *rdnss;
         struct sd_radv_opt_dns *dnssl;
@@ -172,6 +180,32 @@ struct sd_radv_route_prefix {
         usec_t valid_until;
 };
 
+/* rfc8781: section 4 - Scaled Lifetime: 13-bit unsigned integer. PLC (Prefix Length Code): 3-bit unsigned integer */
+#define radv_pref64_prefix_opt__contents { \
+        uint8_t type;                      \
+        uint8_t length;                    \
+        uint16_t lifetime_and_plc;         \
+        uint8_t prefix[12];                \
+}
+
+struct radv_pref64_prefix_opt radv_pref64_prefix_opt__contents;
+
+struct radv_pref64_prefix_opt__packed radv_pref64_prefix_opt__contents _packed_;
+assert_cc(sizeof(struct radv_pref64_prefix_opt) == sizeof(struct radv_pref64_prefix_opt__packed));
+
+struct sd_radv_pref64_prefix {
+        unsigned n_ref;
+
+        struct radv_pref64_prefix_opt opt;
+
+        struct in6_addr in6_addr;
+        uint8_t prefixlen;
+
+        usec_t lifetime_usec;
+
+        LIST_FIELDS(struct sd_radv_pref64_prefix, prefix);
+};
+
 #define log_radv_errno(radv, error, fmt, ...)           \
         log_interface_prefix_full_errno(                \
                 "RADV: ",                               \
index 5d4dfdef0282b187c51bd8decb2b9d322639a69d..983c01b202fc6e7280e3f3da084894b39482ae81 100644 (file)
@@ -25,6 +25,7 @@
 #include "socket-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "unaligned.h"
 
 int sd_radv_new(sd_radv **ret) {
         _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
@@ -220,6 +221,9 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us
                 iov[msg.msg_iovlen++] = IOVEC_MAKE(&rt->opt, sizeof(rt->opt));
         }
 
+        LIST_FOREACH(prefix, p, ra->pref64_prefixes)
+                iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
+
         if (ra->rdnss)
                 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
 
@@ -738,6 +742,78 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
         return 0;
 }
 
+int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
+        sd_radv_pref64_prefix *found = NULL;
+        int r;
+
+        assert_return(ra, -EINVAL);
+        assert_return(p, -EINVAL);
+
+        const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->in6_addr, p->prefixlen);
+
+        LIST_FOREACH(prefix, cur, ra->pref64_prefixes) {
+                r = in_addr_prefix_intersect(AF_INET6,
+                                             (const union in_addr_union*) &cur->in6_addr,
+                                             cur->prefixlen,
+                                             (const union in_addr_union*) &p->in6_addr,
+                                             p->prefixlen);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        continue;
+
+                if (cur->prefixlen == p->prefixlen) {
+                        found = cur;
+                        break;
+                }
+
+                return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
+                                      "IPv6 PREF64 prefix %s conflicts with %s, ignoring.",
+                                      addr_p,
+                                      IN6_ADDR_PREFIX_TO_STRING(&cur->in6_addr, cur->prefixlen));
+        }
+
+        if (found) {
+                /* p and cur may be equivalent. First increment the reference counter. */
+                sd_radv_pref64_prefix_ref(p);
+
+                /* Then, remove the old entry. */
+                LIST_REMOVE(prefix, ra->pref64_prefixes, found);
+                sd_radv_pref64_prefix_unref(found);
+
+                /* Finally, add the new entry. */
+                LIST_APPEND(prefix, ra->pref64_prefixes, p);
+
+                log_radv(ra, "Updated/replaced IPv6 PREF64 prefix %s (lifetime: %s)",
+                         strna(addr_p),
+                         FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
+        } else {
+                /* The route prefix is new. Let's simply add it. */
+
+                sd_radv_pref64_prefix_ref(p);
+                LIST_APPEND(prefix, ra->pref64_prefixes, p);
+                ra->n_pref64_prefixes++;
+
+                log_radv(ra, "Added PREF64 prefix %s", strna(addr_p));
+        }
+
+        if (ra->state == RADV_STATE_IDLE)
+                return 0;
+
+        if (ra->ra_sent == 0)
+                return 0;
+
+        /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
+        r = radv_send(ra, NULL, ra->lifetime_usec);
+        if (r < 0)
+                log_radv_errno(ra, r, "Unable to send Router Advertisement for added PREF64 prefix %s, ignoring: %m",
+                               strna(addr_p));
+        else
+                log_radv(ra, "Sent Router Advertisement for added PREF64 prefix %s.", strna(addr_p));
+
+        return 0;
+}
+
 int sd_radv_set_rdnss(
                 sd_radv *ra,
                 uint32_t lifetime,
@@ -983,3 +1059,77 @@ int sd_radv_route_prefix_set_lifetime(sd_radv_route_prefix *p, uint64_t lifetime
 
         return 0;
 }
+
+int sd_radv_pref64_prefix_new(sd_radv_pref64_prefix **ret) {
+        sd_radv_pref64_prefix *p;
+
+        assert_return(ret, -EINVAL);
+
+        p = new(sd_radv_pref64_prefix, 1);
+        if (!p)
+                return -ENOMEM;
+
+        *p = (sd_radv_pref64_prefix) {
+                .n_ref = 1,
+
+                .opt.type = RADV_OPT_PREF64,
+                .opt.length = 2,
+        };
+
+        *ret = p;
+        return 0;
+}
+
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_pref64_prefix, sd_radv_pref64_prefix, mfree);
+
+int sd_radv_pref64_prefix_set_prefix(
+                sd_radv_pref64_prefix *p,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen,
+                uint64_t lifetime_usec) {
+
+        uint16_t pref64_lifetime;
+        uint8_t prefixlen_code;
+
+        assert_return(p, -EINVAL);
+        assert_return(prefix, -EINVAL);
+
+        switch (prefixlen) {
+        case 96:
+                prefixlen_code = 0;
+                break;
+        case 64:
+                prefixlen_code = 1;
+                break;
+        case 56:
+                prefixlen_code = 2;
+                break;
+        case 48:
+                prefixlen_code = 3;
+                break;
+        case 40:
+                prefixlen_code = 4;
+                break;
+        case 32:
+                prefixlen_code = 5;
+                break;
+        default:
+                log_radv(NULL, "Unsupported PREF64 prefix length %u. Valid lengths are 32, 40, 48, 56, 64 and 96", prefixlen);
+                return -EINVAL;
+        }
+
+        if (lifetime_usec == USEC_INFINITY || DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13)
+                return -EINVAL;
+
+        /* RFC 8781 - 4.1 rounding up lifetime to multiply of 8 */
+        pref64_lifetime = DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) << 3;
+        pref64_lifetime |= prefixlen_code;
+
+        unaligned_write_be16(&p->opt.lifetime_and_plc, pref64_lifetime);
+        memcpy(&p->opt.prefix, prefix, sizeof(p->opt.prefix));
+
+        p->in6_addr = *prefix;
+        p->prefixlen = prefixlen;
+
+        return 0;
+}
index 40e78c91b3046fe0b05ab5fbf32bc8162c478903..022bd597583c960c66fb0dd6bc3e50f0ae9577b6 100644 (file)
@@ -389,6 +389,8 @@ IPv6Prefix.RouteMetric,                      config_parse_prefix_metric,
 IPv6Prefix.Token,                            config_parse_prefix_token,                                0,                             0
 IPv6RoutePrefix.Route,                       config_parse_route_prefix,                                0,                             0
 IPv6RoutePrefix.LifetimeSec,                 config_parse_route_prefix_lifetime,                       0,                             0
+IPv6PREF64Prefix.Prefix,                     config_parse_pref64_prefix,                               0,                             0
+IPv6PREF64Prefix.LifetimeSec,                config_parse_pref64_prefix_lifetime,                      0,                             0
 LLDP.MUDURL,                                 config_parse_mud_url,                                     0,                             offsetof(Network, lldp_mudurl)
 CAN.BitRate,                                 config_parse_can_bitrate,                                 0,                             offsetof(Network, can_bitrate)
 CAN.SamplePoint,                             config_parse_permille,                                    0,                             offsetof(Network, can_sample_point)
index b5eef894be9d6d81d3db16a7a677ade547667b20..bdf5acceb55a81dd215e886fa5749ffff8e9a6fb 100644 (file)
@@ -529,6 +529,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                         "IPv6PrefixDelegation\0"
                         "IPv6Prefix\0"
                         "IPv6RoutePrefix\0"
+                        "IPv6PREF64Prefix\0"
                         "LLDP\0"
                         "TrafficControlQueueingDiscipline\0"
                         "CAN\0"
@@ -779,6 +780,7 @@ static Network *network_free(Network *network) {
         hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
         hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
         hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
+        hashmap_free_with_destructor(network->pref64_prefixes_by_section, pref64_prefix_free);
         hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
         hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
         ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
@@ -844,6 +846,9 @@ bool network_has_static_ipv6_configurations(Network *network) {
         if (!hashmap_isempty(network->route_prefixes_by_section))
                 return true;
 
+        if (!hashmap_isempty(network->pref64_prefixes_by_section))
+                return true;
+
         return false;
 }
 
index cb8626f008e687601200fb4ed450ae4bfb359f60..7270ace45d39c98788cd24bde76c48b3c711f5c8 100644 (file)
@@ -358,6 +358,7 @@ struct Network {
         Hashmap *address_labels_by_section;
         Hashmap *prefixes_by_section;
         Hashmap *route_prefixes_by_section;
+        Hashmap *pref64_prefixes_by_section;
         Hashmap *rules_by_section;
         Hashmap *dhcp_static_leases_by_section;
         Hashmap *qdiscs_by_section;
index 1bf6fc99d97dd537ceeeacdc823d908507d06699..57fd68f5a0f758617ed0a4f6df01d5ac16137895 100644 (file)
@@ -48,6 +48,7 @@ void network_adjust_radv(Network *network) {
         if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
                 network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
                 network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
+                network->pref64_prefixes_by_section = hashmap_free_with_destructor(network->pref64_prefixes_by_section, pref64_prefix_free);
         }
 }
 
@@ -177,6 +178,61 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig
         return 0;
 }
 
+pref64Prefix *pref64_prefix_free(pref64Prefix *prefix) {
+        if (!prefix)
+                return NULL;
+
+        if (prefix->network) {
+                assert(prefix->section);
+                hashmap_remove(prefix->network->pref64_prefixes_by_section, prefix->section);
+        }
+
+        config_section_free(prefix->section);
+
+        return mfree(prefix);
+}
+
+DEFINE_SECTION_CLEANUP_FUNCTIONS(pref64Prefix, pref64_prefix_free);
+
+static int pref64_prefix_new_static(Network *network, const char *filename, unsigned section_line, pref64Prefix **ret) {
+        _cleanup_(config_section_freep) ConfigSection *n = NULL;
+        _cleanup_(pref64_prefix_freep) pref64Prefix *prefix = NULL;
+        int r;
+
+        assert(network);
+        assert(ret);
+        assert(filename);
+        assert(section_line > 0);
+
+        r = config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        prefix = hashmap_get(network->pref64_prefixes_by_section, n);
+        if (prefix) {
+                *ret = TAKE_PTR(prefix);
+                return 0;
+        }
+
+        prefix = new(pref64Prefix, 1);
+        if (!prefix)
+                return -ENOMEM;
+
+        *prefix = (pref64Prefix) {
+                .network = network,
+                .section = TAKE_PTR(n),
+
+                .lifetime = RADV_DEFAULT_PRE64_LIFETIME_USEC,
+        };
+
+        r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(prefix);
+        return 0;
+}
+
 int link_request_radv_addresses(Link *link) {
         Prefix *p;
         int r;
@@ -294,6 +350,25 @@ static int radv_set_route_prefix(Link *link, RoutePrefix *prefix) {
         return sd_radv_add_route_prefix(link->radv, p);
 }
 
+static int radv_set_pref64_prefix(Link *link, pref64Prefix *prefix) {
+        _cleanup_(sd_radv_pref64_prefix_unrefp) sd_radv_pref64_prefix *p = NULL;
+        int r;
+
+        assert(link);
+        assert(link->radv);
+        assert(prefix);
+
+        r = sd_radv_pref64_prefix_new(&p);
+        if (r < 0)
+                return r;
+
+        r = sd_radv_pref64_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen, prefix->lifetime);
+        if (r < 0)
+                return r;
+
+        return sd_radv_add_pref64_prefix(link->radv, p);
+}
+
 static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
         _cleanup_free_ struct in6_addr *addresses = NULL;
         size_t n_addresses = 0;
@@ -441,6 +516,7 @@ static int radv_find_uplink(Link *link, Link **ret) {
 static int radv_configure(Link *link) {
         Link *uplink = NULL;
         RoutePrefix *q;
+        pref64Prefix *n;
         Prefix *p;
         int r;
 
@@ -508,6 +584,12 @@ static int radv_configure(Link *link) {
                         return r;
         }
 
+        HASHMAP_FOREACH(n, link->network->pref64_prefixes_by_section) {
+                r = radv_set_pref64_prefix(link, n);
+                if (r < 0 && r != -EEXIST)
+                        return r;
+        }
+
         (void) radv_find_uplink(link, &uplink);
 
         r = radv_set_dns(link, uplink);
@@ -792,6 +874,16 @@ void network_drop_invalid_route_prefixes(Network *network) {
                         route_prefix_free(p);
 }
 
+void network_drop_invalid_pref64_prefixes(Network *network) {
+        pref64Prefix *p;
+
+        assert(network);
+
+        HASHMAP_FOREACH(p, network->pref64_prefixes_by_section)
+                 if (section_is_invalid(p->section))
+                         pref64_prefix_free(p);
+}
+
 int config_parse_prefix(
                 const char *unit,
                 const char *filename,
@@ -1083,6 +1175,99 @@ int config_parse_route_prefix_lifetime(
         return 0;
 }
 
+int config_parse_pref64_prefix(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        _cleanup_(pref64_prefix_free_or_set_invalidp) pref64Prefix *p = NULL;
+        Network *network = ASSERT_PTR(userdata);
+        union in_addr_union a;
+        uint8_t prefixlen;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+
+        r = pref64_prefix_new_static(network, filename, section_line, &p);
+        if (r < 0)
+                return log_oom();
+
+        r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "PREF64 prefix is invalid, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        if (!IN_SET(prefixlen, 96, 64, 56, 48, 40, 32)) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "PREF64 prefixlen is invalid, ignoring assignment: %s", rvalue);
+                return 0;
+       }
+
+        (void) in6_addr_mask(&a.in6,prefixlen);
+        p->prefix = a.in6;
+        p->prefixlen = prefixlen;
+
+        TAKE_PTR(p);
+        return 0;
+}
+
+int config_parse_pref64_prefix_lifetime(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        _cleanup_(pref64_prefix_free_or_set_invalidp) pref64Prefix *p = NULL;
+        Network *network = ASSERT_PTR(userdata);
+        usec_t usec;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+
+        r = pref64_prefix_new_static(network, filename, section_line, &p);
+        if (r < 0)
+                return log_oom();
+
+        r = parse_sec(rvalue, &usec);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "PREF64 lifetime is invalid, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        if (usec == USEC_INFINITY || DIV_ROUND_UP(usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "PREF64 lifetime is too long, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        p->lifetime = usec;
+
+        TAKE_PTR(p);
+        return 0;
+}
+
 int config_parse_radv_dns(
                 const char *unit,
                 const char *filename,
index e1c22d054f2691b3d06e21b4dac4ec2480ffe354..8ea1a85b26c699da6a584c34e11b3d37a3385d30 100644 (file)
@@ -52,11 +52,22 @@ typedef struct RoutePrefix {
         usec_t lifetime;
 } RoutePrefix;
 
+typedef struct pref64Prefix {
+        Network *network;
+        ConfigSection *section;
+
+        struct in6_addr prefix;
+        uint8_t prefixlen;
+        usec_t lifetime;
+} pref64Prefix;
+
 Prefix *prefix_free(Prefix *prefix);
 RoutePrefix *route_prefix_free(RoutePrefix *prefix);
+pref64Prefix *pref64_prefix_free(pref64Prefix *prefix);
 
 void network_drop_invalid_prefixes(Network *network);
 void network_drop_invalid_route_prefixes(Network *network);
+void network_drop_invalid_pref64_prefixes(Network *network);
 void network_adjust_radv(Network *network);
 
 int link_request_radv_addresses(Link *link);
@@ -85,3 +96,5 @@ CONFIG_PARSER_PROTOTYPE(config_parse_radv_dns);
 CONFIG_PARSER_PROTOTYPE(config_parse_radv_search_domains);
 CONFIG_PARSER_PROTOTYPE(config_parse_route_prefix);
 CONFIG_PARSER_PROTOTYPE(config_parse_route_prefix_lifetime);
+CONFIG_PARSER_PROTOTYPE(config_parse_pref64_prefix);
+CONFIG_PARSER_PROTOTYPE(config_parse_pref64_prefix_lifetime);
index 98fda297a72ee7cf85f6a247490d3fa966d9a467..882613c0b3f92f23729ca617d3a9026d6a3640e5 100644 (file)
@@ -33,6 +33,7 @@ _SD_BEGIN_DECLARATIONS;
 typedef struct sd_radv sd_radv;
 typedef struct sd_radv_prefix sd_radv_prefix;
 typedef struct sd_radv_route_prefix sd_radv_route_prefix;
+typedef struct sd_radv_pref64_prefix sd_radv_pref64_prefix;
 
 /* Router Advertisement */
 int sd_radv_new(sd_radv **ret);
@@ -60,6 +61,7 @@ int sd_radv_set_other_information(sd_radv *ra, int other);
 int sd_radv_set_preference(sd_radv *ra, unsigned preference);
 int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
 int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p);
+int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p);
 void sd_radv_remove_prefix(sd_radv *ra, const struct in6_addr *prefix, unsigned char prefixlen);
 int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
                       const struct in6_addr *dns, size_t n_dns);
@@ -87,9 +89,16 @@ sd_radv_route_prefix *sd_radv_route_prefix_unref(sd_radv_route_prefix *ra);
 int sd_radv_route_prefix_set_prefix(sd_radv_route_prefix *p, const struct in6_addr *in6_addr, unsigned char prefixlen);
 int sd_radv_route_prefix_set_lifetime(sd_radv_route_prefix *p, uint64_t lifetime_usec, uint64_t valid_until);
 
+int sd_radv_pref64_prefix_new(sd_radv_pref64_prefix **ret);
+int sd_radv_pref64_prefix_set_prefix(sd_radv_pref64_prefix *p, const struct in6_addr *prefix,
+                                     uint8_t prefixlen, uint64_t lifetime_usec);
+sd_radv_pref64_prefix *sd_radv_pref64_prefix_ref(sd_radv_pref64_prefix *ra);
+sd_radv_pref64_prefix *sd_radv_pref64_prefix_unref(sd_radv_pref64_prefix *ra);
+
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv, sd_radv_unref);
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_prefix, sd_radv_prefix_unref);
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_route_prefix, sd_radv_route_prefix_unref);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_pref64_prefix, sd_radv_pref64_prefix_unref);
 
 _SD_END_DECLARATIONS;