代码版本:
Socket Pool
套接字池(Socket Pool)为虚拟路由冗余协议(VRRP)实例高效管理网络通信,可在合适的情况下允许多个实例共享套接字。
vrrp_dispatcher_init
创建和申请一个 socket pool。
假设有 n 个网卡。每个网卡最多有 2 个 fds(1个用于 VRRP,另一个用于 IPSEC_AH)。所有的 VRRP 实例都通过这些文件描述符(fds)实现多路复用。因此,我们的设计可支持 2×n 个多路复用节点。
1 2 3 4
| fd1 fd2 fd3 fd4 fdi fdi+1 -----\__/--------\__/---........---\__/--- | ETH0 | | ETH1 | | ETHn | +------+ +------+ +------+
|
多个 VRRP 实例不单独占用套接字,而是共享一组 fds 资源,通过操作系统的 I/O 多路复用技术(如 Linux 的epoll、BSD 的kqueue)实现对多个实例通信需求的并发处理,最终达成 “用少量 fds 支持大量实例” 的高效设计目标。
vrrp_create_sockpool
为 VRRP instances 创建 sockets 结构
1 2 3 4 5
| vrrp_create_sockpool(vrrp_data->vrrp_socket_pool) for(e : vrrp_data->vrrp_socket_pool) { alloc_sock MALLOC }
|
vrrp_open_sockpool
开启物理 sockets
1 2 3 4 5 6 7 8
| vrrp_open_sockpool(vrrp_data->vrrp_socket_pool) for(e : vrrp_data->vrrp_socket_pool) { sock_obj = ELEMENT_DATA(e); sock_obj->fd_in = open_vrrp_socket(); socket(AF_INET, SOCK_RAW, proto); sock_obj->fd_out = open_vrrp_send_socket(); socket(AF_INET, SOCK_RAW, proto); }
|
vrrp_set_fds
为 VRRP instances 分配合适的 sockets
1 2 3 4 5
| vrrp_set_fds(vrrp_data->vrrp_socket_pool) for(e : vrrp_data->vrrp_socket_pool) { vrrp->fd_in = sock_obj->fd_in; vrrp->fd_out = sock_obj->fd_out; }
|
通告处理
VRRP 调度器处理传入的 VRRP 通告,并根据实例的当前状态对其进行处理:

代码流程
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 27 28 29 30 31 32 33 34 35 36 37 38
| vrrp_read_dispatcher_thread vrrp_dispatcher_read read(fd, vrrp_buffer, VRRP_PACKET_TEMP_LEN);
vrrp = vrrp_index_lookup(hd->vrid, fd);
prev_state = vrrp->state; VRRP_FSM_READ(vrrp, vrrp_buffer, len); vrrp_leave_master vrrp_state_master_rx ret = vrrp_check_packet(vrrp, buf, buflen);
if (Lower priority) { vrrp_send_adv(vrrp, vrrp->priority); vrrp_send_gratuitous_arp(vrrp); return 0; } else { vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); vrrp->wantstate = VRRP_STATE_BACK; vrrp->state = VRRP_STATE_BACK; return 1; } vrrp_backup vrrp_state_backup if(Higher priority) vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp); else vrrp->wantstate = VRRP_STATE_GOTO_MASTER; vrrp_send_adv(vrrp, vrrp->priority);
|
vrrp_send_adv
- VRRP 协议报文封装在 IP 报文中,发送到分配给 VRRP 的 IP 组播地址
- 在IP 报文头中
- 源地址为发送报文接口的主 IP 地址
- 目的地址为 224.0.0.18
- TTL 必须是 255。(VRRP 路由器会丢弃 TTL 不等于 255 的 VRRP 协议报文)
- 协议号是 112
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| vrrp_send_adv vrrp_build_pkt(vrrp, prio) vrrp_build_ip ip->ttl = VRRP_IP_TTL; ip->protocol = (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP; ip->saddr = VRRP_PKT_SADDR(vrrp); ip->daddr = htonl(INADDR_VRRP_GROUP); ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0); vrrp_build_vrrp(vrrp, prio, vrrp->send_buffer, vrrp->send_buffer_size)
|
keepalived