接口状态检测
定时轮询
- 通过定时轮询,每 POLLING_DELAY 秒刷新一次接口状态(通过 if_ioctl_flags)。
1
| thread_add_timer(master, if_linkbeat_refresh_thread, ifp, POLLING_DELAY);
|
获取接口标志
- 使用
ioctl SIOCGIFFLAGS 系统调用获取接口标志。
1 2 3 4 5 6 7 8 9 10
| void if_ioctl_flags(interface_t * ifp) { int fd = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifr.ifr_name, ifp->ifname, sizeof(ifr.ifr_name)); ioctl(fd, SIOCGIFFLAGS, &ifr); ifp->flags = ifr.ifr_flags; close(fd); }
|
链路检测
1 2 3 4 5 6 7 8 9
| int if_linkbeat(const interface_t * ifp) { if (!global_data->linkbeat_use_polling) return 1; if (IF_MII_SUPPORTED(ifp) || IF_ETHTOOL_SUPPORTED(ifp)) return IF_LINKBEAT(ifp); return 1; }
|
IF_ISUP
1 2 3
| #define IF_ISUP(X) (((X)->flags & IFF_UP) && \ ((X)->flags & IFF_RUNNING) && \ if_linkbeat(X))
|
接口被认为 UP 需要同时满足:
- IFF_UP - 接口已启用
- IFF_RUNNING - 接口正在运行(已分配资源)
- if_linkbeat() - 链路检测通过
VRRP_ISUP
1 2
| #define VRRP_ISUP(V) ((IF_ISUP((V)->ifp) || (V)->dont_track_primary) & \ ((!LIST_ISEMPTY((V)->track_ifp)) ? TRACK_ISUP((V)->track_ifp) : 1))
|
- 如果配置了 dont_track_primary,则不跟踪主接口状态
- 还需要考虑跟踪脚本的权重
接口 down
MASTER 状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| vrrp_master() │ ├─ 检测接口状态: if (!VRRP_ISUP(vrrp)) │ └─ 设置: vrrp->wantstate = VRRP_STATE_GOTO_FAULT │ └─ vrrp_state_leave_master(vrrp) │ ├─ 发送停止优先级广告: vrrp_send_adv(vrrp, VRRP_PRIO_STOP = 0) │ (通知其他路由器立即进行 MASTER 选举) │ ├─ 删除虚拟路由: vrrp_handle_iproutes(, IPROUTE_DEL) │ ├─ 删除虚拟 IP: vrrp_handle_ipaddress(, IPADDRESS_DEL) │ - VIP (vip) │ - 扩展 VIP (evip) │ ├─ 更新状态: vrrp->state = VRRP_STATE_FAULT │ ├─ 执行通知脚本: notify_instance_exec(vrrp, VRRP_STATE_FAULT) │ - notify_backup 脚本 │ - notify_fault 脚本 │ - 通用 notify 脚本 │ ├─ 发送 SNMP Trap (如果启用) │ └─ 设置 down_timer: ms_down_timer = 3 * adver_int + skew
|
BACKUP 状态
BACKUP 状态下接口 down 不会立即触发 FAULT,而是:
- 检测到接口 down 后,在 vrrp_backup() 中会忽略接收到的报文
- 如果 wantstate 是 MASTER,会尝试转换为 MASTER 但会被阻止
- 主要在 vrrp_leave_master 和 vrrp_goto_master 中处理
keepalived