Example #1
0
/* Return base interface from interface index incase of VMAC */
interface_t *
base_if_get_by_ifindex(const int ifindex)
{
	interface_t *ifp = if_get_by_ifindex(ifindex);

	return (ifp && ifp->vmac) ? if_get_by_ifindex(ifp->base_ifindex) : ifp;
}
Example #2
0
/* Return base interface from interface index incase of VMAC */
interface_t *
base_if_get_by_ifindex(const int ifindex)
{
	interface_t *ifp = if_get_by_ifindex(ifindex);

#ifdef _HAVE_VRRP_VMAC_
	return (ifp && ifp->vmac) ? if_get_by_ifindex(ifp->base_ifindex) : ifp;
#else
	return ifp;
#endif
}
Example #3
0
void
dump_iproute(void *rt_data)
{
	ip_route_t *route = rt_data;
	char *log_msg = MALLOC(1024);
	char *op = log_msg;

	if (route->blackhole) {
		strncat(log_msg, "blackhole ", 30);
	}
	if (route->dst)
		op += snprintf(op, log_msg + 1024 - op, "%s/%d", ipaddresstos(NULL, route->dst), route->dmask);
	if (route->gw)
		op += snprintf(op, log_msg + 1024 - op, " gw %s", ipaddresstos(NULL, route->gw));
	if (route->gw2)
		op += snprintf(op, log_msg + 1024 - op, " or gw %s", ipaddresstos(NULL, route->gw2));
	if (route->src)
		op += snprintf(op, log_msg + 1024 - op, " src %s", ipaddresstos(NULL, route->src));
	if (route->index)
		op += snprintf(op, log_msg + 1024 - op, " dev %s",
			 IF_NAME(if_get_by_ifindex(route->index)));
	if (route->table)
		op += snprintf(op, log_msg + 1024 - op, " table %d", route->table);
	if (route->scope)
		op += snprintf(op, log_msg + 1024 - op, " scope %s",
			 netlink_scope_n2a(route->scope));
	if (route->metric)
		op += snprintf(op, log_msg + 1024 - op, " metric %d", route->metric);

	log_message(LOG_INFO, "     %s", log_msg);

	FREE(log_msg);
}
Example #4
0
static void
route_print(FILE *file, void *data)
{
	ip_route_t *route = data;

	fprintf(file, "     ");

	if (route->blackhole)
		fprintf(file, "blackhole ");
	if (route->dst)
		fprintf(file, "%s/%d", ipaddresstos(NULL, route->dst), route->dmask);
	if (route->gw)
		fprintf(file, " gw %s", ipaddresstos(NULL, route->gw));
	if (route->gw2)
		fprintf(file, " or gw %s", ipaddresstos(NULL, route->gw2));
	if (route->src)
		fprintf(file, " src %s", ipaddresstos(NULL, route->src));
	if (route->index)
		fprintf(file, " dev %s", IF_NAME(if_get_by_ifindex(route->index)));
	if (route->table)
		fprintf(file, " table %d", route->table);
	if (route->scope)
		fprintf(file, " scope %s", netlink_scope_n2a(route->scope));
	if (route->metric)
		fprintf(file, " metric %d", route->metric);

	fprintf(file, "\n");
}
Example #5
0
void
dump_iproute(void *rt_data)
{
	ip_route_t *route = rt_data;
	char *log_msg = MALLOC(1024);
	char *tmp = MALLOC(INET6_ADDRSTRLEN + 30);
	char *tmp_str;

	if (route->blackhole) {
		strncat(log_msg, "blackhole ", 30);
	}
	if (route->dst) {
		tmp_str = ipaddresstos(route->dst);
		snprintf(tmp, INET6_ADDRSTRLEN + 30, "%s/%d", tmp_str, route->dmask);
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
		FREE(tmp_str);
	}
	if (route->gw) {
		tmp_str = ipaddresstos(route->gw);
		snprintf(tmp, INET6_ADDRSTRLEN + 30, " gw %s", tmp_str);
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
		FREE(tmp_str);
	}
	if (route->gw2) {
		tmp_str = ipaddresstos(route->gw2);
		snprintf(tmp, INET6_ADDRSTRLEN + 30, " or gw %s", tmp_str);
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
		FREE(tmp_str);
	}
	if (route->src) {
		tmp_str = ipaddresstos(route->src);
		snprintf(tmp, INET6_ADDRSTRLEN + 30, " src %s", tmp_str);
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
		FREE(tmp_str);
	}
	if (route->index) {
		snprintf(tmp, INET6_ADDRSTRLEN + 30, " dev %s",
			 IF_NAME(if_get_by_ifindex(route->index)));
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
	}
	if (route->table) {
		snprintf(tmp, INET6_ADDRSTRLEN + 30, " table %d", route->table);
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
	}
	if (route->scope) {
		snprintf(tmp, INET6_ADDRSTRLEN + 30, " scope %s",
			 netlink_scope_n2a(route->scope));
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
	}
	if (route->metric) {
		snprintf(tmp, INET6_ADDRSTRLEN + 30, " metric %d", route->metric);
		strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30);
	}

	log_message(LOG_INFO, "     %s", log_msg);

	FREE(tmp);
	FREE(log_msg);
}
Example #6
0
/*
 * Netlink interface address lookup filter
 * We need to handle multiple primary address and
 * multiple secondary address to the same interface.
 */
static int
netlink_if_address_filter(struct sockaddr_nl *snl, struct nlmsghdr *h)
{
	struct ifaddrmsg *ifa;
	struct rtattr *tb[IFA_MAX + 1];
	interface_t *ifp;
	int len;
	void *addr;

	ifa = NLMSG_DATA(h);

	/* Only IPV4 are valid us */
	if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6)
		return 0;

	if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
		return 0;

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg));
	if (len < 0)
		return -1;

	memset(tb, 0, sizeof (tb));
	parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);

	/* Fetch interface_t */
	ifp = if_get_by_ifindex(ifa->ifa_index);
	if (!ifp)
		return 0;
	if (tb[IFA_LOCAL] == NULL)
		tb[IFA_LOCAL] = tb[IFA_ADDRESS];
	if (tb[IFA_ADDRESS] == NULL)
		tb[IFA_ADDRESS] = tb[IFA_LOCAL];

	/* local interface address */
	addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);

	if (addr == NULL)
		return -1;

	/* If no address is set on interface then set the first time */
	if (ifa->ifa_family == AF_INET) {
		if (!ifp->sin_addr.s_addr)
			ifp->sin_addr = *(struct in_addr *) addr;
	} else {
		if (!ifp->sin6_addr.s6_addr16[0] && ifa->ifa_scope == RT_SCOPE_LINK)
			ifp->sin6_addr = *(struct in6_addr *) addr;
	}

#ifdef _WITH_LVS_
	/* Refresh checkers state */
	update_checker_activity(ifa->ifa_family, addr,
				(h->nlmsg_type == RTM_NEWADDR) ? 1 : 0);
#endif
	return 0;
}
Example #7
0
void
route_print(FILE *file, void *data)
{
	ip_route_t *route = data;
	char *msg = MALLOC(150);
	char *tmp = MALLOC(30);

	if (route->blackhole) {
		strncat(msg, "blackhole ", 30);
	}
	if (route->dst) {
		snprintf(tmp, 30, "%s/%d", ipaddresstos(route->dst),
			route->dmask);
		strncat(msg, tmp, 30);
	}
	if (route->gw) {
		snprintf(tmp, 30, " gw %s", ipaddresstos(route->gw));
		strncat(msg, tmp, 30);
	}
	if (route->gw2) {
		snprintf(tmp, 30, " or gw %s", ipaddresstos(route->gw2));
		strncat(msg, tmp, 30);
	}
	if (route->src) {
		snprintf(tmp, 30, " src %s", ipaddresstos(route->src));
		strncat(msg, tmp, 30);
	}
	if (route->index) {
		snprintf(tmp, 30, " dev %s",
		  IF_NAME(if_get_by_ifindex(route->index)));
		strncat(msg, tmp, 30);
	}
	if (route->table) {
		snprintf(tmp, 30, " table %d", route->table);
		strncat(msg, tmp, 30);
	}
	if (route->scope) {
		snprintf(tmp, 30, " scope %s",
		  netlink_scope_n2a(route->scope));
		strncat(msg, tmp, 30);
	}
	if (route->metric) {
		snprintf(tmp, 30, " metric %d", route->metric);
		strncat(msg, tmp, 30);
	}

	fprintf(file, "     %s\n", msg);

	FREE(tmp);
	FREE(msg);

}
Example #8
0
/* Netlink flag Link update */
static int
netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h)
{
	struct ifinfomsg *ifi;
	struct rtattr *tb[IFLA_MAX + 1];
	interface_t *ifp;
	int len;

	ifi = NLMSG_DATA(h);
	if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
		return 0;

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg));
	if (len < 0)
		return -1;

	/* Interface name lookup */
	memset(tb, 0, sizeof (tb));
	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
	if (tb[IFLA_IFNAME] == NULL)
		return -1;

	/* ignore loopback device */
	if (ifi->ifi_type == ARPHRD_LOOPBACK)
		return 0;

	/* find the VMAC interface (if any) */
	ifp = if_get_by_vmac_base_ifindex(ifi->ifi_index);

	/* if found, reflect base interface flags on VMAC interface */
	if (ifp)
		ifp->flags = ifi->ifi_flags;

	/* find the interface_t */
	ifp = if_get_by_ifindex(ifi->ifi_index);
	if (!ifp)
		return -1;

	/*
	 * Update flags.
	 * VMAC interfaces should never update it own flags, only be reflected
	 * by the base interface flags, see above.
	 */
	if (!ifp->vmac)
		ifp->flags = ifi->ifi_flags;

	return 0;
}
Example #9
0
int
netlink_link_del_vmac(vrrp_t *vrrp)
{
	int status = 1;

	interface_t *base_ifp ;
	struct {
		struct nlmsghdr n;
		struct ifinfomsg ifi;
		char buf[256];
	} req;

	if (!vrrp->ifp)
		return -1;

	/* Reset arp_ignore and arp_filter on the base interface if necessary */
	if (vrrp->family == AF_INET) {
		base_ifp = if_get_by_ifindex(vrrp->ifp->base_ifindex);

		if (base_ifp)
			reset_interface_parameters(base_ifp);
		else
			log_message(LOG_INFO, "Unable to find base interface for vrrp instance %s", vrrp->iname);
	}

	memset(&req, 0, sizeof (req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_DELLINK;
	req.ifi.ifi_family = AF_INET;
	req.ifi.ifi_index = vrrp->vmac_ifindex;

	if (netlink_talk(&nl_cmd, &req.n) < 0) {
		log_message(LOG_INFO, "vmac: Error removing VMAC interface %s for vrrp_instance %s!!!"
				    , vrrp->vmac_ifname, vrrp->iname);
		return -1;
	}

	log_message(LOG_INFO, "vmac: Success removing VMAC interface %s for vrrp_instance %s"
			    , vrrp->vmac_ifname, vrrp->iname);

	return status;
}
Example #10
0
/* Netlink flag Link update */
static int
netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h)
{
	struct ifinfomsg *ifi;
	struct rtattr *tb[IFLA_MAX + 1];
	interface *ifp;
	int len;

	ifi = NLMSG_DATA(h);
	if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
		return 0;

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg));
	if (len < 0)
		return -1;

	/* Interface name lookup */
	memset(tb, 0, sizeof (tb));
	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
	if (tb[IFLA_IFNAME] == NULL)
		return -1;

	/* ignore loopback device */
	if (ifi->ifi_type == ARPHRD_LOOPBACK)
		return 0;

	/* find the interface */
	ifp = if_get_by_ifindex(ifi->ifi_index);
	if (!ifp)
		return -1;

	/* Update flags */
	ifp->flags = ifi->ifi_flags;

	return 0;
}
Example #11
0
static void
dump_if(void *data)
{
	interface_t *ifp = data;
#ifdef _HAVE_VRRP_VMAC_
	interface_t *ifp_u;
#endif
	char addr_str[INET6_ADDRSTRLEN];

	log_message(LOG_INFO, "------< NIC >------");
	log_message(LOG_INFO, " Name = %s", ifp->ifname);
	log_message(LOG_INFO, " index = %d", ifp->ifindex);
	log_message(LOG_INFO, " IPv4 address = %s", inet_ntop2(ifp->sin_addr.s_addr));
	inet_ntop(AF_INET6, &ifp->sin6_addr, addr_str, sizeof(addr_str));
	log_message(LOG_INFO, " IPv6 address = %s", addr_str);

	/* FIXME: Hardcoded for ethernet */
	if (ifp->hw_type == ARPHRD_ETHER)
		log_message(LOG_INFO, " MAC = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
		       ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2]
		       , ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5]);

	if (ifp->flags & IFF_UP)
		log_message(LOG_INFO, " is UP");

	if (ifp->flags & IFF_RUNNING)
		log_message(LOG_INFO, " is RUNNING");

	if (!(ifp->flags & IFF_UP) && !(ifp->flags & IFF_RUNNING))
		log_message(LOG_INFO, " is DOWN");

	log_message(LOG_INFO, " MTU = %d", ifp->mtu);

	switch (ifp->hw_type) {
	case ARPHRD_LOOPBACK:
		log_message(LOG_INFO, " HW Type = LOOPBACK");
		break;
	case ARPHRD_ETHER:
		log_message(LOG_INFO, " HW Type = ETHERNET");
		break;
	default:
		log_message(LOG_INFO, " HW Type = UNKNOWN");
		break;
	}

#ifdef _HAVE_VRRP_VMAC_
	if (ifp->vmac && (ifp_u = if_get_by_ifindex(ifp->base_ifindex)))
		log_message(LOG_INFO, " VMAC underlying interface = %s", ifp_u->ifname);
#endif

	/* MII channel supported ? */
	if (IF_MII_SUPPORTED(ifp))
		log_message(LOG_INFO, " NIC support MII regs");
	else if (IF_ETHTOOL_SUPPORTED(ifp))
		log_message(LOG_INFO, " NIC support EHTTOOL GLINK interface");
	else
		log_message(LOG_INFO, " Enabling NIC ioctl refresh polling");

	if (ifp->garp_delay) {
		if (ifp->garp_delay->have_garp_interval)
			log_message(LOG_INFO, " Gratuitous ARP interval %ldms",
				    ifp->garp_delay->garp_interval.tv_sec * 100 +
				     ifp->garp_delay->garp_interval.tv_usec / (TIMER_HZ / 100));

		if (ifp->garp_delay->have_gna_interval)
			log_message(LOG_INFO, " Gratuitous NA interval %ldms",
				    ifp->garp_delay->gna_interval.tv_sec * 100 +
				     ifp->garp_delay->gna_interval.tv_usec / (TIMER_HZ / 100));
		if (ifp->garp_delay->aggregation_group)
			log_message(LOG_INFO, " Gratuitous ARP aggregation group %d", ifp->garp_delay->aggregation_group);
	}
}
Example #12
0
/* Netlink flag Link update */
static int
netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h)
{
	struct ifinfomsg *ifi;
	struct rtattr *tb[IFLA_MAX + 1];
	interface_t *ifp;
	int len, status;

	ifi = NLMSG_DATA(h);
	if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
		return 0;

	len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg));
	if (len < 0)
		return -1;

	/* Interface name lookup */
	memset(tb, 0, sizeof (tb));
	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
	if (tb[IFLA_IFNAME] == NULL)
		return -1;

	/* ignore loopback device */
	if (ifi->ifi_type == ARPHRD_LOOPBACK)
		return 0;

	/* find the interface_t. If the interface doesn't exist in the interface
	 * list and this is a new interface add it to the interface list.
	 * If an interface with the same name exists overwrite the older
	 * structure and fill it with the new interface information.
	 */
	ifp = if_get_by_ifindex(ifi->ifi_index);
	if (!ifp) {
		if (h->nlmsg_type == RTM_NEWLINK) {
			char *name;
			name = (char *) RTA_DATA(tb[IFLA_IFNAME]);
			ifp = if_get_by_ifname(name);
			if (!ifp) {
				ifp = (interface_t *) MALLOC(sizeof(interface_t));
				if_add_queue(ifp);
			} else {
				memset(ifp, 0, sizeof(interface_t));
			}
			status = netlink_if_link_populate(ifp, tb, ifi);
			if (status < 0)
				return -1;
		} else {
			if (__test_bit(LOG_DETAIL_BIT, &debug))
				log_message(LOG_INFO, "Unknown interface %s deleted", (char *)tb[IFLA_IFNAME]);
			return 0;
		}
	}

	/*
	 * Update flags.
	 * VMAC interfaces should never update it own flags, only be reflected
	 * by the base interface flags.
	 */
#ifdef _HAVE_VRRP_VMAC_
	if (!ifp->vmac)
#endif
	{
#ifdef _HAVE_VRRP_VMAC_
		if_vmac_reflect_flags(ifi->ifi_index, ifi->ifi_flags);
#endif
		ifp->flags = ifi->ifi_flags;
	}

	return 0;
}
Example #13
0
/* Our netlink parser */
static int
netlink_parse_info(int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
		   nl_handle_t *nl, struct nlmsghdr *n)
{
	int status;
	int ret = 0;
	int error;

	while (1) {
		char buf[4096];
		struct iovec iov = {
			.iov_base = buf,
			.iov_len = sizeof buf
		};
		struct sockaddr_nl snl;
		struct msghdr msg = {
			.msg_name = &snl,
			.msg_namelen = sizeof(snl),
			.msg_iov = &iov,
			.msg_iovlen = 1,
			.msg_control = NULL,
			.msg_controllen = 0,
			.msg_flags = 0
		};
		struct nlmsghdr *h;

		status = recvmsg(nl->fd, &msg, 0);

		if (status < 0) {
			if (errno == EINTR)
				continue;
			if (errno == EWOULDBLOCK || errno == EAGAIN)
				break;
			log_message(LOG_INFO, "Netlink: Received message overrun (%m)");
			continue;
		}

		if (status == 0) {
			log_message(LOG_INFO, "Netlink: EOF");
			return -1;
		}

		if (msg.msg_namelen != sizeof snl) {
			log_message(LOG_INFO,
			       "Netlink: Sender address length error: length %d",
			       msg.msg_namelen);
			return -1;
		}

		for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, status);
		     h = NLMSG_NEXT(h, status)) {
			/* Finish of reading. */
			if (h->nlmsg_type == NLMSG_DONE)
				return ret;

			/* Error handling. */
			if (h->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA(h);

				/*
				 * If error == 0 then this is a netlink ACK.
				 * return if not related to multipart message.
				 */
				if (err->error == 0) {
					if (!(h->nlmsg_flags & NLM_F_MULTI))
						return 0;
					continue;
				}

				if (h->nlmsg_len < NLMSG_LENGTH(sizeof (struct nlmsgerr))) {
					log_message(LOG_INFO,
					       "Netlink: error: message truncated");
					return -1;
				}

				if (n && (err->error == -EEXIST) &&
				    ((n->nlmsg_type == RTM_NEWROUTE) ||
				     (n->nlmsg_type == RTM_NEWADDR)))
					return 0;

				/* If have more than one IPv4 address in the same CIDR
				 * and the "primary" address is removed, unless promote_secondaries
				 * is configured on the interface, all the "secondary" addresses
				 * in the same CIDR are deleted */
				if (n && err->error == -EADDRNOTAVAIL &&
				    n->nlmsg_type == RTM_DELADDR) {
					netlink_if_address_filter(NULL, n);
					if (!(h->nlmsg_flags & NLM_F_MULTI))
						return 0;
					continue;
				}
				if (netlink_error_ignore != -err->error)
					log_message(LOG_INFO,
					       "Netlink: error: %s, type=(%u), seq=%u, pid=%d",
					       strerror(-err->error),
					       err->msg.nlmsg_type,
					       err->msg.nlmsg_seq, err->msg.nlmsg_pid);

				return -1;
			}

			/* Skip unsolicited messages from cmd channel */
			if (nl != &nl_cmd && h->nlmsg_pid == nl_cmd.nl_pid)
				continue;

			error = (*filter) (&snl, h);
			if (error < 0) {
				log_message(LOG_INFO, "Netlink: filter function error");
				ret = error;
			}
		}

		/* After error care. */
		if (msg.msg_flags & MSG_TRUNC) {
			log_message(LOG_INFO, "Netlink: error: message truncated");
			continue;
		}
		if (status) {
			log_message(LOG_INFO, "Netlink: error: data remnant size %d",
			       status);
			return -1;
		}
	}

	return ret;
}

/* Out talk filter */
static int
netlink_talk_filter(struct sockaddr_nl *snl, struct nlmsghdr *h)
{
	log_message(LOG_INFO, "Netlink: ignoring message type 0x%04x",
	       h->nlmsg_type);
	return 0;
}

/* send message to netlink kernel socket, then receive response */
int
netlink_talk(nl_handle_t *nl, struct nlmsghdr *n)
{
	int status;
	int ret, flags;
	struct sockaddr_nl snl;
	struct iovec iov = {
		.iov_base = n,
		.iov_len = n->nlmsg_len
	};
	struct msghdr msg = {
		.msg_name = &snl,
		.msg_namelen = sizeof(snl),
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = NULL,
		.msg_controllen = 0,
		.msg_flags = 0
	};

	memset(&snl, 0, sizeof snl);
	snl.nl_family = AF_NETLINK;

	n->nlmsg_seq = ++nl->seq;

	/* Request Netlink acknowledgement */
	n->nlmsg_flags |= NLM_F_ACK;

	/* Send message to netlink interface. */
	status = sendmsg(nl->fd, &msg, 0);
	if (status < 0) {
		log_message(LOG_INFO, "Netlink: sendmsg() error: %s",
		       strerror(errno));
		return -1;
	}

	/* Set blocking flag */
	ret = netlink_set_block(nl, &flags);
	if (ret < 0)
		log_message(LOG_INFO, "Netlink: Warning, couldn't set "
		       "blocking flag to netlink socket...");

	status = netlink_parse_info(netlink_talk_filter, nl, n);

	/* Restore previous flags */
	if (ret == 0)
		netlink_set_nonblock(nl, &flags);
	return status;
}

/* Fetch a specific type information from netlink kernel */
static int
netlink_request(nl_handle_t *nl, int family, int type)
{
	int status;
	struct sockaddr_nl snl;
	struct {
		struct nlmsghdr nlh;
		struct rtgenmsg g;
	} req;

	/* Cleanup the room */
	memset(&snl, 0, sizeof (snl));
	snl.nl_family = AF_NETLINK;

	req.nlh.nlmsg_len = sizeof (req);
	req.nlh.nlmsg_type = type;
	req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
	req.nlh.nlmsg_pid = 0;
	req.nlh.nlmsg_seq = ++nl->seq;
	req.g.rtgen_family = family;

	status = sendto(nl->fd, (void *) &req, sizeof (req)
			, 0, (struct sockaddr *) &snl, sizeof (snl));
	if (status < 0) {
		log_message(LOG_INFO, "Netlink: sendto() failed: %s",
		       strerror(errno));
		return -1;
	}
	return 0;
}

static int
netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg *ifi)
{
	char *name;
	int i;
#ifdef _HAVE_VRRP_VMAC_
	struct rtattr* linkinfo[IFLA_INFO_MAX+1];
	struct rtattr* linkattr[IFLA_MACVLAN_MAX+1];
	interface_t *ifp_base;
#endif

	name = (char *) RTA_DATA(tb[IFLA_IFNAME]);
	/* Fill the interface structure */
	memcpy(ifp->ifname, name, strlen(name));
	ifp->ifindex = ifi->ifi_index;
	ifp->mtu = *(int *) RTA_DATA(tb[IFLA_MTU]);
	ifp->hw_type = ifi->ifi_type;

	if (tb[IFLA_ADDRESS]) {
		int hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);

		if (hw_addr_len > IF_HWADDR_MAX) {
			log_message(LOG_ERR, "MAC address for %s is too large: %d",
				name, hw_addr_len);
			return -1;
		}
		else {
			ifp->hw_addr_len = hw_addr_len;
			memcpy(ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]),
				hw_addr_len);
			for (i = 0; i < hw_addr_len; i++)
				if (ifp->hw_addr[i] != 0)
					break;
			if (i == hw_addr_len)
				ifp->hw_addr_len = 0;
			else
				ifp->hw_addr_len = hw_addr_len;
		}
	}

#ifdef _HAVE_VRRP_VMAC_
	/* See if this interface is a MACVLAN of ours */
	if (tb[IFLA_LINKINFO] && tb[IFLA_LINK]){
		/* If appears that the value of *(int*)RTA_DATA(tb[IFLA_LINKINFO]) is 0x1000c
		 *   for macvlan.  0x10000 for nested data, or'ed with 0x0c for macvlan;
		 *   other values are 0x09 for vlan, 0x0b for bridge, 0x08 for tun, -1 for no
		 *   underlying interface.
		 *
		 * I can't find where in the kernel these values are set or defined, so use
		 * the string as below.
		 */
		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);

		if (linkinfo[IFLA_INFO_KIND] &&
		    RTA_PAYLOAD(linkinfo[IFLA_INFO_KIND]) >= strlen(macvlan_ll_kind) &&
		    !strncmp(macvlan_ll_kind, RTA_DATA(linkinfo[IFLA_INFO_KIND]), strlen(macvlan_ll_kind)) &&
		    linkinfo[IFLA_INFO_DATA]) {
			parse_rtattr_nested(linkattr, IFLA_MACVLAN_MAX, linkinfo[IFLA_INFO_DATA]);

			if (linkattr[IFLA_MACVLAN_MODE] &&
			    *(int*)RTA_DATA(linkattr[IFLA_MACVLAN_MODE]) == MACVLAN_MODE_PRIVATE) {
				ifp->base_ifindex = *(int*)RTA_DATA(tb[IFLA_LINK]);
				ifp->vmac = true;
			}
		}
	}

	if (!ifp->vmac)
#endif
	{
#ifdef _HAVE_VRRP_VMAC_
		if_vmac_reflect_flags(ifi->ifi_index, ifi->ifi_flags);
#endif
		ifp->flags = ifi->ifi_flags;
#ifdef _HAVE_VRRP_VMAC_
log_message(LOG_INFO, "Setting base index for %s to ifi_index %d", name, ifi->ifi_index);
		ifp->base_ifindex = ifi->ifi_index;
#endif
	}
#ifdef _HAVE_VRRP_VMAC_
	else {
		if ((ifp_base = if_get_by_ifindex(ifp->base_ifindex)))
			ifp->flags = ifp_base->flags;
	}
#endif

	return 1;
}