.. versionadded:: 3.6
+- :const:`AF_VSOCK` allows communication between virtual machines and
+ their hosts. The sockets are represented as a ``(CID, port)`` tuple
+ where the context ID or CID and port are integers.
+
+ Availability: Linux >= 4.8 QEMU >= 2.8 ESX >= 4.0 ESX Workstation >= 6.5
+
+ .. versionadded:: 3.7
+
- Certain other address families (:const:`AF_PACKET`, :const:`AF_CAN`)
support specific representations.
.. versionadded:: 3.6
+
+.. data:: AF_VSOCK
+ IOCTL_VM_SOCKETS_GET_LOCAL_CID
+ VMADDR*
+ SO_VM*
+
+ Constants for Linux host/guest communication.
+
+ Availability: Linux >= 4.8.
+
+ .. versionadded:: 3.7
+
.. data:: AF_LINK
Availability: BSD, OSX.
HOST = support.HOST
MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return
+VSOCKPORT = 1234
+
try:
import _thread as thread
import threading
except ImportError:
_socket = None
+def get_cid():
+ if fcntl is None:
+ return None
+ try:
+ with open("/dev/vsock", "rb") as f:
+ r = fcntl.ioctl(f, socket.IOCTL_VM_SOCKETS_GET_LOCAL_CID, " ")
+ except OSError:
+ return None
+ else:
+ return struct.unpack("I", r)[0]
def _have_socket_can():
"""Check whether CAN sockets are supported on this host."""
s.close()
return True
+def _have_socket_vsock():
+ """Check whether AF_VSOCK sockets are supported on this host."""
+ ret = get_cid() is not None
+ return ret
+
HAVE_SOCKET_CAN = _have_socket_can()
HAVE_SOCKET_CAN_ISOTP = _have_socket_can_isotp()
HAVE_SOCKET_ALG = _have_socket_alg()
+HAVE_SOCKET_VSOCK = _have_socket_vsock()
+
# Size in bytes of the int type
SIZEOF_INT = array.array("i").itemsize
self.cli = None
ThreadableTest.clientTearDown(self)
+@unittest.skipIf(fcntl is None, "need fcntl")
+@unittest.skipUnless(thread, 'Threading required for this test.')
+@unittest.skipUnless(HAVE_SOCKET_VSOCK,
+ 'VSOCK sockets required for this test.')
+@unittest.skipUnless(get_cid() != 2,
+ "This test can only be run on a virtual guest.")
+class ThreadedVSOCKSocketStreamTest(unittest.TestCase, ThreadableTest):
+
+ def __init__(self, methodName='runTest'):
+ unittest.TestCase.__init__(self, methodName=methodName)
+ ThreadableTest.__init__(self)
+
+ def setUp(self):
+ self.serv = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
+ self.addCleanup(self.serv.close)
+ self.serv.bind((socket.VMADDR_CID_ANY, VSOCKPORT))
+ self.serv.listen()
+ self.serverExplicitReady()
+ self.conn, self.connaddr = self.serv.accept()
+ self.addCleanup(self.conn.close)
+
+ def clientSetUp(self):
+ time.sleep(0.1)
+ self.cli = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
+ self.addCleanup(self.cli.close)
+ cid = get_cid()
+ self.cli.connect((cid, VSOCKPORT))
+
+ def testStream(self):
+ msg = self.conn.recv(1024)
+ self.assertEqual(msg, MSG)
+
+ def _testStream(self):
+ self.cli.send(MSG)
+ self.cli.close()
+
class SocketConnectedTest(ThreadedTCPSocketTest):
"""Socket tests for client-server connection.
self.assertIn(self.serv, r)
+@unittest.skipIf(fcntl is None, "need fcntl")
+@unittest.skipUnless(HAVE_SOCKET_VSOCK,
+ 'VSOCK sockets required for this test.')
+class BasicVSOCKTest(unittest.TestCase):
+
+ def testCrucialConstants(self):
+ socket.AF_VSOCK
+
+ def testVSOCKConstants(self):
+ socket.SO_VM_SOCKETS_BUFFER_SIZE
+ socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE
+ socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE
+ socket.VMADDR_CID_ANY
+ socket.VMADDR_PORT_ANY
+ socket.VMADDR_CID_HOST
+ socket.VM_SOCKETS_INVALID_VERSION
+ socket.IOCTL_VM_SOCKETS_GET_LOCAL_CID
+
+ def testCreateSocket(self):
+ with socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) as s:
+ pass
+
+ def testSocketBufferSize(self):
+ with socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) as s:
+ orig_max = s.getsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE)
+ orig = s.getsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_SIZE)
+ orig_min = s.getsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE)
+
+ s.setsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE, orig_max * 2)
+ s.setsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_SIZE, orig * 2)
+ s.setsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE, orig_min * 2)
+
+ self.assertEqual(orig_max * 2,
+ s.getsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_MAX_SIZE))
+ self.assertEqual(orig * 2,
+ s.getsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_SIZE))
+ self.assertEqual(orig_min * 2,
+ s.getsockopt(socket.AF_VSOCK,
+ socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE))
+
@unittest.skipUnless(thread, 'Threading required for this test.')
class BasicTCPTest(SocketConnectedTest):
tests.extend([BasicCANTest, CANTest])
tests.extend([BasicRDSTest, RDSTest])
tests.append(LinuxKernelCryptoAPI)
+ tests.extend([
+ BasicVSOCKTest,
+ ThreadedVSOCKSocketStreamTest,
+ ])
tests.extend([
CmsgMacroTests,
SendmsgUDPTest,
Ammar Askar
Chris AtLee
Aymeric Augustin
+Cathy Avery
John Aycock
Donovan Baarda
Arne Babenhauserheide
--- /dev/null
+``AF_VSOCK`` has been added to the socket interface which allows
+communication between virtual machines and their host.
}
#endif /* AF_NETLINK */
+#if defined(AF_VSOCK)
+ case AF_VSOCK:
+ {
+ struct sockaddr_vm *a = (struct sockaddr_vm *) addr;
+ return Py_BuildValue("II", a->svm_cid, a->svm_port);
+ }
+#endif /* AF_VSOCK */
+
#ifdef ENABLE_IPV6
case AF_INET6:
{
}
#endif
+#if defined(AF_VSOCK)
+ case AF_VSOCK:
+ {
+ struct sockaddr_vm* addr;
+ int port, cid;
+ addr = (struct sockaddr_vm *)addr_ret;
+ memset(addr, 0, sizeof(struct sockaddr_vm));
+ if (!PyTuple_Check(args)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "getsockaddrarg: "
+ "AF_VSOCK address must be tuple, not %.500s",
+ Py_TYPE(args)->tp_name);
+ return 0;
+ }
+ if (!PyArg_ParseTuple(args, "II:getsockaddrarg", &cid, &port))
+ return 0;
+ addr->svm_family = s->sock_family;
+ addr->svm_port = port;
+ addr->svm_cid = cid;
+ *len_ret = sizeof(*addr);
+ return 1;
+ }
+#endif
+
+
#ifdef AF_RDS
case AF_RDS:
/* RDS sockets use sockaddr_in: fall-through */
}
#endif
+#if defined(AF_VSOCK)
+ case AF_VSOCK:
+ {
+ *len_ret = sizeof (struct sockaddr_vm);
+ return 1;
+ }
+#endif
+
#ifdef AF_RDS
case AF_RDS:
/* RDS sockets use sockaddr_in: fall-through */
unsigned int optlen;
PyObject *none;
+#ifdef AF_VSOCK
+ if (s->sock_family == AF_VSOCK) {
+ uint64_t vflag; // Must be set width of 64 bits
+ /* setsockopt(level, opt, flag) */
+ if (PyArg_ParseTuple(args, "iiK:setsockopt",
+ &level, &optname, &vflag)) {
+ // level should always be set to AF_VSOCK
+ res = setsockopt(s->sock_fd, level, optname,
+ (void*)&vflag, sizeof vflag);
+ goto done;
+ }
+ return NULL;
+ }
+#endif
+
/* setsockopt(level, opt, flag) */
if (PyArg_ParseTuple(args, "iii:setsockopt",
&level, &optname, &flag)) {
int res;
PyObject *buf;
socklen_t buflen = 0;
+ int flag = 0;
+ socklen_t flagsize;
if (!PyArg_ParseTuple(args, "ii|i:getsockopt",
&level, &optname, &buflen))
return NULL;
if (buflen == 0) {
- int flag = 0;
- socklen_t flagsize = sizeof flag;
+#ifdef AF_VSOCK
+ if (s->sock_family == AF_VSOCK) {
+ uint64_t vflag = 0; // Must be set width of 64 bits
+ flagsize = sizeof vflag;
+ res = getsockopt(s->sock_fd, level, optname,
+ (void *)&vflag, &flagsize);
+ if (res < 0)
+ return s->errorhandler();
+ return PyLong_FromUnsignedLong(vflag);
+ }
+#endif
+ flagsize = sizeof flag;
res = getsockopt(s->sock_fd, level, optname,
(void *)&flag, &flagsize);
if (res < 0)
return s->errorhandler();
return PyLong_FromLong(flag);
}
+#ifdef AF_VSOCK
+ if (s->sock_family == AF_VSOCK) {
+ PyErr_SetString(PyExc_OSError,
+ "getsockopt string buffer not allowed");
+ return NULL;
+ }
+#endif
if (buflen <= 0 || buflen > 1024) {
PyErr_SetString(PyExc_OSError,
"getsockopt buflen out of range");
PyModule_AddIntMacro(m, NETLINK_CRYPTO);
#endif
#endif /* AF_NETLINK */
+
+#ifdef AF_VSOCK
+ PyModule_AddIntConstant(m, "AF_VSOCK", AF_VSOCK);
+ PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_SIZE", 0);
+ PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_MIN_SIZE", 1);
+ PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_MAX_SIZE", 2);
+ PyModule_AddIntConstant(m, "VMADDR_CID_ANY", 0xffffffff);
+ PyModule_AddIntConstant(m, "VMADDR_PORT_ANY", 0xffffffff);
+ PyModule_AddIntConstant(m, "VMADDR_CID_HOST", 2);
+ PyModule_AddIntConstant(m, "VM_SOCKETS_INVALID_VERSION", 0xffffffff);
+ PyModule_AddIntConstant(m, "IOCTL_VM_SOCKETS_GET_LOCAL_CID", _IO(7, 0xb9));
+#endif
+
#ifdef AF_ROUTE
/* Alias to emulate 4.4BSD */
PyModule_AddIntMacro(m, AF_ROUTE);
#define SOL_ALG 279
#endif
+#ifdef HAVE_LINUX_VM_SOCKETS_H
+# include <linux/vm_sockets.h>
+#else
+# undef AF_VSOCK
+#endif
+
/* Linux 3.19 */
#ifndef ALG_SET_AEAD_ASSOCLEN
#define ALG_SET_AEAD_ASSOCLEN 4
#ifdef HAVE_SOCKADDR_ALG
struct sockaddr_alg alg;
#endif
+#ifdef AF_VSOCK
+ struct sockaddr_vm vm;
+#endif
} sock_addr_t;
/* The object holding a socket. It holds some extra information,
done
+for ac_header in linux/vm_sockets.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+"
+if test "x$ac_cv_header_linux_vm_sockets_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LINUX_VM_SOCKETS_H 1
+_ACEOF
+
+fi
+
+done
+
+
# On Linux, can.h and can/raw.h require sys/socket.h
for ac_header in linux/can.h linux/can/raw.h linux/can/bcm.h
do :
#endif
])
+AC_CHECK_HEADERS(linux/vm_sockets.h,,,[
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
# On Linux, can.h and can/raw.h require sys/socket.h
AC_CHECK_HEADERS(linux/can.h linux/can/raw.h linux/can/bcm.h,,,[
#ifdef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <linux/tipc.h> header file. */
#undef HAVE_LINUX_TIPC_H
+/* Define to 1 if you have the <linux/vm_sockets.h> header file. */
+#undef HAVE_LINUX_VM_SOCKETS_H
+
/* Define to 1 if you have the 'lockf' function and the F_LOCK macro. */
#undef HAVE_LOCKF