Compare commits
7 Commits
1294661381
...
28ca867abd
Author | SHA1 | Date |
---|---|---|
Michal Sekletár | 28ca867abd | |
Zbigniew Jędrzejewski-Szmek | c7220ca802 | |
Chris Down | e0e2112f61 | |
Michal Koutný | 8b51950f4c | |
Zbigniew Jędrzejewski-Szmek | 5bbcff2a1d | |
Yu Watanabe | 87bbebeab6 | |
Susant Sahani | 5f506a5560 |
|
@ -381,9 +381,9 @@ that might have changed user identity), in bytes. Enforced by
|
||||||
[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html),
|
[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html),
|
||||||
similar to `tasksMax`.
|
similar to `tasksMax`.
|
||||||
|
|
||||||
`cpuWeight`/`ioWeight` → These take unsigned integers in the range 100…10000
|
`cpuWeight`/`ioWeight` → These take unsigned integers in the range 1…10000
|
||||||
and configure the CPU and IO scheduling weights for the user's processes as a
|
(defaults to 100) and configure the CPU and IO scheduling weights for the
|
||||||
whole. Also enforced by
|
user's processes as a whole. Also enforced by
|
||||||
[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html),
|
[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html),
|
||||||
similar to `tasksMax`, `memoryHigh` and `memoryMax`.
|
similar to `tasksMax`, `memoryHigh` and `memoryMax`.
|
||||||
|
|
||||||
|
|
|
@ -308,11 +308,19 @@
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>IPv6Token=</varname></term>
|
<term><varname>IPv6Token=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>An IPv6 address with the top 64 bits unset. When set, indicates the
|
<para>Specifies an optional address generation mechanism and an optional address prefix. If
|
||||||
64-bit interface part of SLAAC IPv6 addresses for this link. Note that
|
the mechanism is present, the two parts must be separated with a colon
|
||||||
the token is only ever used for SLAAC, and not for DHCPv6 addresses, even
|
<literal><replaceable>type</replaceable>:<replaceable>prefix</replaceable></literal>. The
|
||||||
in the case DHCP is requested by router advertisement. By default, the
|
address generation mechanism may be either <constant>prefixstable</constant> or
|
||||||
token is autogenerated.</para>
|
<constant>eui64</constant>. If not specified, <constant>eui64</constant> is assumed. When
|
||||||
|
set to <literal>prefixstable</literal> a method for generating IPv6 Interface Identifiers to
|
||||||
|
be used with IPv6 Stateless Address Autocon figuration (SLAAC). See
|
||||||
|
<ulink url="https://tools.ietf.org/html/rfc7217">RFC 7217</ulink>. When IPv6 address is set,
|
||||||
|
indicates the 64-bit interface part of SLAAC IPv6 addresses for this link.</para>
|
||||||
|
|
||||||
|
<para>Note that the token is only ever used for SLAAC, and not for DHCPv6 addresses, even in
|
||||||
|
the case DHCP is requested by router advertisement. By default, the token is autogenerated.
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "cgroup-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
assert_cc(sizeof(pid_t) == sizeof(int32_t));
|
assert_cc(sizeof(pid_t) == sizeof(int32_t));
|
||||||
|
@ -71,8 +72,15 @@ typedef enum {
|
||||||
FORMAT_BYTES_TRAILING_B = 1 << 2,
|
FORMAT_BYTES_TRAILING_B = 1 << 2,
|
||||||
} FormatBytesFlag;
|
} FormatBytesFlag;
|
||||||
|
|
||||||
#define FORMAT_BYTES_MAX 8
|
#define FORMAT_BYTES_MAX 16
|
||||||
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
|
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
|
||||||
static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
|
static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
|
||||||
return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
|
return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
|
||||||
}
|
}
|
||||||
|
static inline char *format_bytes_cgroup_protection(char *buf, size_t l, uint64_t t) {
|
||||||
|
if (t == CGROUP_LIMIT_MAX) {
|
||||||
|
(void) snprintf(buf, l, "%s", "infinity");
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
return format_bytes(buf, l, t);
|
||||||
|
}
|
||||||
|
|
|
@ -601,7 +601,7 @@ static int journal_file_verify_header(JournalFile *f) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int journal_file_fstat(JournalFile *f) {
|
int journal_file_fstat(JournalFile *f) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(f);
|
assert(f);
|
||||||
|
|
|
@ -145,6 +145,7 @@ int journal_file_open(
|
||||||
int journal_file_set_offline(JournalFile *f, bool wait);
|
int journal_file_set_offline(JournalFile *f, bool wait);
|
||||||
bool journal_file_is_offlining(JournalFile *f);
|
bool journal_file_is_offlining(JournalFile *f);
|
||||||
JournalFile* journal_file_close(JournalFile *j);
|
JournalFile* journal_file_close(JournalFile *j);
|
||||||
|
int journal_file_fstat(JournalFile *f);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(JournalFile*, journal_file_close);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(JournalFile*, journal_file_close);
|
||||||
|
|
||||||
int journal_file_open_reliably(
|
int journal_file_open_reliably(
|
||||||
|
|
|
@ -2661,6 +2661,8 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
|
||||||
assert_return(!journal_pid_changed(j), -ECHILD);
|
assert_return(!journal_pid_changed(j), -ECHILD);
|
||||||
|
|
||||||
if (j->inotify_fd < 0) {
|
if (j->inotify_fd < 0) {
|
||||||
|
Iterator i;
|
||||||
|
JournalFile *f;
|
||||||
|
|
||||||
/* This is the first invocation, hence create the
|
/* This is the first invocation, hence create the
|
||||||
* inotify watch */
|
* inotify watch */
|
||||||
|
@ -2668,6 +2670,19 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
/* Server might have done some vacuuming while we weren't watching.
|
||||||
|
Get rid of the deleted files now so they don't stay around indefinitely. */
|
||||||
|
ORDERED_HASHMAP_FOREACH(f, j->files, i) {
|
||||||
|
r = journal_file_fstat(f);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r,"Failed to fstat() journal file '%s' : %m", f->path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->last_stat.st_nlink <= 0)
|
||||||
|
remove_file_real(j, f);
|
||||||
|
}
|
||||||
|
|
||||||
/* The journal might have changed since the context
|
/* The journal might have changed since the context
|
||||||
* object was created and we weren't watching before,
|
* object was created and we weren't watching before,
|
||||||
* hence don't wait for anything, and return
|
* hence don't wait for anything, and return
|
||||||
|
|
|
@ -13,12 +13,74 @@
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-ndisc.h"
|
#include "networkd-ndisc.h"
|
||||||
#include "networkd-route.h"
|
#include "networkd-route.h"
|
||||||
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
||||||
#define NDISC_DNSSL_MAX 64U
|
#define NDISC_DNSSL_MAX 64U
|
||||||
#define NDISC_RDNSS_MAX 64U
|
#define NDISC_RDNSS_MAX 64U
|
||||||
#define NDISC_PREFIX_LFT_MIN 7200U
|
#define NDISC_PREFIX_LFT_MIN 7200U
|
||||||
|
|
||||||
|
#define DAD_CONFLICTS_IDGEN_RETRIES_RFC7217 3
|
||||||
|
|
||||||
|
/* https://tools.ietf.org/html/rfc5453 */
|
||||||
|
/* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */
|
||||||
|
|
||||||
|
#define SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } })
|
||||||
|
#define SUBNET_ROUTER_ANYCAST_PREFIXLEN 8
|
||||||
|
#define RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x02, 0x00, 0x5E, 0xFF, 0xFE } })
|
||||||
|
#define RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN 5
|
||||||
|
#define RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291 ((struct in6_addr) { .s6_addr = { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } })
|
||||||
|
#define RESERVED_SUBNET_ANYCAST_PREFIXLEN 7
|
||||||
|
|
||||||
|
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
|
||||||
|
|
||||||
|
static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
|
||||||
|
assert(addr);
|
||||||
|
|
||||||
|
/* According to rfc4291, generated address should not be in the following ranges. */
|
||||||
|
|
||||||
|
if (memcmp(addr, &SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291, SUBNET_ROUTER_ANYCAST_PREFIXLEN) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (memcmp(addr, &RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291, RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (memcmp(addr, &RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291, RESERVED_SUBNET_ANYCAST_PREFIXLEN) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr *addr) {
|
||||||
|
sd_id128_t secret_key;
|
||||||
|
struct siphash state;
|
||||||
|
uint64_t rid;
|
||||||
|
size_t l;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* According to rfc7217 section 5.1
|
||||||
|
* RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */
|
||||||
|
|
||||||
|
r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to generate key: %m");
|
||||||
|
|
||||||
|
siphash24_init(&state, secret_key.bytes);
|
||||||
|
|
||||||
|
l = MAX(DIV_ROUND_UP(prefix_len, 8), 8);
|
||||||
|
siphash24_compress(prefix, l, &state);
|
||||||
|
siphash24_compress(link->ifname, strlen(link->ifname), &state);
|
||||||
|
siphash24_compress(&link->mac, sizeof(struct ether_addr), &state);
|
||||||
|
siphash24_compress(&dad_counter, sizeof(uint8_t), &state);
|
||||||
|
|
||||||
|
rid = htole64(siphash24_finalize(&state));
|
||||||
|
|
||||||
|
memcpy(addr->s6_addr, prefix->s6_addr, l);
|
||||||
|
memcpy((uint8_t *) &addr->s6_addr + l, &rid, 16 - l);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ndisc_netlink_route_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int ndisc_netlink_route_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -192,12 +254,62 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ndisc_router_generate_address(Link *link, unsigned prefixlen, uint32_t lifetime_preferred, Address *address) {
|
||||||
|
bool prefix = false;
|
||||||
|
struct in6_addr addr;
|
||||||
|
IPv6Token *j;
|
||||||
|
Iterator i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(address);
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
addr = address->in_addr.in6;
|
||||||
|
ORDERED_HASHMAP_FOREACH(j, link->network->ipv6_tokens, i)
|
||||||
|
if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
|
||||||
|
&& memcmp(&j->prefix, &addr, FAMILY_ADDRESS_SIZE(address->family)) == 0) {
|
||||||
|
for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
|
||||||
|
r = make_stableprivate_address(link, &j->prefix, prefixlen, j->dad_counter, &address->in_addr.in6);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (stableprivate_address_is_valid(&address->in_addr.in6)) {
|
||||||
|
prefix = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_EUI64) {
|
||||||
|
memcpy(((uint8_t *)&address->in_addr.in6) + 8, ((uint8_t *) &j->prefix) + 8, 8);
|
||||||
|
prefix = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eui64 or fallback if prefixstable do not match */
|
||||||
|
if (!prefix) {
|
||||||
|
/* see RFC4291 section 2.5.1 */
|
||||||
|
address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
|
||||||
|
address->in_addr.in6.s6_addr[8] ^= 1 << 1;
|
||||||
|
address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
|
||||||
|
address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
|
||||||
|
address->in_addr.in6.s6_addr[11] = 0xff;
|
||||||
|
address->in_addr.in6.s6_addr[12] = 0xfe;
|
||||||
|
address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
|
||||||
|
address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
|
||||||
|
address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
address->prefixlen = prefixlen;
|
||||||
|
address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
|
||||||
|
address->cinfo.ifa_prefered = lifetime_preferred;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
|
static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
|
||||||
|
uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
|
||||||
_cleanup_(address_freep) Address *address = NULL;
|
_cleanup_(address_freep) Address *address = NULL;
|
||||||
Address *existing_address;
|
Address *existing_address;
|
||||||
uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
|
|
||||||
usec_t time_now;
|
|
||||||
unsigned prefixlen;
|
unsigned prefixlen;
|
||||||
|
usec_t time_now;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
@ -232,23 +344,9 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
||||||
|
|
||||||
if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
|
r = ndisc_router_generate_address(link, prefixlen, lifetime_preferred, address);
|
||||||
memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
|
if (r < 0)
|
||||||
else {
|
return log_link_error_errno(link, r, "Falied to generate prefix stable address: %m");
|
||||||
/* see RFC4291 section 2.5.1 */
|
|
||||||
address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
|
|
||||||
address->in_addr.in6.s6_addr[8] ^= 1 << 1;
|
|
||||||
address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
|
|
||||||
address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
|
|
||||||
address->in_addr.in6.s6_addr[11] = 0xff;
|
|
||||||
address->in_addr.in6.s6_addr[12] = 0xfe;
|
|
||||||
address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
|
|
||||||
address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
|
|
||||||
address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
|
|
||||||
}
|
|
||||||
address->prefixlen = prefixlen;
|
|
||||||
address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
|
|
||||||
address->cinfo.ifa_prefered = lifetime_preferred;
|
|
||||||
|
|
||||||
/* see RFC4862 section 5.5.3.e */
|
/* see RFC4862 section 5.5.3.e */
|
||||||
r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
|
r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
|
||||||
|
@ -755,6 +853,30 @@ void ndisc_flush(Link *link) {
|
||||||
link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
|
link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ipv6token_new(IPv6Token **ret) {
|
||||||
|
IPv6Token *p;
|
||||||
|
|
||||||
|
p = new(IPv6Token, 1);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*p = (IPv6Token) {
|
||||||
|
.address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(p);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
ipv6_token_hash_ops,
|
||||||
|
void,
|
||||||
|
trivial_hash_func,
|
||||||
|
trivial_compare_func,
|
||||||
|
IPv6Token,
|
||||||
|
free);
|
||||||
|
|
||||||
int config_parse_ndisc_black_listed_prefix(
|
int config_parse_ndisc_black_listed_prefix(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -826,3 +948,86 @@ int config_parse_ndisc_black_listed_prefix(
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_address_generation_type(
|
||||||
|
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_free_ IPv6Token *token = NULL;
|
||||||
|
_cleanup_free_ char *word = NULL;
|
||||||
|
union in_addr_union buffer;
|
||||||
|
Network *network = data;
|
||||||
|
const char *p;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
if (isempty(rvalue)) {
|
||||||
|
network->ipv6_tokens = ordered_hashmap_free(network->ipv6_tokens);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = rvalue;
|
||||||
|
r = extract_first_word(&p, &word, ":", 0);
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r <= 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
|
"Invalid IPv6Token= , ignoring assignment: %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = ipv6token_new(&token);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (streq(word, "eui64"))
|
||||||
|
token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_EUI64;
|
||||||
|
else if (streq(word, "prefixstable"))
|
||||||
|
token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE;
|
||||||
|
else {
|
||||||
|
token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_EUI64;
|
||||||
|
p = rvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = in_addr_from_string(AF_INET6, p, &buffer);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
|
"Failed to parse IPv6 %s, ignoring: %s", lvalue, rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_addr_is_null(AF_INET6, &buffer)) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||||
|
"IPv6 %s cannot be the ANY address, ignoring: %s", lvalue, rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
token->prefix = buffer.in6;
|
||||||
|
|
||||||
|
r = ordered_hashmap_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = ordered_hashmap_put(network->ipv6_tokens, &token->prefix, token);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
|
"Failed to store IPv6 token '%s'", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAKE_PTR(token);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,16 @@
|
||||||
#include "networkd-link.h"
|
#include "networkd-link.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
|
typedef struct IPv6Token IPv6Token;
|
||||||
|
|
||||||
|
typedef enum IPv6TokenAddressGeneration {
|
||||||
|
IPV6_TOKEN_ADDRESS_GENERATION_NONE,
|
||||||
|
IPV6_TOKEN_ADDRESS_GENERATION_EUI64,
|
||||||
|
IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE,
|
||||||
|
_IPV6_TOKEN_ADDRESS_GENERATION_MAX,
|
||||||
|
_IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -1,
|
||||||
|
} IPv6TokenAddressGeneration;
|
||||||
|
|
||||||
typedef struct NDiscRDNSS {
|
typedef struct NDiscRDNSS {
|
||||||
usec_t valid_until;
|
usec_t valid_until;
|
||||||
struct in6_addr address;
|
struct in6_addr address;
|
||||||
|
@ -15,6 +25,16 @@ typedef struct NDiscDNSSL {
|
||||||
/* The domain name follows immediately. */
|
/* The domain name follows immediately. */
|
||||||
} NDiscDNSSL;
|
} NDiscDNSSL;
|
||||||
|
|
||||||
|
struct IPv6Token {
|
||||||
|
IPv6TokenAddressGeneration address_generation_type;
|
||||||
|
|
||||||
|
uint8_t dad_counter;
|
||||||
|
struct in6_addr prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
int ipv6token_new(IPv6Token **ret);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(IPv6Token *, freep);
|
||||||
|
|
||||||
static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
|
static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
|
||||||
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
|
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
|
||||||
}
|
}
|
||||||
|
@ -24,3 +44,4 @@ void ndisc_vacuum(Link *link);
|
||||||
void ndisc_flush(Link *link);
|
void ndisc_flush(Link *link);
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_black_listed_prefix);
|
CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_black_listed_prefix);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
|
||||||
|
|
|
@ -68,7 +68,7 @@ Network.DHCPServer, config_parse_bool,
|
||||||
Network.LinkLocalAddressing, config_parse_link_local_address_family, 0, offsetof(Network, link_local)
|
Network.LinkLocalAddressing, config_parse_link_local_address_family, 0, offsetof(Network, link_local)
|
||||||
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
|
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
|
||||||
Network.DefaultRouteOnDevice, config_parse_bool, 0, offsetof(Network, default_route_on_device)
|
Network.DefaultRouteOnDevice, config_parse_bool, 0, offsetof(Network, default_route_on_device)
|
||||||
Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
|
Network.IPv6Token, config_parse_address_generation_type, 0, 0
|
||||||
Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode)
|
Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode)
|
||||||
Network.EmitLLDP, config_parse_lldp_emit, 0, offsetof(Network, lldp_emit)
|
Network.EmitLLDP, config_parse_lldp_emit, 0, offsetof(Network, lldp_emit)
|
||||||
Network.Address, config_parse_address, 0, 0
|
Network.Address, config_parse_address, 0, 0
|
||||||
|
|
|
@ -705,6 +705,7 @@ static Network *network_free(Network *network) {
|
||||||
|
|
||||||
ordered_hashmap_free(network->dhcp_client_send_options);
|
ordered_hashmap_free(network->dhcp_client_send_options);
|
||||||
ordered_hashmap_free(network->dhcp_server_send_options);
|
ordered_hashmap_free(network->dhcp_server_send_options);
|
||||||
|
ordered_hashmap_free(network->ipv6_tokens);
|
||||||
|
|
||||||
return mfree(network);
|
return mfree(network);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "networkd-ipv6-proxy-ndp.h"
|
#include "networkd-ipv6-proxy-ndp.h"
|
||||||
#include "networkd-lldp-rx.h"
|
#include "networkd-lldp-rx.h"
|
||||||
#include "networkd-lldp-tx.h"
|
#include "networkd-lldp-tx.h"
|
||||||
|
#include "networkd-ndisc.h"
|
||||||
#include "networkd-neighbor.h"
|
#include "networkd-neighbor.h"
|
||||||
#include "networkd-nexthop.h"
|
#include "networkd-nexthop.h"
|
||||||
#include "networkd-radv.h"
|
#include "networkd-radv.h"
|
||||||
|
@ -218,8 +219,8 @@ struct Network {
|
||||||
uint32_t ipv6_accept_ra_route_table;
|
uint32_t ipv6_accept_ra_route_table;
|
||||||
bool ipv6_accept_ra_route_table_set;
|
bool ipv6_accept_ra_route_table_set;
|
||||||
Set *ndisc_black_listed_prefix;
|
Set *ndisc_black_listed_prefix;
|
||||||
|
OrderedHashmap *ipv6_tokens;
|
||||||
|
|
||||||
union in_addr_union ipv6_token;
|
|
||||||
IPv6PrivacyExtensions ipv6_privacy_extensions;
|
IPv6PrivacyExtensions ipv6_privacy_extensions;
|
||||||
|
|
||||||
struct ether_addr *mac;
|
struct ether_addr *mac;
|
||||||
|
|
|
@ -4478,11 +4478,11 @@ static void print_status_info(
|
||||||
|
|
||||||
printf(" (");
|
printf(" (");
|
||||||
if (i->memory_min > 0) {
|
if (i->memory_min > 0) {
|
||||||
printf("%smin: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_min));
|
printf("%smin: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_min));
|
||||||
prefix = " ";
|
prefix = " ";
|
||||||
}
|
}
|
||||||
if (i->memory_low > 0) {
|
if (i->memory_low > 0) {
|
||||||
printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low));
|
printf("%slow: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_low));
|
||||||
prefix = " ";
|
prefix = " ";
|
||||||
}
|
}
|
||||||
if (i->memory_high != CGROUP_LIMIT_MAX) {
|
if (i->memory_high != CGROUP_LIMIT_MAX) {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
[Match]
|
||||||
|
Name=veth99
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
IPv6AcceptRA=true
|
||||||
|
IPv6Token=::1a:2b:3c:4d
|
|
@ -0,0 +1,6 @@
|
||||||
|
[Match]
|
||||||
|
Name=veth99
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
IPv6AcceptRA=true
|
||||||
|
IPv6Token=prefixstable:2002:da8:1::
|
|
@ -2644,7 +2644,9 @@ class NetworkdRATests(unittest.TestCase, Utilities):
|
||||||
units = [
|
units = [
|
||||||
'25-veth.netdev',
|
'25-veth.netdev',
|
||||||
'ipv6-prefix.network',
|
'ipv6-prefix.network',
|
||||||
'ipv6-prefix-veth.network']
|
'ipv6-prefix-veth.network',
|
||||||
|
'ipv6-prefix-veth-token-eui64.network',
|
||||||
|
'ipv6-prefix-veth-token-prefixstable.network']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
remove_links(self.links)
|
remove_links(self.links)
|
||||||
|
@ -2669,6 +2671,24 @@ class NetworkdRATests(unittest.TestCase, Utilities):
|
||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, '2002:da8:1:0')
|
self.assertRegex(output, '2002:da8:1:0')
|
||||||
|
|
||||||
|
def test_ipv6_token_eui64(self):
|
||||||
|
copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-eui64.network')
|
||||||
|
start_networkd()
|
||||||
|
self.wait_online(['veth99:routable', 'veth-peer:degraded'])
|
||||||
|
|
||||||
|
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
|
||||||
|
print(output)
|
||||||
|
self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
|
||||||
|
|
||||||
|
def test_ipv6_token_prefixstable(self):
|
||||||
|
copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
|
||||||
|
start_networkd()
|
||||||
|
self.wait_online(['veth99:routable', 'veth-peer:degraded'])
|
||||||
|
|
||||||
|
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
|
||||||
|
print(output)
|
||||||
|
self.assertRegex(output, '2002:da8:1:0')
|
||||||
|
|
||||||
class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
|
class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
|
||||||
links = ['veth99']
|
links = ['veth99']
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Initrd File Systems
|
Description=Initrd File Systems
|
||||||
Documentation=man:systemd.special(7)
|
Documentation=man:systemd.special(7)
|
||||||
OnFailure=emergency.target
|
|
||||||
OnFailureJobMode=replace-irreversibly
|
|
||||||
ConditionPathExists=/etc/initrd-release
|
ConditionPathExists=/etc/initrd-release
|
||||||
After=initrd-parse-etc.service
|
After=initrd-parse-etc.service
|
||||||
DefaultDependencies=no
|
DefaultDependencies=no
|
||||||
|
|
|
@ -11,7 +11,5 @@
|
||||||
Description=Initrd Root Device
|
Description=Initrd Root Device
|
||||||
Documentation=man:systemd.special(7)
|
Documentation=man:systemd.special(7)
|
||||||
ConditionPathExists=/etc/initrd-release
|
ConditionPathExists=/etc/initrd-release
|
||||||
OnFailure=emergency.target
|
|
||||||
OnFailureJobMode=replace-irreversibly
|
|
||||||
DefaultDependencies=no
|
DefaultDependencies=no
|
||||||
Conflicts=shutdown.target
|
Conflicts=shutdown.target
|
||||||
|
|
|
@ -11,7 +11,5 @@
|
||||||
Description=Initrd Root File System
|
Description=Initrd Root File System
|
||||||
Documentation=man:systemd.special(7)
|
Documentation=man:systemd.special(7)
|
||||||
ConditionPathExists=/etc/initrd-release
|
ConditionPathExists=/etc/initrd-release
|
||||||
OnFailure=emergency.target
|
|
||||||
OnFailureJobMode=replace-irreversibly
|
|
||||||
DefaultDependencies=no
|
DefaultDependencies=no
|
||||||
Conflicts=shutdown.target
|
Conflicts=shutdown.target
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Initrd Default Target
|
Description=Initrd Default Target
|
||||||
Documentation=man:systemd.special(7)
|
Documentation=man:systemd.special(7)
|
||||||
OnFailure=emergency.target
|
|
||||||
OnFailureJobMode=replace-irreversibly
|
|
||||||
ConditionPathExists=/etc/initrd-release
|
ConditionPathExists=/etc/initrd-release
|
||||||
Requires=basic.target
|
Requires=basic.target
|
||||||
Wants=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-parse-etc.service
|
Wants=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-parse-etc.service
|
||||||
|
|
|
@ -13,5 +13,3 @@ Documentation=man:systemd.special(7)
|
||||||
DefaultDependencies=no
|
DefaultDependencies=no
|
||||||
Conflicts=shutdown.target
|
Conflicts=shutdown.target
|
||||||
After=local-fs-pre.target
|
After=local-fs-pre.target
|
||||||
OnFailure=emergency.target
|
|
||||||
OnFailureJobMode=replace-irreversibly
|
|
||||||
|
|
Loading…
Reference in New Issue