Klemens Nanni <k...@openbsd.org> writes:
> kern.version=OpenBSD 7.4-current (GENERIC.MP) #1667: Wed Feb 7 20:09:35 MST > 2024 > dera...@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP > > 'locked addr' in `switch' block yields > vm/foo/vionet0: vionet_rx_copy: invalid injected packet object > > Minimal reproducer from my vm.conf(5) that used to work fine: > > # ifconfig vport0 inet6 fd00::1 up > # ifconfig veb0 add vport0 > # cat /tmp/vm.conf > switch uplink { > interface veb0 > locked lladdr > } > vm foo { > disable > boot /bsd.rd > disk /tmp/disk.img > interface { > switch uplink > locked lladdr > } > } > # vmctl create -s1m /tmp/foo.img > # `which vmd` -f/tmp/vm.conf -dvv > > vmd: startup > vmd: /tmp/vm.conf:4: switch "uplink" registered > vmd: vm_register: registering vm 1 > vmd: /tmp/vm.conf:13: vm "foo" registered (disabled) > vmd: vm_priv_brconfig: interface veb0 description switch1-uplink > vmd: vmd_configure: setting staggered start configuration to parallelism: 12 > and delay: 30 > vmd: vmd_configure: starting vms in staggered fashion > vmd: start_vm_batch: starting batch of 12 vms > vmd: start_vm_batch: not starting vm foo (disabled) > vmd: start_vm_batch: done starting vms > priv: config_getconfig: priv retrieving config > vmm: config_getconfig: vmm retrieving config > agentx: config_getconfig: agentx retrieving config > control: config_getconfig: control retrieving config > > # vmctl start -c foo > > vmd: vm_opentty: vm foo tty /dev/ttyp7 uid 0 gid 4 mode 620 > vmm: vm_register: registering vm 1 > vmd: vm_priv_ifconfig: interface tap0 description vm1-if0-foo > vmd: vm_priv_ifconfig: switch "uplink" interface veb0 add tap0 > vmd: started foo (vm 1) successfully, tty /dev/ttyp7 > vm/foo: loadfile_elf: loaded ELF kernel > vm/foo: pic_set_elcr: setting level triggered mode for irq 3 > vm/foo: pic_set_elcr: setting level triggered mode for irq 5 > vm/foo: virtio_init: vm "foo" vio0 lladdr fe:e1:bb:d1:5a:58, locked > vm/foo: pic_set_elcr: setting level triggered mode for irq 6 > vm/foo: foo: launching vioblk0 > vm/foo: virtio_dev_launch: sending 'd' type device struct > vm/foo: virtio_dev_launch: sending vm message for 'foo' > vm/foo/vioblk: vioblk_main: got viblk dev. num disk fds = 1, sync fd = 16, > async fd = 18, capacity = 0 seg_max = 126, vmm fd = 5 > vm/foo/vioblk0: vioblk_main: initialized vioblk0 with raw image > (capacity=2048) > vm/foo/vioblk0: vioblk_main: wiring in async vm event handler (fd=18) > vm/foo/vioblk0: vm_device_pipe: initializing 'd' device pipe (fd=18) > vm/foo/vioblk0: vioblk_main: wiring in sync channel handler (fd=16) > vm/foo/vioblk0: vioblk_main: telling vm foo device is ready > vm/foo/vioblk0: vioblk_main: sending heartbeat > vm/foo: virtio_dev_launch: receiving reply > vm/foo: virtio_dev_launch: device reports ready via sync channel > vm/foo: vm_device_pipe: initializing 'd' device pipe (fd=17) > vm/foo: foo: launching vionet0 > vm/foo: virtio_dev_launch: sending 'n' type device struct > vm/foo: virtio_dev_launch: sending vm message for 'foo' > vm/foo/vionet: vionet_main: got vionet dev. tap fd = 8, syncfd = 16, asyncfd > = 19, vmm fd = 5 > vm/foo/vionet0: vionet_main: wiring in async vm event handler (fd=19) > vm/foo/vionet0: vm_device_pipe: initializing 'n' device pipe (fd=19) > vm/foo/vionet0: vionet_main: wiring in tap fd handler (fd=8) > vm/foo/vionet0: vionet_main: wiring in packet injection handler (fd=3) > vm/foo/vionet0: vionet_main: wiring in sync channel handler (fd=16) > vm/foo/vionet0: vionet_main: telling vm foo device is ready > vm/foo/vionet0: vionet_main: sending async ready message > vm/foo: virtio_dev_launch: receiving reply > vm/foo: virtio_dev_launch: device reports ready via sync channel > vm/foo: vm_device_pipe: initializing 'n' device pipe (fd=18) > vm/foo: pic_set_elcr: setting level triggered mode for irq 7 > vm/foo: run_vm: starting 1 vcpu thread(s) for vm foo > vm/foo: vcpu_reset: resetting vcpu 0 for vm 29 > vm/foo: run_vm: waiting on events for VM foo > vm/foo: foo: received tap addr fe:e1:ba:dd:0e:e5 for nic 0 > vm/foo: handle_dev_msg: device reports ready > vm/foo: handle_dev_msg: device reports ready > vm/foo/vionet0: dev_dispatch_vm: set hostmac > vm/foo: vcpu_exit_i8253: channel 0 reset, mode=2, start=65535 > vm/foo: vcpu_process_com_lcr: set baudrate = 115200 > vm/foo: i8259_write_datareg: master pic, reset IRQ vector to 0x20 > vm/foo: i8259_write_datareg: slave pic, reset IRQ vector to 0x28 > vm/foo: vcpu_exit_i8253: channel 0 reset, mode=2, start=11932 > vm/foo: vcpu_process_com_lcr: set baudrate = 115200 > vm/foo: vcpu_exit_eptviolation: fault already handled > vm/foo: vcpu_exit_eptviolation: fault already handled > vm/foo: vcpu_process_com_lcr: set baudrate = 115200 > vm/foo: vcpu_exit_eptviolation: fault already handled > > Welcome to the OpenBSD/amd64 7.4 installation program. > (I)nstall, (U)pgrade, (A)utoinstall or (S)hell? s > # ifconfig vio0 inet6 fd00::2 > # ping6 -c1 fd00::1 > PING fd00::1 (fd00::1): 56 data bytes > > --- fd00::1 ping statistics --- > 1 packets transmitted, 0 packets received, 100.0% packet loss > > vm/foo/vionet0: vionet_rx_copy: invalid injected packet object Turns out I had a bug in my packet injection logic. Locked addr forces use of the copy mode (i.e. not the zero-copy mode) and my logic was thinking the packet being read was an "injected" packet from the dhcp intercept. I don't think this is ipv6 specific. > Removing 'locked addr' from either `switch' or `interface' is not enough, > both lines must be removed for packets to flow again: > > # ping6 -qc1 fd00::1 > PING fd00::1 (fd00::1): 56 data bytes > > --- fd00::1 ping statistics --- > 1 packets transmitted, 1 packets received, 0.0% packet loss > round-trip min/avg/max/std-dev = 0.838/0.838/0.838/0.000 ms Try this diff: diff /usr/src commit - e56f03c81d8d8caa46c3a9dd3ebf582fb69cd317 path + /usr/src blob - 6f4b741bd1f960913774ee51c4ffd8dc98068d17 file + usr.sbin/vmd/vionet.c --- usr.sbin/vmd/vionet.c +++ usr.sbin/vmd/vionet.c @@ -514,8 +514,9 @@ vionet_rx_copy(struct vionet_dev *dev, int fd, const s /* If reading the tap(4), we should get valid ethernet. */ log_warnx("%s: invalid packet size", __func__); return (0); - } else if (sz != sizeof(struct packet)) { - log_warnx("%s: invalid injected packet object", __func__); + } else if (fd == pipe_inject[READ] && sz != sizeof(struct packet)) { + log_warnx("%s: invalid injected packet object (sz=%ld)", + __func__, sz); return (0); }