]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
a0e5c15d | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
a0e5c15d | 4 | #include <linux/if.h> |
a0e5c15d | 5 | |
a0e5c15d FK |
6 | #include "netlink-util.h" |
7 | #include "networkd-ipv6-proxy-ndp.h" | |
8 | #include "networkd-link.h" | |
9 | #include "networkd-manager.h" | |
10 | #include "networkd-network.h" | |
fdeba3f5 | 11 | #include "networkd-queue.h" |
18a121f9 | 12 | #include "socket-util.h" |
62e021a9 | 13 | #include "string-util.h" |
a0e5c15d | 14 | |
14d9ab9d YW |
15 | void network_adjust_ipv6_proxy_ndp(Network *network) { |
16 | assert(network); | |
17 | ||
18 | if (set_isempty(network->ipv6_proxy_ndp_addresses)) | |
19 | return; | |
20 | ||
21 | if (!socket_ipv6_is_supported()) { | |
22 | log_once(LOG_WARNING, | |
23 | "%s: IPv6 proxy NDP addresses are set, but IPv6 is not supported by kernel, " | |
24 | "Ignoring IPv6 proxy NDP addresses.", network->filename); | |
25 | network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses); | |
26 | } | |
27 | } | |
28 | ||
fdeba3f5 | 29 | static int ipv6_proxy_ndp_address_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { |
a0e5c15d FK |
30 | int r; |
31 | ||
32 | assert(link); | |
fdeba3f5 YW |
33 | assert(link->static_ipv6_proxy_ndp_messages > 0); |
34 | ||
35 | link->static_ipv6_proxy_ndp_messages--; | |
a0e5c15d FK |
36 | |
37 | r = sd_netlink_message_get_errno(m); | |
190d05c0 | 38 | if (r < 0) |
5ecb131d | 39 | log_link_message_warning_errno(link, m, r, "Could not add IPv6 proxy ndp address entry, ignoring"); |
a0e5c15d | 40 | |
fdeba3f5 YW |
41 | if (link->static_ipv6_proxy_ndp_messages == 0) { |
42 | log_link_debug(link, "IPv6 proxy NDP addresses set."); | |
43 | link->static_ipv6_proxy_ndp_configured = true; | |
44 | link_check_ready(link); | |
45 | } | |
46 | ||
a0e5c15d FK |
47 | return 1; |
48 | } | |
49 | ||
387f6955 | 50 | /* send a request to the kernel to add an IPv6 Proxy entry to the neighbour table */ |
fdeba3f5 YW |
51 | static int ipv6_proxy_ndp_address_configure( |
52 | const struct in6_addr *address, | |
53 | Link *link, | |
54 | link_netlink_message_handler_t callback) { | |
55 | ||
a0e5c15d | 56 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; |
a0e5c15d FK |
57 | int r; |
58 | ||
fdeba3f5 | 59 | assert(address); |
a0e5c15d | 60 | assert(link); |
a0e5c15d | 61 | assert(link->manager); |
fdeba3f5 YW |
62 | assert(link->manager->rtnl); |
63 | assert(callback); | |
a0e5c15d FK |
64 | |
65 | /* create new netlink message */ | |
d349f502 | 66 | r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6); |
a0e5c15d | 67 | if (r < 0) |
98b02994 | 68 | return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m"); |
a0e5c15d | 69 | |
4816e7bb | 70 | r = sd_rtnl_message_neigh_set_flags(req, NTF_PROXY); |
a0e5c15d | 71 | if (r < 0) |
98b02994 | 72 | return log_link_error_errno(link, r, "Could not set neighbor flags: %m"); |
a0e5c15d | 73 | |
d349f502 | 74 | r = sd_netlink_message_append_in6_addr(req, NDA_DST, address); |
a0e5c15d | 75 | if (r < 0) |
98b02994 | 76 | return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m"); |
a0e5c15d | 77 | |
fdeba3f5 | 78 | r = netlink_call_async(link->manager->rtnl, NULL, req, callback, |
302a796f | 79 | link_netlink_destroy_callback, link); |
a0e5c15d FK |
80 | if (r < 0) |
81 | return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); | |
82 | ||
1046bf9b YW |
83 | link_ref(link); |
84 | ||
fdeba3f5 | 85 | return 1; |
a0e5c15d FK |
86 | } |
87 | ||
fdeba3f5 | 88 | int link_request_static_ipv6_proxy_ndp_addresses(Link *link) { |
d349f502 | 89 | struct in6_addr *address; |
a0e5c15d FK |
90 | int r; |
91 | ||
18a121f9 | 92 | assert(link); |
d349f502 | 93 | assert(link->network); |
18a121f9 | 94 | |
fdeba3f5 YW |
95 | link->static_ipv6_proxy_ndp_configured = false; |
96 | ||
d349f502 | 97 | SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) { |
fdeba3f5 YW |
98 | r = link_queue_request(link, REQUEST_TYPE_IPV6_PROXY_NDP, address, false, |
99 | &link->static_ipv6_proxy_ndp_messages, | |
100 | ipv6_proxy_ndp_address_configure_handler, NULL); | |
d349f502 | 101 | if (r < 0) |
fdeba3f5 YW |
102 | return log_link_warning_errno(link, r, "Failed to request IPv6 proxy NDP address: %m"); |
103 | } | |
104 | ||
105 | if (link->static_ipv6_proxy_ndp_messages == 0) { | |
106 | link->static_ipv6_proxy_ndp_configured = true; | |
107 | link_check_ready(link); | |
108 | } else { | |
109 | log_link_debug(link, "Setting IPv6 proxy NDP addresses."); | |
110 | link_set_state(link, LINK_STATE_CONFIGURING); | |
a0e5c15d | 111 | } |
d349f502 | 112 | |
a0e5c15d FK |
113 | return 0; |
114 | } | |
a8c82f90 | 115 | |
fdeba3f5 YW |
116 | int request_process_ipv6_proxy_ndp_address(Request *req) { |
117 | assert(req); | |
118 | assert(req->link); | |
119 | assert(req->ipv6_proxy_ndp); | |
120 | assert(req->type == REQUEST_TYPE_IPV6_PROXY_NDP); | |
121 | ||
122 | if (!link_is_ready_to_configure(req->link, false)) | |
123 | return 0; | |
124 | ||
125 | return ipv6_proxy_ndp_address_configure(req->ipv6_proxy_ndp, req->link, req->netlink_handler); | |
126 | } | |
127 | ||
a8c82f90 YW |
128 | int config_parse_ipv6_proxy_ndp_address( |
129 | const char *unit, | |
130 | const char *filename, | |
131 | unsigned line, | |
132 | const char *section, | |
133 | unsigned section_line, | |
134 | const char *lvalue, | |
135 | int ltype, | |
136 | const char *rvalue, | |
137 | void *data, | |
138 | void *userdata) { | |
139 | ||
d349f502 | 140 | _cleanup_free_ struct in6_addr *address = NULL; |
a8c82f90 | 141 | Network *network = userdata; |
a8c82f90 | 142 | union in_addr_union buffer; |
d349f502 | 143 | int r; |
a8c82f90 YW |
144 | |
145 | assert(filename); | |
a8c82f90 | 146 | assert(rvalue); |
d349f502 | 147 | assert(network); |
a8c82f90 | 148 | |
d349f502 YW |
149 | if (isempty(rvalue)) { |
150 | network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses); | |
151 | return 0; | |
152 | } | |
a8c82f90 YW |
153 | |
154 | r = in_addr_from_string(AF_INET6, rvalue, &buffer); | |
155 | if (r < 0) { | |
156 | log_syntax(unit, LOG_WARNING, filename, line, r, | |
d349f502 | 157 | "Failed to parse IPv6 proxy NDP address, ignoring: %s", rvalue); |
a8c82f90 YW |
158 | return 0; |
159 | } | |
160 | ||
161 | if (in_addr_is_null(AF_INET6, &buffer)) { | |
162 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
163 | "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue); | |
164 | return 0; | |
165 | } | |
166 | ||
d349f502 YW |
167 | address = newdup(struct in6_addr, &buffer.in6, 1); |
168 | if (!address) | |
169 | return log_oom(); | |
170 | ||
171 | r = set_ensure_put(&network->ipv6_proxy_ndp_addresses, &in6_addr_hash_ops, address); | |
172 | if (r < 0) | |
173 | return log_oom(); | |
174 | if (r > 0) | |
175 | TAKE_PTR(address); | |
a8c82f90 YW |
176 | |
177 | return 0; | |
178 | } |