return generate_addresses(link, tokens, &RADV_APP_ID, prefix, prefixlen, ret);
}
+int regenerate_address(Address *address, Link *link) {
+ struct in6_addr masked;
+ sd_id128_t app_id;
+
+ assert(link);
+ assert(address);
+ assert(address->family == AF_INET6);
+ assert(!address->link && !address->network);
+
+ if (!address->token ||
+ address->token->type != ADDRESS_GENERATION_PREFIXSTABLE)
+ return 0;
+
+ switch (address->source) {
+ case NETWORK_CONFIG_SOURCE_STATIC:
+ app_id = RADV_APP_ID;
+ break;
+ case NETWORK_CONFIG_SOURCE_DHCP_PD:
+ app_id = DHCP_PD_APP_ID;
+ break;
+ case NETWORK_CONFIG_SOURCE_NDISC:
+ app_id = NDISC_APP_ID;
+ break;
+ default:
+ assert_not_reached();
+ }
+
+ masked = address->in_addr.in6;
+ in6_addr_mask(&masked, address->prefixlen);
+
+ return generate_stable_private_address(link, &app_id, &address->token->secret_key, &masked, &address->in_addr.in6, &address->in_addr.in6);
+}
+
int config_parse_address_generation_type(
const char *unit,
const char *filename,
#include "hashmap.h"
#include "in-addr-util.h"
+typedef struct Address Address;
typedef struct IPv6Token IPv6Token;
typedef struct Link Link;
int ndisc_generate_addresses(Link *link, const struct in6_addr *prefix, uint8_t prefixlen, Hashmap **ret);
int radv_generate_addresses(Link *link, Set *tokens, const struct in6_addr *prefix, uint8_t prefixlen, Hashmap **ret);
+int regenerate_address(Address *address, Link *link);
+
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
#include "netlink-util.h"
#include "networkd-address-pool.h"
#include "networkd-address.h"
+#include "networkd-dhcp-prefix-delegation.h"
#include "networkd-dhcp-server.h"
#include "networkd-ipv4acd.h"
#include "networkd-manager.h"
+#include "networkd-ndisc.h"
#include "networkd-netlabel.h"
#include "networkd-network.h"
#include "networkd-queue.h"
return 0;
}
-static int address_drop(Address *address) {
- Link *link = ASSERT_PTR(ASSERT_PTR(address)->link);
+static int address_removed_maybe_kernel_dad(Link *link, Address *address) {
+ int r;
+
+ assert(link);
+ assert(address);
+
+ if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ return 0;
+
+ if (address->family != AF_INET6)
+ return 0;
+
+ if (!FLAGS_SET(address->flags, IFA_F_TENTATIVE))
+ return 0;
+
+ log_link_info(link, "Address %s with tentative flag is removed, maybe a duplicated address is assigned on another node or link?",
+ IN6_ADDR_TO_STRING(&address->in_addr.in6));
+
+ /* Reset the address state, as the object may be reused in the below. */
+ address->state = 0;
+
+ switch (address->source) {
+ case NETWORK_CONFIG_SOURCE_STATIC:
+ r = link_reconfigure_radv_address(address, link);
+ break;
+ case NETWORK_CONFIG_SOURCE_DHCP_PD:
+ r = dhcp_pd_reconfigure_address(address, link);
+ break;
+ case NETWORK_CONFIG_SOURCE_NDISC:
+ r = ndisc_reconfigure_address(address, link);
+ break;
+ default:
+ r = 0;
+ }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to configure an alternative address: %m");
+
+ return 0;
+}
+
+static int address_drop(Address *in, bool removed_by_us) {
+ _cleanup_(address_unrefp) Address *address = address_ref(ASSERT_PTR(in));
+ Link *link = ASSERT_PTR(address->link);
int r;
r = address_set_masquerade(address, /* add = */ false);
address_detach(address);
+ if (!removed_by_us) {
+ r = address_removed_maybe_kernel_dad(link, address);
+ if (r < 0) {
+ link_enter_failed(link);
+ return r;
+ }
+ }
+
link_update_operstate(link, /* also_update_master = */ true);
link_check_ready(link);
return 0;
if (address_get_request(link, address, &req) >= 0)
address_enter_removed(req->userdata);
- (void) address_drop(address);
+ (void) address_drop(address, /* removed_by_us = */ true);
}
}
if (type == RTM_DELADDR) {
if (address) {
+ bool removed_by_us = FLAGS_SET(address->state, NETWORK_CONFIG_STATE_REMOVING);
+
address_enter_removed(address);
log_address_debug(address, "Forgetting removed", link);
- (void) address_drop(address);
+ (void) address_drop(address, removed_by_us);
} else
log_address_debug(tmp, "Kernel removed unknown", link);
return link_request_address(link, address, &link->dhcp_pd_messages, dhcp_pd_address_handler, NULL);
}
+int dhcp_pd_reconfigure_address(Address *address, Link *link) {
+ int r;
+
+ assert(address);
+ assert(address->source == NETWORK_CONFIG_SOURCE_DHCP_PD);
+ assert(link);
+
+ r = regenerate_address(address, link);
+ if (r <= 0)
+ return r;
+
+ r = dhcp_pd_request_address_one(address, link);
+ if (r < 0)
+ return r;
+
+ if (!link->dhcp_pd_configured)
+ link_set_state(link, LINK_STATE_CONFIGURING);
+
+ link_check_ready(link);
+ return 0;
+}
+
static int dhcp_pd_request_address(
Link *link,
const struct in6_addr *prefix,
#include "conf-parser.h"
+typedef struct Address Address;
typedef struct Link Link;
bool link_dhcp_pd_is_enabled(Link *link);
int dhcp6_pd_prefix_acquired(Link *uplink);
void dhcp_pd_prefix_lost(Link *uplink);
void dhcp4_pd_prefix_lost(Link *uplink);
+int dhcp_pd_reconfigure_address(Address *address, Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_pd_subnet_id);
return 0;
}
+int ndisc_reconfigure_address(Address *address, Link *link) {
+ int r;
+
+ assert(address);
+ assert(address->source == NETWORK_CONFIG_SOURCE_NDISC);
+ assert(link);
+
+ r = regenerate_address(address, link);
+ if (r <= 0)
+ return r;
+
+ r = ndisc_request_address(address, link, NULL);
+ if (r < 0)
+ return r;
+
+ if (!link->ndisc_configured)
+ link_set_state(link, LINK_STATE_CONFIGURING);
+
+ link_check_ready(link);
+ return 0;
+}
+
static int ndisc_redirect_route_new(sd_ndisc_redirect *rd, Route **ret) {
_cleanup_(route_unrefp) Route *route = NULL;
struct in6_addr gateway, destination;
#include "conf-parser.h"
#include "time-util.h"
+typedef struct Address Address;
typedef struct Link Link;
typedef struct Network Network;
void ndisc_flush(Link *link);
int link_request_ndisc(Link *link);
+int ndisc_reconfigure_address(Address *address, Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_start_dhcp6_client);
CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_use_domains);
return 0;
}
+int link_reconfigure_radv_address(Address *address, Link *link) {
+ int r;
+
+ assert(address);
+ assert(address->source == NETWORK_CONFIG_SOURCE_STATIC);
+ assert(link);
+
+ r = regenerate_address(address, link);
+ if (r <= 0)
+ return r;
+
+ r = link_request_static_address(link, address);
+ if (r < 0)
+ return r;
+
+ if (link->static_address_messages != 0) {
+ link->static_addresses_configured = false;
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ }
+
+ return 0;
+}
+
static int radv_set_prefix(Link *link, Prefix *prefix) {
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
int r;
void network_adjust_radv(Network *network);
int link_request_radv_addresses(Link *link);
+int link_reconfigure_radv_address(Address *address, Link *link);
bool link_radv_enabled(Link *link);
int radv_start(Link *link);