If you have ever configured keepalived’s vrrp_script and been surprised by which node became master, this post is for you. The interaction between a script’s weight and a node’s base priority is subtle — and the keepalived documentation leaves many details underspecified. The only reliable reference is the source code. This post reads through it to give you a precise mental model.
→ Related: Keepalived VRRP failover in production — multi-node setup and failure lessons (Blog 08)
The Config Model: priority, weight, and rise/fall
In keepalived.conf, each vrrp_instance has a priority (an integer from 1 to 254). Each vrrp_script attached to the instance has a weight value. The weight can be positive or negative. It also has rise (number of consecutive successes to become OK) and fall (consecutive failures to become KO) counters.
vrrp_script chk_haproxy { script “/usr/bin/killall -0 haproxy” interval 2 weight -20 fall 2 rise 2 } vrrp_instance VI_1 { priority 100 track_script { chk_haproxy } }
The Source: vrrp_script.c and vrrp.c
Script state tracking lives in lib/vrrp_script.c. The script’s result (OK or KO) is updated in vrrp_script_update_weight(). The effective priority calculation for a VRRP instance happens in vrrp_set_effective_priority() in lib/vrrp.c (in some versions this logic is in vrrp_script.c as update_script_priorities).
The key logic: for each tracked script, if the script is in KO state, its weight is subtracted from the base priority (for negative weights) or not added (for positive weights). If the script is in OK state, positive weights add to the base priority, negative weights do not subtract.
The Math: Positive vs Negative Weight
With a negative weight (e.g., weight -20): when the script is OK, the effective priority equals the base priority (no change). When the script is KO, effective priority = base priority + weight (e.g., 100 + (-20) = 80). The node loses priority when its script fails.
With a positive weight (e.g., weight 10): when the script is OK, effective priority = base priority + weight (e.g., 100 + 10 = 110). When the script is KO, effective priority = base priority. The node gains priority when its script succeeds.
This asymmetry is the source of most keepalived vrrp_script weight priority confusion. Negative weights penalize failures. Positive weights reward successes. Both can be used to implement health-based failover, but the threshold arithmetic differs.
A Worked Example: Two-Node Failover
Node A: priority 100, weight -20, script currently OK. Effective priority: 100. Node B: priority 90, weight -20, script currently OK. Effective priority: 90. Node A is master.
Now Node A’s script fails (reaches fall threshold). Node A effective priority: 100 + (-20) = 80. Node B effective priority: 90. Node B’s priority (90) is now higher. Node B will send VRRP advertisements with priority 90 > 80. Node A, receiving advertisements with higher priority than its own, transitions to BACKUP. Node B becomes MASTER.
For this failover to work, the weight must be large enough that Node A’s penalized priority falls below Node B’s base priority: weight < (Node B priority – Node A priority) in absolute value terms, and Node A base priority + weight < Node B base priority.
/* Required for clean failover: */ /* NodeA.priority + weight < NodeB.priority */ /* 100 + (-20) = 80 < 90 ✓ */
rise and fall: Hysteresis in the Source
The rise and fall parameters add hysteresis. In vrrp_script.c, the script’s result counter is incremented on success and decremented on failure. The state transitions from OK to KO only when the counter hits -fall, and from KO to OK only when it hits +rise. This prevents flapping when the monitored process is intermittently failing.
Reading vrrp_script_update() shows that each timer tick calls the script, evaluates the exit code (0=success, nonzero=failure), and updates the counter. The actual priority recalculation only happens on state transition (OK→KO or KO→OK), not on every tick.
Debugging: vrrp_debug and syslog
To observe the priority calculations live, enable debug logging in keepalived.conf (log_detail, log_facility). Keepalived will log each script execution result and the resulting effective priority to syslog. This is invaluable when the failover behavior does not match your arithmetic — often it reveals that the rise/fall counters have not yet reached threshold.
Conclusion
The keepalived vrrp_script weight priority interaction is precise but not complicated once you read the source. Negative weights penalize KO scripts. Positive weights reward OK scripts. The failover threshold depends on the arithmetic relationship between Node A’s penalized priority and Node B’s priority. The rise/fall hysteresis prevents flapping. With this mental model, you can design keepalived configurations that fail over exactly when you intend them to.


Leave a Reply