keepalived源码解析 —— vrrp_send_adv()

vrrp_send_adv() 发送 vrrp 通告:
1、构造 vrrp 通告消息,存储在 vrrp->send_buffer;
2、使用 sendmsg,向 单播地址、IPV4 组播地址:224.0.0.18 或 IPV6 组播地址:ff02::12 发送 vrrp 通告。

/* send VRRP advertisement */
void
vrrp_send_adv(vrrp_t * vrrp, uint8_t prio)
{
	unicast_peer_t *peer;
	element e;

#ifdef _HAVE_VRRP_IPVLAN_
	if (__test_bit(VRRP_IPVLAN_BIT, &vrrp->vmac_flags) &&
	    vrrp->saddr.ss_family == AF_UNSPEC &&
	    vrrp->family == AF_INET6) {
		if (!vrrp->ifp->sin6_addr.s6_addr32[0] &&
		    !vrrp->ifp->sin6_addr.s6_addr32[1] &&
		    !vrrp->ifp->sin6_addr.s6_addr32[2] &&
		    !vrrp->ifp->sin6_addr.s6_addr32[3]) {
			log_message(LOG_INFO, "No address yet for %s", vrrp->ifp->ifname);
			return;
		}
		inet_ip6tosockaddr(&vrrp->ifp->sin6_addr, &vrrp->saddr);
	}
#endif

	/* 构造包,包数据存储:vrrp->send_buffer */
	vrrp_update_pkt(vrrp, prio, NULL);

	/* Send the packet, but don't log an error if it is a prio 0 message
	 * and the interface is down. */
	if (LIST_ISEMPTY(vrrp->unicast_peer)) {
		/* 向 ipv4/ipv6 组播 地址发送 vrrp 通告 */
		if (vrrp_send_pkt(vrrp, NULL) == -1 &&
		    (prio != VRRP_PRIO_STOP || errno != ENETUNREACH || IF_FLAGS_UP(vrrp->ifp)))
			log_message(LOG_INFO, "(%s): send advert error %d (%m)", vrrp->iname, errno);
	}
	else {
		LIST_FOREACH(vrrp->unicast_peer, peer, e) {
			/* 向各点播地址发送 vrrp 通告 */
			if (vrrp->family == AF_INET)
				vrrp_update_pkt(vrrp, prio, &peer->address);
			if (vrrp_send_pkt(vrrp, peer) == -1 &&
			    (prio != VRRP_PRIO_STOP || errno != ENETUNREACH || IF_FLAGS_UP(vrrp->ifp)))
				log_message(LOG_INFO, "(%s) Cant send advert to %s (%m)"
						    , vrrp->iname, inet_sockaddrtos(&peer->address));
		}
	}

	++vrrp->stats->advert_sent;
}
static ssize_t
vrrp_send_pkt(vrrp_t * vrrp, unicast_peer_t *peer)
{
	struct sockaddr_storage *src = &vrrp->saddr;
	struct msghdr msg;
	struct iovec iov;
	char cbuf[256];

	/* Build the message data */
	memset(&msg, 0, sizeof(msg));
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	iov.iov_base = vrrp->send_buffer; /* 消息的内容 */
	iov.iov_len = vrrp->send_buffer_size; /* 消息的长度 */

	/* Unicast sending path */
	if (peer && peer->address.ss_family == AF_INET) {
		msg.msg_name = &peer->address; /* 数据包的目的地址:单播地址 */
		msg.msg_namelen = sizeof(struct sockaddr_in); /* 目的地址的长度 */
	} else if (peer && peer->address.ss_family == AF_INET6) {
		msg.msg_name = &peer->address;
		msg.msg_namelen = sizeof(struct sockaddr_in6);
		vrrp_build_ancillary_data(&msg, cbuf, src, vrrp);
	} else if (vrrp->family == AF_INET) { /* Multicast sending path */
		msg.msg_name = &global_data->vrrp_mcast_group4; /* IPV4 组播地址:224.0.0.18 */
		msg.msg_namelen = sizeof(struct sockaddr_in);
	} else if (vrrp->family == AF_INET6) {
		msg.msg_name = &global_data->vrrp_mcast_group6; /* IPV6 组播地址:ff02::12 */
		msg.msg_namelen = sizeof(struct sockaddr_in6);
		vrrp_build_ancillary_data(&msg, cbuf, src, vrrp);
	}

#ifdef _CHECKSUM_DEBUG_
	if (vrrp->family == AF_INET && do_checksum_debug)
		check_tx_checksum(vrrp, peer);
#endif

	/* Send the packet */
	return sendmsg(vrrp->sockets->fd_out, &msg, (peer) ? 0 : MSG_DONTROUTE);
}
发布了69 篇原创文章 · 获赞 20 · 访问量 5万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章