public inbox for b.a.t.m.a.n@lists.open-mesh.org
 help / color / mirror / Atom feed
From: Matthias Schiffer <mschiffer@universe-factory.net>
To: b.a.t.m.a.n@lists.open-mesh.org
Subject: Re: [B.A.T.M.A.N.] [RFC v2 0/5] batman-adv netlink query API
Date: Thu, 17 Mar 2016 18:04:56 +0100	[thread overview]
Message-ID: <56EAE3B8.3050808@universe-factory.net> (raw)
In-Reply-To: <cover.1458231707.git.mschiffer@universe-factory.net>


[-- Attachment #1.1.1: Type: text/plain, Size: 1947 bytes --]

On 03/17/2016 05:45 PM, Matthias Schiffer wrote:
> Hi,
> this is the second take of my netlink API patches. As mentioned before, the
> netlink API is superior to the current debugfs API in many aspects:
> 
> * debugfs is broken (see PATCH 1 for details)
> * Netlink is namespace-aware, and can be used in unprivileged containers
>   without problems
> * Netlink packets are more machine-readable than text files, and can be
>   easily extended without potentially breaking userspace
> * On older kernels, seq_file can't fall back to vmalloc if kmalloc fails,
>   which often leads to OOM when reading "originators" in large meshes, as
>   the whole file must fit into a single buffer
> 
> Of course, are also a few downsides; when the data is too big to fit into
> a single netlink packet, the provided data may be inconsistent (entries may
> be missing or duplicated.) This will happen in large meshes only, and be
> improbable in any case.
> 
> The patches have been developed on top of the netns patchset, but should
> be applicable independently (maybe with minor changes.)
> 
> All netlink queries returning lists of any kind can only be used with
> NLM_F_DUMP queries, so that arbitrarity large responses are possible (split
> across multiple packets if necessary.)
> 
> At the moment, the following debugfs files have corresponding netlink APIs:
> 
> * routing_algos
> * neighbors
> * originators
> * transtable_global
> * transtable_local
> * (hardinterfaces for a softif can be queried)
> 
> The following files are still missing:
> 
> * gateways
> * bla_claim_table
> * bla_backbone_table
> * dat_cache
> * nc_nodes
> 
> Obviously, documentation is also a TODO. Comments about the API design are
> very welcome...
> 
> Regards,
> Matthias
> 
> 

And here is the new version of the PoC userspace tool.
Build with:

gcc -o batnl batnl.c $$(pkg-config --cflags --libs libnl-1) -Wall


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.2: batnl.c --]
[-- Type: text/x-csrc; name="batnl.c", Size: 16521 bytes --]

#include <stdio.h>
#include <string.h>

#include <net/if.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "batman_adv.h"


static void usage()
{
	fprintf(stderr, "Usage:\n\n");
	fprintf(stderr, "  batnl routing_algos\n");
	fprintf(stderr, "  batnl info <mesh>\n");
	fprintf(stderr, "  batnl interface <mesh>\n");
	fprintf(stderr, "  batnl translocal <mesh>\n");
	fprintf(stderr, "  batnl transglobal <mesh>\n");
	fprintf(stderr, "  batnl neighbors <mesh> [<hardif>]\n");
	fprintf(stderr, "  batnl originators <mesh> [<hardif>]\n");
	exit(2);
}

static int print_error(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
{
	fprintf(stderr, "Error received: %s\n", strerror(-nlerr->error));
	exit(1);
}

static int stop_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	int *error = nlmsg_data(nlh);

	if (*error)
		fprintf(stderr, "Error received: %s\n", strerror(-*error));

	return NL_STOP;
}

static int routing_algos_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_ROUTING_ALGOS)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	const char *algo_name = nla_get_string(attrs[BATADV_ATTR_ALGO_NAME]);

	printf(" * %s\n", algo_name);

	return NL_OK;
}

static void routing_algos(struct nl_handle *sock, int family)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_ROUTING_ALGOS, 1);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, routing_algos_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int info_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_MESH_INFO)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	const char *mesh_name = nla_get_string(attrs[BATADV_ATTR_MESH_IFNAME]);

	if (attrs[BATADV_ATTR_HARD_IFNAME]) {
		const char *version = nla_get_string(attrs[BATADV_ATTR_VERSION]);
		const char *algo_name = nla_get_string(attrs[BATADV_ATTR_ALGO_NAME]);
		const char *primary_if = nla_get_string(attrs[BATADV_ATTR_HARD_IFNAME]);
		const uint8_t *primary_mac = nla_data(attrs[BATADV_ATTR_HARD_ADDRESS]);

		printf("[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%02x:%02x:%02x:%02x:%02x:%02x (%s %s)]\n",
		       version, primary_if,
		       primary_mac[0], primary_mac[1], primary_mac[2],
		       primary_mac[3], primary_mac[4], primary_mac[5],
		       mesh_name, algo_name);

	}
	else {
		printf("BATMAN mesh %s disabled\n", mesh_name);
	}

	return NL_STOP;
}

static void info(struct nl_handle *sock, int family, int ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, 0, BATADV_CMD_GET_MESH_INFO, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, info_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int interface_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_HARDIFS)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	const char *ifname = nla_get_string(attrs[BATADV_ATTR_HARD_IFNAME]);

	printf("%s: %sactive\n", ifname, attrs[BATADV_ATTR_ACTIVE] ? "" : "in");

	return NL_OK;
}

static void interface(struct nl_handle *sock, int family, int ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_HARDIFS, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, interface_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int translocal_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_TRANSTABLE_LOCAL)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	uint8_t *addr = nla_data(attrs[BATADV_ATTR_TT_ADDRESS]);
	int16_t vid = nla_get_u16(attrs[BATADV_ATTR_TT_VID]);
	uint32_t crc32 = nla_get_u32(attrs[BATADV_ATTR_TT_CRC32]);
	uint32_t flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]);
	int last_seen_msecs = 0, last_seen_secs = 0;

	char r = '.', p = '.', n = '.', x = '.', w = '.', i = '.';
	if (flags & BATADV_TT_CLIENT_ROAM)
		r = 'R';
	if (flags & BATADV_TT_CLIENT_NEW)
		n = 'N';
	if (flags & BATADV_TT_CLIENT_PENDING)
		x = 'X';
	if (flags & BATADV_TT_CLIENT_WIFI)
		w = 'W';
	if (flags & BATADV_TT_CLIENT_ISOLA)
		i = 'I';

	if (flags & BATADV_TT_CLIENT_NOPURGE)  {
		p = 'P';
	}
	else {
		last_seen_msecs = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]);
		last_seen_secs = last_seen_msecs / 1000;
		last_seen_msecs = last_seen_msecs % 1000;
	}


	printf(" * %02x:%02x:%02x:%02x:%02x:%02x %4i [%c%c%c%c%c%c] %3u.%03u   (0x%.8x)\n",
	       addr[0], addr[1], addr[2],
	       addr[3], addr[4], addr[5],
	       vid, r, p, n, x, w, i,
	       last_seen_secs, last_seen_msecs,
	       crc32);

	return NL_OK;
}

static void translocal(struct nl_handle *sock, int family, int ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_TRANSTABLE_LOCAL, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, translocal_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int transglobal_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_TRANSTABLE_GLOBAL)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	uint8_t *addr = nla_data(attrs[BATADV_ATTR_TT_ADDRESS]);
	uint8_t *orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]);
	int16_t vid = nla_get_u16(attrs[BATADV_ATTR_TT_VID]);
	uint8_t ttvn = nla_get_u8(attrs[BATADV_ATTR_TT_TTVN]);
	uint8_t last_ttvn = nla_get_u8(attrs[BATADV_ATTR_TT_LAST_TTVN]);
	uint32_t crc32 = nla_get_u32(attrs[BATADV_ATTR_TT_CRC32]);
	uint32_t flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]);

	char c = '+', r = '.', w = '.', i = '.', t = '.';
	if (attrs[BATADV_ATTR_FLAG_BEST])
		c = '*';
	if (flags & BATADV_TT_CLIENT_ROAM)
		r = 'R';
	if (flags & BATADV_TT_CLIENT_WIFI)
		w = 'W';
	if (flags & BATADV_TT_CLIENT_ISOLA)
		i = 'I';
	if (flags & BATADV_TT_CLIENT_TEMP)
		t = 'T';


	printf(" %c %02x:%02x:%02x:%02x:%02x:%02x %4i   (%3u) via %02x:%02x:%02x:%02x:%02x:%02x     (%3u)   (0x%.8x) [%c%c%c%c]\n",
	       c,
	       addr[0], addr[1], addr[2],
	       addr[3], addr[4], addr[5],
	       vid, ttvn,
	       orig[0], orig[1], orig[2],
	       orig[3], orig[4], orig[5],
	       last_ttvn, crc32, r, w, i, t);

	return NL_OK;
}

static void transglobal(struct nl_handle *sock, int family, int ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_TRANSTABLE_GLOBAL, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, transglobal_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int originators_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	uint8_t *orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]);
	uint8_t *neigh = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]);

	char ifname[IF_NAMESIZE];
	if (!if_indextoname(nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]), ifname))
		ifname[0] = '\0';

	char c = '+';
	if (attrs[BATADV_ATTR_FLAG_BEST])
		c = '*';

	int last_seen_msecs, last_seen_secs;
	last_seen_msecs = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]);
	last_seen_secs = last_seen_msecs / 1000;
	last_seen_msecs = last_seen_msecs % 1000;

	if (attrs[BATADV_ATTR_THROUGHPUT]) {
		unsigned throughput_mbits, throughput_kbits;
		throughput_kbits = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]);
		throughput_mbits = throughput_kbits / 1000;
		throughput_kbits = throughput_kbits % 1000;

		printf(" %c %02x:%02x:%02x:%02x:%02x:%02x %4i.%03is (%9u.%1u) %02x:%02x:%02x:%02x:%02x:%02x [%10s]\n",
		       c,
		       orig[0], orig[1], orig[2],
		       orig[3], orig[4], orig[5],
		       last_seen_secs, last_seen_msecs,
		       throughput_mbits, throughput_kbits / 100,
		       neigh[0], neigh[1], neigh[2],
		       neigh[3], neigh[4], neigh[5],
		       ifname);
	}
	else {
		uint8_t tq = nla_get_u8(attrs[BATADV_ATTR_TQ]);

		printf(" %c %02x:%02x:%02x:%02x:%02x:%02x %4i.%03is   (%3i) %02x:%02x:%02x:%02x:%02x:%02x [%10s]\n",
		       c,
		       orig[0], orig[1], orig[2],
		       orig[3], orig[4], orig[5],
		       last_seen_secs, last_seen_msecs, tq,
		       neigh[0], neigh[1], neigh[2],
		       neigh[3], neigh[4], neigh[5],
		       ifname);
	}

	return NL_OK;
}

static void originators(struct nl_handle *sock, int family, int ifindex, int hard_ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_ORIGINATORS, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	if (hard_ifindex)
		nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, hard_ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, originators_callback, NULL);
	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

static int neighbors_callback(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *ghdr;
	struct nlattr *attrs[BATADV_ATTR_MAX+1];

	if (!genlmsg_valid_hdr(nlh, 0)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	ghdr = nlmsg_data(nlh);

	if (ghdr->cmd != BATADV_CMD_GET_NEIGHBORS)
		return NL_OK;

	if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), NULL)) {
		fputs("Received invalid data from kernel.", stderr);
		exit(1);
	}

	uint8_t *neigh = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]);

	char ifname[IF_NAMESIZE];
	if (!if_indextoname(nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]), ifname))
		ifname[0] = '\0';

	int last_seen_msecs, last_seen_secs;
	last_seen_msecs = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]);
	last_seen_secs = last_seen_msecs / 1000;
	last_seen_msecs = last_seen_msecs % 1000;

	if (attrs[BATADV_ATTR_THROUGHPUT]) {
		unsigned throughput_mbits, throughput_kbits;
		throughput_kbits = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]);
		throughput_mbits = throughput_kbits / 1000;
		throughput_kbits = throughput_kbits % 1000;

		printf("%02x:%02x:%02x:%02x:%02x:%02x %4i.%03is (%9u.%1u) [%10s]\n",
		       neigh[0], neigh[1], neigh[2],
		       neigh[3], neigh[4], neigh[5],
		       last_seen_secs, last_seen_msecs,
		       throughput_mbits, throughput_kbits / 100,
		       ifname);
	}
	else {
		printf("   %10s   %02x:%02x:%02x:%02x:%02x:%02x %4i.%03is\n",
		       ifname,
		       neigh[0], neigh[1], neigh[2],
		       neigh[3], neigh[4], neigh[5],
		       last_seen_secs, last_seen_msecs);
	}

	return NL_OK;
}

static void neighbors(struct nl_handle *sock, int family, int ifindex, int hard_ifindex)
{
	struct nl_msg *msg;
	struct nl_cb *cb;

	msg = nlmsg_alloc();
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, BATADV_CMD_GET_NEIGHBORS, 1);

	nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex);

	if (hard_ifindex)
		nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, hard_ifindex);

	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, neighbors_callback, NULL);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, stop_callback, NULL);
	nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);

	nl_recvmsgs(sock, cb);
}

int main(int argc, char *argv[])
{
	struct nl_handle *sock;
	int family;

	sock = nl_handle_alloc();
	genl_connect(sock);

	family = genl_ctrl_resolve(sock, BATADV_NL_NAME);
	if (family < 0) {
		fputs("Your kernel doesn't support the batman-adv netlink interface.\n", stderr);
		exit(1);
	}

	if (argc < 2 || argc > 4)
		usage();

	int ifindex = 0;
	if (argc > 2) {
		ifindex = if_nametoindex(argv[2]);
		if (!ifindex)
			usage();
	}

	int hard_ifindex = 0;
	if (argc > 3) {
		hard_ifindex = if_nametoindex(argv[3]);
		if (!hard_ifindex)
			usage();
	}

	if (!strcmp(argv[1], "routing_algos"))
		routing_algos(sock, family);
	else if (!strcmp(argv[1], "info"))
		info(sock, family, ifindex);
	else if (!strcmp(argv[1], "interface"))
		interface(sock, family, ifindex);
	else if (!strcmp(argv[1], "translocal"))
		translocal(sock, family, ifindex);
	else if (!strcmp(argv[1], "transglobal"))
		transglobal(sock, family, ifindex);
	else if (!strcmp(argv[1], "originators"))
		originators(sock, family, ifindex, hard_ifindex);
	else if (!strcmp(argv[1], "neighbors"))
		neighbors(sock, family, ifindex, hard_ifindex);
	else
		usage();

	return 0;
}

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

  parent reply	other threads:[~2016-03-17 17:04 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-17 16:45 [B.A.T.M.A.N.] [RFC v2 0/5] batman-adv netlink query API Matthias Schiffer
2016-03-17 16:45 ` [B.A.T.M.A.N.] [RFC v2 1/5] batman-adv: add generic netlink query API to replace debugfs files Matthias Schiffer
2016-03-17 16:45 ` [B.A.T.M.A.N.] [RFC v2 2/5] batman-adv: netlink: add translation table query Matthias Schiffer
2016-03-17 16:45 ` [B.A.T.M.A.N.] [RFC v2 3/5] batman-adv: netlink: add originator and neighbor table queries Matthias Schiffer
2016-03-17 16:45 ` [B.A.T.M.A.N.] [RFC v2 4/5] batman-adv: add B.A.T.M.A.N. IV bat_{orig, neigh}_dump implementations Matthias Schiffer
2016-03-17 16:45 ` [B.A.T.M.A.N.] [RFC v2 5/5] batman-adv: add B.A.T.M.A.N. V " Matthias Schiffer
2016-03-17 17:04 ` Matthias Schiffer [this message]
2016-03-18  7:09   ` [B.A.T.M.A.N.] [RFC v2 0/5] batman-adv netlink query API Sven Eckelmann
2016-03-18 11:53     ` Matthias Schiffer
2016-04-18 10:59       ` Sven Eckelmann
2016-03-18 11:23 ` Sven Eckelmann
2016-03-18 12:00   ` Matthias Schiffer
2016-03-18 12:04     ` Sven Eckelmann
2016-03-19  8:49       ` Antonio Quartulli
2016-03-19  9:19         ` Sven Eckelmann
2016-04-18 11:10           ` Sven Eckelmann
2016-04-18 14:50 ` Simon Wunderlich
2016-04-20  2:31   ` Andrew Lunn
2016-04-20 11:39     ` Simon Wunderlich
2016-04-20  7:32   ` Matthias Schiffer
2016-04-20  7:39     ` Sven Eckelmann
2016-04-20  7:49       ` Matthias Schiffer
2016-04-20  7:53         ` Sven Eckelmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=56EAE3B8.3050808@universe-factory.net \
    --to=mschiffer@universe-factory.net \
    --cc=b.a.t.m.a.n@lists.open-mesh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox