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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章