1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
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"
11 #include "socket-util.h"
12 #include "string-util.h"
13 #include "sysctl-util.h"
15 static int set_ipv6_proxy_ndp_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
20 r
= sd_netlink_message_get_errno(m
);
21 if (r
< 0 && r
!= -EEXIST
)
22 log_link_message_warning_errno(link
, m
, r
, "Could not add IPv6 proxy ndp address entry, ignoring");
27 /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
28 static int ipv6_proxy_ndp_address_configure(Link
*link
, const struct in6_addr
*address
) {
29 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
33 assert(link
->manager
);
36 /* create new netlink message */
37 r
= sd_rtnl_message_new_neigh(link
->manager
->rtnl
, &req
, RTM_NEWNEIGH
, link
->ifindex
, AF_INET6
);
39 return log_link_error_errno(link
, r
, "Could not create RTM_NEWNEIGH message: %m");
41 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
43 return log_link_error_errno(link
, r
, "Could not set neighbor flags: %m");
45 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, address
);
47 return log_link_error_errno(link
, r
, "Could not append NDA_DST attribute: %m");
49 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, set_ipv6_proxy_ndp_address_handler
,
50 link_netlink_destroy_callback
, link
);
52 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
59 static bool ipv6_proxy_ndp_is_needed(Link
*link
) {
62 if (link
->flags
& IFF_LOOPBACK
)
68 if (link
->network
->ipv6_proxy_ndp
>= 0)
69 return link
->network
->ipv6_proxy_ndp
;
71 return !set_isempty(link
->network
->ipv6_proxy_ndp_addresses
);
74 static int ipv6_proxy_ndp_set(Link
*link
) {
80 if (!socket_ipv6_is_supported())
83 v
= ipv6_proxy_ndp_is_needed(link
);
85 r
= sysctl_write_ip_property_boolean(AF_INET6
, link
->ifname
, "proxy_ndp", v
);
87 return log_link_warning_errno(link
, r
, "Cannot configure proxy NDP for the interface, ignoring: %m");
92 /* configure all ipv6 proxy ndp addresses */
93 int link_set_ipv6_proxy_ndp_addresses(Link
*link
) {
94 struct in6_addr
*address
;
98 assert(link
->network
);
100 /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
101 r
= ipv6_proxy_ndp_set(link
);
105 SET_FOREACH(address
, link
->network
->ipv6_proxy_ndp_addresses
) {
106 r
= ipv6_proxy_ndp_address_configure(link
, address
);
114 int config_parse_ipv6_proxy_ndp_address(
116 const char *filename
,
119 unsigned section_line
,
126 _cleanup_free_
struct in6_addr
*address
= NULL
;
127 Network
*network
= userdata
;
128 union in_addr_union buffer
;
135 if (isempty(rvalue
)) {
136 network
->ipv6_proxy_ndp_addresses
= set_free_free(network
->ipv6_proxy_ndp_addresses
);
140 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
142 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
143 "Failed to parse IPv6 proxy NDP address, ignoring: %s", rvalue
);
147 if (in_addr_is_null(AF_INET6
, &buffer
)) {
148 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
149 "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue
);
153 address
= newdup(struct in6_addr
, &buffer
.in6
, 1);
157 r
= set_ensure_put(&network
->ipv6_proxy_ndp_addresses
, &in6_addr_hash_ops
, address
);