Propagate host-side tap(4) lladdr to guest vm process to allow unicast dhcp
authordv <dv@openbsd.org>
Mon, 29 Mar 2021 23:37:01 +0000 (23:37 +0000)
committerdv <dv@openbsd.org>
Mon, 29 Mar 2021 23:37:01 +0000 (23:37 +0000)
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@

usr.sbin/vmd/config.c
usr.sbin/vmd/dhcp.c
usr.sbin/vmd/priv.c
usr.sbin/vmd/virtio.c
usr.sbin/vmd/virtio.h
usr.sbin/vmd/vm.c
usr.sbin/vmd/vmd.c
usr.sbin/vmd/vmd.h
usr.sbin/vmd/vmm.c

index 9bcf49b..46acf78 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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))
index 63d17d0..987d438 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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)
index 7335f0c..6718174 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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;
index 1d269ed..f937bf6 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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)
 {
index 1672cca..9d7ef81 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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);
index bf515eb..9ffd159 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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,
index 3bceb5c..cd585d5 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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)
 {
index a2d80eb..a9d752a 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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;
index 19964a8..faebf67 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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);
        }