From b5b0430c399e443ffd588ddefbcd67e6f49f8c27 Mon Sep 17 00:00:00 2001 From: Bowen Wang Date: Tue, 19 Mar 2024 15:17:08 +0800 Subject: [PATCH] net/vsock: add AF_VSOCK address family Add AF_VSOCK address family support, This is the vsock framework preparation patch. Signed-off-by: Bowen Wang --- include/netpacket/vm_sockets.h | 206 ++++++++++++++++++++++++++++++ include/sys/socket.h | 2 + libs/libc/netdb/lib_getaddrinfo.c | 86 ++++++++++++- 3 files changed, 287 insertions(+), 7 deletions(-) create mode 100644 include/netpacket/vm_sockets.h diff --git a/include/netpacket/vm_sockets.h b/include/netpacket/vm_sockets.h new file mode 100644 index 00000000000..14f7c76878c --- /dev/null +++ b/include/netpacket/vm_sockets.h @@ -0,0 +1,206 @@ +/**************************************************************************** + * include/netpacket/vm_sockets.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NETPACKET_VM_SOCKETS_H +#define __INCLUDE_NETPACKET_VM_SOCKETS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Option name for STREAM socket buffer size. Use as the option name in + * setsockopt(3) or getsockopt(3) to set or get an unsigned long long that + * specifies the size of the buffer underlying a vSockets STREAM socket. + * Value is clamped to the MIN and MAX. + */ + +#define SO_VM_SOCKETS_BUFFER_SIZE 0 + +/* Option name for STREAM socket minimum buffer size. Use as the option name + * in setsockopt(3) or getsockopt(3) to set or get an unsigned long long that + * specifies the minimum size allowed for the buffer underlying a vSockets + * STREAM socket. + */ + +#define SO_VM_SOCKETS_BUFFER_MIN_SIZE 1 + +/* Option name for STREAM socket maximum buffer size. Use as the option name + * in setsockopt(3) or getsockopt(3) to set or get an unsigned long long + * that specifies the maximum size allowed for the buffer underlying a + * vSockets STREAM socket. + */ + +#define SO_VM_SOCKETS_BUFFER_MAX_SIZE 2 + +/* Option name for socket peer's host-specific VM ID. Use as the option name + * in getsockopt(3) to get a host-specific identifier for the peer endpoint's + * VM. The identifier is a signed integer. + * Only available for hypervisor endpoints. + */ + +#define SO_VM_SOCKETS_PEER_HOST_VM_ID 3 + +/* Option name for determining if a socket is trusted. Use as the option + * name in getsockopt(3) to determine if a socket is trusted. The value is a + * signed integer. + */ + +#define SO_VM_SOCKETS_TRUSTED 5 + +/* Option name for using non-blocking send/receive. Use as the option name + * for setsockopt(3) or getsockopt(3) to set or get the non-blocking + * transmit/receive flag for a STREAM socket. This flag determines whether + * send() and recv() can be called in non-blocking contexts for the given + * socket. The value is a signed integer. + * + * This option is only relevant to kernel endpoints, where descheduling the + * thread of execution is not allowed, for example, while holding a spinlock. + * It is not to be confused with conventional non-blocking socket operations. + * + * Only available for hypervisor endpoints. + */ + +#define SO_VM_SOCKETS_NONBLOCK_TXRX 7 + +/* Option name for STREAM socket connection timeout. Use as the option name + * in setsockopt(3) or getsockopt(3) to set or get the connection + * timeout for a STREAM socket. + */ + +#define SO_VM_SOCKETS_CONNECT_TIMEOUT 8 + +/* The vSocket equivalent of INADDR_ANY. This works for the svm_cid field of + * sockaddr_vm and indicates the context ID of the current endpoint. + */ + +#define VMADDR_CID_ANY -1u + +/* Bind to any available port. Works for the svm_port field of + * sockaddr_vm. + */ + +#define VMADDR_PORT_ANY -1u + +/* Use this as the destination CID in an address when referring to the + * hypervisor. VMCI relies on it being 0, but this would be useful for other + * transports too. + */ + +#define VMADDR_CID_HYPERVISOR 0 + +/* Use this as the destination CID in an address when referring to the + * local communication (loopback). + * (This was VMADDR_CID_RESERVED, but even VMCI doesn't use it anymore, + * it was a legacy value from an older release). + */ + +#define VMADDR_CID_LOCAL 1 + +/* Use this as the destination CID in an address when referring to the host + * (any process other than the hypervisor). VMCI relies on it being 2, but + * this would be useful for other transports too. + */ + +#define VMADDR_CID_HOST 2 + +/* The current default use case for the vsock channel is the following: + * local vsock communication between guest and host and nested VMs setup. + * In addition to this, implicitly, the vsock packets are forwarded to the + * host if no host->guest vsock transport is set. + * + * Set this flag value in the sockaddr_vm corresponding field if the vsock + * packets need to be always forwarded to the host. Using this behavior, + * vsock communication between sibling VMs can be setup. + * + * This way can explicitly distinguish between vsock channels created for + * different use cases, such as nested VMs (or local communication between + * guest and host) and sibling VMs. + * + * The flag can be set in the connect logic in the user space application + * flow. In the listen logic (from kernel space) the flag is set on the + * remote peer address. This happens for an incoming connection when it is + * routed from the host and comes from the guest (local CID and + * remote CID > VMADDR_CID_HOST). + */ + +#define VMADDR_FLAG_TO_HOST 0x01 + +/* Invalid vSockets version. */ + +#define VM_SOCKETS_INVALID_VERSION -1u + +/* The epoch (first) component of the vSockets version. A single byte + * representing the epoch component of the vSockets version. + */ + +#define VM_SOCKETS_VERSION_EPOCH(v) (((v) & 0xFF000000) >> 24) + +/* The major (second) component of the vSockets version. A single byte + * representing the major component of the vSockets version. Typically + * changes for every major release of a product. + */ + +#define VM_SOCKETS_VERSION_MAJOR(v) (((v) & 0x00FF0000) >> 16) + +/* The minor (third) component of the vSockets version. Two bytes + * representing the minor component of the vSockets version. + */ + +#define VM_SOCKETS_VERSION_MINOR(v) (((v) & 0x0000FFFF)) + +/* vSocket get local cid ioctl command */ + +#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _SIOC(0x0040) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Address structure for vSockets. The address family should be set to + * AF_VSOCK. The structure members should all align on their natural + * boundaries without resorting to compiler packing directives. The total + * size of this structure should be exactly the same as that of + * struct sockaddr. + */ + +struct sockaddr_vm +{ + sa_family_t svm_family; + unsigned short svm_reserved1; + unsigned int svm_port; + unsigned int svm_cid; + uint8_t svm_flags; + unsigned char svm_zero[sizeof(struct sockaddr) - + sizeof(sa_family_t) - + sizeof(unsigned short) - + sizeof(unsigned int) - + sizeof(unsigned int) - + sizeof(uint8_t)]; +}; + +#endif /* __INCLUDE_NETPACKET_VM_SOCKETS_H */ diff --git a/include/sys/socket.h b/include/sys/socket.h index 28ee1861711..fc604bde209 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -52,6 +52,7 @@ #define PF_CAN 29 /* Controller Area Network (SocketCAN) */ #define PF_BLUETOOTH 31 /* Bluetooth sockets */ #define PF_IEEE802154 36 /* Low level IEEE 802.15.4 radio frame interface */ +#define PF_VSOCK 40 /* vSockets */ #define PF_PKTRADIO 64 /* Low level packet radio interface */ #define PF_RPMSG 65 /* Remote core communication */ @@ -70,6 +71,7 @@ #define AF_CAN PF_CAN #define AF_BLUETOOTH PF_BLUETOOTH #define AF_IEEE802154 PF_IEEE802154 +#define AF_VSOCK PF_VSOCK #define AF_PKTRADIO PF_PKTRADIO #define AF_RPMSG PF_RPMSG diff --git a/libs/libc/netdb/lib_getaddrinfo.c b/libs/libc/netdb/lib_getaddrinfo.c index 380cf700694..fe1b333d819 100644 --- a/libs/libc/netdb/lib_getaddrinfo.c +++ b/libs/libc/netdb/lib_getaddrinfo.c @@ -26,11 +26,13 @@ #include +#include #include #include #include #include +#include #include #include @@ -50,6 +52,7 @@ struct ai_s struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr_rpmsg srp; + struct sockaddr_vm svm; } sa; }; @@ -105,6 +108,14 @@ FAR static struct ai_s *alloc_ai(int family, int socktype, int protocol, strlcpy(ai->sa.srp.rp_cpu, addr, sizeof(ai->sa.srp.rp_cpu)); snprintf(ai->sa.srp.rp_name, sizeof(ai->sa.srp.rp_name), "%d", port); break; +#endif +#ifdef CONFIG_NET_VSOCK + case AF_VSOCK: + ai->ai.ai_addrlen = sizeof(struct sockaddr_vm); + ai->sa.svm.svm_family = AF_VSOCK; + ai->sa.svm.svm_cid = strtoul(addr, NULL, 0); + ai->sa.svm.svm_port = ntohl(port); + break; #endif } @@ -158,6 +169,7 @@ int getaddrinfo(FAR const char *hostname, FAR const char *servname, family != AF_INET6 && family != AF_LOCAL && family != AF_RPMSG && + family != AF_VSOCK && family != AF_UNSPEC) { return EAI_FAMILY; @@ -201,13 +213,11 @@ int getaddrinfo(FAR const char *hostname, FAR const char *servname, if ((flags & AI_PASSIVE) != 0 && hostname == NULL) { - struct in6_addr addr; - - memset(&addr, 0, sizeof(struct in6_addr)); - #ifdef CONFIG_NET_IPv4 if (family == AF_INET || family == AF_UNSPEC) { + struct in_addr addr; + memset(&addr, 0, sizeof(struct in_addr)); ai = alloc_ai(AF_INET, socktype, proto, port, &addr); if (ai != NULL) { @@ -219,6 +229,8 @@ int getaddrinfo(FAR const char *hostname, FAR const char *servname, #ifdef CONFIG_NET_IPv6 if (family == AF_INET6 || family == AF_UNSPEC) { + struct in6_addr addr; + memset(&addr, 0, sizeof(struct in6_addr)); ai = alloc_ai(AF_INET6, socktype, proto, port, &addr); if (ai != NULL) { @@ -236,6 +248,44 @@ int getaddrinfo(FAR const char *hostname, FAR const char *servname, } #endif +#if defined(CONFIG_NET_RPMSG) + if (family == AF_RPMSG || family == AF_UNSPEC) + { + ai = alloc_ai(AF_RPMSG, socktype, proto, port, ""); + if (ai != NULL) + { + if (*res != NULL) + { + (*res)->ai_next = (FAR struct addrinfo *)ai; + } + else + { + *res = (FAR struct addrinfo *)ai; + } + } + } +#endif + +#if defined(CONFIG_NET_VSOCK) + if (family == AF_VSOCK || family == AF_UNSPEC) + { + /* "-1" <--> VMADDR_CID_ANY */ + + ai = alloc_ai(AF_VSOCK, socktype, proto, port, "-1"); + if (ai != NULL) + { + if (*res != NULL) + { + (*res)->ai_next = (FAR struct addrinfo *)ai; + } + else + { + *res = (FAR struct addrinfo *)ai; + } + } + } +#endif + return (*res != NULL) ? OK : EAI_MEMORY; } @@ -276,17 +326,39 @@ int getaddrinfo(FAR const char *hostname, FAR const char *servname, } } #endif +#endif +#if defined(CONFIG_NET_VSOCK) + if (family == AF_VSOCK || family == AF_UNSPEC) + { + /* "1" <--> VMADDR_CID_LOCAL */ + + ai = alloc_ai(AF_VSOCK, socktype, proto, port, "1"); + if (ai != NULL) + { + if (*res != NULL) + { + (*res)->ai_next = (FAR struct addrinfo *)ai; + } + else + { + *res = (FAR struct addrinfo *)ai; + } + } + } +#endif + +#if defined(CONFIG_NET_LOOPBACK) || defined(CONFIG_NET_VSOCK) return (*res != NULL) ? OK : EAI_MEMORY; #else /* Local service, but no loopback so cannot succeed. */ return EAI_FAIL; -#endif /* CONFIG_NET_LOOPBACK */ +#endif } -#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_RPMSG) - if (family == AF_LOCAL || family == AF_RPMSG) +#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_RPMSG) || defined(CONFIG_NET_VSOCK) + if (family == AF_LOCAL || family == AF_RPMSG || family == AF_VSOCK) { ai = alloc_ai(family, socktype, proto, port, hostname); if (ai != NULL)