コード例 #1
0
static gboolean
sync_connection_setup (NMNetlinkMonitor *self, GError **error)
{
	NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
	struct nl_cache *addr_cache;
#endif
	int err;

	/* Set up the event listener connection */
	priv->nlh_sync = nl_socket_alloc ();
	if (!priv->nlh_sync) {
		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
		             NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
		             _("unable to allocate netlink handle for monitoring link status: %s"),
		             nl_geterror (ENOMEM));
		goto error;
	}

	if (!nlh_setup (priv->nlh_sync, NULL, self, error))
		goto error;

#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
	/* Work around apparent libnl bug; rtnl_addr requires that all
	 * addresses have the "peer" attribute set in order to be compared
	 * for equality, but this attribute is not normally set. As a
	 * result, most addresses will not compare as equal even to
	 * themselves, busting caching.
	 */
	rtnl_addr_alloc_cache (priv->nlh_sync, &addr_cache);
	g_warn_if_fail (addr_cache != NULL);
	nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80;
	nl_cache_free (addr_cache);
#endif

	err = rtnl_link_alloc_cache (priv->nlh_sync, AF_UNSPEC, &priv->link_cache);
	if (err < 0) {
		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
		             NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE,
		             _("unable to allocate netlink link cache for monitoring link status: %s"),
		             nl_geterror (err));
		goto error;
	}
	nl_cache_mngt_provide (priv->link_cache);

	return TRUE;

error:
	if (priv->link_cache) {
		nl_cache_free (priv->link_cache);
		priv->link_cache = NULL;
	}

	if (priv->nlh_sync) {
		nl_socket_free (priv->nlh_sync);
		priv->nlh_sync = NULL;
	}

	return FALSE;
}
コード例 #2
0
ファイル: runner.c プロジェクト: mato/docker-unikernel-runner
/*
 * Get the first AF_INET address on 'link'. Returns 0 if successful. Caller
 * must release reference to *addr.
 */
static int get_link_inet_addr(struct nl_sock *sk, struct rtnl_link *link,
        struct nl_addr **addr)
{
    struct nl_cache *addr_cache;
    int err;
    err = rtnl_addr_alloc_cache(sk, &addr_cache);
    if (err < 0) {
        warnx("rtnl_addr_alloc_cache() failed: %s", nl_geterror(err));
        return 1;
    }

    /* Retrieve the first AF_INET address on the requested interface. */
    struct rtnl_addr *filter;
    filter = rtnl_addr_alloc();
    assert(filter);
    rtnl_addr_set_ifindex(filter, rtnl_link_get_ifindex(link));
    rtnl_addr_set_family(filter, AF_INET);

    *addr = NULL;
    nl_cache_foreach_filter(addr_cache, (struct nl_object *)filter,
            match_first_addr, addr);
    if (*addr == NULL) {
        warnx("No AF_INET address found on veth");
        
        rtnl_addr_put(filter);
        nl_cache_free(addr_cache);
        return 1;
    }

    rtnl_addr_put(filter);
    nl_cache_free(addr_cache);
    return 0;
}
コード例 #3
0
	NetLinkManager::NetLinkManager()
	 : _initialized(false), _sock(NULL), _refresh_cache(false)
	{
		ibrcommon::MutexLock l(_call_mutex);

		_handle = nl_handle_alloc();
		nl_connect(_handle, NETLINK_ROUTE);

		_link_cache = rtnl_link_alloc_cache(_handle);

		if (_link_cache == NULL)
		{
			nl_close(_handle);
			nl_handle_destroy(_handle);
			throw ibrcommon::vsocket_exception("netlink cache allocation failed");
		}

		_addr_cache = rtnl_addr_alloc_cache(_handle);

		if (_addr_cache == NULL)
		{
			nl_close(_handle);
			nl_handle_destroy(_handle);
			nl_cache_free(_link_cache);
			_link_cache = NULL;
			throw ibrcommon::vsocket_exception("netlink cache allocation failed");
		}

		_initialized = true;

		// create a new socket for the netlink interface
		_sock = new ibrcommon::vsocket();
	}
コード例 #4
0
static void
nm_ip6_manager_init (NMIP6Manager *manager)
{
	NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);

	priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal,
	                                       NULL,
	                                       (GDestroyNotify) nm_ip6_device_destroy);

	priv->monitor = nm_netlink_monitor_get ();
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_ROUTE, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);

	priv->netlink_id = g_signal_connect (priv->monitor, "notification",
	                                     G_CALLBACK (netlink_notification), manager);

	priv->nlh = nm_netlink_get_default_handle ();
	rtnl_addr_alloc_cache (priv->nlh, &priv->addr_cache);
	g_warn_if_fail (priv->addr_cache != NULL);
	rtnl_route_alloc_cache (priv->nlh, NETLINK_ROUTE, NL_AUTO_PROVIDE, &priv->route_cache);
	g_warn_if_fail (priv->route_cache != NULL);
}
コード例 #5
0
	const std::list<vaddress> NetLinkManager::getAddressList(const vinterface &interface, const vaddress::Family f)
	{
		ibrcommon::MutexLock l(_call_mutex);

		if (_refresh_cache)
		{
			nl_cache_free(_addr_cache);
			nl_cache_free(_link_cache);

			_link_cache = rtnl_link_alloc_cache(_handle);

			if (_link_cache == NULL)
			{
				throw ibrcommon::vsocket_exception("netlink cache allocation failed");
			}

			_addr_cache = rtnl_addr_alloc_cache(_handle);

			if (_addr_cache == NULL)
			{
				nl_cache_free(_link_cache);
				throw ibrcommon::vsocket_exception("netlink cache allocation failed");
			}

			// mark the cache as refreshed
			_refresh_cache = false;
		}

		std::list<vaddress> addresses;

		struct rtnl_addr *filter = rtnl_addr_alloc();
		const std::string i = interface.toString();
		rtnl_addr_set_ifindex(filter, rtnl_link_name2i(_link_cache, i.c_str()));

		if (f == vaddress::VADDRESS_UNSPEC)
		{
			rtnl_addr_set_family(filter, AF_INET6);
			nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
									add_addr_to_list, &addresses);

			rtnl_addr_set_family(filter, AF_INET);
			nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
									add_addr_to_list, &addresses);
		}
		else
		{
			rtnl_addr_set_family(filter, f);
			nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
									add_addr_to_list, &addresses);
		}

		rtnl_addr_put(filter);

		return addresses;
	}
コード例 #6
0
struct nl_cache *nltool_alloc_addr_cache(struct nl_handle *nlh)
{
	struct nl_cache *cache;

	cache = rtnl_addr_alloc_cache(nlh);
	if (!cache)
		fprintf(stderr, "Unable to retrieve address cache: %s\n",
			nl_geterror());
	else
		nl_cache_mngt_provide(cache);

	return cache;
}
コード例 #7
0
ファイル: module.c プロジェクト: ManiacTwister/dionaea
static bool nl_new(struct dionaea *d)
{
	g_debug("%s", __PRETTY_FUNCTION__);
	nl_runtime.sock = nl_socket_alloc();
	struct nl_sock  *sock = nl_runtime.sock;
	nl_socket_disable_seq_check(sock);
	nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, nl_event_input, NULL);
	nl_join_groups(sock, RTMGRP_LINK);
	int err;
	if ( (err = nl_connect(sock, NETLINK_ROUTE)) < 0) 
	{
		g_error("Could not connect netlink (%s)", nl_geterror(err));
	}

	nl_socket_add_membership(sock, RTNLGRP_LINK);
	nl_socket_add_membership(sock, RTNLGRP_NEIGH);
	nl_socket_add_membership(sock, RTNLGRP_IPV4_IFADDR);
	nl_socket_add_membership(sock, RTNLGRP_IPV6_IFADDR);

	if( (err=rtnl_neigh_alloc_cache(sock, &nl_runtime.neigh_cache)) != 0 )
	{
		g_error("Could not allocate neigh cache! (%s)", nl_geterror(err));
	}
#if LIBNL_RTNL_LINK_ALLOC_CACHE_ARGC == 3
	if( (err=rtnl_link_alloc_cache(sock, AF_UNSPEC, &nl_runtime.link_cache)) != 0 )
#elif LIBNL_RTNL_LINK_ALLOC_CACHE_ARGC == 2
	if( (err=rtnl_link_alloc_cache(sock, &nl_runtime.link_cache)) != 0 )
#endif
	{
		g_error("Could not allocate link cache! (%s)", nl_geterror(err));
	}

	if( (err=rtnl_addr_alloc_cache(sock, &nl_runtime.addr_cache)) != 0 )
	{
		g_error("Could not allocate addr cache! (%s)", nl_geterror(err));
	}

	nl_cache_mngt_provide(nl_runtime.neigh_cache);
	nl_cache_mngt_provide(nl_runtime.link_cache);
	nl_cache_mngt_provide(nl_runtime.addr_cache);
	
	nl_runtime.ihandler = ihandler_new("dionaea.connection.*.accept", nl_ihandler_cb, NULL);

	ev_io_init(&nl_runtime.io_in, nl_io_in_cb, nl_socket_get_fd(sock), EV_READ);
	ev_io_start(g_dionaea->loop, &nl_runtime.io_in);
	nl_runtime.link_addr_cache = g_hash_table_new(g_int_hash, g_int_equal);
	nl_cache_foreach(nl_runtime.link_cache, nl_obj_input, NULL);
	nl_cache_foreach(nl_runtime.addr_cache, nl_obj_input, NULL);
    return true;
}
コード例 #8
0
/**
 * nm_netlink_find_address:
 * @ifindex: interface index
 * @family: address family, either AF_INET or AF_INET6
 * @addr: binary address, either struct in_addr* or struct in6_addr*
 * @prefix: prefix length
 *
 * Searches for a matching address on the given interface.
 *
 * Returns: %TRUE if the given address was found on the interface, %FALSE if it
 * was not found or an error occurred.
 **/
gboolean
nm_netlink_find_address (int ifindex,
                         int family,
                         void *addr,  /* struct in_addr or struct in6_addr */
                         int prefix)
{
	struct nl_sock *nlh = NULL;
	struct nl_cache *cache = NULL;
	FindAddrInfo info;

	g_return_val_if_fail (ifindex > 0, FALSE);
	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
	g_return_val_if_fail (addr != NULL, FALSE);
	g_return_val_if_fail (prefix >= 0, FALSE);

	memset (&info, 0, sizeof (info));
	info.ifindex = ifindex;
	info.family = family;
	info.prefix = prefix;
	info.addr = addr;
	if (family == AF_INET)
		info.addrlen = sizeof (struct in_addr);
	else if (family == AF_INET6)
		info.addrlen = sizeof (struct in6_addr);
	else
		g_assert_not_reached ();

	nlh = nm_netlink_get_default_handle ();
	if (nlh) {
		rtnl_addr_alloc_cache(nlh, &cache);
		if (cache) {
			nl_cache_mngt_provide (cache);
			nl_cache_foreach (cache, find_one_address, &info);
			nl_cache_free (cache);
		}
	}
	return info.found;
}
コード例 #9
0
ファイル: netlink.cpp プロジェクト: dcherednik/porto
TError TNlLink::WaitAddress(int timeout_s) {
    struct nl_cache *cache;
    int ret;

    L() << "Wait for autoconf at " << GetDesc() << std::endl;

    ret = rtnl_addr_alloc_cache(GetSock(), &cache);
    if (ret < 0)
        return Nl->Error(ret, "Cannot allocate addr cache");

    do {
        for (auto obj = nl_cache_get_first(cache); obj; obj = nl_cache_get_next(obj)) {
            auto addr = (struct rtnl_addr *)obj;

            if (!rtnl_addr_get_local(addr) ||
                    rtnl_addr_get_ifindex(addr) != GetIndex() ||
                    rtnl_addr_get_family(addr) != AF_INET6 ||
                    rtnl_addr_get_scope(addr) >= RT_SCOPE_LINK ||
                    (rtnl_addr_get_flags(addr) &
                     (IFA_F_TENTATIVE | IFA_F_DEPRECATED)))
                continue;

            L() << "Got " << TNlAddr(rtnl_addr_get_local(addr)).Format()
                << " at " << GetDesc() << std::endl;

            nl_cache_free(cache);
            return TError::Success();
        }

        usleep(1000000);
        ret = nl_cache_refill(GetSock(), cache);
        if (ret < 0)
            return Nl->Error(ret, "Cannot refill address cache");
    } while (--timeout_s > 0);

    nl_cache_free(cache);
    return TError(EError::Unknown, "Network autoconf timeout");
}
コード例 #10
0
ファイル: etherinfo.c プロジェクト: Bearlock/spacewalk
/**
 * Query NETLINK for ethernet configuration
 *
 * @param ethinf Pointer to an available struct etherinfo element.  The 'device' member
 *               must contain a valid string to the device to query for information
 * @param nlc    Pointer to the libnl handle, which is used for the query against NETLINK
 * @param query  What to query for.  Must be NLQRY_LINK or NLQRY_ADDR.
 *
 * @return Returns 1 on success, otherwise 0.
 */
int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
{
	struct nl_cache *link_cache;
	struct nl_cache *addr_cache;
	struct rtnl_addr *addr;
	struct rtnl_link *link;
	struct etherinfo *ethinf = NULL;
	int ret = 0;

	if( !data || !data->ethinfo ) {
		return 0;
	}
	ethinf = data->ethinfo;

	/* Open a NETLINK connection on-the-fly */
	if( !open_netlink(data) ) {
		PyErr_Format(PyExc_RuntimeError,
			     "Could not open a NETLINK connection for %s",
			     ethinf->device);
		return 0;
	}

	/* Find the interface index we're looking up.
	 * As we don't expect it to change, we're reusing a "cached"
	 * interface index if we have that
	 */
	if( ethinf->index < 0 ) {
		link_cache = rtnl_link_alloc_cache(*data->nlc);
		ethinf->index = rtnl_link_name2i(link_cache, ethinf->device);
		if( ethinf->index < 0 ) {
			return 0;
		}
		nl_cache_free(link_cache);
	}

	/* Query the for requested info vai NETLINK */
	switch( query ) {
	case NLQRY_LINK:
		/* Extract MAC/hardware address of the interface */
		link_cache = rtnl_link_alloc_cache(*data->nlc);
		link = rtnl_link_alloc();
		rtnl_link_set_ifindex(link, ethinf->index);
		nl_cache_foreach_filter(link_cache, (struct nl_object *)link, callback_nl_link, ethinf);
		rtnl_link_put(link);
		nl_cache_free(link_cache);
		ret = 1;
		break;

	case NLQRY_ADDR:
		/* Extract IP address information */
		addr_cache = rtnl_addr_alloc_cache(*data->nlc);
		addr = rtnl_addr_alloc();
		rtnl_addr_set_ifindex(addr, ethinf->index);

                /* Make sure we don't have any old IPv6 addresses saved */
                if( ethinf->ipv6_addresses ) {
                        free_ipv6addresses(ethinf->ipv6_addresses);
                        ethinf->ipv6_addresses = NULL;
                }

                /* Retrieve all address information */
		nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, callback_nl_address, ethinf);
		rtnl_addr_put(addr);
		nl_cache_free(addr_cache);
		ret = 1;
		break;

	default:
		ret = 0;
	}
	return ret;
}
コード例 #11
0
ファイル: libnl3.c プロジェクト: exuuwen/study
int main(int argc, char *argv[])
{
	struct nl_sock *nl_sock;
	struct nl_cache *link_cache;
	int ifindex;
	int ret = 0;
	int err = 0;

	if (argc < 2)
	{
		printf("%s ip gw on/off tip\n", argv[0]);
		return -1;
	}

//link
	if (err = rtnl_route_read_table_names(ROUTE_TABLE)) {
		printf("failed to read %s. err = %s\n", ROUTE_TABLE, nl_geterror(err));
		return -1;;
	}

	nl_sock = nl_socket_alloc();
	if (NULL == nl_sock) {
		printf("failed to alloc netlink handler.\n");
		return -1;
	}

	if (err = nl_connect(nl_sock, NETLINK_ROUTE)) {
		printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err));
		ret = -1;
		goto release_nl;
	}

	if (err = rtnl_link_alloc_cache(nl_sock, AF_INET, &link_cache))
	{
		printf("failed to allocate link cache. err = %s\n", nl_geterror(err));
		ret = -1;
		goto release_nl;
	}

	ifindex = rtnl_link_name2i(link_cache, NAME);
	if (0 == ifindex) {
		printf("%s - failed to find.\n", NAME);
		ret = -1;
		goto release_link_cache;
	}

	struct rtnl_link * link = rtnl_link_get(link_cache, ifindex);
	if (link == NULL)
	{
		printf("can't get link.\n");
		ret = -1;
		goto release_link_cache;
	}
	//rtnl_link_get_by_name

	struct nl_addr *lladdr = rtnl_link_get_addr(link);
	if (NULL == lladdr || AF_LLC != nl_addr_get_family(lladdr)) {
		printf("failed to get MAC\n");
		ret = -1;
		goto release_link;
	}

	uint8_t mac_address[ETHER_ADDR_LEN];
	memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN);
	printf("%02X:%02X:%02X:%02X:%02X:%02X\n",
		 mac_address[0],
		 mac_address[1],
		 mac_address[2],
		 mac_address[3],
		 mac_address[4],
		 mac_address[5]);

//addr 
	struct nl_cache * addr_cache;
	if (err  = rtnl_addr_alloc_cache(nl_sock, &addr_cache))
	{
		printf("fail to get addr_cache\n");
		ret = -1;
		goto release_link;
	}
	struct rtnl_addr *addr = rtnl_addr_alloc();
	rtnl_addr_set_ifindex(addr, ifindex);
	rtnl_addr_set_family(addr, AF_INET);
	int prefixlen = 16;
	nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, get_ip, &prefixlen);
	nl_cache_free(addr_cache);

	uint32_t ipaddr = inet_addr(argv[1]);
	struct nl_addr * local = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr));
	rtnl_addr_set_local(addr, local);
	rtnl_addr_set_ifindex(addr, ifindex);
	rtnl_addr_set_family(addr, AF_INET);
	rtnl_addr_set_prefixlen(addr, 32);

	if (!strcmp(argv[2], "on"))
	{
		if (err = rtnl_addr_add(nl_sock, addr, 0))
		{
			printf("fail to add addr %s\n", nl_geterror(err));
			ret = -1;
			goto release_addr;
		}
	}
	else
	{
		if (err = rtnl_addr_delete(nl_sock, addr, 0))
		{
			printf("fail to del addr %s\n", nl_geterror(err));
			ret = -1;
			goto release_addr;
		}
		
	}
//neigh
	struct nl_cache * neigh_cache;
	if (err = rtnl_neigh_alloc_cache(nl_sock, &neigh_cache))
	{
		printf("failed to allocate neighbor cache. err = %s\n", nl_geterror(err));
		ret = -1;
		goto release_neigh_cache;
	}

	uint32_t gw = inet_addr(argv[3]);
	struct nl_addr * gw_addr = nl_addr_build(AF_INET, &gw, sizeof(gw));

	struct rtnl_neigh * neigh = rtnl_neigh_get(neigh_cache, ifindex, gw_addr);
	if (neigh) {
		// It's optional
		struct nl_addr * lladdr = rtnl_neigh_get_lladdr(neigh);
		if (lladdr) {
			uint8_t mac_address[ETHER_ADDR_LEN];
			memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN);
			printf("gw  %02X:%02X:%02X:%02X:%02X:%02X\n",
		 		mac_address[0],
		 		mac_address[1],
		 		mac_address[2],
		 		mac_address[3],
		 		mac_address[4],
		 		mac_address[5]);
		}
	}

	nl_addr_put(gw_addr);

//route
	struct nl_cache *route_cache;
	if (err = rtnl_route_alloc_cache(nl_sock, AF_INET, 0, &route_cache))
	{
		printf("failed to allocate route cache. err = %s\n", nl_geterror(err));
		ret = -1;
		goto release_neigh_cache;
	}

	struct rtnl_route *route = rtnl_route_alloc();
	struct nl_addr * taddr;
	err = nl_addr_parse(argv[4], AF_INET, &taddr);
        if (err)
        {
                printf("failed to get taddr. err = %s\n", nl_geterror(err));
                ret = -1;
                goto release_route_cache;
                
        }

	nl_cache_foreach_filter(route_cache, OBJ_CAST(route), get_route, NULL);
/*
	struct nl_sock *nl_fib_sock;
	nl_fib_sock = nl_socket_alloc();
	if (err = nl_connect(nl_fib_sock, NETLINK_FIB_LOOKUP)) {
		printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err));
		ret = -1;
		goto release_nl;
	}
	struct nl_dump_params params = {
		.dp_fd = stdout,
		.dp_type = NL_DUMP_DETAILS,
	};

	struct nl_cache *route_cache = flnl_result_alloc_cache();

        struct flnl_request *req = flnl_request_alloc();
        struct nl_addr * taddr;
	err = nl_addr_parse(argv[4], AF_INET, &taddr);
	if (err)
	{
		printf("failed to get taddr. err = %s\n", nl_geterror(err));
		ret = -1;
		goto release_route;
		
	}
	int table = RT_TABLE_UNSPEC, scope = RT_SCOPE_UNIVERSE;
        flnl_request_set_addr(req, taddr);
	flnl_request_set_table(req, table);
	flnl_request_set_scope(req, scope);
        err = flnl_lookup(nl_fib_sock, req, route_cache);
	if (err)
	{
		printf("failed to fib lookup. err = %s\n", nl_geterror(err));
		ret = -1;
		goto release_route_addr;
	}
	
	nl_cache_dump(route_cache, &params);

release_route_addr:
	nl_addr_put(taddr);	

release_route:
        nl_cache_free(route_cache);
	nl_object_put(OBJ_CAST(req));

	nl_close(nl_fib_sock);
	nl_socket_free(nl_fib_sock);
*/
release_route_cache:
	nl_cache_free(route_cache);
release_neigh_cache:
	nl_cache_free(neigh_cache);
release_addr:
	nl_addr_put(local);
	rtnl_addr_put(addr);
release_link:
	rtnl_link_put(link);
release_link_cache:
	nl_cache_free(link_cache);
release_nl:
	nl_close(nl_sock);
	nl_socket_free(nl_sock);

	return ret;
}
コード例 #12
0
ファイル: nl.c プロジェクト: SteveJones/j4status-plugins
static J4statusPluginContext *
_j4status_nl_init(J4statusCoreInterface *core)
{
    gchar **interfaces = NULL;
    guint64 addresses = ADDRESSES_ALL;

    GKeyFile *key_file;
    key_file = j4status_config_get_key_file("Netlink");
    if ( key_file != NULL )
    {
        interfaces = g_key_file_get_string_list(key_file, "Netlink", "Interfaces", NULL, NULL);
        j4status_config_key_file_get_enum(key_file, "Netlink", "Addresses", _j4status_nl_addresses, G_N_ELEMENTS(_j4status_nl_addresses), &addresses);

        g_key_file_free(key_file);
    }

    if ( interfaces == NULL )
    {
        g_message("No interface to monitor, aborting");
        return NULL;
    }

    gint err;
    J4statusPluginContext *self;

    self = g_new0(J4statusPluginContext, 1);
    self->addresses = addresses;

    self->sections = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, _j4status_nl_section_free);

    self->source = g_water_nl_source_new_cache_mngr(NULL, NETLINK_ROUTE, NL_AUTO_PROVIDE, &err);
    if ( self->source == NULL )
    {
        g_warning("Couldn't subscribe to events: %s", nl_geterror(err));
        goto error;
    }
    self->sock = g_water_nl_source_get_sock(self->source);
    self->cache_mngr = g_water_nl_source_get_cache_mngr(self->source);

    err = rtnl_link_alloc_cache(self->sock, AF_UNSPEC, &self->link_cache);
    if ( err < 0 )
    {
        g_warning("Couldn't allocate links cache: %s", nl_geterror(err));
        goto error;
    }

    err = nl_cache_mngr_add_cache(self->cache_mngr, self->link_cache, _j4status_nl_cache_change, self);
    if ( err < 0 )
    {
        g_warning("Couldn't manage links cache: %s", nl_geterror(err));
        goto error;
    }

    err = rtnl_addr_alloc_cache(self->sock, &self->addr_cache);
    if ( err < 0 )
    {
        g_warning("Couldn't allocate addresses cache: %s", nl_geterror(err));
        goto error;
    }

    err = nl_cache_mngr_add_cache(self->cache_mngr, self->addr_cache, _j4status_nl_cache_change, self);
    if ( err < 0 )
    {
        g_warning("Couldn't manage addresses cache: %s", nl_geterror(err));
        goto error;
    }

    gchar **interface;
    for ( interface = interfaces ; *interface != NULL ; ++interface )
    {
        J4statusNlSection *section;
        section = _j4status_nl_section_new(self, core, *interface);
        if ( section != NULL )
            g_hash_table_insert(self->sections, GINT_TO_POINTER(section->ifindex), section);
        else
            g_free(*interface);
    }

    g_free(interfaces);


    if ( g_hash_table_size(self->sections) < 1 )
        goto error;

    self->formats.up   = j4status_format_string_parse(NULL, _j4status_nl_format_up_tokens, G_N_ELEMENTS(_j4status_nl_format_up_tokens), J4STATUS_NL_DEFAULT_UP_FORMAT,   NULL);
    self->formats.down = j4status_format_string_parse(NULL, NULL,                          0,                                           J4STATUS_NL_DEFAULT_DOWN_FORMAT, NULL);


    return self;

error:
    _j4status_nl_uninit(self);
    return NULL;
}