When net.inet.carp.preempt=1 and a physical interface goes down, the global V_carp_demotion counter is incremented. For CARP this was already reflected in outgoing advertisements via DEMOTE_ADVSKEW(), but VRRP sent the raw sc_vrrp_prio unchanged, so demotion had no effect.
Add DEMOTE_VRRP_PRIO(), a macro analogous to DEMOTE_ADVSKEW(): it subtracts V_carp_demotion from the configured priority and clamps the result to [0, 254]. Priority 0 is VRRPv3's "resign" signal and causes backups to preempt immediately. Priority 255 (IP address owner) is never demoted.
Apply the macro in three places in vrrp_input_c():
- when building outgoing advertisements, so a backup can preempt;
- in the MASTER receive path, so a demoted master yields to a backup whose priority exceeds the demoted value;
- in the BACKUP preempt check, so a demoted node does not immediately preempt back.
Addied a test that with net.inet.carp.preempt=1, bringing down one physical interface demotes all VRRPv3 instances on the host, causing a backup to take over on the remaining interfaces. Also verify that the higher-priority router reclaims MASTER once the interface is restored.