1 /*
2  * Copyright 6WIND S.A., 2014
3  *
4  * This work is licensed under the terms of the GNU GPL, version 2 or
5  * (at your option) any later version.  See the COPYING file in the
6  * top-level directory.
7  */
8 
9 #ifndef _IVSHMEM_SERVER_H_
10 #define _IVSHMEM_SERVER_H_
11 
12 /**
13  * The ivshmem server is a daemon that creates a unix socket in listen
14  * mode. The ivshmem clients (qemu or ivshmem-client) connect to this
15  * unix socket. For each client, the server will create some eventfd
16  * (see EVENTFD(2)), one per vector. These fd are transmitted to all
17  * clients using the SCM_RIGHTS cmsg message. Therefore, each client is
18  * able to send a notification to another client without beeing
19  * "profixied" by the server.
20  *
21  * We use this mechanism to send interruptions between guests.
22  * qemu is able to transform an event on a eventfd into a PCI MSI-x
23  * interruption in the guest.
24  *
25  * The ivshmem server is also able to share the file descriptor
26  * associated to the ivshmem shared memory.
27  */
28 
29 #include <sys/select.h>
30 
31 #include "qemu/event_notifier.h"
32 #include "qemu/queue.h"
33 #include "hw/misc/ivshmem.h"
34 
35 /**
36  * Maximum number of notification vectors supported by the server
37  */
38 #define IVSHMEM_SERVER_MAX_VECTORS 64
39 
40 /**
41  * Structure storing a peer
42  *
43  * Each time a client connects to an ivshmem server, a new
44  * IvshmemServerPeer structure is created. This peer and all its
45  * vectors are advertised to all connected clients through the connected
46  * unix sockets.
47  */
48 typedef struct IvshmemServerPeer {
49     QTAILQ_ENTRY(IvshmemServerPeer) next;    /**< next in list*/
50     int sock_fd;                             /**< connected unix sock */
51     int64_t id;                              /**< the id of the peer */
52     EventNotifier vectors[IVSHMEM_SERVER_MAX_VECTORS]; /**< one per vector */
53     unsigned vectors_count;                  /**< number of vectors */
54 } IvshmemServerPeer;
55 QTAILQ_HEAD(IvshmemServerPeerList, IvshmemServerPeer);
56 
57 typedef struct IvshmemServerPeerList IvshmemServerPeerList;
58 
59 /**
60  * Structure describing an ivshmem server
61  *
62  * This structure stores all information related to our server: the name
63  * of the server unix socket and the list of connected peers.
64  */
65 typedef struct IvshmemServer {
66     char unix_sock_path[PATH_MAX];   /**< path to unix socket */
67     int sock_fd;                     /**< unix sock file descriptor */
68     char shm_path[PATH_MAX];         /**< path to shm */
69     size_t shm_size;                 /**< size of shm */
70     int shm_fd;                      /**< shm file descriptor */
71     unsigned n_vectors;              /**< number of vectors */
72     uint16_t cur_id;                 /**< id to be given to next client */
73     bool verbose;                    /**< true in verbose mode */
74     IvshmemServerPeerList peer_list; /**< list of peers */
75 } IvshmemServer;
76 
77 /**
78  * Initialize an ivshmem server
79  *
80  * @server:         A pointer to an uninitialized IvshmemServer structure
81  * @unix_sock_path: The pointer to the unix socket file name
82  * @shm_path:       Path to the shared memory. The path corresponds to a POSIX
83  *                  shm name or a hugetlbfs mount point.
84  * @shm_size:       Size of shared memory
85  * @n_vectors:      Number of interrupt vectors per client
86  * @verbose:        True to enable verbose mode
87  *
88  * Returns:         0 on success, or a negative value on error
89  */
90 int
91 ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
92                     const char *shm_path, size_t shm_size, unsigned n_vectors,
93                     bool verbose);
94 
95 /**
96  * Open the shm, then create and bind to the unix socket
97  *
98  * @server: The pointer to the initialized IvshmemServer structure
99  *
100  * Returns: 0 on success, or a negative value on error
101  */
102 int ivshmem_server_start(IvshmemServer *server);
103 
104 /**
105  * Close the server
106  *
107  * Close connections to all clients, close the unix socket and the
108  * shared memory file descriptor. The structure remains initialized, so
109  * it is possible to call ivshmem_server_start() again after a call to
110  * ivshmem_server_close().
111  *
112  * @server: The ivshmem server
113  */
114 void ivshmem_server_close(IvshmemServer *server);
115 
116 /**
117  * Fill a fd_set with file descriptors to be monitored
118  *
119  * This function will fill a fd_set with all file descriptors that must
120  * be polled (unix server socket and peers unix socket). The function
121  * will not initialize the fd_set, it is up to the caller to do it.
122  *
123  * @server: The ivshmem server
124  * @fds:    The fd_set to be updated
125  * @maxfd:  Must be set to the max file descriptor + 1 in fd_set. This value is
126  *          updated if this function adds a greater fd in fd_set.
127  */
128 void
129 ivshmem_server_get_fds(const IvshmemServer *server, fd_set *fds, int *maxfd);
130 
131 /**
132  * Read and handle new messages
133  *
134  * Given a fd_set (for instance filled by a call to select()), handle
135  * incoming messages from peers.
136  *
137  * @server: The ivshmem server
138  * @fds:    The fd_set containing the file descriptors to be checked. Note that
139  *          file descriptors that are not related to our server are ignored.
140  * @maxfd:  The maximum fd in fd_set, plus one.
141  *
142  * Returns: 0 on success, or a negative value on error
143  */
144 int ivshmem_server_handle_fds(IvshmemServer *server, fd_set *fds, int maxfd);
145 
146 /**
147  * Search a peer from its identifier
148  *
149  * @server:  The ivshmem server
150  * @peer_id: The identifier of the peer structure
151  *
152  * Returns:  The peer structure, or NULL if not found
153  */
154 IvshmemServerPeer *
155 ivshmem_server_search_peer(IvshmemServer *server, int64_t peer_id);
156 
157 /**
158  * Dump information of this ivshmem server and its peers on stdout
159  *
160  * @server: The ivshmem server
161  */
162 void ivshmem_server_dump(const IvshmemServer *server);
163 
164 #endif /* _IVSHMEM_SERVER_H_ */
165