tested on FreeBSD 15.0-CURRENT #8 main-n267554-c8328f1a7b6e when an interface is destroyed, an rtnetlink socket monitoring RTNLGRP_LINK will get 1 or more spurious RTM_NEWLINKS, followed by the actual RTM_DELLINK. this can be observed with 'route monitor' which uses netlink: # ifconfig bridge1 create 03:49:47.538 PID 10747 add/repl iface iface#8 bridge1 admin DOWN oper DOWN mtu 1500 # ifconfig bridge1 destroy 03:50:14.124 PID 10747 add/repl iface iface#8 bridge1 admin DOWN oper DOWN mtu 1500 03:50:14.124 PID 10747 delete iface iface#8 bridge1 admin DOWN oper DOWN mtu 1500 with wg(4) interfaces, there are several spurious RTM_NEWLINKs after destroy: 03:50:44.607 PID 10747 add/repl iface iface#8 wg1 admin DOWN oper DOWN mtu 1420 03:50:44.607 PID 0 add/repl iface iface#8 wg1 admin DOWN oper DOWN mtu 1420 03:50:44.654 PID 10747 add/repl iface iface#8 wg1 admin DOWN oper DOWN mtu 1420 03:50:44.654 PID 0 delete iface iface#8 wg1 admin DOWN oper DOWN mtu 1420 i'm not particularly familiar with the netlink API, but from reading the documentation, this isn't the behaviour i'd expect.
Let's send it to melifaro@ for comment to start with
A dtrace script which gives some info about where the notifications are coming from: dtrace -n 'fbt::rtnl_handle_ifevent:entry /args[1] == 16/{stack();}' When I destroy a wg interface, I get: 8 22603 rtnl_handle_ifevent:entry kernel`do_link_state_change+0x44 kernel`taskqueue_run_locked+0x182 kernel`taskqueue_run+0x68 kernel`ithread_loop+0x257 kernel`fork_exit+0x7f kernel`0xffffffff80fff13e 8 22603 rtnl_handle_ifevent:entry kernel`do_link_state_change+0x1e7 kernel`taskqueue_run_locked+0x182 kernel`taskqueue_run+0x68 kernel`ithread_loop+0x257 kernel`fork_exit+0x7f kernel`0xffffffff80fff13e 4 22603 rtnl_handle_ifevent:entry kernel`if_detach_internal+0x138 kernel`if_detach+0x59 0xffffffff843e59cb kernel`if_clone_destroy+0x91 kernel`ifioctl+0x899 kernel`kern_ioctl+0x255 kernel`sys_ioctl+0x114 kernel`amd64_syscall+0x109 kernel`0xffffffff80ffe9eb These are triggered by if_link_state_change(LINK_STATE_DOWN) calls in the wireguard code, of which there are several... perhaps some are redundant?