Skip to content

Commit 0d29ad8

Browse files
authored
Support IPv6 in get_address() (#387)
Uses `psutil` to retrieve IPv6 address of a network interface when the optional `use_ipv6=True` kwarg is set. Note: testing is not included as it's not safely possible at the moment because it requires that the system itself has IPv6 support enabled, there's at least one interface with an IPv6 address and that the test itself can determine those conditions a priori. Closes #386 . Authors: - Peter Andreas Entschev (https://github.com/pentschev) Approvers: - Mads R. B. Kristensen (https://github.com/madsbk) URL: #387
1 parent 076aba9 commit 0d29ad8

File tree

1 file changed

+34
-9
lines changed

1 file changed

+34
-9
lines changed

python/ucxx/ucxx/utils.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES.
1+
# SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION & AFFILIATES.
22
# SPDX-License-Identifier: BSD-3-Clause
33

44
import fcntl
@@ -126,7 +126,7 @@ def filter(self, record):
126126
return logger
127127

128128

129-
def get_address(ifname=None):
129+
def get_address(ifname=None, use_ipv6=False):
130130
"""
131131
Get the address associated with a network interface.
132132
@@ -137,6 +137,15 @@ def get_address(ifname=None):
137137
If None, it uses the value of environment variable `UCXPY_IFNAME`
138138
and if `UCXPY_IFNAME` is not set it defaults to "ib0"
139139
An OSError is raised for invalid interfaces.
140+
use_ipv6 : bool
141+
Whether to get IPv6 addresses instead of the IPv4 default.
142+
NOTE: Requires the `psutil` package.
143+
144+
Raises
145+
------
146+
OSError
147+
If no device was found with the specified `ifname`, or no suitable
148+
devices were found when `ifname=None`.
140149
141150
Returns
142151
-------
@@ -150,16 +159,31 @@ def get_address(ifname=None):
150159
151160
>>> get_address(ifname='lo')
152161
'127.0.0.1'
162+
163+
>>> get_address(ifname='lo', use_ipv6=True)
164+
'::1'
153165
"""
154166

155167
def _get_address(ifname):
156-
ifname = ifname.encode()
157-
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
158-
return socket.inet_ntoa(
159-
fcntl.ioctl(
160-
s.fileno(), 0x8915, struct.pack("256s", ifname[:15]) # SIOCGIFADDR
161-
)[20:24]
162-
)
168+
if use_ipv6:
169+
import psutil
170+
171+
addrs = psutil.net_if_addrs()
172+
if ifname in addrs:
173+
for addr in addrs[ifname]:
174+
if addr.family == socket.AF_INET6:
175+
return addr.address.split("%")[0]
176+
raise OSError("No such device")
177+
else:
178+
ifname = ifname.encode()
179+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
180+
return socket.inet_ntoa(
181+
fcntl.ioctl(
182+
s.fileno(),
183+
0x8915, # SIOCGIFADDR
184+
struct.pack("256s", ifname[:15]),
185+
)[20:24]
186+
)
163187

164188
def _try_interfaces():
165189
prefix_priority = ["ib", "eth", "en"]
@@ -177,6 +201,7 @@ def _try_interfaces():
177201
return _get_address(i)
178202
except OSError:
179203
pass
204+
raise OSError("No devices found")
180205

181206
if ifname is None:
182207
ifname = os.environ.get("UCXPY_IFNAME")

0 commit comments

Comments
 (0)