.. meta:: :description: First-Hop Redundancy Protocols (FHRPs)—principally the vendor-neutral **Virtual Router Redundancy Protocol (VRRPv2/v3, RFC 5798)** and Cisco's proprietary... :keywords: Python, Snmp, Vrrp, Hsrp, Fhrp, High-Availability, Ezsnmp, Python, ezsnmp, Networking, DevOps :author: Carlos Santos (@carlkidcrypto) :property=og:title: First-Hop Redundancy Monitoring: VRRP & HSRP with ezsnmp :property=og:description: First-Hop Redundancy Protocols (FHRPs)—principally the vendor-neutral **Virtual Router Redundancy Protocol (VRRPv2/v3, RFC 5798)** and Cisco's proprietary... :property=og:type: article :property=og:url: https://carlkidcrypto.github.io/blog/ezsnmp-vrrp-hsrp-redundancy-monitoring.html :property=og:image: https://carlkidcrypto.github.io/_static/logo.png :name=twitter:card: summary :name=twitter:title: First-Hop Redundancy Monitoring: VRRP & HSRP with ezsnmp :name=twitter:description: First-Hop Redundancy Protocols (FHRPs)—principally the vendor-neutral **Virtual Router Redundancy Protocol (VRRPv2/v3, RFC 5798)** and Cisco's proprietary... :name=twitter:image: https://carlkidcrypto.github.io/_static/logo.png ============================================================ First-Hop Redundancy Monitoring: VRRP & HSRP with ezsnmp ============================================================ .. note:: * **Published:** November 03, 2026 * **Authors:** Written by Gemini 3.8 Flash, Co-Authored & Reviewed by `Carlos Santos (@carlkidcrypto) `_ * **Estimated Reading Time:** 5 minutes * **Tags:** `Python` • `Snmp` • `Vrrp` • `Hsrp` • `Fhrp` • `High-Availability` • `Ezsnmp` Why Gateway Redundancy Telemetry Is Critical ============================================ First-Hop Redundancy Protocols (FHRPs)—principally the vendor-neutral **Virtual Router Redundancy Protocol (VRRPv2/v3, RFC 5798)** and Cisco's proprietary **Hot Standby Router Protocol (HSRP, RFC 2281)**—provide default gateway resiliency for campus subnets, server clusters, and storage fabrics. By sharing a virtual IP (VIP) and virtual MAC (VMAC) address across redundant routers, FHRP ensures client traffic fails over seamlessly if the active gateway experiences hardware or uplink failure. However, gateway redundancy introduces insidious failure modes: * **Split-Brain / Dual-Master State**: If transit links drop VRRP multicast advertisements (224.0.0.18) or ACLs misfilter UDP/IP protocol 112, both routers assume the active role, poisoning client ARP tables and dropping traffic. * **No-Master State**: Mismatched authentication keys or misconfigured virtual IPs causing all routers to remain in ``Backup`` or ``Initialize`` state. * **Preemption Churn**: An unstable upstream link causing a higher-priority router to repeatedly seize and surrender the Master role. * **Priority Tracking Failure**: Uplink tracking scripts failing to decrement router priority when external transit links disconnect. `ezsnmp `_ provides native Net-SNMP C bindings to query standard VRRP and HSRP MIBs, allowing engineers to audit gateway states and detect split-brain anomalies across hundreds of subnets in milliseconds. The Architecture of VRRP-MIB (RFC 2787) ======================================= The standard ``VRRP-MIB`` structures operational gateway telemetry under the ``vrrpOperTable`` (OID ``.1.3.6.1.2.1.68.1.3.1``): * **``vrrpOperState``**: The Finite State Machine (FSM) integer: - ``initialize(1)``: Waiting for startup event or interface up signal. - ``backup(2)``: Monitoring Master advertisements; ready to fail over. - ``master(3)``: Actively serving the virtual IP and answering ARP queries. * **``vrrpOperPriority``**: Priority value (1..254, where 255 indicates the IP address owner). Higher priority wins Master elections. * **``vrrpOperMasterIpAddr``**: The primary physical IP address of the router currently recognized as Master. * **``vrrpOperVirtualMacAddr``**: The active virtual MAC address (e.g. ``00:00:5E:00:01:{VRID}``). * **``vrrpOperAdvertisementInterval``**: Time between multicast heartbeat advertisements (seconds or centiseconds). * **``vrrpOperPreemptMode``**: Indicates whether a higher-priority router preempts an existing Master (``true(1)`` or ``false(2)``). Chassis Error Counters & Polling Skew --------------------------------------- Under ``vrrpRouterChecksumErrors``, ``vrrpRouterVersionErrors``, and ``vrrpRouterVrIdErrors``, switches track packet-level reception faults. Spikes in these counters pinpoint misconfigured VRID numbers or MTU truncation. When monitoring redundant router pairs, sequential polling can sample nodes across an in-flight master transition, falsely suggesting a split-brain or missing master condition. High-availability auditors should query both peers concurrently and verify anomalies over consecutive polling intervals before raising critical alerts. Practical Implementation: Redundancy Health Auditor =================================================== Below is a complete script demonstrating how to query VRRP states across a pair of redundant gateways and detect split-brain or missing master conditions: .. code-block:: python from concurrent.futures import ThreadPoolExecutor from ezsnmp import Session from ezsnmp.exceptions import GenericError VRRP_STATE_MAP = { 1: "INITIALIZE", 2: "BACKUP", 3: "MASTER", } def parse_numeric(val, default=0): digits = "".join(c for c in str(val) if c.isdigit()) return int(digits) if digits else default def extract_if_and_vrid(idx_str: str, oid_str: str) -> tuple[int, int]: """Extract local (ifIndex, vrid) from composite index.""" parts = [int(p) for p in str(idx_str).split(".") if p.isdigit()] if len(parts) >= 2: return parts[0], parts[1] oid_parts = [int(p) for p in str(oid_str).split(".") if p.isdigit()] if len(oid_parts) >= 2: return oid_parts[-2], oid_parts[-1] return 0, 0 def collect_vrrp_state(hostname: str, community: str = "public") -> dict: """Collect VRRP group states with full (ifIndex, vrid) composite identity.""" session = Session( hostname=hostname, community=community, version=2, timeout=2, retries=1, set_max_repeaters_to_num=25, print_enums_numerically=True ) try: # Bulk-walk VRRP operational columns state_vars = session.bulk_walk("vrrpOperState") prio_vars = session.bulk_walk("vrrpOperPriority") master_vars = session.bulk_walk("vrrpOperMasterIpAddr") prio_map = {v.index: parse_numeric(v.value) for v in prio_vars} master_map = {v.index: str(v.value).strip() for v in master_vars} vrrp_groups = {} for v in state_vars: idx = v.index if_idx, vrid = extract_if_and_vrid(idx, v.oid) raw_state = str(v.value).strip() if raw_state.isdigit(): state_code = int(raw_state) state_name = VRRP_STATE_MAP.get(state_code, "UNKNOWN") else: state_name = raw_state.upper() state_code = {val: k for k, val in VRRP_STATE_MAP.items()}.get(state_name, 0) master_ip = master_map.get(idx, "Unknown") group_key = ( f"vrid_{vrid}_vip_{master_ip}" if master_ip not in ("Unknown", "0.0.0.0") else f"if_{if_idx}_vrid_{vrid}" ) vrrp_groups[group_key] = { "if_index": if_idx, "vrid": vrid, "state": state_name, "state_code": state_code, "priority": prio_map.get(idx, 0), "master_ip": master_ip, } return vrrp_groups except GenericError as exc: print(f"[{hostname}] VRRP query failed: {exc}") return {} def reconcile_fhrp_pair(rtr1_host: str, rtr2_host: str): """Cross-reconcile VRRP states across an HA router pair using concurrent polling.""" with ThreadPoolExecutor(max_workers=2) as executor: f1 = executor.submit(collect_vrrp_state, rtr1_host) f2 = executor.submit(collect_vrrp_state, rtr2_host) rtr1_groups = f1.result() rtr2_groups = f2.result() all_keys = set(rtr1_groups.keys()) | set(rtr2_groups.keys()) print(f"--- FHRP Reconciliation: {rtr1_host} vs {rtr2_host} ---") for key in sorted(all_keys): g1 = rtr1_groups.get(key, {}) g2 = rtr2_groups.get(key, {}) vrid = g1.get("vrid") or g2.get("vrid") or 0 s1 = g1.get("state", "MISSING") s2 = g2.get("state", "MISSING") p1 = g1.get("priority", 0) p2 = g2.get("priority", 0) # Strict health decision: exactly one MASTER and one BACKUP alert = False status = "HEALTHY" if s1 == "MASTER" and s2 == "MASTER": status = "CRITICAL_SPLIT_BRAIN_DUAL_MASTER" alert = True elif s1 != "MASTER" and s2 != "MASTER": status = "CRITICAL_NO_ACTIVE_MASTER" alert = True elif (s1 == "MASTER" and s2 == "BACKUP") or (s1 == "BACKUP" and s2 == "MASTER"): status = "HEALTHY" alert = False else: status = f"DEGRADED_STATE_{s1}_{s2}" alert = True flag = f" [{status}]" if alert else " [OK]" print( f" VRID {vrid:>3} ({key}) | " f"{rtr1_host}: {s1:<6} (Prio {p1:>3}) | " f"{rtr2_host}: {s2:<6} (Prio {p2:>3}){flag}" ) if __name__ == "__main__": reconcile_fhrp_pair("gw-core01.internal", "gw-core02.internal") 📥 `Download this script: reconcile_fhrp_pair.py `_ Production Best Practices ========================= * **Cross-Reconcile Gateway Pairs**: Auditing a single router in isolation cannot confirm gateway health. Always poll peer routers concurrently to verify that exactly one router reports ``MASTER`` and the peer reports ``BACKUP``. * **Monitor Error Counters**: In high-density fabrics, periodically poll ``vrrpRouterChecksumErrors``. A rising counter indicates that multicast packets are truncating or VLAN tags are leaking between subnets. * **Correlate with Cisco HSRP MIB**: For enterprise environments running HSRP, query ``cHsrpGrpTable`` (OID ``.1.3.6.1.4.1.9.9.106.1.2.1``) to inspect ``cHsrpGrpStandbyState`` (Active=6, Standby=5) using identical patterns. Migration Notes: Easy SNMP vs ezsnmp ==================================== * **Process-Isolated HA Polling**: Cross-reconciling HA pairs requires querying multiple hosts simultaneously. While ``ezsnmp`` encapsulates Net-SNMP sessions with C++17 RAII structures, Net-SNMP itself uses process-global C variables and format locks. For high-frequency HA audits across large router inventories, execute checks via ``concurrent.futures.ProcessPoolExecutor`` to achieve linear concurrency without global lock serialization. * **Memory Integrity in Fast Heartbeat Audits**: Polling gateway states every 10 seconds cleanly reclaims Net-SNMP PDU chains via RAII destructors, ensuring zero memory leakage in 24/7 monitoring daemons. Useful Links & Community ======================== * **Source Repository**: `carlkidcrypto/ezsnmp on GitHub `_ * **PyPI Distribution**: `ezsnmp Package on PyPI `_ * **Documentation**: `ezsnmp Online Documentation `_ * **Blog & Updates**: `Carlos Santos Blog Updates`_ .. _Carlos Santos Blog Updates: https://github.com/carlkidcrypto/carlkidcrypto.github.io/tree/feature/updates ---- .. warning:: AI-generated content may contain misinformation or mistakes. A human does review this, but we are only human.