admin管理员组文章数量:1642360
当 vrrp socket 发生 读超时时,会调用函数:vrrp_dispatcher_read_timeout()。
1、依据当前 master/back 状态,进行处理。若 back 发生读超时,则尝试将本端 vrrp 切换到 master;若 master 发生读超时,则直接发送 gratuitous ARP、vrrp 通告等。
/* Handle dispatcher read timeout */
static int
vrrp_dispatcher_read_timeout(sock_t *sock)
{
vrrp_t *vrrp;
int prev_state;
set_time_now();
rb_for_each_entry_cached(vrrp, &sock->rb_sands, rb_sands) {
/* 判断是否超时 */
if (vrrp->sands.tv_sec == TIMER_DISABLED ||
timercmp(&vrrp->sands, &time_now, >))
break;
prev_state = vrrp->state;
if (vrrp->state == VRRP_STATE_BACK) {
if (__test_bit(LOG_DETAIL_BIT, &debug))
log_message(LOG_INFO, "(%s) Receive advertisement timeout", vrrp->iname);
/* back 接收 master vrrp 通告超时时,尝试把本端 vrrp 切换成master */
vrrp_goto_master(vrrp);
}
else if (vrrp->state == VRRP_STATE_MAST)
/* 发送 gratuitous ARP、vrrp 通告等,参考 2.3小节 */
vrrp_master(vrrp);
/* handle instance synchronization */
#ifdef _TSM_DEBUG_
if (do_tsm_debug)
log_message(LOG_INFO, "Send [%s] TSM transition : [%d,%d] Wantstate = [%d]",
vrrp->iname, prev_state, vrrp->state, vrrp->wantstate);
#endif
VRRP_TSM_HANDLE(prev_state, vrrp);
/* 设置 vrrp sands 并调整 rb tree,具体参看 2.2小节 */
vrrp_init_instance_sands(vrrp);
}
return sock->fd_in;
}
2、back 尝试将本端 vrrp 切换到 master:
static void
vrrp_goto_master(vrrp_t * vrrp)
{
/* handle master state transition */
vrrp->wantstate = VRRP_STATE_MAST; /* 想要切换到 master */
vrrp_state_goto_master(vrrp);
}
void
vrrp_state_goto_master(vrrp_t * vrrp)
{
/* 若开启了同步组,进一步判断是否需要切换到 master */
if (vrrp->sync && !vrrp_sync_can_goto_master(vrrp))
{
vrrp->wantstate = VRRP_STATE_MAST;
return;
}
#if defined _WITH_VRRP_AUTH_
/* If becoming MASTER in IPSEC AH AUTH, we reset the anti-replay */
if (vrrp->ipsecah_counter.cycle) {
vrrp->ipsecah_counter.cycle = false;
vrrp->ipsecah_counter.seq_number = 0;
}
#endif
#ifdef _WITH_SNMP_RFCV3_
vrrp->stats->master_reason = vrrp->stats->next_master_reason;
#endif
vrrp->state = VRRP_STATE_MAST;
/* 设置 vrrp sands 并调整 rb tree */
vrrp_init_instance_sands(vrrp);
/* 发送 gratuitous ARP、vrrp 通告等 */
vrrp_state_master_tx(vrrp);
}
2.1 判断同步组是否需要切换到 master:
vrrp 同步组(syncchroization group):
假设路由有2个网段,一个内网,一个外网,每个网段都开启一个 vrrp_instance,且 vrrp 配置为检查内网:
1)若不使用同步组,那么当外网出现问题时,vrrp 会认为自己是健康的,则不会发生 master 和 back 的切换,从而导致问题;
2)若使用同步组,那么可以把内外网两个 vrrp_instance 放入同一个 vrrp_rsync_group,那么当 Group 里任何一个 vrrp_instance 出现问题时,另一个 vrrp_instance 也会发生切换(即使这个instance没有发生故障)。
/* Check transition to master state */
bool
vrrp_sync_can_goto_master(vrrp_t * vrrp)
{
vrrp_t *isync;
vrrp_sgroup_t *vgroup = vrrp->sync;
element e;
/* 同步组的状态为 master */
if (GROUP_STATE(vgroup) == VRRP_STATE_MAST)
return true;
/* Only sync to master if everyone wants to
* i.e. prefer backup state to avoid thrashing */
/* 判断同步组下的其他 vrrp_instance 是否想要切换到 master */
LIST_FOREACH(vgroup->vrrp_instances, isync, e) {
if (isync != vrrp && isync->wantstate != VRRP_STATE_MAST) {
/* Make sure we give time for other instances to be
* ready to become master. The timer here doesn't
* really matter, since we are waiting for other
* instances to be ready. */
vrrp->ms_down_timer = 3 * vrrp->master_adver_int + VRRP_TIMER_SKEW(vrrp);
vrrp_init_instance_sands(vrrp);
return false;
}
}
return true;
}
2.2 设置 vrrp sands 并调整 rb tree:
/* Compute the new instance sands */
void
vrrp_init_instance_sands(vrrp_t * vrrp)
{
set_time_now();
if (vrrp->state == VRRP_STATE_MAST) {
if (vrrp->reload_master)
/* 设置为当前时间 */
vrrp->sands = time_now;
else
/* 当前时间 + vrrp 发送通告报文的时间间隔 */
vrrp->sands = timer_add_long(time_now, vrrp->adver_int);
}
else if (vrrp->state == VRRP_STATE_BACK) {
/*
* When in the BACKUP state the expiry timer should be updated to
* time_now plus the Master Down Timer, when a non-preemptable packet is
* received.
*/
/*
当前时间 + master 超时时间
master 超时时间:vrrp->ms_down_timer = 3 * vrrp->master_adver_int + VRRP_TIMER_SKEW(vrrp),
若此计时器超时,则 back 就会宣布 master 死亡。
master_adver_int:master 发送 vrrp 通告报文的时间间隔
*/
vrrp->sands = timer_add_long(time_now, vrrp->ms_down_timer);
}
else if (vrrp->state == VRRP_STATE_FAULT || vrrp->state == VRRP_STATE_INIT)
vrrp->sands.tv_sec = TIMER_DISABLED; /* TIMER_DISABLED = LONG_MIN */
/* Move node to new position in tree */
rb_move_cached(&vrrp->sockets->rb_sands, vrrp, rb_sands, vrrp_timer_cmp);
}
2.3 发送 gratuitous ARP、vrrp 通告:
/* MASTER state processing */
void
vrrp_state_master_tx(vrrp_t * vrrp)
{
/* 若未设置 vip */
if (!VRRP_VIP_ISSET(vrrp)) {
log_message(LOG_INFO, "(%s) Entering MASTER STATE"
, vrrp->iname);
/* 添加 Virtual IP addresses / virtual routes / virtual rules */
vrrp_state_become_master(vrrp);
/*
* If we catch the master transition
* register a gratuitous arp thread delayed to garp_delay secs.
*/
/*
vrrp_gratuitous_arp_thread() :延迟广播 gratuitous ARP
garp_delay:发送 gratuitous ARP/NA 的时间间隔。
gratuitous ARP 也称为免费 ARP,无故 ARP。
gratuitous ARP 不同于一般的 ARP 请求,它并非期待得到 ip 对应的 mac 地址,
而是当主机启动时,将发送一个 gratuitous arp 请求,即请求自己的 ip 地址的 mac 地址。
*/
if (vrrp->garp_delay)
thread_add_timer(master, vrrp_gratuitous_arp_thread,
vrrp, vrrp->garp_delay);
} else if (timerisset(&vrrp->garp_refresh) &&
timercmp(&time_now, &vrrp->garp_refresh_timer, >)) {
/* 直接广播 gratuitous ARP */
vrrp_send_link_update(vrrp, vrrp->garp_refresh_rep);
vrrp->garp_refresh_timer = timer_add_now(vrrp->garp_refresh);
}
/* 向 ipv4 组播、ipv6 组播或点播地址发送 vrrp 通告 */
vrrp_send_adv(vrrp, vrrp->effective_priority);
}
本文标签: 源码Keepalivedvrrpdispatcherreadtimeout
版权声明:本文标题:keepalived源码解析 —— vrrp_dispatcher_read_timeout 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1729328089a1196022.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论