Hi

On Wed, May 5, 2021 at 4:38 PM Dr. David Alan Gilbert <dgilb...@redhat.com>
wrote:

> (Resend, remembering to add list)
> Hi,
>   I'm trying to understand what restrictions there are on the
> payload that's part of VhostUserMsg; and am confused by
> inconsistencies.
>
> Lets start with this version:
>
> subprojects/libvhost-user/libvhost-user.h :
> typedef struct VhostUserMsg {
>     int request;
>
> #define VHOST_USER_VERSION_MASK     (0x3)
> #define VHOST_USER_REPLY_MASK       (0x1 << 2)
> #define VHOST_USER_NEED_REPLY_MASK  (0x1 << 3)
>     uint32_t flags;
>     uint32_t size; /* the following payload size */
>
>     union {
> #define VHOST_USER_VRING_IDX_MASK   (0xff)
> #define VHOST_USER_VRING_NOFD_MASK  (0x1 << 8)
>         uint64_t u64;
>         struct vhost_vring_state state;
>         struct vhost_vring_addr addr;
>         VhostUserMemory memory;
>         VhostUserMemRegMsg memreg;
>         VhostUserLog log;
>         VhostUserConfig config;
>         VhostUserVringArea area;
>         VhostUserInflight inflight;
>     } payload;
>
>     int fds[VHOST_MEMORY_BASELINE_NREGIONS];
>     int fd_num;
>     uint8_t *data;
> } VU_PACKED VhostUserMsg;
>
> note the 'fds' array after the payload but before
> the end of the structure.
>
> But then there's the version in:
> hw/virtio/vhost-user.c
> typedef union {
> #define VHOST_USER_VRING_IDX_MASK   (0xff)
> #define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
>         uint64_t u64;
>         struct vhost_vring_state state;
>         struct vhost_vring_addr addr;
>         VhostUserMemory memory;
>         VhostUserMemRegMsg mem_reg;
>         VhostUserLog log;
>         struct vhost_iotlb_msg iotlb;
>         VhostUserConfig config;
>         VhostUserCryptoSession session;
>         VhostUserVringArea area;
>         VhostUserInflight inflight;
> } VhostUserPayload;
>
> typedef struct VhostUserMsg {
>     VhostUserHeader hdr;
>     VhostUserPayload payload;
> } QEMU_PACKED VhostUserMsg;
>
> which hasn't got the 'fds' section.
> Yet they're both marked as 'packed'.
>

They are packed, because both are used to serialize/deserialize the stream.


> That's a bit unfortunate for two structures with the same name.
>
>
Yes, maybe it's time to have a canonical system header used by both?


> Am I right in thinking that the vhost-user.c version is sent over
> the wire, while the libvhost-user.h one is really just an interface?
>
>
I believe the extra fields are not used for serializing the message, but
just a convenient way to group related data.


> Is it safe for me to add a new, larger entry in the payload union
> without breaking existing clients?
>

It should be.


> I ended up at this question after trying to add a variable length
> entry to the union:
>
> typedef struct {
>     VhostUserFSSlaveMsg fs;
>     VhostUserFSSlaveMsgEntry entries[VHOST_USER_FS_SLAVE_MAX_ENTRIES];
> } QEMU_PACKED VhostUserFSSlaveMsgMax;
>
> ...
> union ....
>         VhostUserFSSlaveMsg fs;
>         VhostUserFSSlaveMsgMax fs_max; /* Never actually used */
> } VhostUserPayload;
>
> and in the .h I had:
> typedef struct {
>     /* Generic flags for the overall message */
>     uint32_t flags;
>     /* Number of entries */
>     uint16_t count;
>     /* Spare */
>     uint16_t align;
>
>     VhostUserFSSlaveMsgEntry entries[];
> } VhostUserFSSlaveMsg;
>
>     union {
> ...
>         VhostUserInflight inflight;
>         VhostUserFSSlaveMsg fs;
>     } payload;
>
> which is apparently OK in the .c version, and gcc is happy with the same
> in the libvhost-user.h version; but clang gets upset by the .h
> version because it doesn't like the variable length structure
> before the end of the struct - which I have sympathy for.
>
>
Indeed, we probably want to allocate the message separately then.

thanks

-- 
Marc-André Lureau

Reply via email to