summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2009-12-16 16:20:46 +0100
committerThomas Graf <tgraf@suug.ch>2009-12-16 16:20:46 +0100
commit8808743839b0f459394ecd00cb0f7c1896c0ab7a (patch)
treea3ab1da0c8bb02390662891bcb92e2130662b5d7 /src/lib
parentff76549013c31082d303b3feef755bbd35e13ec6 (diff)
downloadandroid_external_libnl-8808743839b0f459394ecd00cb0f7c1896c0ab7a.tar.gz
android_external_libnl-8808743839b0f459394ecd00cb0f7c1896c0ab7a.tar.bz2
android_external_libnl-8808743839b0f459394ecd00cb0f7c1896c0ab7a.zip
CLI - Command Line Interface Library
Moved common code in src/ used by CLI tools to src/lib/ for possible use by other CLI tools. Just link to libnl-cli.{so|la}
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/Makefile.am41
-rw-r--r--src/lib/addr.c135
-rw-r--r--src/lib/ct.c162
-rw-r--r--src/lib/link.c73
-rw-r--r--src/lib/neigh.c88
-rw-r--r--src/lib/qdisc.c72
-rw-r--r--src/lib/route.c270
-rw-r--r--src/lib/rule.c55
-rw-r--r--src/lib/utils.c147
9 files changed, 1043 insertions, 0 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644
index 0000000..068c3a6
--- /dev/null
+++ b/src/lib/Makefile.am
@@ -0,0 +1,41 @@
+# -*- Makefile -*-
+
+AM_CFLAGS = -Wall -I${top_srcdir}/include -D_GNU_SOURCE -DPKGLIBDIR=\"$(pkglibdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -rdynamic
+AM_LDFLAGS = -L${top_builddir}/lib -ldl
+
+#nobase_pkglib_LTLIBRARIES = cls/basic.la cls/ematch/cmp.la
+#cls_basic_la_LDFLAGS = -module -version-info 2:0:0
+#cls_ematch_cmp_la_LDFLAGS = -module -version-info 2:0:0
+
+#cls/ematch_grammar.c: cls/ematch_grammar.l
+# $(LEX) --header-file=cls/ematch_grammar.h $(LFLAGS) -o $@ $^
+
+#cls/ematch_syntax.c: cls/ematch_syntax.y
+# $(YACC) -d $(YFLAGS) -o $@ $^
+
+#cls/pktloc_grammar.c: cls/pktloc_grammar.l
+# $(LEX) --header-file=cls/pktloc_grammar.h $(LFLAGS) -o $@ $^
+
+#cls/pktloc_syntax.c: cls/pktloc_syntax.y
+# $(YACC) -d $(YFLAGS) -o $@ $^
+
+#CLEANFILES = \
+# cls/ematch_grammar.c cls/ematch_grammar.h \
+# cls/ematch_syntax.c cls/ematch_syntax.h \
+# cls/pktloc_grammar.c cls/pktloc_grammar.h \
+# cls/pktloc_syntax.c cls/pktloc_syntax.h
+
+lib_LTLIBRARIES = \
+ libnl-cli.la
+
+libnl_cli_la_LDFLAGS = -version-info 2:0:0
+
+libnl_cli_la_LIBADD = ${top_builddir}/lib/libnl.la \
+ ${top_builddir}/lib/libnl-route.la \
+ ${top_builddir}/lib/libnl-nf.la \
+ ${top_builddir}/lib/libnl-genl.la
+
+libnl_cli_la_SOURCES = \
+ utils.c addr.c ct.c link.c neigh.c qdisc.c rule.c route.c
+# cls/ematch_syntax.c cls/ematch_grammar.c cls/ematch.c
+# cls/pktloc_syntax.c cls/pktloc_grammar.c cls/utils.c
diff --git a/src/lib/addr.c b/src/lib/addr.c
new file mode 100644
index 0000000..a9c137b
--- /dev/null
+++ b/src/lib/addr.c
@@ -0,0 +1,135 @@
+/*
+ * src/lib/addr.c Address 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_addr Addresses
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/addr.h>
+
+struct rtnl_addr *nl_cli_addr_alloc(void)
+{
+ struct rtnl_addr *addr;
+
+ addr = rtnl_addr_alloc();
+ if (!addr)
+ nl_cli_fatal(ENOMEM, "Unable to allocate address object");
+
+ return addr;
+}
+
+void nl_cli_addr_parse_family(struct rtnl_addr *addr, char *arg)
+{
+ int family;
+
+ if ((family = nl_str2af(arg)) != AF_UNSPEC)
+ rtnl_addr_set_family(addr, family);
+}
+
+void nl_cli_addr_parse_local(struct rtnl_addr *addr, char *arg)
+{
+ struct nl_addr *a;
+ int err;
+
+ a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr));
+ if ((err = rtnl_addr_set_local(addr, a)) < 0)
+ nl_cli_fatal(err, "Unable to set local address: %s",
+ nl_geterror(err));
+
+ nl_addr_put(a);
+}
+
+void nl_cli_addr_parse_dev(struct rtnl_addr *addr, struct nl_cache *link_cache,
+ char *arg)
+{
+ int ival;
+
+ if (!(ival = rtnl_link_name2i(link_cache, arg)))
+ nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+ rtnl_addr_set_ifindex(addr, ival);
+}
+
+void nl_cli_addr_parse_label(struct rtnl_addr *addr, char *arg)
+{
+ int err;
+
+ if ((err = rtnl_addr_set_label(addr, arg)) < 0)
+ nl_cli_fatal(err, "Unable to set address label: %s",
+ nl_geterror(err));
+}
+
+void nl_cli_addr_parse_peer(struct rtnl_addr *addr, char *arg)
+{
+ struct nl_addr *a;
+ int err;
+
+ a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr));
+ if ((err = rtnl_addr_set_peer(addr, a)) < 0)
+ nl_cli_fatal(err, "Unable to set peer address: %s",
+ nl_geterror(err));
+
+ nl_addr_put(a);
+}
+
+void nl_cli_addr_parse_scope(struct rtnl_addr *addr, char *arg)
+{
+ int ival;
+
+ if ((ival = rtnl_str2scope(arg)) < 0)
+ nl_cli_fatal(EINVAL, "Unknown address scope \"%s\"", arg);
+
+ rtnl_addr_set_scope(addr, ival);
+}
+
+void nl_cli_addr_parse_broadcast(struct rtnl_addr *addr, char *arg)
+{
+ struct nl_addr *a;
+ int err;
+
+ a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr));
+ if ((err = rtnl_addr_set_broadcast(addr, a)) < 0)
+ nl_cli_fatal(err, "Unable to set broadcast address: %s",
+ nl_geterror(err));
+
+ nl_addr_put(a);
+}
+
+static uint32_t parse_lifetime(const char *arg)
+{
+ uint64_t msecs;
+ int err;
+
+ if (!strcasecmp(arg, "forever"))
+ return 0xFFFFFFFFU;
+
+ if ((err = nl_str2msec(arg, &msecs)) < 0)
+ nl_cli_fatal(err, "Unable to parse time string \"%s\": %s",
+ arg, nl_geterror(err));
+
+ return (msecs / 1000);
+}
+
+void nl_cli_addr_parse_preferred(struct rtnl_addr *addr, char *arg)
+{
+ rtnl_addr_set_preferred_lifetime(addr, parse_lifetime(arg));
+}
+
+void nl_cli_addr_parse_valid(struct rtnl_addr *addr, char *arg)
+{
+ rtnl_addr_set_valid_lifetime(addr, parse_lifetime(arg));
+}
+
+/** @} */
diff --git a/src/lib/ct.c b/src/lib/ct.c
new file mode 100644
index 0000000..5bab08f
--- /dev/null
+++ b/src/lib/ct.c
@@ -0,0 +1,162 @@
+/*
+ * src/lib/ct.c CLI 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_ct Connection Tracking
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/ct.h>
+
+struct nfnl_ct *nl_cli_ct_alloc(void)
+{
+ struct nfnl_ct *ct;
+
+ ct = nfnl_ct_alloc();
+ if (!ct)
+ nl_cli_fatal(ENOMEM, "Unable to allocate conntrack object");
+
+ return ct;
+}
+
+struct nl_cache *nl_cli_ct_alloc_cache(struct nl_sock *sk)
+{
+ return nl_cli_alloc_cache(sk, "conntrack", nfnl_ct_alloc_cache);
+}
+
+void nl_cli_ct_parse_family(struct nfnl_ct *ct, char *arg)
+{
+ int family;
+
+ if ((family = nl_str2af(arg)) == AF_UNSPEC)
+ nl_cli_fatal(EINVAL,
+ "Unable to nl_cli_ct_parse family \"%s\": %s",
+ arg, nl_geterror(NLE_INVAL));
+
+ nfnl_ct_set_family(ct, family);
+}
+
+void nl_cli_ct_parse_protocol(struct nfnl_ct *ct, char *arg)
+{
+ int proto;
+
+ if ((proto = nl_str2ip_proto(arg)) < 0)
+ nl_cli_fatal(proto,
+ "Unable to nl_cli_ct_parse protocol \"%s\": %s",
+ arg, nl_geterror(proto));
+
+ nfnl_ct_set_proto(ct, proto);
+}
+
+void nl_cli_ct_parse_mark(struct nfnl_ct *ct, char *arg)
+{
+ uint32_t mark = nl_cli_parse_u32(arg);
+ nfnl_ct_set_mark(ct, mark);
+}
+
+void nl_cli_ct_parse_timeout(struct nfnl_ct *ct, char *arg)
+{
+ uint32_t timeout = nl_cli_parse_u32(arg);
+ nfnl_ct_set_timeout(ct, timeout);
+}
+
+void nl_cli_ct_parse_id(struct nfnl_ct *ct, char *arg)
+{
+ uint32_t id = nl_cli_parse_u32(arg);
+ nfnl_ct_set_id(ct, id);
+}
+
+void nl_cli_ct_parse_use(struct nfnl_ct *ct, char *arg)
+{
+ uint32_t use = nl_cli_parse_u32(arg);
+ nfnl_ct_set_use(ct, use);
+}
+
+void nl_cli_ct_parse_src(struct nfnl_ct *ct, int reply, char *arg)
+{
+ int err;
+ struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_ct_get_family(ct));
+ if ((err = nfnl_ct_set_src(ct, reply, a)) < 0)
+ nl_cli_fatal(err, "Unable to set source address: %s",
+ nl_geterror(err));
+}
+
+void nl_cli_ct_parse_dst(struct nfnl_ct *ct, int reply, char *arg)
+{
+ int err;
+ struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_ct_get_family(ct));
+ if ((err = nfnl_ct_set_dst(ct, reply, a)) < 0)
+ nl_cli_fatal(err, "Unable to set destination address: %s",
+ nl_geterror(err));
+}
+
+void nl_cli_ct_parse_src_port(struct nfnl_ct *ct, int reply, char *arg)
+{
+ uint32_t port = nl_cli_parse_u32(arg);
+ nfnl_ct_set_src_port(ct, reply, port);
+}
+
+void nl_cli_ct_parse_dst_port(struct nfnl_ct *ct, int reply, char *arg)
+{
+ uint32_t port = nl_cli_parse_u32(arg);
+ nfnl_ct_set_dst_port(ct, reply, port);
+}
+
+void nl_cli_ct_parse_tcp_state(struct nfnl_ct *ct, char *arg)
+{
+ int state;
+
+ if ((state = nfnl_ct_str2tcp_state(arg)) < 0)
+ nl_cli_fatal(state,
+ "Unable to nl_cli_ct_parse tcp state \"%s\": %s",
+ arg, nl_geterror(state));
+
+ nfnl_ct_set_tcp_state(ct, state);
+}
+
+void nl_cli_ct_parse_status(struct nfnl_ct *ct, char *arg)
+{
+ int status;
+
+ if ((status = nfnl_ct_str2status(arg)) < 0)
+ nl_cli_fatal(status,
+ "Unable to nl_cli_ct_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/lib/link.c b/src/lib/link.c
new file mode 100644
index 0000000..c192569
--- /dev/null
+++ b/src/lib/link.c
@@ -0,0 +1,73 @@
+/*
+ * src/lib/link.c CLI 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_link Links
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+struct rtnl_link *nl_cli_link_alloc(void)
+{
+ struct rtnl_link *link;
+
+ link = rtnl_link_alloc();
+ if (!link)
+ nl_cli_fatal(ENOMEM, "Unable to allocate link object");
+
+ return link;
+}
+
+void nl_cli_link_parse_family(struct rtnl_link *link, char *arg)
+{
+ int family;
+
+ if ((family = nl_str2af(arg)) == AF_UNSPEC)
+ nl_cli_fatal(EINVAL,
+ "Unable to translate address family \"%s\"", arg);
+
+ rtnl_link_set_family(link, family);
+}
+
+void nl_cli_link_parse_name(struct rtnl_link *link, char *arg)
+{
+ rtnl_link_set_name(link, arg);
+}
+
+void nl_cli_link_parse_mtu(struct rtnl_link *link, char *arg)
+{
+ uint32_t mtu = nl_cli_parse_u32(arg);
+ rtnl_link_set_mtu(link, mtu);
+}
+
+void nl_cli_link_parse_ifindex(struct rtnl_link *link, char *arg)
+{
+ uint32_t index = nl_cli_parse_u32(arg);
+ rtnl_link_set_ifindex(link, index);
+}
+
+void nl_cli_link_parse_txqlen(struct rtnl_link *link, char *arg)
+{
+ uint32_t qlen = nl_cli_parse_u32(arg);
+ rtnl_link_set_txqlen(link, qlen);
+}
+
+void nl_cli_link_parse_weight(struct rtnl_link *link, char *arg)
+{
+ uint32_t weight = nl_cli_parse_u32(arg);
+ rtnl_link_set_weight(link, weight);
+}
+
+/** @} */
diff --git a/src/lib/neigh.c b/src/lib/neigh.c
new file mode 100644
index 0000000..a814bd8
--- /dev/null
+++ b/src/lib/neigh.c
@@ -0,0 +1,88 @@
+/*
+ * src/lib/neigh.c CLI 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_neigh Neighbour
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/neigh.h>
+
+struct rtnl_neigh *nl_cli_neigh_alloc(void)
+{
+ struct rtnl_neigh *neigh;
+
+ neigh = rtnl_neigh_alloc();
+ if (!neigh)
+ nl_cli_fatal(ENOMEM, "Unable to allocate neighbout object");
+
+ return neigh;
+}
+
+void nl_cli_neigh_parse_dst(struct rtnl_neigh *neigh, char *arg)
+{
+ struct nl_addr *a;
+ int err;
+
+ a = nl_cli_addr_parse(arg, rtnl_neigh_get_family(neigh));
+ if ((err = rtnl_neigh_set_dst(neigh, a)) < 0)
+ nl_cli_fatal(err, "Unable to set local address: %s",
+ nl_geterror(err));
+
+ nl_addr_put(a);
+}
+
+void nl_cli_neigh_parse_lladdr(struct rtnl_neigh *neigh, char *arg)
+{
+ struct nl_addr *a;
+
+ a = nl_cli_addr_parse(arg, AF_UNSPEC);
+ rtnl_neigh_set_lladdr(neigh, a);
+ nl_addr_put(a);
+}
+
+void nl_cli_neigh_parse_dev(struct rtnl_neigh *neigh,
+ struct nl_cache *link_cache, char *arg)
+{
+ int ival;
+
+ if (!(ival = rtnl_link_name2i(link_cache, arg)))
+ nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+ rtnl_neigh_set_ifindex(neigh, ival);
+}
+
+void nl_cli_neigh_parse_family(struct rtnl_neigh *neigh, char *arg)
+{
+ int family;
+
+ if ((family = nl_str2af(arg)) == AF_UNSPEC)
+ nl_cli_fatal(EINVAL,
+ "Unable to translate address family \"%s\"", arg);
+
+ rtnl_neigh_set_family(neigh, family);
+}
+
+void nl_cli_neigh_parse_state(struct rtnl_neigh *neigh, char *arg)
+{
+ int state;
+
+ if ((state = rtnl_neigh_str2state(arg)) < 0)
+ nl_cli_fatal(state, "Unable to translate state \"%s\": %s",
+ arg, state);
+
+ rtnl_neigh_set_state(neigh, state);
+}
+
+/** @} */
diff --git a/src/lib/qdisc.c b/src/lib/qdisc.c
new file mode 100644
index 0000000..bc7ff92
--- /dev/null
+++ b/src/lib/qdisc.c
@@ -0,0 +1,72 @@
+/*
+ * src/lib/qdisc.c CLI 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_qdisc Queueing Disciplines
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/qdisc.h>
+
+struct rtnl_qdisc *nl_cli_qdisc_alloc(void)
+{
+ struct rtnl_qdisc *qdisc;
+
+ qdisc = rtnl_qdisc_alloc();
+ if (!qdisc)
+ nl_cli_fatal(ENOMEM, "Unable to allocate qdisc object");
+
+ return qdisc;
+}
+
+void nl_cli_qdisc_parse_dev(struct rtnl_qdisc *qdisc, struct nl_cache *link_cache, char *arg)
+{
+ int ival;
+
+ if (!(ival = rtnl_link_name2i(link_cache, arg)))
+ nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+ rtnl_qdisc_set_ifindex(qdisc, ival);
+}
+
+void nl_cli_qdisc_parse_parent(struct rtnl_qdisc *qdisc, char *arg)
+{
+ uint32_t parent;
+ int err;
+
+ if ((err = rtnl_tc_str2handle(arg, &parent)) < 0)
+ nl_cli_fatal(err, "Unable to parse handle \"%s\": %s",
+ arg, nl_geterror(err));
+
+ rtnl_qdisc_set_parent(qdisc, parent);
+}
+
+void nl_cli_qdisc_parse_handle(struct rtnl_qdisc *qdisc, char *arg)
+{
+ uint32_t handle;
+ int err;
+
+ if ((err = rtnl_tc_str2handle(arg, &handle)) < 0)
+ nl_cli_fatal(err, "Unable to parse handle \"%s\": %s",
+ arg, nl_geterror(err));
+
+ rtnl_qdisc_set_handle(qdisc, handle);
+}
+
+void nl_cli_qdisc_parse_kind(struct rtnl_qdisc *qdisc, char *arg)
+{
+ rtnl_qdisc_set_kind(qdisc, arg);
+}
+
+/** @} */
diff --git a/src/lib/route.c b/src/lib/route.c
new file mode 100644
index 0000000..05cb2ad
--- /dev/null
+++ b/src/lib/route.c
@@ -0,0 +1,270 @@
+/*
+ * src/lib/route.c CLI Route 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_route Routing
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/route.h>
+
+struct rtnl_route *nl_cli_route_alloc(void)
+{
+ struct rtnl_route *route;
+
+ route = rtnl_route_alloc();
+ if (!route)
+ nl_cli_fatal(ENOMEM, "Unable to allocate route object");
+
+ return route;
+}
+
+struct nl_cache *nl_cli_route_alloc_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)
+ nl_cli_fatal(err, "Unable to allocate route cache: %s\n",
+ nl_geterror(err));
+
+ nl_cache_mngt_provide(cache);
+
+ return cache;
+}
+
+void nl_cli_route_parse_family(struct rtnl_route *route, char *arg)
+{
+ int family;
+
+ if ((family = nl_str2af(arg)) != AF_UNSPEC)
+ rtnl_route_set_family(route, family);
+}
+
+void nl_cli_route_parse_dst(struct rtnl_route *route, char *arg)
+{
+ struct nl_addr *addr;
+ int err;
+
+ addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
+ if ((err = rtnl_route_set_dst(route, addr)) < 0)
+ nl_cli_fatal(err, "Unable to set destination address: %s",
+ nl_geterror(err));
+
+ nl_addr_put(addr);
+}
+
+void nl_cli_route_parse_src(struct rtnl_route *route, char *arg)
+{
+ struct nl_addr *addr;
+ int err;
+
+ addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
+ if ((err = rtnl_route_set_src(route, addr)) < 0)
+ nl_cli_fatal(err, "Unable to set source address: %s",
+ nl_geterror(err));
+
+ nl_addr_put(addr);
+}
+
+void nl_cli_route_parse_pref_src(struct rtnl_route *route, char *arg)
+{
+ struct nl_addr *addr;
+ int err;
+
+ addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
+ if ((err = rtnl_route_set_pref_src(route, addr)) < 0)
+ nl_cli_fatal(err, "Unable to set preferred source address: %s",
+ nl_geterror(err));
+
+ nl_addr_put(addr);
+}
+
+void nl_cli_route_parse_metric(struct rtnl_route *route, char *subopts)
+{
+ /* strict equal order to RTAX_* */
+ static char *const tokens[] = {
+ "unspec",
+ "lock",
+ "mtu",
+ "window",
+ "rtt",
+ "rttvar",
+ "sstresh",
+ "cwnd",
+ "advmss",
+ "reordering",
+ "hoplimit",
+ "initcwnd",
+ "features",
+ NULL,
+ };
+ unsigned long lval;
+ char *arg, *endptr;
+
+ while (*subopts != '\0') {
+ int ret = getsubopt(&subopts, tokens, &arg);
+ if (ret == -1)
+ nl_cli_fatal(EINVAL, "Unknown metric token \"%s\"", arg);
+
+ if (ret == 0)
+ nl_cli_fatal(EINVAL, "Invalid metric \"%s\"", tokens[ret]);
+
+ if (arg == NULL)
+ nl_cli_fatal(EINVAL, "Metric \"%s\", no value given", tokens[ret]);
+
+ lval = strtoul(arg, &endptr, 0);
+ if (endptr == arg)
+ nl_cli_fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]);
+
+ if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0)
+ nl_cli_fatal(ret, "Unable to set metric: %s",
+ nl_geterror(ret));
+ }
+}
+
+void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts,
+ struct nl_cache *link_cache)
+{
+ enum {
+ NH_DEV,
+ NH_VIA,
+ NH_WEIGHT,
+ };
+ static char *const tokens[] = {
+ "dev",
+ "via",
+ "weight",
+ NULL,
+ };
+ struct rtnl_nexthop *nh;
+ unsigned long lval;
+ struct nl_addr *addr;
+ int ival;
+ char *arg, *endptr;
+
+ if (!(nh = rtnl_route_nh_alloc()))
+ nl_cli_fatal(ENOMEM, "Out of memory");
+
+ while (*subopts != '\0') {
+ int ret = getsubopt(&subopts, tokens, &arg);
+ if (ret == -1)
+ nl_cli_fatal(EINVAL, "Unknown nexthop token \"%s\"", arg);
+
+ if (arg == NULL)
+ nl_cli_fatal(EINVAL, "Missing argument to option \"%s\"\n",
+ tokens[ret]);
+
+ switch (ret) {
+ case NH_DEV:
+ if (!(ival = rtnl_link_name2i(link_cache, arg)))
+ nl_cli_fatal(ENOENT,"Link \"%s\" does not exist", arg);
+
+ rtnl_route_nh_set_ifindex(nh, ival);
+ break;
+
+ case NH_VIA:
+ addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route));
+ rtnl_route_nh_set_gateway(nh, addr);
+ nl_addr_put(addr);
+ break;
+
+ case NH_WEIGHT:
+ lval = strtoul(arg, &endptr, 0);
+ if (endptr == arg)
+ nl_cli_fatal(EINVAL,
+ "Invalid weight \"%s\", not numeric",
+ arg);
+ rtnl_route_nh_set_weight(nh, lval);
+ break;
+ }
+ }
+
+ rtnl_route_add_nexthop(route, nh);
+}
+
+void nl_cli_route_parse_table(struct rtnl_route *route, char *arg)
+{
+ unsigned long lval;
+ char *endptr;
+
+ lval = strtoul(arg, &endptr, 0);
+ if (endptr == arg) {
+ if ((lval = rtnl_route_str2table(arg)) < 0)
+ nl_cli_fatal(EINVAL, "Unknown table name \"%s\"", arg);
+ }
+
+ rtnl_route_set_table(route, lval);
+}
+
+void nl_cli_route_parse_prio(struct rtnl_route *route, char *arg)
+{
+ unsigned long lval;
+ char *endptr;
+
+ lval = strtoul(arg, &endptr, 0);
+ if (endptr == arg)
+ nl_cli_fatal(EINVAL, "Invalid priority value, not numeric");
+ rtnl_route_set_priority(route, lval);
+}
+
+void nl_cli_route_parse_scope(struct rtnl_route *route, char *arg)
+{
+ int ival;
+
+ if ((ival = rtnl_str2scope(arg)) < 0)
+ nl_cli_fatal(EINVAL, "Unknown routing scope \"%s\"", arg);
+
+ rtnl_route_set_scope(route, ival);
+}
+
+void nl_cli_route_parse_protocol(struct rtnl_route *route, char *arg)
+{
+ unsigned long lval;
+ char *endptr;
+
+ lval = strtoul(arg, &endptr, 0);
+ if (endptr == arg) {
+ if ((lval = rtnl_route_str2proto(arg)) < 0)
+ nl_cli_fatal(EINVAL,
+ "Unknown routing protocol name \"%s\"",
+ arg);
+ }
+
+ rtnl_route_set_protocol(route, lval);
+}
+
+void nl_cli_route_parse_type(struct rtnl_route *route, char *arg)
+{
+ int ival;
+
+ if ((ival = nl_str2rtntype(arg)) < 0)
+ nl_cli_fatal(EINVAL, "Unknown routing type \"%s\"", arg);
+
+ if ((ival = rtnl_route_set_type(route, ival)) < 0)
+ nl_cli_fatal(ival, "Unable to set routing type: %s",
+ nl_geterror(ival));
+}
+
+void nl_cli_route_parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache)
+{
+ int ival;
+
+ if (!(ival = rtnl_link_name2i(link_cache, arg)))
+ nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+ rtnl_route_set_iif(route, ival);
+}
+
+/** @} */
diff --git a/src/lib/rule.c b/src/lib/rule.c
new file mode 100644
index 0000000..96f1d4c
--- /dev/null
+++ b/src/lib/rule.c
@@ -0,0 +1,55 @@
+/*
+ * src/lib/rule.c CLI 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_rule Routing Rules
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/rule.h>
+
+struct rtnl_rule *nl_cli_rule_alloc(void)
+{
+ struct rtnl_rule *rule;
+
+ rule = rtnl_rule_alloc();
+ if (!rule)
+ nl_cli_fatal(ENOMEM, "Unable to allocate rule object");
+
+ return rule;
+}
+
+struct nl_cache *nl_cli_rule_alloc_cache(struct nl_sock *sk)
+{
+ struct nl_cache *cache;
+ int err;
+
+ if ((err = rtnl_rule_alloc_cache(sk, AF_UNSPEC, &cache)) < 0)
+ nl_cli_fatal(err, "Unable to allocate routing rule cache: %s\n",
+ nl_geterror(err));
+
+ nl_cache_mngt_provide(cache);
+
+ return cache;
+}
+
+void nl_cli_rule_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/lib/utils.c b/src/lib/utils.c
new file mode 100644
index 0000000..02a7be1
--- /dev/null
+++ b/src/lib/utils.c
@@ -0,0 +1,147 @@
+/*
+ * src/utils.c Utilities
+ *
+ * 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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @defgroup cli Command Line Interface API
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+
+uint32_t nl_cli_parse_u32(const char *arg)
+{
+ unsigned long lval;
+ char *endptr;
+
+ lval = strtoul(arg, &endptr, 0);
+ if (endptr == arg || lval == ULONG_MAX)
+ nl_cli_fatal(EINVAL, "Unable to parse \"%s\", not a number.",
+ arg);
+
+ return (uint32_t) lval;
+}
+
+void nl_cli_print_version(void)
+{
+ printf("libnl tools version %s\n", LIBNL_VERSION);
+ printf(
+ "Copyright (C) 2003-2009 Thomas Graf <tgraf@redhat.com>\n"
+ "\n"
+ "This program comes with ABSOLUTELY NO WARRANTY. This is free \n"
+ "software, and you are welcome to redistribute it under certain\n"
+ "conditions. See the GNU General Public License for details.\n"
+ );
+
+ exit(0);
+}
+
+void nl_cli_fatal(int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "Error: ");
+
+ if (fmt) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ } else
+ fprintf(stderr, "%s\n", strerror(err));
+
+ exit(abs(err));
+}
+
+int nl_cli_connect(struct nl_sock *sk, int protocol)
+{
+ int err;
+
+ if ((err = nl_connect(sk, protocol)) < 0)
+ nl_cli_fatal(err, "Unable to connect netlink socket: %s",
+ nl_geterror(err));
+
+ return err;
+}
+
+struct nl_sock *nl_cli_alloc_socket(void)
+{
+ struct nl_sock *sock;
+
+ if (!(sock = nl_socket_alloc()))
+ nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket");
+
+ return sock;
+}
+
+struct nl_addr *nl_cli_addr_parse(const char *str, int family)
+{
+ struct nl_addr *addr;
+ int err;
+
+ if ((err = nl_addr_parse(str, family, &addr)) < 0)
+ nl_cli_fatal(err, "Unable to parse address \"%s\": %s",
+ str, nl_geterror(err));
+
+ return addr;
+}
+
+int nl_cli_parse_dumptype(const char *str)
+{
+ if (!strcasecmp(str, "brief"))
+ return NL_DUMP_LINE;
+ else if (!strcasecmp(str, "details") || !strcasecmp(str, "detailed"))
+ return NL_DUMP_DETAILS;
+ else if (!strcasecmp(str, "stats"))
+ return NL_DUMP_STATS;
+ else if (!strcasecmp(str, "env"))
+ return NL_DUMP_ENV;
+ else
+ nl_cli_fatal(EINVAL, "Invalid dump type \"%s\".\n", str);
+
+ return 0;
+}
+
+int nl_cli_confirm(struct nl_object *obj, struct nl_dump_params *params,
+ int default_yes)
+{
+ int answer;
+
+ nl_object_dump(obj, params);
+ 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');
+
+ return answer == 'y';
+}
+
+struct nl_cache *nl_cli_alloc_cache(struct nl_sock *sock, const char *name,
+ int (*ac)(struct nl_sock *, struct nl_cache **))
+{
+ struct nl_cache *cache;
+ int err;
+
+ if ((err = ac(sock, &cache)) < 0)
+ nl_cli_fatal(err, "Unable to allocate %s cache: %s",
+ name, nl_geterror(err));
+
+ nl_cache_mngt_provide(cache);
+
+ return cache;
+}
+
+/** @} */