network: Add support to advertie ipv6 route
Implements https://tools.ietf.org/html/rfc4191 cat veth99.network ``` [Match] Name=veth99 [Network] DHCP=no IPv6PrefixDelegation=yes Address=2001:db8:0:1::1/64 [IPv6Prefix] Prefix=2001:db8:0:1::4/64 [IPv6RoutePrefix] Route=2001:db0:fff::/48 ``` Wireshark ``` Frame 481: 142 bytes on wire (1136 bits), 142 bytes captured (1136 bits) on interface 0 Ethernet II, Src: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4), Dst: IPv6mcast_01 (33:33:00:00:00:01) Internet Protocol Version 6, Src: fe80::1c04:f8ff:feb8:2fd4, Dst: ff02::1 Internet Control Message Protocol v6 Type: Router Advertisement (134) Code: 0 Checksum: 0xec77 [correct] [Checksum Status: Good] Cur hop limit: 0 Flags: 0x00, Prf (Default Router Preference): Medium Router lifetime (s): 0 Reachable time (ms): 0 Retrans timer (ms): 0 ICMPv6 Option (Source link-layer address : 1e:04:f8:b8:2f:d4) Type: Source link-layer address (1) Length: 1 (8 bytes) Link-layer address: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4) ICMPv6 Option (MTU : 1500) Type: MTU (5) Length: 1 (8 bytes) Reserved MTU: 1500 ICMPv6 Option (Prefix information : 2001:db8:0:1::4/64) Type: Prefix information (3) Length: 4 (32 bytes) Prefix Length: 64 Flag: 0xc0, On-link flag(L), Autonomous address-configuration flag(A) Valid Lifetime: 2592000 Preferred Lifetime: 604800 Reserved Prefix: 2001:db8:0:1::4 ICMPv6 Option (Route Information : Medium 2001:db0:fff::/48) Type: Route Information (24) Length: 3 (24 bytes) Prefix Length: 48 Flag: 0x00, Route Preference: Medium ...0 0... = Route Preference: Medium (0) 000. .000 = Reserved: 0 Route Lifetime: 604800 Prefix: 2001:db0:fff:: ```
This commit is contained in:
@@ -223,6 +223,8 @@ IPv6Prefix.OnLink, config_parse_prefix_flags,
|
||||
IPv6Prefix.AddressAutoconfiguration, config_parse_prefix_flags, 0, 0
|
||||
IPv6Prefix.ValidLifetimeSec, config_parse_prefix_lifetime, 0, 0
|
||||
IPv6Prefix.PreferredLifetimeSec, config_parse_prefix_lifetime, 0, 0
|
||||
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
|
||||
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
|
||||
CAN.BitRate, config_parse_si_size, 0, offsetof(Network, can_bitrate)
|
||||
CAN.SamplePoint, config_parse_permille, 0, offsetof(Network, can_sample_point)
|
||||
CAN.RestartSec, config_parse_sec, 0, offsetof(Network, can_restart_us)
|
||||
|
||||
@@ -458,6 +458,7 @@ int network_load_one(Manager *manager, const char *filename) {
|
||||
"BridgeVLAN\0"
|
||||
"IPv6PrefixDelegation\0"
|
||||
"IPv6Prefix\0"
|
||||
"IPv6RoutePrefix\0"
|
||||
"CAN\0",
|
||||
config_item_perf_lookup, network_network_gperf_lookup,
|
||||
CONFIG_PARSE_WARN, network);
|
||||
|
||||
@@ -221,6 +221,7 @@ struct Network {
|
||||
LIST_HEAD(Neighbor, neighbors);
|
||||
LIST_HEAD(AddressLabel, address_labels);
|
||||
LIST_HEAD(Prefix, static_prefixes);
|
||||
LIST_HEAD(Prefix, static_route_prefixes);
|
||||
LIST_HEAD(RoutingPolicyRule, rules);
|
||||
|
||||
unsigned n_static_addresses;
|
||||
@@ -230,6 +231,7 @@ struct Network {
|
||||
unsigned n_neighbors;
|
||||
unsigned n_address_labels;
|
||||
unsigned n_static_prefixes;
|
||||
unsigned n_static_route_prefixes;
|
||||
unsigned n_rules;
|
||||
|
||||
Hashmap *addresses_by_section;
|
||||
@@ -238,6 +240,7 @@ struct Network {
|
||||
Hashmap *neighbors_by_section;
|
||||
Hashmap *address_labels_by_section;
|
||||
Hashmap *prefixes_by_section;
|
||||
Hashmap *route_prefixes_by_section;
|
||||
Hashmap *rules_by_section;
|
||||
|
||||
/* All kinds of DNS configuration */
|
||||
|
||||
+186
-9
@@ -101,16 +101,100 @@ static int prefix_new_static(Network *network, const char *filename,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_prefix_new(Prefix **ret) {
|
||||
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
||||
|
||||
prefix = new0(Prefix, 1);
|
||||
if (!prefix)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sd_radv_route_prefix_new(&prefix->radv_route_prefix) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(prefix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void route_prefix_free(Prefix *prefix) {
|
||||
if (!prefix)
|
||||
return;
|
||||
|
||||
if (prefix->network) {
|
||||
LIST_REMOVE(prefixes, prefix->network->static_route_prefixes, prefix);
|
||||
assert(prefix->network->n_static_route_prefixes > 0);
|
||||
prefix->network->n_static_route_prefixes--;
|
||||
|
||||
if (prefix->section)
|
||||
hashmap_remove(prefix->network->route_prefixes_by_section,
|
||||
prefix->section);
|
||||
}
|
||||
|
||||
network_config_section_free(prefix->section);
|
||||
|
||||
free(prefix);
|
||||
}
|
||||
|
||||
static int route_prefix_new_static(Network *network, const char *filename,
|
||||
unsigned section_line, Prefix **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
assert(!!filename == (section_line > 0));
|
||||
|
||||
if (filename) {
|
||||
r = network_config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (section_line) {
|
||||
prefix = hashmap_get(network->route_prefixes_by_section, n);
|
||||
if (prefix) {
|
||||
*ret = TAKE_PTR(prefix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r = route_prefix_new(&prefix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
prefix->network = network;
|
||||
LIST_APPEND(prefixes, network->static_route_prefixes, prefix);
|
||||
network->n_static_route_prefixes++;
|
||||
|
||||
if (filename) {
|
||||
prefix->section = TAKE_PTR(n);
|
||||
|
||||
r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(prefix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_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) {
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
||||
@@ -234,6 +318,90 @@ int config_parse_prefix_lifetime(const char *unit,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_route_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) {
|
||||
|
||||
Network *network = userdata;
|
||||
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
||||
uint8_t prefixlen = 64;
|
||||
union in_addr_union in6addr;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_prefix_new_static(network, filename, section_line, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sd_radv_prefix_set_route_prefix(p->radv_route_prefix, &in6addr.in6, prefixlen) < 0)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
log_syntax(unit, LOG_INFO, filename, line, r, "Found route prefix %s", rvalue);
|
||||
|
||||
p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_route_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) {
|
||||
Network *network = userdata;
|
||||
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
||||
usec_t usec;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = route_prefix_new_static(network, filename, section_line, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = parse_sec(rvalue, &usec);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Roure lifetime is invalid, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* a value of 0xffffffff represents infinity */
|
||||
r = sd_radv_route_prefix_set_lifetime(p->radv_route_prefix, DIV_ROUND_UP(usec, USEC_PER_SEC));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
|
||||
size_t *n_dns) {
|
||||
_cleanup_free_ struct in6_addr *addresses = NULL;
|
||||
@@ -438,6 +606,15 @@ int radv_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
LIST_FOREACH(prefixes, p, link->network->static_route_prefixes) {
|
||||
r = sd_radv_add_route_prefix(link->radv, p->radv_route_prefix, false);
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return radv_emit_dns(link);
|
||||
|
||||
@@ -26,8 +26,10 @@ struct Prefix {
|
||||
NetworkConfigSection *section;
|
||||
|
||||
sd_radv_prefix *radv_prefix;
|
||||
sd_radv_route_prefix *radv_route_prefix;
|
||||
|
||||
LIST_FIELDS(Prefix, prefixes);
|
||||
LIST_FIELDS(Prefix, route_prefixes);
|
||||
};
|
||||
|
||||
int prefix_new(Prefix **ret);
|
||||
@@ -35,6 +37,11 @@ void prefix_free(Prefix *prefix);
|
||||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
|
||||
|
||||
int route_prefix_new(Prefix **ret);
|
||||
void route_prefix_free(Prefix *prefix);
|
||||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, route_prefix_free);
|
||||
|
||||
int radv_emit_dns(Link *link);
|
||||
int radv_configure(Link *link);
|
||||
|
||||
@@ -48,3 +55,5 @@ CONFIG_PARSER_PROTOTYPE(config_parse_prefix_flags);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_lifetime);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user