Skip to content

Commit 6b4d5af

Browse files
russellbMu Huai
authored and
Mu Huai
committed
[Core] Enable IPv6 with vllm.utils.make_zmq_socket() (vllm-project#16506)
Signed-off-by: Russell Bryant <[email protected]> Signed-off-by: Mu Huai <[email protected]>
1 parent 658f4ea commit 6b4d5af

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

tests/test_utils.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010

1111
import pytest
1212
import torch
13+
import zmq
1314
from vllm_test_utils.monitor import monitor
1415

1516
from vllm.config import ParallelConfig, VllmConfig, set_current_vllm_config
1617
from vllm.utils import (CacheInfo, FlexibleArgumentParser, LRUCache,
1718
MemorySnapshot, PlaceholderModule, StoreBoolean,
1819
bind_kv_cache, deprecate_kwargs, get_open_port,
19-
memory_profiling, merge_async_iterators, sha256,
20+
make_zmq_socket, memory_profiling,
21+
merge_async_iterators, sha256, split_zmq_path,
2022
supports_kw, swap_dict_values)
2123

2224
from .utils import create_new_process_for_each_test, error_on_warning
@@ -662,3 +664,53 @@ def test_sha256(input: tuple, output: int):
662664

663665
# hashing different input, returns different value
664666
assert hash != sha256(input + (1, ))
667+
668+
669+
@pytest.mark.parametrize(
670+
"path,expected",
671+
[
672+
("ipc://some_path", ("ipc", "some_path", "")),
673+
("tcp://127.0.0.1:5555", ("tcp", "127.0.0.1", "5555")),
674+
("tcp://[::1]:5555", ("tcp", "::1", "5555")), # IPv6 address
675+
("inproc://some_identifier", ("inproc", "some_identifier", "")),
676+
]
677+
)
678+
def test_split_zmq_path(path, expected):
679+
assert split_zmq_path(path) == expected
680+
681+
682+
@pytest.mark.parametrize(
683+
"invalid_path",
684+
[
685+
"invalid_path", # Missing scheme
686+
"tcp://127.0.0.1", # Missing port
687+
"tcp://[::1]", # Missing port for IPv6
688+
"tcp://:5555", # Missing host
689+
]
690+
)
691+
def test_split_zmq_path_invalid(invalid_path):
692+
with pytest.raises(ValueError):
693+
split_zmq_path(invalid_path)
694+
695+
696+
def test_make_zmq_socket_ipv6():
697+
# Check if IPv6 is supported by trying to create an IPv6 socket
698+
try:
699+
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
700+
sock.close()
701+
except socket.error:
702+
pytest.skip("IPv6 is not supported on this system")
703+
704+
ctx = zmq.Context()
705+
ipv6_path = "tcp://[::]:5555" # IPv6 loopback address
706+
socket_type = zmq.REP # Example socket type
707+
708+
# Create the socket
709+
zsock: zmq.Socket = make_zmq_socket(ctx, ipv6_path, socket_type)
710+
711+
# Verify that the IPV6 option is set
712+
assert zsock.getsockopt(zmq.IPV6) == 1, "IPV6 option should be enabled for IPv6 addresses"
713+
714+
# Clean up
715+
zsock.close()
716+
ctx.term()

vllm/utils.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from typing import (TYPE_CHECKING, Any, Callable, Generic, Literal, NamedTuple,
4646
Optional, Sequence, Tuple, Type, TypeVar, Union, cast,
4747
overload)
48+
from urllib.parse import urlparse
4849
from uuid import uuid4
4950

5051
import cachetools
@@ -2278,6 +2279,27 @@ def get_exception_traceback():
22782279
return err_str
22792280

22802281

2282+
def split_zmq_path(path: str) -> Tuple[str, str, str]:
2283+
"""Split a zmq path into its parts."""
2284+
parsed = urlparse(path)
2285+
if not parsed.scheme:
2286+
raise ValueError(f"Invalid zmq path: {path}")
2287+
2288+
scheme = parsed.scheme
2289+
host = parsed.hostname or ""
2290+
port = str(parsed.port or "")
2291+
2292+
if scheme == "tcp" and not all((host, port)):
2293+
# The host and port fields are required for tcp
2294+
raise ValueError(f"Invalid zmq path: {path}")
2295+
2296+
if scheme != "tcp" and port:
2297+
# port only makes sense with tcp
2298+
raise ValueError(f"Invalid zmq path: {path}")
2299+
2300+
return scheme, host, port
2301+
2302+
22812303
# Adapted from: https://github.com/sgl-project/sglang/blob/v0.4.1/python/sglang/srt/utils.py#L783 # noqa: E501
22822304
def make_zmq_socket(
22832305
ctx: Union[zmq.asyncio.Context, zmq.Context], # type: ignore[name-defined]
@@ -2317,6 +2339,12 @@ def make_zmq_socket(
23172339
if identity is not None:
23182340
socket.setsockopt(zmq.IDENTITY, identity)
23192341

2342+
# Determine if the path is a TCP socket with an IPv6 address.
2343+
# Enable IPv6 on the zmq socket if so.
2344+
scheme, host, _ = split_zmq_path(path)
2345+
if scheme == "tcp" and is_valid_ipv6_address(host):
2346+
socket.setsockopt(zmq.IPV6, 1)
2347+
23202348
if bind:
23212349
socket.bind(path)
23222350
else:

0 commit comments

Comments
 (0)