Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit effc12f

Browse files
caaverytiran
authored andcommitted
bpo-27584: New addition of vSockets to the python socket module (#2489)
* bpo-27584: New addition of vSockets to the python socket module Support for AF_VSOCK on Linux only * bpo-27584: Fixes for V2 Fixed syntax and naming problems. Fixed #ifdef AF_VSOCK checking Restored original aclocal.m4 * bpo-27584: Fixes for V3 Added checking for fcntl and thread modules. * bpo-27584: Fixes for V4 Fixed white space error * bpo-27584: Fixes for V5 Added back comma in (CID, port). * bpo-27584: Fixes for V6 Added news file. socket.rst now reflects first Linux introduction of AF_VSOCK. Fixed get_cid in test_socket.py. Replaced PyLong_FromLong with PyLong_FromUnsignedLong in socketmodule.c Got rid of extra AF_VSOCK #define. Added sockaddr_vm to sock_addr. * bpo-27584: Fixes for V7 Minor cleanup. * bpo-27584: Fixes for V8 Put back #undef AF_VSOCK as it is necessary when vm_sockets.h is not installed.
1 parent 5d57844 commit effc12f

File tree

9 files changed

+257
-2
lines changed

9 files changed

+257
-2
lines changed

Doc/library/socket.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ created. Socket addresses are represented as follows:
153153

154154
.. versionadded:: 3.6
155155

156+
- :const:`AF_VSOCK` allows communication between virtual machines and
157+
their hosts. The sockets are represented as a ``(CID, port)`` tuple
158+
where the context ID or CID and port are integers.
159+
160+
Availability: Linux >= 4.8 QEMU >= 2.8 ESX >= 4.0 ESX Workstation >= 6.5
161+
162+
.. versionadded:: 3.7
163+
156164
- Certain other address families (:const:`AF_PACKET`, :const:`AF_CAN`)
157165
support specific representations.
158166

@@ -395,6 +403,18 @@ Constants
395403

396404
.. versionadded:: 3.6
397405

406+
407+
.. data:: AF_VSOCK
408+
IOCTL_VM_SOCKETS_GET_LOCAL_CID
409+
VMADDR*
410+
SO_VM*
411+
412+
Constants for Linux host/guest communication.
413+
414+
Availability: Linux >= 4.8.
415+
416+
.. versionadded:: 3.7
417+
398418
.. data:: AF_LINK
399419

400420
Availability: BSD, OSX.

Lib/test/test_socket.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
HOST = support.HOST
3434
MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return
3535

36+
VSOCKPORT = 1234
37+
3638
try:
3739
import _thread as thread
3840
import threading
@@ -44,6 +46,16 @@
4446
except ImportError:
4547
_socket = None
4648

49+
def get_cid():
50+
if fcntl is None:
51+
return None
52+
try:
53+
with open("/dev/vsock", "rb") as f:
54+
r = fcntl.ioctl(f, socket.IOCTL_VM_SOCKETS_GET_LOCAL_CID, " ")
55+
except OSError:
56+
return None
57+
else:
58+
return struct.unpack("I", r)[0]
4759

4860
def _have_socket_can():
4961
"""Check whether CAN sockets are supported on this host."""
@@ -85,6 +97,11 @@ def _have_socket_alg():
8597
s.close()
8698
return True
8799

100+
def _have_socket_vsock():
101+
"""Check whether AF_VSOCK sockets are supported on this host."""
102+
ret = get_cid() is not None
103+
return ret
104+
88105
HAVE_SOCKET_CAN = _have_socket_can()
89106

90107
HAVE_SOCKET_CAN_ISOTP = _have_socket_can_isotp()
@@ -93,6 +110,8 @@ def _have_socket_alg():
93110

94111
HAVE_SOCKET_ALG = _have_socket_alg()
95112

113+
HAVE_SOCKET_VSOCK = _have_socket_vsock()
114+
96115
# Size in bytes of the int type
97116
SIZEOF_INT = array.array("i").itemsize
98117

@@ -387,6 +406,42 @@ def clientTearDown(self):
387406
self.cli = None
388407
ThreadableTest.clientTearDown(self)
389408

409+
@unittest.skipIf(fcntl is None, "need fcntl")
410+
@unittest.skipUnless(thread, 'Threading required for this test.')
411+
@unittest.skipUnless(HAVE_SOCKET_VSOCK,
412+
'VSOCK sockets required for this test.')
413+
@unittest.skipUnless(get_cid() != 2,
414+
"This test can only be run on a virtual guest.")
415+
class ThreadedVSOCKSocketStreamTest(unittest.TestCase, ThreadableTest):
416+
417+
def __init__(self, methodName='runTest'):
418+
unittest.TestCase.__init__(self, methodName=methodName)
419+
ThreadableTest.__init__(self)
420+
421+
def setUp(self):
422+
self.serv = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
423+
self.addCleanup(self.serv.close)
424+
self.serv.bind((socket.VMADDR_CID_ANY, VSOCKPORT))
425+
self.serv.listen()
426+
self.serverExplicitReady()
427+
self.conn, self.connaddr = self.serv.accept()
428+
self.addCleanup(self.conn.close)
429+
430+
def clientSetUp(self):
431+
time.sleep(0.1)
432+
self.cli = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
433+
self.addCleanup(self.cli.close)
434+
cid = get_cid()
435+
self.cli.connect((cid, VSOCKPORT))
436+
437+
def testStream(self):
438+
msg = self.conn.recv(1024)
439+
self.assertEqual(msg, MSG)
440+
441+
def _testStream(self):
442+
self.cli.send(MSG)
443+
self.cli.close()
444+
390445
class SocketConnectedTest(ThreadedTCPSocketTest):
391446
"""Socket tests for client-server connection.
392447
@@ -1874,6 +1929,54 @@ def _testCongestion(self):
18741929
self.assertIn(self.serv, r)
18751930

18761931

1932+
@unittest.skipIf(fcntl is None, "need fcntl")
1933+
@unittest.skipUnless(HAVE_SOCKET_VSOCK,
1934+
'VSOCK sockets required for this test.')
1935+
class BasicVSOCKTest(unittest.TestCase):
1936+
1937+
def testCrucialConstants(self):
1938+
socket.AF_VSOCK
1939+
1940+
def testVSOCKConstants(self):
1941+
socket.SO_VM_SOCKETS_BUFFER_SIZE
1942+
socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE
1943+
socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE
1944+
socket.VMADDR_CID_ANY
1945+
socket.VMADDR_PORT_ANY
1946+
socket.VMADDR_CID_HOST
1947+
socket.VM_SOCKETS_INVALID_VERSION
1948+
socket.IOCTL_VM_SOCKETS_GET_LOCAL_CID
1949+
1950+
def testCreateSocket(self):
1951+
with socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) as s:
1952+
pass
1953+
1954+
def testSocketBufferSize(self):
1955+
with socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) as s:
1956+
orig_max = s.getsockopt(socket.AF_VSOCK,
1957+
socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE)
1958+
orig = s.getsockopt(socket.AF_VSOCK,
1959+
socket.SO_VM_SOCKETS_BUFFER_SIZE)
1960+
orig_min = s.getsockopt(socket.AF_VSOCK,
1961+
socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE)
1962+
1963+
s.setsockopt(socket.AF_VSOCK,
1964+
socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE, orig_max * 2)
1965+
s.setsockopt(socket.AF_VSOCK,
1966+
socket.SO_VM_SOCKETS_BUFFER_SIZE, orig * 2)
1967+
s.setsockopt(socket.AF_VSOCK,
1968+
socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE, orig_min * 2)
1969+
1970+
self.assertEqual(orig_max * 2,
1971+
s.getsockopt(socket.AF_VSOCK,
1972+
socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE))
1973+
self.assertEqual(orig * 2,
1974+
s.getsockopt(socket.AF_VSOCK,
1975+
socket.SO_VM_SOCKETS_BUFFER_SIZE))
1976+
self.assertEqual(orig_min * 2,
1977+
s.getsockopt(socket.AF_VSOCK,
1978+
socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE))
1979+
18771980
@unittest.skipUnless(thread, 'Threading required for this test.')
18781981
class BasicTCPTest(SocketConnectedTest):
18791982

@@ -5681,6 +5784,10 @@ def test_main():
56815784
tests.extend([BasicCANTest, CANTest])
56825785
tests.extend([BasicRDSTest, RDSTest])
56835786
tests.append(LinuxKernelCryptoAPI)
5787+
tests.extend([
5788+
BasicVSOCKTest,
5789+
ThreadedVSOCKSocketStreamTest,
5790+
])
56845791
tests.extend([
56855792
CmsgMacroTests,
56865793
SendmsgUDPTest,

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ David Ascher
6565
Ammar Askar
6666
Chris AtLee
6767
Aymeric Augustin
68+
Cathy Avery
6869
John Aycock
6970
Donovan Baarda
7071
Arne Babenhauserheide
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
``AF_VSOCK`` has been added to the socket interface which allows
2+
communication between virtual machines and their host.

Modules/socketmodule.c

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,14 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
12251225
}
12261226
#endif /* AF_NETLINK */
12271227

1228+
#if defined(AF_VSOCK)
1229+
case AF_VSOCK:
1230+
{
1231+
struct sockaddr_vm *a = (struct sockaddr_vm *) addr;
1232+
return Py_BuildValue("II", a->svm_cid, a->svm_port);
1233+
}
1234+
#endif /* AF_VSOCK */
1235+
12281236
#ifdef ENABLE_IPV6
12291237
case AF_INET6:
12301238
{
@@ -1586,6 +1594,32 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
15861594
}
15871595
#endif
15881596

1597+
#if defined(AF_VSOCK)
1598+
case AF_VSOCK:
1599+
{
1600+
struct sockaddr_vm* addr;
1601+
int port, cid;
1602+
addr = (struct sockaddr_vm *)addr_ret;
1603+
memset(addr, 0, sizeof(struct sockaddr_vm));
1604+
if (!PyTuple_Check(args)) {
1605+
PyErr_Format(
1606+
PyExc_TypeError,
1607+
"getsockaddrarg: "
1608+
"AF_VSOCK address must be tuple, not %.500s",
1609+
Py_TYPE(args)->tp_name);
1610+
return 0;
1611+
}
1612+
if (!PyArg_ParseTuple(args, "II:getsockaddrarg", &cid, &port))
1613+
return 0;
1614+
addr->svm_family = s->sock_family;
1615+
addr->svm_port = port;
1616+
addr->svm_cid = cid;
1617+
*len_ret = sizeof(*addr);
1618+
return 1;
1619+
}
1620+
#endif
1621+
1622+
15891623
#ifdef AF_RDS
15901624
case AF_RDS:
15911625
/* RDS sockets use sockaddr_in: fall-through */
@@ -2103,6 +2137,14 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
21032137
}
21042138
#endif
21052139

2140+
#if defined(AF_VSOCK)
2141+
case AF_VSOCK:
2142+
{
2143+
*len_ret = sizeof (struct sockaddr_vm);
2144+
return 1;
2145+
}
2146+
#endif
2147+
21062148
#ifdef AF_RDS
21072149
case AF_RDS:
21082150
/* RDS sockets use sockaddr_in: fall-through */
@@ -2598,6 +2640,21 @@ sock_setsockopt(PySocketSockObject *s, PyObject *args)
25982640
unsigned int optlen;
25992641
PyObject *none;
26002642

2643+
#ifdef AF_VSOCK
2644+
if (s->sock_family == AF_VSOCK) {
2645+
uint64_t vflag; // Must be set width of 64 bits
2646+
/* setsockopt(level, opt, flag) */
2647+
if (PyArg_ParseTuple(args, "iiK:setsockopt",
2648+
&level, &optname, &vflag)) {
2649+
// level should always be set to AF_VSOCK
2650+
res = setsockopt(s->sock_fd, level, optname,
2651+
(void*)&vflag, sizeof vflag);
2652+
goto done;
2653+
}
2654+
return NULL;
2655+
}
2656+
#endif
2657+
26012658
/* setsockopt(level, opt, flag) */
26022659
if (PyArg_ParseTuple(args, "iii:setsockopt",
26032660
&level, &optname, &flag)) {
@@ -2668,20 +2725,39 @@ sock_getsockopt(PySocketSockObject *s, PyObject *args)
26682725
int res;
26692726
PyObject *buf;
26702727
socklen_t buflen = 0;
2728+
int flag = 0;
2729+
socklen_t flagsize;
26712730

26722731
if (!PyArg_ParseTuple(args, "ii|i:getsockopt",
26732732
&level, &optname, &buflen))
26742733
return NULL;
26752734

26762735
if (buflen == 0) {
2677-
int flag = 0;
2678-
socklen_t flagsize = sizeof flag;
2736+
#ifdef AF_VSOCK
2737+
if (s->sock_family == AF_VSOCK) {
2738+
uint64_t vflag = 0; // Must be set width of 64 bits
2739+
flagsize = sizeof vflag;
2740+
res = getsockopt(s->sock_fd, level, optname,
2741+
(void *)&vflag, &flagsize);
2742+
if (res < 0)
2743+
return s->errorhandler();
2744+
return PyLong_FromUnsignedLong(vflag);
2745+
}
2746+
#endif
2747+
flagsize = sizeof flag;
26792748
res = getsockopt(s->sock_fd, level, optname,
26802749
(void *)&flag, &flagsize);
26812750
if (res < 0)
26822751
return s->errorhandler();
26832752
return PyLong_FromLong(flag);
26842753
}
2754+
#ifdef AF_VSOCK
2755+
if (s->sock_family == AF_VSOCK) {
2756+
PyErr_SetString(PyExc_OSError,
2757+
"getsockopt string buffer not allowed");
2758+
return NULL;
2759+
}
2760+
#endif
26852761
if (buflen <= 0 || buflen > 1024) {
26862762
PyErr_SetString(PyExc_OSError,
26872763
"getsockopt buflen out of range");
@@ -6645,6 +6721,19 @@ PyInit__socket(void)
66456721
PyModule_AddIntMacro(m, NETLINK_CRYPTO);
66466722
#endif
66476723
#endif /* AF_NETLINK */
6724+
6725+
#ifdef AF_VSOCK
6726+
PyModule_AddIntConstant(m, "AF_VSOCK", AF_VSOCK);
6727+
PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_SIZE", 0);
6728+
PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_MIN_SIZE", 1);
6729+
PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_MAX_SIZE", 2);
6730+
PyModule_AddIntConstant(m, "VMADDR_CID_ANY", 0xffffffff);
6731+
PyModule_AddIntConstant(m, "VMADDR_PORT_ANY", 0xffffffff);
6732+
PyModule_AddIntConstant(m, "VMADDR_CID_HOST", 2);
6733+
PyModule_AddIntConstant(m, "VM_SOCKETS_INVALID_VERSION", 0xffffffff);
6734+
PyModule_AddIntConstant(m, "IOCTL_VM_SOCKETS_GET_LOCAL_CID", _IO(7, 0xb9));
6735+
#endif
6736+
66486737
#ifdef AF_ROUTE
66496738
/* Alias to emulate 4.4BSD */
66506739
PyModule_AddIntMacro(m, AF_ROUTE);

Modules/socketmodule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ typedef int socklen_t;
107107
#define SOL_ALG 279
108108
#endif
109109

110+
#ifdef HAVE_LINUX_VM_SOCKETS_H
111+
# include <linux/vm_sockets.h>
112+
#else
113+
# undef AF_VSOCK
114+
#endif
115+
110116
/* Linux 3.19 */
111117
#ifndef ALG_SET_AEAD_ASSOCLEN
112118
#define ALG_SET_AEAD_ASSOCLEN 4
@@ -193,6 +199,9 @@ typedef union sock_addr {
193199
#ifdef HAVE_SOCKADDR_ALG
194200
struct sockaddr_alg alg;
195201
#endif
202+
#ifdef AF_VSOCK
203+
struct sockaddr_vm vm;
204+
#endif
196205
} sock_addr_t;
197206

198207
/* The object holding a socket. It holds some extra information,

configure

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8088,6 +8088,24 @@ fi
80888088
done
80898089

80908090

8091+
for ac_header in linux/vm_sockets.h
8092+
do :
8093+
ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "
8094+
#ifdef HAVE_SYS_SOCKET_H
8095+
#include <sys/socket.h>
8096+
#endif
8097+
8098+
"
8099+
if test "x$ac_cv_header_linux_vm_sockets_h" = xyes; then :
8100+
cat >>confdefs.h <<_ACEOF
8101+
#define HAVE_LINUX_VM_SOCKETS_H 1
8102+
_ACEOF
8103+
8104+
fi
8105+
8106+
done
8107+
8108+
80918109
# On Linux, can.h and can/raw.h require sys/socket.h
80928110
for ac_header in linux/can.h linux/can/raw.h linux/can/bcm.h
80938111
do :

0 commit comments

Comments
 (0)