|
| 1 | +/* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| 2 | + |
| 3 | +#include <linux/if.h> |
| 4 | +#include <linux/if_arp.h> |
| 5 | + |
| 6 | +#include "in-addr-util.h" |
| 7 | +#include "networkd-address.h" |
| 8 | +#include "networkd-ipv6ll.h" |
| 9 | +#include "networkd-link.h" |
| 10 | +#include "networkd-network.h" |
| 11 | +#include "networkd-util.h" |
| 12 | +#include "socket-util.h" |
| 13 | +#include "string-table.h" |
| 14 | +#include "strv.h" |
| 15 | + |
| 16 | +bool link_ipv6ll_enabled(Link *link) { |
| 17 | + assert(link); |
| 18 | + |
| 19 | + if (!socket_ipv6_is_supported()) |
| 20 | + return false; |
| 21 | + |
| 22 | + if (link->flags & IFF_LOOPBACK) |
| 23 | + return false; |
| 24 | + |
| 25 | + if (!link->network) |
| 26 | + return false; |
| 27 | + |
| 28 | + if (link->iftype == ARPHRD_CAN) |
| 29 | + return false; |
| 30 | + |
| 31 | + if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "nlmon")) |
| 32 | + return false; |
| 33 | + |
| 34 | + if (link->network->bond) |
| 35 | + return false; |
| 36 | + |
| 37 | + return link->network->link_local & ADDRESS_FAMILY_IPV6; |
| 38 | +} |
| 39 | + |
| 40 | +bool link_may_have_ipv6ll(Link *link) { |
| 41 | + assert(link); |
| 42 | + |
| 43 | + /* |
| 44 | + * This is equivalent to link_ipv6ll_enabled() for non-WireGuard interfaces. |
| 45 | + * |
| 46 | + * For WireGuard interface, the kernel does not assign any IPv6LL addresses, but we can assign |
| 47 | + * it manually. It is necessary to set an IPv6LL address manually to run NDisc or RADV on |
| 48 | + * WireGuard interface. Note, also Multicast=yes must be set. See #17380. |
| 49 | + * |
| 50 | + * TODO: May be better to introduce GenerateIPv6LinkLocalAddress= setting, and use algorithms |
| 51 | + * used in networkd-address-generation.c |
| 52 | + */ |
| 53 | + |
| 54 | + if (link_ipv6ll_enabled(link)) |
| 55 | + return true; |
| 56 | + |
| 57 | + /* IPv6LL address can be manually assigned on WireGuard interface. */ |
| 58 | + if (streq_ptr(link->kind, "wireguard")) { |
| 59 | + Address *a; |
| 60 | + |
| 61 | + if (!link->network) |
| 62 | + return false; |
| 63 | + |
| 64 | + ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) { |
| 65 | + if (a->family != AF_INET6) |
| 66 | + continue; |
| 67 | + if (in6_addr_is_set(&a->in_addr_peer.in6)) |
| 68 | + continue; |
| 69 | + if (in6_addr_is_link_local(&a->in_addr.in6)) |
| 70 | + return true; |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + return false; |
| 75 | +} |
| 76 | + |
| 77 | +static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = { |
| 78 | + [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64", |
| 79 | + [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none", |
| 80 | + [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy", |
| 81 | + [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random", |
| 82 | +}; |
| 83 | + |
| 84 | +DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode); |
| 85 | +DEFINE_CONFIG_PARSE_ENUM( |
| 86 | + config_parse_ipv6_link_local_address_gen_mode, |
| 87 | + ipv6_link_local_address_gen_mode, |
| 88 | + IPv6LinkLocalAddressGenMode, |
| 89 | + "Failed to parse IPv6 link local address generation mode"); |
0 commit comments