"Timothy Beaver" <realbeaver9...@danwin1210.de> writes:
> Hi folks, > > Dave Voutila <d...@sisu.io> writes: >> Lucas <lu...@sexy.is> writes: >> >> >>Fix: >> > Dunno. I have the theory that this "broke" (idk if it worked >> > before or not) after "vmd(8): introduce multi-process model for >> > virtio devices." Haven't found out yet a way to notify vionet >> > process about the config: calls into vionet_main (triggered from >> > vm_main) happen before configuration parsing but after init, so >> > it gets the default value of 100.64.0.0/10. Haven't checked it >> > neither, but I also predict that "vmctl load" changes won't be >> > reflected. >> >> Thanks, I'll look to reproduce. There's definitely a message type for >> mac address setting, but I honestly don't know how we were handling this >> prior to the split out into a device process. This might need to be a >> new imsg for any runtime changes via "vmctl load". > > I've been able to reproduce this issue as well on my own server, and > was able to get things working properly with the patch inlined below. > > Some details: as alluded to above, the vm processes (and thus the > device processes they spawn, including vionet) don't have an up to > date copy of the config (including the 'local prefix[6]'). I was able > to solve this without adding a new message type - by stashing the > currently configured interface prefix into the vmop_create_params > struct when config_setvm() is called. From here, the prefix flows > down from vmm -> vm -> vionet, where tweaked address calculation > functions (vm_priv_addr and vm_priv_addr8) extract this information > rather than falling back on the (incorrect) global config. Thanks for the effort, but I have some reservations about your approach as it's more akin to a bandaid than an improvement given where vmd is going with my recent changes for multi-process emulation. In short: 1) vmop_create_params contains settings specific to a vm and the local prefix settings are currently global. I don't want to mix semantics if we don't have to. Plus, as you call out below, a configuration reload via `vmctl reload` will not be handled by your approach. 2) you're adding a new usage of the current_vm extern, which i'm trying to phase out as much as possible (there's too much implicit global state throughout vmd). Adding another extern to dhcp.c, a source of many headaches in the past, is not something I want to do. Some notes below in the diff, but in general I'd much rather prefer a message-based approach that allows us to remove even more dependence on the crufty global state (env, current_vm). I recommend looking at how the host mac is set asynchronously with all virtio network device processes. > > I briefly tested this patch and confirmed things now work as they > should - more thorough testing is forthcoming. A downside of > this approach vs. the messaging approach is that a vmctl load will > only change the prefix setting for VMs created in the future. I'm > not sure whether this is a problem / what the utility of changing > the prefix for existing VMs on the fly would be. > > I'm new to contributing to vmd and OpenBSD in general, so of course > I'm open to any critiques - thanks! > > Index: config.c > =================================================================== > RCS file: /cvs/src/usr.sbin/vmd/config.c,v > retrieving revision 1.71 > diff -u -p -u -p -r1.71 config.c > --- config.c 28 Apr 2023 19:46:42 -0000 1.71 > +++ config.c 14 May 2023 17:04:42 -0000 > @@ -210,9 +210,10 @@ config_getreset(struct vmd *env, struct > * Returns 0 on success, error code on failure. > */ > int > -config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, > uid_t uid) > +config_setvm(struct vmd *env, struct vmd_vm *vm, uint32_t peerid, uid_t uid) > { > int diskfds[VM_MAX_DISKS_PER_VM][VM_MAX_BASE_PER_DISK]; > + struct privsep *ps = &env->vmd_ps; > struct vmd_if *vif; > struct vmop_create_params *vmc = &vm->vm_params; > struct vm_create_params *vcp = &vmc->vmc_params; > @@ -279,6 +280,13 @@ config_setvm(struct privsep *ps, struct > > vm->vm_peerid = peerid; > vm->vm_uid = uid; > + > + /* > + * Plumb configured localprefix through to vmc so it > + * makes it to child processes > + */ > + vmc->vmc_localprefix = env->vmd_cfg.cfg_localprefix; > + vmc->vmc_localprefix6 = env->vmd_cfg.cfg_localprefix6; We don't tend to do implicit assignment like this for structures. > > /* > * From here onward, all failures need cleanup and use goto fail > Index: dhcp.c > =================================================================== > RCS file: /cvs/src/usr.sbin/vmd/dhcp.c,v > retrieving revision 1.12 > diff -u -p -u -p -r1.12 dhcp.c > --- dhcp.c 27 Apr 2023 22:47:27 -0000 1.12 > +++ dhcp.c 14 May 2023 17:04:42 -0000 > @@ -41,6 +41,7 @@ > > static const uint8_t broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; > extern struct vmd *env; > +extern struct vmd_vm *current_vm; > This is where I don't want to add more global state. I'd rather any runtime configuration details required for device emulation be part of the device struct, so in this case members of virtio_dev. This would also let us drop usage of the global `env` polluting dhcp.c. > ssize_t > dhcp_request(struct virtio_dev *dev, char *buf, size_t buflen, char **obuf) > @@ -147,8 +148,7 @@ dhcp_request(struct virtio_dev *dev, cha > } > > if ((client_addr.s_addr = > - vm_priv_addr(&env->vmd_cfg, > - dev->vm_vmid, vionet->idx, 1)) == 0) > + vm_priv_addr(current_vm, vionet->idx, 1)) == 0) > return (-1); > memcpy(&resp.yiaddr, &client_addr, > sizeof(client_addr)); > @@ -156,8 +156,8 @@ dhcp_request(struct virtio_dev *dev, cha > sizeof(client_addr)); > ss2sin(&pc.pc_dst)->sin_port = htons(CLIENT_PORT); > > - if ((server_addr.s_addr = vm_priv_addr(&env->vmd_cfg, dev->vm_vmid, > - vionet->idx, 0)) == 0) > + if ((server_addr.s_addr = > + vm_priv_addr(current_vm, vionet->idx, 0)) == 0) > return (-1); > memcpy(&resp.siaddr, &server_addr, sizeof(server_addr)); > memcpy(&ss2sin(&pc.pc_src)->sin_addr, &server_addr, > Index: priv.c > =================================================================== > RCS file: /cvs/src/usr.sbin/vmd/priv.c,v > retrieving revision 1.22 > diff -u -p -u -p -r1.22 priv.c > --- priv.c 28 Jan 2023 14:40:53 -0000 1.22 > +++ priv.c 14 May 2023 17:04:42 -0000 > @@ -466,8 +466,7 @@ vm_priv_ifconfig(struct privsep *ps, str > sin4->sin_family = AF_INET; > sin4->sin_len = sizeof(*sin4); > if ((sin4->sin_addr.s_addr = > - vm_priv_addr(&env->vmd_cfg, > - vm->vm_vmid, i, 0)) == 0) > + vm_priv_addr(vm, i, 0)) == 0) > return (-1); > > inet_ntop(AF_INET, &sin4->sin_addr, > @@ -493,8 +492,7 @@ vm_priv_ifconfig(struct privsep *ps, str > sin6 = ss2sin6(&vfr.vfr_addr); > sin6->sin6_family = AF_INET6; > sin6->sin6_len = sizeof(*sin6); > - if (vm_priv_addr6(&env->vmd_cfg, > - vm->vm_vmid, i, 0, &sin6->sin6_addr) == -1) > + if (vm_priv_addr6(vm, i, 0, &sin6->sin6_addr) == -1) > return (-1); > > inet_ntop(AF_INET6, &sin6->sin6_addr, > @@ -565,9 +563,9 @@ vm_priv_brconfig(struct privsep *ps, str > } > > uint32_t > -vm_priv_addr(struct vmd_config *cfg, uint32_t vmid, int idx, int isvm) > +vm_priv_addr(struct vmd_vm *vm, int idx, int isvm) To improve things here instead of just shuffling things around, I'd rather see us passing in just what this function needs to compute the address. > { > - struct address *h = &cfg->cfg_localprefix; > + struct address *h = &vm->vm_params.vmc_localprefix; > in_addr_t prefix, mask, addr; > > /* > @@ -580,7 +578,7 @@ vm_priv_addr(struct vmd_config *cfg, uin > mask = prefixlen2mask(h->prefixlen); > > /* 2. Encode the VM ID as a per-VM subnet range N, 100.64.N.0/24. */ > - addr = vmid << 8; > + addr = vm->vm_vmid << 8; > > /* > * 3. Assign a /31 subnet M per VM interface, 100.64.N.M/31. > @@ -603,7 +601,7 @@ vm_priv_addr(struct vmd_config *cfg, uin > */ > if (prefix != (addr & mask) || idx >= 0x7f) { > log_warnx("%s: dhcp address range exceeded," > - " vm id %u interface %d", __func__, vmid, idx); > + " vm id %u interface %d", __func__, vm->vm_vmid, idx); > return (0); > } > > @@ -611,10 +609,9 @@ vm_priv_addr(struct vmd_config *cfg, uin > } > > int > -vm_priv_addr6(struct vmd_config *cfg, uint32_t vmid, > - int idx, int isvm, struct in6_addr *in6_addr) > +vm_priv_addr6(struct vmd_vm *vm, int idx, int isvm, struct in6_addr > *in6_addr) > { > - struct address *h = &cfg->cfg_localprefix6; > + struct address *h = &vm->vm_params.vmc_localprefix6; > struct in6_addr addr, mask; > uint32_t addr4; > > @@ -626,7 +623,7 @@ vm_priv_addr6(struct vmd_config *cfg, ui > prefixlen2mask6(h->prefixlen, &mask); > > /* 2. Encode the VM IPv4 address as subnet, fd00::NN:NN:0:0/96. */ > - if ((addr4 = vm_priv_addr(cfg, vmid, idx, 1)) == 0) > + if ((addr4 = vm_priv_addr(vm, idx, 1)) == 0) > return (0); > memcpy(&addr.s6_addr[8], &addr4, sizeof(addr4)); > > Index: vmd.c > =================================================================== > RCS file: /cvs/src/usr.sbin/vmd/vmd.c,v > retrieving revision 1.149 > diff -u -p -u -p -r1.149 vmd.c > --- vmd.c 13 May 2023 23:15:28 -0000 1.149 > +++ vmd.c 14 May 2023 17:04:42 -0000 > @@ -142,7 +142,7 @@ vmd_dispatch_control(int fd, struct priv > } > > /* Try to start the launch of the VM. */ > - res = config_setvm(ps, vm, imsg->hdr.peerid, > + res = config_setvm(env, vm, imsg->hdr.peerid, > vm->vm_params.vmc_owner.uid); > if (res) > cmd = IMSG_VMDOP_START_VM_RESPONSE; > @@ -318,7 +318,7 @@ vmd_dispatch_control(int fd, struct priv > close(imsg->fd); > } else { > vm->vm_state |= VM_STATE_RECEIVED; > - config_setvm(ps, vm, imsg->hdr.peerid, > + config_setvm(env, vm, imsg->hdr.peerid, > vmc.vmc_owner.uid); > log_debug("%s: sending fd to vmm", __func__); > proc_compose_imsg(ps, PROC_VMM, -1, > @@ -494,7 +494,7 @@ vmd_dispatch_vmm(int fd, struct privsep_ > } else { > /* Stop VM instance but keep the tty open */ > vm_stop(vm, 1, __func__); > - config_setvm(ps, vm, (uint32_t)-1, vm->vm_uid); > + config_setvm(env, vm, (uint32_t)-1, vm->vm_uid); > } > > /* The error is meaningless for deferred responses */ > @@ -995,7 +995,7 @@ start_vm_batch(int fd, short type, void > break; > } > vm->vm_state &= ~VM_STATE_WAITING; > - config_setvm(&env->vmd_ps, vm, -1, vm->vm_params.vmc_owner.uid); > + config_setvm(env, vm, -1, vm->vm_params.vmc_owner.uid); > } > log_debug("%s: done starting vms", __func__); > } > Index: vmd.h > =================================================================== > RCS file: /cvs/src/usr.sbin/vmd/vmd.h,v > retrieving revision 1.122 > diff -u -p -u -p -r1.122 vmd.h > --- vmd.h 13 May 2023 23:15:28 -0000 1.122 > +++ vmd.h 14 May 2023 17:04:42 -0000 > @@ -195,6 +195,13 @@ struct vmop_owner { > int64_t gid; > }; > > +struct address { > + struct sockaddr_storage ss; > + int prefixlen; > + TAILQ_ENTRY(address) entry; > +}; > +TAILQ_HEAD(addresslist, address); > + > struct vmop_create_params { > struct vm_create_params vmc_params; > unsigned int vmc_flags; > @@ -238,6 +245,8 @@ struct vmop_create_params { > char vmc_ifgroup[VM_MAX_NICS_PER_VM][IF_NAMESIZE]; > unsigned int vmc_ifrdomain[VM_MAX_NICS_PER_VM]; > uint8_t vmc_macs[VM_MAX_NICS_PER_VM][6]; > + struct address vmc_localprefix; > + struct address vmc_localprefix6; > > struct vmop_owner vmc_owner; > > @@ -341,13 +350,6 @@ struct name2id { > }; > TAILQ_HEAD(name2idlist, name2id); > > -struct address { > - struct sockaddr_storage ss; > - int prefixlen; > - TAILQ_ENTRY(address) entry; > -}; > -TAILQ_HEAD(addresslist, address); > - > #define SUN_PATH_LEN (sizeof(((struct sockaddr_un *)NULL)->sun_path)) > struct vmd_agentx { > int ax_enabled; > @@ -473,9 +475,8 @@ int priv_findname(const char *, const c > int priv_validgroup(const char *); > int vm_priv_ifconfig(struct privsep *, struct vmd_vm *); > int vm_priv_brconfig(struct privsep *, struct vmd_switch *); > -uint32_t vm_priv_addr(struct vmd_config *, uint32_t, int, int); > -int vm_priv_addr6(struct vmd_config *, uint32_t, int, int, > - struct in6_addr *); > +uint32_t vm_priv_addr(struct vmd_vm *, int, int); > +int vm_priv_addr6(struct vmd_vm *, int, int, struct in6_addr *); > > /* vmm.c */ > void vmm(struct privsep *, struct privsep_proc *); > @@ -505,7 +506,7 @@ int config_setconfig(struct vmd *); > int config_getconfig(struct vmd *, struct imsg *); > int config_setreset(struct vmd *, unsigned int); > int config_getreset(struct vmd *, struct imsg *); > -int config_setvm(struct privsep *, struct vmd_vm *, uint32_t, uid_t); > +int config_setvm(struct vmd *, struct vmd_vm *, uint32_t, uid_t); > int config_getvm(struct privsep *, struct imsg *); > int config_getdisk(struct privsep *, struct imsg *); > int config_getif(struct privsep *, struct imsg *);