From 10cf5a586c149fdb7e2639000dbfae5e6f8522a5 Mon Sep 17 00:00:00 2001
From: Thomas Graf <tgr@lsx.localdomain>
Date: Fri, 23 May 2008 00:02:02 +0200
Subject: New set of libnl tools

Converts all tools to the API changes and improves the useability by
introducing regular options and long options.
---
 src/.gitignore              |  20 ++---
 src/Makefile                |  24 +++++-
 src/addr-utils.c            |  11 +++
 src/addr-utils.h            |   1 +
 src/ct-utils.c              | 148 +++++++++++++++++++++++++++++++++
 src/ct-utils.h              |  34 ++++++++
 src/ctrl-utils.c            |  18 ++++
 src/ctrl-utils.h            |  19 +++++
 src/disabled-nl-qdisc-add.c | 196 ++++++++++++++++++++++++++++++++++++++++++++
 src/f_ct.c                  | 170 --------------------------------------
 src/f_link.c                | 106 ------------------------
 src/f_neigh.c               |  51 ------------
 src/genl-ctrl-dump.c        |  65 ---------------
 src/genl-ctrl-list.c        |  63 ++++++++++++++
 src/link-utils.c            |  62 ++++++++++++++
 src/link-utils.h            |  25 ++++++
 src/log-utils.c             |  23 ++++++
 src/log-utils.h             |  22 +++++
 src/neigh-utils.c           |  76 +++++++++++++++++
 src/neigh-utils.h           |  24 ++++++
 src/nf-ct-dump.c            |  91 --------------------
 src/nf-ct-list.c            | 135 ++++++++++++++++++++++++++++++
 src/nf-log.c                | 110 +++++++------------------
 src/nf-monitor.c            |  63 ++++++--------
 src/nf-queue.c              | 107 ++++++------------------
 src/nl-fib-lookup.c         |  43 +++-------
 src/nl-link-dump.c          |  75 -----------------
 src/nl-link-ifindex2name.c  |  55 +++++--------
 src/nl-link-list.c          | 105 ++++++++++++++++++++++++
 src/nl-link-name2ifindex.c  |  48 ++++-------
 src/nl-link-set.c           | 153 +++++++++++++++++++++-------------
 src/nl-link-stats.c         | 129 +++++++++++++++--------------
 src/nl-monitor.c            |  44 +++-------
 src/nl-neigh-add.c          | 146 ++++++++++++++++++++-------------
 src/nl-neigh-delete.c       | 137 +++++++++++++++++++++----------
 src/nl-neigh-dump.c         |  82 ------------------
 src/nl-neigh-list.c         |  87 ++++++++++++++++++++
 src/nl-neightbl-dump.c      |  70 ----------------
 src/nl-neightbl-list.c      |  64 +++++++++++++++
 src/nl-qdisc-add.c          | 196 --------------------------------------------
 src/nl-qdisc-delete.c       | 138 ++++++++++++++++++++-----------
 src/nl-qdisc-dump.c         |  74 -----------------
 src/nl-qdisc-list.c         |  88 ++++++++++++++++++++
 src/nl-route-add.c          |  40 +++------
 src/nl-route-delete.c       |  55 ++++---------
 src/nl-route-get.c          |  85 +++++++------------
 src/nl-route-list.c         |  38 +++------
 src/nl-rule-dump.c          |  78 ------------------
 src/nl-rule-list.c          |  75 +++++++++++++++++
 src/nl-tctree-dump.c        | 144 --------------------------------
 src/nl-tctree-list.c        | 147 +++++++++++++++++++++++++++++++++
 src/nl-util-addr.c          |  17 ++--
 src/qdisc-utils.c           |  62 ++++++++++++++
 src/qdisc-utils.h           |  23 ++++++
 src/queue-utils.c           |  24 ++++++
 src/queue-utils.h           |  24 ++++++
 src/route-utils.c           |  54 ++++++------
 src/route-utils.h           |   1 +
 src/rtnl-utils.c            |  66 +++++++++++++++
 src/rtnl-utils.h            |  25 ++++++
 src/rule-utils.c            |  31 +++++++
 src/rule-utils.h            |  20 +++++
 src/utils.c                 |  80 ++++--------------
 src/utils.h                 |  18 ++--
 64 files changed, 2430 insertions(+), 2075 deletions(-)
 create mode 100644 src/ct-utils.c
 create mode 100644 src/ct-utils.h
 create mode 100644 src/ctrl-utils.c
 create mode 100644 src/ctrl-utils.h
 create mode 100644 src/disabled-nl-qdisc-add.c
 delete mode 100644 src/f_ct.c
 delete mode 100644 src/f_link.c
 delete mode 100644 src/f_neigh.c
 delete mode 100644 src/genl-ctrl-dump.c
 create mode 100644 src/genl-ctrl-list.c
 create mode 100644 src/link-utils.c
 create mode 100644 src/link-utils.h
 create mode 100644 src/log-utils.c
 create mode 100644 src/log-utils.h
 create mode 100644 src/neigh-utils.c
 create mode 100644 src/neigh-utils.h
 delete mode 100644 src/nf-ct-dump.c
 create mode 100644 src/nf-ct-list.c
 delete mode 100644 src/nl-link-dump.c
 create mode 100644 src/nl-link-list.c
 delete mode 100644 src/nl-neigh-dump.c
 create mode 100644 src/nl-neigh-list.c
 delete mode 100644 src/nl-neightbl-dump.c
 create mode 100644 src/nl-neightbl-list.c
 delete mode 100644 src/nl-qdisc-add.c
 delete mode 100644 src/nl-qdisc-dump.c
 create mode 100644 src/nl-qdisc-list.c
 delete mode 100644 src/nl-rule-dump.c
 create mode 100644 src/nl-rule-list.c
 delete mode 100644 src/nl-tctree-dump.c
 create mode 100644 src/nl-tctree-list.c
 create mode 100644 src/qdisc-utils.c
 create mode 100644 src/qdisc-utils.h
 create mode 100644 src/queue-utils.c
 create mode 100644 src/queue-utils.h
 create mode 100644 src/rtnl-utils.c
 create mode 100644 src/rtnl-utils.h
 create mode 100644 src/rule-utils.c
 create mode 100644 src/rule-utils.h

diff --git a/src/.gitignore b/src/.gitignore
index 8d71209..60233c8 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,13 +1,12 @@
-genl-ctrl-dump
-genl-ctrl-get
-nf-ct-dump
+genl-ctrl-list
+nf-ct-list
 nf-log
 nf-monitor
 nl-addr-add
 nl-addr-delete
-nl-addr-dump
+nl-addr-list
 nl-fib-lookup
-nl-link-dump
+nl-link-list
 nl-link-ifindex2name
 nl-link-name2ifindex
 nl-link-set
@@ -17,15 +16,16 @@ nl-list-sockets
 nl-monitor
 nl-neigh-add
 nl-neigh-delete
-nl-neigh-dump
-nl-neightbl-dump
+nl-neigh-list
+nl-neightbl-list
 nl-qdisc-add
 nl-qdisc-delete
-nl-qdisc-dump
+nl-qdisc-list
 nl-route-add
 nl-route-delete
 nl-route-list
 nl-route-get
-nl-rule-dump
-nl-tctree-dump
+nl-rule-list
+nl-tctree-list
 nl-util-addr
+nf-queue
diff --git a/src/Makefile b/src/Makefile
index 5dad9e6..55ee339 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -20,19 +20,35 @@ TOOLS	:= $(CIN:%.c=%)
 all: $(TOOLS)
 
 $(TOOLS): utils.o
-nl-route-add nl-route-delete nl-route-list: route-utils.o
-nl-addr-add nl-addr-delete nl-addr-list: addr-utils.o
+nl-route-add nl-route-delete nl-route-list: route-utils.o rtnl-utils.o
+nl-route-get: rtnl-utils.o
+nl-addr-add nl-addr-delete nl-addr-list: addr-utils.o rtnl-utils.o
+nl-link-list nl-link-set nl-link-stats: link-utils.o rtnl-utils.o
+nl-link-ifindex2name nl-link-name2ifindex: rtnl-utils.o
+nl-neigh-add nl-neigh-delete nl-neigh-list: neigh-utils.o rtnl-utils.o
+nl-qdisc-delete nl-qdisc-list: qdisc-utils.o rtnl-utils.o
+nl-rule-list: rule-utils.o rtnl-utils.o
+nl-neightbl-list: rtnl-utils.o
+nl-monitor: rtnl-utils.o
+nl-tctree-list: rtnl-utils.o
+
+genl-ctrl-list: ctrl-utils.o
+
+nf-ct-list: ct-utils.o
+nf-log: log-utils.o rtnl-utils.o
+nf-queue: queue-utils.o rtnl-utils.o
 
 nl-%: nl-%.c
+	@echo "  LD $@"; \
 	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lnl-route
 
 genl-%: genl-%.c
 	@echo "  LD $@"; \
-	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lnl-genl
 
 nf-%: nf-%.c
 	@echo "  LD $@"; \
-	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lnl-nf
 
 clean:
 	@echo "  CLEAN src"; \
diff --git a/src/addr-utils.c b/src/addr-utils.c
index 3c8ee4d..900be14 100644
--- a/src/addr-utils.c
+++ b/src/addr-utils.c
@@ -11,6 +11,17 @@
 
 #include "addr-utils.h"
 
+struct rtnl_addr *nlt_alloc_addr(void)
+{
+	struct rtnl_addr *addr;
+
+	addr = rtnl_addr_alloc();
+	if (!addr)
+		fatal(ENOMEM, "Unable to allocate address object");
+
+	return addr;
+}
+
 void parse_family(struct rtnl_addr *addr, char *arg)
 {
 	int family;
diff --git a/src/addr-utils.h b/src/addr-utils.h
index 0a4db23..45a9709 100644
--- a/src/addr-utils.h
+++ b/src/addr-utils.h
@@ -14,6 +14,7 @@
 
 #include "utils.h"
 
+extern struct rtnl_addr *nlt_alloc_addr(void);
 extern void parse_family(struct rtnl_addr *, char *);
 extern void parse_local(struct rtnl_addr *, char *);
 extern void parse_dev(struct rtnl_addr *, struct nl_cache *, char *);
diff --git a/src/ct-utils.c b/src/ct-utils.c
new file mode 100644
index 0000000..7d116fa
--- /dev/null
+++ b/src/ct-utils.c
@@ -0,0 +1,148 @@
+/*
+ * src/ct-utils.c		Conntrack Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "ct-utils.h"
+
+struct nfnl_ct *nlt_alloc_ct(void)
+{
+	struct nfnl_ct *ct;
+
+	ct = nfnl_ct_alloc();
+	if (!ct)
+		fatal(ENOMEM, "Unable to allocate conntrack object");
+
+	return ct;
+}
+
+struct nl_cache *nlt_alloc_ct_cache(struct nl_sock *sk)
+{
+	return alloc_cache(sk, "conntrack", nfnl_ct_alloc_cache);
+}
+
+void parse_family(struct nfnl_ct *ct, char *arg)
+{
+	int family;
+
+	if ((family = nl_str2af(arg)) == AF_UNSPEC)
+		fatal(EINVAL, "Unable to parse family \"%s\": %s",
+		      arg, nl_geterror(NLE_INVAL));
+
+	nfnl_ct_set_family(ct, family);
+}
+
+void parse_protocol(struct nfnl_ct *ct, char *arg)
+{
+	int proto;
+
+	if ((proto = nl_str2ip_proto(arg)) < 0)
+		fatal(proto, "Unable to parse protocol \"%s\": %s",
+		      arg, nl_geterror(proto));
+
+	nfnl_ct_set_proto(ct, proto);
+}
+
+void parse_mark(struct nfnl_ct *ct, char *arg)
+{
+	uint32_t mark = parse_u32(arg);
+	nfnl_ct_set_mark(ct, mark);
+}
+
+void parse_timeout(struct nfnl_ct *ct, char *arg)
+{
+	uint32_t timeout = parse_u32(arg);
+	nfnl_ct_set_timeout(ct, timeout);
+}
+
+void parse_id(struct nfnl_ct *ct, char *arg)
+{
+	uint32_t id = parse_u32(arg);
+	nfnl_ct_set_id(ct, id);
+}
+
+void parse_use(struct nfnl_ct *ct, char *arg)
+{
+	uint32_t use = parse_u32(arg);
+	nfnl_ct_set_use(ct, use);
+}
+
+void parse_src(struct nfnl_ct *ct, int reply, char *arg)
+{
+	int err;
+	struct nl_addr *a = nlt_addr_parse(arg, nfnl_ct_get_family(ct));
+	if ((err = nfnl_ct_set_src(ct, reply, a)) < 0)
+		fatal(err, "Unable to set source address: %s",
+		      nl_geterror(err));
+}
+
+void parse_dst(struct nfnl_ct *ct, int reply, char *arg)
+{
+	int err;
+	struct nl_addr *a = nlt_addr_parse(arg, nfnl_ct_get_family(ct));
+	if ((err = nfnl_ct_set_dst(ct, reply, a)) < 0)
+		fatal(err, "Unable to set destination address: %s",
+		      nl_geterror(err));
+}
+
+void parse_src_port(struct nfnl_ct *ct, int reply, char *arg)
+{
+	uint32_t port = parse_u32(arg);
+	nfnl_ct_set_src_port(ct, reply, port);
+}
+
+void parse_dst_port(struct nfnl_ct *ct, int reply, char *arg)
+{
+	uint32_t port = parse_u32(arg);
+	nfnl_ct_set_dst_port(ct, reply, port);
+}
+
+void parse_tcp_state(struct nfnl_ct *ct, char *arg)
+{
+	int state;
+
+	if ((state = nfnl_ct_str2tcp_state(arg)) < 0)
+		fatal(state, "Unable to parse tcp state \"%s\": %s",
+		      arg, nl_geterror(state));
+
+	nfnl_ct_set_tcp_state(ct, state);
+}
+
+void parse_status(struct nfnl_ct *ct, char *arg)
+{
+	int status;
+
+	if ((status = nfnl_ct_str2status(arg)) < 0)
+		fatal(status, "Unable to parse flags \"%s\": %s",
+		      arg, nl_geterror(status));
+
+	nfnl_ct_set_status(ct, status);
+}
+
+#if 0
+		} else if (arg_match("origicmpid")) {
+			if (argc > ++idx)
+				nfnl_ct_set_icmp_id(ct, 0, strtoul(argv[idx++], NULL, 0));
+		} else if (arg_match("origicmptype")) {
+			if (argc > ++idx)
+				nfnl_ct_set_icmp_type(ct, 0, strtoul(argv[idx++], NULL, 0));
+		} else if (arg_match("origicmpcode")) {
+			if (argc > ++idx)
+				nfnl_ct_set_icmp_code(ct, 0, strtoul(argv[idx++], NULL, 0));
+		} else if (arg_match("replyicmpid")) {
+			if (argc > ++idx)
+				nfnl_ct_set_icmp_id(ct, 1, strtoul(argv[idx++], NULL, 0));
+		} else if (arg_match("replyicmptype")) {
+			if (argc > ++idx)
+				nfnl_ct_set_icmp_type(ct, 1, strtoul(argv[idx++], NULL, 0));
+		} else if (arg_match("replyicmpcode")) {
+			if (argc > ++idx)
+				nfnl_ct_set_icmp_code(ct, 1, strtoul(argv[idx++], NULL, 0));
+		}
+#endif
diff --git a/src/ct-utils.h b/src/ct-utils.h
new file mode 100644
index 0000000..fc20e49
--- /dev/null
+++ b/src/ct-utils.h
@@ -0,0 +1,34 @@
+/*
+ * src/ct-utils.h		Conntrack Helper
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __CT_UTILS_H_
+#define __CT_UTILS_H_
+
+#include "utils.h"
+#include <netlink/netfilter/ct.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+
+extern struct nfnl_ct *nlt_alloc_ct(void);
+extern struct nl_cache *nlt_alloc_ct_cache(struct nl_sock *);
+extern void parse_family(struct nfnl_ct *, char *);
+extern void parse_protocol(struct nfnl_ct *, char *);
+extern void parse_mark(struct nfnl_ct *, char *);
+extern void parse_timeout(struct nfnl_ct *, char *);
+extern void parse_id(struct nfnl_ct *, char *);
+extern void parse_use(struct nfnl_ct *, char *);
+extern void parse_src(struct nfnl_ct *, int, char *);
+extern void parse_dst(struct nfnl_ct *, int, char *);
+extern void parse_src_port(struct nfnl_ct *, int, char *);
+extern void parse_dst_port(struct nfnl_ct *, int, char *);
+extern void parse_tcp_state(struct nfnl_ct *, char *);
+extern void parse_status(struct nfnl_ct *, char *);
+
+#endif
diff --git a/src/ctrl-utils.c b/src/ctrl-utils.c
new file mode 100644
index 0000000..5309c23
--- /dev/null
+++ b/src/ctrl-utils.c
@@ -0,0 +1,18 @@
+/*
+ * src/ctrl-utils.c		Generic Ctrl Netlink Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "ctrl-utils.h"
+
+struct nl_cache *nlt_alloc_genl_family_cache(struct nl_sock *sk)
+{
+	return alloc_cache(sk, "generic netlink family",
+			   genl_ctrl_alloc_cache);
+}
diff --git a/src/ctrl-utils.h b/src/ctrl-utils.h
new file mode 100644
index 0000000..59e3cdc
--- /dev/null
+++ b/src/ctrl-utils.h
@@ -0,0 +1,19 @@
+/*
+ * src/ctrl-utils.h		Generic Netlink Ctrl Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __SRC_CTRL_UTILS_H_
+#define __SRC_CTRL_UTILS_H_
+
+#include "utils.h"
+
+extern struct nl_cache *nlt_alloc_genl_family_cache(struct nl_sock *);
+
+#endif
diff --git a/src/disabled-nl-qdisc-add.c b/src/disabled-nl-qdisc-add.c
new file mode 100644
index 0000000..be19f9b
--- /dev/null
+++ b/src/disabled-nl-qdisc-add.c
@@ -0,0 +1,196 @@
+/*
+ * src/nl-qdisc-dump.c     Dump qdisc attributes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "utils.h"
+#include <netlink/route/sch/fifo.h>
+#include <netlink/route/sch/prio.h>
+
+static void print_usage(void)
+{
+	printf(
+"Usage: nl-qdisc-add <ifindex> <handle> <parent> <kind>\n");
+	exit(1);
+}
+
+static int parse_blackhole_opts(struct rtnl_qdisc *qdisc, char *argv[],
+				int argc)
+{
+	return 0;
+}
+
+static int parse_pfifo_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
+{
+	int err, limit;
+
+	if (argc > 0) {
+		if (argc != 2 || strcasecmp(argv[0], "limit")) {
+			fprintf(stderr, "Usage: ... pfifo limit <limit>\n");
+			return -1;
+		}
+
+		limit = strtoul(argv[1], NULL, 0);
+		err = rtnl_qdisc_fifo_set_limit(qdisc, limit);
+		if (err < 0) {
+			fprintf(stderr, "%s\n", nl_geterror());
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_bfifo_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
+{
+	int err, limit;
+
+	if (argc > 0) {
+		if (argc != 2 || strcasecmp(argv[0], "limit")) {
+			fprintf(stderr, "Usage: ... bfifo limit <limit>\n");
+			return -1;
+		}
+
+		limit = nl_size2int(argv[1]);
+		if (limit < 0) {
+			fprintf(stderr, "Invalid value for limit.\n");
+			return -1;
+		}
+
+		err = rtnl_qdisc_fifo_set_limit(qdisc, limit);
+		if (err < 0) {
+			fprintf(stderr, "%s\n", nl_geterror());
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_prio_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
+{
+	int i, err, bands;
+	uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
+
+	if (argc > 0) {
+		if (argc < 2 || strcasecmp(argv[0], "bands"))
+			goto usage;
+
+		bands = strtoul(argv[1], NULL, 0);
+		err = rtnl_qdisc_prio_set_bands(qdisc, bands);
+		if (err < 0) {
+			fprintf(stderr, "%s\n", nl_geterror());
+			return -1;
+		}
+	}
+
+	if (argc > 2) {
+		if (argc < 5 || strcasecmp(argv[2], "map"))
+			goto usage;
+
+		for (i = 3; i < (argc & ~1U); i += 2) {
+			int prio, band;
+
+			prio = rtnl_str2prio(argv[i]);
+			if (prio < 0 || prio > sizeof(map)/sizeof(map[0])) {
+				fprintf(stderr, "Invalid priority \"%s\"\n",
+					argv[i]);
+				return -1;
+			}
+
+			band = strtoul(argv[i+1], NULL, 0);
+
+			map[prio] = band;
+		}
+	}
+
+	err = rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
+	if (err < 0) {
+		fprintf(stderr, "%s\n", nl_geterror());
+		return -1;
+	}
+
+	return 0;
+usage:
+	fprintf(stderr, "Usage: ... prio bands <nbands> map MAP\n"
+			"MAP := <prio> <band>\n");
+	return -1;
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_handle *nlh;
+	struct rtnl_qdisc *qdisc;
+	uint32_t handle, parent;
+	int err = 1;
+
+	if (nltool_init(argc, argv) < 0)
+		return -1;
+
+	if (argc < 5 || !strcmp(argv[1], "-h"))
+		print_usage();
+
+	nlh = nltool_alloc_handle();
+	if (!nlh)
+		goto errout;
+
+	qdisc = rtnl_qdisc_alloc();
+	if (!qdisc)
+		goto errout_free_handle;
+
+	rtnl_qdisc_set_ifindex(qdisc, strtoul(argv[1], NULL, 0));
+
+	if (rtnl_tc_str2handle(argv[2], &handle) < 0) {
+		fprintf(stderr, "%s\n", nl_geterror());
+		goto errout_free_qdisc;
+	}
+
+	if (rtnl_tc_str2handle(argv[3], &parent) < 0) {
+		fprintf(stderr, "%s\n", nl_geterror());
+		goto errout_free_qdisc;
+	}
+
+	rtnl_qdisc_set_handle(qdisc, handle);
+	rtnl_qdisc_set_parent(qdisc, parent);
+	rtnl_qdisc_set_kind(qdisc, argv[4]);
+
+	if (!strcasecmp(argv[4], "blackhole"))
+		err = parse_blackhole_opts(qdisc, &argv[5], argc-5);
+	else if (!strcasecmp(argv[4], "pfifo"))
+		err = parse_pfifo_opts(qdisc, &argv[5], argc-5);
+	else if (!strcasecmp(argv[4], "bfifo"))
+		err = parse_bfifo_opts(qdisc, &argv[5], argc-5);
+	else if (!strcasecmp(argv[4], "prio"))
+		err = parse_prio_opts(qdisc, &argv[5], argc-5);
+	else {
+		fprintf(stderr, "Unknown qdisc \"%s\"\n", argv[4]);
+		goto errout_free_qdisc;
+	}
+
+	if (err < 0)
+		goto errout_free_qdisc;
+
+	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
+		goto errout_free_qdisc;
+
+	if (rtnl_qdisc_add(nlh, qdisc, NLM_F_REPLACE) < 0) {
+		fprintf(stderr, "Unable to add Qdisc: %s\n", nl_geterror());
+		goto errout_close;
+	}
+
+	err = 0;
+errout_close:
+	nl_close(nlh);
+errout_free_qdisc:
+	rtnl_qdisc_put(qdisc);
+errout_free_handle:
+	nl_handle_destroy(nlh);
+errout:
+	return err;
+}
diff --git a/src/f_ct.c b/src/f_ct.c
deleted file mode 100644
index fbb04fc..0000000
--- a/src/f_ct.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * src/f_ct.c     	Conntrack Filter
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
- * Copyright (c) 2007 Secure Computing Corporation
- */
-
-static void get_filter(struct nfnl_ct *ct, int argc, char **argv, int idx)
-{
-	struct nl_addr *a;
-
-	while (argc > idx) {
-		if (arg_match("family")) {
-			if (argc > ++idx) {
-				int family = nl_str2af(argv[idx++]);
-				if (family == AF_UNSPEC)
-					goto err_invaf;
-				nfnl_ct_set_family(ct, family);
-			}
-		} else if (arg_match("proto")) {
-			if (argc > ++idx) {
-				int proto = nl_str2ip_proto(argv[idx++]);
-				if (proto < 0)
-					goto err_invproto;
-				nfnl_ct_set_proto(ct, proto);
-			}
-		} else if (arg_match("tcpstate")) {
-			if (argc > ++idx) {
-				int state = nfnl_ct_str2tcp_state(argv[idx++]);
-				if (state < 0)
-					goto err_invtcpstate;
-				nfnl_ct_set_tcp_state(ct, state);
-			}
-		} else if (arg_match("status")) {
-			if (argc > ++idx) {
-				int status = strtoul(argv[idx++], NULL, 0);
-				nfnl_ct_set_status(ct, status);
-				nfnl_ct_unset_status(ct, ~status);
-			}
-		} else if (arg_match("timeout")) {
-			if (argc > ++idx)
-				nfnl_ct_set_timeout(ct, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("mark")) {
-			if (argc > ++idx)
-				nfnl_ct_set_mark(ct, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("use")) {
-			if (argc > ++idx)
-				nfnl_ct_set_use(ct, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("id")) {
-			if (argc > ++idx)
-				nfnl_ct_set_id(ct, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("origsrc")) {
-			if (argc > ++idx) {
-				a = nl_addr_parse(argv[idx++],
-						  nfnl_ct_get_family(ct));
-				if (!a)
-					goto err_invaddr;
-				nfnl_ct_set_src(ct, 0, a);
-				nl_addr_put(a);
-			}
-		} else if (arg_match("origdst")) {
-			if (argc > ++idx) {
-				a = nl_addr_parse(argv[idx++],
-						  nfnl_ct_get_family(ct));
-				if (!a)
-					goto err_invaddr;
-				nfnl_ct_set_dst(ct, 0, a);
-				nl_addr_put(a);
-			}
-		} else if (arg_match("origsrcport")) {
-			if (argc > ++idx)
-				nfnl_ct_set_src_port(ct, 0, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("origdstport")) {
-			if (argc > ++idx)
-				nfnl_ct_set_dst_port(ct, 0, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("origicmpid")) {
-			if (argc > ++idx)
-				nfnl_ct_set_icmp_id(ct, 0, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("origicmptype")) {
-			if (argc > ++idx)
-				nfnl_ct_set_icmp_type(ct, 0, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("origicmpcode")) {
-			if (argc > ++idx)
-				nfnl_ct_set_icmp_code(ct, 0, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("origpackets")) {
-			if (argc > ++idx)
-				nfnl_ct_set_packets(ct, 0, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("origbytes")) {
-			if (argc > ++idx)
-				nfnl_ct_set_bytes(ct, 0, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("replysrc")) {
-			if (argc > ++idx) {
-				a = nl_addr_parse(argv[idx++],
-						  nfnl_ct_get_family(ct));
-				if (!a)
-					goto err_invaddr;
-				nfnl_ct_set_src(ct, 1, a);
-				nl_addr_put(a);
-			}
-		} else if (arg_match("replydst")) {
-			if (argc > ++idx) {
-				a = nl_addr_parse(argv[idx++],
-						  nfnl_ct_get_family(ct));
-				if (!a)
-					goto err_invaddr;
-				nfnl_ct_set_dst(ct, 1, a);
-				nl_addr_put(a);
-			}
-		} else if (arg_match("replysrcport")) {
-			if (argc > ++idx)
-				nfnl_ct_set_src_port(ct, 1, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("replydstport")) {
-			if (argc > ++idx)
-				nfnl_ct_set_dst_port(ct, 1, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("replyicmpid")) {
-			if (argc > ++idx)
-				nfnl_ct_set_icmp_id(ct, 1, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("replyicmptype")) {
-			if (argc > ++idx)
-				nfnl_ct_set_icmp_type(ct, 1, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("replyicmpcode")) {
-			if (argc > ++idx)
-				nfnl_ct_set_icmp_code(ct, 1, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("replypackets")) {
-			if (argc > ++idx)
-				nfnl_ct_set_packets(ct, 1, strtoul(argv[idx++], NULL, 0));
-		} else if (arg_match("replybytes")) {
-			if (argc > ++idx)
-				nfnl_ct_set_bytes(ct, 1, strtoul(argv[idx++], NULL, 0));
-		}
-#define MSTATUS(STR, STATUS) \
-	else if (!strcasecmp(argv[idx], STR)) { \
-		nfnl_ct_set_status(ct, STATUS); idx++; }
-#define MNOSTATUS(STR, STATUS) \
-	else if (!strcasecmp(argv[idx], STR)) { \
-		nfnl_ct_unset_status(ct, STATUS); idx++; }
-
-		MSTATUS("replied", IPS_SEEN_REPLY)
-		MNOSTATUS("unreplied", IPS_SEEN_REPLY)
-		MSTATUS("assured", IPS_ASSURED)
-		MNOSTATUS("unassured", IPS_ASSURED)
-#undef MSTATUS
-#undef MNOSTATUS
-		else {
-			fprintf(stderr, "What is '%s'?\n", argv[idx]);
-			exit(1);
-		}
-	}
-
-	return;
-
-err_invproto:
-	fprintf(stderr, "Invalid IP protocol \"%s\".\n", argv[idx-1]);
-	exit(1);
-err_invtcpstate:
-	fprintf(stderr, "Invalid TCP state \"%s\".\n", argv[idx-1]);
-	exit(1);
-err_invaf:
-	fprintf(stderr, "Invalid address family \"%s\"\n", argv[idx-1]);
-	exit(1);
-err_invaddr:
-	fprintf(stderr, "Invalid address \"%s\": %s\n", argv[idx-1], nl_geterror());
-	exit(1);
-}
diff --git a/src/f_link.c b/src/f_link.c
deleted file mode 100644
index 3c1cb93..0000000
--- a/src/f_link.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * src/f_link.c		Link Filter
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include <linux/if.h>
-
-static void get_filter(struct rtnl_link *l, int ac, char **av, int idx,
-		       struct nl_cache *cache)
-{
-	while (ac > idx) {
-		if (!strcasecmp(av[idx], "dev")) {
-			if (ac > ++idx) {
-				int ifindex = rtnl_link_name2i(cache, av[idx++]);
-				if (ifindex == RTNL_LINK_NOT_FOUND)
-					goto err_notfound;
-				rtnl_link_set_ifindex(l, ifindex);
-			}
-		} else if (!strcasecmp(av[idx], "mtu")) {
-			if (ac > ++idx)
-				rtnl_link_set_mtu(l, strtoul(av[idx++], NULL, 0));
-		} else if (!strcasecmp(av[idx], "txqlen")) {
-			if (ac > ++idx)
-				rtnl_link_set_txqlen(l, strtoul(av[idx++], NULL, 0));
-		} else if (!strcasecmp(av[idx], "weight")) {
-			if (ac > ++idx)
-				rtnl_link_set_weight(l, strtoul(av[idx++], NULL, 0));
-		} else if (!strcasecmp(av[idx], "link")) {
-			if (ac > ++idx) {
-				int ifindex = rtnl_link_name2i(cache, av[idx++]);
-				if (ifindex == RTNL_LINK_NOT_FOUND)
-					goto err_notfound;
-				rtnl_link_set_link(l, ifindex);
-			}
-		} else if (!strcasecmp(av[idx], "master")) {
-			if (ac > ++idx) {
-				int ifindex = rtnl_link_name2i(cache, av[idx++]);
-				if (ifindex == RTNL_LINK_NOT_FOUND)
-					goto err_notfound;
-				rtnl_link_set_master(l, ifindex);
-			}
-		} else if (!strcasecmp(av[idx], "qdisc")) {
-			if (ac > ++idx)
-				rtnl_link_set_qdisc(l, av[idx++]);
-		} else if (!strcasecmp(av[idx], "name")) {
-			if (ac > ++idx)
-				rtnl_link_set_name(l, av[idx++]);
-		} else if (!strcasecmp(av[idx], "addr")) {
-			if (ac > ++idx) {
-				struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC);
-				if (a == NULL)
-					goto err;
-				rtnl_link_set_addr(l, a);
-				nl_addr_put(a);
-			}
-		} else if (!strcasecmp(av[idx], "broadcast")) {
-			if (ac > ++idx) {
-				struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC);
-				if (a == NULL)
-					goto err;
-				rtnl_link_set_broadcast(l, a);
-				nl_addr_put(a);
-			}
-		}
-#define MFLAG(STR, FLAG) \
-	else if (!strcasecmp(av[idx], STR)) { \
-		rtnl_link_set_flags(l, FLAG); idx++; }
-#define MNOFLAG(STR, FLAG) \
-	else if (!strcasecmp(av[idx], STR)) { \
-		rtnl_link_unset_flags(l, FLAG); idx++; }
-
-		MFLAG("up", IFF_UP)
-		MNOFLAG("down", IFF_UP)
-		MFLAG("noarp", IFF_NOARP)
-		MNOFLAG("arp", IFF_NOARP)
-		MFLAG("promisc", IFF_PROMISC)
-		MNOFLAG("nopromisc", IFF_PROMISC)
-		MFLAG("dynamic", IFF_DYNAMIC)
-		MNOFLAG("nodynamic", IFF_DYNAMIC)
-		MFLAG("multicast", IFF_MULTICAST)
-		MNOFLAG("nomulticast", IFF_MULTICAST)
-		MFLAG("allmulticast", IFF_ALLMULTI)
-		MNOFLAG("noallmulticast", IFF_ALLMULTI)
-#undef MFLAG
-#undef MNOFLAG
-		else {
-			fprintf(stderr, "What is '%s'?\n", av[idx]);
-			exit(1);
-		}
-	}
-
-	return;
-
-err_notfound:
-	fprintf(stderr, "Unknown link %s\n", av[idx-1]);
-	exit(1);
-err:
-	fprintf(stderr, "%s\n", nl_geterror());
-	exit(1);
-}
diff --git a/src/f_neigh.c b/src/f_neigh.c
deleted file mode 100644
index ac9355c..0000000
--- a/src/f_neigh.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * src/f_neigh.c	Neighbour Filter
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-static void get_filter(struct rtnl_neigh *n, int ac, char **av, int idx,
-		       struct nl_cache *cache)
-{
-	struct nl_cache *lc = nl_cache_mngt_require("route/link");
-	
-	while (ac > idx) {
-		if (!strcasecmp(av[idx], "dev")) {
-			if (ac > ++idx) {
-				int ifindex = rtnl_link_name2i(lc, av[idx++]);
-				if (ifindex == RTNL_LINK_NOT_FOUND)
-					goto err_notfound;
-				rtnl_neigh_set_ifindex(n, ifindex);
-			}
-		} else if (!strcasecmp(av[idx], "dst")) {
-			if (ac > ++idx) {
-				struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC);
-				if (a == NULL)
-					goto err;
-				rtnl_neigh_set_dst(n, a);
-				nl_addr_put(a);
-			}
-		} else if (!strcasecmp(av[idx], "lladdr")) {
-			if (ac > ++idx) {
-				struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC);
-				if (a == NULL)
-					goto err;
-				rtnl_neigh_set_lladdr(n, a);
-				nl_addr_put(a);
-			}
-		}
-	}
-
-	return;
-err_notfound:
-	fprintf(stderr, "Unable to find interface %s\n", av[idx-1]);
-	exit(1);
-err:
-	fprintf(stderr, "%s\n", nl_geterror());
-	exit(1);
-}
diff --git a/src/genl-ctrl-dump.c b/src/genl-ctrl-dump.c
deleted file mode 100644
index 98a26a1..0000000
--- a/src/genl-ctrl-dump.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * src/genl-ctrl-dump.c	Dump Generic Netlink Controller
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-
-static void print_usage(void)
-{
-	printf(
-	"Usage: genl-ctrl-dump <mode> [<filter>]\n"
-	"  mode := { brief | detailed | stats }\n"
-	"  filter := \n");
-	exit(1);
-}
-
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct nl_cache *family_cache;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF
-	};
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	if (genl_connect(nlh) < 0) {
-		fprintf(stderr, "Unable to connect generic netlink socket%s\n",
-			nl_geterror());
-		goto errout;
-	}
-
-	family_cache = nltool_alloc_genl_family_cache(nlh);
-	if (!family_cache)
-		goto errout;
-
-	params.dp_type = nltool_parse_dumptype(argv[1]);
-	if (params.dp_type < 0)
-		goto errout;
-
-	//get_filter(link, argc, argv, 2, link_cache);
-	nl_cache_dump(family_cache, &params);
-	nl_cache_free(family_cache);
-	err = 0;
-errout:
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
-	return err;
-}
diff --git a/src/genl-ctrl-list.c b/src/genl-ctrl-list.c
new file mode 100644
index 0000000..335c62b
--- /dev/null
+++ b/src/genl-ctrl-list.c
@@ -0,0 +1,63 @@
+/*
+ * src/genl-ctrl-list.c	List Generic Netlink Controller
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "ctrl-utils.h"
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: genl-ctrl-list [OPTION]...\n"
+	"\n"
+	"Options\n"
+	" -f, --format=TYPE     Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct nl_cache *family_cache;
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+ 
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_GENERIC);
+	family_cache = nlt_alloc_genl_family_cache(sock);
+ 
+	for (;;) {
+		int c, optidx = 0;
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		}
+ 	}
+
+	nl_cache_dump(family_cache, &params);
+
+	return 0;
+}
diff --git a/src/link-utils.c b/src/link-utils.c
new file mode 100644
index 0000000..93bb4c0
--- /dev/null
+++ b/src/link-utils.c
@@ -0,0 +1,62 @@
+/*
+ * src/link-utils.c     Link Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "link-utils.h"
+
+struct rtnl_link *nlt_alloc_link(void)
+{
+	struct rtnl_link *link;
+
+	link = rtnl_link_alloc();
+	if (!link)
+		fatal(ENOMEM, "Unable to allocate link object");
+
+	return link;
+}
+
+void parse_family(struct rtnl_link *link, char *arg)
+{
+	int family;
+
+	if ((family = nl_str2af(arg)) == AF_UNSPEC)
+		fatal(EINVAL, "Unable to translate address family \"%s\"", arg);
+
+	rtnl_link_set_family(link, family);
+}
+
+void parse_name(struct rtnl_link *link, char *arg)
+{
+	rtnl_link_set_name(link, arg);
+}
+
+void parse_mtu(struct rtnl_link *link, char *arg)
+{
+	uint32_t mtu = parse_u32(arg);
+	rtnl_link_set_mtu(link, mtu);
+}
+
+void parse_ifindex(struct rtnl_link *link, char *arg)
+{
+	uint32_t index = parse_u32(arg);
+	rtnl_link_set_ifindex(link, index);
+}
+
+void parse_txqlen(struct rtnl_link *link, char *arg)
+{
+	uint32_t qlen = parse_u32(arg);
+	rtnl_link_set_txqlen(link, qlen);
+}
+
+void parse_weight(struct rtnl_link *link, char *arg)
+{
+	uint32_t weight = parse_u32(arg);
+	rtnl_link_set_weight(link, weight);
+}
diff --git a/src/link-utils.h b/src/link-utils.h
new file mode 100644
index 0000000..1d5c6c0
--- /dev/null
+++ b/src/link-utils.h
@@ -0,0 +1,25 @@
+/*
+ * src/link-utils.h     Link Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __LINK_UTILS_H_
+#define __LINK_UTILS_H_
+
+#include "utils.h"
+
+extern struct rtnl_link *nlt_alloc_link(void);
+extern void parse_family(struct rtnl_link *, char *);
+extern void parse_name(struct rtnl_link *, char *);
+extern void parse_mtu(struct rtnl_link *, char *);
+extern void parse_ifindex(struct rtnl_link *, char *);
+extern void parse_txqlen(struct rtnl_link *, char *);
+extern void parse_weight(struct rtnl_link *, char *);
+
+#endif
diff --git a/src/log-utils.c b/src/log-utils.c
new file mode 100644
index 0000000..e3cfe44
--- /dev/null
+++ b/src/log-utils.c
@@ -0,0 +1,23 @@
+/*
+ * src/ct-utils.c		Conntrack Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "log-utils.h"
+
+struct nfnl_log *nlt_alloc_log(void)
+{
+	struct nfnl_log *log;
+
+	log = nfnl_log_alloc();
+	if (!log)
+		fatal(ENOMEM, "Unable to allocate log object");
+
+	return log;
+}
diff --git a/src/log-utils.h b/src/log-utils.h
new file mode 100644
index 0000000..fb5bf2a
--- /dev/null
+++ b/src/log-utils.h
@@ -0,0 +1,22 @@
+/*
+ * src/log-utils.h		Log Helper
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __LOG_UTILS_H_
+#define __LOG_UTILS_H_
+
+#include "utils.h"
+#include <linux/netfilter/nfnetlink_log.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log.h>
+
+extern struct nfnl_log *nlt_alloc_log(void);
+
+#endif
diff --git a/src/neigh-utils.c b/src/neigh-utils.c
new file mode 100644
index 0000000..3e2d699
--- /dev/null
+++ b/src/neigh-utils.c
@@ -0,0 +1,76 @@
+/*
+ * src/neigh-utils.c     Neighbour Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "neigh-utils.h"
+
+struct rtnl_neigh *nlt_alloc_neigh(void)
+{
+	struct rtnl_neigh *neigh;
+
+	neigh = rtnl_neigh_alloc();
+	if (!neigh)
+		fatal(ENOMEM, "Unable to allocate neighbout object");
+
+	return neigh;
+}
+
+void parse_dst(struct rtnl_neigh *neigh, char *arg)
+{
+	struct nl_addr *a;
+	int err;
+
+	a = nlt_addr_parse(arg, rtnl_neigh_get_family(neigh));
+	if ((err = rtnl_neigh_set_dst(neigh, a)) < 0)
+		fatal(err, "Unable to set local address: %s",
+			nl_geterror(err));
+
+	nl_addr_put(a);
+}
+
+void parse_lladdr(struct rtnl_neigh *neigh, char *arg)
+{
+	struct nl_addr *a;
+
+	a = nlt_addr_parse(arg, AF_UNSPEC);
+	rtnl_neigh_set_lladdr(neigh, a);
+	nl_addr_put(a);
+}
+
+void parse_dev(struct rtnl_neigh *neigh, struct nl_cache *link_cache, char *arg)
+{
+	int ival;
+
+	if (!(ival = rtnl_link_name2i(link_cache, arg)))
+		fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+	rtnl_neigh_set_ifindex(neigh, ival);
+}
+
+void parse_family(struct rtnl_neigh *neigh, char *arg)
+{
+	int family;
+
+	if ((family = nl_str2af(arg)) == AF_UNSPEC)
+		fatal(EINVAL, "Unable to translate address family \"%s\"", arg);
+
+	rtnl_neigh_set_family(neigh, family);
+}
+
+void parse_state(struct rtnl_neigh *neigh, char *arg)
+{
+	int state;
+	
+	if ((state = rtnl_neigh_str2state(arg)) < 0)
+		fatal(state, "Unable to translate state \"%s\": %s",
+			arg, state);
+
+	rtnl_neigh_set_state(neigh, state);
+}
diff --git a/src/neigh-utils.h b/src/neigh-utils.h
new file mode 100644
index 0000000..3662546
--- /dev/null
+++ b/src/neigh-utils.h
@@ -0,0 +1,24 @@
+/*
+ * src/neigh-utils.h     Neighbour Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NEIGH_UTILS_H_
+#define __NEIGH_UTILS_H_
+
+#include "utils.h"
+
+extern struct rtnl_neigh *nlt_alloc_neigh(void);
+extern void parse_dst(struct rtnl_neigh *, char *);
+extern void parse_lladdr(struct rtnl_neigh *, char *);
+extern void parse_dev(struct rtnl_neigh *, struct nl_cache *, char *);
+extern void parse_family(struct rtnl_neigh *, char *);
+extern void parse_state(struct rtnl_neigh *, char *);
+
+#endif
diff --git a/src/nf-ct-dump.c b/src/nf-ct-dump.c
deleted file mode 100644
index 54ee4c7..0000000
--- a/src/nf-ct-dump.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * src/nf-ct-dump.c     Dump conntrack attributes
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
- * Copyright (c) 2007 Secure Computing Corporation
- */
-
-#include "utils.h"
-#include <netlink/netfilter/ct.h>
-#include <linux/netfilter/nf_conntrack_common.h>
-
-#include "f_ct.c"
-
-static void print_usage(void)
-{
-	printf(
-	"Usage: nf-ct-dump <mode> [<filter>]\n"
-	"  mode := { brief | detailed | stats | xml }\n"
-	"  filter := [family FAMILY] [proto PROTO] [tcpstate TCPSTATE]\n"
-	"            [status STATUS] [timeout TIMEOUT] [mark MARK] [use USE] [id ID]\n"
-	"            [origsrc ADDR] [origdst ADDR] [origsrcport PORT] [origdstport PORT]\n"
-	"            [origicmpid ID] [origicmptype TYPE] [origicmpcode CODE]\n"
-	"            [origpackets PACKETS] [origbytes BYTES]\n"
-	"            [replysrc ADDR] [replydst ADDR] [replysrcport PORT] [replydstport PORT]\n"
-	"            [replyicmpid ID] [replyicmptype TYPE] [replyicmpcode CODE]\n"
-	"            [replypackets PACKETS] [replybytes BYTES]\n"
-	"            [{ replied | unreplied }] [{ assured | unassured }]\n"
-	);
-	exit(1);
-}
-
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct nl_cache *ct_cache;
-	struct nfnl_ct *ct;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF
-	};
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	ct = nfnl_ct_alloc();
-	if (!ct)
-		goto errout;
-
-	if (nltool_connect(nlh, NETLINK_NETFILTER) < 0)
-		goto errout_free;
-
-	ct_cache = nfnl_ct_alloc_cache(nlh);
-        if (!ct_cache) {
-		fprintf(stderr, "Unable to retrieve ct cache: %s\n",
-			nl_geterror());
-		goto errout_close;
-	}
-	nl_cache_mngt_provide(ct_cache);
-
-	params.dp_type = nltool_parse_dumptype(argv[1]);
-	if (params.dp_type < 0)
-		goto errout_ct_cache;
-
-	get_filter(ct, argc, argv, 2);
-	nl_cache_dump_filter(ct_cache, &params, (struct nl_object *) ct);
-
-	err = 0;
-
-errout_ct_cache:
-	nl_cache_free(ct_cache);
-errout_close:
-	nl_close(nlh);
-errout_free:
-	nfnl_ct_put(ct);
-errout:
-	return err;
-}
diff --git a/src/nf-ct-list.c b/src/nf-ct-list.c
new file mode 100644
index 0000000..2f4c4fc
--- /dev/null
+++ b/src/nf-ct-list.c
@@ -0,0 +1,135 @@
+/*
+ * src/nf-ct-list.c     List Conntrack Entries
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include "ct-utils.h"
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nf-ct-list [OPTION]... [CONNTRACK ENTRY]\n"
+	"\n"
+	"Options\n"
+	" -f, --format=TYPE     Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"Conntrack Selection\n"
+	" -i, --id=NUM            Identifier\n"
+	" -p, --proto=PROTOCOL    Protocol\n"
+	"     --tcp-state=STATE   TCP connection state\n"
+	"     --orig-src=ADDR     Original source address\n"
+	"     --orig-sport=PORT   Original source port\n"
+	"     --orig-dst=ADDR     Original destination address\n"
+	"     --orig-dport=PORT   Original destination port\n"
+	"     --reply-src=ADDR    Reply source address\n"
+	"     --reply-sport=PORT  Reply source port\n"
+	"     --reply-dst=ADDR    Reply destination address\n"
+	"     --reply-dport=PORT  Reply destination port\n"
+	" -F, --family=FAMILY     Address family\n"
+	"     --mark=NUM          Mark value\n"
+	"     --timeout=NUM       Timeout value\n"
+	"     --refcnt=NUM        Use counter value\n"
+	"     --flags             Flags\n"
+	);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct nl_cache *ct_cache;
+	struct nfnl_ct *ct;
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+ 
+ 	ct = nlt_alloc_ct();
+ 
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_MARK = 257,
+			ARG_TCP_STATE = 258,
+			ARG_ORIG_SRC,
+			ARG_ORIG_SPORT,
+			ARG_ORIG_DST,
+			ARG_ORIG_DPORT,
+			ARG_REPLY_SRC,
+			ARG_REPLY_SPORT,
+			ARG_REPLY_DST,
+			ARG_REPLY_DPORT,
+			ARG_TIMEOUT,
+			ARG_REFCNT,
+			ARG_FLAGS,
+		};
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "id", 1, 0, 'i' },
+			{ "proto", 1, 0, 'p' },
+			{ "tcp-state", 1, 0, ARG_TCP_STATE },
+			{ "orig-src", 1, 0, ARG_ORIG_SRC },
+			{ "orig-sport", 1, 0, ARG_ORIG_SPORT },
+			{ "orig-dst", 1, 0, ARG_ORIG_DST },
+			{ "orig-dport", 1, 0, ARG_ORIG_DPORT },
+			{ "reply-src", 1, 0, ARG_REPLY_SRC },
+			{ "reply-sport", 1, 0, ARG_REPLY_SPORT },
+			{ "reply-dst", 1, 0, ARG_REPLY_DST },
+			{ "reply-dport", 1, 0, ARG_REPLY_DPORT },
+			{ "family", 1, 0, 'F' },
+			{ "mark", 1, 0, ARG_MARK },
+			{ "timeout", 1, 0, ARG_TIMEOUT },
+			{ "refcnt", 1, 0, ARG_REFCNT },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case '?': exit(NLE_INVAL);
+		case '4': nfnl_ct_set_family(ct, AF_INET); break;
+		case '6': nfnl_ct_set_family(ct, AF_INET6); break;
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'i': parse_id(ct, optarg); break;
+		case 'p': parse_protocol(ct, optarg); break;
+		case ARG_TCP_STATE: parse_tcp_state(ct, optarg); break;
+		case ARG_ORIG_SRC: parse_src(ct, 0, optarg); break;
+		case ARG_ORIG_SPORT: parse_src_port(ct, 0, optarg); break;
+		case ARG_ORIG_DST: parse_dst(ct, 0, optarg); break;
+		case ARG_ORIG_DPORT: parse_dst_port(ct, 0, optarg); break;
+		case ARG_REPLY_SRC: parse_src(ct, 1, optarg); break;
+		case ARG_REPLY_SPORT: parse_src_port(ct, 1, optarg); break;
+		case ARG_REPLY_DST: parse_dst(ct, 1, optarg); break;
+		case ARG_REPLY_DPORT: parse_dst_port(ct, 1, optarg); break;
+		case 'F': parse_family(ct, optarg); break;
+		case ARG_MARK: parse_mark(ct, optarg); break;
+		case ARG_TIMEOUT: parse_timeout(ct, optarg); break;
+		case ARG_REFCNT: parse_use(ct, optarg); break;
+		case ARG_FLAGS: parse_status(ct, optarg); break;
+		}
+ 	}
+
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_NETFILTER);
+	ct_cache = nlt_alloc_ct_cache(sock);
+
+	nl_cache_dump_filter(ct_cache, &params, OBJ_CAST(ct));
+
+	return 0;
+}
diff --git a/src/nf-log.c b/src/nf-log.c
index d1f0ed6..d855efc 100644
--- a/src/nf-log.c
+++ b/src/nf-log.c
@@ -6,17 +6,12 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  */
 
-#include <sys/types.h>
-#include <linux/netfilter/nfnetlink_log.h>
-
-#include "utils.h"
-#include <netlink/netfilter/nfnl.h>
-#include <netlink/netfilter/log.h>
+#include "log-utils.h"
 
 static void obj_input(struct nl_object *obj, void *arg)
 {
@@ -40,25 +35,18 @@ static int event_input(struct nl_msg *msg, void *arg)
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nfnlh;
-	struct nl_handle *rtnlh;
+	struct nl_sock *nf_sock;
+	struct nl_sock *rt_sock;
         struct nl_cache *link_cache;
 	struct nfnl_log *log;
 	enum nfnl_log_copy_mode copy_mode;
 	uint32_t copy_range;
-	int err = 1;
+	int err;
 	int family;
 
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	nfnlh = nltool_alloc_handle();
-	if (nfnlh == NULL)
-		return -1;
-
-	nl_disable_sequence_check(nfnlh);
-
-	nl_socket_modify_cb(nfnlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+	nf_sock = nlt_alloc_socket();
+	nl_disable_sequence_check(nf_sock);
+	nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
 
 	if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
 		printf("Usage: nf-log family group [ copy_mode ] "
@@ -66,38 +54,26 @@ int main(int argc, char *argv[])
 		return 2;
 	}
 
-	if (nfnl_connect(nfnlh) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	nlt_connect(nf_sock, NETLINK_NETFILTER);
 
 	family = nl_str2af(argv[1]);
-	if (family == AF_UNSPEC) {
-		fprintf(stderr, "Unknown family: %s\n", argv[1]);
-		goto errout;
-	}
+	if (family == AF_UNSPEC)
+		fatal(NLE_INVAL, "Unknown family \"%s\": %s",
+		      argv[1], nl_geterror(family));
 
-	nfnl_log_pf_unbind(nfnlh, family);
-	if (nfnl_log_pf_bind(nfnlh, family) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
-
-	log = nfnl_log_alloc();
-	if (log == NULL) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	nfnl_log_pf_unbind(nf_sock, family);
+	if ((err = nfnl_log_pf_bind(nf_sock, family)) < 0)
+		fatal(err, "Unable to bind logger: %s", nl_geterror(err));
 
+	log = nlt_alloc_log();
 	nfnl_log_set_group(log, atoi(argv[2]));
 
 	copy_mode = NFNL_LOG_COPY_META;
 	if (argc > 3) {
 		copy_mode = nfnl_log_str2copy_mode(argv[3]);
-		if (copy_mode < 0) {
-			fprintf(stderr, "%s\n", nl_geterror());
-			goto errout;
-		}
+		if (copy_mode < 0)
+			fatal(copy_mode, "Unable to parse copy mode \"%s\": %s",
+			      argv[3], nl_geterror(copy_mode));
 	}
 	nfnl_log_set_copy_mode(log, copy_mode);
 
@@ -106,10 +82,8 @@ int main(int argc, char *argv[])
 		copy_mode = atoi(argv[4]);
 	nfnl_log_set_copy_range(log, copy_range);
 
-	if (nfnl_log_create(nfnlh, log) <0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	if ((err = nfnl_log_create(nf_sock, log)) < 0)
+		fatal(err, "Unable to bind instance: %s", nl_geterror(err));
 
 	{
 		struct nl_dump_params dp = {
@@ -122,22 +96,9 @@ int main(int argc, char *argv[])
 		nl_object_dump((struct nl_object *) log, &dp);
 	}
 
-	rtnlh = nltool_alloc_handle();
-	if (rtnlh == NULL) {
-		goto errout_close;
-	}
-
-	if (nl_connect(rtnlh, NETLINK_ROUTE) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
-
-	if ((link_cache = rtnl_link_alloc_cache(rtnlh)) == NULL) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_close;
-	}
-
-	nl_cache_mngt_provide(link_cache);
+	rt_sock = nlt_alloc_socket();
+	nlt_connect(rt_sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(rt_sock);
 
 	while (1) {
 		fd_set rfds;
@@ -145,35 +106,24 @@ int main(int argc, char *argv[])
 
 		FD_ZERO(&rfds);
 
-		maxfd = nffd = nl_socket_get_fd(nfnlh);
+		maxfd = nffd = nl_socket_get_fd(nf_sock);
 		FD_SET(nffd, &rfds);
 
-		rtfd = nl_socket_get_fd(rtnlh);
+		rtfd = nl_socket_get_fd(rt_sock);
 		FD_SET(rtfd, &rfds);
 		if (maxfd < rtfd)
 			maxfd = rtfd;
 
-		/* wait for an incoming message on the netlink socket */
+		/* wait for an incoming message on the netlink nf_socket */
 		retval = select(maxfd+1, &rfds, NULL, NULL, NULL);
 
 		if (retval) {
 			if (FD_ISSET(nffd, &rfds))
-				nl_recvmsgs_default(nfnlh);
+				nl_recvmsgs_default(nf_sock);
 			if (FD_ISSET(rtfd, &rfds))
-				nl_recvmsgs_default(rtnlh);
+				nl_recvmsgs_default(rt_sock);
 		}
 	}
 
-	nl_cache_mngt_unprovide(link_cache);
-	nl_cache_free(link_cache);
-
-	nfnl_log_put(log);
-
-	nl_close(rtnlh);
-	nl_handle_destroy(rtnlh);
-errout_close:
-	nl_close(nfnlh);
-	nl_handle_destroy(nfnlh);
-errout:
-	return err;
+	return 0;
 }
diff --git a/src/nf-monitor.c b/src/nf-monitor.c
index 2bc58c9..0113931 100644
--- a/src/nf-monitor.c
+++ b/src/nf-monitor.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  */
@@ -36,67 +36,58 @@ static int event_input(struct nl_msg *msg, void *arg)
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
-	int err = 1;
+	struct nl_sock *sock;
+	int err;
 	int i, idx;
 
 	static const struct {
 		enum nfnetlink_groups gr_id;
 		const char* gr_name;
-	} known_groups[] = {
+	} groups[] = {
 		{ NFNLGRP_CONNTRACK_NEW, "ct-new" },
 		{ NFNLGRP_CONNTRACK_UPDATE, "ct-update" },
 		{ NFNLGRP_CONNTRACK_DESTROY, "ct-destroy" },
 		{ NFNLGRP_NONE, NULL }
 	};
 
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	nlh = nltool_alloc_handle();
-	if (nlh == NULL)
-		return -1;
-
-	nl_disable_sequence_check(nlh);
-
-	nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+	sock = nlt_alloc_socket();
+	nl_disable_sequence_check(sock);
+	nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
 
 	if (argc > 1 && !strcasecmp(argv[1], "-h")) {
 		printf("Usage: nf-monitor [<groups>]\n");
 
 		printf("Known groups:");
-		for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++)
-			printf(" %s", known_groups[i].gr_name);
+		for (i = 0; groups[i].gr_id != NFNLGRP_NONE; i++)
+			printf(" %s", groups[i].gr_name);
 		printf("\n");
 		return 2;
 	}
 
-	if (nfnl_connect(nlh) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	nlt_connect(sock, NETLINK_NETFILTER);
 
 	for (idx = 1; argc > idx; idx++) {
-		for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++) {
-			if (!strcmp(argv[idx], known_groups[i].gr_name)) {
-
-				if (nl_socket_add_membership(nlh, known_groups[i].gr_id) < 0) {
-					fprintf(stderr, "%s: %s\n", argv[idx], nl_geterror());
-					goto errout;
-				}
-
-				break;
-			}
+		for (i = 0; groups[i].gr_id != NFNLGRP_NONE; i++) {
+			if (strcmp(argv[idx], groups[i].gr_name))
+				continue;
+
+			err = nl_socket_add_membership(sock, groups[i].gr_id);
+			if (err < 0)
+				fatal(err, "Unable to add membership: %s",
+				      nl_geterror(err));
+			break;
 		}
-		if (known_groups[i].gr_id == NFNLGRP_NONE)
-			fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]);
+
+		if (groups[i].gr_id == NFNLGRP_NONE)
+			fatal(NLE_OBJ_NOTFOUND, "Unknown group: \"%s\"",
+			      argv[idx]);
 	}
 
 	while (1) {
 		fd_set rfds;
 		int fd, retval;
 
-		fd = nl_socket_get_fd(nlh);
+		fd = nl_socket_get_fd(sock);
 
 		FD_ZERO(&rfds);
 		FD_SET(fd, &rfds);
@@ -105,11 +96,9 @@ int main(int argc, char *argv[])
 
 		if (retval) {
 			/* FD_ISSET(fd, &rfds) will be true */
-			nl_recvmsgs_default(nlh);
+			nl_recvmsgs_default(sock);
 		}
 	}
 
-	nl_close(nlh);
-errout:
-	return err;
+	return 0;
 }
diff --git a/src/nf-queue.c b/src/nf-queue.c
index 1420273..4e17f70 100644
--- a/src/nf-queue.c
+++ b/src/nf-queue.c
@@ -9,16 +9,10 @@
  * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
  */
 
-#include <sys/types.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nfnetlink_queue.h>
 
-#include "utils.h"
-#include <netlink/netfilter/nfnl.h>
-#include <netlink/netfilter/queue.h>
-#include <netlink/netfilter/queue_msg.h>
+#include "queue-utils.h"
 
-static struct nl_handle *nfnlh;
+static struct nl_sock *nf_sock;
 
 static void obj_input(struct nl_object *obj, void *arg)
 {
@@ -31,7 +25,7 @@ static void obj_input(struct nl_object *obj, void *arg)
 
 	nfnl_queue_msg_set_verdict(msg, NF_ACCEPT);
 	nl_object_dump(obj, &dp);
-	nfnl_queue_msg_send_verdict(nfnlh, msg);
+	nfnl_queue_msg_send_verdict(nf_sock, msg);
 }
 
 static int event_input(struct nl_msg *msg, void *arg)
@@ -45,7 +39,7 @@ static int event_input(struct nl_msg *msg, void *arg)
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *rtnlh;
+	struct nl_sock *rt_sock;
 	struct nl_cache *link_cache;
 	struct nfnl_queue *queue;
 	enum nfnl_queue_copy_mode copy_mode;
@@ -53,16 +47,9 @@ int main(int argc, char *argv[])
 	int err = 1;
 	int family;
 
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	nfnlh = nltool_alloc_handle();
-	if (nfnlh == NULL)
-		return -1;
-
-	nl_disable_sequence_check(nfnlh);
-
-	nl_socket_modify_cb(nfnlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+	nf_sock = nlt_alloc_socket();
+	nl_disable_sequence_check(nf_sock);
+	nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
 
 	if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
 		printf("Usage: nf-queue family group [ copy_mode ] "
@@ -70,38 +57,24 @@ int main(int argc, char *argv[])
 		return 2;
 	}
 
-	if (nfnl_connect(nfnlh) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	nlt_connect(nf_sock, NETLINK_NETFILTER);
 
-	family = nl_str2af(argv[1]);
-	if (family == AF_UNSPEC) {
-		fprintf(stderr, "Unknown family: %s\n", argv[1]);
-		goto errout;
-	}
+	if ((family = nl_str2af(argv[1])) == AF_UNSPEC)
+		fatal(NLE_INVAL, "Unknown family \"%s\"", argv[1]);
 
-	nfnl_queue_pf_unbind(nfnlh, family);
-	if (nfnl_queue_pf_bind(nfnlh, family) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
-
-	queue = nfnl_queue_alloc();
-	if (queue == NULL) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	nfnl_queue_pf_unbind(nf_sock, family);
+	if ((err = nfnl_queue_pf_bind(nf_sock, family)) < 0)
+		fatal(err, "Unable to bind logger: %s", nl_geterror(err));
 
+	queue = nlt_alloc_queue();
 	nfnl_queue_set_group(queue, atoi(argv[2]));
 
 	copy_mode = NFNL_QUEUE_COPY_PACKET;
 	if (argc > 3) {
 		copy_mode = nfnl_queue_str2copy_mode(argv[3]);
-		if (copy_mode < 0) {
-			fprintf(stderr, "%s\n", nl_geterror());
-			goto errout;
-		}
+		if (copy_mode < 0)
+			fatal(copy_mode, "Unable to parse copy mode \"%s\": %s",
+			      argv[3], nl_geterror(copy_mode));
 	}
 	nfnl_queue_set_copy_mode(queue, copy_mode);
 
@@ -110,27 +83,12 @@ int main(int argc, char *argv[])
 		copy_range = atoi(argv[4]);
 	nfnl_queue_set_copy_range(queue, copy_range);
 
-	if (nfnl_queue_create(nfnlh, queue) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	if ((err = nfnl_queue_create(nf_sock, queue)) < 0)
+		fatal(err, "Unable to bind queue: %s", nl_geterror(err));
 
-	rtnlh = nltool_alloc_handle();
-	if (rtnlh == NULL) {
-		goto errout_close;
-	}
-
-	if (nl_connect(rtnlh, NETLINK_ROUTE) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
-
-	if ((link_cache = rtnl_link_alloc_cache(rtnlh)) == NULL) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_close;
-	}
-
-	nl_cache_mngt_provide(link_cache);
+	rt_sock = nlt_alloc_socket();
+	nlt_connect(rt_sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(rt_sock);
 
 	while (1) {
 		fd_set rfds;
@@ -138,10 +96,10 @@ int main(int argc, char *argv[])
 
 		FD_ZERO(&rfds);
 
-		maxfd = nffd = nl_socket_get_fd(nfnlh);
+		maxfd = nffd = nl_socket_get_fd(nf_sock);
 		FD_SET(nffd, &rfds);
 
-		rtfd = nl_socket_get_fd(rtnlh);
+		rtfd = nl_socket_get_fd(rt_sock);
 		FD_SET(rtfd, &rfds);
 		if (maxfd < rtfd)
 			maxfd = rtfd;
@@ -151,22 +109,11 @@ int main(int argc, char *argv[])
 
 		if (retval) {
 			if (FD_ISSET(nffd, &rfds))
-				nl_recvmsgs_default(nfnlh);
+				nl_recvmsgs_default(nf_sock);
 			if (FD_ISSET(rtfd, &rfds))
-				nl_recvmsgs_default(rtnlh);
+				nl_recvmsgs_default(rt_sock);
 		}
 	}
 
-	nl_cache_mngt_unprovide(link_cache);
-	nl_cache_free(link_cache);
-
-	nfnl_queue_put(queue);
-
-	nl_close(rtnlh);
-	nl_handle_destroy(rtnlh);
-errout_close:
-	nl_close(nfnlh);
-	nl_handle_destroy(nfnlh);
-errout:
-	return err;
+	return 0;
 }
diff --git a/src/nl-fib-lookup.c b/src/nl-fib-lookup.c
index 5bbf91e..2507be8 100644
--- a/src/nl-fib-lookup.c
+++ b/src/nl-fib-lookup.c
@@ -37,9 +37,6 @@ int main(int argc, char *argv[])
 	int tos = 0, err = 1;
 	uint64_t fwmark = 0;
 
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
 	while (1) {
 		static struct option long_opts[] = {
 			{"table", 1, 0, 't'},
@@ -76,24 +73,19 @@ int main(int argc, char *argv[])
 	if (optind >= argc)
 		print_usage();
 
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
+	nlh = nlt_alloc_socket();
 
-	addr = nl_addr_parse(argv[optind], AF_INET);
-	if (!addr) {
-		fprintf(stderr, "Unable to parse address \"%s\": %s\n",
-			argv[optind], nl_geterror());
-		goto errout;
-	}
+	if ((err = nl_addr_parse(argv[optind], AF_INET, &addr)) < 0)
+		fatal(err, "Unable to parse address \"%s\": %s\n",
+			argv[optind], nl_geterror(err));
 
 	result = flnl_result_alloc_cache();
 	if (!result)
-		goto errout_addr;
+		fatal(ENOMEM, "Unable to allocate cache");
 
 	request = flnl_request_alloc();
 	if (!request)
-		goto errout_result;
+		fatal(ENOMEM, "Unable to allocate request");
 
 	flnl_request_set_table(request, table);
 	flnl_request_set_fwmark(request, fwmark);
@@ -103,28 +95,15 @@ int main(int argc, char *argv[])
 	err = flnl_request_set_addr(request, addr);
 	nl_addr_put(addr);
 	if (err < 0)
-		goto errout_put;
+		fatal(err, "Unable to send request: %s", nl_geterror(err));
 
-	if (nltool_connect(nlh, NETLINK_FIB_LOOKUP) < 0)
-		goto errout_put;
+	nlt_connect(nlh, NETLINK_FIB_LOOKUP);
 
 	err = flnl_lookup(nlh, request, result);
-	if (err < 0) {
-		fprintf(stderr, "Unable to lookup: %s\n", nl_geterror());
-		goto errout_put;
-	}
+	if (err < 0)
+		fatal(err, "Unable to lookup: %s\n", nl_geterror(err));
 
 	nl_cache_dump(result, &params);
 
-	err = 0;
-errout_put:
-	nl_object_put(OBJ_CAST(request));
-errout_result:
-	nl_cache_free(result);
-errout_addr:
-	nl_addr_put(addr);
-errout:
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
-	return err;
+	return 0;
 }
diff --git a/src/nl-link-dump.c b/src/nl-link-dump.c
deleted file mode 100644
index 0214025..0000000
--- a/src/nl-link-dump.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * src/nl-link-dump.c	Dump link attributes
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-
-static void print_usage(void)
-{
-	printf(
-	"Usage: nl-link-dump <mode> [<filter>]\n"
-	"  mode := { brief | detailed | stats | xml }\n"
-	"  filter := [dev DEV] [mtu MTU] [txqlen TXQLEN] [weight WEIGHT] [link LINK]\n"
-	"            [master MASTER] [qdisc QDISC] [addr ADDR] [broadcast BRD]\n"
-	"            [{ up | down }] [{ arp | noarp }] [{ promisc | nopromisc }]\n"
-	"            [{ dynamic | nodynamic }] [{ multicast | nomulticast }]\n"
-	"            [{ trailers | notrailers }] [{ allmulticast | noallmulticast }]\n");
-	exit(1);
-}
-
-#include "f_link.c"
-
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct nl_cache *link_cache;
-	struct rtnl_link *link;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF
-	};
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	link = rtnl_link_alloc();
-	if (!link)
-		goto errout;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_put;
-
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout_put;
-
-	params.dp_type = nltool_parse_dumptype(argv[1]);
-	if (params.dp_type < 0)
-		goto errout_put;
-
-	get_filter(link, argc, argv, 2, link_cache);
-	nl_cache_dump_filter(link_cache, &params, (struct nl_object *) link);
-	nl_cache_free(link_cache);
-	err = 0;
-errout_put:
-	rtnl_link_put(link);
-errout:
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
-	return err;
-}
diff --git a/src/nl-link-ifindex2name.c b/src/nl-link-ifindex2name.c
index e1043fb..109ec46 100644
--- a/src/nl-link-ifindex2name.c
+++ b/src/nl-link-ifindex2name.c
@@ -6,50 +6,37 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #include "utils.h"
 
-int main(int argc, char **argv)
+static void print_usage(void)
 {
-	struct nl_handle *nlh;
-	struct nl_cache *link_cache;
-	int err = -1, ifindex;
-	char dst[32] = {0};
-	const char *name;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h")) {
-		fprintf(stderr, "Usage: nl-link-ifindex2name <ifindex>\n");
-		return -1;
-	}
+	printf("Usage: nl-link-ifindex2name <ifindex>\n");
+	exit(0);
+}
 
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct nl_cache *link_cache;
+	char name[IFNAMSIZ];
+	uint32_t ifindex;
 
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout;
+	if (argc < 2)
+		print_usage();
 
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout;
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
 
-	ifindex = strtoul(argv[1], NULL, 0);
+	ifindex = parse_u32(argv[1]);
 
-	if (!(name = rtnl_link_i2name(link_cache, ifindex, dst, sizeof(dst))))
-		fprintf(stderr, "Interface index %d does not exist\n", ifindex);
-	else
-		printf("%s\n", name);
+	if (!rtnl_link_i2name(link_cache, ifindex, name, sizeof(name)))
+		fatal(ENOENT, "Interface index %d does not exist", ifindex);
 
-	nl_cache_free(link_cache);
-	err = 0;
-errout:
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
+	printf("%s\n", name);
 
-	return err;
+	return 0;
 }
diff --git a/src/nl-link-list.c b/src/nl-link-list.c
new file mode 100644
index 0000000..3afa5ed
--- /dev/null
+++ b/src/nl-link-list.c
@@ -0,0 +1,105 @@
+/*
+ * src/nl-link-dump.c	Dump link attributes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#if 0
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-link-dump <mode> [<filter>]\n"
+	"  mode := { brief | detailed | stats | xml }\n"
+	"  filter := [dev DEV] [mtu MTU] [txqlen TXQLEN] [weight WEIGHT] [link LINK]\n"
+	"            [master MASTER] [qdisc QDISC] [addr ADDR] [broadcast BRD]\n"
+	"            [{ up | down }] [{ arp | noarp }] [{ promisc | nopromisc }]\n"
+	"            [{ dynamic | nodynamic }] [{ multicast | nomulticast }]\n"
+	"            [{ trailers | notrailers }] [{ allmulticast | noallmulticast }]\n");
+	exit(1);
+}
+#endif
+
+#include "link-utils.h"
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-link-list [OPTION]... [Link]\n"
+	"\n"
+	"Options\n"
+	" -f, --format=TYPE     Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"Link Options\n"
+	" -n, --name=NAME	link name\n"
+	" -i, --index           interface index\n"
+	"     --mtu=NUM         MTU value\n"
+	"     --txqlen=NUM      TX queue length\n"
+	"     --weight=NUM      weight\n"
+	);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct nl_cache *link_cache;
+	struct rtnl_link *link;
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	link = nlt_alloc_link();
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_FAMILY = 257,
+			ARG_MTU = 258,
+			ARG_TXQLEN,
+			ARG_WEIGHT,
+		};
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "name", 1, 0, 'n' },
+			{ "index", 1, 0, 'i' },
+			{ "family", 1, 0, ARG_FAMILY },
+			{ "mtu", 1, 0, ARG_MTU },
+			{ "txqlen", 1, 0, ARG_TXQLEN },
+			{ "weight", 1, 0, ARG_WEIGHT },
+			{ 0, 0, 0, 0 }
+		};
+
+		c = getopt_long(argc, argv, "f:hvn:i:", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'n': parse_name(link, optarg); break;
+		case 'i': parse_ifindex(link, optarg); break;
+		case ARG_FAMILY: parse_family(link, optarg); break;
+		case ARG_MTU: parse_mtu(link, optarg); break;
+		case ARG_TXQLEN: parse_txqlen(link, optarg); break;
+		case ARG_WEIGHT: parse_weight(link, optarg); break;
+		}
+	}
+
+	nl_cache_dump_filter(link_cache, &params, OBJ_CAST(link));
+
+	return 0;
+}
diff --git a/src/nl-link-name2ifindex.c b/src/nl-link-name2ifindex.c
index 993397d..12a61c6 100644
--- a/src/nl-link-name2ifindex.c
+++ b/src/nl-link-name2ifindex.c
@@ -6,46 +6,34 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #include "utils.h"
 
+static void print_usage(void)
+{
+	printf("Usage: nl-link-ifindex2name <ifindex>\n");
+	exit(0);
+}
+
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
+	struct nl_sock *sock;
 	struct nl_cache *link_cache;
-	int err = -1, ifindex;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h")) {
-		printf("Usage: nl-link-name2ifindex <name>\n");
-		return -1;
-	}
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
+	uint32_t ifindex;
 
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout;
+	if (argc < 2)
+		print_usage();
 
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout;
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
 
-	if ((ifindex = rtnl_link_name2i(link_cache, argv[1])) == RTNL_LINK_NOT_FOUND)
-		fprintf(stderr, "Interface %s does not exist\n", argv[1]);
-	else
-		printf("%d\n", ifindex);
+	if (!(ifindex = rtnl_link_name2i(link_cache, argv[1])))
+		fatal(ENOENT, "Interface \"%s\" does not exist", argv[1]);
 
-	nl_cache_free(link_cache);
-	err = 0;
-errout:
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
+	printf("%u\n", ifindex);
 
-	return err;
+	return 0;
 }
diff --git a/src/nl-link-set.c b/src/nl-link-set.c
index 1872301..02c35d6 100644
--- a/src/nl-link-set.c
+++ b/src/nl-link-set.c
@@ -6,78 +6,117 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "utils.h"
+#include "link-utils.h"
 
-static void print_usage(void)
-{
-	printf(
-	"Usage: nl-link-set <ifindex> <changes>\n"
-	"  changes := [dev DEV] [mtu MTU] [txqlen TXQLEN] [weight WEIGHT] [link LINK]\n"
+static struct nl_sock *sock;
+static int quiet = 0;
+
+#if 0
+	"  changes := [link LINK]\n"
 	"             [master MASTER] [qdisc QDISC] [addr ADDR] [broadcast BRD]\n"
 	"             [{ up | down }] [{ arp | noarp }] [{ promisc | nopromisc }]\n"
 	"             [{ dynamic | nodynamic }] [{ multicast | nomulticast }]\n"
 	"             [{ trailers | notrailers }] [{ allmulticast | noallmulticast }]\n");
-	exit(1);
+#endif
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-link-set [OPTION]... [LINK]\n"
+	"\n"
+	"Options\n"
+	" -q, --quiet		Do not print informal notifications\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"Selecting the Link\n"
+	" -n, --name=NAME	link name\n"
+	" -i, --index           interface index\n"
+	"Change Options\n"
+	"     --rename=NAME     rename interface\n"
+	"     --mtu=NUM         MTU value\n"
+	"     --txqlen=NUM      TX queue length\n"
+	"     --weight=NUM      weight\n"
+	);
+	exit(0);
 }
 
-#include "f_link.c"
+static void set_cb(struct nl_object *obj, void *arg)
+{
+	struct rtnl_link *link = nl_object_priv(obj);
+	struct rtnl_link *change = arg;
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+	int err;
+
+	if ((err = rtnl_link_change(sock, link, change, 0) < 0))
+		fatal(err, "Unable to change link: %s", nl_geterror(err));
+
+	if (!quiet) {
+		printf("Changed ");
+		nl_object_dump(OBJ_CAST(link), &params);
+	}
+}
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
 	struct nl_cache *link_cache;
-	struct rtnl_link *link, *orig;
-	int err = 1, ifindex;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	link = rtnl_link_alloc();
-	if (!link)
-		goto errout;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_free;
-
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout_close;
-
-	ifindex = strtoul(argv[1], NULL, 0);
-
-	if (!(orig = rtnl_link_get(link_cache, ifindex))) {
-		fprintf(stderr, "Interface index %d does not exist\n", ifindex);
-		goto errout_cache;
+	struct rtnl_link *link, *change;
+	int ok = 0;
+
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	link = nlt_alloc_link();
+	change = nlt_alloc_link();
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_RENAME = 257,
+			ARG_MTU = 258,
+			ARG_TXQLEN,
+			ARG_WEIGHT,
+		};
+		static struct option long_opts[] = {
+			{ "quiet", 0, 0, 'q' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "name", 1, 0, 'n' },
+			{ "index", 1, 0, 'i' },
+			{ "rename", 1, 0, ARG_RENAME },
+			{ "mtu", 1, 0, ARG_MTU },
+			{ "txqlen", 1, 0, ARG_TXQLEN },
+			{ "weight", 1, 0, ARG_WEIGHT },
+			{ 0, 0, 0, 0 }
+		};
+
+		c = getopt_long(argc, argv, "qhvn:i:", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'q': quiet = 1; break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'n': ok++; parse_name(link, optarg); break;
+		case 'i': ok++; parse_ifindex(link, optarg); break;
+		case ARG_RENAME: parse_name(change, optarg); break;
+		case ARG_MTU: parse_mtu(link, optarg); break;
+		case ARG_TXQLEN: parse_txqlen(link, optarg); break;
+		case ARG_WEIGHT: parse_weight(link, optarg); break;
+		}
 	}
 
-	get_filter(link, argc, argv, 2, link_cache);
-
-	if (rtnl_link_change(nlh, orig, link, 0) < 0) {
-		fprintf(stderr, "Unable to change link: %s\n", nl_geterror());
-		goto errout_put;
-	}
+	if (!ok)
+		print_usage();
 
-	err = 0;
+	nl_cache_foreach_filter(link_cache, OBJ_CAST(link), set_cb, change);
 
-errout_put:
-	rtnl_link_put(orig);
-errout_cache:
-	nl_cache_free(link_cache);
-errout_close:
-	nl_close(nlh);
-errout_free:
-	rtnl_link_put(link);
-errout:
-	nl_handle_destroy(nlh);
-	return err;
+	return 0;
 }
diff --git a/src/nl-link-stats.c b/src/nl-link-stats.c
index 8a9200e..9203e08 100644
--- a/src/nl-link-stats.c
+++ b/src/nl-link-stats.c
@@ -6,31 +6,45 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "utils.h"
+#include "link-utils.h"
 
 static void print_usage(void)
 {
 	printf(
-"Usage: nl-link-stats <ifindex> [<statistic> ...]\n"
-"  ifindex   := { all | number }\n"
-"  statistic := { (rx|tx)_packets | (rx|tx)_bytes | (rx|tx)_errors |\n"
-"                 (rx|tx)_dropped | (rx|tx)_compressed | (rx|tx)_fifo_err |\n" \
-"                 rx_len_err | rx_over_err | rx_crc_err | rx_frame_err |\n"
-"                 rx_missed_err | tx_abort_err | tx_carrier_err |\n"
-"                 tx_hbeat_err | tx_win_err | tx_collision | multicast }\n");
-	exit(1);
+	"Usage: nl-link-stats [OPTION]... [LINK] [ListOfStats]\n"
+	"\n"
+	"Options\n"
+	" -l, --list            List available statistic names\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"Link Options\n"
+	" -n, --name=NAME	link name\n"
+	" -i, --index=NUM       interface index\n"
+	);
+	exit(0);
+}
+
+static void list_stat_names(void)
+{
+	char buf[64];
+	int i;
+
+	for (i = 0; i < RTNL_LINK_STATS_MAX; i++)
+		printf("%s\n", rtnl_link_stat2str(i, buf, sizeof(buf)));
+
+	exit(0);
 }
 
-static char **gargv;
 static int gargc;
 
 static void dump_stat(struct rtnl_link *link, int id)
 {
 	uint64_t st = rtnl_link_get_stat(link, id);
-	char buf[62];
+	char buf[64];
 
 	printf("%s.%s %" PRIu64 "\n", rtnl_link_get_name(link),
 	       rtnl_link_stat2str(id, buf, sizeof(buf)), st);
@@ -38,72 +52,67 @@ static void dump_stat(struct rtnl_link *link, int id)
 
 static void dump_stats(struct nl_object *obj, void *arg)
 {
-	int i;
 	struct rtnl_link *link = (struct rtnl_link *) obj;
+	char **argv = arg;
+
+	if (optind >= gargc) {
+		int i;
 
-	if (!strcasecmp(gargv[0], "all")) {
 		for (i = 0; i < RTNL_LINK_STATS_MAX; i++)
 			dump_stat(link, i);
 	} else {
-		for (i = 0; i < gargc; i++) {
-			int id = rtnl_link_str2stat(gargv[i]);
+		while (optind < gargc) {
+			int id = rtnl_link_str2stat(argv[optind]);
 
 			if (id < 0)
 				fprintf(stderr, "Warning: Unknown statistic "
-					"\"%s\"\n", gargv[i]);
+					"\"%s\"\n", argv[optind]);
 			else
 				dump_stat(link, id);
+
+			optind++;
 		}
 	}
 }
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
+	struct nl_sock *sock;
 	struct nl_cache *link_cache;
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 3 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout;
-
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout_close;
-
-	gargv = &argv[2];
-	gargc = argc - 2;
-
-	if (!strcasecmp(argv[1], "all"))
-		nl_cache_foreach(link_cache, dump_stats, NULL);
-	else {
-		int ifindex = strtoul(argv[1], NULL, 0);
-		struct rtnl_link *link = rtnl_link_get(link_cache, ifindex);
-
-		if (!link) {
-			fprintf(stderr, "Could not find ifindex %d\n", ifindex);
-			goto errout_link_cache;
+	struct rtnl_link *link;
+
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	link = nlt_alloc_link();
+
+	for (;;) {
+		int c, optidx = 0;
+		static struct option long_opts[] = {
+			{ "list", 0, 0, 'l' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "name", 1, 0, 'n' },
+			{ "index", 1, 0, 'i' },
+			{ 0, 0, 0, 0 }
+		};
+
+		c = getopt_long(argc, argv, "lhvn:i:", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'l': list_stat_names(); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'n': parse_name(link, optarg); break;
+		case 'i': parse_ifindex(link, optarg); break;
 		}
-
-		dump_stats((struct nl_object *) link, NULL);
-		rtnl_link_put(link);
 	}
 
-	err = 0;
-errout_link_cache:
-	nl_cache_free(link_cache);
-errout_close:
-	nl_close(nlh);
-errout:
-	nl_handle_destroy(nlh);
-	return err;
+	gargc = argc;
+	nl_cache_foreach_filter(link_cache, OBJ_CAST(link), dump_stats, argv);
+
+	return 0;
 }
+
diff --git a/src/nl-monitor.c b/src/nl-monitor.c
index 9f21dbb..520ac37 100644
--- a/src/nl-monitor.c
+++ b/src/nl-monitor.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #include "utils.h"
@@ -35,7 +35,7 @@ static int event_input(struct nl_msg *msg, void *arg)
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
+	struct nl_sock *sock;
 	struct nl_cache *link_cache;
 	int err = 1;
 	int i, idx;
@@ -61,16 +61,9 @@ int main(int argc, char *argv[])
 		{ RTNLGRP_NONE, NULL }
 	};
 
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	nlh = nltool_alloc_handle();
-	if (nlh == NULL)
-		return -1;
-
-	nl_disable_sequence_check(nlh);
-
-	nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+	sock = nlt_alloc_socket();
+	nl_disable_sequence_check(sock);
+	nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
 
 	if (argc > 1 && !strcasecmp(argv[1], "-h")) {
 		printf("Usage: nl-monitor [<groups>]\n");
@@ -82,18 +75,14 @@ int main(int argc, char *argv[])
 		return 2;
 	}
 
-	if (nl_connect(nlh, NETLINK_ROUTE) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout;
-	}
+	nlt_connect(sock, NETLINK_ROUTE);
 
 	for (idx = 1; argc > idx; idx++) {
 		for (i = 0; known_groups[i].gr_id != RTNLGRP_NONE; i++) {
 			if (!strcmp(argv[idx], known_groups[i].gr_name)) {
 
-				if (nl_socket_add_membership(nlh, known_groups[i].gr_id) < 0) {
-					fprintf(stderr, "%s: %s\n", argv[idx], nl_geterror());
-					goto errout;
+				if ((err = nl_socket_add_membership(sock, known_groups[i].gr_id)) < 0) {
+					fatal(err, "%s: %s\n", argv[idx], nl_geterror(err));
 				}
 
 				break;
@@ -103,18 +92,13 @@ int main(int argc, char *argv[])
 			fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]);
 	}
 
-	if ((link_cache = rtnl_link_alloc_cache(nlh)) == NULL) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_close;
-	}
-
-	nl_cache_mngt_provide(link_cache);
+	link_cache = nlt_alloc_link_cache(sock);
 
 	while (1) {
 		fd_set rfds;
 		int fd, retval;
 
-		fd = nl_socket_get_fd(nlh);
+		fd = nl_socket_get_fd(sock);
 
 		FD_ZERO(&rfds);
 		FD_SET(fd, &rfds);
@@ -123,13 +107,9 @@ int main(int argc, char *argv[])
 
 		if (retval) {
 			/* FD_ISSET(fd, &rfds) will be true */
-			nl_recvmsgs_default(nlh);
+			nl_recvmsgs_default(sock);
 		}
 	}
 
-	nl_cache_free(link_cache);
-errout_close:
-	nl_close(nlh);
-errout:
-	return err;
+	return 0;
 }
diff --git a/src/nl-neigh-add.c b/src/nl-neigh-add.c
index 14b99de..b222c7a 100644
--- a/src/nl-neigh-add.c
+++ b/src/nl-neigh-add.c
@@ -6,74 +6,102 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "utils.h"
+#include "neigh-utils.h"
 
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct rtnl_neigh *neigh;
-	struct nl_addr *addr;
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 4 || !strcmp(argv[1], "-h")) {
-		printf("Usage: nl-neigh-add <addr> <lladdr> "
-		       "<ifindex> [<state>]\n");
-		return 1;
-	}
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	neigh = rtnl_neigh_alloc();
-	if (!neigh)
-		goto errout;
+static int quiet = 0;
 
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_free;
-
-	addr = nltool_addr_parse(argv[1]);
-	if (!addr)
-		goto errout_close;
-	rtnl_neigh_set_dst(neigh, addr);
-	nl_addr_put(addr);
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-neigh-add [OPTION]... NEIGHBOUR\n"
+	"\n"
+	"Options\n"
+	"     --update-only     Do not create neighbour, updates exclusively\n"
+	"     --create-only     Do not update neighbour if it exists already.\n"
+	" -q, --quiet           Do not print informal notifications\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"Neighbour Options\n"
+	" -a, --addr=ADDR       Destination address of neighbour\n"
+	" -l, --lladdr=ADDR     Link layer address of neighbour\n"
+	" -d, --dev=DEV         Device the neighbour is connected to\n"
+	"     --state=STATE     Neighbour state, (default = permanent)\n"
+	"\n"
+	"Example\n"
+	"  nl-neigh-add --create-only --addr=10.0.0.1 --dev=eth0 \\\n"
+	"               --lladdr=AA:BB:CC:DD:EE:FF\n"
+	);
 
-	addr = nltool_addr_parse(argv[2]);
-	if (!addr)
-		goto errout_close;
-	rtnl_neigh_set_lladdr(neigh, addr);
-	nl_addr_put(addr);
+	exit(0);
+}
 
-	rtnl_neigh_set_ifindex(neigh, strtoul(argv[3], NULL, 0));
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct rtnl_neigh *neigh;
+	struct nl_cache *link_cache;
+	struct nl_dump_params dp = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+	int err, ok = 0, nlflags = NLM_F_REPLACE | NLM_F_CREATE;
+ 
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+ 	neigh = nlt_alloc_neigh();
+ 
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_UPDATE_ONLY = 257,
+			ARG_CREATE_ONLY = 258,
+			ARG_STATE,
+		};
+		static struct option long_opts[] = {
+			{ "update-only", 0, 0, ARG_UPDATE_ONLY },
+			{ "create-only", 0, 0, ARG_CREATE_ONLY },
+			{ "quiet", 0, 0, 'q' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "addr", 1, 0, 'a' },
+			{ "lladdr", 1, 0, 'l' },
+			{ "dev", 1, 0, 'd' },
+			{ "state", 1, 0, ARG_STATE },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx);
+		if (c == -1)
+			break;
 
-	if (argc > 4) {
-		int state = rtnl_neigh_str2state(argv[4]);
-		if (state < 0) {
-			fprintf(stderr, "Unknown state \"%s\"\n", argv[4]);
-			goto errout_close;
+		switch (c) {
+		case ARG_UPDATE_ONLY: nlflags &= ~NLM_F_CREATE; break;
+		case ARG_CREATE_ONLY: nlflags |= NLM_F_EXCL; break;
+		case 'q': quiet = 1; break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'a': ok++; parse_dst(neigh, optarg); break;
+		case 'l': parse_lladdr(neigh, optarg); break;
+		case 'd': parse_dev(neigh, link_cache, optarg); break;
+		case ARG_STATE: parse_state(neigh, optarg); break;
 		}
-		rtnl_neigh_set_state(neigh, state);
-	} else
-		rtnl_neigh_set_state(neigh, NUD_PERMANENT);
+ 	}
+
+	if (!ok)
+		print_usage();
 
-	if (rtnl_neigh_add(nlh, neigh, 0) < 0) {
-		fprintf(stderr, "Unable to add address: %s\n", nl_geterror());
-		goto errout_close;
-	}
+	if ((err = rtnl_neigh_add(sock, neigh, nlflags)) < 0)
+		fatal(err, "Unable to add neighbour: %s", nl_geterror(err));
 
-	err = 0;
+	if (!quiet) {
+		printf("Added ");
+		nl_object_dump(OBJ_CAST(neigh), &dp);
+ 	}
 
-errout_close:
-	nl_close(nlh);
-errout_free:
-	rtnl_neigh_put(neigh);
-errout:
-	nl_handle_destroy(nlh);
-	return err;
+	return 0;
 }
diff --git a/src/nl-neigh-delete.c b/src/nl-neigh-delete.c
index 7829d34..c9facb9 100644
--- a/src/nl-neigh-delete.c
+++ b/src/nl-neigh-delete.c
@@ -6,61 +6,114 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "utils.h"
+#include "neigh-utils.h"
 
-int main(int argc, char *argv[])
+static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
+struct nl_sock *sock;
+
+static void print_usage(void)
 {
-	struct nl_handle *nlh;
-	struct rtnl_neigh *neigh;
-	struct nl_addr *addr;
-	int err = 1;
+	printf(
+	"Usage: nl-neigh-delete [OPTION]... [NEIGHBOUR]\n"
+	"\n"
+	"Options\n"
+	" -i, --interactive     Run interactively\n"
+	"     --yes             Set default answer to yes\n"
+	" -q, --quiet           Do not print informal notifications\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"Neighbour Options\n"
+	" -a, --addr=ADDR       Destination address of neighbour\n"
+	" -l, --lladdr=ADDR     Link layer address of neighbour\n"
+	" -d, --dev=DEV         Device the neighbour is connected to\n"
+	"     --family=FAMILY   Destination address family\n"
+	"     --state=STATE     Neighbour state, (default = permanent)\n"
+	);
 
-	if (nltool_init(argc, argv) < 0)
-		return -1;
+	exit(0);
+}
 
-	if (argc < 3 || !strcmp(argv[1], "-h")) {
-		printf("Usage: nl-neigh-delete <addr> <ifindex>\n");
-		return 2;
-	}
+static void delete_cb(struct nl_object *obj, void *arg)
+{
+	struct rtnl_neigh *neigh = nl_object_priv(obj);
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+	int err;
 
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
+	if (interactive && !nlt_confirm(obj, &params, default_yes))
+		return;
 
-	neigh = rtnl_neigh_alloc();
-	if (neigh == NULL)
-		goto errout;
+	if ((err = rtnl_neigh_delete(sock, neigh, 0)) < 0)
+		fatal(err, "Unable to delete neighbour: %s\n", nl_geterror(err));
 
-	if (nl_connect(nlh, NETLINK_ROUTE) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_free;
+	if (!quiet) {
+		printf("Deleted ");
+		nl_object_dump(obj, &params);
 	}
 
-	addr = nl_addr_parse(argv[1], AF_UNSPEC);
-	if (addr == NULL) {
-		fprintf(stderr, "Invalid address \"%s\"\n", argv[1]);
-		goto errout_close;
-	}
-	rtnl_neigh_set_dst(neigh, addr);
-	nl_addr_put(addr);
+	deleted++;
+}
+
+int main(int argc, char *argv[])
+{
+	struct rtnl_neigh *neigh;
+	struct nl_cache *link_cache, *neigh_cache;
+ 
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	neigh_cache = nlt_alloc_neigh_cache(sock);
+ 	neigh = nlt_alloc_neigh();
+ 
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_FAMILY = 257,
+			ARG_STATE = 258,
+			ARG_YES,
+		};
+		static struct option long_opts[] = {
+			{ "interactive", 0, 0, 'i' },
+			{ "yes", 0, 0, ARG_YES },
+			{ "quiet", 0, 0, 'q' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "addr", 1, 0, 'a' },
+			{ "lladdr", 1, 0, 'l' },
+			{ "dev", 1, 0, 'd' },
+			{ "family", 1, 0, ARG_FAMILY },
+			{ "state", 1, 0, ARG_STATE },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx);
+		if (c == -1)
+			break;
 
-	rtnl_neigh_set_ifindex(neigh, strtoul(argv[2], NULL, 0));
+		switch (c) {
+		case 'i': interactive = 1; break;
+		case ARG_YES: default_yes = 1; break;
+		case 'q': quiet = 1; break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'a': parse_dst(neigh, optarg); break;
+		case 'l': parse_lladdr(neigh, optarg); break;
+		case 'd': parse_dev(neigh, link_cache, optarg); break;
+		case ARG_FAMILY: parse_family(neigh, optarg); break;
+		case ARG_STATE: parse_state(neigh, optarg); break;
+		}
+ 	}
 
-	if (rtnl_neigh_delete(nlh, neigh, 0) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_close;
-	}
+	nl_cache_foreach_filter(neigh_cache, OBJ_CAST(neigh), delete_cb, NULL);
 
-	err = 0;
+	if (!quiet)
+		printf("Deleted %d neighbours\n", deleted);
 
-errout_close:
-	nl_close(nlh);
-errout_free:
-	rtnl_neigh_put(neigh);
-errout:
-	nl_handle_destroy(nlh);
-	return err;
+	return 0;
 }
diff --git a/src/nl-neigh-dump.c b/src/nl-neigh-dump.c
deleted file mode 100644
index 4553f2e..0000000
--- a/src/nl-neigh-dump.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * src/nl-neigh-dump.c     Dump neighbour attributes
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-
-static void print_usage(void)
-{
-	printf(
-	"Usage: nl-neigh-dump <mode> [<filter>]\n"
-	"  mode := { brief | detailed | stats | xml }\n"
-	"  filter := [dev DEV] [dst ADDR] [lladdr ADDR]\n");
-	exit(1);
-}
-
-#include "f_neigh.c"
-
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct nl_cache *link_cache, *neigh_cache;
-	struct rtnl_neigh *neigh;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF
-	};
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		print_usage();
-	
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	neigh = rtnl_neigh_alloc();
-	if (neigh == NULL)
-		goto errout;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_free;
-
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout_close;
-
-	neigh_cache = nltool_alloc_neigh_cache(nlh);
-	if (!neigh_cache)
-		goto errout_link_cache;
-
-	params.dp_type = nltool_parse_dumptype(argv[1]);
-	if (params.dp_type < 0)
-		goto errout_neigh_cache;
-
-	get_filter(neigh, argc, argv, 2, neigh_cache);
-
-	nl_cache_dump_filter(neigh_cache, &params, (struct nl_object *) neigh);
-
-	err = 0;
-
-errout_neigh_cache:
-	nl_cache_free(neigh_cache);
-errout_link_cache:
-	nl_cache_free(link_cache);
-errout_close:
-	nl_close(nlh);
-errout_free:
-	rtnl_neigh_put(neigh);
-errout:
-	nl_handle_destroy(nlh);
-	return err;
-}
diff --git a/src/nl-neigh-list.c b/src/nl-neigh-list.c
new file mode 100644
index 0000000..aa766d5
--- /dev/null
+++ b/src/nl-neigh-list.c
@@ -0,0 +1,87 @@
+/*
+ * src/nl-neigh-list.c      List Neighbours
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "neigh-utils.h"
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-neigh-list [OPTION]... [NEIGHBOUR]\n"
+	"\n"
+	"Options\n"
+	" -f, --format=TYPE     Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"Neighbour Options\n"
+	" -a, --addr=ADDR       Destination address of neighbour\n"
+	" -l, --lladdr=ADDR     Link layer address of neighbour\n"
+	" -d, --dev=DEV         Device the neighbour is connected to\n"
+	"     --family=FAMILY   Destination address family\n"
+	"     --state=STATE     Neighbour state, (default = permanent)\n"
+	);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct rtnl_neigh *neigh;
+	struct nl_cache *link_cache, *neigh_cache;
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+ 
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	neigh_cache = nlt_alloc_neigh_cache(sock);
+ 	neigh = nlt_alloc_neigh();
+ 
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_FAMILY = 257,
+			ARG_STATE = 258,
+		};
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "addr", 1, 0, 'a' },
+			{ "lladdr", 1, 0, 'l' },
+			{ "dev", 1, 0, 'd' },
+			{ "family", 1, 0, ARG_FAMILY },
+			{ "state", 1, 0, ARG_STATE },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "f:hva:l:d:", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'a': parse_dst(neigh, optarg); break;
+		case 'l': parse_lladdr(neigh, optarg); break;
+		case 'd': parse_dev(neigh, link_cache, optarg); break;
+		case ARG_FAMILY: parse_family(neigh, optarg); break;
+		case ARG_STATE: parse_state(neigh, optarg); break;
+		}
+ 	}
+
+	nl_cache_dump_filter(neigh_cache, &params, OBJ_CAST(neigh));
+
+	return 0;
+}
diff --git a/src/nl-neightbl-dump.c b/src/nl-neightbl-dump.c
deleted file mode 100644
index 0d79711..0000000
--- a/src/nl-neightbl-dump.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * src/nl-neightbl-dump.c     Dump neighbour tables
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-
-static void print_usage(void)
-{
-	printf(
-	"Usage: nl-neightbl-dump <mode> [<filter>]\n"
-	"  mode := { brief | detailed | stats | xml }\n"
-	"  filter :=\n");
-	exit(1);
-}
-
-int main(int argc, char *argv[])
-{
-	int err = -1;
-	struct nl_handle *nlh;
-	struct nl_cache *ntc, *lc;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF,
-	};
-
-	if (argc < 2)
-		print_usage();
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout;
-
-	ntc = nltool_alloc_neightbl_cache(nlh);
-	if (!ntc)
-		goto errout_close;
-
-	lc = nltool_alloc_link_cache(nlh);
-	if (!lc)
-		goto errout_ntbl_cache;
-
-	params.dp_type = nltool_parse_dumptype(argv[1]);
-	if (params.dp_type < 0)
-		goto errout_link_cache;
-
-	nl_cache_dump(ntc, &params);
-	err = 0;
-
-errout_link_cache:
-	nl_cache_free(lc);
-errout_ntbl_cache:
-	nl_cache_free(ntc);
-errout_close:
-	nl_close(nlh);
-errout:
-	nl_handle_destroy(nlh);
-	return err;
-}
diff --git a/src/nl-neightbl-list.c b/src/nl-neightbl-list.c
new file mode 100644
index 0000000..4e5acc6
--- /dev/null
+++ b/src/nl-neightbl-list.c
@@ -0,0 +1,64 @@
+/*
+ * src/nl-neightbl-list.c     Dump neighbour tables
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "utils.h"
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-neightbl-list [OPTION]...\n"
+	"\n"
+	"Options\n"
+	" -f, --format=TYPE     Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct nl_cache *link_cache, *neightbl_cache;
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+ 
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	neightbl_cache = nlt_alloc_neightbl_cache(sock);
+ 
+	for (;;) {
+		int c, optidx = 0;
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		}
+ 	}
+
+	nl_cache_dump(neightbl_cache, &params);
+
+	return 0;
+}
diff --git a/src/nl-qdisc-add.c b/src/nl-qdisc-add.c
deleted file mode 100644
index be19f9b..0000000
--- a/src/nl-qdisc-add.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * src/nl-qdisc-dump.c     Dump qdisc attributes
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-#include <netlink/route/sch/fifo.h>
-#include <netlink/route/sch/prio.h>
-
-static void print_usage(void)
-{
-	printf(
-"Usage: nl-qdisc-add <ifindex> <handle> <parent> <kind>\n");
-	exit(1);
-}
-
-static int parse_blackhole_opts(struct rtnl_qdisc *qdisc, char *argv[],
-				int argc)
-{
-	return 0;
-}
-
-static int parse_pfifo_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
-{
-	int err, limit;
-
-	if (argc > 0) {
-		if (argc != 2 || strcasecmp(argv[0], "limit")) {
-			fprintf(stderr, "Usage: ... pfifo limit <limit>\n");
-			return -1;
-		}
-
-		limit = strtoul(argv[1], NULL, 0);
-		err = rtnl_qdisc_fifo_set_limit(qdisc, limit);
-		if (err < 0) {
-			fprintf(stderr, "%s\n", nl_geterror());
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int parse_bfifo_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
-{
-	int err, limit;
-
-	if (argc > 0) {
-		if (argc != 2 || strcasecmp(argv[0], "limit")) {
-			fprintf(stderr, "Usage: ... bfifo limit <limit>\n");
-			return -1;
-		}
-
-		limit = nl_size2int(argv[1]);
-		if (limit < 0) {
-			fprintf(stderr, "Invalid value for limit.\n");
-			return -1;
-		}
-
-		err = rtnl_qdisc_fifo_set_limit(qdisc, limit);
-		if (err < 0) {
-			fprintf(stderr, "%s\n", nl_geterror());
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int parse_prio_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
-{
-	int i, err, bands;
-	uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
-
-	if (argc > 0) {
-		if (argc < 2 || strcasecmp(argv[0], "bands"))
-			goto usage;
-
-		bands = strtoul(argv[1], NULL, 0);
-		err = rtnl_qdisc_prio_set_bands(qdisc, bands);
-		if (err < 0) {
-			fprintf(stderr, "%s\n", nl_geterror());
-			return -1;
-		}
-	}
-
-	if (argc > 2) {
-		if (argc < 5 || strcasecmp(argv[2], "map"))
-			goto usage;
-
-		for (i = 3; i < (argc & ~1U); i += 2) {
-			int prio, band;
-
-			prio = rtnl_str2prio(argv[i]);
-			if (prio < 0 || prio > sizeof(map)/sizeof(map[0])) {
-				fprintf(stderr, "Invalid priority \"%s\"\n",
-					argv[i]);
-				return -1;
-			}
-
-			band = strtoul(argv[i+1], NULL, 0);
-
-			map[prio] = band;
-		}
-	}
-
-	err = rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
-	if (err < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		return -1;
-	}
-
-	return 0;
-usage:
-	fprintf(stderr, "Usage: ... prio bands <nbands> map MAP\n"
-			"MAP := <prio> <band>\n");
-	return -1;
-}
-
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct rtnl_qdisc *qdisc;
-	uint32_t handle, parent;
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 5 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		goto errout;
-
-	qdisc = rtnl_qdisc_alloc();
-	if (!qdisc)
-		goto errout_free_handle;
-
-	rtnl_qdisc_set_ifindex(qdisc, strtoul(argv[1], NULL, 0));
-
-	if (rtnl_tc_str2handle(argv[2], &handle) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_free_qdisc;
-	}
-
-	if (rtnl_tc_str2handle(argv[3], &parent) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_free_qdisc;
-	}
-
-	rtnl_qdisc_set_handle(qdisc, handle);
-	rtnl_qdisc_set_parent(qdisc, parent);
-	rtnl_qdisc_set_kind(qdisc, argv[4]);
-
-	if (!strcasecmp(argv[4], "blackhole"))
-		err = parse_blackhole_opts(qdisc, &argv[5], argc-5);
-	else if (!strcasecmp(argv[4], "pfifo"))
-		err = parse_pfifo_opts(qdisc, &argv[5], argc-5);
-	else if (!strcasecmp(argv[4], "bfifo"))
-		err = parse_bfifo_opts(qdisc, &argv[5], argc-5);
-	else if (!strcasecmp(argv[4], "prio"))
-		err = parse_prio_opts(qdisc, &argv[5], argc-5);
-	else {
-		fprintf(stderr, "Unknown qdisc \"%s\"\n", argv[4]);
-		goto errout_free_qdisc;
-	}
-
-	if (err < 0)
-		goto errout_free_qdisc;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_free_qdisc;
-
-	if (rtnl_qdisc_add(nlh, qdisc, NLM_F_REPLACE) < 0) {
-		fprintf(stderr, "Unable to add Qdisc: %s\n", nl_geterror());
-		goto errout_close;
-	}
-
-	err = 0;
-errout_close:
-	nl_close(nlh);
-errout_free_qdisc:
-	rtnl_qdisc_put(qdisc);
-errout_free_handle:
-	nl_handle_destroy(nlh);
-errout:
-	return err;
-}
diff --git a/src/nl-qdisc-delete.c b/src/nl-qdisc-delete.c
index b8a17ca..32523b7 100644
--- a/src/nl-qdisc-delete.c
+++ b/src/nl-qdisc-delete.c
@@ -1,76 +1,114 @@
 /*
- * src/nl-qdisc-delete.c     Delete Qdiscs
+ * src/nl-qdisc-delete.c     Delete Queuing Disciplines
  *
  *	This library is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU Lesser General Public
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
-#include "utils.h"
+#include "qdisc-utils.h"
+
+static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
+struct nl_sock *sock;
 
 static void print_usage(void)
 {
-	printf("Usage: nl-qdisc-delete <ifindex> <parent> <handle>\n");
-	exit(1);
+	printf(
+	"Usage: nl-qdisc-delete [OPTION]... [QDISC]\n"
+	"\n"
+	"Options\n"
+	" -i, --interactive     Run interactively\n"
+	"     --yes             Set default answer to yes\n"
+	" -q, --quiet           Do not print informal notifications\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"QDisc Options\n"
+	" -d, --dev=DEV         Device the qdisc is attached to\n"
+	" -p, --parent=HANDLE   Identifier of parent qdisc\n"
+	" -H, --handle=HANDLE   Identifier\n"
+	" -k, --kind=NAME       Kind of qdisc (e.g. pfifo_fast)\n"
+	);
+
+	exit(0);
 }
 
-int main(int argc, char *argv[])
+static void delete_cb(struct nl_object *obj, void *arg)
 {
-	struct nl_handle *nlh;
-	struct rtnl_qdisc *qdisc;
-	uint32_t handle, parent;
-	int err = 1;
+	struct rtnl_qdisc *qdisc = nl_object_priv(obj);
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+	int err;
 
-	if (nltool_init(argc, argv) < 0)
-		return -1;
+	if (interactive && !nlt_confirm(obj, &params, default_yes))
+		return;
 
-	if (argc < 3 || !strcmp(argv[1], "-h"))
-		print_usage();
+	if ((err = rtnl_qdisc_delete(sock, qdisc)) < 0)
+		fatal(err, "Unable to delete qdisc: %s\n", nl_geterror(err));
 
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		goto errout;
-
-	qdisc = rtnl_qdisc_alloc();
-	if (!qdisc)
-		goto errout_free_handle;
-
-	rtnl_qdisc_set_ifindex(qdisc, strtoul(argv[1], NULL, 0));
-
-	if (rtnl_tc_str2handle(argv[2], &parent) < 0) {
-		fprintf(stderr, "%s\n", nl_geterror());
-		goto errout_free_qdisc;
+	if (!quiet) {
+		printf("Deleted ");
+		nl_object_dump(obj, &params);
 	}
 
-	if (argc > 3) {
-		if (rtnl_tc_str2handle(argv[3], &handle) < 0) {
-			fprintf(stderr, "%s\n", nl_geterror());
-			goto errout_free_qdisc;
-		}
+	deleted++;
+}
 
-		rtnl_qdisc_set_handle(qdisc, handle);
-	}
+int main(int argc, char *argv[])
+{
+	struct rtnl_qdisc *qdisc;
+	struct nl_cache *link_cache, *qdisc_cache;
+ 
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	qdisc_cache = nlt_alloc_qdisc_cache(sock);
+ 	qdisc = nlt_alloc_qdisc();
+ 
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_YES = 257,
+		};
+		static struct option long_opts[] = {
+			{ "interactive", 0, 0, 'i' },
+			{ "yes", 0, 0, ARG_YES },
+			{ "quiet", 0, 0, 'q' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "dev", 1, 0, 'd' },
+			{ "parent", 1, 0, 'p' },
+			{ "handle", 1, 0, 'H' },
+			{ "kind", 1, 0, 'k' },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "iqhvd:p:H:k:", long_opts, &optidx);
+		if (c == -1)
+			break;
 
-	rtnl_qdisc_set_parent(qdisc, parent);
+		switch (c) {
+		case 'i': interactive = 1; break;
+		case ARG_YES: default_yes = 1; break;
+		case 'q': quiet = 1; break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'd': parse_dev(qdisc, link_cache, optarg); break;
+		case 'p': parse_parent(qdisc, optarg); break;
+		case 'H': parse_handle(qdisc, optarg); break;
+		case 'k': parse_kind(qdisc, optarg); break;
+		}
+ 	}
 
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_free_qdisc;
+	nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(qdisc), delete_cb, NULL);
 
-	if (rtnl_qdisc_delete(nlh, qdisc) < 0) {
-		fprintf(stderr, "Unable to delete Qdisc: %s\n", nl_geterror());
-		goto errout_close;
-	}
+	if (!quiet)
+		printf("Deleted %d qdiscs\n", deleted);
 
-	err = 0;
-errout_close:
-	nl_close(nlh);
-errout_free_qdisc:
-	rtnl_qdisc_put(qdisc);
-errout_free_handle:
-	nl_handle_destroy(nlh);
-errout:
-	return err;
+	return 0;
 }
diff --git a/src/nl-qdisc-dump.c b/src/nl-qdisc-dump.c
deleted file mode 100644
index 167dc7f..0000000
--- a/src/nl-qdisc-dump.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * src/nl-qdisc-dump.c     Dump qdisc attributes
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-
-static void print_usage(void)
-{
-	printf(
-"Usage: nl-qdisc-dump <mode>\n"
-"  mode := { brief | detailed | stats | xml }\n");
-	exit(1);
-}
-
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct nl_cache *link_cache, *qdisc_cache;
-	struct rtnl_qdisc *qdisc;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF
-	};
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	params.dp_type = nltool_parse_dumptype(argv[1]);
-	if (params.dp_type < 0)
-		return -1;
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	qdisc = rtnl_qdisc_alloc();
-	if (!qdisc)
-		goto errout_no_put;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout;
-
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout;
-
-	qdisc_cache = nltool_alloc_qdisc_cache(nlh);
-	if (!qdisc_cache)
-		goto errout_link_cache;
-
-	nl_cache_dump_filter(qdisc_cache, &params, (struct nl_object *) qdisc);
-	nl_cache_free(qdisc_cache);
-	err = 0;
-
-errout_link_cache:
-	nl_cache_free(link_cache);
-errout:
-	rtnl_qdisc_put(qdisc);
-errout_no_put:
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
-	return err;
-}
diff --git a/src/nl-qdisc-list.c b/src/nl-qdisc-list.c
new file mode 100644
index 0000000..bad3817
--- /dev/null
+++ b/src/nl-qdisc-list.c
@@ -0,0 +1,88 @@
+/*
+ * src/nl-qdisc-list.c     List Qdiscs
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "qdisc-utils.h"
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-qdisc-list [OPTION]... [QDISC]\n"
+	"\n"
+	"Options\n"
+	" -f, --format=TYPE     Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version         Show versioning information\n"
+	"\n"
+	"QDisc Options\n"
+	" -d, --dev=DEV         Device the qdisc is attached to\n"
+	" -p, --parent=HANDLE   Identifier of parent qdisc\n"
+	" -H, --handle=HANDLE   Identifier\n"
+	" -k, --kind=NAME       Kind of qdisc (e.g. pfifo_fast)\n"
+	);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct rtnl_qdisc *qdisc;
+	struct nl_cache *link_cache, *qdisc_cache;
+	struct nl_dump_params params = {
+		.dp_type = NL_DUMP_ONELINE,
+		.dp_fd = stdout,
+	};
+ 
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	qdisc_cache = nlt_alloc_qdisc_cache(sock);
+ 	qdisc = nlt_alloc_qdisc();
+ 
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_YES = 257,
+		};
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "quiet", 0, 0, 'q' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "dev", 1, 0, 'd' },
+			{ "parent", 1, 0, 'p' },
+			{ "handle", 1, 0, 'H' },
+			{ "kind", 1, 0, 'k' },
+			{ 0, 0, 0, 0 }
+		};
+	
+		c = getopt_long(argc, argv, "f:qhvd:p:H:k:",
+				long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'q': quiet = 1; break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case 'd': parse_dev(qdisc, link_cache, optarg); break;
+		case 'p': parse_parent(qdisc, optarg); break;
+		case 'H': parse_handle(qdisc, optarg); break;
+		case 'k': parse_kind(qdisc, optarg); break;
+		}
+ 	}
+
+	nl_cache_dump_filter(qdisc_cache, &params, OBJ_CAST(qdisc));
+
+	return 0;
+}
diff --git a/src/nl-route-add.c b/src/nl-route-add.c
index f411b30..9c3c36a 100644
--- a/src/nl-route-add.c
+++ b/src/nl-route-add.c
@@ -14,12 +14,6 @@
 static int quiet = 0;
 static struct nl_cache *link_cache, *route_cache;
 
-static void print_version(void)
-{
-	fprintf(stderr, "%s\n", LIBNL_STRING);
-	exit(0);
-}
-
 static void print_usage(void)
 {
 	printf(
@@ -55,7 +49,7 @@ static void print_usage(void)
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
+	struct nl_handle *sock;
 	struct rtnl_route *route;
 	struct nl_dump_params dp = {
 		.dp_type = NL_DUMP_ONELINE,
@@ -63,14 +57,11 @@ int main(int argc, char *argv[])
 	};
 	int err = 1;
 
-	nlh = nltool_alloc_handle();
-	nltool_connect(nlh, NETLINK_ROUTE);
-	link_cache = nltool_alloc_link_cache(nlh);
-	route_cache = nltool_alloc_route_cache(nlh, 0);
-
-	route = rtnl_route_alloc();
-	if (!route)
-		goto errout;
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	route_cache = nlt_alloc_route_cache(sock, 0);
+	route = nlt_alloc_route();
 
 	for (;;) {
 		int c, optidx = 0;
@@ -111,7 +102,7 @@ int main(int argc, char *argv[])
 		switch (c) {
 		case 'q': quiet = 1; break;
 		case 'h': print_usage(); break;
-		case 'v': print_version(); break;
+		case 'v': nlt_print_version(); break;
 		case 'd': parse_dst(route, optarg); break;
 		case 'n': parse_nexthop(route, optarg, link_cache); break;
 		case 't': parse_table(route, optarg); break;
@@ -127,24 +118,13 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	if (rtnl_route_add(nlh, route, 0) < 0) {
-		fprintf(stderr, "rtnl_route_add failed: %s\n", nl_geterror());
-		goto errout_free;
-	}
+	if ((err = rtnl_route_add(sock, route, 0)) < 0)
+		fatal(err, "Unable to add route: %s", nl_geterror(err));
 
 	if (!quiet) {
 		printf("Added ");
 		nl_object_dump(OBJ_CAST(route), &dp);
 	}
 
-	err = 0;
-errout_free:
-	rtnl_route_put(route);
-errout:
-	nl_cache_free(route_cache);
-	nl_cache_free(link_cache);
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
-
-	return err;
+	return 0;
 }
diff --git a/src/nl-route-delete.c b/src/nl-route-delete.c
index 78403f6..5a442b5 100644
--- a/src/nl-route-delete.c
+++ b/src/nl-route-delete.c
@@ -13,7 +13,7 @@
 
 static int interactive = 0, default_yes = 0, quiet = 0;
 static int deleted = 0;
-static struct nl_handle *nlh;
+static struct nl_handle *sock;
 
 static void print_version(void)
 {
@@ -59,36 +59,21 @@ static void print_usage(void)
 static void delete_cb(struct nl_object *obj, void *arg)
 {
 	struct rtnl_route *route = (struct rtnl_route *) obj;
-	struct nl_dump_params dp = {
+	struct nl_dump_params params = {
 		.dp_type = NL_DUMP_ONELINE,
 		.dp_fd = stdout,
 	};
 	int err;
 
-	if (interactive) {
-		int answer;
+	if (interactive && !nlt_confirm(obj, &params, default_yes))
+		return;
 
-		nl_object_dump(obj, &dp);
-		printf("Delete? (%c/%c) ",
-			default_yes ? 'Y' : 'y',
-			default_yes ? 'n' : 'N');
-
-		do {
-			answer = tolower(getchar());
-			if (answer == '\n')
-				answer = default_yes ? 'y' : 'n';
-		} while (answer != 'y' && answer != 'n');
-
-		if (answer == 'n')
-			return;
-	}
-
-	if ((err = rtnl_route_delete(nlh, route, 0)) < 0)
-		fatal(err, "rtnl_route_del failed: %s\n", nl_geterror());
+	if ((err = rtnl_route_delete(sock, route, 0)) < 0)
+		fatal(err, "Unable to delete route: %s", nl_geterror(err));
 
 	if (!quiet) {
 		printf("Deleted ");
-		nl_object_dump(obj, &dp);
+		nl_object_dump(obj, &params);
 	}
 
 	deleted++;
@@ -98,16 +83,13 @@ int main(int argc, char *argv[])
 {
 	struct nl_cache *link_cache, *route_cache;
 	struct rtnl_route *route;
-	int err = 1, nf = 0;
+	int nf = 0;
 
-	nlh = nltool_alloc_handle();
-	nltool_connect(nlh, NETLINK_ROUTE);
-	link_cache = nltool_alloc_link_cache(nlh);
-	route_cache = nltool_alloc_route_cache(nlh, 0);
-
-	route = rtnl_route_alloc();
-	if (!route)
-		goto errout;
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	route_cache = nlt_alloc_route_cache(sock, 0);
+	route = nlt_alloc_route();
 
 	for (;;) {
 		int c, optidx = 0;
@@ -180,14 +162,5 @@ int main(int argc, char *argv[])
 	if (!quiet)
 		printf("Deleted %d routes\n", deleted);
 
-	err = 0;
-
-	rtnl_route_put(route);
-errout:
-	nl_cache_free(route_cache);
-	nl_cache_free(link_cache);
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
-
-	return err;
+	return 0;
 }
diff --git a/src/nl-route-get.c b/src/nl-route-get.c
index dbd8648..ce267ec 100644
--- a/src/nl-route-get.c
+++ b/src/nl-route-get.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #include "utils.h"
@@ -17,48 +17,43 @@ static void print_usage(void)
 	exit(1);
 }
 
+static void parse_cb(struct nl_object *obj, void *arg)
+{
+	//struct rtnl_route *route = (struct rtnl_route *) obj;
+	struct nl_dump_params params = {
+		.dp_fd = stdout,
+		.dp_type = NL_DUMP_DETAILS,
+	};
+
+	nl_object_dump(obj, &params);
+}
+
 static int cb(struct nl_msg *msg, void *arg)
 {
-	nl_cache_parse_and_add(arg, msg);
+	int err;
+
+	if ((err = nl_msg_parse(msg, &parse_cb, NULL)) < 0)
+		fatal(err, "Unable to parse object: %s", nl_geterror(err));
 
 	return 0;
 }
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
+	struct nl_sock *sock;
 	struct nl_cache *link_cache, *route_cache;
 	struct nl_addr *dst;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF
-	};
 	int err = 1;
 
 	if (argc < 2 || !strcmp(argv[1], "-h"))
 		print_usage();
 
-	if (nltool_init(argc, argv) < 0)
-		goto errout;
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		goto errout;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_free_handle;
-
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout_close;
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	route_cache = nlt_alloc_route_cache(sock, 0);
 
-	dst = nltool_addr_parse(argv[1]);
-	if (!dst)
-		goto errout_link_cache;
-
-	route_cache = nltool_alloc_route_cache(nlh, 0);
-	if (!route_cache)
-		goto errout_addr_put;
+	dst = nlt_addr_parse(argv[1], AF_INET);
 
 	{
 		struct nl_msg *m;
@@ -71,36 +66,18 @@ int main(int argc, char *argv[])
 		nlmsg_append(m, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
 		nla_put_addr(m, RTA_DST, dst);
 
-		if ((err = nl_send_auto_complete(nlh, m)) < 0) {
-			nlmsg_free(m);
-			fprintf(stderr, "%s\n", nl_geterror());
-			goto errout_route_cache;
-		}
-
+		err = nl_send_auto_complete(sock, m);
 		nlmsg_free(m);
+		if (err < 0)
+			fatal(err, "%s", nl_geterror(err));
 
-		nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, cb,
-				 route_cache);
+		nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
 
-		if (nl_recvmsgs_default(nlh) < 0) {
-			fprintf(stderr, "%s\n", nl_geterror());
-			goto errout_route_cache;
-		}
+		if (nl_recvmsgs_default(sock) < 0)
+			fatal(err, "%s", nl_geterror(err));
 	}
 
-	nl_cache_dump(route_cache, &params);
-
-	err = 0;
-errout_route_cache:
-	nl_cache_free(route_cache);
-errout_addr_put:
-	nl_addr_put(dst);
-errout_link_cache:
-	nl_cache_free(link_cache);
-errout_close:
-	nl_close(nlh);
-errout_free_handle:
-	nl_handle_destroy(nlh);
-errout:
-	return err;
+	//nl_cache_dump(route_cache, &params);
+
+	return 0;
 }
diff --git a/src/nl-route-list.c b/src/nl-route-list.c
index 9999a02..02b4851 100644
--- a/src/nl-route-list.c
+++ b/src/nl-route-list.c
@@ -11,12 +11,6 @@
 
 #include "route-utils.h"
 
-static void print_version(void)
-{
-	fprintf(stderr, "%s\n", LIBNL_STRING);
-	exit(0);
-}
-
 static void print_usage(void)
 {
 	printf(
@@ -53,22 +47,19 @@ static void print_usage(void)
 
 int main(int argc, char *argv[])
 {
-	struct nl_handle *nlh;
+	struct nl_sock *sock;
 	struct nl_cache *link_cache, *route_cache;
 	struct rtnl_route *route;
 	struct nl_dump_params params = {
 		.dp_fd = stdout,
 		.dp_type = NL_DUMP_BRIEF
 	};
-	int err = 1, print_cache = 0;
+	int print_cache = 0;
 
-	nlh = nltool_alloc_handle();
-	nltool_connect(nlh, NETLINK_ROUTE);
-	link_cache = nltool_alloc_link_cache(nlh);
-
-	route = rtnl_route_alloc();
-	if (!route)
-		goto errout;
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	route = nlt_alloc_route();
 
 	for (;;) {
 		int c, optidx = 0;
@@ -109,9 +100,9 @@ int main(int argc, char *argv[])
 
 		switch (c) {
 		case 'c': print_cache = 1; break;
-		case 'f': params.dp_type = nltool_parse_dumptype(optarg); break;
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
 		case 'h': print_usage(); break;
-		case 'v': print_version(); break;
+		case 'v': nlt_print_version(); break;
 		case 'd': parse_dst(route, optarg); break;
 		case 'n': parse_nexthop(route, optarg, link_cache); break;
 		case 't': parse_table(route, optarg); break;
@@ -127,19 +118,10 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	route_cache = nltool_alloc_route_cache(nlh,
+	route_cache = nlt_alloc_route_cache(sock,
 				print_cache ? ROUTE_CACHE_CONTENT : 0);
 
 	nl_cache_dump_filter(route_cache, &params, OBJ_CAST(route));
 
-	err = 0;
-
-	rtnl_route_put(route);
-	nl_cache_free(route_cache);
-errout:
-	nl_cache_free(link_cache);
-	nl_close(nlh);
-	nl_handle_destroy(nlh);
-
-	return err;
+	return 0;
 }
diff --git a/src/nl-rule-dump.c b/src/nl-rule-dump.c
deleted file mode 100644
index f9e483a..0000000
--- a/src/nl-rule-dump.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * src/nl-rule-dump.c     Dump rule attributes
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-
-static void print_usage(void)
-{
-	printf(
-	"Usage: nl-rule-dump <mode> [<filter>]\n"
-	"  mode := { brief | detailed | stats | xml }\n");
-	exit(1);
-}
-
-int main(int argc, char *argv[])
-{
-	struct nl_handle *nlh;
-	struct nl_cache *link_cache, *rule_cache;
-	struct rtnl_rule *rule;
-	struct nl_dump_params params = {
-		.dp_fd = stdout,
-		.dp_type = NL_DUMP_BRIEF
-	};
-	int err = 1;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		print_usage();
-
-	nlh = nltool_alloc_handle();
-	if (!nlh)
-		return -1;
-
-	rule = rtnl_rule_alloc();
-	if (!rule)
-		goto errout;
-
-	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
-		goto errout_free;
-
-	link_cache = nltool_alloc_link_cache(nlh);
-	if (!link_cache)
-		goto errout_close;
-
-	rule_cache = nltool_alloc_rule_cache(nlh);
-	if (!rule_cache)
-		goto errout_link_cache;
-
-	params.dp_type = nltool_parse_dumptype(argv[1]);
-	if (params.dp_type < 0)
-		goto errout_rule_cache;
-
-	//get_filter(route, argc, argv, 2, route_cache);
-
-	nl_cache_dump_filter(rule_cache, &params, (struct nl_object *) rule);
-
-	err = 0;
-
-errout_rule_cache:
-	nl_cache_free(rule_cache);
-errout_link_cache:
-	nl_cache_free(link_cache);
-errout_close:
-	nl_close(nlh);
-errout_free:
-	nl_object_put((struct nl_object *) rule);
-errout:
-	return err;
-}
diff --git a/src/nl-rule-list.c b/src/nl-rule-list.c
new file mode 100644
index 0000000..7541d0a
--- /dev/null
+++ b/src/nl-rule-list.c
@@ -0,0 +1,75 @@
+/*
+ * src/nl-rule-dump.c     Dump rule attributes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "rule-utils.h"
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-rule-list [OPTION]... [ROUTE]\n"
+	"\n"
+	"Options\n"
+	" -c, --cache           List the contents of the route cache\n"
+	" -f, --format=TYPE	Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version		Show versioning information\n"
+	"\n"
+	"Rule Options\n"
+	"     --family          Address family\n"
+	);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	struct rtnl_rule *rule;
+	struct nl_cache *link_cache, *rule_cache;
+	struct nl_dump_params params = {
+		.dp_fd = stdout,
+		.dp_type = NL_DUMP_BRIEF
+	};
+
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	rule_cache = nlt_alloc_rule_cache(sock);
+	rule = nlt_alloc_rule();
+
+	for (;;) {
+		int c, optidx = 0;
+		enum {
+			ARG_FAMILY = 257,
+		};
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ "family", 1, 0, ARG_FAMILY },
+			{ 0, 0, 0, 0 }
+		};
+
+		c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		case ARG_FAMILY: parse_family(rule, optarg); break;
+		}
+	}
+
+	nl_cache_dump_filter(rule_cache, &params, OBJ_CAST(rule));
+
+	return 0;
+}
diff --git a/src/nl-tctree-dump.c b/src/nl-tctree-dump.c
deleted file mode 100644
index 8b45e7b..0000000
--- a/src/nl-tctree-dump.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * src/nl-tctree-dump.c		Dump Traffic Control Tree
- *
- *	This library is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU Lesser General Public
- *	License as published by the Free Software Foundation version 2.1
- *	of the License.
- *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- */
-
-#include "utils.h"
-#include <linux/pkt_sched.h>
-
-static struct nl_handle *nl_handle;
-static struct nl_cache *qdisc_cache, *class_cache;
-static struct nl_dump_params dump_params = {
-	.dp_type = NL_DUMP_FULL,
-};
-
-static int ifindex;
-static void print_qdisc(struct nl_object *, void *);
-
-static void print_class(struct nl_object *obj, void *arg)
-{
-	struct rtnl_qdisc *leaf;
-	struct rtnl_class *class = (struct rtnl_class *) obj;
-	struct nl_cache *cls_cache;
-	uint32_t parent = rtnl_class_get_handle(class);
-
-	dump_params.dp_prefix = (int)(long) arg;
-	nl_object_dump(obj, &dump_params);
-
-	leaf = rtnl_class_leaf_qdisc(class, qdisc_cache);
-	if (leaf)
-		print_qdisc((struct nl_object *) leaf, arg + 2);
-
-	rtnl_class_foreach_child(class, class_cache, &print_class, arg + 2);
-
-	cls_cache = rtnl_cls_alloc_cache(nl_handle, ifindex, parent);
-	if (!cls_cache)
-		return;
-
-	dump_params.dp_prefix = (int)(long) arg + 2;
-	nl_cache_dump(cls_cache, &dump_params);
-	nl_cache_free(cls_cache);
-}
-
-static void print_qdisc(struct nl_object *obj, void *arg)
-{
-	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
-	struct nl_cache *cls_cache;
-	uint32_t parent = rtnl_qdisc_get_handle(qdisc);
-
-	dump_params.dp_prefix = (int)(long) arg;
-	nl_object_dump(obj, &dump_params);
-
-	rtnl_qdisc_foreach_child(qdisc, class_cache, &print_class, arg + 2);
-
-	cls_cache = rtnl_cls_alloc_cache(nl_handle, ifindex, parent);
-	if (!cls_cache)
-		return;
-
-	dump_params.dp_prefix = (int)(long) arg + 2;
-	nl_cache_dump(cls_cache, &dump_params);
-	nl_cache_free(cls_cache);
-}
-
-static void print_link(struct nl_object *obj, void *arg)
-{
-	struct rtnl_link *link = (struct rtnl_link *) obj;
-	struct rtnl_qdisc *qdisc;
-
-	ifindex = rtnl_link_get_ifindex(link);
-	dump_params.dp_prefix = 0;
-	nl_object_dump(obj, &dump_params);
-
-	class_cache = rtnl_class_alloc_cache(nl_handle, ifindex);
-	if (!class_cache)
-		return;
-
-	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
-	if (qdisc) {
-		print_qdisc((struct nl_object *) qdisc, (void *) 2);
-		rtnl_qdisc_put(qdisc);
-	}
-
-	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
-	if (qdisc) {
-		print_qdisc((struct nl_object *) qdisc, (void *) 2);
-		rtnl_qdisc_put(qdisc);
-	}
-
-	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
-	if (qdisc) {
-		print_qdisc((struct nl_object *) qdisc, (void *) 2);
-		rtnl_qdisc_put(qdisc);
-	}
-
-	nl_cache_free(class_cache);
-}
-
-int main(int argc, char *argv[])
-{
-	struct nl_cache *link_cache;
-
-	if (nltool_init(argc, argv) < 0)
-		return -1;
-
-	dump_params.dp_fd = stdout;
-
-	if (argc > 1) {
-		if (!strcasecmp(argv[1], "brief"))
-			dump_params.dp_type = NL_DUMP_BRIEF;
-		else if (!strcasecmp(argv[1], "full"))
-			dump_params.dp_type = NL_DUMP_FULL;
-		else if (!strcasecmp(argv[1], "stats"))
-			dump_params.dp_type = NL_DUMP_STATS;
-	}
-
-	nl_handle = nltool_alloc_handle();
-	if (!nl_handle)
-		return 1;
-
-	if (nltool_connect(nl_handle, NETLINK_ROUTE) < 0)
-		return 1;
-
-	link_cache = nltool_alloc_link_cache(nl_handle);
-	if (!link_cache)
-		return 1;
-
-	qdisc_cache = nltool_alloc_qdisc_cache(nl_handle);
-	if (!qdisc_cache)
-		return 1;
-
-	nl_cache_foreach(link_cache, &print_link, NULL);
-
-	nl_cache_free(qdisc_cache);
-	nl_cache_free(link_cache);
-
-	nl_close(nl_handle);
-	nl_handle_destroy(nl_handle);
-	return 0;
-}
diff --git a/src/nl-tctree-list.c b/src/nl-tctree-list.c
new file mode 100644
index 0000000..6f6bf56
--- /dev/null
+++ b/src/nl-tctree-list.c
@@ -0,0 +1,147 @@
+/*
+ * src/nl-tctree-list.c		List Traffic Control Tree
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "utils.h"
+#include <linux/pkt_sched.h>
+
+static struct nl_sock *sock;
+static struct nl_cache *qdisc_cache, *class_cache;
+static struct nl_dump_params params = {
+	.dp_type = NL_DUMP_DETAILS,
+};
+
+static int ifindex;
+static void print_qdisc(struct nl_object *, void *);
+
+static void print_usage(void)
+{
+	printf(
+	"Usage: nl-tctree-list [OPTION]...\n"
+	"\n"
+	"Options\n"
+	" -f, --format=TYPE	Output format { brief | details | stats }\n"
+	" -h, --help            Show this help\n"
+	" -v, --version		Show versioning information\n"
+	);
+	exit(0);
+}
+
+static void print_class(struct nl_object *obj, void *arg)
+{
+	struct rtnl_qdisc *leaf;
+	struct rtnl_class *class = (struct rtnl_class *) obj;
+	struct nl_cache *cls_cache;
+	uint32_t parent = rtnl_class_get_handle(class);
+
+	params.dp_prefix = (int)(long) arg;
+	nl_object_dump(obj, &params);
+
+	leaf = rtnl_class_leaf_qdisc(class, qdisc_cache);
+	if (leaf)
+		print_qdisc((struct nl_object *) leaf, arg + 2);
+
+	rtnl_class_foreach_child(class, class_cache, &print_class, arg + 2);
+
+	if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
+		return;
+
+	params.dp_prefix = (int)(long) arg + 2;
+	nl_cache_dump(cls_cache, &params);
+	nl_cache_free(cls_cache);
+}
+
+static void print_qdisc(struct nl_object *obj, void *arg)
+{
+	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
+	struct nl_cache *cls_cache;
+	uint32_t parent = rtnl_qdisc_get_handle(qdisc);
+
+	params.dp_prefix = (int)(long) arg;
+	nl_object_dump(obj, &params);
+
+	rtnl_qdisc_foreach_child(qdisc, class_cache, &print_class, arg + 2);
+
+	if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
+		return;
+
+	params.dp_prefix = (int)(long) arg + 2;
+	nl_cache_dump(cls_cache, &params);
+	nl_cache_free(cls_cache);
+}
+
+static void print_link(struct nl_object *obj, void *arg)
+{
+	struct rtnl_link *link = (struct rtnl_link *) obj;
+	struct rtnl_qdisc *qdisc;
+
+	ifindex = rtnl_link_get_ifindex(link);
+	params.dp_prefix = 0;
+	nl_object_dump(obj, &params);
+
+	if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
+		return;
+
+	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
+	if (qdisc) {
+		print_qdisc((struct nl_object *) qdisc, (void *) 2);
+		rtnl_qdisc_put(qdisc);
+	}
+
+	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
+	if (qdisc) {
+		print_qdisc((struct nl_object *) qdisc, (void *) 2);
+		rtnl_qdisc_put(qdisc);
+	}
+
+	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
+	if (qdisc) {
+		print_qdisc((struct nl_object *) qdisc, (void *) 2);
+		rtnl_qdisc_put(qdisc);
+	}
+
+	nl_cache_free(class_cache);
+}
+
+int main(int argc, char *argv[])
+{
+	struct nl_cache *link_cache;
+
+	sock = nlt_alloc_socket();
+	nlt_connect(sock, NETLINK_ROUTE);
+	link_cache = nlt_alloc_link_cache(sock);
+	qdisc_cache = nlt_alloc_qdisc_cache(sock);
+
+	params.dp_fd = stdout;
+
+	for (;;) {
+		int c, optidx = 0;
+		static struct option long_opts[] = {
+			{ "format", 1, 0, 'f' },
+			{ "help", 0, 0, 'h' },
+			{ "version", 0, 0, 'v' },
+			{ 0, 0, 0, 0 }
+		};
+
+		c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'f': params.dp_type = nlt_parse_dumptype(optarg); break;
+		case 'h': print_usage(); break;
+		case 'v': nlt_print_version(); break;
+		}
+	}
+
+	nl_cache_foreach(link_cache, &print_link, NULL);
+
+	return 0;
+}
diff --git a/src/nl-util-addr.c b/src/nl-util-addr.c
index 9f12795..93779ea 100644
--- a/src/nl-util-addr.c
+++ b/src/nl-util-addr.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #include "utils.h"
@@ -21,19 +21,12 @@ int main(int argc, char *argv[])
 		fprintf(stderr, "Usage: nl-util-addr <address>\n");
 		return -1;
 	}
-	
-	a = nl_addr_parse(argv[1], AF_UNSPEC);
-	if (a == NULL) {
-		fprintf(stderr, "Cannot parse address \"%s\"\n", argv[1]);
-		return -1;
-	}
 
+	a = nlt_addr_parse(argv[1], AF_UNSPEC);
 	err = nl_addr_resolve(a, host, sizeof(host));
-	if (err != 0) {
-		fprintf(stderr, "Cannot resolve address \"%s\": %d\n",
-			argv[1], err);
-		return -1;
-	}
+	if (err != 0)
+		fatal(err, "Unable to resolve address \"%s\": %s",
+		      argv[1], nl_geterror(err));
 
 	printf("%s\n", host);
 
diff --git a/src/qdisc-utils.c b/src/qdisc-utils.c
new file mode 100644
index 0000000..57b5066
--- /dev/null
+++ b/src/qdisc-utils.c
@@ -0,0 +1,62 @@
+/*
+ * src/qdisc-utils.c     QDisc Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "qdisc-utils.h"
+
+struct rtnl_qdisc *nlt_alloc_qdisc(void)
+{
+	struct rtnl_qdisc *qdisc;
+
+	qdisc = rtnl_qdisc_alloc();
+	if (!qdisc)
+		fatal(ENOMEM, "Unable to allocate qdisc object");
+
+	return qdisc;
+}
+
+void parse_dev(struct rtnl_qdisc *qdisc, struct nl_cache *link_cache, char *arg)
+{
+	int ival;
+
+	if (!(ival = rtnl_link_name2i(link_cache, arg)))
+		fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+	rtnl_qdisc_set_ifindex(qdisc, ival);
+}
+
+void parse_parent(struct rtnl_qdisc *qdisc, char *arg)
+{
+	uint32_t parent;
+	int err;
+
+	if ((err = rtnl_tc_str2handle(arg, &parent)) < 0)
+		fatal(err, "Unable to parse handle \"%s\": %s",
+		      arg, nl_geterror(err));
+
+	rtnl_qdisc_set_parent(qdisc, parent);
+}
+
+void parse_handle(struct rtnl_qdisc *qdisc, char *arg)
+{
+	uint32_t handle;
+	int err;
+
+	if ((err = rtnl_tc_str2handle(arg, &handle)) < 0)
+		fatal(err, "Unable to parse handle \"%s\": %s",
+		      arg, nl_geterror(err));
+
+	rtnl_qdisc_set_handle(qdisc, handle);
+}
+
+void parse_kind(struct rtnl_qdisc *qdisc, char *arg)
+{
+	rtnl_qdisc_set_kind(qdisc, arg);
+}
diff --git a/src/qdisc-utils.h b/src/qdisc-utils.h
new file mode 100644
index 0000000..f6ce3ef
--- /dev/null
+++ b/src/qdisc-utils.h
@@ -0,0 +1,23 @@
+/*
+ * src/qdisc-utils.h     QDisc Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __QDISC_UTILS_H_
+#define __QDISC_UTILS_H_
+
+#include "utils.h"
+
+extern struct rtnl_qdisc *nlt_alloc_qdisc(void);
+extern void parse_dev(struct rtnl_qdisc *, struct nl_cache *, char *);
+extern void parse_parent(struct rtnl_qdisc *, char *);
+extern void parse_handle(struct rtnl_qdisc *, char *);
+extern void parse_kind(struct rtnl_qdisc *, char *);
+
+#endif
diff --git a/src/queue-utils.c b/src/queue-utils.c
new file mode 100644
index 0000000..77038aa
--- /dev/null
+++ b/src/queue-utils.c
@@ -0,0 +1,24 @@
+/*
+ * src/queue-utils.c		Queue Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "queue-utils.h"
+
+struct nfnl_queue *nlt_alloc_queue(void)
+{
+	struct nfnl_queue *queue;
+
+	queue = nfnl_queue_alloc();
+	if (!queue)
+		fatal(ENOMEM, "Unable to allocate queue object");
+
+	return queue;
+}
+
diff --git a/src/queue-utils.h b/src/queue-utils.h
new file mode 100644
index 0000000..5a628fe
--- /dev/null
+++ b/src/queue-utils.h
@@ -0,0 +1,24 @@
+/*
+ * src/queue-utils.h		Queue Helper
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __QUEUE_UTILS_H_
+#define __QUEUE_UTILS_H_
+
+#include "utils.h"
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue.h>
+#include <netlink/netfilter/queue_msg.h>
+
+extern struct nfnl_queue *nlt_alloc_queue(void);
+
+#endif
diff --git a/src/route-utils.c b/src/route-utils.c
index 7f73a41..549e6ff 100644
--- a/src/route-utils.c
+++ b/src/route-utils.c
@@ -11,6 +11,17 @@
 
 #include "route-utils.h"
 
+struct rtnl_route *nlt_alloc_route(void)
+{
+	struct rtnl_route *route;
+
+	route = rtnl_route_alloc();
+	if (!route)
+		fatal(ENOMEM, "Unable to allocate route object");
+
+	return route;
+}
+
 void parse_family(struct rtnl_route *route, char *arg)
 {
 	int family;
@@ -24,12 +35,10 @@ void parse_dst(struct rtnl_route *route, char *arg)
 	struct nl_addr *addr;
 	int err;
 
-	addr = nl_addr_parse(arg, rtnl_route_get_family(route));
-	if (addr == NULL)
-		fatal(nl_get_errno(), nl_geterror());
-
+	addr = nlt_addr_parse(arg, rtnl_route_get_family(route));
 	if ((err = rtnl_route_set_dst(route, addr)) < 0)
-		fatal(err, nl_geterror());
+		fatal(err, "Unable to set destination address: %s",
+		      nl_geterror(err));
 
 	nl_addr_put(addr);
 }
@@ -39,12 +48,10 @@ void parse_src(struct rtnl_route *route, char *arg)
 	struct nl_addr *addr;
 	int err;
 
-	addr = nl_addr_parse(arg, rtnl_route_get_family(route));
-	if (addr == NULL)
-		fatal(nl_get_errno(), nl_geterror());
-
+	addr = nlt_addr_parse(arg, rtnl_route_get_family(route));
 	if ((err = rtnl_route_set_src(route, addr)) < 0)
-		fatal(err, nl_geterror());
+		fatal(err, "Unable to set source address: %s",
+		      nl_geterror(err));
 
 	nl_addr_put(addr);
 }
@@ -54,12 +61,10 @@ void parse_pref_src(struct rtnl_route *route, char *arg)
 	struct nl_addr *addr;
 	int err;
 
-	addr = nl_addr_parse(arg, rtnl_route_get_family(route));
-	if (addr == NULL)
-		fatal(nl_get_errno(), nl_geterror());
-
+	addr = nlt_addr_parse(arg, rtnl_route_get_family(route));
 	if ((err = rtnl_route_set_pref_src(route, addr)) < 0)
-		fatal(err, nl_geterror());
+		fatal(err, "Unable to set preferred source address: %s",
+		      nl_geterror(err));
 
 	nl_addr_put(addr);
 }
@@ -102,7 +107,8 @@ void parse_metric(struct rtnl_route *route, char *subopts)
 			fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]);
 
 		if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0)
-			fatal(ret, nl_geterror());
+			fatal(ret, "Unable to set metric: %s",
+			      nl_geterror(ret));
 	}
 }
 
@@ -140,18 +146,14 @@ void parse_nexthop(struct rtnl_route *route, char *subopts,
 
 		switch (ret) {
 		case NH_DEV:
-			ival = rtnl_link_name2i(link_cache, arg);
-			if (ival == RTNL_LINK_NOT_FOUND)
-				fatal(ENOENT, "Link \"%s\" does not exist", arg);
+			if (!(ival = rtnl_link_name2i(link_cache, arg)))
+				fatal(ENOENT,"Link \"%s\" does not exist", arg);
 
 			rtnl_route_nh_set_ifindex(nh, ival);
 			break;
 
 		case NH_VIA:
-			addr = nl_addr_parse(arg, rtnl_route_get_family(route));
-			if (addr == NULL)
-				fatal(nl_get_errno(), nl_geterror());
-
+			addr = nlt_addr_parse(arg,rtnl_route_get_family(route));
 			rtnl_route_nh_set_gateway(nh, addr);
 			nl_addr_put(addr);
 			break;
@@ -226,15 +228,15 @@ void parse_type(struct rtnl_route *route, char *arg)
 		fatal(EINVAL, "Unknown routing type \"%s\"", arg);
 
 	if ((ival = rtnl_route_set_type(route, ival)) < 0)
-		fatal(ival, nl_geterror());
+		fatal(ival, "Unable to set routing type: %s",
+		      nl_geterror(ival));
 }
 
 void parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache)
 {
 	int ival;
 
-	ival = rtnl_link_name2i(link_cache, arg);
-	if (ival == RTNL_LINK_NOT_FOUND)
+	if (!(ival = rtnl_link_name2i(link_cache, arg)))
 		fatal(ENOENT, "Link \"%s\" does not exist", arg);
 
 	rtnl_route_set_iif(route, ival);
diff --git a/src/route-utils.h b/src/route-utils.h
index 873835c..b410557 100644
--- a/src/route-utils.h
+++ b/src/route-utils.h
@@ -14,6 +14,7 @@
 
 #include "utils.h"
 
+extern struct rtnl_route *nlt_alloc_route(void);
 extern void	parse_family(struct rtnl_route *, char *);
 extern void	parse_dst(struct rtnl_route *, char *);
 extern void	parse_src(struct rtnl_route *, char *);
diff --git a/src/rtnl-utils.c b/src/rtnl-utils.c
new file mode 100644
index 0000000..5c4228b
--- /dev/null
+++ b/src/rtnl-utils.c
@@ -0,0 +1,66 @@
+/*
+ * src/rtnl-utils.c	rtnetlink helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "rtnl-utils.h"
+
+struct nl_cache *nlt_alloc_link_cache(struct nl_sock *sk)
+{
+	return alloc_cache(sk, "link", rtnl_link_alloc_cache);
+}
+
+struct nl_cache *nlt_alloc_addr_cache(struct nl_sock *sk)
+{
+	return alloc_cache(sk, "address", rtnl_addr_alloc_cache);
+}
+
+struct nl_cache *nlt_alloc_neigh_cache(struct nl_sock *sk)
+{
+	return alloc_cache(sk, "neighbour", rtnl_neigh_alloc_cache);
+}
+
+struct nl_cache *nlt_alloc_neightbl_cache(struct nl_sock *sk)
+{
+	return alloc_cache(sk, "neighbour table", rtnl_neightbl_alloc_cache);
+}
+
+struct nl_cache *nlt_alloc_route_cache(struct nl_sock *sk, int flags)
+{
+	struct nl_cache *cache;
+	int err;
+
+	if ((err = rtnl_route_alloc_cache(sk, AF_UNSPEC, flags, &cache)) < 0)
+		fatal(err, "Unable to allocate route cache: %s\n",
+		      nl_geterror(err));
+
+	nl_cache_mngt_provide(cache);
+
+	return cache;
+}
+
+struct nl_cache *nlt_alloc_rule_cache(struct nl_sock *sk)
+{
+	struct nl_cache *cache;
+	int err;
+
+	if ((err = rtnl_rule_alloc_cache(sk, AF_UNSPEC, &cache)) < 0)
+		fatal(err, "Unable to allocate routing rule cache: %s\n",
+		      nl_geterror(err));
+
+	nl_cache_mngt_provide(cache);
+
+	return cache;
+}
+
+struct nl_cache *nlt_alloc_qdisc_cache(struct nl_sock *sk)
+{
+	return alloc_cache(sk, "queueing disciplines", rtnl_qdisc_alloc_cache);
+}
+
diff --git a/src/rtnl-utils.h b/src/rtnl-utils.h
new file mode 100644
index 0000000..5f2bbe3
--- /dev/null
+++ b/src/rtnl-utils.h
@@ -0,0 +1,25 @@
+/*
+ * src/rtnl-utils.h	rtnetlink helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __SRC_RTNL_UTILS_H_
+#define __SRC_RTNL_UTILS_H_
+
+#include "utils.h"
+
+extern struct nl_cache *nlt_alloc_link_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_addr_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_neigh_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_neightbl_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_qdisc_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_route_cache(struct nl_sock *, int);
+extern struct nl_cache *nlt_alloc_rule_cache(struct nl_sock *);
+
+#endif
diff --git a/src/rule-utils.c b/src/rule-utils.c
new file mode 100644
index 0000000..e8f3ba7
--- /dev/null
+++ b/src/rule-utils.c
@@ -0,0 +1,31 @@
+/*
+ * src/rule-utils.c     Routing Rule Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "rule-utils.h"
+
+struct rtnl_rule *nlt_alloc_rule(void)
+{
+	struct rtnl_rule *rule;
+
+	rule = rtnl_rule_alloc();
+	if (!rule)
+		fatal(ENOMEM, "Unable to allocate rule object");
+
+	return rule;
+}
+
+void parse_family(struct rtnl_rule *rule, char *arg)
+{
+	int family;
+
+	if ((family = nl_str2af(arg)) != AF_UNSPEC)
+		rtnl_rule_set_family(rule, family);
+}
diff --git a/src/rule-utils.h b/src/rule-utils.h
new file mode 100644
index 0000000..fcbf9a7
--- /dev/null
+++ b/src/rule-utils.h
@@ -0,0 +1,20 @@
+/*
+ * src/rule-utils.h     Routing Rule Helpers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __RULE_UTILS_H_
+#define __RULE_UTILS_H_
+
+#include "utils.h"
+
+extern struct rtnl_rule *nlt_alloc_rule(void);
+extern void parse_family(struct rtnl_rule *, char *);
+
+#endif
diff --git a/src/utils.c b/src/utils.c
index f7fd648..95c9329 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -13,6 +13,18 @@
 
 #include <stdlib.h>
 
+uint32_t parse_u32(const char *arg)
+{
+	unsigned long lval;
+	char *endptr;
+
+	lval = strtoul(arg, &endptr, 0);
+	if (endptr == arg || lval == ULONG_MAX)
+		fatal(EINVAL, "Unable to parse \"%s\", not a number.", arg);
+
+	return (uint32_t) lval;
+}
+
 void nlt_print_version(void)
 {
 	printf("libnl tools version %s\n", LIBNL_VERSION);
@@ -112,8 +124,8 @@ int nlt_confirm(struct nl_object *obj, struct nl_dump_params *params,
 	return answer == 'y';
 }
 
-static struct nl_cache *alloc_cache(struct nl_sock *sock, const char *name,
-			    int (*ac)(struct nl_sock *, struct nl_cache **))
+struct nl_cache *alloc_cache(struct nl_sock *sock, const char *name,
+			     int (*ac)(struct nl_sock *, struct nl_cache **))
 {
 	struct nl_cache *cache;
 	int err;
@@ -127,67 +139,3 @@ static struct nl_cache *alloc_cache(struct nl_sock *sock, const char *name,
 	return cache;
 }
 
-struct nl_cache *nlt_alloc_link_cache(struct nl_sock *sk)
-{
-	return alloc_cache(sk, "link", rtnl_link_alloc_cache);
-}
-
-struct nl_cache *nlt_alloc_addr_cache(struct nl_sock *sk)
-{
-	return alloc_cache(sk, "address", rtnl_addr_alloc_cache);
-}
-
-struct rtnl_addr *nlt_alloc_addr(void)
-{
-	struct rtnl_addr *addr;
-
-	addr = rtnl_addr_alloc();
-	if (!addr)
-		fatal(ENOMEM, "Unable to allocate address object");
-
-	return addr;
-}
-
-struct nl_cache *nltool_alloc_neigh_cache(struct nl_sock *sk)
-{
-	return alloc_cache(sk, "neighbour", rtnl_neigh_alloc_cache);
-}
-
-struct nl_cache *nltool_alloc_neightbl_cache(struct nl_sock *sk)
-{
-	return alloc_cache(sk, "neighbour table", rtnl_neightbl_alloc_cache);
-}
-
-struct nl_cache *nltool_alloc_route_cache(struct nl_sock *sk, int flags)
-{
-	struct nl_cache *cache;
-	int err;
-
-	if ((err = rtnl_route_alloc_cache(sk, AF_UNSPEC, flags, &cache)) < 0)
-		fatal(err, "Unable to allocate route cache: %s\n",
-		      nl_geterror(err));
-
-	nl_cache_mngt_provide(cache);
-
-	return cache;
-}
-
-struct nl_cache *nltool_alloc_rule_cache(struct nl_sock *sk)
-{
-	struct nl_cache *cache;
-	int err;
-
-	if ((err = rtnl_rule_alloc_cache(sk, AF_UNSPEC, &cache)) < 0)
-		fatal(err, "Unable to allocate routing rule cache: %s\n",
-		      nl_geterror(err));
-
-	nl_cache_mngt_provide(cache);
-
-	return cache;
-}
-
-struct nl_cache *nltool_alloc_qdisc_cache(struct nl_sock *sk)
-{
-	return alloc_cache(sk, "queueing disciplines", rtnl_qdisc_alloc_cache);
-}
-
diff --git a/src/utils.h b/src/utils.h
index b22dfbf..12f7c52 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -44,6 +44,8 @@
 #include <netlink/genl/mngt.h>
 #include <netlink/netfilter/ct.h>
 
+extern uint32_t parse_u32(const char *);
+
 extern void		nlt_print_version(void);
 extern void		fatal(int err, const char *fmt, ...);
 extern struct nl_addr *	nlt_addr_parse(const char *, int);
@@ -55,15 +57,13 @@ extern int nlt_parse_dumptype(const char *str);
 extern int nlt_confirm(struct nl_object *, struct nl_dump_params *, int);
 
 extern struct nl_cache *nlt_alloc_link_cache(struct nl_sock *);
-
 extern struct nl_cache *nlt_alloc_addr_cache(struct nl_sock *);
-extern struct rtnl_addr *nlt_alloc_addr(void);
-
-extern struct nl_cache *nltool_alloc_neigh_cache(struct nl_sock *nlh);
-extern struct nl_cache *nltool_alloc_neightbl_cache(struct nl_sock *nlh);
-extern struct nl_cache *nltool_alloc_route_cache(struct nl_sock *nlh, int);
-extern struct nl_cache *nltool_alloc_rule_cache(struct nl_sock *nlh);
-extern struct nl_cache *nltool_alloc_qdisc_cache(struct nl_sock *nlh);
-extern struct nl_cache *nltool_alloc_genl_family_cache(struct nl_sock *nlh);
+extern struct nl_cache *nlt_alloc_neigh_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_neightbl_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_qdisc_cache(struct nl_sock *);
+extern struct nl_cache *nlt_alloc_route_cache(struct nl_sock *, int);
+extern struct nl_cache *nlt_alloc_rule_cache(struct nl_sock *);
+extern struct nl_cache *alloc_cache(struct nl_sock *, const char *,
+			     int (*ac)(struct nl_sock *, struct nl_cache **));
 
 #endif
-- 
cgit v0.12