X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-address.c;h=aeadb7b01bf3992508497f923d1b3c958e888751;hb=93b0b88c3a3f9e942aeedcdf5d12585dba61790d;hp=23d40ccc4119b67fb809ee3a9bc0952c65be32a9;hpb=a93503e86f5ee5f46fdb3960d88dbfb2e55198c4;p=thirdparty%2Fsystemd.git diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 23d40ccc411..aeadb7b01bf 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -20,6 +20,24 @@ #define ADDRESSES_PER_LINK_MAX 2048U #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U +int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret) { + assert(link); + assert(ret); + + /* see RFC4291 section 2.5.1 */ + ret->s6_addr[8] = link->mac.ether_addr_octet[0]; + ret->s6_addr[8] ^= 1 << 1; + ret->s6_addr[9] = link->mac.ether_addr_octet[1]; + ret->s6_addr[10] = link->mac.ether_addr_octet[2]; + ret->s6_addr[11] = 0xff; + ret->s6_addr[12] = 0xfe; + ret->s6_addr[13] = link->mac.ether_addr_octet[3]; + ret->s6_addr[14] = link->mac.ether_addr_octet[4]; + ret->s6_addr[15] = link->mac.ether_addr_octet[5]; + + return 0; +} + int address_new(Address **ret) { _cleanup_(address_freep) Address *address = NULL; @@ -32,6 +50,8 @@ int address_new(Address **ret) { .scope = RT_SCOPE_UNIVERSE, .cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME, .cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME, + .duplicate_address_detection = ADDRESS_FAMILY_IPV6, + .prefix_route = true, }; *ret = TAKE_PTR(address); @@ -102,7 +122,7 @@ void address_free(Address *address) { hashmap_remove(address->network->addresses_by_section, address->section); } - if (address->link) { + if (address->link && !address->acd) { set_remove(address->link->addresses, address); set_remove(address->link->addresses_foreign, address); @@ -110,6 +130,8 @@ void address_free(Address *address) { memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr)); } + sd_ipv4acd_unref(address->acd); + network_config_section_free(address->section); free(address->label); free(address); @@ -183,7 +205,7 @@ static int address_compare_func(const Address *a1, const Address *a2) { } } -DEFINE_PRIVATE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func); +DEFINE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func); bool address_equal(Address *a1, Address *a2) { if (a1 == a2) @@ -244,11 +266,7 @@ static int address_add_internal(Link *link, Set **addresses, /* Consider address tentative until we get the real flags from the kernel */ address->flags = IFA_F_TENTATIVE; - r = set_ensure_allocated(addresses, &address_hash_ops); - if (r < 0) - return r; - - r = set_put(*addresses, address); + r = set_ensure_put(addresses, &address_hash_ops, address); if (r < 0) return r; if (r == 0) @@ -258,9 +276,7 @@ static int address_add_internal(Link *link, Set **addresses, if (ret) *ret = address; - - address = NULL; - + TAKE_PTR(address); return 0; } @@ -280,11 +296,7 @@ int address_add(Link *link, int family, const union in_addr_union *in_addr, unsi return r; } else if (r == 0) { /* Take over a foreign address */ - r = set_ensure_allocated(&link->addresses, &address_hash_ops); - if (r < 0) - return r; - - r = set_put(link->addresses, address); + r = set_ensure_put(&link->addresses, &address_hash_ops, address); if (r < 0) return r; @@ -431,7 +443,9 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EADDRNOTAVAIL) - log_link_warning_errno(link, r, "Could not drop address: %m"); + log_link_message_warning_errno(link, m, r, "Could not drop address"); + else + (void) manager_rtnl_process_address(rtnl, m, link->manager); return 1; } @@ -587,13 +601,13 @@ int address_configure( if (address->home_address) address->flags |= IFA_F_HOMEADDRESS; - if (address->duplicate_address_detection) + if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV6)) address->flags |= IFA_F_NODAD; if (address->manage_temporary_address) address->flags |= IFA_F_MANAGETEMPADDR; - if (address->prefix_route) + if (!address->prefix_route) address->flags |= IFA_F_NOPREFIXROUTE; if (address->autojoin) @@ -658,9 +672,101 @@ int address_configure( return log_link_error_errno(link, r, "Could not add address: %m"); } + if (address->acd) { + assert(address->family == AF_INET); + if (DEBUG_LOGGING) { + _cleanup_free_ char *pretty = NULL; + + (void) in_addr_to_string(address->family, &address->in_addr, &pretty); + log_link_debug(link, "Starting IPv4ACD client. Probing address %s", strna(pretty)); + } + + r = sd_ipv4acd_start(address->acd, true); + if (r < 0) + log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m"); + } + return 1; } +static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) { + _cleanup_free_ char *pretty = NULL; + Address *address; + Link *link; + int r; + + assert(acd); + assert(userdata); + + address = (Address *) userdata; + link = address->link; + + (void) in_addr_to_string(address->family, &address->in_addr, &pretty); + switch (event) { + case SD_IPV4ACD_EVENT_STOP: + log_link_debug(link, "Stopping ACD client..."); + return; + + case SD_IPV4ACD_EVENT_BIND: + log_link_debug(link, "Successfully claimed address %s", strna(pretty)); + link_check_ready(link); + break; + + case SD_IPV4ACD_EVENT_CONFLICT: + log_link_warning(link, "DAD conflict. Dropping address %s", strna(pretty)); + r = address_remove(address, link, NULL); + if (r < 0) + log_link_error_errno(link, r, "Failed to drop DAD conflicted address %s", strna(pretty));; + + link_check_ready(link); + break; + + default: + assert_not_reached("Invalid IPv4ACD event."); + } + + sd_ipv4acd_stop(acd); + + return; +} + +int configure_ipv4_duplicate_address_detection(Link *link, Address *address) { + int r; + + assert(link); + assert(address); + assert(address->family == AF_INET); + assert(!address->link && address->network); + + address->link = link; + + r = sd_ipv4acd_new(&address->acd); + if (r < 0) + return r; + + r = sd_ipv4acd_attach_event(address->acd, NULL, 0); + if (r < 0) + return r; + + r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex); + if (r < 0) + return r; + + r = sd_ipv4acd_set_mac(address->acd, &link->mac); + if (r < 0) + return r; + + r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in); + if (r < 0) + return r; + + r = sd_ipv4acd_set_callback(address->acd, static_address_on_acd, address); + if (r < 0) + return r; + + return 0; +} + int config_parse_broadcast( const char *unit, const char *filename, @@ -840,7 +946,7 @@ int config_parse_lifetime(const char *unit, void *userdata) { Network *network = userdata; _cleanup_(address_free_or_set_invalidp) Address *n = NULL; - unsigned k; + uint32_t k; int r; assert(filename); @@ -853,8 +959,8 @@ int config_parse_lifetime(const char *unit, if (r < 0) return r; - /* We accept only "forever", "infinity", or "0". */ - if (STR_IN_SET(rvalue, "forever", "infinity")) + /* We accept only "forever", "infinity", empty, or "0". */ + if (STR_IN_SET(rvalue, "forever", "infinity", "")) k = CACHE_INFO_INFINITY_LIFE_TIME; else if (streq(rvalue, "0")) k = 0; @@ -865,7 +971,7 @@ int config_parse_lifetime(const char *unit, } n->cinfo.ifa_prefered = k; - n = NULL; + TAKE_PTR(n); return 0; } @@ -897,17 +1003,17 @@ int config_parse_address_flags(const char *unit, r = parse_boolean(rvalue); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to parse address flag, ignoring: %s", rvalue); + "Failed to parse %s=, ignoring: %s", lvalue, rvalue); return 0; } if (streq(lvalue, "HomeAddress")) n->home_address = r; - else if (streq(lvalue, "DuplicateAddressDetection")) - n->duplicate_address_detection = r; else if (streq(lvalue, "ManageTemporaryAddress")) n->manage_temporary_address = r; else if (streq(lvalue, "PrefixRoute")) + n->prefix_route = !r; + else if (streq(lvalue, "AddPrefixRoute")) n->prefix_route = r; else if (streq(lvalue, "AutoJoin")) n->autojoin = r; @@ -957,6 +1063,56 @@ int config_parse_address_scope(const char *unit, } } + n->scope_set = true; + n = NULL; + return 0; +} + +int config_parse_duplicate_address_detection( + 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_(address_free_or_set_invalidp) Address *n = NULL; + AddressFamily a; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = address_new_static(network, filename, section_line, &n); + if (r < 0) + return r; + + r = parse_boolean(rvalue); + if (r >= 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "For historical reasons, %s=%s means %s=%s. " + "Please use 'both', 'ipv4', 'ipv6' or 'none' instead.", + lvalue, rvalue, lvalue, r ? "none" : "both"); + n->duplicate_address_detection = r ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_YES; + n = NULL; + return 0; + } + + a = duplicate_address_detection_address_family_from_string(rvalue); + if (a < 0) { + log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), + "Failed to parse %s=, ignoring: %s", lvalue, rvalue); + return 0; + } + + n->duplicate_address_detection = a; n = NULL; return 0; } @@ -980,5 +1136,8 @@ int address_section_verify(Address *address) { address->section->filename, address->section->line); } + if (!address->scope_set && in_addr_is_localhost(address->family, &address->in_addr) > 0) + address->scope = RT_SCOPE_HOST; + return 0; }