From: dv Date: Mon, 29 Mar 2021 23:37:01 +0000 (+0000) Subject: Propagate host-side tap(4) lladdr to guest vm process to allow unicast dhcp X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=97f33f1d96ff4ad5235952e1d2fee5ab905682f6;p=openbsd Propagate host-side tap(4) lladdr to guest vm process to allow unicast dhcp and bootp renewals with vmd(8)'s built-in dhcp server. Previous behavior ignored did not intercept these packets and instead transmitted them. This should make vmd(8)'s dhcp behave more as a true dhcp server should and allows it to work properly with the new dhcpleased(8) attempting a renewal. OK mlarkin@ --- diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c index 9bcf49b5304..46acf78ce8a 100644 --- a/usr.sbin/vmd/config.c +++ b/usr.sbin/vmd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.60 2021/03/19 09:29:33 kn Exp $ */ +/* $OpenBSD: config.c,v 1.61 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -227,6 +227,7 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid) char base[PATH_MAX]; unsigned int unit; struct timeval tv, rate, since_last; + struct vmop_addr_req var; errno = 0; @@ -499,6 +500,12 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid) proc_compose_imsg(ps, PROC_VMM, -1, IMSG_VMDOP_START_VM_IF, vm->vm_vmid, tapfds[i], &i, sizeof(i)); + + memset(&var, 0, sizeof(var)); + var.var_vmid = vm->vm_vmid; + var.var_nic_idx = i; + proc_compose_imsg(ps, PROC_PRIV, -1, IMSG_VMDOP_PRIV_GET_ADDR, + vm->vm_vmid, dup(tapfds[i]), &var, sizeof(var)); } if (!(vm->vm_state & VM_STATE_RECEIVED)) diff --git a/usr.sbin/vmd/dhcp.c b/usr.sbin/vmd/dhcp.c index 63d17d0dcc9..987d4386f9f 100644 --- a/usr.sbin/vmd/dhcp.c +++ b/usr.sbin/vmd/dhcp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dhcp.c,v 1.8 2018/12/27 19:51:30 anton Exp $ */ +/* $OpenBSD: dhcp.c,v 1.9 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2017 Reyk Floeter @@ -57,8 +57,11 @@ dhcp_request(struct vionet_dev *dev, char *buf, size_t buflen, char **obuf) if ((offset = decode_hw_header(buf, buflen, 0, &pc, HTYPE_ETHER)) < 0) return (-1); - if (memcmp(pc.pc_smac, dev->mac, ETHER_ADDR_LEN) != 0 || - memcmp(pc.pc_dmac, broadcast, ETHER_ADDR_LEN) != 0) + if (memcmp(pc.pc_dmac, broadcast, ETHER_ADDR_LEN) != 0 && + memcmp(pc.pc_dmac, dev->hostmac, ETHER_ADDR_LEN) != 0) + return (-1); + + if (memcmp(pc.pc_smac, dev->mac, ETHER_ADDR_LEN) != 0) return (-1); if ((offset = decode_udp_ip_header(buf, buflen, offset, &pc)) < 0) diff --git a/usr.sbin/vmd/priv.c b/usr.sbin/vmd/priv.c index 7335f0c4a89..6718174765a 100644 --- a/usr.sbin/vmd/priv.c +++ b/usr.sbin/vmd/priv.c @@ -1,4 +1,4 @@ -/* $OpenBSD: priv.c,v 1.16 2021/02/28 22:56:09 dlg Exp $ */ +/* $OpenBSD: priv.c,v 1.17 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2016 Reyk Floeter @@ -92,6 +92,8 @@ priv_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) struct ifaliasreq ifra; struct in6_aliasreq in6_ifra; struct if_afreq ifar; + struct vmop_addr_req vareq; + struct vmop_addr_result varesult; char type[IF_NAMESIZE]; switch (imsg->hdr.type) { @@ -115,6 +117,7 @@ priv_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) break; case IMSG_VMDOP_CONFIG: case IMSG_CTL_RESET: + case IMSG_VMDOP_PRIV_GET_ADDR: break; default: return (-1); @@ -245,6 +248,22 @@ priv_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) if (ioctl(env->vmd_fd6, SIOCAIFADDR_IN6, &in6_ifra) == -1) log_warn("SIOCAIFADDR_IN6"); break; + case IMSG_VMDOP_PRIV_GET_ADDR: + IMSG_SIZE_CHECK(imsg, &vareq); + memcpy(&vareq, imsg->data, sizeof(vareq)); + + varesult.var_vmid = vareq.var_vmid; + varesult.var_nic_idx = vareq.var_nic_idx; + + /* resolve lladdr for the tap(4) and send back to parent */ + if (ioctl(imsg->fd, SIOCGIFADDR, &varesult.var_addr) != 0) + log_warn("SIOCGIFADDR"); + else + proc_compose_imsg(ps, PROC_PARENT, -1, + IMSG_VMDOP_PRIV_GET_ADDR_RESPONSE, imsg->hdr.peerid, + -1, &varesult, sizeof(varesult)); + close(imsg->fd); + break; case IMSG_VMDOP_CONFIG: config_getconfig(env, imsg); break; diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c index 1d269ed65ff..f937bf602f6 100644 --- a/usr.sbin/vmd/virtio.c +++ b/usr.sbin/vmd/virtio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.c,v 1.83 2021/03/26 17:40:03 deraadt Exp $ */ +/* $OpenBSD: virtio.c,v 1.84 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -2034,6 +2034,31 @@ virtio_init(struct vmd_vm *vm, int child_cdrom, evtimer_set(&vmmci.timeout, vmmci_timeout, NULL); } +/* + * vionet_set_hostmac + * + * Sets the hardware address for the host-side tap(4) on a vionet_dev. + * + * This should only be called from the event-loop thread + * + * vm: pointer to the current vmd_vm instance + * idx: index into the array of vionet_dev's for the target vionet_dev + * addr: ethernet address to set + */ +void +vionet_set_hostmac(struct vmd_vm *vm, unsigned int idx, uint8_t *addr) +{ + struct vmop_create_params *vmc = &vm->vm_params; + struct vm_create_params *vcp = &vmc->vmc_params; + struct vionet_dev *dev; + + if (idx > vcp->vcp_nnics) + fatalx("vionet_set_hostmac"); + + dev = &vionet[idx]; + memcpy(dev->hostmac, addr, sizeof(dev->hostmac)); +} + void virtio_shutdown(struct vmd_vm *vm) { diff --git a/usr.sbin/vmd/virtio.h b/usr.sbin/vmd/virtio.h index 1672cca267c..9d7ef81831d 100644 --- a/usr.sbin/vmd/virtio.h +++ b/usr.sbin/vmd/virtio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.h,v 1.36 2021/01/07 17:11:38 tracey Exp $ */ +/* $OpenBSD: virtio.h,v 1.37 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -208,6 +208,7 @@ struct vionet_dev { uint32_t vm_vmid; int irq; uint8_t mac[6]; + uint8_t hostmac[6]; int idx; int lockedmac; @@ -298,6 +299,7 @@ void vionet_notify_rx(struct vionet_dev *); int vionet_notify_tx(struct vionet_dev *); void vionet_process_rx(uint32_t); int vionet_enq_rx(struct vionet_dev *, char *, ssize_t, int *); +void vionet_set_hostmac(struct vmd_vm *, unsigned int, uint8_t *); int vmmci_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t); int vmmci_dump(int); diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index bf515eb3778..9ffd1598b21 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm.c,v 1.60 2021/03/19 09:29:33 kn Exp $ */ +/* $OpenBSD: vm.c,v 1.61 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -394,6 +394,7 @@ vm_dispatch_vmm(int fd, short event, void *arg) { struct vmd_vm *vm = arg; struct vmop_result vmr; + struct vmop_addr_result var; struct imsgev *iev = &vm->vm_iev; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; @@ -471,6 +472,16 @@ vm_dispatch_vmm(int fd, short event, void *arg) _exit(0); } break; + case IMSG_VMDOP_PRIV_GET_ADDR_RESPONSE: + IMSG_SIZE_CHECK(&imsg, &var); + memcpy(&var, imsg.data, sizeof(var)); + + log_debug("%s: received tap addr %s for nic %d", + vm->vm_params.vmc_params.vcp_name, + ether_ntoa((void *)var.var_addr), var.var_nic_idx); + + vionet_set_hostmac(vm, var.var_nic_idx, var.var_addr); + break; default: fatalx("%s: got invalid imsg %d from %s", __func__, imsg.hdr.type, diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c index 3bceb5c0593..cd585d5a197 100644 --- a/usr.sbin/vmd/vmd.c +++ b/usr.sbin/vmd/vmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.c,v 1.120 2021/01/27 07:21:54 deraadt Exp $ */ +/* $OpenBSD: vmd.c,v 1.121 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -58,6 +58,7 @@ void vmd_shutdown(void); int vmd_control_run(void); int vmd_dispatch_control(int, struct privsep_proc *, struct imsg *); int vmd_dispatch_vmm(int, struct privsep_proc *, struct imsg *); +int vmd_dispatch_priv(int, struct privsep_proc *, struct imsg *); int vmd_check_vmh(struct vm_dump_header *); int vm_instance(struct privsep *, struct vmd_vm **, @@ -70,7 +71,7 @@ struct vmd *env; static struct privsep_proc procs[] = { /* Keep "priv" on top as procs[0] */ - { "priv", PROC_PRIV, NULL, priv }, + { "priv", PROC_PRIV, vmd_dispatch_priv, priv }, { "control", PROC_CONTROL, vmd_dispatch_control, control }, { "vmm", PROC_VMM, vmd_dispatch_vmm, vmm, vmm_shutdown }, }; @@ -550,6 +551,24 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg) return (0); } +int +vmd_dispatch_priv(int fd, struct privsep_proc *p, struct imsg *imsg) +{ + struct vmop_addr_result var; + + switch (imsg->hdr.type) { + case IMSG_VMDOP_PRIV_GET_ADDR_RESPONSE: + IMSG_SIZE_CHECK(imsg, &var); + memcpy(&var, imsg->data, sizeof(var)); + proc_forward_imsg(p->p_ps, imsg, PROC_VMM, -1); + break; + default: + return (-1); + } + + return (0); +} + int vmd_check_vmh(struct vm_dump_header *vmh) { diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index a2d80eb2181..a9d752a2c2a 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.102 2021/03/19 09:29:33 kn Exp $ */ +/* $OpenBSD: vmd.h,v 1.103 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -120,6 +120,8 @@ enum imsg_type { IMSG_VMDOP_PRIV_IFADDR, IMSG_VMDOP_PRIV_IFADDR6, IMSG_VMDOP_PRIV_IFRDOMAIN, + IMSG_VMDOP_PRIV_GET_ADDR, + IMSG_VMDOP_PRIV_GET_ADDR_RESPONSE, IMSG_VMDOP_VM_SHUTDOWN, IMSG_VMDOP_VM_REBOOT, IMSG_VMDOP_CONFIG, @@ -158,6 +160,17 @@ struct vmop_ifreq { struct sockaddr_storage vfr_mask; }; +struct vmop_addr_req { + uint32_t var_vmid; + unsigned int var_nic_idx; +}; + +struct vmop_addr_result { + uint32_t var_vmid; + unsigned int var_nic_idx; + uint8_t var_addr[ETHER_ADDR_LEN]; +}; + struct vmop_owner { uid_t uid; int64_t gid; diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c index 19964a86f80..faebf670dee 100644 --- a/usr.sbin/vmd/vmm.c +++ b/usr.sbin/vmd/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.97 2021/03/02 02:56:22 jsg Exp $ */ +/* $OpenBSD: vmm.c,v 1.98 2021/03/29 23:37:01 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -109,6 +109,7 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) struct vmop_id vid; struct vmop_result vmr; struct vmop_create_params vmc; + struct vmop_addr_result var; uint32_t id = 0, peerid = imsg->hdr.peerid; pid_t pid = 0; unsigned int mode, flags; @@ -332,6 +333,18 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) res = ENOENT; cmd = IMSG_VMDOP_START_VM_RESPONSE; break; + case IMSG_VMDOP_PRIV_GET_ADDR_RESPONSE: + IMSG_SIZE_CHECK(imsg, &var); + memcpy(&var, imsg->data, sizeof(var)); + if ((vm = vm_getbyvmid(var.var_vmid)) == NULL) { + res = ENOENT; + break; + } + /* Forward hardware address details to the guest vm */ + imsg_compose_event(&vm->vm_iev, + imsg->hdr.type, imsg->hdr.peerid, imsg->hdr.pid, + imsg->fd, &var, sizeof(var)); + break; default: return (-1); }