keepalived源码解析 —— vrrp_state_master_rx()

功能:
1、分析收到的 vrrp 包。若包分析返回结果:VRRP_PACKET_OK,则直接返回 false;
2、若满足以下任一条件:
1)master 收到一个 priority = 0 的通告;
2)配置文件指定了:higher_prio_send_advert(若 master 收到一个更高优先级的 vrrp,则自身在变成 backup 之前发送一个通告)
且 对端 vrrp 的优先级 > 本端 vrrp 的优先级,或者 两者的优先级相同但ip相同;
则:
发送 vrrp 通告;
3、若对端与本端 vrrp 优先级均为 VRRP_PRIO_OWNER(255),则本端 vrrp 优先级-1;
4、若满足以下任一条件:
1)对端 vrrp 的优先级 < 本端 vrrp 的优先级;
2)两端优先级相同,所使用的的 ip 不同;
则:
1)发送 vrrp 通告(若配置项未指定 lower_prio_no_advert,即:如果收到低优先级的通告,不发送任何通告);
2)发送 ARP 数据包,更新远端 ARP 缓冲区;
5、若对端 vrrp 优先级 > 本端 vrrp 优先级 或者两者优先级相同但地址不同,
则:本端 vrrp 切换为 master

返回值 True:离开 master 状态,false:保留 master 状态

bool
vrrp_state_master_rx(vrrp_t * vrrp, const vrrphdr_t *hd, const char *buf, ssize_t buflen)
{
	ssize_t ret;
#ifdef _WITH_VRRP_AUTH_
	const ipsec_ah_t *ah;
#endif
	unsigned master_adver_int;
	int addr_cmp;
	vrrp_t *gvrrp;
	element e;

// TODO - could we get here with wantstate == FAULT and STATE != FAULT?
	/* return on link failure */
// TODO - not needed???
	/* vrrp 出现故障 */
	if (vrrp->wantstate == VRRP_STATE_FAULT) {
		vrrp->master_adver_int = vrrp->adver_int;
		vrrp->ms_down_timer = 3 * vrrp->master_adver_int + VRRP_TIMER_SKEW(vrrp);
		vrrp->state = VRRP_STATE_FAULT;
		send_instance_notifies(vrrp);
		vrrp->last_transition = timer_now();
		return true;
	}

	/* 分析收到的数据包 */
	ret = vrrp_check_packet(vrrp, hd, buf, buflen, true);
	
	/* 包无效,直接返回 */
	if (ret != VRRP_PACKET_OK)
		return false;
	
	/* 比较数据包地址 与 vrrp 地址*/
	addr_cmp = vrrp_saddr_cmp(&vrrp->pkt_saddr, vrrp);
	
	/*
	若满足以下任一条件:
	1、master 收到一个 priority = 0 的通告;
	2、配置文件指定了:higher_prio_send_advert(若 master 收到一个更高优先级的 vrrp,则自身在变成 backup 之前发送一个通告)
	且 对端 vrrp 的优先级 > 本端 vrrp 的优先级,或者 两者的优先级相同但ip相同;
	则:
	发送 vrrp 通告	
	*/
	if (hd->priority == 0 ||
	    (vrrp->higher_prio_send_advert &&
	     (hd->priority > vrrp->effective_priority ||
	      (hd->priority == vrrp->effective_priority && addr_cmp > 0)))) {
		log_message(LOG_INFO, "(%s) Master received priority 0 or lower priority advert", vrrp->iname);
		vrrp_send_adv(vrrp, vrrp->effective_priority);/* 发送 vrrp 通告 */

		if (hd->priority == 0)
			return false;
	}
	
	/* 若对端与本端 vrrp 优先级均为 VRRP_PRIO_OWNER(255),则本端 vrrp 优先级-1 */
	if (hd->priority == vrrp->effective_priority) {
		if (addr_cmp == 0)
			/* 对端使用与本端相同的ip发送优先级一样的 vrrp */
			log_message(LOG_INFO, "(%s) WARNING - equal priority advert received from remote host with our IP address.", vrrp->iname);
		else if (vrrp->effective_priority == VRRP_PRIO_OWNER) {
			/* If we are configured as the address owner (priority == 255), and we receive an advertisement
			 * from another system indicating it is also the address owner, then there is a clear conflict.
			 * Report a configuration error, and drop our priority as a workaround. */
			log_message(LOG_INFO, "(%s) CONFIGURATION ERROR: local instance and a remote instance are both configured as address owner, please fix - reducing local priority", vrrp->iname);
			vrrp->effective_priority = VRRP_PRIO_OWNER - 1;
			vrrp->base_priority = VRRP_PRIO_OWNER - 1;
		}
	}
	
	/*
	若满足以下任一条件:
	1、对端 vrrp 的优先级 < 本端 vrrp 的优先级;
	2、两端优先级相同,所使用的的 ip 不同;
	则:
	1)发送 vrrp 通告(若配置项未指定 lower_prio_no_advert,即:如果收到低优先级的通告,不发送任何通告);
	2)发送 ARP 数据包,更新远端 ARP 缓冲区;
	*/
	if (hd->priority < vrrp->effective_priority ||
	    (hd->priority == vrrp->effective_priority &&
	     addr_cmp < 0)) {
		/* We receive a lower prio adv we just refresh remote ARP cache */
		log_message(LOG_INFO, "(%s) Received advert from %s with lower priority %d, ours %d%s",
					vrrp->iname,
					inet_sockaddrtos(&vrrp->pkt_saddr),
					hd->priority,
					vrrp->effective_priority,
					!vrrp->lower_prio_no_advert ? ", forcing new election" : "");
#ifdef _WITH_VRRP_AUTH_
		if (vrrp->auth_type == VRRP_AUTH_AH) {
			ah = (const ipsec_ah_t *) (buf + sizeof(struct iphdr));
			log_message(LOG_INFO, "(%s) IPSEC-AH : Syncing seq_num"
					      " - Increment seq"
					    , vrrp->iname);
// TODO - why is seq_number taken from lower priority advert?
			vrrp->ipsecah_counter.seq_number = ntohl(ah->seq_number) + 1;
			vrrp->ipsecah_counter.cycle = false;
		}
#endif
		/*
		若配置项未指定 lower_prio_no_advert(如果收到低优先级的通告,不发送任何通告),
		则发送 vrrp 通告
		*/
		if (!vrrp->lower_prio_no_advert)
			vrrp_send_adv(vrrp, vrrp->effective_priority);
		
		/*
		若指定了 garp_lower_prio_rep(当 master 接收到一个较低优先级的 vrrp 后,一次发送 gratuitous apr 的数量组),
		则发送 ARP 数据包,更新远端 ARP 缓冲区
		*/
		if (vrrp->garp_lower_prio_rep) {
			vrrp_send_link_update(vrrp, vrrp->garp_lower_prio_rep);
			if (vrrp->garp_lower_prio_delay)
				thread_add_timer(master, vrrp_lower_prio_gratuitous_arp_thread,
						 vrrp, vrrp->garp_lower_prio_delay);

			/* If we are a member of a sync group, send GARP messages
			 * for any other member of the group that has
			 * garp_lower_prio_rep set */
			if (vrrp->sync) {
				LIST_FOREACH(vrrp->sync->vrrp_instances, gvrrp, e) {
					if (gvrrp == vrrp)
						continue;
					if (!gvrrp->garp_lower_prio_rep)
						continue;

					vrrp_send_link_update(gvrrp, gvrrp->garp_lower_prio_rep);
					if (gvrrp->garp_lower_prio_delay)
						thread_add_timer(master, vrrp_lower_prio_gratuitous_arp_thread,
								 gvrrp, gvrrp->garp_lower_prio_delay);
				}
			}
		}

		/* If a lower priority router has transitioned to master, there has presumably
		 * been an intermittent communications break between the master and backup. It
		 * appears that servers in an Amazon AWS environment can experience this.
		 * The problem then occurs if a notify_master script is executed on the backup
		 * that has just transitioned to master and the script executes something like
		 * a `aws ec2 assign-private-ip-addresses` command, thereby removing the address
		 * from the 'proper' master. Executing notify_master_rx_lower_pri notification
		 * allows the 'proper' master to recover the secondary addresses. */
		send_event_notify(vrrp, VRRP_EVENT_MASTER_RX_LOWER_PRI);

		return false;
	}
	
	/*
	若对端 vrrp 优先级 > 本端 vrrp 优先级 或者两者优先级相同但地址不同,
	则:本端 vrrp 切换为 master
	*/
	if (hd->priority > vrrp->effective_priority ||
	    (hd->priority == vrrp->effective_priority && addr_cmp > 0)) {
		if (hd->priority > vrrp->effective_priority)
			log_message(LOG_INFO, "(%s) Master received advert from %s with higher priority %d, ours %d",
						vrrp->iname,
						inet_sockaddrtos(&vrrp->pkt_saddr),
						hd->priority,
						vrrp->effective_priority);
		else
			log_message(LOG_INFO, "(%s) Master received advert from %s with same priority %d but higher IP address than ours",
						vrrp->iname,
						inet_sockaddrtos(&vrrp->pkt_saddr),
						hd->priority);
#ifdef _WITH_VRRP_AUTH_
		if (vrrp->auth_type == VRRP_AUTH_AH)
			vrrp->ipsecah_counter.cycle = false;
#endif

		if (vrrp->version == VRRP_VERSION_3) {
			master_adver_int = (ntohs(hd->v3.adver_int) & 0x0FFF) * TIMER_CENTI_HZ;
			/* As per RFC5798, set Master_Adver_Interval to Adver Interval contained
			 * in the ADVERTISEMENT
			 */
			if (vrrp->master_adver_int != master_adver_int) {
				log_message(LOG_INFO, "(%s) advertisement interval updated from %u to %u milli-sec from higher priority master",
						vrrp->iname, vrrp->master_adver_int / (TIMER_HZ / 1000), master_adver_int / (TIMER_HZ / 1000));
				vrrp->master_adver_int = master_adver_int;
			}
		}
		vrrp->ms_down_timer = 3 * vrrp->master_adver_int + VRRP_TIMER_SKEW(vrrp);
		vrrp->master_priority = hd->priority;
		vrrp->wantstate = VRRP_STATE_BACK;
		vrrp->state = VRRP_STATE_BACK;
		return true;
	}

	return false;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值