Example #1
0
/* Interface lookup by netlink socket. */
int
interface_lookup_netlink (void)
{
  int ret;

  /* Get interface information. */
  ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
  if (ret < 0)
    return ret;
  ret = netlink_parse_info (netlink_interface, &netlink_cmd);
  if (ret < 0)
    return ret;

  /* Get IPv4 address of the interfaces. */
  ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
  if (ret < 0)
    return ret;
  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
  if (ret < 0)
    return ret;

#ifdef HAVE_IPV6
  /* Get IPv6 address of the interfaces. */
  ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
  if (ret < 0)
    return ret;
  ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
  if (ret < 0)
    return ret;
#endif /* HAVE_IPV6 */

  return 0;
}
Example #2
0
/* Adresses lookup bootstrap function */
static int
netlink_address_lookup(void)
{
	nl_handle_t nlh;
	int status = 0;

	if (netlink_socket(&nlh, 0, 0) < 0)
		return -1;

	/* IPv4 Address lookup */
	if (netlink_request(&nlh, AF_INET, RTM_GETADDR) < 0) {
		status = -1;
		goto end_addr;
	}
	status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL);

	/* IPv6 Address lookup */
	if (netlink_request(&nlh, AF_INET6, RTM_GETADDR) < 0) {
		status = -1;
		goto end_addr;
	}
	status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL);

end_addr:
	netlink_close(&nlh);
	return status;
}
Example #3
0
/* Adresses lookup bootstrap function */
static int
netlink_address_lookup(void)
{
	nl_handle_t nlh;
	int status = 0;
	int ret, flags;

	if (netlink_socket(&nlh, 0) < 0)
		return -1;

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

	/* IPv4 Address lookup */
	if (netlink_request(&nlh, AF_INET, RTM_GETADDR) < 0) {
		status = -1;
		goto end_addr;
	}
	status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL);

	/* IPv6 Address lookup */
	if (netlink_request(&nlh, AF_INET6, RTM_GETADDR) < 0) {
		status = -1;
		goto end_addr;
	}
	status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL);

end_addr:
	netlink_close(&nlh);
	return status;
}
Example #4
0
/* Routing table read function using netlink interface.  Only called
   bootstrap time. */
int
netlink_route_read ()
{
    int ret;

    /* Get IPv4 routing table. */
    ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
    if (ret < 0)
        return ret;
    ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
    if (ret < 0)
        return ret;

#ifdef HAVE_IPV6
    /* Get IPv6 routing table. */
    ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
    if (ret < 0)
        return ret;
    ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
    if (ret < 0)
        return ret;
#endif /* HAVE_IPV6 */

    return 0;
}
Example #5
0
/* Interface lookup by netlink socket. */
int interface_lookup_netlink(struct zebra_ns *zns)
{
	int ret;

	/* Get interface information. */
	ret = netlink_request_intf_addr(zns, AF_PACKET, RTM_GETLINK, 0);
	if (ret < 0)
		return ret;
	ret = netlink_parse_info(netlink_interface, &zns->netlink_cmd, zns, 0,
				 1);
	if (ret < 0)
		return ret;

	/* Get interface information - for bridge interfaces. */
	ret = netlink_request_intf_addr(zns, AF_BRIDGE, RTM_GETLINK,
					RTEXT_FILTER_BRVLAN);
	if (ret < 0)
		return ret;
	ret = netlink_parse_info(netlink_interface, &zns->netlink_cmd, zns, 0,
				 0);
	if (ret < 0)
		return ret;

	/* Get interface information - for bridge interfaces. */
	ret = netlink_request_intf_addr(zns, AF_BRIDGE, RTM_GETLINK,
					RTEXT_FILTER_BRVLAN);
	if (ret < 0)
		return ret;
	ret = netlink_parse_info(netlink_interface, &zns->netlink_cmd, zns, 0,
				 0);
	if (ret < 0)
		return ret;

	/* Get IPv4 address of the interfaces. */
	ret = netlink_request_intf_addr(zns, AF_INET, RTM_GETADDR, 0);
	if (ret < 0)
		return ret;
	ret = netlink_parse_info(netlink_interface_addr, &zns->netlink_cmd, zns,
				 0, 1);
	if (ret < 0)
		return ret;

	/* Get IPv6 address of the interfaces. */
	ret = netlink_request_intf_addr(zns, AF_INET6, RTM_GETADDR, 0);
	if (ret < 0)
		return ret;
	ret = netlink_parse_info(netlink_interface_addr, &zns->netlink_cmd, zns,
				 0, 1);
	if (ret < 0)
		return ret;

	return 0;
}
Example #6
0
/* Interfaces lookup bootstrap function */
int
netlink_interface_lookup(void)
{
	nl_handle_t nlh;
	int status = 0;
	int ret, flags;

	if (netlink_socket(&nlh, 0) < 0)
		return -1;

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

	/* Interface lookup */
	if (netlink_request(&nlh, AF_PACKET, RTM_GETLINK) < 0) {
		status = -1;
		goto end_int;
	}
	status = netlink_parse_info(netlink_if_link_filter, &nlh, NULL);

end_int:
	netlink_close(&nlh);
	return status;
}
Example #7
0
/* sendmsg() to netlink socket then recvmsg(). */
int
netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
{
    int status;
    struct sockaddr_nl snl;
    struct iovec iov = { (void*) n, n->nlmsg_len };
    struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0};

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

    n->nlmsg_seq = ++netlink_cmd.seq;

    if (IS_ZEBRA_DEBUG_KERNEL)
        zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
                   lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
                   n->nlmsg_seq);

    /* Send message to netlink interface. */
    status = sendmsg (nl->sock, &msg, 0);
    if (status < 0)
    {
        zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
              strerror (errno));
        return -1;
    }

    status = netlink_parse_info (netlink_talk_filter, nl);
    return status;
}
Example #8
0
/* Kernel route reflection. */
static int
kernel_read (struct thread *thread)
{
  netlink_parse_info (netlink_information_fetch, &netlink);
  thread_add_read (hm->master, kernel_read, NULL, netlink.sock);

  return 0;
}
Example #9
0
int
kernel_netlink(thread_t * thread)
{
	if (thread->type != THREAD_READ_TIMEOUT)
		netlink_parse_info(netlink_broadcast_filter, &nl_kernel, NULL);
	thread_add_read(master, kernel_netlink, NULL, nl_kernel.fd,
			NETLINK_TIMER);
	return 0;
}
Example #10
0
static int
kernel_netlink(thread_t * thread)
{
	nl_handle_t *nl = THREAD_ARG(thread);

	if (thread->type != THREAD_READ_TIMEOUT)
		netlink_parse_info(netlink_broadcast_filter, nl, NULL);
	nl->thread = thread_add_read(master, kernel_netlink, nl, nl->fd,
				      NETLINK_TIMER);
	return 0;
}
Example #11
0
/* Kernel route reflection. */
int
kernel_read (struct thread *thread)
{
    int ret;
    int sock;

    sock = THREAD_FD (thread);
    ret = netlink_parse_info (netlink_information_fetch, &netlink);
    thread_add_read (master, kernel_read, NULL, netlink.sock);

    return 0;
}
Example #12
0
/* Interfaces lookup bootstrap function */
int
netlink_interface_lookup(void)
{
	nl_handle_t nlh;
	int status = 0;

	if (netlink_socket(&nlh, 0, 0) < 0)
		return -1;

	/* Interface lookup */
	if (netlink_request(&nlh, AF_PACKET, RTM_GETLINK) < 0) {
		status = -1;
		goto end_int;
	}
	status = netlink_parse_info(netlink_if_link_filter, &nlh, NULL);

end_int:
	netlink_close(&nlh);
	return status;
}
Example #13
0
/* sendmsg() to netlink socket then recvmsg(). */
static int
netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
{
  int status;
  struct sockaddr_nl snl;
  struct iovec iov = { (void *) n, n->nlmsg_len };
  struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
  int save_errno;

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

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

  /* Request an acknowledgement by setting NLM_F_ACK */
  n->nlmsg_flags |= NLM_F_ACK;

  if (IS_DEBUG_HA(kroute, KROUTE))
    zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
               lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
               n->nlmsg_seq);

  /* Send message to netlink interface. */
  status = sendmsg (nl->sock, &msg, 0);
  save_errno = errno;

  if (status < 0)
    {
      zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
            safe_strerror (save_errno));
      return -1;
    }


  /* 
   * Get reply from netlink socket. 
   * The reply should either be an acknowlegement or an error.
   */
  return netlink_parse_info (netlink_talk_filter, nl);
}
Example #14
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 = { (void *) n, n->nlmsg_len };
	struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 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;
}
Example #15
0
/* sendmsg() to netlink socket then recvmsg(). */
int
netlink_talk (struct nlmsghdr *n, struct nlsock *nl, void *a, unsigned int size)
{
  int status;
  struct sockaddr_nl snl;
  struct iovec iov = { (void *) n, n->nlmsg_len };
  struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
  int flags = 0;
  int snb_ret;
  int save_errno;

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

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

  /* Request an acknowledgement by setting NLM_F_ACK */
  if (!a)
    n->nlmsg_flags |= NLM_F_ACK;

  if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
               lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
               n->nlmsg_seq);

  /* Send message to netlink interface. */
  if (zserv_privs.change (ZPRIVS_RAISE))
    zlog (NULL, LOG_ERR, "Can't raise privileges");
  status = sendmsg (nl->sock, &msg, 0);
  save_errno = errno;
  if (zserv_privs.change (ZPRIVS_LOWER))
    zlog (NULL, LOG_ERR, "Can't lower privileges");

  if (status < 0)
    {
      zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
            safe_strerror (save_errno));
      return -1;
    }

  if (!a)
    {
      /* 
       * Change socket flags for blocking I/O. 
       * This ensures we wait for a reply in netlink_parse_info().
       */
      snb_ret = set_netlink_blocking (nl, &flags);
      if (snb_ret < 0)
        zlog (NULL, LOG_WARNING,
              "%s:%i Warning: Could not set netlink socket to blocking.",
              __FUNCTION__, __LINE__);
    }

  /* 
   * Get reply from netlink socket. 
   * The reply should either be an acknowlegement or an error.
   */
  status = netlink_parse_info (netlink_talk_filter, nl, a, size);

  /* Restore socket flags for nonblocking I/O */
  if (snb_ret == 0 && !a)
    set_netlink_nonblocking (nl, &flags);

  return status;
}
Example #16
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;
}
Example #17
0
/* sendmsg() to netlink socket then recvmsg(). */
int
netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
{
  int status;
  struct sockaddr_nl snl;
  struct iovec iov = { (void*) n, n->nlmsg_len };
  struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0};
  int flags = 0;
  
  memset (&snl, 0, sizeof snl);
  snl.nl_family = AF_NETLINK;
  
  n->nlmsg_seq = ++netlink_cmd.seq;

  /* Request an acknowledgement by setting NLM_F_ACK */
  n->nlmsg_flags |= NLM_F_ACK;
  
  if (IS_ZEBRA_DEBUG_KERNEL) 
    zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
	      lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
	      n->nlmsg_seq);

  /* Send message to netlink interface. */
  status = sendmsg (nl->sock, &msg, 0);
  if (status < 0)
    {
      zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
	    strerror (errno));
      return -1;
    }
  
  /* 
   * Change socket flags for blocking I/O. 
   * This ensures we wait for a reply in netlink_parse_info().
   */
  if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0) 
    {
      zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", 
              __FUNCTION__, __LINE__, strerror (errno));
    }
  flags &= ~O_NONBLOCK;
  if(fcntl(nl->sock, F_SETFL, flags) < 0) 
    {
      zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", 
              __FUNCTION__, __LINE__, strerror (errno));
    }

  /* 
   * Get reply from netlink socket. 
   * The reply should either be an acknowlegement or an error.
   */
  status = netlink_parse_info (netlink_talk_filter, nl);
  
  /* Restore socket flags for nonblocking I/O */
  flags |= O_NONBLOCK;
  if(fcntl(nl->sock, F_SETFL, flags) < 0) 
    {
      zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", 
              __FUNCTION__, __LINE__, strerror (errno));
    }
  
  return status;
}