netpoll: Extract IPv6 address retrieval function

Extract the IPv6 address retrieval logic from netpoll_setup() into
a dedicated helper function netpoll_take_ipv6() to improve code
organization and readability.

The function handles obtaining the local IPv6 address from the
network device, including proper address type matching between
local and remote addresses (link-local vs global), and includes
appropriate error handling when IPv6 is not supported or no
suitable address is available.

Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250618-netpoll_ip_ref-v1-3-c2ac00fe558f@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Breno Leitao 2025-06-18 02:32:47 -07:00 committed by Jakub Kicinski
parent 3699f992e8
commit 6ad7969a36

View File

@ -598,6 +598,47 @@ static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev,
}
}
/*
* Take the IPv6 from ndev and populate local_ip structure in netpoll
*/
static int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev)
{
char buf[MAC_ADDR_STR_LEN + 1];
int err = -EDESTADDRREQ;
struct inet6_dev *idev;
if (!IS_ENABLED(CONFIG_IPV6)) {
np_err(np, "IPv6 is not supported %s, aborting\n",
egress_dev(np, buf));
return -EINVAL;
}
idev = __in6_dev_get(ndev);
if (idev) {
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
list_for_each_entry(ifp, &idev->addr_list, if_list) {
if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
!!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
continue;
/* Got the IP, let's return */
np->local_ip.in6 = ifp->addr;
err = 0;
break;
}
read_unlock_bh(&idev->lock);
}
if (err) {
np_err(np, "no IPv6 address for %s, aborting\n",
egress_dev(np, buf));
return err;
}
np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
return 0;
}
/*
* Take the IPv4 from ndev and populate local_ip structure in netpoll
*/
@ -675,41 +716,12 @@ int netpoll_setup(struct netpoll *np)
err = netpoll_take_ipv4(np, ndev);
if (err)
goto put;
ip_overwritten = true;
} else {
#if IS_ENABLED(CONFIG_IPV6)
struct inet6_dev *idev;
err = -EDESTADDRREQ;
idev = __in6_dev_get(ndev);
if (idev) {
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
list_for_each_entry(ifp, &idev->addr_list, if_list) {
if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
!!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
continue;
np->local_ip.in6 = ifp->addr;
ip_overwritten = true;
err = 0;
break;
}
read_unlock_bh(&idev->lock);
}
if (err) {
np_err(np, "no IPv6 address for %s, aborting\n",
egress_dev(np, buf));
err = netpoll_take_ipv6(np, ndev);
if (err)
goto put;
} else
np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
#else
np_err(np, "IPv6 is not supported %s, aborting\n",
egress_dev(np, buf));
err = -EINVAL;
goto put;
#endif
}
ip_overwritten = true;
}
err = __netpoll_setup(np, ndev);