summaryrefslogtreecommitdiffstats
path: root/lib/route
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route')
-rw-r--r--lib/route/.gitignore4
-rw-r--r--lib/route/addr.c514
-rw-r--r--lib/route/class.c147
-rw-r--r--lib/route/class_api.c6
-rw-r--r--lib/route/class_obj.c52
-rw-r--r--lib/route/cls.c (renamed from lib/route/classifier.c)159
-rw-r--r--lib/route/cls/basic.c211
-rw-r--r--lib/route/cls/cgroup.c141
-rw-r--r--lib/route/cls/ematch.c410
-rw-r--r--lib/route/cls/ematch/cmp.c116
-rw-r--r--lib/route/cls/ematch/container.c39
-rw-r--r--lib/route/cls/fw.c143
-rw-r--r--lib/route/cls/u32.c234
-rw-r--r--lib/route/cls_api.c6
-rw-r--r--lib/route/cls_obj.c122
-rw-r--r--lib/route/link.c343
-rw-r--r--lib/route/link/api.c8
-rw-r--r--lib/route/link/vlan.c100
-rw-r--r--lib/route/neigh.c325
-rw-r--r--lib/route/neightbl.c193
-rw-r--r--lib/route/nexthop.c239
-rw-r--r--lib/route/pktloc.c168
-rw-r--r--lib/route/pktloc_grammar.l42
-rw-r--r--lib/route/pktloc_syntax.y108
-rw-r--r--lib/route/qdisc.c159
-rw-r--r--lib/route/qdisc_api.c4
-rw-r--r--lib/route/qdisc_obj.c49
-rw-r--r--lib/route/route.c354
-rw-r--r--lib/route/route_obj.c1080
-rw-r--r--lib/route/route_utils.c33
-rw-r--r--lib/route/rtnl.c11
-rw-r--r--lib/route/rule.c328
-rw-r--r--lib/route/sch/cbq.c100
-rw-r--r--lib/route/sch/dsmark.c68
-rw-r--r--lib/route/sch/fifo.c28
-rw-r--r--lib/route/sch/htb.c59
-rw-r--r--lib/route/sch/netem.c444
-rw-r--r--lib/route/sch/prio.c66
-rw-r--r--lib/route/sch/red.c33
-rw-r--r--lib/route/sch/sfq.c41
-rw-r--r--lib/route/sch/tbf.c65
-rw-r--r--lib/route/tc.c78
42 files changed, 4031 insertions, 2799 deletions
diff --git a/lib/route/.gitignore b/lib/route/.gitignore
new file mode 100644
index 0000000..debf3b7
--- /dev/null
+++ b/lib/route/.gitignore
@@ -0,0 +1,4 @@
+pktloc_grammar.h
+pktloc_grammar.c
+pktloc_syntax.h
+pktloc_syntax.c
diff --git a/lib/route/addr.c b/lib/route/addr.c
index b8ec56c..2e72f6e 100644
--- a/lib/route/addr.c
+++ b/lib/route/addr.c
@@ -6,8 +6,8 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- * Baruch Even <baruch@ev-en.org>,
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
* Mediatrix Telecom, inc. <ericb@mediatrix.com>
*/
@@ -48,17 +48,16 @@
* // cannot be set for IPv6 addresses.
* rtnl_addr_set_scope(addr, rtnl_str2scope("site"));
*
- * // Broadcast and anycast address may be specified using the relevant
+ * // Broadcast address may be specified using the relevant
* // functions, the address family will be verified if one of the other
* // addresses has been set already. Currently only works for IPv4.
* rtnl_addr_set_broadcast(addr, broadcast_addr);
- * rtnl_addr_set_anycast(addr, anycast_addr);
*
* // Build the netlink message and send it to the kernel, the operation will
* // block until the operation has been completed. Alternatively the required
* // netlink message can be built using rtnl_addr_build_add_request() to be
* // sent out using nl_send_auto_complete().
- * rtnl_addr_add(handle, addr, 0);
+ * rtnl_addr_add(sk, addr, 0);
*
* // Free the memory
* rtnl_addr_put(addr);
@@ -99,7 +98,7 @@
* // block until the operation has been completed. Alternatively the required
* // netlink message can be built using rtnl_addr_build_delete_request()
* // to be sent out using nl_send_auto_complete().
- * rtnl_addr_delete(handle, addr, 0);
+ * rtnl_addr_delete(sk, addr, 0);
*
* // Free the memory
* rtnl_addr_put(addr);
@@ -126,13 +125,20 @@
#define ADDR_ATTR_PEER 0x0080
#define ADDR_ATTR_LOCAL 0x0100
#define ADDR_ATTR_BROADCAST 0x0200
-#define ADDR_ATTR_ANYCAST 0x0400
-#define ADDR_ATTR_MULTICAST 0x0800
+#define ADDR_ATTR_MULTICAST 0x0400
+#define ADDR_ATTR_ANYCAST 0x0800
static struct nl_cache_ops rtnl_addr_ops;
static struct nl_object_ops addr_obj_ops;
/** @endcond */
+static void addr_constructor(struct nl_object *obj)
+{
+ struct rtnl_addr *addr = nl_object_priv(obj);
+
+ addr->a_scope = RT_SCOPE_NOWHERE;
+}
+
static void addr_free_data(struct nl_object *obj)
{
struct rtnl_addr *addr = nl_object_priv(obj);
@@ -143,8 +149,8 @@ static void addr_free_data(struct nl_object *obj)
nl_addr_put(addr->a_peer);
nl_addr_put(addr->a_local);
nl_addr_put(addr->a_bcast);
- nl_addr_put(addr->a_anycast);
nl_addr_put(addr->a_multicast);
+ nl_addr_put(addr->a_anycast);
}
static int addr_clone(struct nl_object *_dst, struct nl_object *_src)
@@ -154,27 +160,25 @@ static int addr_clone(struct nl_object *_dst, struct nl_object *_src)
if (src->a_peer)
if (!(dst->a_peer = nl_addr_clone(src->a_peer)))
- goto errout;
+ return -NLE_NOMEM;
if (src->a_local)
if (!(dst->a_local = nl_addr_clone(src->a_local)))
- goto errout;
+ return -NLE_NOMEM;
if (src->a_bcast)
if (!(dst->a_bcast = nl_addr_clone(src->a_bcast)))
- goto errout;
-
- if (src->a_anycast)
- if (!(dst->a_anycast = nl_addr_clone(src->a_anycast)))
- goto errout;
+ return -NLE_NOMEM;
if (src->a_multicast)
if (!(dst->a_multicast = nl_addr_clone(src->a_multicast)))
- goto errout;
+ return -NLE_NOMEM;
+
+ if (src->a_anycast)
+ if (!(dst->a_anycast = nl_addr_clone(src->a_anycast)))
+ return -NLE_NOMEM;
return 0;
-errout:
- return nl_get_errno();
}
static struct nla_policy addr_policy[IFA_MAX+1] = {
@@ -189,21 +193,20 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct rtnl_addr *addr;
struct ifaddrmsg *ifa;
struct nlattr *tb[IFA_MAX+1];
- int err = -ENOMEM, peer_prefix = 0;
+ int err, peer_prefix = 0, family;
addr = rtnl_addr_alloc();
- if (!addr) {
- err = nl_errno(ENOMEM);
- goto errout;
- }
+ if (!addr)
+ return -NLE_NOMEM;
+
addr->ce_msgtype = nlh->nlmsg_type;
err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy);
if (err < 0)
- goto errout_free;
+ goto errout;
ifa = nlmsg_data(nlh);
- addr->a_family = ifa->ifa_family;
+ addr->a_family = family = ifa->ifa_family;
addr->a_prefixlen = ifa->ifa_prefixlen;
addr->a_flags = ifa->ifa_flags;
addr->a_scope = ifa->ifa_scope;
@@ -229,18 +232,18 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
if (tb[IFA_LOCAL]) {
- addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family);
+ addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family);
if (!addr->a_local)
- goto errout_free;
+ goto errout_nomem;
addr->ce_mask |= ADDR_ATTR_LOCAL;
}
if (tb[IFA_ADDRESS]) {
struct nl_addr *a;
- a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family);
+ a = nl_addr_alloc_attr(tb[IFA_ADDRESS], family);
if (!a)
- goto errout_free;
+ goto errout_nomem;
/* IPv6 sends the local address as IFA_ADDRESS with
* no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
@@ -260,48 +263,48 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
addr->a_prefixlen);
if (tb[IFA_BROADCAST]) {
- addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family);
+ addr->a_bcast = nl_addr_alloc_attr(tb[IFA_BROADCAST], family);
if (!addr->a_bcast)
- goto errout_free;
+ goto errout_nomem;
addr->ce_mask |= ADDR_ATTR_BROADCAST;
}
- if (tb[IFA_ANYCAST]) {
- addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family);
- if (!addr->a_anycast)
- goto errout_free;
-
- addr->ce_mask |= ADDR_ATTR_ANYCAST;
- }
-
if (tb[IFA_MULTICAST]) {
- addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST],
- addr->a_family);
+ addr->a_multicast = nl_addr_alloc_attr(tb[IFA_MULTICAST],
+ family);
if (!addr->a_multicast)
- goto errout_free;
+ goto errout_nomem;
addr->ce_mask |= ADDR_ATTR_MULTICAST;
}
- err = pp->pp_cb((struct nl_object *) addr, pp);
- if (err < 0)
- goto errout_free;
+ if (tb[IFA_ANYCAST]) {
+ addr->a_anycast = nl_addr_alloc_attr(tb[IFA_ANYCAST],
+ family);
+ if (!addr->a_anycast)
+ goto errout_nomem;
- err = P_ACCEPT;
+ addr->ce_mask |= ADDR_ATTR_ANYCAST;
+ }
-errout_free:
- rtnl_addr_put(addr);
+ err = pp->pp_cb((struct nl_object *) addr, pp);
errout:
+ rtnl_addr_put(addr);
+
return err;
+
+errout_nomem:
+ err = -NLE_NOMEM;
+ goto errout;
}
-static int addr_request_update(struct nl_cache *cache, struct nl_handle *handle)
+static int addr_request_update(struct nl_cache *cache, struct nl_sock *sk)
{
- return nl_rtgen_request(handle, RTM_GETADDR, AF_UNSPEC, NLM_F_DUMP);
+ return nl_rtgen_request(sk, RTM_GETADDR, AF_UNSPEC, NLM_F_DUMP);
}
-static int addr_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
+static void addr_dump_line(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_addr *addr = (struct rtnl_addr *) obj;
struct nl_cache *link_cache;
@@ -310,259 +313,166 @@ static int addr_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
link_cache = nl_cache_mngt_require("route/link");
if (addr->ce_mask & ADDR_ATTR_LOCAL)
- dp_dump(p, "%s",
+ nl_dump_line(p, "%s",
nl_addr2str(addr->a_local, buf, sizeof(buf)));
else
- dp_dump(p, "none");
+ nl_dump_line(p, "none");
if (addr->ce_mask & ADDR_ATTR_PEER)
- dp_dump(p, " peer %s",
+ nl_dump(p, " peer %s",
nl_addr2str(addr->a_peer, buf, sizeof(buf)));
- dp_dump(p, " %s ", nl_af2str(addr->a_family, buf, sizeof(buf)));
+ nl_dump(p, " %s ", nl_af2str(addr->a_family, buf, sizeof(buf)));
if (link_cache)
- dp_dump(p, "dev %s ",
+ nl_dump(p, "dev %s ",
rtnl_link_i2name(link_cache, addr->a_ifindex,
buf, sizeof(buf)));
else
- dp_dump(p, "dev %d ", addr->a_ifindex);
+ nl_dump(p, "dev %d ", addr->a_ifindex);
- dp_dump(p, "scope %s",
+ nl_dump(p, "scope %s",
rtnl_scope2str(addr->a_scope, buf, sizeof(buf)));
rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf));
if (buf[0])
- dp_dump(p, " <%s>", buf);
-
- dp_dump(p, "\n");
+ nl_dump(p, " <%s>", buf);
- return 1;
+ nl_dump(p, "\n");
}
-static int addr_dump_full(struct nl_object *obj, struct nl_dump_params *p)
+static void addr_dump_details(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_addr *addr = (struct rtnl_addr *) obj;
- int line = addr_dump_brief(obj, p);
char buf[128];
+ addr_dump_line(obj, p);
+
if (addr->ce_mask & (ADDR_ATTR_LABEL | ADDR_ATTR_BROADCAST |
- ADDR_ATTR_ANYCAST | ADDR_ATTR_MULTICAST)) {
- dp_dump_line(p, line++, " ");
+ ADDR_ATTR_MULTICAST)) {
+ nl_dump_line(p, " ");
if (addr->ce_mask & ADDR_ATTR_LABEL)
- dp_dump(p, " label %s", addr->a_label);
+ nl_dump(p, " label %s", addr->a_label);
if (addr->ce_mask & ADDR_ATTR_BROADCAST)
- dp_dump(p, " broadcast %s",
+ nl_dump(p, " broadcast %s",
nl_addr2str(addr->a_bcast, buf, sizeof(buf)));
- if (addr->ce_mask & ADDR_ATTR_ANYCAST)
- dp_dump(p, " anycast %s",
- nl_addr2str(addr->a_anycast, buf,
- sizeof(buf)));
-
if (addr->ce_mask & ADDR_ATTR_MULTICAST)
- dp_dump(p, " multicast %s",
+ nl_dump(p, " multicast %s",
nl_addr2str(addr->a_multicast, buf,
sizeof(buf)));
- dp_dump(p, "\n");
+ if (addr->ce_mask & ADDR_ATTR_ANYCAST)
+ nl_dump(p, " anycast %s",
+ nl_addr2str(addr->a_anycast, buf,
+ sizeof(buf)));
+
+ nl_dump(p, "\n");
}
if (addr->ce_mask & ADDR_ATTR_CACHEINFO) {
struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo;
- dp_dump_line(p, line++, " valid-lifetime %s",
+ nl_dump_line(p, " valid-lifetime %s",
ci->aci_valid == 0xFFFFFFFFU ? "forever" :
nl_msec2str(ci->aci_valid * 1000,
buf, sizeof(buf)));
- dp_dump(p, " preferred-lifetime %s\n",
+ nl_dump(p, " preferred-lifetime %s\n",
ci->aci_prefered == 0xFFFFFFFFU ? "forever" :
nl_msec2str(ci->aci_prefered * 1000,
buf, sizeof(buf)));
- dp_dump_line(p, line++, " created boot-time+%s ",
+ nl_dump_line(p, " created boot-time+%s ",
nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10,
buf, sizeof(buf)));
- dp_dump(p, "last-updated boot-time+%s\n",
+ nl_dump(p, "last-updated boot-time+%s\n",
nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10,
buf, sizeof(buf)));
}
-
- return line;
-}
-
-static int addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
-{
- return addr_dump_full(obj, p);
}
-static int addr_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
+static void addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
- struct rtnl_addr *addr = (struct rtnl_addr *) obj;
- struct nl_cache *link_cache;
- char buf[128];
- int line = 0;
-
- dp_dump_line(p, line++, "<address>\n");
- dp_dump_line(p, line++, " <family>%s</family>\n",
- nl_af2str(addr->a_family, buf, sizeof(buf)));
-
- if (addr->ce_mask & ADDR_ATTR_LOCAL)
- dp_dump_line(p, line++, " <local>%s</local>\n",
- nl_addr2str(addr->a_local, buf, sizeof(buf)));
-
- if (addr->ce_mask & ADDR_ATTR_PEER)
- dp_dump_line(p, line++, " <peer>%s</peer>\n",
- nl_addr2str(addr->a_peer, buf, sizeof(buf)));
-
- if (addr->ce_mask & ADDR_ATTR_BROADCAST)
- dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n",
- nl_addr2str(addr->a_bcast, buf, sizeof(buf)));
-
- if (addr->ce_mask & ADDR_ATTR_ANYCAST)
- dp_dump_line(p, line++, " <anycast>%s</anycast>\n",
- nl_addr2str(addr->a_anycast, buf, sizeof(buf)));
-
- if (addr->ce_mask & ADDR_ATTR_MULTICAST)
- dp_dump_line(p, line++, " <multicast>%s</multicast>\n",
- nl_addr2str(addr->a_multicast, buf,
- sizeof(buf)));
-
- if (addr->ce_mask & ADDR_ATTR_PREFIXLEN)
- dp_dump_line(p, line++, " <prefixlen>%u</prefixlen>\n",
- addr->a_prefixlen);
- link_cache = nl_cache_mngt_require("route/link");
-
- if (link_cache)
- dp_dump_line(p, line++, " <device>%s</device>\n",
- rtnl_link_i2name(link_cache, addr->a_ifindex,
- buf, sizeof(buf)));
- else
- dp_dump_line(p, line++, " <device>%u</device>\n",
- addr->a_ifindex);
-
- if (addr->ce_mask & ADDR_ATTR_SCOPE)
- dp_dump_line(p, line++, " <scope>%s</scope>\n",
- rtnl_scope2str(addr->a_scope, buf, sizeof(buf)));
-
- if (addr->ce_mask & ADDR_ATTR_LABEL)
- dp_dump_line(p, line++, " <label>%s</label>\n", addr->a_label);
-
- rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf));
- if (buf[0])
- dp_dump_line(p, line++, " <flags>%s</flags>\n", buf);
-
- if (addr->ce_mask & ADDR_ATTR_CACHEINFO) {
- struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo;
-
- dp_dump_line(p, line++, " <cacheinfo>\n");
-
- dp_dump_line(p, line++, " <valid>%s</valid>\n",
- ci->aci_valid == 0xFFFFFFFFU ? "forever" :
- nl_msec2str(ci->aci_valid * 1000,
- buf, sizeof(buf)));
-
- dp_dump_line(p, line++, " <prefered>%s</prefered>\n",
- ci->aci_prefered == 0xFFFFFFFFU ? "forever" :
- nl_msec2str(ci->aci_prefered * 1000,
- buf, sizeof(buf)));
-
- dp_dump_line(p, line++, " <created>%s</created>\n",
- nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10,
- buf, sizeof(buf)));
-
- dp_dump_line(p, line++, " <last-update>%s</last-update>\n",
- nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10,
- buf, sizeof(buf)));
-
- dp_dump_line(p, line++, " </cacheinfo>\n");
- }
-
- dp_dump_line(p, line++, "</address>\n");
-
- return line;
+ addr_dump_details(obj, p);
}
-static int addr_dump_env(struct nl_object *obj, struct nl_dump_params *p)
+static void addr_dump_env(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_addr *addr = (struct rtnl_addr *) obj;
struct nl_cache *link_cache;
char buf[128];
- int line = 0;
- dp_dump_line(p, line++, "ADDR_FAMILY=%s\n",
+ nl_dump_line(p, "ADDR_FAMILY=%s\n",
nl_af2str(addr->a_family, buf, sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_LOCAL)
- dp_dump_line(p, line++, "ADDR_LOCAL=%s\n",
+ nl_dump_line(p, "ADDR_LOCAL=%s\n",
nl_addr2str(addr->a_local, buf, sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_PEER)
- dp_dump_line(p, line++, "ADDR_PEER=%s\n",
+ nl_dump_line(p, "ADDR_PEER=%s\n",
nl_addr2str(addr->a_peer, buf, sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_BROADCAST)
- dp_dump_line(p, line++, "ADDR_BROADCAST=%s\n",
+ nl_dump_line(p, "ADDR_BROADCAST=%s\n",
nl_addr2str(addr->a_bcast, buf, sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_ANYCAST)
- dp_dump_line(p, line++, "ADDR_ANYCAST=%s\n",
+ nl_dump_line(p, "ADDR_ANYCAST=%s\n",
nl_addr2str(addr->a_anycast, buf, sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_MULTICAST)
- dp_dump_line(p, line++, "ADDR_MULTICAST=%s\n",
+ nl_dump_line(p, "ADDR_MULTICAST=%s\n",
nl_addr2str(addr->a_multicast, buf,
sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_PREFIXLEN)
- dp_dump_line(p, line++, "ADDR_PREFIXLEN=%u\n",
+ nl_dump_line(p, "ADDR_PREFIXLEN=%u\n",
addr->a_prefixlen);
link_cache = nl_cache_mngt_require("route/link");
- dp_dump_line(p, line++, "ADDR_IFINDEX=%u\n", addr->a_ifindex);
+ nl_dump_line(p, "ADDR_IFINDEX=%u\n", addr->a_ifindex);
if (link_cache)
- dp_dump_line(p, line++, "ADDR_IFNAME=%s\n",
+ nl_dump_line(p, "ADDR_IFNAME=%s\n",
rtnl_link_i2name(link_cache, addr->a_ifindex,
- buf, sizeof(buf)));
+ buf, sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_SCOPE)
- dp_dump_line(p, line++, "ADDR_SCOPE=%s\n",
+ nl_dump_line(p, "ADDR_SCOPE=%s\n",
rtnl_scope2str(addr->a_scope, buf, sizeof(buf)));
if (addr->ce_mask & ADDR_ATTR_LABEL)
- dp_dump_line(p, line++, "ADDR_LABEL=%s\n", addr->a_label);
+ nl_dump_line(p, "ADDR_LABEL=%s\n", addr->a_label);
rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf));
if (buf[0])
- dp_dump_line(p, line++, "ADDR_FLAGS=%s\n", buf);
+ nl_dump_line(p, "ADDR_FLAGS=%s\n", buf);
if (addr->ce_mask & ADDR_ATTR_CACHEINFO) {
struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo;
- dp_dump_line(p, line++, "ADDR_CACHEINFO_VALID=%s\n",
+ nl_dump_line(p, "ADDR_CACHEINFO_VALID=%s\n",
ci->aci_valid == 0xFFFFFFFFU ? "forever" :
nl_msec2str(ci->aci_valid * 1000,
buf, sizeof(buf)));
- dp_dump_line(p, line++, "ADDR_CACHEINFO_PREFERED=%s\n",
+ nl_dump_line(p, "ADDR_CACHEINFO_PREFERED=%s\n",
ci->aci_prefered == 0xFFFFFFFFU ? "forever" :
nl_msec2str(ci->aci_prefered * 1000,
buf, sizeof(buf)));
- dp_dump_line(p, line++, "ADDR_CACHEINFO_CREATED=%s\n",
+ nl_dump_line(p, "ADDR_CACHEINFO_CREATED=%s\n",
nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10,
buf, sizeof(buf)));
- dp_dump_line(p, line++, "ADDR_CACHEINFO_LASTUPDATE=%s\n",
+ nl_dump_line(p, "ADDR_CACHEINFO_LASTUPDATE=%s\n",
nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10,
buf, sizeof(buf)));
}
-
- return line;
}
static int addr_compare(struct nl_object *_a, struct nl_object *_b,
@@ -580,12 +490,12 @@ static int addr_compare(struct nl_object *_a, struct nl_object *_b,
diff |= ADDR_DIFF(LABEL, strcmp(a->a_label, b->a_label));
diff |= ADDR_DIFF(PEER, nl_addr_cmp(a->a_peer, b->a_peer));
diff |= ADDR_DIFF(LOCAL, nl_addr_cmp(a->a_local, b->a_local));
- diff |= ADDR_DIFF(ANYCAST, nl_addr_cmp(a->a_anycast,b->a_anycast));
diff |= ADDR_DIFF(MULTICAST, nl_addr_cmp(a->a_multicast,
b->a_multicast));
diff |= ADDR_DIFF(BROADCAST, nl_addr_cmp(a->a_bcast, b->a_bcast));
+ diff |= ADDR_DIFF(ANYCAST, nl_addr_cmp(a->a_anycast, b->a_anycast));
- if (flags & LOOSE_FLAG_COMPARISON)
+ if (flags & LOOSE_COMPARISON)
diff |= ADDR_DIFF(FLAGS,
(a->a_flags ^ b->a_flags) & b->a_flag_mask);
else
@@ -607,7 +517,6 @@ static struct trans_tbl addr_attrs[] = {
__ADD(ADDR_ATTR_PEER, peer)
__ADD(ADDR_ATTR_LOCAL, local)
__ADD(ADDR_ATTR_BROADCAST, broadcast)
- __ADD(ADDR_ATTR_ANYCAST, anycast)
__ADD(ADDR_ATTR_MULTICAST, multicast)
};
@@ -639,25 +548,15 @@ void rtnl_addr_put(struct rtnl_addr *addr)
* @{
*/
-struct nl_cache *rtnl_addr_alloc_cache(struct nl_handle *handle)
+int rtnl_addr_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
{
- struct nl_cache *cache;
-
- cache = nl_cache_alloc(&rtnl_addr_ops);
- if (!cache)
- return NULL;
-
- if (handle && nl_cache_refill(handle, cache) < 0) {
- nl_cache_free(cache);
- return NULL;
- }
-
- return cache;
+ return nl_cache_alloc_and_fill(&rtnl_addr_ops, sk, result);
}
/** @} */
-static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags)
+static int build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags,
+ struct nl_msg **result)
{
struct nl_msg *msg;
struct ifaddrmsg am = {
@@ -680,7 +579,7 @@ static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags)
msg = nlmsg_alloc_simple(cmd, flags);
if (!msg)
- goto nla_put_failure;
+ return -NLE_NOMEM;
if (nlmsg_append(msg, &am, sizeof(am), NLMSG_ALIGNTO) < 0)
goto nla_put_failure;
@@ -690,7 +589,7 @@ static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags)
if (tmpl->ce_mask & ADDR_ATTR_PEER)
NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_peer);
- else
+ else if (tmpl->ce_mask & ADDR_ATTR_LOCAL)
NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_local);
if (tmpl->ce_mask & ADDR_ATTR_LABEL)
@@ -699,14 +598,22 @@ static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags)
if (tmpl->ce_mask & ADDR_ATTR_BROADCAST)
NLA_PUT_ADDR(msg, IFA_BROADCAST, tmpl->a_bcast);
- if (tmpl->ce_mask & ADDR_ATTR_ANYCAST)
- NLA_PUT_ADDR(msg, IFA_ANYCAST, tmpl->a_anycast);
+ if (tmpl->ce_mask & ADDR_ATTR_CACHEINFO) {
+ struct ifa_cacheinfo ca = {
+ .ifa_valid = tmpl->a_cacheinfo.aci_valid,
+ .ifa_prefered = tmpl->a_cacheinfo.aci_prefered,
+ };
+
+ NLA_PUT(msg, IFA_CACHEINFO, sizeof(ca), &ca);
+ }
+
- return msg;
+ *result = msg;
+ return 0;
nla_put_failure:
nlmsg_free(msg);
- return NULL;
+ return -NLE_MSGSIZE;
}
/**
@@ -718,6 +625,7 @@ nla_put_failure:
* Build netlink request message to request addition of new address
* @arg addr Address object representing the new address.
* @arg flags Additional netlink message flags.
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting the addition of a new
* address. The netlink message header isn't fully equipped with
@@ -732,25 +640,24 @@ nla_put_failure:
* which case a host scope is used if not specified otherwise.
*
* @note Free the memory after usage using nlmsg_free().
- * @return Newly allocated netlink message or NULL if an error occured.
+ *
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags)
+int rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags,
+ struct nl_msg **result)
{
int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY |
ADDR_ATTR_PREFIXLEN | ADDR_ATTR_LOCAL;
- if ((addr->ce_mask & required) != required) {
- nl_error(EINVAL, "Missing mandatory attributes, required are: "
- "ifindex, family, prefixlen, local address.");
- return NULL;
- }
+ if ((addr->ce_mask & required) != required)
+ return -NLE_MISSING_ATTR;
- return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags);
+ return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags, result);
}
/**
* Request addition of new address
- * @arg handle Netlink handle.
+ * @arg sk Netlink socket.
* @arg addr Address object representing the new address.
* @arg flags Additional netlink message flags.
*
@@ -762,21 +669,20 @@ struct nl_msg *rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_addr_add(struct nl_handle *handle, struct rtnl_addr *addr, int flags)
+int rtnl_addr_add(struct nl_sock *sk, struct rtnl_addr *addr, int flags)
{
struct nl_msg *msg;
int err;
- msg = rtnl_addr_build_add_request(addr, flags);
- if (!msg)
- return nl_get_errno();
+ if ((err = rtnl_addr_build_add_request(addr, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
nlmsg_free(msg);
if (err < 0)
return err;
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -790,6 +696,7 @@ int rtnl_addr_add(struct nl_handle *handle, struct rtnl_addr *addr, int flags)
* Build a netlink request message to request deletion of an address
* @arg addr Address object to be deleteted.
* @arg flags Additional netlink message flags.
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting a deletion of an address.
* The netlink message header isn't fully equipped with all relevant
@@ -806,24 +713,23 @@ int rtnl_addr_add(struct nl_handle *handle, struct rtnl_addr *addr, int flags)
* - peer address (rtnl_addr_set_peer(), IPv4 only)
*
* @note Free the memory after usage using nlmsg_free().
- * @return Newly allocated netlink message or NULL if an error occured.
+ *
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags)
+int rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags,
+ struct nl_msg **result)
{
int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY;
- if ((addr->ce_mask & required) != required) {
- nl_error(EINVAL, "Missing mandatory attributes, required are: "
- "ifindex, family");
- return NULL;
- }
-
- return build_addr_msg(addr, RTM_DELADDR, flags);
+ if ((addr->ce_mask & required) != required)
+ return -NLE_MISSING_ATTR;
+
+ return build_addr_msg(addr, RTM_DELADDR, flags, result);
}
/**
* Request deletion of an address
- * @arg handle Netlink handle.
+ * @arg sk Netlink socket.
* @arg addr Address object to be deleted.
* @arg flags Additional netlink message flags.
*
@@ -835,22 +741,20 @@ struct nl_msg *rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_addr_delete(struct nl_handle *handle, struct rtnl_addr *addr,
- int flags)
+int rtnl_addr_delete(struct nl_sock *sk, struct rtnl_addr *addr, int flags)
{
struct nl_msg *msg;
int err;
- msg = rtnl_addr_build_delete_request(addr, flags);
- if (!msg)
- return nl_get_errno();
+ if ((err = rtnl_addr_build_delete_request(addr, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
nlmsg_free(msg);
if (err < 0)
return err;
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -860,10 +764,15 @@ int rtnl_addr_delete(struct nl_handle *handle, struct rtnl_addr *addr,
* @{
*/
-void rtnl_addr_set_label(struct rtnl_addr *addr, const char *label)
+int rtnl_addr_set_label(struct rtnl_addr *addr, const char *label)
{
- strncpy(addr->a_label, label, sizeof(addr->a_label) - 1);
+ if (strlen(label) > sizeof(addr->a_label) - 1)
+ return -NLE_RANGE;
+
+ strcpy(addr->a_label, label);
addr->ce_mask |= ADDR_ATTR_LABEL;
+
+ return 0;
}
char *rtnl_addr_get_label(struct rtnl_addr *addr)
@@ -882,10 +791,7 @@ void rtnl_addr_set_ifindex(struct rtnl_addr *addr, int ifindex)
int rtnl_addr_get_ifindex(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_IFINDEX)
- return addr->a_ifindex;
- else
- return RTNL_LINK_NOT_FOUND;
+ return addr->a_ifindex;
}
void rtnl_addr_set_family(struct rtnl_addr *addr, int family)
@@ -896,10 +802,7 @@ void rtnl_addr_set_family(struct rtnl_addr *addr, int family)
int rtnl_addr_get_family(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_FAMILY)
- return addr->a_family;
- else
- return AF_UNSPEC;
+ return addr->a_family;
}
void rtnl_addr_set_prefixlen(struct rtnl_addr *addr, int prefix)
@@ -910,10 +813,7 @@ void rtnl_addr_set_prefixlen(struct rtnl_addr *addr, int prefix)
int rtnl_addr_get_prefixlen(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_PREFIXLEN)
- return addr->a_prefixlen;
- else
- return -1;
+ return addr->a_prefixlen;
}
void rtnl_addr_set_scope(struct rtnl_addr *addr, int scope)
@@ -924,10 +824,7 @@ void rtnl_addr_set_scope(struct rtnl_addr *addr, int scope)
int rtnl_addr_get_scope(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_SCOPE)
- return addr->a_scope;
- else
- return -1;
+ return addr->a_scope;
}
void rtnl_addr_set_flags(struct rtnl_addr *addr, unsigned int flags)
@@ -954,7 +851,7 @@ static inline int __assign_addr(struct rtnl_addr *addr, struct nl_addr **pos,
{
if (addr->ce_mask & ADDR_ATTR_FAMILY) {
if (new->a_family != addr->a_family)
- return nl_error(EINVAL, "Address family mismatch");
+ return -NLE_AF_MISMATCH;
} else
addr->a_family = new->a_family;
@@ -985,10 +882,7 @@ int rtnl_addr_set_local(struct rtnl_addr *addr, struct nl_addr *local)
struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_LOCAL)
- return addr->a_local;
- else
- return NULL;
+ return addr->a_local;
}
int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer)
@@ -1003,10 +897,7 @@ int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer)
struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_PEER)
- return addr->a_peer;
- else
- return NULL;
+ return addr->a_peer;
}
int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast)
@@ -1016,10 +907,18 @@ int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast)
struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_BROADCAST)
- return addr->a_bcast;
- else
- return NULL;
+ return addr->a_bcast;
+}
+
+int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast)
+{
+ return __assign_addr(addr, &addr->a_multicast, multicast,
+ ADDR_ATTR_MULTICAST);
+}
+
+struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr)
+{
+ return addr->a_multicast;
}
int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast)
@@ -1030,24 +929,45 @@ int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast)
struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_ANYCAST)
- return addr->a_anycast;
+ return addr->a_anycast;
+}
+
+uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *addr)
+{
+ if (addr->ce_mask & ADDR_ATTR_CACHEINFO)
+ return addr->a_cacheinfo.aci_valid;
else
- return NULL;
+ return 0xFFFFFFFFU;
}
-int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast)
+void rtnl_addr_set_valid_lifetime(struct rtnl_addr *addr, uint32_t lifetime)
{
- return __assign_addr(addr, &addr->a_multicast, multicast,
- ADDR_ATTR_MULTICAST);
+ addr->a_cacheinfo.aci_valid = lifetime;
+ addr->ce_mask |= ADDR_ATTR_CACHEINFO;
}
-struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr)
+uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *addr)
{
- if (addr->ce_mask & ADDR_ATTR_MULTICAST)
- return addr->a_multicast;
+ if (addr->ce_mask & ADDR_ATTR_CACHEINFO)
+ return addr->a_cacheinfo.aci_prefered;
else
- return NULL;
+ return 0xFFFFFFFFU;
+}
+
+void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *addr, uint32_t lifetime)
+{
+ addr->a_cacheinfo.aci_prefered = lifetime;
+ addr->ce_mask |= ADDR_ATTR_CACHEINFO;
+}
+
+uint32_t rtnl_addr_get_create_time(struct rtnl_addr *addr)
+{
+ return addr->a_cacheinfo.aci_cstamp;
+}
+
+uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *addr)
+{
+ return addr->a_cacheinfo.aci_tstamp;
}
/** @} */
@@ -1059,6 +979,9 @@ struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr)
static struct trans_tbl addr_flags[] = {
__ADD(IFA_F_SECONDARY, secondary)
+ __ADD(IFA_F_NODAD, nodad)
+ __ADD(IFA_F_OPTIMISTIC, optimistic)
+ __ADD(IFA_F_HOMEADDRESS, homeaddress)
__ADD(IFA_F_DEPRECATED, deprecated)
__ADD(IFA_F_TENTATIVE, tentative)
__ADD(IFA_F_PERMANENT, permanent)
@@ -1080,18 +1003,19 @@ int rtnl_addr_str2flags(const char *name)
static struct nl_object_ops addr_obj_ops = {
.oo_name = "route/addr",
.oo_size = sizeof(struct rtnl_addr),
+ .oo_constructor = addr_constructor,
.oo_free_data = addr_free_data,
.oo_clone = addr_clone,
- .oo_dump[NL_DUMP_BRIEF] = addr_dump_brief,
- .oo_dump[NL_DUMP_FULL] = addr_dump_full,
- .oo_dump[NL_DUMP_STATS] = addr_dump_stats,
- .oo_dump[NL_DUMP_XML] = addr_dump_xml,
- .oo_dump[NL_DUMP_ENV] = addr_dump_env,
+ .oo_dump = {
+ [NL_DUMP_LINE] = addr_dump_line,
+ [NL_DUMP_DETAILS] = addr_dump_details,
+ [NL_DUMP_STATS] = addr_dump_stats,
+ [NL_DUMP_ENV] = addr_dump_env,
+ },
.oo_compare = addr_compare,
.oo_attrs2str = addr_attrs2str,
.oo_id_attrs = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
- ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN |
- ADDR_ATTR_PEER),
+ ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN),
};
static struct nl_af_group addr_groups[] = {
diff --git a/lib/route/class.c b/lib/route/class.c
index 7966b09..ddf2d2e 100644
--- a/lib/route/class.c
+++ b/lib/route/class.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>
*/
/**
@@ -36,7 +36,7 @@ static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
class = rtnl_class_alloc();
if (!class) {
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
goto errout;
}
class->ce_msgtype = n->nlmsg_type;
@@ -53,26 +53,20 @@ static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
err = pp->pp_cb((struct nl_object *) class, pp);
- if (err < 0)
- goto errout_free;
-
- err = P_ACCEPT;
-
errout_free:
rtnl_class_put(class);
errout:
return err;
}
-static int class_request_update(struct nl_cache *cache,
- struct nl_handle *handle)
+static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
{
struct tcmsg tchdr = {
.tcm_family = AF_UNSPEC,
.tcm_ifindex = cache->c_iarg1,
};
- return nl_send_simple(handle, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
+ return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
sizeof(tchdr));
}
@@ -81,15 +75,15 @@ static int class_request_update(struct nl_cache *cache,
* @{
*/
-static struct nl_msg *class_build(struct rtnl_class *class, int type, int flags)
+static int class_build(struct rtnl_class *class, int type, int flags,
+ struct nl_msg **result)
{
struct rtnl_class_ops *cops;
- struct nl_msg *msg;
int err;
- msg = tca_build_msg((struct rtnl_tca *) class, type, flags);
- if (!msg)
- goto errout;
+ err = tca_build_msg((struct rtnl_tca *) class, type, flags, result);
+ if (err < 0)
+ return err;
cops = rtnl_class_lookup_ops(class);
if (cops && cops->co_get_opts) {
@@ -97,23 +91,24 @@ static struct nl_msg *class_build(struct rtnl_class *class, int type, int flags)
opts = cops->co_get_opts(class);
if (opts) {
- err = nla_put_nested(msg, TCA_OPTIONS, opts);
+ err = nla_put_nested(*result, TCA_OPTIONS, opts);
nlmsg_free(opts);
if (err < 0)
goto errout;
}
}
- return msg;
+ return 0;
errout:
- nlmsg_free(msg);
- return NULL;
+ nlmsg_free(*result);
+ return err;
}
/**
* Build a netlink message to add a new class
* @arg class class to add
* @arg flags additional netlink message flags
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting an addition of a class.
* The netlink message header isn't fully equipped with all relevant
@@ -123,16 +118,17 @@ errout:
* Common message flags
* - NLM_F_REPLACE - replace possibly existing classes
*
- * @return New netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_class_build_add_request(struct rtnl_class *class, int flags)
+int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
+ struct nl_msg **result)
{
- return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags);
+ return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result);
}
/**
* Add a new class
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg class class to delete
* @arg flags additional netlink message flags
*
@@ -145,22 +141,74 @@ struct nl_msg *rtnl_class_build_add_request(struct rtnl_class *class, int flags)
*
* @return 0 on success or a negative error code
*/
-int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class,
- int flags)
+int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
{
struct nl_msg *msg;
int err;
- msg = rtnl_class_build_add_request(class, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
+ return wait_for_ack(sk);
+}
+
+int rtnl_class_build_delete_request(struct rtnl_class *class,
+ struct nl_msg **result)
+{
+ struct nl_msg *msg;
+ struct tcmsg tchdr;
+ int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
+
+ if ((class->ce_mask & required) != required)
+ BUG();
+
+ msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ tchdr.tcm_family = AF_UNSPEC;
+ tchdr.tcm_handle = class->c_handle;
+ tchdr.tcm_parent = class->c_parent;
+ tchdr.tcm_ifindex = class->c_ifindex;
+ if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+ }
+
+ *result = msg;
+ return 0;
+}
+
+/**
+ * Delete a class
+ * @arg sk Netlink socket.
+ * @arg class class to delete
+ *
+ * Builds a netlink message by calling rtnl_class_build_delete_request(),
+ * sends the request to the kernel and waits for the ACK to be
+ * received and thus blocks until the request has been processed.
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
+{
+ struct nl_msg *msg;
+ int err;
+
+ if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ if (err < 0)
+ return err;
+
+ return wait_for_ack(sk);
}
/** @} */
@@ -172,7 +220,7 @@ int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class,
/**
* Build a class cache including all classes attached to the specified interface
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg ifindex interface index of the link the classes are
* attached to.
*
@@ -181,22 +229,49 @@ int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class,
*
* @return The cache or NULL if an error has occured.
*/
-struct nl_cache * rtnl_class_alloc_cache(struct nl_handle *handle, int ifindex)
+int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
+ struct nl_cache **result)
{
struct nl_cache * cache;
+ int err;
cache = nl_cache_alloc(&rtnl_class_ops);
if (!cache)
- return NULL;
+ return -NLE_NOMEM;
cache->c_iarg1 = ifindex;
- if (handle && nl_cache_refill(handle, cache) < 0) {
+ if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
nl_cache_free(cache);
- return NULL;
+ return err;
}
- return cache;
+ *result = cache;
+ return 0;
+}
+
+/**
+ * Look up class by its handle in the provided cache
+ * @arg cache class cache
+ * @arg ifindex interface the class is attached to
+ * @arg handle class handle
+ * @return pointer to class inside the cache or NULL if no match was found.
+ */
+struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
+ uint32_t handle)
+{
+ struct rtnl_class *class;
+
+ if (cache->c_ops != &rtnl_class_ops)
+ return NULL;
+
+ nl_list_for_each_entry(class, &cache->c_items, ce_list) {
+ if (class->c_handle == handle && class->c_ifindex == ifindex) {
+ nl_object_get((struct nl_object *) class);
+ return class;
+ }
+ }
+ return NULL;
}
/** @} */
diff --git a/lib/route/class_api.c b/lib/route/class_api.c
index c814486..374cf0f 100644
--- a/lib/route/class_api.c
+++ b/lib/route/class_api.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>
*/
/**
@@ -43,7 +43,7 @@ int rtnl_class_register(struct rtnl_class_ops *cops)
for (op = &class_ops_list; (o = *op) != NULL; op = &o->co_next)
if (!strcasecmp(cops->co_kind, o->co_kind))
- return nl_errno(EEXIST);
+ return -NLE_EXIST;
cops->co_next = NULL;
*op = cops;
@@ -64,7 +64,7 @@ int rtnl_class_unregister(struct rtnl_class_ops *cops)
break;
if (!o)
- return nl_errno(ENOENT);
+ return -NLE_OBJ_NOTFOUND;
*op = cops->co_next;
diff --git a/lib/route/class_obj.c b/lib/route/class_obj.c
index 0601bdf..5c2e5be 100644
--- a/lib/route/class_obj.c
+++ b/lib/route/class_obj.c
@@ -55,62 +55,54 @@ errout:
return err;
}
-static int class_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
+static void class_dump_line(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_class *class = (struct rtnl_class *) obj;
struct rtnl_class_ops *cops;
- int line = tca_dump_brief((struct rtnl_tca *) class, "class", p, 0);
+ tca_dump_line((struct rtnl_tca *) class, "class", p);
cops = rtnl_class_lookup_ops(class);
- if (cops && cops->co_dump[NL_DUMP_BRIEF])
- line = cops->co_dump[NL_DUMP_BRIEF](class, p, line);
- dp_dump(p, "\n");
-
- return line;
+ if (cops && cops->co_dump[NL_DUMP_LINE])
+ cops->co_dump[NL_DUMP_LINE](class, p);
+ nl_dump(p, "\n");
}
-static int class_dump_full(struct nl_object *obj, struct nl_dump_params *p)
+static void class_dump_details(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_class *class = (struct rtnl_class *) obj;
struct rtnl_class_ops *cops;
- int line;
- line = class_dump_brief(obj, p);
- line = tca_dump_full((struct rtnl_tca *) class, p, line);
+ class_dump_line(obj, p);
+ tca_dump_details((struct rtnl_tca *) class, p);
if (class->c_info) {
char buf[32];
- dp_dump(p, "child-qdisc %s ",
+ nl_dump(p, "child-qdisc %s ",
rtnl_tc_handle2str(class->c_info, buf, sizeof(buf)));
}
cops = rtnl_class_lookup_ops(class);
- if (cops && cops->co_dump[NL_DUMP_FULL])
- line = cops->co_dump[NL_DUMP_FULL](class, p, line);
+ if (cops && cops->co_dump[NL_DUMP_DETAILS])
+ cops->co_dump[NL_DUMP_DETAILS](class, p);
else if (!class->c_info)
- dp_dump(p, "noop (no leaf qdisc)");
-
- dp_dump(p, "\n");
+ nl_dump(p, "noop (no leaf qdisc)");
- return line;
+ nl_dump(p, "\n");
}
-static int class_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+static void class_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_class *class = (struct rtnl_class *) obj;
struct rtnl_class_ops *cops;
- int line;
- line = class_dump_full(obj, p);
- line = tca_dump_stats((struct rtnl_tca *) class, p, line);
- dp_dump(p, "\n");
+ class_dump_details(obj, p);
+ tca_dump_stats((struct rtnl_tca *) class, p);
+ nl_dump(p, "\n");
cops = rtnl_class_lookup_ops(class);
if (cops && cops->co_dump[NL_DUMP_STATS])
- line = cops->co_dump[NL_DUMP_STATS](class, p, line);
-
- return line;
+ cops->co_dump[NL_DUMP_STATS](class, p);
}
/**
@@ -277,9 +269,11 @@ struct nl_object_ops class_obj_ops = {
.oo_size = sizeof(struct rtnl_class),
.oo_free_data = class_free_data,
.oo_clone = class_clone,
- .oo_dump[NL_DUMP_BRIEF] = class_dump_brief,
- .oo_dump[NL_DUMP_FULL] = class_dump_full,
- .oo_dump[NL_DUMP_STATS] = class_dump_stats,
+ .oo_dump = {
+ [NL_DUMP_LINE] = class_dump_line,
+ [NL_DUMP_DETAILS] = class_dump_details,
+ [NL_DUMP_STATS] = class_dump_stats,
+ },
.oo_compare = tca_compare,
.oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
};
diff --git a/lib/route/classifier.c b/lib/route/cls.c
index df6d3ae..cbf0345 100644
--- a/lib/route/classifier.c
+++ b/lib/route/cls.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-2009 Thomas Graf <tgraf@suug.ch>
*/
/**
@@ -38,13 +38,13 @@ static struct nl_cache_ops rtnl_cls_ops;
static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
- int err;
- struct rtnl_cls *cls;
struct rtnl_cls_ops *cops;
+ struct rtnl_cls *cls;
+ int err;
cls = rtnl_cls_alloc();
if (!cls) {
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
goto errout;
}
cls->ce_msgtype = nlh->nlmsg_type;
@@ -57,25 +57,17 @@ static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
cops = rtnl_cls_lookup_ops(cls);
- if (cops && cops->co_msg_parser) {
- err = cops->co_msg_parser(cls);
- if (err < 0)
- goto errout_free;
- }
-
- err = pp->pp_cb((struct nl_object *) cls, pp);
- if (err < 0)
+ if (cops && cops->co_msg_parser && (err = cops->co_msg_parser(cls)) < 0)
goto errout_free;
- err = P_ACCEPT;
-
+ err = pp->pp_cb((struct nl_object *) cls, pp);
errout_free:
rtnl_cls_put(cls);
errout:
return err;
}
-static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle)
+static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
{
struct tcmsg tchdr = {
.tcm_family = AF_UNSPEC,
@@ -83,44 +75,48 @@ static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle)
.tcm_parent = cache->c_iarg2,
};
- return nl_send_simple(handle, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
+ return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
sizeof(tchdr));
}
-static struct nl_msg *cls_build(struct rtnl_cls *cls, int type, int flags)
+static int cls_build(struct rtnl_cls *cls, int type, int flags,
+ struct nl_msg **result)
{
- struct nl_msg *msg;
struct rtnl_cls_ops *cops;
int err, prio, proto;
struct tcmsg *tchdr;
- msg = tca_build_msg((struct rtnl_tca *) cls, type, flags);
- if (!msg)
- goto errout;
+ err = tca_build_msg((struct rtnl_tca *) cls, type, flags, result);
+ if (err < 0)
+ return err;
- tchdr = nlmsg_data(nlmsg_hdr(msg));
+ tchdr = nlmsg_data(nlmsg_hdr(*result));
prio = rtnl_cls_get_prio(cls);
proto = rtnl_cls_get_protocol(cls);
- tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)),
+ tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
cops = rtnl_cls_lookup_ops(cls);
if (cops && cops->co_get_opts) {
struct nl_msg *opts;
-
- opts = cops->co_get_opts(cls);
- if (opts) {
- err = nla_put_nested(msg, TCA_OPTIONS, opts);
- nlmsg_free(opts);
- if (err < 0)
- goto errout;
+
+ if (!(opts = nlmsg_alloc())) {
+ err = -NLE_NOMEM;
+ goto errout;
}
+
+ if (!(err = cops->co_get_opts(cls, opts)))
+ err = nla_put_nested(*result, TCA_OPTIONS, opts);
+
+ nlmsg_free(opts);
+ if (err < 0)
+ goto errout;
}
- return msg;
+ return 0;
errout:
- nlmsg_free(msg);
- return NULL;
+ nlmsg_free(*result);
+ return err;
}
/**
@@ -132,6 +128,7 @@ errout:
* Build a netlink message to add a new classifier
* @arg cls classifier to add
* @arg flags additional netlink message flags
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting an addition of a classifier
* The netlink message header isn't fully equipped with all relevant
@@ -140,16 +137,17 @@ errout:
* the new classifier set via \c rtnl_cls_set_* functions. \a opts
* may point to the clsasifier specific options.
*
- * @return New netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags)
+int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
+ struct nl_msg **result)
{
- return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags);
+ return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result);
}
/**
* Add a new classifier
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg cls classifier to add
* @arg flags additional netlink message flags
*
@@ -159,43 +157,44 @@ struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_cls_add(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
+int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_cls_build_add_request(cls, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return nl_wait_for_ack(sk);
}
/**
* Build a netlink message to change classifier attributes
* @arg cls classifier to change
* @arg flags additional netlink message flags
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting a change of a neigh
* attributes. The netlink message header isn't fully equipped with
* all relevant fields and must thus be sent out via nl_send_auto_complete()
* or supplemented as needed.
*
- * @return The netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags)
+int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
+ struct nl_msg **result)
{
- return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags);
+ return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
}
/**
* Change a classifier
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg cls classifier to change
* @arg flags additional netlink message flags
*
@@ -205,45 +204,45 @@ struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_cls_change(struct nl_handle *handle, struct rtnl_cls *cls,
- int flags)
+int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_cls_build_change_request(cls, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return nl_wait_for_ack(sk);
}
/**
* Build a netlink request message to delete a classifier
* @arg cls classifier to delete
* @arg flags additional netlink message flags
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting a deletion of a classifier.
* The netlink message header isn't fully equipped with all relevant
* fields and must thus be sent out via nl_send_auto_complete()
* or supplemented as needed.
*
- * @return New netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags)
+int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
+ struct nl_msg **result)
{
- return cls_build(cls, RTM_DELTFILTER, flags);
+ return cls_build(cls, RTM_DELTFILTER, flags, result);
}
/**
* Delete a classifier
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg cls classifier to delete
* @arg flags additional netlink message flags
*
@@ -253,21 +252,20 @@ struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
+int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_cls_build_delete_request(cls, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return nl_wait_for_ack(sk);
}
/** @} */
@@ -280,36 +278,37 @@ int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
/**
* Build a classifier cache including all classifiers attached to the
* specified class/qdisc on eht specified interface.
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg ifindex interface index of the link the classes are
* attached to.
* @arg parent parent qdisc/class
+ * @arg result Pointer to store resulting cache.
*
* Allocates a new cache, initializes it properly and updates it to
* include all classes attached to the specified interface.
*
* @note The caller is responsible for destroying and freeing the
* cache after using it.
- * @return The cache or NULL if an error has occured.
+ * @return 0 on success or a negative error code.
*/
-struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *handle,
- int ifindex, uint32_t parent)
+int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result)
{
struct nl_cache * cache;
+ int err;
- cache = nl_cache_alloc(&rtnl_cls_ops);
- if (cache == NULL)
- return NULL;
+ if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
+ return -NLE_NOMEM;
cache->c_iarg1 = ifindex;
cache->c_iarg2 = parent;
- if (handle && nl_cache_refill(handle, cache) < 0) {
+ if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
nl_cache_free(cache);
- return NULL;
+ return err;
}
- return cache;
+ *result = cache;
+ return 0;
}
/** @} */
diff --git a/lib/route/cls/basic.c b/lib/route/cls/basic.c
new file mode 100644
index 0000000..1460b72
--- /dev/null
+++ b/lib/route/cls/basic.c
@@ -0,0 +1,211 @@
+/*
+ * lib/route/cls/basic.c Basic Classifier
+ *
+ * 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 cls
+ * @defgroup basic Basic Classifier
+ *
+ * @par Introduction
+ * The basic classifier is the simplest form of a classifier. It does
+ * not have any special classification capabilities, instead it can be
+ * used to classify exclusively based on extended matches or to
+ * create a "catch-all" filter.
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/classifier-modules.h>
+#include <netlink/route/cls/basic.h>
+#include <netlink/route/cls/ematch.h>
+
+struct rtnl_basic
+{
+ uint32_t b_classid;
+ struct rtnl_ematch_tree * b_ematch;
+ int b_mask;
+};
+
+/** @cond SKIP */
+#define BASIC_ATTR_CLASSID 0x001
+#define BASIC_ATTR_EMATCH 0x002
+/** @endcond */
+
+static struct nla_policy basic_policy[TCA_FW_MAX+1] = {
+ [TCA_BASIC_CLASSID] = { .type = NLA_U32 },
+ [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED },
+ [TCA_BASIC_ACT] = { .type = NLA_NESTED },
+ [TCA_BASIC_POLICE] = { .type = NLA_NESTED },
+};
+
+static int basic_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
+{
+ return -NLE_OPNOTSUPP;
+}
+
+static void basic_free_data(struct rtnl_cls *cls)
+{
+ struct rtnl_basic *basic = rtnl_cls_data(cls);
+
+ rtnl_ematch_tree_free(basic->b_ematch);
+}
+
+static int basic_msg_parser(struct rtnl_cls *cls)
+{
+ struct nlattr *tb[TCA_BASIC_MAX + 1];
+ struct rtnl_basic *basic = rtnl_cls_data(cls);
+ int err;
+
+ err = tca_parse(tb, TCA_BASIC_MAX, (struct rtnl_tca *) cls, basic_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_BASIC_CLASSID]) {
+ basic->b_classid = nla_get_u32(tb[TCA_BASIC_CLASSID]);
+ basic->b_mask |= BASIC_ATTR_CLASSID;
+ }
+
+ if (tb[TCA_BASIC_EMATCHES]) {
+ if ((err = rtnl_ematch_parse(tb[TCA_BASIC_EMATCHES],
+ &basic->b_ematch)) < 0)
+ return err;
+
+ if (basic->b_ematch)
+ basic->b_mask |= BASIC_ATTR_EMATCH;
+ }
+
+ if (tb[TCA_BASIC_ACT]) {
+ /* XXX */
+ }
+
+ if (tb[TCA_BASIC_POLICE]) {
+ /* XXX */
+ }
+
+ return 0;
+}
+
+static void basic_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
+{
+ struct rtnl_basic *b = rtnl_cls_data(cls);
+ char buf[32];
+
+ if (b->b_mask & BASIC_ATTR_EMATCH)
+ nl_dump(p, " ematch");
+ else
+ nl_dump(p, " match-all");
+
+ if (b->b_mask & BASIC_ATTR_CLASSID)
+ nl_dump(p, " classify-to %s",
+ rtnl_tc_handle2str(b->b_classid, buf, sizeof(buf)));
+}
+
+static void basic_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
+{
+ struct rtnl_basic *b = rtnl_cls_data(cls);
+
+ if (b->b_mask & BASIC_ATTR_EMATCH) {
+ nl_dump(p, "\n");
+ nl_dump_line(p, " ematch ");
+ rtnl_ematch_tree_dump(b->b_ematch, p);
+ } else
+ nl_dump(p, "no options.\n");
+}
+
+static int basic_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
+{
+ struct rtnl_basic *b = rtnl_cls_data(cls);
+
+ if (!(b->b_mask & BASIC_ATTR_CLASSID))
+ return -NLE_MISSING_ATTR;
+
+ NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_classid);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+int rtnl_basic_set_classid(struct rtnl_cls *cls, uint32_t classid)
+{
+ struct rtnl_basic *b = rtnl_cls_data(cls);
+
+ b->b_classid = classid;
+ b->b_mask |= BASIC_ATTR_CLASSID;
+
+ return 0;
+}
+
+uint32_t rtnl_basic_get_classid(struct rtnl_cls *cls)
+{
+ struct rtnl_basic *b = rtnl_cls_data(cls);
+
+ return b->b_classid;
+}
+
+int rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
+{
+ struct rtnl_basic *b = rtnl_cls_data(cls);
+
+ if (b->b_ematch) {
+ rtnl_ematch_tree_free(b->b_ematch);
+ b->b_mask &= ~BASIC_ATTR_EMATCH;
+ }
+
+ b->b_ematch = tree;
+
+ if (tree)
+ b->b_mask |= BASIC_ATTR_EMATCH;
+
+ return 0;
+}
+
+struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls)
+{
+ struct rtnl_basic *b = rtnl_cls_data(cls);
+ return b->b_ematch;
+}
+
+/** @} */
+
+static struct rtnl_cls_ops basic_ops = {
+ .co_kind = "basic",
+ .co_size = sizeof(struct rtnl_basic),
+ .co_msg_parser = basic_msg_parser,
+ .co_clone = basic_clone,
+ .co_free_data = basic_free_data,
+ .co_get_opts = basic_get_opts,
+ .co_dump = {
+ [NL_DUMP_LINE] = basic_dump_line,
+ [NL_DUMP_DETAILS] = basic_dump_details,
+ },
+};
+
+static void __init basic_init(void)
+{
+ rtnl_cls_register(&basic_ops);
+}
+
+static void __exit basic_exit(void)
+{
+ rtnl_cls_unregister(&basic_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/cgroup.c b/lib/route/cls/cgroup.c
new file mode 100644
index 0000000..e5f38b8
--- /dev/null
+++ b/lib/route/cls/cgroup.c
@@ -0,0 +1,141 @@
+/*
+ * lib/route/cls/cgroup.c Control Groups Classifier
+ *
+ * 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) 2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cls_api
+ * @defgroup cgroup Control Groups Classifier
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/classifier-modules.h>
+#include <netlink/route/cls/cgroup.h>
+#include <netlink/route/cls/ematch.h>
+
+/** @cond SKIP */
+#define CGROUP_ATTR_EMATCH 0x001
+/** @endcond */
+
+static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = {
+ [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED },
+};
+
+static void cgroup_free_data(struct rtnl_cls *cls)
+{
+ struct rtnl_cgroup *cg = rtnl_cls_data(cls);
+
+ rtnl_ematch_tree_free(cg->cg_ematch);
+}
+
+static int cgroup_msg_parser(struct rtnl_cls *cls)
+{
+ struct rtnl_cgroup *cg = rtnl_cls_data(cls);
+ struct nlattr *tb[TCA_CGROUP_MAX + 1];
+ int err;
+
+ err = tca_parse(tb, TCA_CGROUP_MAX, (struct rtnl_tca *) cls,
+ cgroup_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_CGROUP_EMATCHES]) {
+ if ((err = rtnl_ematch_parse(tb[TCA_CGROUP_EMATCHES],
+ &cg->cg_ematch)) < 0)
+ return err;
+ cg->cg_mask |= CGROUP_ATTR_EMATCH;
+ }
+
+#if 0
+ TODO:
+ TCA_CGROUP_ACT,
+ TCA_CGROUP_POLICE,
+#endif
+
+ return 0;
+}
+
+static void cgroup_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
+{
+ struct rtnl_cgroup *cg = rtnl_cls_data(cls);
+
+ if (cg->cg_mask & CGROUP_ATTR_EMATCH)
+ nl_dump(p, " ematch");
+ else
+ nl_dump(p, " match-all");
+}
+
+static void cgroup_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
+{
+ struct rtnl_cgroup *cg = rtnl_cls_data(cls);
+
+ if (cg->cg_mask & CGROUP_ATTR_EMATCH) {
+ nl_dump(p, "\n");
+ nl_dump_line(p, " ematch ");
+ rtnl_ematch_tree_dump(cg->cg_ematch, p);
+ }
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+int rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
+{
+ struct rtnl_cgroup *cg = rtnl_cls_data(cls);
+
+ if (cg->cg_ematch) {
+ rtnl_ematch_tree_free(cg->cg_ematch);
+ cg->cg_mask &= ~CGROUP_ATTR_EMATCH;
+ }
+
+ cg->cg_ematch = tree;
+
+ if (tree)
+ cg->cg_mask |= CGROUP_ATTR_EMATCH;
+
+ return 0;
+}
+
+struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls)
+{
+ struct rtnl_cgroup *cg = rtnl_cls_data(cls);
+ return cg->cg_ematch;
+}
+
+static struct rtnl_cls_ops cgroup_ops = {
+ .co_kind = "cgroup",
+ .co_size = sizeof(struct rtnl_cgroup),
+ .co_msg_parser = cgroup_msg_parser,
+ .co_free_data = cgroup_free_data,
+ .co_dump = {
+ [NL_DUMP_LINE] = cgroup_dump_line,
+ [NL_DUMP_DETAILS] = cgroup_dump_details,
+ },
+};
+
+static void __init cgroup_init(void)
+{
+ rtnl_cls_register(&cgroup_ops);
+}
+
+static void __exit cgroup_exit(void)
+{
+ rtnl_cls_unregister(&cgroup_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c
new file mode 100644
index 0000000..cb77b16
--- /dev/null
+++ b/lib/route/cls/ematch.c
@@ -0,0 +1,410 @@
+/*
+ * lib/route/cls/ematch.c Extended Matches
+ *
+ * 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 cls
+ * @defgroup ematch Extended Match
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/classifier-modules.h>
+#include <netlink/route/cls/ematch.h>
+
+/**
+ * @name Module Registration
+ * @{
+ */
+
+static NL_LIST_HEAD(ematch_ops_list);
+
+/**
+ * Register ematch module
+ * @arg ops Module operations.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
+{
+ if (rtnl_ematch_lookup_ops(ops->eo_kind))
+ return -NLE_EXIST;
+
+ nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
+
+ return 0;
+}
+
+/**
+ * Unregister ematch module
+ * @arg ops Module operations.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_ematch_unregister(struct rtnl_ematch_ops *ops)
+{
+ struct rtnl_ematch_ops *o;
+
+ nl_list_for_each_entry(o, &ematch_ops_list, eo_list) {
+ if (ops->eo_kind == o->eo_kind) {
+ nl_list_del(&o->eo_list);
+ return 0;
+ }
+ }
+
+ return -NLE_OBJ_NOTFOUND;
+}
+
+/**
+ * Lookup ematch module by kind
+ * @arg kind Module kind.
+ *
+ * @return Module operations or NULL if not found.
+ */
+struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind)
+{
+ struct rtnl_ematch_ops *ops;
+
+ nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
+ if (ops->eo_kind == kind)
+ return ops;
+
+ return NULL;
+}
+
+/**
+ * Lookup ematch module by name
+ * @arg name Name of ematch module.
+ *
+ * @return Module operations or NULL if not fuond.
+ */
+struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_name(const char *name)
+{
+ struct rtnl_ematch_ops *ops;
+
+ nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
+ if (!strcasecmp(ops->eo_name, name))
+ return ops;
+
+ return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Match
+ */
+
+struct rtnl_ematch *rtnl_ematch_alloc(struct rtnl_ematch_ops *ops)
+{
+ struct rtnl_ematch *e;
+ size_t len = sizeof(*e) + (ops ? ops->eo_datalen : 0);
+
+ if (!(e = calloc(1, len)))
+ return NULL;
+
+ NL_INIT_LIST_HEAD(&e->e_list);
+ NL_INIT_LIST_HEAD(&e->e_childs);
+
+ if (ops) {
+ e->e_ops = ops;
+ e->e_kind = ops->eo_kind;
+ }
+
+ return e;
+}
+
+/**
+ * Add ematch to the end of the parent's list of children.
+ * @arg parent Parent ematch.
+ * @arg child Ematch to be added as new child of parent.
+ */
+void rtnl_ematch_add_child(struct rtnl_ematch *parent,
+ struct rtnl_ematch *child)
+{
+ nl_list_add_tail(&child->e_list, &parent->e_childs);
+}
+
+/**
+ * Remove ematch from the list it is linked to.
+ * @arg ematch Ematch to be unlinked.
+ */
+void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
+{
+ nl_list_del(&ematch->e_list);
+}
+
+void rtnl_ematch_free(struct rtnl_ematch *ematch)
+{
+ if (!ematch)
+ return;
+
+ free(ematch);
+}
+
+void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags)
+{
+ ematch->e_flags |= flags;
+}
+
+void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags)
+{
+ ematch->e_flags &= ~flags;
+}
+
+uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch)
+{
+ return ematch->e_flags;
+}
+
+void *rtnl_ematch_data(struct rtnl_ematch *ematch)
+{
+ return ematch->e_data;
+}
+
+/** @} */
+
+/**
+ * @name Tree
+ */
+
+struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid)
+{
+ struct rtnl_ematch_tree *tree;
+
+ if (!(tree = calloc(1, sizeof(*tree))))
+ return NULL;
+
+ NL_INIT_LIST_HEAD(&tree->et_list);
+ tree->et_progid = progid;
+
+ return tree;
+}
+
+static void free_ematch_list(struct nl_list_head *head)
+{
+ struct rtnl_ematch *pos, *next;
+
+ nl_list_for_each_entry_safe(pos, next, head, e_list) {
+ if (!nl_list_empty(&pos->e_childs))
+ free_ematch_list(&pos->e_childs);
+ rtnl_ematch_free(pos);
+ }
+}
+
+void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
+{
+ if (!tree)
+ return;
+
+ free_ematch_list(&tree->et_list);
+ free(tree);
+}
+
+void rtnl_ematch_tree_add_tail(struct rtnl_ematch_tree *tree,
+ struct rtnl_ematch *ematch)
+{
+ nl_list_add_tail(&ematch->e_list, &tree->et_list);
+}
+
+static inline uint32_t container_ref(struct rtnl_ematch *ematch)
+{
+ return *((uint32_t *) rtnl_ematch_data(ematch));
+}
+
+static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos,
+ struct nl_list_head *root)
+{
+ struct rtnl_ematch *ematch;
+ int i;
+
+ for (i = pos; i < nmatches; i++) {
+ ematch = index[i];
+
+ nl_list_add_tail(&ematch->e_list, root);
+
+ if (ematch->e_kind == TCF_EM_CONTAINER)
+ link_tree(index, nmatches, container_ref(ematch),
+ &ematch->e_childs);
+
+ if (!(ematch->e_flags & TCF_EM_REL_MASK))
+ return 0;
+ }
+
+ /* Last entry in chain can't possibly have no relation */
+ return -NLE_INVAL;
+}
+
+static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
+ [TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) },
+ [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED },
+};
+
+/**
+ * Parse ematch netlink attributes
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_ematch_parse(struct nlattr *attr, struct rtnl_ematch_tree **result)
+{
+ struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
+ struct tcf_ematch_tree_hdr *thdr;
+ struct rtnl_ematch_tree *tree;
+ struct rtnl_ematch **index;
+ int nmatches = 0, err, remaining;
+
+ err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[TCA_EMATCH_TREE_HDR])
+ return -NLE_MISSING_ATTR;
+
+ thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);
+
+ /* Ignore empty trees */
+ if (thdr->nmatches == 0)
+ return 0;
+
+ if (!tb[TCA_EMATCH_TREE_LIST])
+ return -NLE_MISSING_ATTR;
+
+ if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
+ nla_total_size(sizeof(struct tcf_ematch_hdr))))
+ return -NLE_INVAL;
+
+ if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
+ return -NLE_NOMEM;
+
+ if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
+ struct rtnl_ematch_ops *ops;
+ struct tcf_ematch_hdr *hdr;
+ struct rtnl_ematch *ematch;
+ void *data;
+ size_t len;
+
+ if (nla_len(a) < sizeof(*hdr)) {
+ err = -NLE_INVAL;
+ goto errout;
+ }
+
+ if (nmatches >= thdr->nmatches) {
+ err = -NLE_RANGE;
+ goto errout;
+ }
+
+ hdr = nla_data(a);
+ data = nla_data(a) + NLA_ALIGN(sizeof(*hdr));
+ len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
+
+ ops = rtnl_ematch_lookup_ops(hdr->kind);
+ if (ops && ops->eo_datalen && len < ops->eo_datalen) {
+ err = -NLE_INVAL;
+ goto errout;
+ }
+
+ if (!(ematch = rtnl_ematch_alloc(ops))) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ ematch->e_id = hdr->matchid;
+ ematch->e_kind = hdr->kind;
+ ematch->e_flags = hdr->flags;
+
+ if (ops && (err = ops->eo_parse(ematch, data, len)) < 0)
+ goto errout;
+
+ if (hdr->kind == TCF_EM_CONTAINER &&
+ container_ref(ematch) >= thdr->nmatches) {
+ err = -NLE_INVAL;
+ goto errout;
+ }
+
+ index[nmatches++] = ematch;
+ }
+
+ if (nmatches != thdr->nmatches) {
+ err = -NLE_INVAL;
+ goto errout;
+ }
+
+ err = link_tree(index, nmatches, 0, &tree->et_list);
+ if (err < 0)
+ goto errout;
+
+ free(index);
+ *result = tree;
+
+ return 0;
+
+errout:
+ rtnl_ematch_tree_free(tree);
+ free(index);
+ return err;
+}
+
+static void dump_ematch_sequence(struct nl_list_head *head,
+ struct nl_dump_params *p)
+{
+ struct rtnl_ematch *match;
+
+ nl_list_for_each_entry(match, head, e_list) {
+ if (match->e_flags & TCF_EM_INVERT)
+ nl_dump(p, "NOT ");
+
+ if (match->e_kind == TCF_EM_CONTAINER) {
+ nl_dump(p, "(");
+ dump_ematch_sequence(&match->e_childs, p);
+ nl_dump(p, ")");
+ } else if (!match->e_ops) {
+ nl_dump(p, "[unknown ematch %d]", match->e_kind);
+ } else {
+ nl_dump(p, "%s(", match->e_ops->eo_name);
+
+ if (match->e_ops->eo_dump)
+ match->e_ops->eo_dump(match, p);
+
+ nl_dump(p, ")");
+ }
+
+ switch (match->e_flags & TCF_EM_REL_MASK) {
+ case TCF_EM_REL_AND:
+ nl_dump(p, " AND ");
+ break;
+ case TCF_EM_REL_OR:
+ nl_dump(p, " OR ");
+ break;
+ default:
+ /* end of first level ematch sequence */
+ return;
+ }
+ }
+}
+
+void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree,
+ struct nl_dump_params *p)
+{
+ dump_ematch_sequence(&tree->et_list, p);
+ nl_dump(p, "\n");
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/route/cls/ematch/cmp.c b/lib/route/cls/ematch/cmp.c
new file mode 100644
index 0000000..ec25320
--- /dev/null
+++ b/lib/route/cls/ematch/cmp.c
@@ -0,0 +1,116 @@
+/*
+ * lib/route/cls/ematch/cmp.c Simple packet data comparison ematch
+ *
+ * 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 ematch
+ * @defgroup em_cmp Simple packet data comparison
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+void rtnl_ematch_cmp_set(struct rtnl_ematch *ematch,
+ struct tcf_em_cmp *cfg)
+{
+ memcpy(rtnl_ematch_data(ematch), cfg, sizeof(*cfg));
+}
+
+struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *ematch)
+{
+ return rtnl_ematch_data(ematch);
+}
+
+static const char *align_txt(struct tcf_em_cmp *cmp)
+{
+ switch (cmp->align) {
+ case TCF_EM_ALIGN_U8:
+ return "u8";
+ case TCF_EM_ALIGN_U16:
+ return (cmp->flags & TCF_EM_CMP_TRANS) ? "h16" : "u16";
+ case TCF_EM_ALIGN_U32:
+ return (cmp->flags & TCF_EM_CMP_TRANS) ? "h32" : "u32";
+ default:
+ return (cmp->flags & TCF_EM_CMP_TRANS) ? "h?" : "u?";
+ }
+}
+
+static const char *layer_txt(struct tcf_em_cmp *cmp)
+{
+ switch (cmp->layer) {
+ case TCF_LAYER_LINK:
+ return "link";
+ case TCF_LAYER_NETWORK:
+ return "network";
+ case TCF_LAYER_TRANSPORT:
+ return "transport";
+ default:
+ return "?";
+ }
+}
+
+static const char *relation_txt(struct tcf_em_cmp *cmp)
+{
+ switch (cmp->opnd) {
+ case TCF_EM_OPND_EQ:
+ return "eq";
+ case TCF_EM_OPND_LT:
+ return "lt";
+ case TCF_EM_OPND_GT:
+ return "gt";
+ default:
+ return "?";
+ }
+}
+
+static int cmp_parse(struct rtnl_ematch *m, void *data, size_t len)
+{
+ memcpy(rtnl_ematch_data(m), data, len);
+
+ return 0;
+}
+
+static void cmp_dump(struct rtnl_ematch *m, struct nl_dump_params *p)
+{
+ struct tcf_em_cmp *cmp = rtnl_ematch_data(m);
+
+ nl_dump(p, "%s at %s+%u ",
+ align_txt(cmp), layer_txt(cmp), cmp->off);
+
+ if (cmp->mask)
+ nl_dump(p, "& 0x%x ", cmp->mask);
+
+ nl_dump(p, "%s %u", relation_txt(cmp), cmp->val);
+}
+
+static struct rtnl_ematch_ops cmp_ops = {
+ .eo_kind = TCF_EM_CMP,
+ .eo_name = "cmp",
+ .eo_datalen = sizeof(struct tcf_em_cmp),
+ .eo_parse = cmp_parse,
+ .eo_dump = cmp_dump,
+};
+
+static void __init cmp_init(void)
+{
+ rtnl_ematch_register(&cmp_ops);
+}
+
+static void __exit cmp_exit(void)
+{
+ rtnl_ematch_unregister(&cmp_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch/container.c b/lib/route/cls/ematch/container.c
new file mode 100644
index 0000000..54d836f
--- /dev/null
+++ b/lib/route/cls/ematch/container.c
@@ -0,0 +1,39 @@
+/*
+ * lib/route/cls/ematch/container.c Container Ematch
+ *
+ * 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>
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+
+static int container_parse(struct rtnl_ematch *m, void *data, size_t len)
+{
+ memcpy(m->e_data, data, sizeof(uint32_t));
+
+ return 0;
+}
+
+static struct rtnl_ematch_ops container_ops = {
+ .eo_kind = TCF_EM_CONTAINER,
+ .eo_name = "container",
+ .eo_datalen = sizeof(uint32_t),
+ .eo_parse = container_parse,
+};
+
+static void __init container_init(void)
+{
+ rtnl_ematch_register(&container_ops);
+}
+
+static void __exit container_exit(void)
+{
+ rtnl_ematch_unregister(&container_ops);
+}
diff --git a/lib/route/cls/fw.c b/lib/route/cls/fw.c
index 7ca7619..8cf25b9 100644
--- a/lib/route/cls/fw.c
+++ b/lib/route/cls/fw.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-2009 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
* Copyright (c) 2006 Siemens AG Oesterreich
*/
@@ -32,19 +32,6 @@
#define FW_ATTR_INDEV 0x008
/** @endcond */
-static inline struct rtnl_fw *fw_cls(struct rtnl_cls *cls)
-{
- return (struct rtnl_fw *) cls->c_subdata;
-}
-
-static inline struct rtnl_fw *fw_alloc(struct rtnl_cls *cls)
-{
- if (!cls->c_subdata)
- cls->c_subdata = calloc(1, sizeof(struct rtnl_fw));
-
- return fw_cls(cls);
-}
-
static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
[TCA_FW_CLASSID] = { .type = NLA_U32 },
[TCA_FW_INDEV] = { .type = NLA_STRING,
@@ -53,34 +40,30 @@ static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
static int fw_msg_parser(struct rtnl_cls *cls)
{
- int err;
+ struct rtnl_fw *f = rtnl_cls_data(cls);
struct nlattr *tb[TCA_FW_MAX + 1];
- struct rtnl_fw *f;
+ int err;
err = tca_parse(tb, TCA_FW_MAX, (struct rtnl_tca *) cls, fw_policy);
if (err < 0)
return err;
- f = fw_alloc(cls);
- if (!f)
- goto errout_nomem;
-
if (tb[TCA_FW_CLASSID]) {
f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]);
f->cf_mask |= FW_ATTR_CLASSID;
}
if (tb[TCA_FW_ACT]) {
- f->cf_act = nla_get_data(tb[TCA_FW_ACT]);
+ f->cf_act = nl_data_alloc_attr(tb[TCA_FW_ACT]);
if (!f->cf_act)
- goto errout_nomem;
+ return -NLE_NOMEM;
f->cf_mask |= FW_ATTR_ACTION;
}
if (tb[TCA_FW_POLICE]) {
- f->cf_police = nla_get_data(tb[TCA_FW_POLICE]);
+ f->cf_police = nl_data_alloc_attr(tb[TCA_FW_POLICE]);
if (!f->cf_police)
- goto errout_nomem;
+ return -NLE_NOMEM;
f->cf_mask |= FW_ATTR_POLICE;
}
@@ -90,120 +73,68 @@ static int fw_msg_parser(struct rtnl_cls *cls)
}
return 0;
-
-errout_nomem:
- err = nl_errno(ENOMEM);
-
- return err;
}
static void fw_free_data(struct rtnl_cls *cls)
{
- struct rtnl_fw *f = fw_cls(cls);
-
- if (!f)
- return;
+ struct rtnl_fw *f = rtnl_cls_data(cls);
nl_data_free(f->cf_act);
nl_data_free(f->cf_police);
-
- free(cls->c_subdata);
}
static int fw_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
{
- struct rtnl_fw *dst, *src = fw_cls(_src);
-
- if (!src)
- return 0;
+ struct rtnl_fw *dst = rtnl_cls_data(_dst);
+ struct rtnl_fw *src = rtnl_cls_data(_src);
- dst = fw_alloc(_dst);
- if (!dst)
- return nl_errno(ENOMEM);
-
- if (src->cf_act)
- if (!(dst->cf_act = nl_data_clone(src->cf_act)))
- goto errout;
+ if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act)))
+ return -NLE_NOMEM;
- if (src->cf_police)
- if (!(dst->cf_police = nl_data_clone(src->cf_police)))
- goto errout;
+ if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police)))
+ return -NLE_NOMEM;
return 0;
-errout:
- return nl_get_errno();
}
-static int fw_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
- int line)
+static void fw_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
{
- struct rtnl_fw *f = fw_cls(cls);
+ struct rtnl_fw *f = rtnl_cls_data(cls);
char buf[32];
- if (!f)
- goto ignore;
-
if (f->cf_mask & FW_ATTR_CLASSID)
- dp_dump(p, " target %s",
+ nl_dump(p, " target %s",
rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf)));
-
-ignore:
- return line;
}
-static int fw_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
- int line)
+static void fw_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
{
- struct rtnl_fw *f = fw_cls(cls);
-
- if (!f)
- goto ignore;
+ struct rtnl_fw *f = rtnl_cls_data(cls);
if (f->cf_mask & FW_ATTR_INDEV)
- dp_dump(p, "indev %s ", f->cf_indev);
-
-ignore:
- return line;
+ nl_dump(p, "indev %s ", f->cf_indev);
}
-static int fw_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
- int line)
+static int fw_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
{
- struct rtnl_fw *f = fw_cls(cls);
-
- if (!f)
- goto ignore;
-
-ignore:
- return line;
-}
-
-static struct nl_msg *fw_get_opts(struct rtnl_cls *cls)
-{
- struct rtnl_fw *f;
- struct nl_msg *msg;
+ struct rtnl_fw *f = rtnl_cls_data(cls);
- f = fw_cls(cls);
- if (!f)
- return NULL;
-
- msg = nlmsg_alloc();
- if (!msg)
- return NULL;
-
if (f->cf_mask & FW_ATTR_CLASSID)
- nla_put_u32(msg, TCA_FW_CLASSID, f->cf_classid);
+ NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid);
if (f->cf_mask & FW_ATTR_ACTION)
- nla_put_data(msg, TCA_FW_ACT, f->cf_act);
+ NLA_PUT_DATA(msg, TCA_FW_ACT, f->cf_act);
if (f->cf_mask & FW_ATTR_POLICE)
- nla_put_data(msg, TCA_FW_POLICE, f->cf_police);
+ NLA_PUT_DATA(msg, TCA_FW_POLICE, f->cf_police);
if (f->cf_mask & FW_ATTR_INDEV)
- nla_put_string(msg, TCA_FW_INDEV, f->cf_indev);
+ NLA_PUT_STRING(msg, TCA_FW_INDEV, f->cf_indev);
- return msg;
+ return 0;
+
+nla_put_failure:
+ return -NLE_NOMEM;
}
/**
@@ -213,12 +144,8 @@ static struct nl_msg *fw_get_opts(struct rtnl_cls *cls)
int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
{
- struct rtnl_fw *f;
+ struct rtnl_fw *f = rtnl_cls_data(cls);
- f = fw_alloc(cls);
- if (!f)
- return nl_errno(ENOMEM);
-
f->cf_classid = classid;
f->cf_mask |= FW_ATTR_CLASSID;
@@ -229,13 +156,15 @@ int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
static struct rtnl_cls_ops fw_ops = {
.co_kind = "fw",
+ .co_size = sizeof(struct rtnl_fw),
.co_msg_parser = fw_msg_parser,
.co_free_data = fw_free_data,
.co_clone = fw_clone,
.co_get_opts = fw_get_opts,
- .co_dump[NL_DUMP_BRIEF] = fw_dump_brief,
- .co_dump[NL_DUMP_FULL] = fw_dump_full,
- .co_dump[NL_DUMP_STATS] = fw_dump_stats,
+ .co_dump = {
+ [NL_DUMP_LINE] = fw_dump_line,
+ [NL_DUMP_DETAILS] = fw_dump_details,
+ },
};
static void __init fw_init(void)
diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c
index 596e63f..80b8851 100644
--- a/lib/route/cls/u32.c
+++ b/lib/route/cls/u32.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-2009 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
* Copyright (c) 2005-2006 Siemens AG Oesterreich
*/
@@ -40,19 +40,6 @@
#define U32_ATTR_INDEV 0x100
/** @endcond */
-static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls)
-{
- return (struct rtnl_u32 *) cls->c_subdata;
-}
-
-static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls)
-{
- if (!cls->c_subdata)
- cls->c_subdata = calloc(1, sizeof(struct rtnl_u32));
-
- return u32_cls(cls);
-}
-
static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
{
return (struct tc_u32_sel *) u->cu_selector->d_data;
@@ -79,25 +66,21 @@ static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
static int u32_msg_parser(struct rtnl_cls *cls)
{
- int err;
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
struct nlattr *tb[TCA_U32_MAX + 1];
- struct rtnl_u32 *u;
+ int err;
err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
if (err < 0)
return err;
- u = u32_alloc(cls);
- if (!u)
- goto errout_nomem;
-
if (tb[TCA_U32_DIVISOR]) {
u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
u->cu_mask |= U32_ATTR_DIVISOR;
}
if (tb[TCA_U32_SEL]) {
- u->cu_selector = nla_get_data(tb[TCA_U32_SEL]);
+ u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
if (!u->cu_selector)
goto errout_nomem;
u->cu_mask |= U32_ATTR_SELECTOR;
@@ -119,14 +102,14 @@ static int u32_msg_parser(struct rtnl_cls *cls)
}
if (tb[TCA_U32_ACT]) {
- u->cu_act = nla_get_data(tb[TCA_U32_ACT]);
+ u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
if (!u->cu_act)
goto errout_nomem;
u->cu_mask |= U32_ATTR_ACTION;
}
if (tb[TCA_U32_POLICE]) {
- u->cu_police = nla_get_data(tb[TCA_U32_POLICE]);
+ u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
if (!u->cu_police)
goto errout_nomem;
u->cu_mask |= U32_ATTR_POLICE;
@@ -137,8 +120,7 @@ static int u32_msg_parser(struct rtnl_cls *cls)
int pcnt_size;
if (!tb[TCA_U32_SEL]) {
- err = nl_error(EINVAL, "Missing TCA_U32_SEL required "
- "for TCA_U32_PCNT");
+ err = -NLE_MISSING_ATTR;
goto errout;
}
@@ -146,11 +128,11 @@ static int u32_msg_parser(struct rtnl_cls *cls)
pcnt_size = sizeof(struct tc_u32_pcnt) +
(sel->nkeys * sizeof(uint64_t));
if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
- err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT");
+ err = -NLE_INVAL;
goto errout;
}
- u->cu_pcnt = nla_get_data(tb[TCA_U32_PCNT]);
+ u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
if (!u->cu_pcnt)
goto errout_nomem;
u->cu_mask |= U32_ATTR_PCNT;
@@ -164,79 +146,56 @@ static int u32_msg_parser(struct rtnl_cls *cls)
return 0;
errout_nomem:
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
errout:
return err;
}
static void u32_free_data(struct rtnl_cls *cls)
{
- struct rtnl_u32 *u = u32_cls(cls);
-
- if (!u)
- return;
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
nl_data_free(u->cu_selector);
nl_data_free(u->cu_act);
nl_data_free(u->cu_police);
nl_data_free(u->cu_pcnt);
-
- free(cls->c_subdata);
}
static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
{
- struct rtnl_u32 *dst, *src = u32_cls(_src);
+ struct rtnl_u32 *dst = rtnl_cls_data(_dst);
+ struct rtnl_u32 *src = rtnl_cls_data(_src);
- if (!src)
- return 0;
+ if (src->cu_selector &&
+ !(dst->cu_selector = nl_data_clone(src->cu_selector)))
+ return -NLE_NOMEM;
- dst = u32_alloc(_dst);
- if (!dst)
- return nl_errno(ENOMEM);
+ if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
+ return -NLE_NOMEM;
- if (src->cu_selector)
- if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
- goto errout;
-
- if (src->cu_act)
- if (!(dst->cu_act = nl_data_clone(src->cu_act)))
- goto errout;
-
- if (src->cu_police)
- if (!(dst->cu_police = nl_data_clone(src->cu_police)))
- goto errout;
+ if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
+ return -NLE_NOMEM;
- if (src->cu_pcnt)
- if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
- goto errout;
+ if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
+ return -NLE_NOMEM;
return 0;
-errout:
- return nl_get_errno();
}
-static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
- int line)
+static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
{
- struct rtnl_u32 *u = u32_cls(cls);
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
char buf[32];
- if (!u)
- goto ignore;
-
if (u->cu_mask & U32_ATTR_DIVISOR)
- dp_dump(p, " divisor %u", u->cu_divisor);
+ nl_dump(p, " divisor %u", u->cu_divisor);
else if (u->cu_mask & U32_ATTR_CLASSID)
- dp_dump(p, " target %s",
+ nl_dump(p, " target %s",
rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
-
-ignore:
- return line;
}
-static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
- struct rtnl_cls *cls, struct rtnl_u32 *u, int line)
+static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
+ struct rtnl_cls *cls, struct rtnl_u32 *u)
{
int i;
struct tc_u32_key *key;
@@ -246,23 +205,23 @@ static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
* exports the selector if no divisor is set but hash offset
* and hash mask make only sense in hash filters with divisor
* set */
- dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
+ nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
}
if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
- dp_dump(p, " offset at %u", sel->off);
+ nl_dump(p, " offset at %u", sel->off);
if (sel->flags & TC_U32_VAROFFSET)
- dp_dump(p, " variable (at %u & 0x%x) >> %u",
+ nl_dump(p, " variable (at %u & 0x%x) >> %u",
sel->offoff, ntohs(sel->offmask), sel->offshift);
}
if (sel->flags) {
int flags = sel->flags;
- dp_dump(p, " <");
+ nl_dump(p, " <");
#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
- flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
+ flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
PRINT_FLAG(TERMINAL);
PRINT_FLAG(OFFSET);
@@ -270,66 +229,56 @@ static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
PRINT_FLAG(EAT);
#undef PRINT_FLAG
- dp_dump(p, ">");
+ nl_dump(p, ">");
}
for (i = 0; i < sel->nkeys; i++) {
key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
- dp_dump(p, "\n");
- dp_dump_line(p, line++, " match key at %s%u ",
- key->offmask ? "nexthdr+" : "", key->off);
+ nl_dump(p, "\n");
+ nl_dump_line(p, " match key at %s%u ",
+ key->offmask ? "nexthdr+" : "", key->off);
if (key->offmask)
- dp_dump(p, "[0x%u] ", key->offmask);
+ nl_dump(p, "[0x%u] ", key->offmask);
- dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
+ nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
if (p->dp_type == NL_DUMP_STATS &&
(u->cu_mask & U32_ATTR_PCNT)) {
struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
- dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
+ nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
}
}
-
- return line;
}
-
-static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
- int line)
+static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
{
- struct rtnl_u32 *u = u32_cls(cls);
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
struct tc_u32_sel *s;
- if (!u)
- goto ignore;
-
if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
- dp_dump(p, "no-selector\n");
- return line;
+ nl_dump(p, "no-selector\n");
+ return;
}
s = u->cu_selector->d_data;
- dp_dump(p, "nkeys %u ", s->nkeys);
+ nl_dump(p, "nkeys %u ", s->nkeys);
if (u->cu_mask & U32_ATTR_HASH)
- dp_dump(p, "ht key 0x%x hash 0x%u",
+ nl_dump(p, "ht key 0x%x hash 0x%u",
TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
if (u->cu_mask & U32_ATTR_LINK)
- dp_dump(p, "link %u ", u->cu_link);
+ nl_dump(p, "link %u ", u->cu_link);
if (u->cu_mask & U32_ATTR_INDEV)
- dp_dump(p, "indev %s ", u->cu_indev);
-
- line = print_selector(p, s, cls, u, line);
- dp_dump(p, "\n");
+ nl_dump(p, "indev %s ", u->cu_indev);
-ignore:
- return line;
+ print_selector(p, s, cls, u);
+ nl_dump(p, "\n");
#if 0
#define U32_ATTR_ACTION 0x040
@@ -340,64 +289,50 @@ ignore:
#endif
}
-static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
- int line)
+static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
{
- struct rtnl_u32 *u = u32_cls(cls);
-
- if (!u)
- goto ignore;
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
if (u->cu_mask & U32_ATTR_PCNT) {
struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
- dp_dump(p, "\n");
- dp_dump_line(p, line++, "%s successful hits\n");
- dp_dump_line(p, line++, "%s %8llu %8llu\n",
+ nl_dump(p, "\n");
+ nl_dump_line(p, " hit %8llu count %8llu\n",
pc->rhit, pc->rcnt);
}
-
-ignore:
- return line;
}
-static struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
+static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
{
- struct rtnl_u32 *u;
- struct nl_msg *msg;
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
- u = u32_cls(cls);
- if (!u)
- return NULL;
-
- msg = nlmsg_alloc();
- if (!msg)
- return NULL;
-
if (u->cu_mask & U32_ATTR_DIVISOR)
- nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
+ NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
if (u->cu_mask & U32_ATTR_HASH)
- nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
+ NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
if (u->cu_mask & U32_ATTR_CLASSID)
- nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
+ NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
if (u->cu_mask & U32_ATTR_LINK)
- nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
+ NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
if (u->cu_mask & U32_ATTR_SELECTOR)
- nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
+ NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
if (u->cu_mask & U32_ATTR_ACTION)
- nla_put_data(msg, TCA_U32_ACT, u->cu_act);
+ NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
if (u->cu_mask & U32_ATTR_POLICE)
- nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
+ NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
if (u->cu_mask & U32_ATTR_INDEV)
- nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
+ NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
- return msg;
+ return 0;
+
+nla_put_failure:
+ return -NLE_NOMEM;
}
/**
@@ -415,12 +350,8 @@ void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
{
- struct rtnl_u32 *u;
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
- u = u32_alloc(cls);
- if (!u)
- return nl_errno(ENOMEM);
-
u->cu_classid = classid;
u->cu_mask |= U32_ATTR_CLASSID;
@@ -437,15 +368,11 @@ int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
{
struct tc_u32_sel *sel;
- struct rtnl_u32 *u;
-
- u = u32_alloc(cls);
- if (!u)
- return nl_errno(ENOMEM);
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
sel = u32_selector_alloc(u);
if (!sel)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
sel->flags |= flags;
u->cu_mask |= U32_ATTR_SELECTOR;
@@ -471,16 +398,12 @@ int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
int off, int offmask)
{
struct tc_u32_sel *sel;
- struct rtnl_u32 *u;
+ struct rtnl_u32 *u = rtnl_cls_data(cls);
int err;
- u = u32_alloc(cls);
- if (!u)
- return nl_errno(ENOMEM);
-
sel = u32_selector_alloc(u);
if (!sel)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
if (err < 0)
@@ -523,7 +446,7 @@ int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
{
int shift = ((off & 3) == 0 ? 16 : 0);
if (off % 2)
- return nl_error(EINVAL, "Invalid offset alignment");
+ return -NLE_INVAL;
return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
htonl((uint32_t)mask << shift),
@@ -580,13 +503,16 @@ int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
static struct rtnl_cls_ops u32_ops = {
.co_kind = "u32",
+ .co_size = sizeof(struct rtnl_u32),
.co_msg_parser = u32_msg_parser,
.co_free_data = u32_free_data,
.co_clone = u32_clone,
.co_get_opts = u32_get_opts,
- .co_dump[NL_DUMP_BRIEF] = u32_dump_brief,
- .co_dump[NL_DUMP_FULL] = u32_dump_full,
- .co_dump[NL_DUMP_STATS] = u32_dump_stats,
+ .co_dump = {
+ [NL_DUMP_LINE] = u32_dump_line,
+ [NL_DUMP_DETAILS] = u32_dump_details,
+ [NL_DUMP_STATS] = u32_dump_stats,
+ },
};
static void __init u32_init(void)
diff --git a/lib/route/cls_api.c b/lib/route/cls_api.c
index f5a083a..73f05df 100644
--- a/lib/route/cls_api.c
+++ b/lib/route/cls_api.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>
*/
/**
@@ -44,7 +44,7 @@ int rtnl_cls_register(struct rtnl_cls_ops *cops)
for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next)
if (!strcasecmp(cops->co_kind, o->co_kind))
- return nl_errno(EEXIST);
+ return -NLE_EXIST;
cops->co_next = NULL;
*op = cops;
@@ -65,7 +65,7 @@ int rtnl_cls_unregister(struct rtnl_cls_ops *cops)
break;
if (!o)
- return nl_errno(ENOENT);
+ return -NLE_OBJ_NOTFOUND;
*op = cops->co_next;
diff --git a/lib/route/cls_obj.c b/lib/route/cls_obj.c
index e12bc95..c8218c0 100644
--- a/lib/route/cls_obj.c
+++ b/lib/route/cls_obj.c
@@ -39,6 +39,8 @@ static void cls_free_data(struct nl_object *obj)
cops = rtnl_cls_lookup_ops(cls);
if (cops && cops->co_free_data)
cops->co_free_data(cls);
+
+ nl_data_free(cls->c_subdata);
}
static int cls_clone(struct nl_object *_dst, struct nl_object *_src)
@@ -52,6 +54,13 @@ static int cls_clone(struct nl_object *_dst, struct nl_object *_src)
if (err < 0)
goto errout;
+ if (src->c_subdata) {
+ if (!(dst->c_subdata = nl_data_clone(src->c_subdata))) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ }
+
cops = rtnl_cls_lookup_ops(src);
if (cops && cops->co_clone)
err = cops->co_clone(dst, src);
@@ -59,59 +68,50 @@ errout:
return err;
}
-static int cls_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
+static void cls_dump_line(struct nl_object *obj, struct nl_dump_params *p)
{
char buf[32];
struct rtnl_cls *cls = (struct rtnl_cls *) obj;
struct rtnl_cls_ops *cops;
- int line;
- line = tca_dump_brief((struct rtnl_tca *) cls, "cls", p, 0);
+ tca_dump_line((struct rtnl_tca *) cls, "cls", p);
- dp_dump(p, " prio %u protocol %s", cls->c_prio,
+ nl_dump(p, " prio %u protocol %s", cls->c_prio,
nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
cops = rtnl_cls_lookup_ops(cls);
- if (cops && cops->co_dump[NL_DUMP_BRIEF])
- line = cops->co_dump[NL_DUMP_BRIEF](cls, p, line);
- dp_dump(p, "\n");
-
- return line;
+ if (cops && cops->co_dump[NL_DUMP_LINE])
+ cops->co_dump[NL_DUMP_LINE](cls, p);
+ nl_dump(p, "\n");
}
-static int cls_dump_full(struct nl_object *obj, struct nl_dump_params *p)
+static void cls_dump_details(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_cls *cls = (struct rtnl_cls *) obj;
struct rtnl_cls_ops *cops;
- int line;
- line = cls_dump_brief(obj, p);
- line = tca_dump_full((struct rtnl_tca *) cls, p, line);
+ cls_dump_line(obj, p);
+ tca_dump_details((struct rtnl_tca *) cls, p);
cops = rtnl_cls_lookup_ops(cls);
- if (cops && cops->co_dump[NL_DUMP_FULL])
- line = cops->co_dump[NL_DUMP_FULL](cls, p, line);
+ if (cops && cops->co_dump[NL_DUMP_DETAILS])
+ cops->co_dump[NL_DUMP_DETAILS](cls, p);
else
- dp_dump(p, "no options\n");
-
- return line;
+ nl_dump(p, "no options\n");
}
-static int cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+static void cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_cls *cls = (struct rtnl_cls *) obj;
struct rtnl_cls_ops *cops;
- int line;
- line = cls_dump_full(obj, p);
- line = tca_dump_stats((struct rtnl_tca *) cls, p, line);
- dp_dump(p, "\n");
+ cls_dump_details(obj, p);
+ tca_dump_stats((struct rtnl_tca *) cls, p);
+ nl_dump(p, "\n");
cops = rtnl_cls_lookup_ops(cls);
if (cops && cops->co_dump[NL_DUMP_STATS])
- line = cops->co_dump[NL_DUMP_STATS](cls, p, line);
-
- return line;
+ cops->co_dump[NL_DUMP_STATS](cls, p);
}
/**
@@ -142,6 +142,11 @@ void rtnl_cls_set_ifindex(struct rtnl_cls *f, int ifindex)
tca_set_ifindex((struct rtnl_tca *) f, ifindex);
}
+int rtnl_cls_get_ifindex(struct rtnl_cls *cls)
+{
+ return cls->c_ifindex;
+}
+
void rtnl_cls_set_handle(struct rtnl_cls *f, uint32_t handle)
{
tca_set_handle((struct rtnl_tca *) f, handle);
@@ -152,19 +157,36 @@ void rtnl_cls_set_parent(struct rtnl_cls *f, uint32_t parent)
tca_set_parent((struct rtnl_tca *) f, parent);
}
-void rtnl_cls_set_kind(struct rtnl_cls *f, const char *kind)
+uint32_t rtnl_cls_get_parent(struct rtnl_cls *cls)
+{
+ return cls->c_parent;
+}
+
+int rtnl_cls_set_kind(struct rtnl_cls *cls, const char *kind)
+{
+ if (cls->ce_mask & TCA_ATTR_KIND)
+ return -NLE_EXIST;
+
+ tca_set_kind((struct rtnl_tca *) cls, kind);
+
+ /* Force allocation of data */
+ rtnl_cls_data(cls);
+
+ return 0;
+}
+
+struct rtnl_cls_ops *rtnl_cls_get_ops(struct rtnl_cls *cls)
{
- tca_set_kind((struct rtnl_tca *) f, kind);
- f->c_ops = __rtnl_cls_lookup_ops(kind);
+ return cls->c_ops;
}
-void rtnl_cls_set_prio(struct rtnl_cls *cls, int prio)
+void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
{
cls->c_prio = prio;
cls->ce_mask |= CLS_ATTR_PRIO;
}
-int rtnl_cls_get_prio(struct rtnl_cls *cls)
+uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
{
if (cls->ce_mask & CLS_ATTR_PRIO)
return cls->c_prio;
@@ -172,13 +194,13 @@ int rtnl_cls_get_prio(struct rtnl_cls *cls)
return 0;
}
-void rtnl_cls_set_protocol(struct rtnl_cls *cls, int protocol)
+void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
{
cls->c_protocol = protocol;
cls->ce_mask |= CLS_ATTR_PROTOCOL;
}
-int rtnl_cls_get_protocol(struct rtnl_cls *cls)
+uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
{
if (cls->ce_mask & CLS_ATTR_PROTOCOL)
return cls->c_protocol;
@@ -186,6 +208,32 @@ int rtnl_cls_get_protocol(struct rtnl_cls *cls)
return ETH_P_ALL;
}
+void *rtnl_cls_data(struct rtnl_cls *cls)
+{
+ if (!cls->c_subdata) {
+ struct rtnl_cls_ops *ops = cls->c_ops;
+
+ if (!ops) {
+ if (!cls->c_kind[0])
+ BUG();
+
+ ops = __rtnl_cls_lookup_ops(cls->c_kind);
+ if (ops == NULL)
+ return NULL;
+
+ cls->c_ops = ops;
+ }
+
+ if (!ops->co_size)
+ BUG();
+
+ if (!(cls->c_subdata = nl_data_alloc(NULL, ops->co_size)))
+ return NULL;
+ }
+
+ return nl_data_get(cls->c_subdata);
+}
+
/** @} */
struct nl_object_ops cls_obj_ops = {
@@ -193,9 +241,11 @@ struct nl_object_ops cls_obj_ops = {
.oo_size = sizeof(struct rtnl_cls),
.oo_free_data = cls_free_data,
.oo_clone = cls_clone,
- .oo_dump[NL_DUMP_BRIEF] = cls_dump_brief,
- .oo_dump[NL_DUMP_FULL] = cls_dump_full,
- .oo_dump[NL_DUMP_STATS] = cls_dump_stats,
+ .oo_dump = {
+ [NL_DUMP_LINE] = cls_dump_line,
+ [NL_DUMP_DETAILS] = cls_dump_details,
+ [NL_DUMP_STATS] = cls_dump_stats,
+ },
.oo_compare = tca_compare,
.oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
};
diff --git a/lib/route/link.c b/lib/route/link.c
index ab89c24..cf488e5 100644
--- a/lib/route/link.c
+++ b/lib/route/link.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>
*/
/**
@@ -78,7 +78,7 @@
* @code
* // The first step is to retrieve a list of all available interfaces within
* // the kernel and put them into a cache.
- * struct nl_cache *cache = rtnl_link_alloc_cache(nl_handle);
+ * struct nl_cache *cache = rtnl_link_alloc_cache(sk);
*
* // In a second step, a specific link may be looked up by either interface
* // index or interface name.
@@ -112,12 +112,12 @@
* // Two ways exist to commit this change request, the first one is to
* // build the required netlink message and send it out in one single
* // step:
- * rtnl_link_change(nl_handle, old, request);
+ * rtnl_link_change(sk, old, request);
*
* // An alternative way is to build the netlink message and send it
* // out yourself using nl_send_auto_complete()
* struct nl_msg *msg = rtnl_link_build_change_request(old, request);
- * nl_send_auto_complete(nl_handle, nlmsg_hdr(msg));
+ * nl_send_auto_complete(sk, nlmsg_hdr(msg));
* nlmsg_free(msg);
*
* // Don't forget to give back the link object ;->
@@ -215,21 +215,19 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
if (src->l_addr)
if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
- goto errout;
+ return -NLE_NOMEM;
if (src->l_bcast)
if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
- goto errout;
+ return -NLE_NOMEM;
if (src->l_info_ops && src->l_info_ops->io_clone) {
err = src->l_info_ops->io_clone(dst, src);
if (err < 0)
- goto errout;
+ return err;
}
return 0;
-errout:
- return nl_get_errno();
}
static struct nla_policy link_policy[IFLA_MAX+1] = {
@@ -265,7 +263,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
link = rtnl_link_alloc();
if (link == NULL) {
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
goto errout;
}
@@ -276,7 +274,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
goto errout;
if (tb[IFLA_IFNAME] == NULL) {
- err = nl_error(EINVAL, "Missing link name TLV");
+ err = -NLE_MISSING_ATTR;
goto errout;
}
@@ -332,18 +330,23 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
if (tb[IFLA_ADDRESS]) {
- link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC);
- if (link->l_addr == NULL)
+ link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
+ if (link->l_addr == NULL) {
+ err = -NLE_NOMEM;
goto errout;
+ }
nl_addr_set_family(link->l_addr,
nl_addr_guess_family(link->l_addr));
link->ce_mask |= LINK_ATTR_ADDR;
}
if (tb[IFLA_BROADCAST]) {
- link->l_bcast = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC);
- if (link->l_bcast == NULL)
+ link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
+ AF_UNSPEC);
+ if (link->l_bcast == NULL) {
+ err = -NLE_NOMEM;
goto errout;
+ }
nl_addr_set_family(link->l_bcast,
nl_addr_guess_family(link->l_bcast));
link->ce_mask |= LINK_ATTR_BRD;
@@ -365,13 +368,8 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
if (tb[IFLA_MAP]) {
- struct rtnl_link_ifmap *map = nla_data(tb[IFLA_MAP]);
- link->l_map.lm_mem_start = map->mem_start;
- link->l_map.lm_mem_end = map->mem_end;
- link->l_map.lm_base_addr = map->base_addr;
- link->l_map.lm_irq = map->irq;
- link->l_map.lm_dma = map->dma;
- link->l_map.lm_port = map->port;
+ nla_memcpy(&link->l_map, tb[IFLA_MAP],
+ sizeof(struct rtnl_link_ifmap));
link->ce_mask |= LINK_ATTR_MAP;
}
@@ -419,125 +417,109 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
err = pp->pp_cb((struct nl_object *) link, pp);
- if (err < 0)
- goto errout;
-
- err = P_ACCEPT;
-
errout:
rtnl_link_put(link);
return err;
}
-static int link_request_update(struct nl_cache *c, struct nl_handle *h)
+static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
{
- return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
+ return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
}
-static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
+static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
{
char buf[128];
struct nl_cache *cache = dp_cache(obj);
struct rtnl_link *link = (struct rtnl_link *) obj;
- int line = 1;
- dp_dump(p, "%s %s ", link->l_name,
- nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
+ nl_dump_line(p, "%s %s ", link->l_name,
+ nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
if (link->l_addr && !nl_addr_iszero(link->l_addr))
- dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
+ nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
if (link->ce_mask & LINK_ATTR_MASTER) {
struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
- dp_dump(p, "master %s ", master ? master->l_name : "inv");
+ nl_dump(p, "master %s ", master ? master->l_name : "inv");
if (master)
rtnl_link_put(master);
}
rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
if (buf[0])
- dp_dump(p, "<%s> ", buf);
+ nl_dump(p, "<%s> ", buf);
if (link->ce_mask & LINK_ATTR_LINK) {
struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
- dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
+ nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
if (ll)
rtnl_link_put(ll);
}
- if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF])
- line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line);
-
- dp_dump(p, "\n");
+ if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
+ link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
- return line;
+ nl_dump(p, "\n");
}
-static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p)
+static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_link *link = (struct rtnl_link *) obj;
char buf[64];
- int line;
- line = link_dump_brief(obj, p);
- dp_new_line(p, line++);
+ link_dump_line(obj, p);
- dp_dump(p, " mtu %u ", link->l_mtu);
- dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
+ nl_dump_line(p, " mtu %u ", link->l_mtu);
+ nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
if (link->ce_mask & LINK_ATTR_QDISC)
- dp_dump(p, "qdisc %s ", link->l_qdisc);
+ nl_dump(p, "qdisc %s ", link->l_qdisc);
if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
- dp_dump(p, "irq %u ", link->l_map.lm_irq);
+ nl_dump(p, "irq %u ", link->l_map.lm_irq);
if (link->ce_mask & LINK_ATTR_IFINDEX)
- dp_dump(p, "index %u ", link->l_index);
-
+ nl_dump(p, "index %u ", link->l_index);
- dp_dump(p, "\n");
- dp_new_line(p, line++);
- dp_dump(p, " ");
+ nl_dump(p, "\n");
+ nl_dump_line(p, " ");
if (link->ce_mask & LINK_ATTR_BRD)
- dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
+ nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
sizeof(buf)));
if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
link->l_operstate != IF_OPER_UNKNOWN) {
rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
- dp_dump(p, "state %s ", buf);
+ nl_dump(p, "state %s ", buf);
}
- dp_dump(p, "mode %s\n",
+ nl_dump(p, "mode %s\n",
rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
- if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL])
- line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line);
-
- return line;
+ if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
+ link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
}
-static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_link *link = (struct rtnl_link *) obj;
char *unit, fmt[64];
float res;
- int line;
- line = link_dump_full(obj, p);
+ link_dump_details(obj, p);
- dp_dump_line(p, line++, " Stats: bytes packets errors "
- " dropped fifo-err compressed\n");
+ nl_dump_line(p, " Stats: bytes packets errors "
+ " dropped fifo-err compressed\n");
res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
- strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
+ strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
fmt[9] = *unit == 'B' ? '9' : '7';
- dp_dump_line(p, line++, fmt,
- res, unit,
+ nl_dump_line(p, fmt, res, unit,
link->l_stats[RTNL_LINK_RX_PACKETS],
link->l_stats[RTNL_LINK_RX_ERRORS],
link->l_stats[RTNL_LINK_RX_DROPPED],
@@ -546,21 +528,20 @@ static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
- strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
+ strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n");
fmt[9] = *unit == 'B' ? '9' : '7';
- dp_dump_line(p, line++, fmt,
- res, unit,
+ nl_dump_line(p, fmt, res, unit,
link->l_stats[RTNL_LINK_TX_PACKETS],
link->l_stats[RTNL_LINK_TX_ERRORS],
link->l_stats[RTNL_LINK_TX_DROPPED],
link->l_stats[RTNL_LINK_TX_FIFO_ERR],
link->l_stats[RTNL_LINK_TX_COMPRESSED]);
- dp_dump_line(p, line++, " Errors: length over crc "
- " frame missed multicast\n");
+ nl_dump_line(p, " Errors: length over crc "
+ " frame missed multicast\n");
- dp_dump_line(p, line++, " RX %10" PRIu64 " %10" PRIu64 " %10"
+ nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10"
PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
PRIu64 "\n",
link->l_stats[RTNL_LINK_RX_LEN_ERR],
@@ -570,11 +551,11 @@ static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
link->l_stats[RTNL_LINK_RX_MISSED_ERR],
link->l_stats[RTNL_LINK_MULTICAST]);
- dp_dump_line(p, line++, " Errors: aborted carrier heartbeat "
- " window collision\n");
+ nl_dump_line(p, " aborted carrier heartbeat "
+ " window collision\n");
- dp_dump_line(p, line++, " TX %10" PRIu64 " %10" PRIu64 " %10"
- PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
+ nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10"
+ PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
link->l_stats[RTNL_LINK_TX_ABORT_ERR],
link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
@@ -582,132 +563,56 @@ static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
link->l_stats[RTNL_LINK_TX_COLLISIONS]);
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
- line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line);
-
- return line;
+ link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
}
-static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
+static void link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_link *link = (struct rtnl_link *) obj;
struct nl_cache *cache = dp_cache(obj);
char buf[128];
- int i, line = 0;
+ int i;
- dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n",
- link->l_name, link->l_index);
- dp_dump_line(p, line++, " <family>%s</family>\n",
+ nl_dump_line(p, "LINK_NAME=%s\n", link->l_name);
+ nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index);
+ nl_dump_line(p, "LINK_FAMILY=%s\n",
nl_af2str(link->l_family, buf, sizeof(buf)));
- dp_dump_line(p, line++, " <arptype>%s</arptype>\n",
- nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
- dp_dump_line(p, line++, " <address>%s</address>\n",
- nl_addr2str(link->l_addr, buf, sizeof(buf)));
- dp_dump_line(p, line++, " <mtu>%u</mtu>\n", link->l_mtu);
- dp_dump_line(p, line++, " <txqlen>%u</txqlen>\n", link->l_txqlen);
- dp_dump_line(p, line++, " <weight>%u</weight>\n", link->l_weight);
-
- rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
- if (buf[0])
- dp_dump_line(p, line++, " <flags>%s</flags>\n", buf);
-
- if (link->ce_mask & LINK_ATTR_QDISC)
- dp_dump_line(p, line++, " <qdisc>%s</qdisc>\n", link->l_qdisc);
-
- if (link->ce_mask & LINK_ATTR_LINK) {
- struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
- dp_dump_line(p, line++, " <link>%s</link>\n",
- ll ? ll->l_name : "none");
- if (ll)
- rtnl_link_put(ll);
- }
-
- if (link->ce_mask & LINK_ATTR_MASTER) {
- struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
- dp_dump_line(p, line++, " <master>%s</master>\n",
- master ? master->l_name : "none");
- if (master)
- rtnl_link_put(master);
- }
-
- if (link->ce_mask & LINK_ATTR_BRD)
- dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n",
- nl_addr2str(link->l_bcast, buf, sizeof(buf)));
-
- if (link->ce_mask & LINK_ATTR_STATS) {
- dp_dump_line(p, line++, " <stats>\n");
- for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) {
- rtnl_link_stat2str(i, buf, sizeof(buf));
- dp_dump_line(p, line++,
- " <%s>%" PRIu64 "</%s>\n",
- buf, link->l_stats[i], buf);
- }
- dp_dump_line(p, line++, " </stats>\n");
- }
-
- if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) {
- dp_dump_line(p, line++, " <info>\n");
- line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line);
- dp_dump_line(p, line++, " </info>\n");
- }
-
- dp_dump_line(p, line++, "</link>\n");
-
-#if 0
- uint32_t l_change; /**< Change mask */
- struct rtnl_lifmap l_map; /**< Interface device mapping */
-#endif
-
- return line;
-}
-
-static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
-{
- struct rtnl_link *link = (struct rtnl_link *) obj;
- struct nl_cache *cache = dp_cache(obj);
- char buf[128];
- int i, line = 0;
-
- dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name);
- dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index);
- dp_dump_line(p, line++, "LINK_FAMILY=%s\n",
- nl_af2str(link->l_family, buf, sizeof(buf)));
- dp_dump_line(p, line++, "LINK_TYPE=%s\n",
+ nl_dump_line(p, "LINK_TYPE=%s\n",
nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
if (link->ce_mask & LINK_ATTR_ADDR)
- dp_dump_line(p, line++, "LINK_ADDRESS=%s\n",
+ nl_dump_line(p, "LINK_ADDRESS=%s\n",
nl_addr2str(link->l_addr, buf, sizeof(buf)));
- dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu);
- dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
- dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight);
+ nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu);
+ nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen);
+ nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight);
rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf));
if (buf[0])
- dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf);
+ nl_dump_line(p, "LINK_FLAGS=%s\n", buf);
if (link->ce_mask & LINK_ATTR_QDISC)
- dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc);
+ nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc);
if (link->ce_mask & LINK_ATTR_LINK) {
struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
- dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link);
+ nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link);
if (ll) {
- dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n",
- ll->l_name);
+ nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name);
rtnl_link_put(ll);
}
}
if (link->ce_mask & LINK_ATTR_MASTER) {
struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
- dp_dump_line(p, line++, "LINK_MASTER=%s\n",
+ nl_dump_line(p, "LINK_MASTER=%s\n",
master ? master->l_name : "none");
if (master)
rtnl_link_put(master);
}
if (link->ce_mask & LINK_ATTR_BRD)
- dp_dump_line(p, line++, "LINK_BROADCAST=%s\n",
+ nl_dump_line(p, "LINK_BROADCAST=%s\n",
nl_addr2str(link->l_bcast, buf, sizeof(buf)));
if (link->ce_mask & LINK_ATTR_STATS) {
@@ -720,15 +625,12 @@ static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p)
*c = toupper(*c);
c++;
}
- dp_dump_line(p, line++,
- "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
+ nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]);
}
}
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV])
- line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line);
-
- return line;
+ link->l_info_ops->io_dump[NL_DUMP_ENV](link, p);
}
#if 0
@@ -800,7 +702,7 @@ static int link_compare(struct nl_object *_a, struct nl_object *_b,
diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr));
diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast));
- if (flags & LOOSE_FLAG_COMPARISON)
+ if (flags & LOOSE_COMPARISON)
diff |= LINK_DIFF(FLAGS,
(a->l_flags ^ b->l_flags) & b->l_flag_mask);
else
@@ -863,28 +765,17 @@ void rtnl_link_put(struct rtnl_link *link)
/**
* Allocate link cache and fill in all configured links.
- * @arg handle Netlink handle.
+ * @arg sk Netlink socket.
+ * @arg result Pointer to store resulting cache.
*
* Allocates a new link cache, initializes it properly and updates it
* to include all links currently configured in the kernel.
*
- * @note Free the memory after usage.
- * @return Newly allocated cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
*/
-struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle)
+int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
{
- struct nl_cache * cache;
-
- cache = nl_cache_alloc(&rtnl_link_ops);
- if (cache == NULL)
- return NULL;
-
- if (handle && nl_cache_refill(handle, cache) < 0) {
- nl_cache_free(cache);
- return NULL;
- }
-
- return cache;
+ return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result);
}
/**
@@ -967,9 +858,9 @@ struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
* @note Not all attributes can be changed, see
* \ref link_changeable "Changeable Attributes" for more details.
*/
-struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
- struct rtnl_link *tmpl,
- int flags)
+int rtnl_link_build_change_request(struct rtnl_link *old,
+ struct rtnl_link *tmpl, int flags,
+ struct nl_msg **result)
{
struct nl_msg *msg;
struct ifinfomsg ifi = {
@@ -984,7 +875,7 @@ struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
if (!msg)
- goto nla_put_failure;
+ return -NLE_NOMEM;
if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
goto nla_put_failure;
@@ -1028,16 +919,17 @@ struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
nla_nest_end(msg, info);
}
- return msg;
+ *result = msg;
+ return 0;
nla_put_failure:
nlmsg_free(msg);
- return NULL;
+ return -NLE_MSGSIZE;
}
/**
* Change link attributes
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg old link to be changed
* @arg tmpl template with requested changes
* @arg flags additional netlink message flags
@@ -1050,22 +942,21 @@ nla_put_failure:
* @note Not all attributes can be changed, see
* \ref link_changeable "Changeable Attributes" for more details.
*/
-int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old,
+int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old,
struct rtnl_link *tmpl, int flags)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_link_build_change_request(old, tmpl, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -1106,11 +997,11 @@ char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
* @arg cache link cache
* @arg name link name
*
- * @return interface index or RTNL_LINK_NOT_FOUND if no match was found.
+ * @return interface index or 0 if no match was found.
*/
int rtnl_link_name2i(struct nl_cache *cache, const char *name)
{
- int ifindex = RTNL_LINK_NOT_FOUND;
+ int ifindex = 0;
struct rtnl_link *link;
link = rtnl_link_get_by_name(cache, name);
@@ -1380,10 +1271,7 @@ void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
int rtnl_link_get_ifindex(struct rtnl_link *link)
{
- if (link->ce_mask & LINK_ATTR_IFINDEX)
- return link->l_index;
- else
- return RTNL_LINK_NOT_FOUND;
+ return link->l_index;
}
void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
@@ -1436,10 +1324,7 @@ void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
int rtnl_link_get_link(struct rtnl_link *link)
{
- if (link->ce_mask & LINK_ATTR_LINK)
- return link->l_link;
- else
- return RTNL_LINK_NOT_FOUND;
+ return link->l_link;
}
void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
@@ -1450,10 +1335,7 @@ void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
int rtnl_link_get_master(struct rtnl_link *link)
{
- if (link->ce_mask & LINK_ATTR_MASTER)
- return link->l_master;
- else
- return RTNL_LINK_NOT_FOUND;
+ return link->l_master;
}
void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate)
@@ -1509,7 +1391,7 @@ int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
int err;
if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
- return nl_error(ENOENT, "No such link info type exists");
+ return -NLE_OPNOTSUPP;
if (link->l_info_ops)
release_link_info(link);
@@ -1544,11 +1426,12 @@ static struct nl_object_ops link_obj_ops = {
.oo_size = sizeof(struct rtnl_link),
.oo_free_data = link_free_data,
.oo_clone = link_clone,
- .oo_dump[NL_DUMP_BRIEF] = link_dump_brief,
- .oo_dump[NL_DUMP_FULL] = link_dump_full,
- .oo_dump[NL_DUMP_STATS] = link_dump_stats,
- .oo_dump[NL_DUMP_XML] = link_dump_xml,
- .oo_dump[NL_DUMP_ENV] = link_dump_env,
+ .oo_dump = {
+ [NL_DUMP_LINE] = link_dump_line,
+ [NL_DUMP_DETAILS] = link_dump_details,
+ [NL_DUMP_STATS] = link_dump_stats,
+ [NL_DUMP_ENV] = link_dump_env,
+ },
.oo_compare = link_compare,
.oo_attrs2str = link_attrs2str,
.oo_id_attrs = LINK_ATTR_IFINDEX,
diff --git a/lib/route/link/api.c b/lib/route/link/api.c
index afe00b1..a0e7679 100644
--- a/lib/route/link/api.c
+++ b/lib/route/link/api.c
@@ -61,10 +61,10 @@ struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
{
if (ops->io_name == NULL)
- return nl_error(EINVAL, "No name specified");
+ return -NLE_INVAL;
if (rtnl_link_info_ops_lookup(ops->io_name))
- return nl_error(EEXIST, "Link info operations already exist");
+ return -NLE_EXIST;
NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
@@ -83,10 +83,10 @@ int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
break;
if (!t)
- return nl_error(ENOENT, "No such link info operations");
+ return -NLE_OPNOTSUPP;
if (t->io_refcnt > 0)
- return nl_error(EBUSY, "Info operations in use");
+ return -NLE_BUSY;
NL_DBG(1, "Unregistered link info perations %s\n", ops->io_name);
diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c
index c148dca..c466afe 100644
--- a/lib/route/link/vlan.c
+++ b/lib/route/link/vlan.c
@@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
*/
/**
@@ -73,7 +73,7 @@ static int vlan_alloc(struct rtnl_link *link)
struct vlan_info *vi;
if ((vi = calloc(1, sizeof(*vi))) == NULL)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
link->l_info = vi;
@@ -119,12 +119,11 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
if (nla_len(nla) < sizeof(*map))
- return nl_error(EINVAL, "Malformed mapping");
+ return -NLE_INVAL;
map = nla_data(nla);
if (map->from < 0 || map->from > VLAN_PRIO_MAX) {
- return nl_error(EINVAL, "VLAN prio %d out of "
- "range", map->from);
+ return -NLE_INVAL;
}
vi->vi_ingress_qos[map->from] = map->to;
@@ -140,7 +139,7 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
if (nla_len(nla) < sizeof(*map))
- return nl_error(EINVAL, "Malformed mapping");
+ return -NLE_INVAL;
i++;
}
@@ -148,7 +147,7 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
vi->vi_egress_size = (i + 32) & ~31;
vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*map));
if (vi->vi_egress_qos == NULL)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
i = 0;
nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
@@ -180,71 +179,60 @@ static void vlan_free(struct rtnl_link *link)
link->l_info = NULL;
}
-static int vlan_dump_brief(struct rtnl_link *link, struct nl_dump_params *p,
- int line)
+static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
{
struct vlan_info *vi = link->l_info;
- dp_dump(p, "vlan-id %d", vi->vi_vlan_id);
-
- return line;
+ nl_dump(p, "vlan-id %d", vi->vi_vlan_id);
}
-static int vlan_dump_full(struct rtnl_link *link, struct nl_dump_params *p,
- int line)
+static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
struct vlan_info *vi = link->l_info;
int i, printed;
char buf[64];
rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf));
- dp_dump_line(p, line++, " vlan-info id %d <%s>\n",
- vi->vi_vlan_id, buf);
+ nl_dump_line(p, " vlan-info id %d <%s>\n", vi->vi_vlan_id, buf);
if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
- dp_dump_line(p, line++,
+ nl_dump_line(p,
" ingress vlan prio -> qos/socket prio mapping:\n");
for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) {
if (vi->vi_ingress_qos[i]) {
- if (printed == 0) {
- dp_new_line(p, line);
- dp_dump(p, " ");
- }
- dp_dump(p, "%x -> %#08x, ",
+ if (printed == 0)
+ nl_dump_line(p, " ");
+ nl_dump(p, "%x -> %#08x, ",
i, vi->vi_ingress_qos[i]);
if (printed++ == 3) {
- dp_dump(p, "\n");
+ nl_dump(p, "\n");
printed = 0;
}
}
}
if (printed > 0 && printed != 4)
- dp_dump(p, "\n");
+ nl_dump(p, "\n");
}
if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
- dp_dump_line(p, line++,
+ nl_dump_line(p,
" egress qos/socket prio -> vlan prio mapping:\n");
for (i = 0, printed = 0; i < vi->vi_negress; i++) {
- if (printed == 0) {
- dp_new_line(p, line);
- dp_dump(p, " ");
- }
- dp_dump(p, "%#08x -> %x, ",
+ if (printed == 0)
+ nl_dump_line(p, " ");
+ nl_dump(p, "%#08x -> %x, ",
vi->vi_egress_qos[i].vm_from,
vi->vi_egress_qos[i].vm_to);
if (printed++ == 3) {
- dp_dump(p, "\n");
+ nl_dump(p, "\n");
printed = 0;
}
}
if (printed > 0 && printed != 4)
- dp_dump(p, "\n");
+ nl_dump(p, "\n");
}
-
- return line;
}
static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -260,7 +248,7 @@ static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
vdst->vi_egress_qos = calloc(vsrc->vi_egress_size,
sizeof(struct vlan_map));
if (!vdst->vi_egress_qos)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
vsrc->vi_egress_size * sizeof(struct vlan_map));
@@ -274,7 +262,7 @@ static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
struct nlattr *data;
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
- return nl_errno(ENOBUFS);
+ return -NLE_MSGSIZE;
if (vi->vi_mask & VLAN_HAS_ID)
NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
@@ -337,8 +325,10 @@ static struct rtnl_link_info_ops vlan_info_ops = {
.io_name = "vlan",
.io_alloc = vlan_alloc,
.io_parse = vlan_parse,
- .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief,
- .io_dump[NL_DUMP_FULL] = vlan_dump_full,
+ .io_dump = {
+ [NL_DUMP_LINE] = vlan_dump_line,
+ [NL_DUMP_DETAILS] = vlan_dump_details,
+ },
.io_clone = vlan_clone,
.io_put_attrs = vlan_put_attrs,
.io_free = vlan_free,
@@ -349,7 +339,7 @@ int rtnl_link_vlan_set_id(struct rtnl_link *link, int id)
struct vlan_info *vi = link->l_info;
if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
- return nl_error(EOPNOTSUPP, "Not a VLAN link");
+ return -NLE_OPNOTSUPP;
vi->vi_vlan_id = id;
vi->vi_mask |= VLAN_HAS_ID;
@@ -362,7 +352,7 @@ int rtnl_link_vlan_get_id(struct rtnl_link *link)
struct vlan_info *vi = link->l_info;
if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
- return nl_error(EOPNOTSUPP, "Not a VLAN link");
+ return -NLE_OPNOTSUPP;
if (vi->vi_mask & VLAN_HAS_ID)
return vi->vi_vlan_id;
@@ -375,7 +365,7 @@ int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags)
struct vlan_info *vi = link->l_info;
if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
- return nl_error(EOPNOTSUPP, "Not a VLAN link");
+ return -NLE_OPNOTSUPP;
vi->vi_flags_mask |= flags;
vi->vi_flags |= flags;
@@ -389,7 +379,7 @@ int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags)
struct vlan_info *vi = link->l_info;
if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
- return nl_error(EOPNOTSUPP, "Not a VLAN link");
+ return -NLE_OPNOTSUPP;
vi->vi_flags_mask |= flags;
vi->vi_flags &= ~flags;
@@ -403,7 +393,7 @@ unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *link)
struct vlan_info *vi = link->l_info;
if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
- return nl_error(EOPNOTSUPP, "Not a VLAN link");
+ return -NLE_OPNOTSUPP;
return vi->vi_flags;
}
@@ -414,11 +404,10 @@ int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from,
struct vlan_info *vi = link->l_info;
if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
- return nl_error(EOPNOTSUPP, "Not a VLAN link");
+ return -NLE_OPNOTSUPP;
if (from < 0 || from > VLAN_PRIO_MAX)
- return nl_error(EINVAL, "Invalid vlan prio 0..%d",
- VLAN_PRIO_MAX);
+ return -NLE_INVAL;
vi->vi_ingress_qos[from] = to;
vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
@@ -430,10 +419,8 @@ uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link)
{
struct vlan_info *vi = link->l_info;
- if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) {
- nl_error(EOPNOTSUPP, "Not a VLAN link");
+ if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
return NULL;
- }
if (vi->vi_mask & VLAN_HAS_INGRESS_QOS)
return vi->vi_ingress_qos;
@@ -446,11 +433,10 @@ int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
struct vlan_info *vi = link->l_info;
if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
- return nl_error(EOPNOTSUPP, "Not a VLAN link");
+ return -NLE_OPNOTSUPP;
if (to < 0 || to > VLAN_PRIO_MAX)
- return nl_error(EINVAL, "Invalid vlan prio 0..%d",
- VLAN_PRIO_MAX);
+ return -NLE_INVAL;
if (vi->vi_negress >= vi->vi_egress_size) {
int new_size = vi->vi_egress_size + 32;
@@ -458,7 +444,7 @@ int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
ptr = realloc(vi->vi_egress_qos, new_size);
if (!ptr)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
vi->vi_egress_qos = ptr;
vi->vi_egress_size = new_size;
@@ -477,15 +463,11 @@ struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link,
{
struct vlan_info *vi = link->l_info;
- if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) {
- nl_error(EOPNOTSUPP, "Not a VLAN link");
+ if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
return NULL;
- }
- if (negress == NULL) {
- nl_error(EINVAL, "Require pointer to store negress");
+ if (negress == NULL)
return NULL;
- }
if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
*negress = vi->vi_negress;
diff --git a/lib/route/neigh.c b/lib/route/neigh.c
index 6f2f0d3..d4dc82c 100644
--- a/lib/route/neigh.c
+++ b/lib/route/neigh.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>
*/
/**
@@ -61,7 +61,7 @@
* @code
* // The first step is to retrieve a list of all available neighbour within
* // the kernel and put them into a cache.
- * struct nl_cache *cache = rtnl_neigh_alloc_cache(handle);
+ * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk);
*
* // Neighbours can then be looked up by the interface and destination
* // address:
@@ -86,7 +86,7 @@
* // block until the operation has been completed. Alternatively the required
* // netlink message can be built using rtnl_neigh_build_add_request()
* // to be sent out using nl_send_auto_complete().
- * rtnl_neigh_add(nl_handle, neigh, NLM_F_REPLACE);
+ * rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
*
* // Free the memory
* rtnl_neigh_put(neigh);
@@ -109,7 +109,7 @@
* // block until the operation has been completed. Alternatively the required
* // netlink message can be built using rtnl_neigh_build_delete_request()
* // to be sent out using nl_send_auto_complete().
- * rtnl_neigh_delete(handle, neigh, 0);
+ * rtnl_neigh_delete(sk, neigh, 0);
*
* // Free the memory
* rtnl_neigh_put(neigh);
@@ -139,7 +139,7 @@
* // block until the operation has been completed. Alternatively the required
* // netlink message can be built using rtnl_neigh_build_change_request()
* // to be sent out using nl_send_auto_complete().
- * rtnl_neigh_change(handle, neigh, 0);
+ * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE);
*
* // Free the memory
* rtnl_neigh_put(neigh);
@@ -187,15 +187,13 @@ static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
if (src->n_lladdr)
if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
- goto errout;
+ return -NLE_NOMEM;
if (src->n_dst)
if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
- goto errout;
+ return -NLE_NOMEM;
return 0;
-errout:
- return nl_get_errno();
}
static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
@@ -213,7 +211,7 @@ static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr));
diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst));
- if (flags & LOOSE_FLAG_COMPARISON) {
+ if (flags & LOOSE_COMPARISON) {
diff |= NEIGH_DIFF(STATE,
(a->n_state ^ b->n_state) & b->n_state_mask);
diff |= NEIGH_DIFF(FLAGS,
@@ -261,7 +259,7 @@ static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
neigh = rtnl_neigh_alloc();
if (!neigh) {
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
goto errout;
}
@@ -283,18 +281,22 @@ static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
NEIGH_ATTR_TYPE);
if (tb[NDA_LLADDR]) {
- neigh->n_lladdr = nla_get_addr(tb[NDA_LLADDR], AF_UNSPEC);
- if (!neigh->n_lladdr)
+ neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC);
+ if (!neigh->n_lladdr) {
+ err = -NLE_NOMEM;
goto errout;
+ }
nl_addr_set_family(neigh->n_lladdr,
nl_addr_guess_family(neigh->n_lladdr));
neigh->ce_mask |= NEIGH_ATTR_LLADDR;
}
if (tb[NDA_DST]) {
- neigh->n_dst = nla_get_addr(tb[NDA_DST], neigh->n_family);
- if (!neigh->n_dst)
+ neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family);
+ if (!neigh->n_dst) {
+ err = -NLE_NOMEM;
goto errout;
+ }
neigh->ce_mask |= NEIGH_ATTR_DST;
}
@@ -315,23 +317,18 @@ static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
err = pp->pp_cb((struct nl_object *) neigh, pp);
- if (err < 0)
- goto errout;
-
- err = P_ACCEPT;
-
errout:
rtnl_neigh_put(neigh);
return err;
}
-static int neigh_request_update(struct nl_cache *c, struct nl_handle *h)
+static int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
{
return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP);
}
-static int neigh_dump_brief(struct nl_object *a, struct nl_dump_params *p)
+static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
{
char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
struct rtnl_neigh *n = (struct rtnl_neigh *) a;
@@ -340,162 +337,95 @@ static int neigh_dump_brief(struct nl_object *a, struct nl_dump_params *p)
link_cache = nl_cache_mngt_require("route/link");
- dp_dump(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
+ nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
if (link_cache)
- dp_dump(p, "dev %s ",
+ nl_dump(p, "dev %s ",
rtnl_link_i2name(link_cache, n->n_ifindex,
state, sizeof(state)));
else
- dp_dump(p, "dev %d ", n->n_ifindex);
+ nl_dump(p, "dev %d ", n->n_ifindex);
if (n->ce_mask & NEIGH_ATTR_LLADDR)
- dp_dump(p, "lladdr %s ",
+ nl_dump(p, "lladdr %s ",
nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
rtnl_neigh_state2str(n->n_state, state, sizeof(state));
rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
if (state[0])
- dp_dump(p, "<%s", state);
+ nl_dump(p, "<%s", state);
if (flags[0])
- dp_dump(p, "%s%s", state[0] ? "," : "<", flags);
+ nl_dump(p, "%s%s", state[0] ? "," : "<", flags);
if (state[0] || flags[0])
- dp_dump(p, ">");
- dp_dump(p, "\n");
-
- return 1;
+ nl_dump(p, ">");
+ nl_dump(p, "\n");
}
-static int neigh_dump_full(struct nl_object *a, struct nl_dump_params *p)
+static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p)
{
char rtn_type[32];
struct rtnl_neigh *n = (struct rtnl_neigh *) a;
int hz = nl_get_hz();
- int line = neigh_dump_brief(a, p);
+ neigh_dump_line(a, p);
- dp_dump_line(p, line++, " refcnt %u type %s confirmed %u used "
+ nl_dump_line(p, " refcnt %u type %s confirmed %u used "
"%u updated %u\n",
n->n_cacheinfo.nci_refcnt,
nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
n->n_cacheinfo.nci_confirmed/hz,
n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
-
- return line;
-}
-
-static int neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
-{
- return neigh_dump_full(a, p);
}
-static int neigh_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
+static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
{
- struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
- char buf[128];
- int line = 0;
-
- dp_dump_line(p, line++, "<neighbour>\n");
- dp_dump_line(p, line++, " <family>%s</family>\n",
- nl_af2str(neigh->n_family, buf, sizeof(buf)));
-
- if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
- dp_dump_line(p, line++, " <lladdr>%s</lladdr>\n",
- nl_addr2str(neigh->n_lladdr, buf, sizeof(buf)));
-
- if (neigh->ce_mask & NEIGH_ATTR_DST)
- dp_dump_line(p, line++, " <dst>%s</dst>\n",
- nl_addr2str(neigh->n_dst, buf, sizeof(buf)));
-
- if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) {
- struct nl_cache *link_cache;
-
- link_cache = nl_cache_mngt_require("route/link");
-
- if (link_cache)
- dp_dump_line(p, line++, " <device>%s</device>\n",
- rtnl_link_i2name(link_cache,
- neigh->n_ifindex,
- buf, sizeof(buf)));
- else
- dp_dump_line(p, line++, " <device>%u</device>\n",
- neigh->n_ifindex);
- }
-
- if (neigh->ce_mask & NEIGH_ATTR_PROBES)
- dp_dump_line(p, line++, " <probes>%u</probes>\n",
- neigh->n_probes);
-
- if (neigh->ce_mask & NEIGH_ATTR_TYPE)
- dp_dump_line(p, line++, " <type>%s</type>\n",
- nl_rtntype2str(neigh->n_type, buf, sizeof(buf)));
-
- rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf));
- if (buf[0])
- dp_dump_line(p, line++, " <flags>%s</flags>\n", buf);
-
- rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf));
- if (buf[0])
- dp_dump_line(p, line++, " <state>%s</state>\n", buf);
-
- dp_dump_line(p, line++, "</neighbour>\n");
-
-#if 0
- struct rtnl_ncacheinfo n_cacheinfo;
-#endif
-
- return line;
+ neigh_dump_details(a, p);
}
-static int neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p)
+static void neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
char buf[128];
- int line = 0;
- dp_dump_line(p, line++, "NEIGH_FAMILY=%s\n",
+ nl_dump_line(p, "NEIGH_FAMILY=%s\n",
nl_af2str(neigh->n_family, buf, sizeof(buf)));
if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
- dp_dump_line(p, line++, "NEIGHT_LLADDR=%s\n",
+ nl_dump_line(p, "NEIGHT_LLADDR=%s\n",
nl_addr2str(neigh->n_lladdr, buf, sizeof(buf)));
if (neigh->ce_mask & NEIGH_ATTR_DST)
- dp_dump_line(p, line++, "NEIGH_DST=%s\n",
+ nl_dump_line(p, "NEIGH_DST=%s\n",
nl_addr2str(neigh->n_dst, buf, sizeof(buf)));
if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) {
struct nl_cache *link_cache;
- dp_dump_line(p, line++, "NEIGH_IFINDEX=%u\n",
- neigh->n_ifindex);
+ nl_dump_line(p, "NEIGH_IFINDEX=%u\n", neigh->n_ifindex);
link_cache = nl_cache_mngt_require("route/link");
if (link_cache)
- dp_dump_line(p, line++, "NEIGH_IFNAME=%s\n",
+ nl_dump_line(p, "NEIGH_IFNAME=%s\n",
rtnl_link_i2name(link_cache,
neigh->n_ifindex,
buf, sizeof(buf)));
}
if (neigh->ce_mask & NEIGH_ATTR_PROBES)
- dp_dump_line(p, line++, "NEIGH_PROBES=%u\n",
- neigh->n_probes);
+ nl_dump_line(p, "NEIGH_PROBES=%u\n", neigh->n_probes);
if (neigh->ce_mask & NEIGH_ATTR_TYPE)
- dp_dump_line(p, line++, "NEIGH_TYPE=%s\n",
+ nl_dump_line(p, "NEIGH_TYPE=%s\n",
nl_rtntype2str(neigh->n_type, buf, sizeof(buf)));
rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf));
if (buf[0])
- dp_dump_line(p, line++, "NEIGH_FLAGS=%s\n", buf);
+ nl_dump_line(p, "NEIGH_FLAGS=%s\n", buf);
rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf));
if (buf[0])
- dp_dump_line(p, line++, "NEIGH_STATE=%s\n", buf);
-
- return line;
+ nl_dump_line(p, "NEIGH_STATE=%s\n", buf);
}
/**
@@ -522,31 +452,17 @@ void rtnl_neigh_put(struct rtnl_neigh *neigh)
/**
* Build a neighbour cache including all neighbours currently configured in the kernel.
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
+ * @arg result Pointer to store resulting cache.
*
* Allocates a new neighbour cache, initializes it properly and updates it
* to include all neighbours currently configured in the kernel.
*
- * @note The caller is responsible for destroying and freeing the
- * cache after using it.
- * @return The new cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
*/
-struct nl_cache *rtnl_neigh_alloc_cache(struct nl_handle *handle)
+int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
{
- struct nl_cache *cache;
-
- cache = nl_cache_alloc(&rtnl_neigh_ops);
- if (cache == NULL)
- return NULL;
-
- if (handle && nl_cache_refill(handle, cache) < 0) {
- nl_cache_free(cache);
- return NULL;
- }
-
- NL_DBG(2, "Returning new cache %p\n", cache);
-
- return cache;
+ return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
}
/**
@@ -579,22 +495,26 @@ struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
* @{
*/
-static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd,
- int flags)
+static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
+ struct nl_msg **result)
{
struct nl_msg *msg;
struct ndmsg nhdr = {
.ndm_ifindex = tmpl->n_ifindex,
- .ndm_family = nl_addr_get_family(tmpl->n_dst),
.ndm_state = NUD_PERMANENT,
};
+ if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
+ return -NLE_MISSING_ATTR;
+
+ nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
+
if (tmpl->ce_mask & NEIGH_ATTR_STATE)
nhdr.ndm_state = tmpl->n_state;
msg = nlmsg_alloc_simple(cmd, flags);
if (!msg)
- return NULL;
+ return -NLE_NOMEM;
if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
goto nla_put_failure;
@@ -604,17 +524,19 @@ static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd,
if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
- return msg;
+ *result = msg;
+ return 0;
nla_put_failure:
nlmsg_free(msg);
- return NULL;
+ return -NLE_MSGSIZE;
}
/**
* Build netlink request message to add a new neighbour
* @arg tmpl template with data of new neighbour
* @arg flags additional netlink message flags
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting a addition of a new
* neighbour. The netlink message header isn't fully equipped with
@@ -628,16 +550,17 @@ nla_put_failure:
* - Destination address (rtnl_neigh_set_dst())
* - Link layer address (rtnl_neigh_set_lladdr())
*
- * @return The netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags)
+int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
+ struct nl_msg **result)
{
- return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE | flags);
+ return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
}
/**
* Add a new neighbour
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg tmpl template with requested changes
* @arg flags additional netlink message flags
*
@@ -653,21 +576,20 @@ struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags)
+int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
{
int err;
struct nl_msg *msg;
- msg = rtnl_neigh_build_add_request(tmpl, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -681,6 +603,7 @@ int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags)
* Build a netlink request message to delete a neighbour
* @arg neigh neighbour to delete
* @arg flags additional netlink message flags
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting a deletion of a neighbour.
* The netlink message header isn't fully equipped with all relevant
@@ -688,17 +611,17 @@ int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags)
* or supplemented as needed. \a neigh must point to an existing
* neighbour.
*
- * @return The netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh,
- int flags)
+int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
+ struct nl_msg **result)
{
- return build_neigh_msg(neigh, RTM_DELNEIGH, flags);
+ return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
}
/**
* Delete a neighbour
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg neigh neighbour to delete
* @arg flags additional netlink message flags
*
@@ -708,81 +631,21 @@ struct nl_msg *rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh,
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_neigh_delete(struct nl_handle *handle, struct rtnl_neigh *neigh,
+int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
int flags)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_neigh_build_delete_request(neigh, flags);
- if (!msg)
- return nl_errno(ENOMEM);
-
- err = nl_send_auto_complete(handle, msg);
- if (err < 0)
+ if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
return err;
+ err = nl_send_auto_complete(sk, msg);
nlmsg_free(msg);
- return nl_wait_for_ack(handle);
-}
-
-/** @} */
-
-/**
- * @name Neighbour Modification
- * @{
- */
-
-/**
- * Build a netlink request message to change neighbour attributes
- * @arg neigh the neighbour to change
- * @arg flags additional netlink message flags
- *
- * Builds a new netlink message requesting a change of a neigh
- * attributes. The netlink message header isn't fully equipped with
- * all relevant fields and must thus be sent out via nl_send_auto_complete()
- * or supplemented as needed.
- *
- * @return The netlink message
- * @note Not all attributes can be changed, see
- * \ref neigh_changeable "Changeable Attributes" for a list.
- */
-struct nl_msg *rtnl_neigh_build_change_request(struct rtnl_neigh *neigh,
- int flags)
-{
- return build_neigh_msg(neigh, RTM_NEWNEIGH, NLM_F_REPLACE | flags);
-}
-
-/**
- * Change neighbour attributes
- * @arg handle netlink handle
- * @arg neigh neighbour to be changed
- * @arg flags additional netlink message flags
- *
- * Builds a netlink message by calling rtnl_neigh_build_change_request(),
- * sends the request to the kernel and waits for the next ACK to be
- * received and thus blocks until the request has been fullfilled.
- *
- * @return 0 on sucess or a negative error if an error occured.
- * @note Not all attributes can be changed, see
- * \ref neigh_changeable "Changeable Attributes" for a list.
- */
-int rtnl_neigh_change(struct nl_handle *handle, struct rtnl_neigh *neigh,
- int flags)
-{
- int err;
- struct nl_msg *msg;
-
- msg = rtnl_neigh_build_change_request(neigh, flags);
- if (!msg)
- return nl_errno(ENOMEM);
-
- err = nl_send_auto_complete(handle, msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -893,10 +756,7 @@ void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
{
- if (neigh->ce_mask & NEIGH_ATTR_IFINDEX)
- return neigh->n_ifindex;
- else
- return RTNL_LINK_NOT_FOUND;
+ return neigh->n_ifindex;
}
static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
@@ -905,8 +765,7 @@ static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
if (!nocheck) {
if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
if (new->a_family != neigh->n_family)
- return nl_error(EINVAL,
- "Address family mismatch");
+ return -NLE_AF_MISMATCH;
} else {
neigh->n_family = new->a_family;
neigh->ce_mask |= NEIGH_ATTR_FAMILY;
@@ -957,6 +816,11 @@ void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
neigh->ce_mask |= NEIGH_ATTR_FAMILY;
}
+int rtnl_neigh_get_family(struct rtnl_neigh *neigh)
+{
+ return neigh->n_family;
+}
+
void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
{
neigh->n_type = type;
@@ -978,14 +842,15 @@ static struct nl_object_ops neigh_obj_ops = {
.oo_size = sizeof(struct rtnl_neigh),
.oo_free_data = neigh_free_data,
.oo_clone = neigh_clone,
- .oo_dump[NL_DUMP_BRIEF] = neigh_dump_brief,
- .oo_dump[NL_DUMP_FULL] = neigh_dump_full,
- .oo_dump[NL_DUMP_STATS] = neigh_dump_stats,
- .oo_dump[NL_DUMP_XML] = neigh_dump_xml,
- .oo_dump[NL_DUMP_ENV] = neigh_dump_env,
+ .oo_dump = {
+ [NL_DUMP_LINE] = neigh_dump_line,
+ [NL_DUMP_DETAILS] = neigh_dump_details,
+ [NL_DUMP_STATS] = neigh_dump_stats,
+ [NL_DUMP_ENV] = neigh_dump_env,
+ },
.oo_compare = neigh_compare,
.oo_attrs2str = neigh_attrs2str,
- .oo_id_attrs = (NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
+ .oo_id_attrs = (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
};
static struct nl_af_group neigh_groups[] = {
diff --git a/lib/route/neightbl.c b/lib/route/neightbl.c
index 3191b5b..9599faa 100644
--- a/lib/route/neightbl.c
+++ b/lib/route/neightbl.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>
*/
/**
@@ -129,7 +129,7 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops,
ntbl = rtnl_neightbl_alloc();
if (!ntbl) {
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
goto errout;
}
@@ -143,7 +143,7 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops,
ntbl->nt_family = rtmsg->rtgen_family;
if (tb[NDTA_NAME] == NULL) {
- err = nl_error(EINVAL, "NDTA_NAME is missing");
+ return -NLE_MISSING_ATTR;
goto errout;
}
@@ -217,27 +217,22 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops,
}
err = pp->pp_cb((struct nl_object *) ntbl, pp);
- if (err < 0)
- goto errout;
-
- err = P_ACCEPT;
errout:
rtnl_neightbl_put(ntbl);
return err;
}
-static int neightbl_request_update(struct nl_cache *c, struct nl_handle *h)
+static int neightbl_request_update(struct nl_cache *c, struct nl_sock *h)
{
return nl_rtgen_request(h, RTM_GETNEIGHTBL, AF_UNSPEC, NLM_F_DUMP);
}
-static int neightbl_dump_brief(struct nl_object *arg, struct nl_dump_params *p)
+static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p)
{
- int line = 1;
struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
- dp_dump(p, "%s", ntbl->nt_name);
+ nl_dump_line(p, "%s", ntbl->nt_name);
if (ntbl->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) {
struct nl_cache *link_cache;
@@ -246,57 +241,52 @@ static int neightbl_dump_brief(struct nl_object *arg, struct nl_dump_params *p)
if (link_cache) {
char buf[32];
- dp_dump(p, "<%s> ",
+ nl_dump(p, "<%s> ",
rtnl_link_i2name(link_cache,
ntbl->nt_parms.ntp_ifindex,
buf, sizeof(buf)));
} else
- dp_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex);
+ nl_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex);
} else
- dp_dump(p, " ");
+ nl_dump(p, " ");
if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG)
- dp_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries);
+ nl_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries);
if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
char rt[32], rt2[32];
struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
- dp_dump(p, "reachable-time %s retransmit-time %s",
+ nl_dump(p, "reachable-time %s retransmit-time %s",
nl_msec2str(pa->ntp_reachable_time, rt, sizeof(rt)),
nl_msec2str(pa->ntp_retrans_time, rt2, sizeof(rt2)));
}
- dp_dump(p, "\n");
-
- return line;
+ nl_dump(p, "\n");
}
-static int neightbl_dump_full(struct nl_object *arg, struct nl_dump_params *p)
+static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *p)
{
char x[32], y[32], z[32];
struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
- int line = neightbl_dump_brief(arg, p);
+ neightbl_dump_line(arg, p);
if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) {
- dp_new_line(p, line++);
- dp_dump(p, " key-len %u entry-size %u last-flush %s\n",
+ nl_dump_line(p, " key-len %u entry-size %u last-flush %s\n",
ntbl->nt_config.ndtc_key_len,
ntbl->nt_config.ndtc_entry_size,
nl_msec2str(ntbl->nt_config.ndtc_last_flush,
x, sizeof(x)));
- dp_new_line(p, line++);
- dp_dump(p, " gc threshold %u/%u/%u interval %s " \
+ nl_dump_line(p, " gc threshold %u/%u/%u interval %s " \
"chain-position %u\n",
ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2,
ntbl->nt_gc_thresh3,
nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)),
ntbl->nt_config.ndtc_hash_chain_gc);
- dp_new_line(p, line++);
- dp_dump(p, " hash-rand 0x%08X/0x%08X last-rand %s\n",
+ nl_dump_line(p, " hash-rand 0x%08X/0x%08X last-rand %s\n",
ntbl->nt_config.ndtc_hash_rnd,
ntbl->nt_config.ndtc_hash_mask,
nl_msec2str(ntbl->nt_config.ndtc_last_rand,
@@ -306,49 +296,43 @@ static int neightbl_dump_full(struct nl_object *arg, struct nl_dump_params *p)
if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
- dp_new_line(p, line++);
- dp_dump(p, " refcnt %u pending-queue-limit %u " \
+ nl_dump_line(p, " refcnt %u pending-queue-limit %u " \
"proxy-delayed-queue-limit %u\n",
pa->ntp_refcnt,
pa->ntp_queue_len,
pa->ntp_proxy_qlen);
- dp_new_line(p, line++);
- dp_dump(p, " num-userspace-probes %u num-unicast-probes " \
+ nl_dump_line(p, " num-userspace-probes %u num-unicast-probes " \
"%u num-multicast-probes %u\n",
pa->ntp_app_probes,
pa->ntp_ucast_probes,
pa->ntp_mcast_probes);
- dp_new_line(p, line++);
- dp_dump(p, " min-age %s base-reachable-time %s " \
+ nl_dump_line(p, " min-age %s base-reachable-time %s " \
"stale-check-interval %s\n",
nl_msec2str(pa->ntp_locktime, x, sizeof(x)),
nl_msec2str(pa->ntp_base_reachable_time,
y, sizeof(y)),
nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z)));
- dp_new_line(p, line++);
- dp_dump(p, " initial-probe-delay %s answer-delay %s " \
+ nl_dump_line(p, " initial-probe-delay %s answer-delay %s " \
"proxy-answer-delay %s\n",
nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)),
nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)),
nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z)));
}
-
- return line;
}
-static int neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
+static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
{
struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
- int line = neightbl_dump_full(arg, p);
+
+ neightbl_dump_details(arg, p);
if (!(ntbl->ce_mask & NEIGHTBL_ATTR_STATS))
- return line;
+ return;
- dp_new_line(p, line++);
- dp_dump(p, " lookups %lld hits %lld failed %lld " \
+ nl_dump_line(p, " lookups %lld hits %lld failed %lld " \
"allocations %lld destroys %lld\n",
ntbl->nt_stats.ndts_lookups,
ntbl->nt_stats.ndts_hits,
@@ -356,18 +340,15 @@ static int neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
ntbl->nt_stats.ndts_allocs,
ntbl->nt_stats.ndts_destroys);
- dp_new_line(p, line++);
- dp_dump(p, " hash-grows %lld forced-gc-runs %lld " \
+ nl_dump_line(p, " hash-grows %lld forced-gc-runs %lld " \
"periodic-gc-runs %lld\n",
ntbl->nt_stats.ndts_hash_grows,
ntbl->nt_stats.ndts_forced_gc_runs,
ntbl->nt_stats.ndts_periodic_gc_runs);
- dp_dump(p, " rcv-unicast-probes %lld rcv-multicast-probes %lld\n",
+ nl_dump_line(p, " rcv-unicast-probes %lld rcv-multicast-probes %lld\n",
ntbl->nt_stats.ndts_rcv_probes_ucast,
ntbl->nt_stats.ndts_rcv_probes_mcast);
-
- return line;
}
/**
@@ -394,30 +375,18 @@ void rtnl_neightbl_put(struct rtnl_neightbl *neightbl)
/**
* Build a neighbour table cache including all neighbour tables currently configured in the kernel.
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
+ * @arg result Pointer to store resulting cache.
*
* Allocates a new neighbour table cache, initializes it properly and
* updates it to include all neighbour tables currently configured in
* the kernel.
*
- * @note The caller is responsible for destroying and freeing the
- * cache after using it.
- * @return The new cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
*/
-struct nl_cache * rtnl_neightbl_alloc_cache(struct nl_handle *handle)
+int rtnl_neightbl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
{
- struct nl_cache * cache;
-
- cache = nl_cache_alloc(&rtnl_neightbl_ops);
- if (cache == NULL)
- return NULL;
-
- if (handle && nl_cache_refill(handle, cache) < 0) {
- nl_cache_free(cache);
- return NULL;
- }
-
- return cache;
+ return nl_cache_alloc_and_fill(&rtnl_neightbl_ops, sk, result);
}
/**
@@ -464,6 +433,7 @@ struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache,
* Builds a netlink change request message to change neighbour table attributes
* @arg old neighbour table to change
* @arg tmpl template with requested changes
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting a change of neighbour table
* attributes. The netlink message header isn't fully equipped with all
@@ -473,98 +443,115 @@ struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache,
* kernel and \a tmpl must contain the attributes to be changed set via
* \c rtnl_neightbl_set_* functions.
*
- * @return New netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg * rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
- struct rtnl_neightbl *tmpl)
+int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
+ struct rtnl_neightbl *tmpl,
+ struct nl_msg **result)
{
- struct nl_msg *m;
+ struct nl_msg *m, *parms = NULL;
struct ndtmsg ndt = {
.ndtm_family = old->nt_family,
};
m = nlmsg_alloc_simple(RTM_SETNEIGHTBL, 0);
- nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO);
+ if (!m)
+ return -NLE_NOMEM;
- nla_put_string(m, NDTA_NAME, old->nt_name);
+ if (nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ NLA_PUT_STRING(m, NDTA_NAME, old->nt_name);
if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH1)
- nla_put_u32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1);
+ NLA_PUT_U32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1);
if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
- nla_put_u32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
+ NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
- nla_put_u32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
+ NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
if (tmpl->ce_mask & NEIGHTBL_ATTR_GC_INTERVAL)
- nla_put_u64(m, NDTA_GC_INTERVAL,
+ NLA_PUT_U64(m, NDTA_GC_INTERVAL,
tmpl->nt_gc_interval);
if (tmpl->ce_mask & NEIGHTBL_ATTR_PARMS) {
struct rtnl_neightbl_parms *p = &tmpl->nt_parms;
- struct nl_msg *parms = nlmsg_alloc();
+
+ parms = nlmsg_alloc();
+ if (!parms)
+ goto nla_put_failure;
if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX)
- nla_put_u32(parms, NDTPA_IFINDEX,
+ NLA_PUT_U32(parms, NDTPA_IFINDEX,
old->nt_parms.ntp_ifindex);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_QUEUE_LEN)
- nla_put_u32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len);
+ NLA_PUT_U32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_APP_PROBES)
- nla_put_u32(parms, NDTPA_APP_PROBES, p->ntp_app_probes);
+ NLA_PUT_U32(parms, NDTPA_APP_PROBES, p->ntp_app_probes);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_UCAST_PROBES)
- nla_put_u32(parms, NDTPA_UCAST_PROBES,
+ NLA_PUT_U32(parms, NDTPA_UCAST_PROBES,
p->ntp_ucast_probes);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_MCAST_PROBES)
- nla_put_u32(parms, NDTPA_MCAST_PROBES,
+ NLA_PUT_U32(parms, NDTPA_MCAST_PROBES,
p->ntp_mcast_probes);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_QLEN)
- nla_put_u32(parms, NDTPA_PROXY_QLEN,
+ NLA_PUT_U32(parms, NDTPA_PROXY_QLEN,
p->ntp_proxy_qlen);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME)
- nla_put_u64(parms, NDTPA_BASE_REACHABLE_TIME,
+ NLA_PUT_U64(parms, NDTPA_BASE_REACHABLE_TIME,
p->ntp_base_reachable_time);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_RETRANS_TIME)
- nla_put_u64(parms, NDTPA_RETRANS_TIME,
+ NLA_PUT_U64(parms, NDTPA_RETRANS_TIME,
p->ntp_retrans_time);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_GC_STALETIME)
- nla_put_u64(parms, NDTPA_GC_STALETIME,
+ NLA_PUT_U64(parms, NDTPA_GC_STALETIME,
p->ntp_gc_stale_time);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME)
- nla_put_u64(parms, NDTPA_DELAY_PROBE_TIME,
+ NLA_PUT_U64(parms, NDTPA_DELAY_PROBE_TIME,
p->ntp_proxy_delay);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_ANYCAST_DELAY)
- nla_put_u64(parms, NDTPA_ANYCAST_DELAY,
+ NLA_PUT_U64(parms, NDTPA_ANYCAST_DELAY,
p->ntp_anycast_delay);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_DELAY)
- nla_put_u64(parms, NDTPA_PROXY_DELAY,
+ NLA_PUT_U64(parms, NDTPA_PROXY_DELAY,
p->ntp_proxy_delay);
if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME)
- nla_put_u64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
+ NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
+
+ if (nla_put_nested(m, NDTA_PARMS, parms) < 0)
+ goto nla_put_failure;
- nla_put_nested(m, NDTA_PARMS, parms);
nlmsg_free(parms);
}
-
- return m;
+
+ *result = m;
+ return 0;
+
+nla_put_failure:
+ if (parms)
+ nlmsg_free(parms);
+ nlmsg_free(m);
+ return -NLE_MSGSIZE;
}
/**
* Change neighbour table attributes
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg old neighbour table to be changed
* @arg tmpl template with requested changes
*
@@ -575,19 +562,21 @@ struct nl_msg * rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
*
* @return 0 on success or a negative error code
*/
-int rtnl_neightbl_change(struct nl_handle *handle, struct rtnl_neightbl *old,
+int rtnl_neightbl_change(struct nl_sock *sk, struct rtnl_neightbl *old,
struct rtnl_neightbl *tmpl)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_neightbl_build_change_request(old, tmpl);
- err = nl_send_auto_complete(handle, msg);
- if (err < 0)
+ if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0)
return err;
+ err = nl_send_auto_complete(sk, msg);
nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ if (err < 0)
+ return err;
+
+ return wait_for_ack(sk);
}
/** @} */
@@ -790,9 +779,11 @@ void rtnl_neightbl_set_locktime(struct rtnl_neightbl *ntbl, uint64_t ms)
static struct nl_object_ops neightbl_obj_ops = {
.oo_name = "route/neightbl",
.oo_size = sizeof(struct rtnl_neightbl),
- .oo_dump[NL_DUMP_BRIEF] = neightbl_dump_brief,
- .oo_dump[NL_DUMP_FULL] = neightbl_dump_full,
- .oo_dump[NL_DUMP_STATS] = neightbl_dump_stats,
+ .oo_dump = {
+ [NL_DUMP_LINE] = neightbl_dump_line,
+ [NL_DUMP_DETAILS] = neightbl_dump_details,
+ [NL_DUMP_STATS] = neightbl_dump_stats,
+ },
.oo_compare = neightbl_compare,
};
diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c
index 7486769..788e255 100644
--- a/lib/route/nexthop.c
+++ b/lib/route/nexthop.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>
*/
/**
@@ -21,6 +21,14 @@
#include <netlink/route/rtnl.h>
#include <netlink/route/route.h>
+/** @cond SKIP */
+#define NH_ATTR_FLAGS 0x000001
+#define NH_ATTR_WEIGHT 0x000002
+#define NH_ATTR_IFINDEX 0x000004
+#define NH_ATTR_GATEWAY 0x000008
+#define NH_ATTR_REALMS 0x000010
+/** @endcond */
+
/**
* @name Allocation/Freeing
* @{
@@ -31,10 +39,8 @@ struct rtnl_nexthop *rtnl_route_nh_alloc(void)
struct rtnl_nexthop *nh;
nh = calloc(1, sizeof(*nh));
- if (!nh) {
- nl_errno(ENOMEM);
+ if (!nh)
return NULL;
- }
nl_init_list_head(&nh->rtnh_list);
@@ -53,7 +59,7 @@ struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
nh->rtnh_flag_mask = src->rtnh_flag_mask;
nh->rtnh_weight = src->rtnh_weight;
nh->rtnh_ifindex = src->rtnh_ifindex;
- nh->rtnh_mask = src->rtnh_mask;
+ nh->ce_mask = src->ce_mask;
if (src->rtnh_gateway) {
nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
@@ -74,78 +80,251 @@ void rtnl_route_nh_free(struct rtnl_nexthop *nh)
/** @} */
+int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
+ uint32_t attrs, int loose)
+{
+ int diff = 0;
+
+#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR)
+
+ diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex);
+ diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight);
+ diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms);
+ diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway,
+ b->rtnh_gateway));
+
+ if (loose)
+ diff |= NH_DIFF(FLAGS,
+ (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask);
+ else
+ diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags);
+
+#undef NH_DIFF
+
+ return diff;
+}
+
+static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+ struct nl_cache *link_cache;
+ char buf[128];
+
+ link_cache = nl_cache_mngt_require("route/link");
+
+ nl_dump(dp, "via");
+
+ if (nh->ce_mask & NH_ATTR_GATEWAY)
+ nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
+ buf, sizeof(buf)));
+
+ if(nh->ce_mask & NH_ATTR_IFINDEX) {
+ if (link_cache) {
+ nl_dump(dp, " dev %s",
+ rtnl_link_i2name(link_cache,
+ nh->rtnh_ifindex,
+ buf, sizeof(buf)));
+ } else
+ nl_dump(dp, " dev %d", nh->rtnh_ifindex);
+ }
+
+ nl_dump(dp, " ");
+}
+
+static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+ struct nl_cache *link_cache;
+ char buf[128];
+
+ link_cache = nl_cache_mngt_require("route/link");
+
+ nl_dump(dp, "nexthop");
+
+ if (nh->ce_mask & NH_ATTR_GATEWAY)
+ nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
+ buf, sizeof(buf)));
+
+ if(nh->ce_mask & NH_ATTR_IFINDEX) {
+ if (link_cache) {
+ nl_dump(dp, " dev %s",
+ rtnl_link_i2name(link_cache,
+ nh->rtnh_ifindex,
+ buf, sizeof(buf)));
+ } else
+ nl_dump(dp, " dev %d", nh->rtnh_ifindex);
+ }
+
+ if (nh->ce_mask & NH_ATTR_WEIGHT)
+ nl_dump(dp, " weight %u", nh->rtnh_weight);
+
+ if (nh->ce_mask & NH_ATTR_REALMS)
+ nl_dump(dp, " realm %04x:%04x",
+ RTNL_REALM_FROM(nh->rtnh_realms),
+ RTNL_REALM_TO(nh->rtnh_realms));
+
+ if (nh->ce_mask & NH_ATTR_FLAGS)
+ nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
+ buf, sizeof(buf)));
+}
+
+static void nh_dump_env(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+ struct nl_cache *link_cache;
+ char buf[128];
+
+ link_cache = nl_cache_mngt_require("route/link");
+
+ if (nh->ce_mask & NH_ATTR_GATEWAY)
+ nl_dump_line(dp, "ROUTE_NH%d_VIA=%s\n", dp->dp_ivar,
+ nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf)));
+
+ if(nh->ce_mask & NH_ATTR_IFINDEX) {
+ if (link_cache) {
+ nl_dump_line(dp, "ROUTE_NH%d_DEV=%s\n", dp->dp_ivar,
+ rtnl_link_i2name(link_cache,
+ nh->rtnh_ifindex,
+ buf, sizeof(buf)));
+ } else
+ nl_dump_line(dp, "ROUTE_NH%d_DEV=%d\n", dp->dp_ivar,
+ nh->rtnh_ifindex);
+ }
+
+ if (nh->ce_mask & NH_ATTR_WEIGHT)
+ nl_dump_line(dp, "ROUTE_NH%d_WEIGHT=%u\n", dp->dp_ivar,
+ nh->rtnh_weight);
+
+ if (nh->ce_mask & NH_ATTR_REALMS)
+ nl_dump_line(dp, "ROUTE_NH%d_REALM=%04x:%04x\n", dp->dp_ivar,
+ RTNL_REALM_FROM(nh->rtnh_realms),
+ RTNL_REALM_TO(nh->rtnh_realms));
+
+ if (nh->ce_mask & NH_ATTR_FLAGS)
+ nl_dump_line(dp, "ROUTE_NH%d_FLAGS=<%s>\n", dp->dp_ivar,
+ rtnl_route_nh_flags2str(nh->rtnh_flags,
+ buf, sizeof(buf)));
+}
+void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+ switch (dp->dp_type) {
+ case NL_DUMP_LINE:
+ nh_dump_line(nh, dp);
+ break;
+
+ case NL_DUMP_DETAILS:
+ case NL_DUMP_STATS:
+ if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
+ nh_dump_details(nh, dp);
+ break;
+
+ case NL_DUMP_ENV:
+ nh_dump_env(nh, dp);
+ break;
+
+ default:
+ break;
+ }
+}
+
/**
* @name Attributes
+ * @{
*/
-void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, int weight)
+void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
{
nh->rtnh_weight = weight;
- nh->rtnh_mask |= NEXTHOP_HAS_WEIGHT;
+ nh->ce_mask |= NH_ATTR_WEIGHT;
}
-int rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
+uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
{
- if (nh->rtnh_mask & NEXTHOP_HAS_WEIGHT)
- return nh->rtnh_weight;
- else
- return 0;
+ return nh->rtnh_weight;
}
void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
{
nh->rtnh_ifindex = ifindex;
- nh->rtnh_mask |= NEXTHOP_HAS_IFINDEX;
+ nh->ce_mask |= NH_ATTR_IFINDEX;
}
int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
{
- if (nh->rtnh_mask & NEXTHOP_HAS_IFINDEX)
- return nh->rtnh_ifindex;
- else
- return -1;
+ return nh->rtnh_ifindex;
}
void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
{
struct nl_addr *old = nh->rtnh_gateway;
- nh->rtnh_gateway = nl_addr_get(addr);
+ if (addr) {
+ nh->rtnh_gateway = nl_addr_get(addr);
+ nh->ce_mask |= NH_ATTR_GATEWAY;
+ } else {
+ nh->ce_mask &= ~NH_ATTR_GATEWAY;
+ nh->rtnh_gateway = NULL;
+ }
+
if (old)
nl_addr_put(old);
-
- nh->rtnh_mask |= NEXTHOP_HAS_GATEWAY;
}
struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
{
- if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY)
- return nh->rtnh_gateway;
- else
- return NULL;
+ return nh->rtnh_gateway;
}
void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
{
nh->rtnh_flag_mask |= flags;
nh->rtnh_flags |= flags;
- nh->rtnh_mask |= NEXTHOP_HAS_FLAGS;
+ nh->ce_mask |= NH_ATTR_FLAGS;
}
void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
{
nh->rtnh_flag_mask |= flags;
nh->rtnh_flags &= ~flags;
- nh->rtnh_mask |= NEXTHOP_HAS_FLAGS;
+ nh->ce_mask |= NH_ATTR_FLAGS;
}
unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
{
- if (nh->rtnh_mask & NEXTHOP_HAS_FLAGS)
- return nh->rtnh_flags;
- else
- return 0;
+ return nh->rtnh_flags;
+}
+
+void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
+{
+ nh->rtnh_realms = realms;
+ nh->ce_mask |= NH_ATTR_REALMS;
+}
+
+uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
+{
+ return nh->rtnh_realms;
+}
+
+/** @} */
+
+/**
+ * @name Nexthop Flags Translations
+ * @{
+ */
+
+static struct trans_tbl nh_flags[] = {
+ __ADD(RTNH_F_DEAD, dead)
+ __ADD(RTNH_F_PERVASIVE, pervasive)
+ __ADD(RTNH_F_ONLINK, onlink)
+};
+
+char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
+{
+ return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
+}
+
+int rtnl_route_nh_str2flags(const char *name)
+{
+ return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
}
/** @} */
+
/** @} */
diff --git a/lib/route/pktloc.c b/lib/route/pktloc.c
new file mode 100644
index 0000000..f0d0155
--- /dev/null
+++ b/lib/route/pktloc.c
@@ -0,0 +1,168 @@
+/*
+ * lib/route/pktloc.c Packet Location Aliasing
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2 of the License.
+ *
+ * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup pktloc Packet Location Aliasing
+ * Packet Location Aliasing
+ *
+ * The packet location aliasing interface eases the use of offset definitions
+ * inside packets by allowing them to be referenced by name. Known positions
+ * of protocol fields are stored in a configuration file and associated with
+ * a name for later reference. The configuration file is distributed with the
+ * library and provides a well defined set of definitions for most common
+ * protocol fields.
+ *
+ * @subsection pktloc_examples Examples
+ * @par Example 1.1 Looking up a packet location
+ * @code
+ * struct rtnl_pktloc *loc;
+ *
+ * rtnl_pktloc_lookup("ip.src", &loc);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+
+#include "pktloc_syntax.h"
+#include "pktloc_grammar.h"
+
+/** @cond */
+#define PKTLOC_NAME_HT_SIZ 256
+
+static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
+
+/* djb2 */
+unsigned int pktloc_hash(const char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ while ((c = *str++))
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash % PKTLOC_NAME_HT_SIZ;
+}
+
+
+void rtnl_pktloc_add(struct rtnl_pktloc *loc)
+{
+ nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
+}
+
+extern int pktloc_parse(void *scanner);
+
+/** @endcond */
+
+static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
+{
+ if (!loc)
+ return;
+
+ free(loc->name);
+ free(loc);
+}
+
+static int read_pktlocs(void)
+{
+ YY_BUFFER_STATE buf;
+ yyscan_t scanner = NULL;
+ static time_t last_read;
+ struct stat st = {0};
+ char *path;
+ int i, err;
+ FILE *fd;
+
+ asprintf(&path, "%s/pktloc", SYSCONFDIR);
+
+ /* if stat fails, just try to read the file */
+ if (stat(path, &st) == 0) {
+ /* Don't re-read file if file is unchanged */
+ if (last_read == st.st_mtime)
+ return 0;
+ }
+
+ if (!(fd = fopen(path, "r")))
+ return -NLE_PKTLOC_FILE;
+
+ for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
+ struct rtnl_pktloc *loc, *n;
+
+ nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
+ rtnl_pktloc_free(loc);
+
+ nl_init_list_head(&pktloc_name_ht[i]);
+ }
+
+ if ((err = pktloc_lex_init(&scanner)) < 0)
+ return -NLE_FAILURE;
+
+ buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
+ pktloc__switch_to_buffer(buf, scanner);
+
+ if ((err = pktloc_parse(scanner)) < 0)
+ return -NLE_FAILURE;
+
+ if (scanner)
+ pktloc_lex_destroy(scanner);
+
+ free(path);
+ last_read = st.st_mtime;
+
+ return 0;
+}
+
+/**
+ * Lookup packet location alias
+ * @arg name Name of packet location.
+ *
+ * Tries to find a matching packet location alias for the supplied
+ * packet location name.
+ *
+ * The file containing the packet location definitions is automatically
+ * re-read if its modification time has changed since the last call.
+ *
+ * @return 0 on success or a negative error code.
+ * @retval NLE_PKTLOC_FILE Unable to open packet location file.
+ * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
+ */
+int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
+{
+ struct rtnl_pktloc *loc;
+ int hash, err;
+
+ if ((err = read_pktlocs()) < 0)
+ return err;
+
+ hash = pktloc_hash(name);
+ nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
+ if (!strcasecmp(loc->name, name)) {
+ *result = loc;
+ return 0;
+ }
+ }
+
+ return -NLE_OBJ_NOTFOUND;
+}
+
+static int __init pktloc_init(void)
+{
+ int i;
+
+ for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
+ nl_init_list_head(&pktloc_name_ht[i]);
+
+ return 0;
+}
diff --git a/lib/route/pktloc_grammar.l b/lib/route/pktloc_grammar.l
new file mode 100644
index 0000000..f710430
--- /dev/null
+++ b/lib/route/pktloc_grammar.l
@@ -0,0 +1,42 @@
+%{
+ #include <netlink-local.h>
+ #include <netlink-tc.h>
+ #include <netlink/netlink.h>
+ #include <netlink/utils.h>
+ #include <netlink/route/pktloc.h>
+ #include "pktloc_syntax.h"
+%}
+
+%option 8bit
+%option reentrant
+%option warn
+%option noyywrap
+%option nounput
+%option bison-bridge
+%option bison-locations
+%option prefix="pktloc_"
+
+%%
+
+[ \t\r\n]+
+
+"#".*
+
+[[:digit:]]+ |
+0[xX][[:xdigit:]]+ {
+ yylval->i = strtoul(yytext, NULL, 0);
+ return NUMBER;
+ }
+
+"+" { return yylval->i = yytext[0]; }
+
+[lL][iI][nN][kK] { yylval->i = TCF_LAYER_LINK; return LAYER; }
+[nN][eE][tT] { yylval->i = TCF_LAYER_NETWORK; return LAYER; }
+[tT][cC][pP] { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; }
+
+[^ \t\r\n+]+ {
+ yylval->s = strdup(yytext);
+ if (yylval->s == NULL)
+ return ERROR;
+ return NAME;
+ }
diff --git a/lib/route/pktloc_syntax.y b/lib/route/pktloc_syntax.y
new file mode 100644
index 0000000..05d609a
--- /dev/null
+++ b/lib/route/pktloc_syntax.y
@@ -0,0 +1,108 @@
+%{
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+%}
+
+%locations
+%error-verbose
+%define api.pure
+%name-prefix "pktloc_"
+
+%parse-param {void *scanner}
+%lex-param {void *scanner}
+
+%union {
+ struct rtnl_pktloc *l;
+ uint32_t i;
+ char *s;
+}
+
+%{
+extern int pktloc_lex(YYSTYPE *, YYLTYPE *, void *);
+extern void rtnl_pktloc_add(struct rtnl_pktloc *);
+
+static void yyerror(YYLTYPE *locp, void *scanner, const char *msg)
+{
+ /* FIXME */
+}
+%}
+
+%token <i> ERROR NUMBER LAYER
+%token <s> NAME
+
+%type <i> mask layer
+%type <l> location
+
+%destructor { free($$); } NAME
+
+%start input
+
+%%
+
+input:
+ def
+ { }
+ ;
+
+def:
+ /* empty */
+ { }
+ | location def
+ { }
+ ;
+
+location:
+ NAME NAME layer NUMBER mask
+ {
+ struct rtnl_pktloc *loc;
+
+ if (!(loc = calloc(1, sizeof(*loc)))) {
+ /* FIXME */
+ }
+
+ if (!strcasecmp($2, "u8"))
+ loc->align = TCF_EM_ALIGN_U8;
+ else if (!strcasecmp($2, "h8")) {
+ loc->align = TCF_EM_ALIGN_U8;
+ loc->flags = TCF_EM_CMP_TRANS;
+ } else if (!strcasecmp($2, "u16"))
+ loc->align = TCF_EM_ALIGN_U16;
+ else if (!strcasecmp($2, "h16")) {
+ loc->align = TCF_EM_ALIGN_U16;
+ loc->flags = TCF_EM_CMP_TRANS;
+ } else if (!strcasecmp($2, "u32"))
+ loc->align = TCF_EM_ALIGN_U32;
+ else if (!strcasecmp($2, "h32")) {
+ loc->align = TCF_EM_ALIGN_U32;
+ loc->flags = TCF_EM_CMP_TRANS;
+ }
+
+ free($2);
+
+ loc->name = $1;
+ loc->layer = $3;
+ loc->offset = $4;
+ loc->mask = $5;
+
+ rtnl_pktloc_add(loc);
+
+ $$ = loc;
+ }
+ ;
+
+layer:
+ /* empty */
+ { $$ = TCF_LAYER_NETWORK; }
+ | LAYER '+'
+ { $$ = $1; }
+ ;
+
+mask:
+ /* empty */
+ { $$ = 0; }
+ | NUMBER
+ { $$ = $1; }
+ ;
diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c
index 8eda51b..cfeaf05 100644
--- a/lib/route/qdisc.c
+++ b/lib/route/qdisc.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>
*/
/**
@@ -98,13 +98,13 @@ static struct nl_cache_ops rtnl_qdisc_ops;
static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *n, struct nl_parser_param *pp)
{
- int err = -ENOMEM;
+ int err;
struct rtnl_qdisc *qdisc;
struct rtnl_qdisc_ops *qops;
qdisc = rtnl_qdisc_alloc();
if (!qdisc) {
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
goto errout;
}
@@ -122,25 +122,20 @@ static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
err = pp->pp_cb((struct nl_object *) qdisc, pp);
- if (err < 0)
- goto errout_free;
-
- err = P_ACCEPT;
-
errout_free:
rtnl_qdisc_put(qdisc);
errout:
return err;
}
-static int qdisc_request_update(struct nl_cache *c, struct nl_handle *h)
+static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk)
{
struct tcmsg tchdr = {
.tcm_family = AF_UNSPEC,
.tcm_ifindex = c->c_iarg1,
};
- return nl_send_simple(h, RTM_GETQDISC, NLM_F_DUMP, &tchdr,
+ return nl_send_simple(sk, RTM_GETQDISC, NLM_F_DUMP, &tchdr,
sizeof(tchdr));
}
@@ -149,15 +144,15 @@ static int qdisc_request_update(struct nl_cache *c, struct nl_handle *h)
* @{
*/
-static struct nl_msg *qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags)
+static int qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags,
+ struct nl_msg **result)
{
struct rtnl_qdisc_ops *qops;
- struct nl_msg *msg;
int err;
- msg = tca_build_msg((struct rtnl_tca *) qdisc, type, flags);
- if (!msg)
- goto errout;
+ err = tca_build_msg((struct rtnl_tca *) qdisc, type, flags, result);
+ if (err < 0)
+ return err;
qops = rtnl_qdisc_lookup_ops(qdisc);
if (qops && qops->qo_get_opts) {
@@ -165,24 +160,33 @@ static struct nl_msg *qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags)
opts = qops->qo_get_opts(qdisc);
if (opts) {
- err = nla_put_nested(msg, TCA_OPTIONS, opts);
+ err = nla_put_nested(*result, TCA_OPTIONS, opts);
nlmsg_free(opts);
if (err < 0)
goto errout;
}
}
+ /* Some qdiscs don't accept properly nested messages (e.g. netem). To
+ * accomodate for this, they can complete the message themselves.
+ */
+ else if (qops && qops->qo_build_msg) {
+ err = qops->qo_build_msg(qdisc, *result);
+ if (err < 0)
+ goto errout;
+ }
- return msg;
+ return 0;
errout:
- nlmsg_free(msg);
+ nlmsg_free(*result);
- return NULL;
+ return err;
}
/**
* Build a netlink message to add a new qdisc
* @arg qdisc qdisc to add
* @arg flags additional netlink message flags
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting an addition of a qdisc.
* The netlink message header isn't fully equipped with all relevant
@@ -192,23 +196,17 @@ errout:
* Common message flags used:
* - NLM_F_REPLACE - replace a potential existing qdisc
*
- * @return New netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc,
- int flags)
+int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags,
+ struct nl_msg **result)
{
- struct nl_msg *msg;
-
- msg = qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags);
- if (!msg)
- nl_errno(ENOMEM);
-
- return msg;
+ return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags, result);
}
/**
* Add a new qdisc
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg qdisc qdisc to delete
* @arg flags additional netlink message flags
*
@@ -221,22 +219,21 @@ struct nl_msg *rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc,
*
* @return 0 on success or a negative error code
*/
-int rtnl_qdisc_add(struct nl_handle *handle, struct rtnl_qdisc *qdisc,
+int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
int flags)
{
struct nl_msg *msg;
int err;
- msg = rtnl_qdisc_build_add_request(qdisc, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_qdisc_build_add_request(qdisc, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -250,23 +247,25 @@ int rtnl_qdisc_add(struct nl_handle *handle, struct rtnl_qdisc *qdisc,
* Build a netlink message to change attributes of a existing qdisc
* @arg qdisc qdisc to change
* @arg new new qdisc attributes
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting an change of qdisc
* attributes. The netlink message header isn't fully equipped
* with all relevant fields and must be sent out via
* nl_send_auto_complete() or supplemented as needed.
*
- * @return New netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
- struct rtnl_qdisc *new)
+int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
+ struct rtnl_qdisc *new,
+ struct nl_msg **result)
{
- return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE);
+ return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE, result);
}
/**
* Change attributes of a qdisc
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg qdisc qdisc to change
* @arg new new qdisc attributes
*
@@ -276,22 +275,21 @@ struct nl_msg *rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
*
* @return 0 on success or a negative error code
*/
-int rtnl_qdisc_change(struct nl_handle *handle, struct rtnl_qdisc *qdisc,
+int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
struct rtnl_qdisc *new)
{
struct nl_msg *msg;
int err;
- msg = rtnl_qdisc_build_change_request(qdisc, new);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_qdisc_build_change_request(qdisc, new, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -304,15 +302,17 @@ int rtnl_qdisc_change(struct nl_handle *handle, struct rtnl_qdisc *qdisc,
/**
* Build a netlink request message to delete a qdisc
* @arg qdisc qdisc to delete
+ * @arg result Pointer to store resulting message.
*
* Builds a new netlink message requesting a deletion of a qdisc.
* The netlink message header isn't fully equipped with all relevant
* fields and must thus be sent out via nl_send_auto_complete()
* or supplemented as needed.
*
- * @return New netlink message
+ * @return 0 on success or a negative error code.
*/
-struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc)
+int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc,
+ struct nl_msg **result)
{
struct nl_msg *msg;
struct tcmsg tchdr;
@@ -323,20 +323,24 @@ struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc)
msg = nlmsg_alloc_simple(RTM_DELQDISC, 0);
if (!msg)
- return NULL;
-
- tchdr.tcm_family = AF_UNSPEC,
- tchdr.tcm_handle = qdisc->q_handle,
- tchdr.tcm_parent = qdisc->q_parent,
- tchdr.tcm_ifindex = qdisc->q_ifindex,
- nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO);
+ return -NLE_NOMEM;
+
+ tchdr.tcm_family = AF_UNSPEC;
+ tchdr.tcm_handle = qdisc->q_handle;
+ tchdr.tcm_parent = qdisc->q_parent;
+ tchdr.tcm_ifindex = qdisc->q_ifindex;
+ if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+ }
- return msg;
+ *result = msg;
+ return 0;
}
/**
* Delete a qdisc
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg qdisc qdisc to delete
*
* Builds a netlink message by calling rtnl_qdisc_build_delete_request(),
@@ -345,21 +349,20 @@ struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc)
*
* @return 0 on success or a negative error code
*/
-int rtnl_qdisc_delete(struct nl_handle *handle, struct rtnl_qdisc *qdisc)
+int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc)
{
struct nl_msg *msg;
int err;
- msg = rtnl_qdisc_build_delete_request(qdisc);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_qdisc_build_delete_request(qdisc, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -372,29 +375,17 @@ int rtnl_qdisc_delete(struct nl_handle *handle, struct rtnl_qdisc *qdisc)
/**
* Build a qdisc cache including all qdiscs currently configured in
* the kernel
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
+ * @arg result Pointer to store resulting message.
*
* Allocates a new cache, initializes it properly and updates it to
* include all qdiscs currently configured in the kernel.
*
- * @note The caller is responsible for destroying and freeing the
- * cache after using it.
- * @return The cache or NULL if an error has occured.
+ * @return 0 on success or a negative error code.
*/
-struct nl_cache * rtnl_qdisc_alloc_cache(struct nl_handle *handle)
+int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
{
- struct nl_cache * cache;
-
- cache = nl_cache_alloc(&rtnl_qdisc_ops);
- if (cache == NULL)
- return NULL;
-
- if (handle && nl_cache_refill(handle, cache) < 0) {
- nl_cache_free(cache);
- return NULL;
- }
-
- return cache;
+ return nl_cache_alloc_and_fill(&rtnl_qdisc_ops, sk, result);
}
/**
diff --git a/lib/route/qdisc_api.c b/lib/route/qdisc_api.c
index ef4d07a..089f212 100644
--- a/lib/route/qdisc_api.c
+++ b/lib/route/qdisc_api.c
@@ -46,7 +46,7 @@ int rtnl_qdisc_register(struct rtnl_qdisc_ops *qops)
for (op = &qdisc_ops_list; (o = *op) != NULL; op = &o->qo_next)
if (!strcasecmp(qops->qo_kind, o->qo_kind))
- return nl_errno(EEXIST);
+ return -NLE_EXIST;
qops->qo_next = NULL;
*op = qops;
@@ -67,7 +67,7 @@ int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *qops)
break;
if (!o)
- return nl_errno(ENOENT);
+ return -NLE_OBJ_NOTFOUND;
*op = qops->qo_next;
diff --git a/lib/route/qdisc_obj.c b/lib/route/qdisc_obj.c
index bbbb954..dc52ae8 100644
--- a/lib/route/qdisc_obj.c
+++ b/lib/route/qdisc_obj.c
@@ -56,54 +56,49 @@ errout:
return err;
}
-static int qdisc_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
+static void qdisc_dump_line(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
struct rtnl_qdisc_ops *qops;
-
- int line = tca_dump_brief((struct rtnl_tca *) qdisc, "qdisc", p, 0);
+
+ tca_dump_line((struct rtnl_tca *) qdisc, "qdisc", p);
qops = rtnl_qdisc_lookup_ops(qdisc);
- if (qops && qops->qo_dump[NL_DUMP_BRIEF])
- line = qops->qo_dump[NL_DUMP_BRIEF](qdisc, p, line);
+ if (qops && qops->qo_dump[NL_DUMP_LINE])
+ qops->qo_dump[NL_DUMP_LINE](qdisc, p);
- dp_dump(p, "\n");
-
- return line;
+ nl_dump(p, "\n");
}
-static int qdisc_dump_full(struct nl_object *arg, struct nl_dump_params *p)
+static void qdisc_dump_details(struct nl_object *arg, struct nl_dump_params *p)
{
struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg;
struct rtnl_qdisc_ops *qops;
- int line = qdisc_dump_brief(arg, p);
+ qdisc_dump_line(arg, p);
- line = tca_dump_full((struct rtnl_tca *) qdisc, p, line);
- dp_dump(p, "refcnt %u ", qdisc->q_info);
+ tca_dump_details((struct rtnl_tca *) qdisc, p);
+ nl_dump(p, "refcnt %u ", qdisc->q_info);
qops = rtnl_qdisc_lookup_ops(qdisc);
- if (qops && qops->qo_dump[NL_DUMP_FULL])
- line = qops->qo_dump[NL_DUMP_FULL](qdisc, p, line);
+ if (qops && qops->qo_dump[NL_DUMP_DETAILS])
+ qops->qo_dump[NL_DUMP_DETAILS](qdisc, p);
- dp_dump(p, "\n");
- return line;
+ nl_dump(p, "\n");
}
-static int qdisc_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
+static void qdisc_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
{
struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg;
struct rtnl_qdisc_ops *qops;
- int line = qdisc_dump_full(arg, p);
- line = tca_dump_stats((struct rtnl_tca *) qdisc, p, line );
- dp_dump(p, "\n");
+ qdisc_dump_details(arg, p);
+ tca_dump_stats((struct rtnl_tca *) qdisc, p);
+ nl_dump(p, "\n");
qops = rtnl_qdisc_lookup_ops(qdisc);
if (qops && qops->qo_dump[NL_DUMP_STATS])
- line = qops->qo_dump[NL_DUMP_STATS](qdisc, p, line);
-
- return line;
+ qops->qo_dump[NL_DUMP_STATS](qdisc, p);
}
/**
@@ -263,9 +258,11 @@ struct nl_object_ops qdisc_obj_ops = {
.oo_size = sizeof(struct rtnl_qdisc),
.oo_free_data = qdisc_free_data,
.oo_clone = qdisc_clone,
- .oo_dump[NL_DUMP_BRIEF] = qdisc_dump_brief,
- .oo_dump[NL_DUMP_FULL] = qdisc_dump_full,
- .oo_dump[NL_DUMP_STATS] = qdisc_dump_stats,
+ .oo_dump = {
+ [NL_DUMP_LINE] = qdisc_dump_line,
+ [NL_DUMP_DETAILS] = qdisc_dump_details,
+ [NL_DUMP_STATS] = qdisc_dump_stats,
+ },
.oo_compare = tca_compare,
.oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
};
diff --git a/lib/route/route.c b/lib/route/route.c
index 0644bd7..c85c225 100644
--- a/lib/route/route.c
+++ b/lib/route/route.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>
*/
/**
@@ -27,199 +27,31 @@
static struct nl_cache_ops rtnl_route_ops;
-static struct nla_policy route_policy[RTA_MAX+1] = {
- [RTA_IIF] = { .type = NLA_STRING,
- .maxlen = IFNAMSIZ, },
- [RTA_OIF] = { .type = NLA_U32 },
- [RTA_PRIORITY] = { .type = NLA_U32 },
- [RTA_FLOW] = { .type = NLA_U32 },
- [RTA_MP_ALGO] = { .type = NLA_U32 },
- [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
- [RTA_METRICS] = { .type = NLA_NESTED },
- [RTA_MULTIPATH] = { .type = NLA_NESTED },
-};
-
-static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci,
- struct rtnl_route *route)
-{
- struct rtnl_rtcacheinfo nci = {
- .rtci_clntref = ci->rta_clntref,
- .rtci_last_use = ci->rta_lastuse,
- .rtci_expires = ci->rta_expires,
- .rtci_error = ci->rta_error,
- .rtci_used = ci->rta_used,
- .rtci_id = ci->rta_id,
- .rtci_ts = ci->rta_ts,
- .rtci_tsage = ci->rta_tsage,
- };
-
- rtnl_route_set_cacheinfo(route, &nci);
-}
-
static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
- struct rtmsg *rtm;
struct rtnl_route *route;
- struct nlattr *tb[RTA_MAX + 1];
- struct nl_addr *src = NULL, *dst = NULL, *addr;
int err;
- route = rtnl_route_alloc();
- if (!route) {
- err = nl_errno(ENOMEM);
- goto errout;
- }
-
- route->ce_msgtype = nlh->nlmsg_type;
-
- err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
- route_policy);
- if (err < 0)
- goto errout;
-
- rtm = nlmsg_data(nlh);
- rtnl_route_set_family(route, rtm->rtm_family);
- rtnl_route_set_tos(route, rtm->rtm_tos);
- rtnl_route_set_table(route, rtm->rtm_table);
- rtnl_route_set_type(route, rtm->rtm_type);
- rtnl_route_set_scope(route, rtm->rtm_scope);
- rtnl_route_set_protocol(route, rtm->rtm_protocol);
- rtnl_route_set_flags(route, rtm->rtm_flags);
-
- if (tb[RTA_DST]) {
- dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family);
- if (dst == NULL)
- goto errout_errno;
- } else {
- dst = nl_addr_alloc(0);
- nl_addr_set_family(dst, rtm->rtm_family);
- }
-
- nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
- err = rtnl_route_set_dst(route, dst);
- if (err < 0)
- goto errout;
-
- nl_addr_put(dst);
-
- if (tb[RTA_SRC]) {
- src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family);
- if (src == NULL)
- goto errout_errno;
- } else if (rtm->rtm_src_len)
- src = nl_addr_alloc(0);
-
- if (src) {
- nl_addr_set_prefixlen(src, rtm->rtm_src_len);
- rtnl_route_set_src(route, src);
- nl_addr_put(src);
- }
-
- if (tb[RTA_IIF])
- rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF]));
-
- if (tb[RTA_OIF])
- rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF]));
-
- if (tb[RTA_GATEWAY]) {
- addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family);
- if (addr == NULL)
- goto errout_errno;
- rtnl_route_set_gateway(route, addr);
- nl_addr_put(addr);
- }
-
- if (tb[RTA_PRIORITY])
- rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY]));
-
- if (tb[RTA_PREFSRC]) {
- addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family);
- if (addr == NULL)
- goto errout_errno;
- rtnl_route_set_pref_src(route, addr);
- nl_addr_put(addr);
- }
-
- if (tb[RTA_METRICS]) {
- struct nlattr *mtb[RTAX_MAX + 1];
- int i;
-
- err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
- if (err < 0)
- goto errout;
-
- for (i = 1; i <= RTAX_MAX; i++) {
- if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
- uint32_t m = nla_get_u32(mtb[i]);
- if (rtnl_route_set_metric(route, i, m) < 0)
- goto errout_errno;
- }
- }
- }
-
- if (tb[RTA_MULTIPATH]) {
- struct rtnl_nexthop *nh;
- struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]);
- size_t tlen = nla_len(tb[RTA_MULTIPATH]);
-
- while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
- nh = rtnl_route_nh_alloc();
- if (!nh)
- goto errout;
-
- rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
- rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
- rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
-
- if (rtnh->rtnh_len > sizeof(*rtnh)) {
- struct nlattr *ntb[RTA_MAX + 1];
- nla_parse(ntb, RTA_MAX, (struct nlattr *)
- RTNH_DATA(rtnh),
- rtnh->rtnh_len - sizeof(*rtnh),
- route_policy);
-
- if (ntb[RTA_GATEWAY]) {
- nh->rtnh_gateway = nla_get_addr(
- ntb[RTA_GATEWAY],
- route->rt_family);
- nh->rtnh_mask = NEXTHOP_HAS_GATEWAY;
- }
- }
-
- rtnl_route_add_nexthop(route, nh);
- tlen -= RTNH_ALIGN(rtnh->rtnh_len);
- rtnh = RTNH_NEXT(rtnh);
- }
- }
-
- if (tb[RTA_FLOW])
- rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW]));
-
- if (tb[RTA_CACHEINFO])
- copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route);
-
- if (tb[RTA_MP_ALGO])
- rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO]));
+ if ((err = rtnl_route_parse(nlh, &route)) < 0)
+ return err;
err = pp->pp_cb((struct nl_object *) route, pp);
- if (err < 0)
- goto errout;
-
- err = P_ACCEPT;
-errout:
rtnl_route_put(route);
return err;
-
-errout_errno:
- err = nl_get_errno();
- goto errout;
}
-static int route_request_update(struct nl_cache *c, struct nl_handle *h)
+static int route_request_update(struct nl_cache *c, struct nl_sock *h)
{
- return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP);
+ struct rtmsg rhdr = {
+ .rtm_family = c->c_iarg1,
+ };
+
+ if (c->c_iarg2 & ROUTE_CACHE_CONTENT)
+ rhdr.rtm_flags |= RTM_F_CLONED;
+
+ return nl_send_simple(h, RTM_GETROUTE, NLM_F_DUMP, &rhdr, sizeof(rhdr));
}
/**
@@ -229,7 +61,9 @@ static int route_request_update(struct nl_cache *c, struct nl_handle *h)
/**
* Build a route cache holding all routes currently configured in the kernel
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
+ * @arg family Address family of routes to cover or AF_UNSPEC
+ * @arg flags Flags
*
* Allocates a new cache, initializes it properly and updates it to
* contain all routes currently configured in the kernel.
@@ -238,20 +72,25 @@ static int route_request_update(struct nl_cache *c, struct nl_handle *h)
* cache after using it.
* @return The cache or NULL if an error has occured.
*/
-struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle)
+int rtnl_route_alloc_cache(struct nl_sock *sk, int family, int flags,
+ struct nl_cache **result)
{
struct nl_cache *cache;
+ int err;
- cache = nl_cache_alloc(&rtnl_route_ops);
- if (!cache)
- return NULL;
+ if (!(cache = nl_cache_alloc(&rtnl_route_ops)))
+ return -NLE_NOMEM;
- if (handle && nl_cache_refill(handle, cache) < 0) {
+ cache->c_iarg1 = family;
+ cache->c_iarg2 = flags;
+
+ if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
free(cache);
- return NULL;
+ return err;
}
- return cache;
+ *result = cache;
+ return 0;
}
/** @} */
@@ -261,152 +100,67 @@ struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle)
* @{
*/
-static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
- int flags)
+static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags,
+ struct nl_msg **result)
{
struct nl_msg *msg;
- struct nl_addr *addr;
- int scope, i, oif, nmetrics = 0;
- struct nlattr *metrics;
- struct rtmsg rtmsg = {
- .rtm_family = rtnl_route_get_family(tmpl),
- .rtm_dst_len = rtnl_route_get_dst_len(tmpl),
- .rtm_src_len = rtnl_route_get_src_len(tmpl),
- .rtm_tos = rtnl_route_get_tos(tmpl),
- .rtm_table = rtnl_route_get_table(tmpl),
- .rtm_type = rtnl_route_get_type(tmpl),
- .rtm_protocol = rtnl_route_get_protocol(tmpl),
- .rtm_flags = rtnl_route_get_flags(tmpl),
- };
-
- if (rtmsg.rtm_family == AF_UNSPEC) {
- nl_error(EINVAL, "Cannot build route message, address " \
- "family is unknown.");
- return NULL;
- }
-
- scope = rtnl_route_get_scope(tmpl);
- if (scope == RT_SCOPE_NOWHERE) {
- if (rtmsg.rtm_type == RTN_LOCAL)
- scope = RT_SCOPE_HOST;
- else {
- /* XXX Change to UNIVERSE if gw || nexthops */
- scope = RT_SCOPE_LINK;
- }
- }
-
- rtmsg.rtm_scope = scope;
-
- msg = nlmsg_alloc_simple(cmd, flags);
- if (msg == NULL)
- return NULL;
-
- if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
- goto nla_put_failure;
-
- addr = rtnl_route_get_dst(tmpl);
- if (addr)
- NLA_PUT_ADDR(msg, RTA_DST, addr);
-
- addr = rtnl_route_get_src(tmpl);
- if (addr)
- NLA_PUT_ADDR(msg, RTA_SRC, addr);
-
- addr = rtnl_route_get_gateway(tmpl);
- if (addr)
- NLA_PUT_ADDR(msg, RTA_GATEWAY, addr);
-
- addr = rtnl_route_get_pref_src(tmpl);
- if (addr)
- NLA_PUT_ADDR(msg, RTA_PREFSRC, addr);
-
- NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl));
-
- oif = rtnl_route_get_oif(tmpl);
- if (oif != RTNL_LINK_NOT_FOUND)
- NLA_PUT_U32(msg, RTA_OIF, oif);
-
- for (i = 1; i <= RTAX_MAX; i++)
- if (rtnl_route_get_metric(tmpl, i) != UINT_MAX)
- nmetrics++;
-
- if (nmetrics > 0) {
- unsigned int val;
-
- metrics = nla_nest_start(msg, RTA_METRICS);
- if (metrics == NULL)
- goto nla_put_failure;
+ int err;
- for (i = 1; i <= RTAX_MAX; i++) {
- val = rtnl_route_get_metric(tmpl, i);
- if (val != UINT_MAX)
- NLA_PUT_U32(msg, i, val);
- }
+ if (!(msg = nlmsg_alloc_simple(cmd, flags)))
+ return -NLE_NOMEM;
- nla_nest_end(msg, metrics);
+ if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) {
+ nlmsg_free(msg);
+ return err;
}
-#if 0
- RTA_IIF,
- RTA_MULTIPATH,
- RTA_PROTOINFO,
- RTA_FLOW,
- RTA_CACHEINFO,
- RTA_SESSION,
- RTA_MP_ALGO,
-#endif
-
- return msg;
-
-nla_put_failure:
- nlmsg_free(msg);
- return NULL;
+ *result = msg;
+ return 0;
}
-struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
+int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags,
+ struct nl_msg **result)
{
- return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags);
+ return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags,
+ result);
}
-int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route,
- int flags)
+int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags)
{
struct nl_msg *msg;
int err;
- msg = rtnl_route_build_add_request(route, flags);
- if (!msg)
- return nl_get_errno();
+ if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
nlmsg_free(msg);
if (err < 0)
return err;
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
-struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags)
+int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags,
+ struct nl_msg **result)
{
- return build_route_msg(tmpl, RTM_DELROUTE, flags);
+ return build_route_msg(tmpl, RTM_DELROUTE, flags, result);
}
-int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route,
- int flags)
+int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags)
{
struct nl_msg *msg;
int err;
- msg = rtnl_route_build_del_request(route, flags);
- if (!msg)
- return nl_get_errno();
+ if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
nlmsg_free(msg);
if (err < 0)
return err;
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
index 78e7712..7f26bfd 100644
--- a/lib/route/route_obj.c
+++ b/lib/route/route_obj.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>
*/
/**
@@ -20,14 +20,11 @@
* routing table RT_TABLE_MAIN
* scope RT_SCOPE_NOWHERE
* tos 0
- * realms 0
* protocol RTPROT_STATIC
* prio 0
* family AF_UNSPEC
* type RTN_UNICAST
- * oif RTNL_LINK_NOT_FOUND
* iif NULL
- * mpalgo IP_MP_ALG_NONE
* @endcode
*
* @{
@@ -41,6 +38,7 @@
#include <netlink/route/rtnl.h>
#include <netlink/route/route.h>
#include <netlink/route/link.h>
+#include <netlink/route/nexthop.h>
/** @cond SKIP */
#define ROUTE_ATTR_FAMILY 0x000001
@@ -61,15 +59,18 @@
#define ROUTE_ATTR_MULTIPATH 0x008000
#define ROUTE_ATTR_REALMS 0x010000
#define ROUTE_ATTR_CACHEINFO 0x020000
-#define ROUTE_ATTR_MP_ALGO 0x040000
/** @endcond */
-static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p);
-
static void route_constructor(struct nl_object *c)
{
struct rtnl_route *r = (struct rtnl_route *) c;
+ r->rt_family = AF_UNSPEC;
+ r->rt_scope = RT_SCOPE_NOWHERE;
+ r->rt_table = RT_TABLE_MAIN;
+ r->rt_protocol = RTPROT_STATIC;
+ r->rt_type = RTN_UNICAST;
+
nl_init_list_head(&r->rt_nexthops);
}
@@ -83,11 +84,10 @@ static void route_free_data(struct nl_object *c)
nl_addr_put(r->rt_dst);
nl_addr_put(r->rt_src);
- nl_addr_put(r->rt_gateway);
nl_addr_put(r->rt_pref_src);
nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
- rtnl_route_remove_nexthop(nh);
+ rtnl_route_remove_nexthop(r, nh);
rtnl_route_nh_free(nh);
}
}
@@ -100,366 +100,258 @@ static int route_clone(struct nl_object *_dst, struct nl_object *_src)
if (src->rt_dst)
if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
- goto errout;
+ return -NLE_NOMEM;
if (src->rt_src)
if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
- goto errout;
+ return -NLE_NOMEM;
- if (src->rt_gateway)
- if (!(dst->rt_gateway = nl_addr_clone(src->rt_gateway)))
- goto errout;
-
if (src->rt_pref_src)
if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
- goto errout;
+ return -NLE_NOMEM;
nl_init_list_head(&dst->rt_nexthops);
nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
new = rtnl_route_nh_clone(nh);
if (!new)
- goto errout;
+ return -NLE_NOMEM;
rtnl_route_add_nexthop(dst, new);
}
return 0;
-errout:
- return nl_get_errno();
}
-static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p)
+static void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
{
struct rtnl_route *r = (struct rtnl_route *) a;
struct nl_cache *link_cache;
+ int cache = 0, flags;
char buf[64];
link_cache = nl_cache_mngt_require("route/link");
+ if (r->rt_flags & RTM_F_CLONED)
+ cache = 1;
+
+ nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf)));
+
+ if (cache)
+ nl_dump(p, "cache ");
+
if (!(r->ce_mask & ROUTE_ATTR_DST) ||
nl_addr_get_len(r->rt_dst) == 0)
- dp_dump(p, "default ");
+ nl_dump(p, "default ");
else
- dp_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
+ nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
- if (r->ce_mask & ROUTE_ATTR_OIF) {
- if (link_cache)
- dp_dump(p, "dev %s ",
- rtnl_link_i2name(link_cache, r->rt_oif,
- buf, sizeof(buf)));
- else
- dp_dump(p, "dev %d ", r->rt_oif);
- }
+ if (r->ce_mask & ROUTE_ATTR_TABLE && !cache)
+ nl_dump(p, "table %s ",
+ rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
- if (r->ce_mask & ROUTE_ATTR_GATEWAY)
- dp_dump(p, "via %s ", nl_addr2str(r->rt_gateway, buf,
- sizeof(buf)));
- else if (r->ce_mask & ROUTE_ATTR_MULTIPATH)
- dp_dump(p, "via nexthops ");
+ if (r->ce_mask & ROUTE_ATTR_TYPE)
+ nl_dump(p, "type %s ",
+ nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
- if (r->ce_mask & ROUTE_ATTR_SCOPE)
- dp_dump(p, "scope %s ",
- rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
+ if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0)
+ nl_dump(p, "tos %#x ", r->rt_tos);
- if (r->ce_mask & ROUTE_ATTR_FLAGS && r->rt_flags) {
- int flags = r->rt_flags;
+ if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+ struct rtnl_nexthop *nh;
+
+ nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+ p->dp_ivar = NH_DUMP_FROM_ONELINE;
+ rtnl_route_nh_dump(nh, p);
+ }
+ }
+
+ flags = r->rt_flags & ~(RTM_F_CLONED);
+ if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) {
+
+ nl_dump(p, "<");
- dp_dump(p, "<");
-
#define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
- flags &= ~RTNH_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
+ flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
PRINT_FLAG(DEAD);
PRINT_FLAG(ONLINK);
PRINT_FLAG(PERVASIVE);
#undef PRINT_FLAG
#define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
- flags &= ~RTM_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
+ flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
PRINT_FLAG(NOTIFY);
- PRINT_FLAG(CLONED);
PRINT_FLAG(EQUALIZE);
PRINT_FLAG(PREFIX);
#undef PRINT_FLAG
- dp_dump(p, ">");
- }
+#define PRINT_FLAG(f) if (flags & RTCF_##f) { \
+ flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+ PRINT_FLAG(NOTIFY);
+ PRINT_FLAG(REDIRECTED);
+ PRINT_FLAG(DOREDIRECT);
+ PRINT_FLAG(DIRECTSRC);
+ PRINT_FLAG(DNAT);
+ PRINT_FLAG(BROADCAST);
+ PRINT_FLAG(MULTICAST);
+ PRINT_FLAG(LOCAL);
+#undef PRINT_FLAG
- dp_dump(p, "\n");
+ nl_dump(p, ">");
+ }
- return 1;
+ nl_dump(p, "\n");
}
-static int route_dump_full(struct nl_object *a, struct nl_dump_params *p)
+static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
{
struct rtnl_route *r = (struct rtnl_route *) a;
struct nl_cache *link_cache;
char buf[128];
- int i, line;
+ int i;
link_cache = nl_cache_mngt_require("route/link");
- line = route_dump_brief(a, p);
- if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
- struct rtnl_nexthop *nh;
-
- nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
- dp_dump_line(p, line++, " via ");
-
- if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY)
- dp_dump(p, "%s ",
- nl_addr2str(nh->rtnh_gateway,
- buf, sizeof(buf)));
- if (link_cache) {
- dp_dump(p, "dev %s ",
- rtnl_link_i2name(link_cache,
- nh->rtnh_ifindex,
- buf, sizeof(buf)));
- } else
- dp_dump(p, "dev %d ", nh->rtnh_ifindex);
-
- dp_dump(p, "weight %u <%s>\n", nh->rtnh_weight,
- rtnl_route_nh_flags2str(nh->rtnh_flags,
- buf, sizeof(buf)));
- }
- }
-
- dp_dump_line(p, line++, " ");
+ route_dump_line(a, p);
+ nl_dump_line(p, " ");
if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
- dp_dump(p, "preferred-src %s ",
+ nl_dump(p, "preferred-src %s ",
nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
- if (r->ce_mask & ROUTE_ATTR_TABLE)
- dp_dump(p, "table %s ",
- rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
-
- if (r->ce_mask & ROUTE_ATTR_TYPE)
- dp_dump(p, "type %s ",
- nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
+ if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE)
+ nl_dump(p, "scope %s ",
+ rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
if (r->ce_mask & ROUTE_ATTR_PRIO)
- dp_dump(p, "metric %#x ", r->rt_prio);
-
- if (r->ce_mask & ROUTE_ATTR_FAMILY)
- dp_dump(p, "family %s ",
- nl_af2str(r->rt_family, buf, sizeof(buf)));
+ nl_dump(p, "priority %#x ", r->rt_prio);
if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
- dp_dump(p, "protocol %s ",
+ nl_dump(p, "protocol %s ",
rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
- dp_dump(p, "\n");
-
- if ((r->ce_mask & (ROUTE_ATTR_IIF | ROUTE_ATTR_SRC | ROUTE_ATTR_TOS |
- ROUTE_ATTR_REALMS)) ||
- ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
- r->rt_cacheinfo.rtci_error)) {
- dp_dump_line(p, line++, " ");
-
- if (r->ce_mask & ROUTE_ATTR_IIF)
- dp_dump(p, "iif %s ", r->rt_iif);
+ if (r->ce_mask & ROUTE_ATTR_IIF) {
+ if (link_cache) {
+ nl_dump(p, "iif %s ",
+ rtnl_link_i2name(link_cache, r->rt_iif,
+ buf, sizeof(buf)));
+ } else
+ nl_dump(p, "iif %d ", r->rt_iif);
+ }
- if (r->ce_mask & ROUTE_ATTR_SRC)
- dp_dump(p, "src %s ",
- nl_addr2str(r->rt_src, buf, sizeof(buf)));
+ if (r->ce_mask & ROUTE_ATTR_SRC)
+ nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
- if (r->ce_mask & ROUTE_ATTR_TOS)
- dp_dump(p, "tos %#x ", r->rt_tos);
+ nl_dump(p, "\n");
- if (r->ce_mask & ROUTE_ATTR_REALMS)
- dp_dump(p, "realm %04x:%04x ",
- RTNL_REALM_FROM(r->rt_realms),
- RTNL_REALM_TO(r->rt_realms));
+ if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+ struct rtnl_nexthop *nh;
- if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
- r->rt_cacheinfo.rtci_error)
- dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error,
- strerror(-r->rt_cacheinfo.rtci_error));
+ nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+ nl_dump_line(p, " ");
+ p->dp_ivar = NH_DUMP_FROM_DETAILS;
+ rtnl_route_nh_dump(nh, p);
+ nl_dump(p, "\n");
+ }
+ }
- dp_dump(p, "\n");
+ if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
+ nl_dump_line(p, " cacheinfo error %d (%s)\n",
+ r->rt_cacheinfo.rtci_error,
+ strerror(-r->rt_cacheinfo.rtci_error));
}
if (r->ce_mask & ROUTE_ATTR_METRICS) {
- dp_dump_line(p, line++, " ");
+ nl_dump_line(p, " metrics [");
for (i = 0; i < RTAX_MAX; i++)
if (r->rt_metrics_mask & (1 << i))
- dp_dump(p, "%s %u ",
+ nl_dump(p, "%s %u ",
rtnl_route_metric2str(i+1,
buf, sizeof(buf)),
r->rt_metrics[i]);
- dp_dump(p, "\n");
+ nl_dump(p, "]\n");
}
-
- return line;
}
-static int route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_route *route = (struct rtnl_route *) obj;
- int line;
- line = route_dump_full(obj, p);
+ route_dump_details(obj, p);
if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
- dp_dump_line(p, line++, " used %u refcnt %u ",
- ci->rtci_used, ci->rtci_clntref);
- dp_dump_line(p, line++, "last-use %us expires %us\n",
+
+ nl_dump_line(p, " used %u refcnt %u last-use %us "
+ "expires %us\n",
+ ci->rtci_used, ci->rtci_clntref,
ci->rtci_last_use / nl_get_hz(),
ci->rtci_expires / nl_get_hz());
}
-
- return line;
}
-static int route_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
+static void route_dump_env(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_route *route = (struct rtnl_route *) obj;
+ struct nl_cache *link_cache;
char buf[128];
- int line = 0;
-
- dp_dump_line(p, line++, "<route>\n");
- dp_dump_line(p, line++, " <family>%s</family>\n",
+
+ link_cache = nl_cache_mngt_require("route/link");
+
+ nl_dump_line(p, "ROUTE_FAMILY=%s\n",
nl_af2str(route->rt_family, buf, sizeof(buf)));
if (route->ce_mask & ROUTE_ATTR_DST)
- dp_dump_line(p, line++, " <dst>%s</dst>\n",
+ nl_dump_line(p, "ROUTE_DST=%s\n",
nl_addr2str(route->rt_dst, buf, sizeof(buf)));
if (route->ce_mask & ROUTE_ATTR_SRC)
- dp_dump_line(p, line++, " <src>%s</src>\n",
+ nl_dump_line(p, "ROUTE_SRC=%s\n",
nl_addr2str(route->rt_src, buf, sizeof(buf)));
- if (route->ce_mask & ROUTE_ATTR_GATEWAY)
- dp_dump_line(p, line++, " <gateway>%s</gateway>\n",
- nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
-
if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
- dp_dump_line(p, line++, " <prefsrc>%s</prefsrc>\n",
+ nl_dump_line(p, "ROUTE_PREFSRC=%s\n",
nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
- if (route->ce_mask & ROUTE_ATTR_IIF)
- dp_dump_line(p, line++, " <iif>%s</iif>\n", route->rt_iif);
-
- if (route->ce_mask & ROUTE_ATTR_REALMS)
- dp_dump_line(p, line++, " <realms>%u</realms>\n",
- route->rt_realms);
+ if (route->ce_mask & ROUTE_ATTR_IIF) {
+ if (link_cache) {
+ nl_dump_line(p, "ROUTE_IIF=%s",
+ rtnl_link_i2name(link_cache, route->rt_iif,
+ buf, sizeof(buf)));
+ } else
+ nl_dump_line(p, "ROUTE_IIF=%d", route->rt_iif);
+ }
if (route->ce_mask & ROUTE_ATTR_TOS)
- dp_dump_line(p, line++, " <tos>%u</tos>\n", route->rt_tos);
+ nl_dump_line(p, "ROUTE_TOS=%u\n", route->rt_tos);
if (route->ce_mask & ROUTE_ATTR_TABLE)
- dp_dump_line(p, line++, " <table>%u</table>\n",
+ nl_dump_line(p, "ROUTE_TABLE=%u\n",
route->rt_table);
if (route->ce_mask & ROUTE_ATTR_SCOPE)
- dp_dump_line(p, line++, " <scope>%s</scope>\n",
+ nl_dump_line(p, "ROUTE_SCOPE=%s\n",
rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
if (route->ce_mask & ROUTE_ATTR_PRIO)
- dp_dump_line(p, line++, " <metric>%u</metric>\n",
+ nl_dump_line(p, "ROUTE_PRIORITY=%u\n",
route->rt_prio);
- if (route->ce_mask & ROUTE_ATTR_OIF) {
- struct nl_cache *link_cache;
-
- link_cache = nl_cache_mngt_require("route/link");
- if (link_cache)
- dp_dump_line(p, line++, " <oif>%s</oif>\n",
- rtnl_link_i2name(link_cache,
- route->rt_oif,
- buf, sizeof(buf)));
- else
- dp_dump_line(p, line++, " <oif>%u</oif>\n",
- route->rt_oif);
- }
-
if (route->ce_mask & ROUTE_ATTR_TYPE)
- dp_dump_line(p, line++, " <type>%s</type>\n",
+ nl_dump_line(p, "ROUTE_TYPE=%s\n",
nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
- dp_dump_line(p, line++, "</route>\n");
-
-#if 0
- uint8_t rt_protocol;
- uint32_t rt_flags;
- uint32_t rt_metrics[RTAX_MAX];
- uint32_t rt_metrics_mask;
- struct rtnl_nexthop * rt_nexthops;
- struct rtnl_rtcacheinfo rt_cacheinfo;
- uint32_t rt_mp_algo;
-
-#endif
-
- return line;
-}
-
-static int route_dump_env(struct nl_object *obj, struct nl_dump_params *p)
-{
- struct rtnl_route *route = (struct rtnl_route *) obj;
- char buf[128];
- int line = 0;
-
- dp_dump_line(p, line++, "ROUTE_FAMILY=%s\n",
- nl_af2str(route->rt_family, buf, sizeof(buf)));
-
- if (route->ce_mask & ROUTE_ATTR_DST)
- dp_dump_line(p, line++, "ROUTE_DST=%s\n",
- nl_addr2str(route->rt_dst, buf, sizeof(buf)));
-
- if (route->ce_mask & ROUTE_ATTR_SRC)
- dp_dump_line(p, line++, "ROUTE_SRC=%s\n",
- nl_addr2str(route->rt_src, buf, sizeof(buf)));
-
- if (route->ce_mask & ROUTE_ATTR_GATEWAY)
- dp_dump_line(p, line++, "ROUTE_GATEWAY=%s\n",
- nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
-
- if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
- dp_dump_line(p, line++, "ROUTE_PREFSRC=%s\n",
- nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
-
- if (route->ce_mask & ROUTE_ATTR_IIF)
- dp_dump_line(p, line++, "ROUTE_IIF=%s\n", route->rt_iif);
-
- if (route->ce_mask & ROUTE_ATTR_REALMS)
- dp_dump_line(p, line++, "ROUTE_REALM=%u\n",
- route->rt_realms);
-
- if (route->ce_mask & ROUTE_ATTR_TOS)
- dp_dump_line(p, line++, "ROUTE_TOS=%u\n", route->rt_tos);
-
- if (route->ce_mask & ROUTE_ATTR_TABLE)
- dp_dump_line(p, line++, "ROUTE_TABLE=%u\n",
- route->rt_table);
-
- if (route->ce_mask & ROUTE_ATTR_SCOPE)
- dp_dump_line(p, line++, "ROUTE_SCOPE=%s\n",
- rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
-
- if (route->ce_mask & ROUTE_ATTR_PRIO)
- dp_dump_line(p, line++, "ROUTE_METRIC=%u\n",
- route->rt_prio);
-
- if (route->ce_mask & ROUTE_ATTR_OIF) {
- struct nl_cache *link_cache;
+ if (route->ce_mask & ROUTE_ATTR_MULTIPATH) {
+ struct rtnl_nexthop *nh;
+ int index = 1;
- dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n",
- route->rt_oif);
+ if (route->rt_nr_nh > 0)
+ nl_dump_line(p, "ROUTE_NR_NH=%u\n", route->rt_nr_nh);
- link_cache = nl_cache_mngt_require("route/link");
- if (link_cache)
- dp_dump_line(p, line++, "ROUTE_OIF_IFNAME=%s\n",
- rtnl_link_i2name(link_cache,
- route->rt_oif,
- buf, sizeof(buf)));
+ nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
+ p->dp_ivar = index++;
+ rtnl_route_nh_dump(nh, p);
+ }
}
-
- if (route->ce_mask & ROUTE_ATTR_TYPE)
- dp_dump_line(p, line++, "ROUTE_TYPE=%s\n",
- nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
-
- return line;
}
static int route_compare(struct nl_object *_a, struct nl_object *_b,
@@ -467,7 +359,8 @@ static int route_compare(struct nl_object *_a, struct nl_object *_b,
{
struct rtnl_route *a = (struct rtnl_route *) _a;
struct rtnl_route *b = (struct rtnl_route *) _b;
- int diff = 0;
+ struct rtnl_nexthop *nh_a, *nh_b;
+ int i, diff = 0, found;
#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
@@ -477,29 +370,89 @@ static int route_compare(struct nl_object *_a, struct nl_object *_b,
diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol);
diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope);
diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type);
- diff |= ROUTE_DIFF(OIF, a->rt_oif != b->rt_oif);
diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio);
- diff |= ROUTE_DIFF(REALMS, a->rt_realms != b->rt_realms);
- diff |= ROUTE_DIFF(MP_ALGO, a->rt_mp_algo != b->rt_mp_algo);
diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst));
diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src));
- diff |= ROUTE_DIFF(IIF, strcmp(a->rt_iif, b->rt_iif));
+ diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif);
diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src,
b->rt_pref_src));
- diff |= ROUTE_DIFF(GATEWAY, nl_addr_cmp(a->rt_gateway,
- b->rt_gateway));
- /* FIXME: Compare metrics, multipath config */
+ if (flags & LOOSE_COMPARISON) {
+ nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
+ found = 0;
+ nl_list_for_each_entry(nh_a, &a->rt_nexthops,
+ rtnh_list) {
+ if (!rtnl_route_nh_compare(nh_a, nh_b,
+ nh_b->ce_mask, 1)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ goto nh_mismatch;
+ }
+
+ for (i = 0; i < RTAX_MAX - 1; i++) {
+ if (a->rt_metrics_mask & (1 << i) &&
+ (!(b->rt_metrics_mask & (1 << i)) ||
+ a->rt_metrics[i] != b->rt_metrics[i]))
+ ROUTE_DIFF(METRICS, 1);
+ }
- if (flags & LOOSE_FLAG_COMPARISON)
diff |= ROUTE_DIFF(FLAGS,
(a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
- else
+ } else {
+ if (a->rt_nr_nh != a->rt_nr_nh)
+ goto nh_mismatch;
+
+ /* search for a dup in each nh of a */
+ nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) {
+ found = 0;
+ nl_list_for_each_entry(nh_b, &b->rt_nexthops,
+ rtnh_list) {
+ if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0))
+ found = 1;
+ break;
+ }
+ if (!found)
+ goto nh_mismatch;
+ }
+
+ /* search for a dup in each nh of b, covers case where a has
+ * dupes itself */
+ nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
+ found = 0;
+ nl_list_for_each_entry(nh_a, &a->rt_nexthops,
+ rtnh_list) {
+ if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0))
+ found = 1;
+ break;
+ }
+ if (!found)
+ goto nh_mismatch;
+ }
+
+ for (i = 0; i < RTAX_MAX - 1; i++) {
+ if ((a->rt_metrics_mask & (1 << i)) ^
+ (b->rt_metrics_mask & (1 << i)))
+ diff |= ROUTE_DIFF(METRICS, 1);
+ else
+ diff |= ROUTE_DIFF(METRICS,
+ a->rt_metrics[i] != b->rt_metrics[i]);
+ }
+
diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
-
-#undef ROUTE_DIFF
+ }
+out:
return diff;
+
+nh_mismatch:
+ diff |= ROUTE_DIFF(MULTIPATH, 1);
+ goto out;
+
+#undef ROUTE_DIFF
}
static struct trans_tbl route_attrs[] = {
@@ -521,7 +474,6 @@ static struct trans_tbl route_attrs[] = {
__ADD(ROUTE_ATTR_MULTIPATH, multipath)
__ADD(ROUTE_ATTR_REALMS, realms)
__ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
- __ADD(ROUTE_ATTR_MP_ALGO, mp_algo)
};
static char *route_attrs2str(int attrs, char *buf, size_t len)
@@ -557,100 +509,82 @@ void rtnl_route_put(struct rtnl_route *route)
* @{
*/
-void rtnl_route_set_table(struct rtnl_route *route, int table)
+void rtnl_route_set_table(struct rtnl_route *route, uint32_t table)
{
route->rt_table = table;
route->ce_mask |= ROUTE_ATTR_TABLE;
}
-int rtnl_route_get_table(struct rtnl_route *route)
+uint32_t rtnl_route_get_table(struct rtnl_route *route)
{
- if (route->ce_mask & ROUTE_ATTR_TABLE)
- return route->rt_table;
- else
- return RT_TABLE_MAIN;
+ return route->rt_table;
}
-void rtnl_route_set_scope(struct rtnl_route *route, int scope)
+void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope)
{
route->rt_scope = scope;
route->ce_mask |= ROUTE_ATTR_SCOPE;
}
-int rtnl_route_get_scope(struct rtnl_route *route)
+uint8_t rtnl_route_get_scope(struct rtnl_route *route)
{
- if (route->ce_mask & ROUTE_ATTR_SCOPE)
- return route->rt_scope;
- else
- return RT_SCOPE_NOWHERE;
+ return route->rt_scope;
}
-void rtnl_route_set_tos(struct rtnl_route *route, int tos)
+void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos)
{
route->rt_tos = tos;
route->ce_mask |= ROUTE_ATTR_TOS;
}
-int rtnl_route_get_tos(struct rtnl_route *route)
+uint8_t rtnl_route_get_tos(struct rtnl_route *route)
{
return route->rt_tos;
}
-void rtnl_route_set_realms(struct rtnl_route *route, realm_t realms)
-{
- route->rt_realms = realms;
- route->ce_mask |= ROUTE_ATTR_REALMS;
-}
-
-realm_t rtnl_route_get_realms(struct rtnl_route *route)
+void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol)
{
- return route->rt_realms;
-}
-
-void rtnl_route_set_protocol(struct rtnl_route *route, int proto)
-{
- route->rt_protocol = proto;
+ route->rt_protocol = protocol;
route->ce_mask |= ROUTE_ATTR_PROTOCOL;
}
-int rtnl_route_get_protocol(struct rtnl_route *route)
+uint8_t rtnl_route_get_protocol(struct rtnl_route *route)
{
- if (route->ce_mask & ROUTE_ATTR_PROTOCOL)
- return route->rt_protocol;
- else
- return RTPROT_STATIC;
+ return route->rt_protocol;
}
-void rtnl_route_set_prio(struct rtnl_route *route, int prio)
+void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio)
{
route->rt_prio = prio;
route->ce_mask |= ROUTE_ATTR_PRIO;
}
-int rtnl_route_get_prio(struct rtnl_route *route)
+uint32_t rtnl_route_get_priority(struct rtnl_route *route)
{
return route->rt_prio;
}
-void rtnl_route_set_family(struct rtnl_route *route, int family)
+int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
{
+ if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
+ return -NLE_AF_NOSUPPORT;
+
route->rt_family = family;
route->ce_mask |= ROUTE_ATTR_FAMILY;
+
+ return 0;
}
-int rtnl_route_get_family(struct rtnl_route *route)
+uint8_t rtnl_route_get_family(struct rtnl_route *route)
{
- if (route->ce_mask & ROUTE_ATTR_FAMILY)
- return route->rt_family;
- else
- return AF_UNSPEC;
+ return route->rt_family;
}
int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
{
if (route->ce_mask & ROUTE_ATTR_FAMILY) {
if (addr->a_family != route->rt_family)
- return nl_error(EINVAL, "Address family mismatch");
+ return -NLE_AF_MISMATCH;
} else
route->rt_family = addr->a_family;
@@ -670,19 +604,14 @@ struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
return route->rt_dst;
}
-int rtnl_route_get_dst_len(struct rtnl_route *route)
-{
- if (route->ce_mask & ROUTE_ATTR_DST)
- return nl_addr_get_prefixlen(route->rt_dst);
- else
- return 0;
-}
-
int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
{
+ if (addr->a_family == AF_INET)
+ return -NLE_SRCRT_NOSUPPORT;
+
if (route->ce_mask & ROUTE_ATTR_FAMILY) {
if (addr->a_family != route->rt_family)
- return nl_error(EINVAL, "Address family mismatch");
+ return -NLE_AF_MISMATCH;
} else
route->rt_family = addr->a_family;
@@ -701,66 +630,37 @@ struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
return route->rt_src;
}
-int rtnl_route_get_src_len(struct rtnl_route *route)
+int rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
{
- if (route->ce_mask & ROUTE_ATTR_SRC)
- return nl_addr_get_prefixlen(route->rt_src);
- else
- return 0;
-}
-
-int rtnl_route_set_gateway(struct rtnl_route *route, struct nl_addr *addr)
-{
- if (route->ce_mask & ROUTE_ATTR_FAMILY) {
- if (addr->a_family != route->rt_family)
- return nl_error(EINVAL, "Address family mismatch");
- } else
- route->rt_family = addr->a_family;
+ if (type > RTN_MAX)
+ return -NLE_RANGE;
- if (route->rt_gateway)
- nl_addr_put(route->rt_gateway);
-
- nl_addr_get(addr);
- route->rt_gateway = addr;
- route->ce_mask |= (ROUTE_ATTR_GATEWAY | ROUTE_ATTR_FAMILY);
-
- return 0;
-}
-
-struct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route)
-{
- return route->rt_gateway;
-}
-
-void rtnl_route_set_type(struct rtnl_route *route, int type)
-{
route->rt_type = type;
route->ce_mask |= ROUTE_ATTR_TYPE;
+
+ return 0;
}
-int rtnl_route_get_type(struct rtnl_route *route)
+uint8_t rtnl_route_get_type(struct rtnl_route *route)
{
- if (route->ce_mask & ROUTE_ATTR_TYPE)
- return route->rt_type;
- else
- return RTN_UNICAST;
+ return route->rt_type;
}
-void rtnl_route_set_flags(struct rtnl_route *route, unsigned int flags)
+void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags)
{
route->rt_flag_mask |= flags;
route->rt_flags |= flags;
route->ce_mask |= ROUTE_ATTR_FLAGS;
}
-void rtnl_route_unset_flags(struct rtnl_route *route, unsigned int flags)
+void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags)
{
route->rt_flag_mask |= flags;
route->rt_flags &= ~flags;
route->ce_mask |= ROUTE_ATTR_FLAGS;
}
-unsigned int rtnl_route_get_flags(struct rtnl_route *route)
+uint32_t rtnl_route_get_flags(struct rtnl_route *route)
{
return route->rt_flags;
}
@@ -768,11 +668,16 @@ unsigned int rtnl_route_get_flags(struct rtnl_route *route)
int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
{
if (metric > RTAX_MAX || metric < 1)
- return nl_error(EINVAL, "Metric out of range (1..%d)",
- RTAX_MAX);
+ return -NLE_RANGE;
route->rt_metrics[metric - 1] = value;
- route->rt_metrics_mask |= (1 << (metric - 1));
+
+ if (!(route->rt_metrics_mask & (1 << (metric - 1)))) {
+ route->rt_nmetrics++;
+ route->rt_metrics_mask |= (1 << (metric - 1));
+ }
+
+ route->ce_mask |= ROUTE_ATTR_METRICS;
return 0;
}
@@ -780,30 +685,35 @@ int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
{
if (metric > RTAX_MAX || metric < 1)
- return nl_error(EINVAL, "Metric out of range (1..%d)",
- RTAX_MAX);
+ return -NLE_RANGE;
- route->rt_metrics_mask &= ~(1 << (metric - 1));
+ if (route->rt_metrics_mask & (1 << (metric - 1))) {
+ route->rt_nmetrics--;
+ route->rt_metrics_mask &= ~(1 << (metric - 1));
+ }
return 0;
}
-unsigned int rtnl_route_get_metric(struct rtnl_route *route, int metric)
+int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
{
if (metric > RTAX_MAX || metric < 1)
- return UINT_MAX;
+ return -NLE_RANGE;
if (!(route->rt_metrics_mask & (1 << (metric - 1))))
- return UINT_MAX;
+ return -NLE_OBJ_NOTFOUND;
- return route->rt_metrics[metric - 1];
+ if (value)
+ *value = route->rt_metrics[metric - 1];
+
+ return 0;
}
int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
{
if (route->ce_mask & ROUTE_ATTR_FAMILY) {
if (addr->a_family != route->rt_family)
- return nl_error(EINVAL, "Address family mismatch");
+ return -NLE_AF_MISMATCH;
} else
route->rt_family = addr->a_family;
@@ -822,42 +732,27 @@ struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
return route->rt_pref_src;
}
-void rtnl_route_set_oif(struct rtnl_route *route, int ifindex)
+void rtnl_route_set_iif(struct rtnl_route *route, int ifindex)
{
- route->rt_oif = ifindex;
- route->ce_mask |= ROUTE_ATTR_OIF;
-}
-
-int rtnl_route_get_oif(struct rtnl_route *route)
-{
- if (route->ce_mask & ROUTE_ATTR_OIF)
- return route->rt_oif;
- else
- return RTNL_LINK_NOT_FOUND;
-}
-
-void rtnl_route_set_iif(struct rtnl_route *route, const char *name)
-{
- strncpy(route->rt_iif, name, sizeof(route->rt_iif) - 1);
+ route->rt_iif = ifindex;
route->ce_mask |= ROUTE_ATTR_IIF;
}
-char *rtnl_route_get_iif(struct rtnl_route *route)
+int rtnl_route_get_iif(struct rtnl_route *route)
{
- if (route->ce_mask & ROUTE_ATTR_IIF)
- return route->rt_iif;
- else
- return NULL;
+ return route->rt_iif;
}
void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
{
nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
+ route->rt_nr_nh++;
route->ce_mask |= ROUTE_ATTR_MULTIPATH;
}
-void rtnl_route_remove_nexthop(struct rtnl_nexthop *nh)
+void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
{
+ route->rt_nr_nh--;
nl_list_del(&nh->rtnh_list);
}
@@ -866,44 +761,437 @@ struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
return &route->rt_nexthops;
}
-void rtnl_route_set_cacheinfo(struct rtnl_route *route,
- struct rtnl_rtcacheinfo *ci)
+int rtnl_route_get_nnexthops(struct rtnl_route *route)
{
- memcpy(&route->rt_cacheinfo, ci, sizeof(*ci));
- route->ce_mask |= ROUTE_ATTR_CACHEINFO;
+ return route->rt_nr_nh;
}
-uint32_t rtnl_route_get_mp_algo(struct rtnl_route *route)
+void rtnl_route_foreach_nexthop(struct rtnl_route *r,
+ void (*cb)(struct rtnl_nexthop *, void *),
+ void *arg)
{
- if (route->ce_mask & ROUTE_ATTR_MP_ALGO)
- return route->rt_mp_algo;
- else
- return IP_MP_ALG_NONE;
+ struct rtnl_nexthop *nh;
+
+ if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+ nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+ cb(nh, arg);
+ }
+ }
}
-void rtnl_route_set_mp_algo(struct rtnl_route *route, uint32_t algo)
+struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
{
- route->rt_mp_algo = algo;
- route->ce_mask |= ROUTE_ATTR_MP_ALGO;
+ struct rtnl_nexthop *nh;
+ int i;
+
+ if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
+ i = 0;
+ nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+ if (i == n) return nh;
+ i++;
+ }
+ }
+ return NULL;
}
/** @} */
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Guess scope of a route object.
+ * @arg route Route object.
+ *
+ * Guesses the scope of a route object, based on the following rules:
+ * @code
+ * 1) Local route -> local scope
+ * 2) At least one nexthop not directly connected -> universe scope
+ * 3) All others -> link scope
+ * @endcode
+ *
+ * @return Scope value.
+ */
+int rtnl_route_guess_scope(struct rtnl_route *route)
+{
+ if (route->rt_type == RTN_LOCAL)
+ return RT_SCOPE_HOST;
+
+ if (!nl_list_empty(&route->rt_nexthops)) {
+ struct rtnl_nexthop *nh;
+
+ /*
+ * Use scope uiniverse if there is at least one nexthop which
+ * is not directly connected
+ */
+ nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
+ if (nh->rtnh_gateway)
+ return RT_SCOPE_UNIVERSE;
+ }
+ }
+
+ return RT_SCOPE_LINK;
+}
+
+/** @} */
+
+static struct nla_policy route_policy[RTA_MAX+1] = {
+ [RTA_IIF] = { .type = NLA_U32 },
+ [RTA_OIF] = { .type = NLA_U32 },
+ [RTA_PRIORITY] = { .type = NLA_U32 },
+ [RTA_FLOW] = { .type = NLA_U32 },
+ [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
+ [RTA_METRICS] = { .type = NLA_NESTED },
+ [RTA_MULTIPATH] = { .type = NLA_NESTED },
+};
+
+static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
+{
+ struct rtnl_nexthop *nh = NULL;
+ struct rtnexthop *rtnh = nla_data(attr);
+ size_t tlen = nla_len(attr);
+ int err;
+
+ while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
+ nh = rtnl_route_nh_alloc();
+ if (!nh)
+ return -NLE_NOMEM;
+
+ rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
+ rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
+ rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
+
+ if (rtnh->rtnh_len > sizeof(*rtnh)) {
+ struct nlattr *ntb[RTA_MAX + 1];
+
+ err = nla_parse(ntb, RTA_MAX, (struct nlattr *)
+ RTNH_DATA(rtnh),
+ rtnh->rtnh_len - sizeof(*rtnh),
+ route_policy);
+ if (err < 0)
+ goto errout;
+
+ if (ntb[RTA_GATEWAY]) {
+ struct nl_addr *addr;
+
+ addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
+ route->rt_family);
+ if (!addr) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ rtnl_route_nh_set_gateway(nh, addr);
+ nl_addr_put(addr);
+ }
+
+ if (ntb[RTA_FLOW]) {
+ uint32_t realms;
+
+ realms = nla_get_u32(ntb[RTA_FLOW]);
+ rtnl_route_nh_set_realms(nh, realms);
+ }
+ }
+
+ rtnl_route_add_nexthop(route, nh);
+ tlen -= RTNH_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ err = 0;
+errout:
+ if (err && nh)
+ rtnl_route_nh_free(nh);
+
+ return err;
+}
+
+int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
+{
+ struct rtmsg *rtm;
+ struct rtnl_route *route;
+ struct nlattr *tb[RTA_MAX + 1];
+ struct nl_addr *src = NULL, *dst = NULL, *addr;
+ struct rtnl_nexthop *old_nh = NULL;
+ int err, family;
+
+ route = rtnl_route_alloc();
+ if (!route) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ route->ce_msgtype = nlh->nlmsg_type;
+
+ err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
+ if (err < 0)
+ goto errout;
+
+ rtm = nlmsg_data(nlh);
+ route->rt_family = family = rtm->rtm_family;
+ route->rt_tos = rtm->rtm_tos;
+ route->rt_table = rtm->rtm_table;
+ route->rt_type = rtm->rtm_type;
+ route->rt_scope = rtm->rtm_scope;
+ route->rt_protocol = rtm->rtm_protocol;
+ route->rt_flags = rtm->rtm_flags;
+
+ route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
+ ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
+ ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
+ ROUTE_ATTR_FLAGS;
+
+ if (tb[RTA_DST]) {
+ if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
+ goto errout_nomem;
+ } else {
+ if (!(dst = nl_addr_alloc(0)))
+ goto errout_nomem;
+ nl_addr_set_family(dst, rtm->rtm_family);
+ }
+
+ nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
+ err = rtnl_route_set_dst(route, dst);
+ if (err < 0)
+ goto errout;
+
+ nl_addr_put(dst);
+
+ if (tb[RTA_SRC]) {
+ if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
+ goto errout_nomem;
+ } else if (rtm->rtm_src_len)
+ if (!(src = nl_addr_alloc(0)))
+ goto errout_nomem;
+
+ if (src) {
+ nl_addr_set_prefixlen(src, rtm->rtm_src_len);
+ rtnl_route_set_src(route, src);
+ nl_addr_put(src);
+ }
+
+ if (tb[RTA_IIF])
+ rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF]));
+
+ if (tb[RTA_PRIORITY])
+ rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
+
+ if (tb[RTA_PREFSRC]) {
+ if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
+ goto errout_nomem;
+ rtnl_route_set_pref_src(route, addr);
+ nl_addr_put(addr);
+ }
+
+ if (tb[RTA_METRICS]) {
+ struct nlattr *mtb[RTAX_MAX + 1];
+ int i;
+
+ err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
+ if (err < 0)
+ goto errout;
+
+ for (i = 1; i <= RTAX_MAX; i++) {
+ if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
+ uint32_t m = nla_get_u32(mtb[i]);
+ if (rtnl_route_set_metric(route, i, m) < 0)
+ goto errout;
+ }
+ }
+ }
+
+ if (tb[RTA_MULTIPATH])
+ if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
+ goto errout;
+
+ if (tb[RTA_CACHEINFO]) {
+ nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
+ sizeof(route->rt_cacheinfo));
+ route->ce_mask |= ROUTE_ATTR_CACHEINFO;
+ }
+
+ if (tb[RTA_OIF]) {
+ if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+ goto errout;
+
+ rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
+ }
+
+ if (tb[RTA_GATEWAY]) {
+ if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+ goto errout;
+
+ if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
+ goto errout_nomem;
+
+ rtnl_route_nh_set_gateway(old_nh, addr);
+ nl_addr_put(addr);
+ }
+
+ if (tb[RTA_FLOW]) {
+ if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+ goto errout;
+
+ rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
+ }
+
+ if (old_nh) {
+ if (route->rt_nr_nh == 0) {
+ /* If no nexthops have been provided via RTA_MULTIPATH
+ * we add it as regular nexthop to maintain backwards
+ * compatibility */
+ rtnl_route_add_nexthop(route, old_nh);
+ } else {
+ /* Kernel supports new style nexthop configuration,
+ * verify that it is a duplicate and discard nexthop. */
+ struct rtnl_nexthop *first;
+
+ first = nl_list_first_entry(&route->rt_nexthops,
+ struct rtnl_nexthop,
+ rtnh_list);
+ if (!first)
+ BUG();
+
+ if (rtnl_route_nh_compare(old_nh, first,
+ old_nh->ce_mask, 0)) {
+ err = -NLE_INVAL;
+ goto errout;
+ }
+
+ rtnl_route_nh_free(old_nh);
+ }
+ }
+
+ *result = route;
+ return 0;
+
+errout:
+ rtnl_route_put(route);
+ return err;
+
+errout_nomem:
+ err = -NLE_NOMEM;
+ goto errout;
+}
+
+int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
+{
+ int i;
+ struct nlattr *metrics;
+ struct rtmsg rtmsg = {
+ .rtm_family = route->rt_family,
+ .rtm_tos = route->rt_tos,
+ .rtm_table = route->rt_table,
+ .rtm_protocol = route->rt_protocol,
+ .rtm_scope = route->rt_scope,
+ .rtm_type = route->rt_type,
+ .rtm_flags = route->rt_flags,
+ };
+
+ if (route->rt_dst == NULL)
+ return -NLE_MISSING_ATTR;
+
+ rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
+ if (route->rt_src)
+ rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
+
+
+ if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE)
+ rtmsg.rtm_scope = rtnl_route_guess_scope(route);
+
+ if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ /* Additional table attribute replacing the 8bit in the header, was
+ * required to allow more than 256 tables. */
+ NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
+
+ if (nl_addr_get_len(route->rt_dst))
+ NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
+ NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
+
+ if (route->ce_mask & ROUTE_ATTR_SRC)
+ NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
+
+ if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
+ NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src);
+
+ if (route->ce_mask & ROUTE_ATTR_IIF)
+ NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
+
+ if (route->rt_nmetrics > 0) {
+ uint32_t val;
+
+ metrics = nla_nest_start(msg, RTA_METRICS);
+ if (metrics == NULL)
+ goto nla_put_failure;
+
+ for (i = 1; i <= RTAX_MAX; i++) {
+ if (!rtnl_route_get_metric(route, i, &val))
+ NLA_PUT_U32(msg, i, val);
+ }
+
+ nla_nest_end(msg, metrics);
+ }
+
+ if (rtnl_route_get_nnexthops(route) > 0) {
+ struct nlattr *multipath;
+ struct rtnl_nexthop *nh;
+
+ if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
+ goto nla_put_failure;
+
+ nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
+ struct rtnexthop *rtnh;
+
+ rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
+ if (!rtnh)
+ goto nla_put_failure;
+
+ rtnh->rtnh_flags = nh->rtnh_flags;
+ rtnh->rtnh_hops = nh->rtnh_weight;
+ rtnh->rtnh_ifindex = nh->rtnh_ifindex;
+
+ if (nh->rtnh_gateway)
+ NLA_PUT_ADDR(msg, RTA_GATEWAY,
+ nh->rtnh_gateway);
+
+ if (nh->rtnh_realms)
+ NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
+
+ rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
+ (void *) rtnh;
+ }
+
+ nla_nest_end(msg, multipath);
+ }
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+/** @cond SKIP */
struct nl_object_ops route_obj_ops = {
.oo_name = "route/route",
.oo_size = sizeof(struct rtnl_route),
.oo_constructor = route_constructor,
.oo_free_data = route_free_data,
.oo_clone = route_clone,
- .oo_dump[NL_DUMP_BRIEF] = route_dump_brief,
- .oo_dump[NL_DUMP_FULL] = route_dump_full,
- .oo_dump[NL_DUMP_STATS] = route_dump_stats,
- .oo_dump[NL_DUMP_XML] = route_dump_xml,
- .oo_dump[NL_DUMP_ENV] = route_dump_env,
+ .oo_dump = {
+ [NL_DUMP_LINE] = route_dump_line,
+ [NL_DUMP_DETAILS] = route_dump_details,
+ [NL_DUMP_STATS] = route_dump_stats,
+ [NL_DUMP_ENV] = route_dump_env,
+ },
.oo_compare = route_compare,
.oo_attrs2str = route_attrs2str,
.oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
ROUTE_ATTR_TABLE | ROUTE_ATTR_DST),
};
+/** @endcond */
/** @} */
diff --git a/lib/route/route_utils.c b/lib/route/route_utils.c
index a12d169..41ae65c 100644
--- a/lib/route/route_utils.c
+++ b/lib/route/route_utils.c
@@ -63,6 +63,11 @@ static void __init init_routing_table_names(void)
add_routing_table_name(RT_TABLE_LOCAL, "local");
};
+static void __exit release_routing_table_names(void)
+{
+ __trans_list_clear(&table_names);
+}
+
int rtnl_route_read_table_names(const char *path)
{
__trans_list_clear(&table_names);
@@ -104,6 +109,11 @@ static void __init init_proto_names(void)
add_proto_name(RTPROT_STATIC, "static");
};
+static void __exit release_proto_names(void)
+{
+ __trans_list_clear(&proto_names);
+}
+
int rtnl_route_read_protocol_names(const char *path)
{
__trans_list_clear(&proto_names);
@@ -157,27 +167,4 @@ int rtnl_route_str2metric(const char *name)
/** @} */
-/**
- * @name Nexthop Flags Translations
- * @{
- */
-
-static struct trans_tbl nh_flags[] = {
- __ADD(RTNH_F_DEAD, dead)
- __ADD(RTNH_F_PERVASIVE, pervasive)
- __ADD(RTNH_F_ONLINK, onlink)
-};
-
-char * rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
-{
- return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
-}
-
-int rtnl_route_nh_str2flags(const char *name)
-{
- return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
-}
-
-/** @} */
-
/** @} */
diff --git a/lib/route/rtnl.c b/lib/route/rtnl.c
index 81ddf94..2533674 100644
--- a/lib/route/rtnl.c
+++ b/lib/route/rtnl.c
@@ -6,12 +6,11 @@
* 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>
*/
/**
- * @ingroup nlfam
- * @defgroup rtnl Routing Netlink
+ * @defgroup rtnl Routing Family
* @{
*/
@@ -27,7 +26,7 @@
/**
* Send routing netlink request message
- * @arg handle Netlink handle.
+ * @arg sk Netlink socket.
* @arg type Netlink message type.
* @arg family Address family.
* @arg flags Additional netlink message flags.
@@ -37,13 +36,13 @@
*
* @return 0 on success or a negative error code.
*/
-int nl_rtgen_request(struct nl_handle *handle, int type, int family, int flags)
+int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags)
{
struct rtgenmsg gmsg = {
.rtgen_family = family,
};
- return nl_send_simple(handle, type, flags, &gmsg, sizeof(gmsg));
+ return nl_send_simple(sk, type, flags, &gmsg, sizeof(gmsg));
}
/** @} */
diff --git a/lib/route/rule.c b/lib/route/rule.c
index 60defd7..126e96d 100644
--- a/lib/route/rule.c
+++ b/lib/route/rule.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>
*/
/**
@@ -60,15 +60,13 @@ static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
if (src->r_src)
if (!(dst->r_src = nl_addr_clone(src->r_src)))
- goto errout;
+ return -NLE_NOMEM;
if (src->r_dst)
if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
- goto errout;
+ return -NLE_NOMEM;
return 0;
-errout:
- return nl_get_errno();
}
static struct nla_policy rule_policy[RTA_MAX+1] = {
@@ -85,11 +83,11 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct rtnl_rule *rule;
struct rtmsg *r;
struct nlattr *tb[RTA_MAX+1];
- int err = 1;
+ int err = 1, family;
rule = rtnl_rule_alloc();
if (!rule) {
- err = nl_errno(ENOMEM);
+ err = -NLE_NOMEM;
goto errout;
}
@@ -100,14 +98,15 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (err < 0)
goto errout;
- rule->r_family = r->rtm_family;
+ rule->r_family = family = r->rtm_family;
rule->r_type = r->rtm_type;
rule->r_dsfield = r->rtm_tos;
rule->r_src_len = r->rtm_src_len;
rule->r_dst_len = r->rtm_dst_len;
rule->r_table = r->rtm_table;
rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TYPE | RULE_ATTR_DSFIELD |
- RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE);
+ RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE |
+ RULE_ATTR_TABLE);
if (tb[RTA_PRIORITY]) {
rule->r_prio = nla_get_u32(tb[RTA_PRIORITY]);
@@ -115,21 +114,15 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
if (tb[RTA_SRC]) {
- rule->r_src = nla_get_addr(tb[RTA_SRC], r->rtm_family);
- if (!rule->r_src) {
- err = nl_errno(ENOMEM);
- goto errout;
- }
+ if (!(rule->r_src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
+ goto errout_enomem;
nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len);
rule->ce_mask |= RULE_ATTR_SRC;
}
if (tb[RTA_DST]) {
- rule->r_dst = nla_get_addr(tb[RTA_DST], r->rtm_family);
- if (!rule->r_dst) {
- err = nl_errno(ENOMEM);
- goto errout;
- }
+ if (!(rule->r_dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
+ goto errout_enomem;
nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len);
rule->ce_mask |= RULE_ATTR_DST;
}
@@ -150,216 +143,135 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
if (tb[RTA_GATEWAY]) {
- rule->r_srcmap = nla_get_addr(tb[RTA_GATEWAY], r->rtm_family);
- if (!rule->r_srcmap) {
- err = nl_errno(ENOMEM);
- goto errout;
- }
+ rule->r_srcmap = nl_addr_alloc_attr(tb[RTA_GATEWAY], family);
+ if (!rule->r_srcmap)
+ goto errout_enomem;
rule->ce_mask |= RULE_ATTR_SRCMAP;
}
- err = pp->pp_cb((struct nl_object *) rule, pp);
- if (err < 0)
- goto errout;
-
- err = P_ACCEPT;
+ if (tb[RTA_TABLE]) {
+ rule->r_table = nla_get_u32(tb[RTA_TABLE]);
+ rule->ce_mask |= RULE_ATTR_TABLE;
+ }
+ err = pp->pp_cb((struct nl_object *) rule, pp);
errout:
rtnl_rule_put(rule);
return err;
+
+errout_enomem:
+ err = -NLE_NOMEM;
+ goto errout;
}
-static int rule_request_update(struct nl_cache *c, struct nl_handle *h)
+static int rule_request_update(struct nl_cache *c, struct nl_sock *h)
{
return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP);
}
-static int rule_dump_brief(struct nl_object *o, struct nl_dump_params *p)
+static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
{
struct rtnl_rule *r = (struct rtnl_rule *) o;
char buf[128];
- if (r->ce_mask & RULE_ATTR_PRIO)
- dp_dump(p, "%d:\t", r->r_prio);
- else
- dp_dump(p, "0:\t");
+ nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0);
+ nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf)));
if (r->ce_mask & RULE_ATTR_SRC)
- dp_dump(p, "from %s ",
+ nl_dump(p, "from %s ",
nl_addr2str(r->r_src, buf, sizeof(buf)));
else if (r->ce_mask & RULE_ATTR_SRC_LEN && r->r_src_len)
- dp_dump(p, "from 0/%d ", r->r_src_len);
+ nl_dump(p, "from 0/%d ", r->r_src_len);
if (r->ce_mask & RULE_ATTR_DST)
- dp_dump(p, "to %s ",
+ nl_dump(p, "to %s ",
nl_addr2str(r->r_dst, buf, sizeof(buf)));
else if (r->ce_mask & RULE_ATTR_DST_LEN && r->r_dst_len)
- dp_dump(p, "to 0/%d ", r->r_dst_len);
+ nl_dump(p, "to 0/%d ", r->r_dst_len);
if (r->ce_mask & RULE_ATTR_DSFIELD && r->r_dsfield)
- dp_dump(p, "tos %d ", r->r_dsfield);
+ nl_dump(p, "tos %d ", r->r_dsfield);
if (r->ce_mask & RULE_ATTR_MARK)
- dp_dump(p, "mark %" PRIx64 , r->r_mark);
+ nl_dump(p, "mark %" PRIx64 , r->r_mark);
if (r->ce_mask & RULE_ATTR_IIF)
- dp_dump(p, "iif %s ", r->r_iif);
+ nl_dump(p, "iif %s ", r->r_iif);
if (r->ce_mask & RULE_ATTR_TABLE)
- dp_dump(p, "lookup %s ",
+ nl_dump(p, "lookup %s ",
rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
if (r->ce_mask & RULE_ATTR_REALMS)
- dp_dump(p, "realms %s ",
+ nl_dump(p, "realms %s ",
rtnl_realms2str(r->r_realms, buf, sizeof(buf)));
- dp_dump(p, "action %s\n",
+ nl_dump(p, "action %s\n",
nl_rtntype2str(r->r_type, buf, sizeof(buf)));
-
- return 1;
}
-static int rule_dump_full(struct nl_object *obj, struct nl_dump_params *p)
+static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_rule *rule = (struct rtnl_rule *) obj;
char buf[128];
- int line;
- line = rule_dump_brief(obj, p);
-
- dp_dump_line(p, line++, " family %s",
- nl_af2str(rule->r_family, buf, sizeof(buf)));
+ rule_dump_line(obj, p);
if (rule->ce_mask & RULE_ATTR_SRCMAP)
- dp_dump(p, " srcmap %s",
+ nl_dump_line(p, " srcmap %s\n",
nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
-
- dp_dump(p, "\n");
-
- return line;
}
-static int rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
- return rule_dump_full(obj, p);
+ rule_dump_details(obj, p);
}
-static int rule_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
+static void rule_dump_env(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_rule *rule = (struct rtnl_rule *) obj;
char buf[128];
- int line = 0;
-
- dp_dump_line(p, line++, "<rule>\n");
- dp_dump_line(p, line++, " <priority>%u</priority>\n",
- rule->r_prio);
- dp_dump_line(p, line++, " <family>%s</family>\n",
+ nl_dump_line(p, "RULE_PRIORITY=%u\n", rule->r_prio);
+ nl_dump_line(p, "RULE_FAMILY=%s\n",
nl_af2str(rule->r_family, buf, sizeof(buf)));
if (rule->ce_mask & RULE_ATTR_DST)
- dp_dump_line(p, line++, " <dst>%s</dst>\n",
+ nl_dump_line(p, "RULE_DST=%s\n",
nl_addr2str(rule->r_dst, buf, sizeof(buf)));
if (rule->ce_mask & RULE_ATTR_DST_LEN)
- dp_dump_line(p, line++, " <dstlen>%u</dstlen>\n",
- rule->r_dst_len);
+ nl_dump_line(p, "RULE_DSTLEN=%u\n", rule->r_dst_len);
if (rule->ce_mask & RULE_ATTR_SRC)
- dp_dump_line(p, line++, " <src>%s</src>\n",
+ nl_dump_line(p, "RULE_SRC=%s\n",
nl_addr2str(rule->r_src, buf, sizeof(buf)));
if (rule->ce_mask & RULE_ATTR_SRC_LEN)
- dp_dump_line(p, line++, " <srclen>%u</srclen>\n",
- rule->r_src_len);
+ nl_dump_line(p, "RULE_SRCLEN=%u\n", rule->r_src_len);
if (rule->ce_mask & RULE_ATTR_IIF)
- dp_dump_line(p, line++, " <iif>%s</iif>\n", rule->r_iif);
+ nl_dump_line(p, "RULE_IIF=%s\n", rule->r_iif);
if (rule->ce_mask & RULE_ATTR_TABLE)
- dp_dump_line(p, line++, " <table>%u</table>\n",
- rule->r_table);
+ nl_dump_line(p, "RULE_TABLE=%u\n", rule->r_table);
if (rule->ce_mask & RULE_ATTR_REALMS)
- dp_dump_line(p, line++, " <realms>%u</realms>\n",
- rule->r_realms);
+ nl_dump_line(p, "RULE_REALM=%u\n", rule->r_realms);
if (rule->ce_mask & RULE_ATTR_MARK)
- dp_dump_line(p, line++, " <mark>%" PRIx64 "</mark>\n",
- rule->r_mark);
+ nl_dump_line(p, "RULE_MARK=0x%" PRIx64 "\n", rule->r_mark);
if (rule->ce_mask & RULE_ATTR_DSFIELD)
- dp_dump_line(p, line++, " <dsfield>%u</dsfield>\n",
- rule->r_dsfield);
+ nl_dump_line(p, "RULE_DSFIELD=%u\n", rule->r_dsfield);
if (rule->ce_mask & RULE_ATTR_TYPE)
- dp_dump_line(p, line++, "<type>%s</type>\n",
+ nl_dump_line(p, "RULE_TYPE=%s\n",
nl_rtntype2str(rule->r_type, buf, sizeof(buf)));
if (rule->ce_mask & RULE_ATTR_SRCMAP)
- dp_dump_line(p, line++, "<srcmap>%s</srcmap>\n",
+ nl_dump_line(p, "RULE_SRCMAP=%s\n",
nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
-
- dp_dump_line(p, line++, "</rule>\n");
-
- return line;
-}
-
-static int rule_dump_env(struct nl_object *obj, struct nl_dump_params *p)
-{
- struct rtnl_rule *rule = (struct rtnl_rule *) obj;
- char buf[128];
- int line = 0;
-
- dp_dump_line(p, line++, "RULE_PRIORITY=%u\n",
- rule->r_prio);
- dp_dump_line(p, line++, "RULE_FAMILY=%s\n",
- nl_af2str(rule->r_family, buf, sizeof(buf)));
-
- if (rule->ce_mask & RULE_ATTR_DST)
- dp_dump_line(p, line++, "RULE_DST=%s\n",
- nl_addr2str(rule->r_dst, buf, sizeof(buf)));
-
- if (rule->ce_mask & RULE_ATTR_DST_LEN)
- dp_dump_line(p, line++, "RULE_DSTLEN=%u\n",
- rule->r_dst_len);
-
- if (rule->ce_mask & RULE_ATTR_SRC)
- dp_dump_line(p, line++, "RULE_SRC=%s\n",
- nl_addr2str(rule->r_src, buf, sizeof(buf)));
-
- if (rule->ce_mask & RULE_ATTR_SRC_LEN)
- dp_dump_line(p, line++, "RULE_SRCLEN=%u\n",
- rule->r_src_len);
-
- if (rule->ce_mask & RULE_ATTR_IIF)
- dp_dump_line(p, line++, "RULE_IIF=%s\n", rule->r_iif);
-
- if (rule->ce_mask & RULE_ATTR_TABLE)
- dp_dump_line(p, line++, "RULE_TABLE=%u\n",
- rule->r_table);
-
- if (rule->ce_mask & RULE_ATTR_REALMS)
- dp_dump_line(p, line++, "RULE_REALM=%u\n",
- rule->r_realms);
-
- if (rule->ce_mask & RULE_ATTR_MARK)
- dp_dump_line(p, line++, "RULE_MARK=0x%" PRIx64 "\n",
- rule->r_mark);
-
- if (rule->ce_mask & RULE_ATTR_DSFIELD)
- dp_dump_line(p, line++, "RULE_DSFIELD=%u\n",
- rule->r_dsfield);
-
- if (rule->ce_mask & RULE_ATTR_TYPE)
- dp_dump_line(p, line++, "RULE_TYPE=%s\n",
- nl_rtntype2str(rule->r_type, buf, sizeof(buf)));
-
- if (rule->ce_mask & RULE_ATTR_SRCMAP)
- dp_dump_line(p, line++, "RULE_SRCMAP=%s\n",
- nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
-
- return line;
}
static int rule_compare(struct nl_object *_a, struct nl_object *_b,
@@ -434,51 +346,34 @@ void rtnl_rule_put(struct rtnl_rule *rule)
*/
/**
- * Build a rule cache including all rules of the specified family currently configured in the kernel.
- * @arg handle netlink handle
- * @arg family address family
+ * Build a rule cache including all rules currently configured in the kernel.
+ * @arg sk Netlink socket.
+ * @arg family Address family or AF_UNSPEC.
+ * @arg result Pointer to store resulting cache.
*
* Allocates a new rule cache, initializes it properly and updates it
- * to include all rules of the specified address family currently
- * configured in the kernel.
+ * to include all rules currently configured in the kernel.
*
- * @note The caller is responsible for destroying and freeing the
- * cache after using it. (nl_cache_destroy_and_free())
- * @return The new cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
*/
-struct nl_cache * rtnl_rule_alloc_cache_by_family(struct nl_handle *handle,
- int family)
+int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
+ struct nl_cache **result)
{
struct nl_cache * cache;
+ int err;
- cache = nl_cache_alloc(&rtnl_rule_ops);
- if (cache == NULL)
- return NULL;
+ if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
+ return -NLE_NOMEM;
- /* XXX RULE_CACHE_FAMILY(cache) = family; */
+ cache->c_iarg1 = family;
- if (handle && nl_cache_refill(handle, cache) < 0) {
+ if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
free(cache);
- return NULL;
+ return err;
}
- return cache;
-}
-
-/**
- * Build a rule cache including all rules currently configured in the kernel.
- * @arg handle netlink handle
- *
- * Allocates a new rule cache, initializes it properly and updates it
- * to include all rules currently configured in the kernel.
- *
- * @note The caller is responsible for destroying and freeing the
- * cache after using it. (nl_cache_destroy_and_free())
- * @return The new cache or NULL if an error occured.
- */
-struct nl_cache * rtnl_rule_alloc_cache(struct nl_handle *handle)
-{
- return rtnl_rule_alloc_cache_by_family(handle, AF_UNSPEC);
+ *result = cache;
+ return 0;
}
/** @} */
@@ -488,7 +383,8 @@ struct nl_cache * rtnl_rule_alloc_cache(struct nl_handle *handle)
* @{
*/
-static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags)
+static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
+ struct nl_msg **result)
{
struct nl_msg *msg;
struct rtmsg rtm = {
@@ -518,7 +414,7 @@ static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags)
msg = nlmsg_alloc_simple(cmd, flags);
if (!msg)
- goto nla_put_failure;
+ return -NLE_NOMEM;
if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0)
goto nla_put_failure;
@@ -541,11 +437,12 @@ static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags)
if (tmpl->ce_mask & RULE_ATTR_IIF)
NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif);
- return msg;
+ *result = msg;
+ return 0;
nla_put_failure:
nlmsg_free(msg);
- return NULL;
+ return -NLE_MSGSIZE;
}
/**
@@ -561,14 +458,16 @@ nla_put_failure:
*
* @return The netlink message
*/
-struct nl_msg *rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags)
+int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
+ struct nl_msg **result)
{
- return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags);
+ return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
+ result);
}
/**
* Add a new rule
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg tmpl template with requested changes
* @arg flags additional netlink message flags
*
@@ -578,21 +477,20 @@ struct nl_msg *rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_rule_add(struct nl_handle *handle, struct rtnl_rule *tmpl, int flags)
+int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_rule_build_add_request(tmpl, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -615,14 +513,15 @@ int rtnl_rule_add(struct nl_handle *handle, struct rtnl_rule *tmpl, int flags)
*
* @return The netlink message
*/
-struct nl_msg *rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags)
+int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
+ struct nl_msg **result)
{
- return build_rule_msg(rule, RTM_DELRULE, flags);
+ return build_rule_msg(rule, RTM_DELRULE, flags, result);
}
/**
* Delete a rule
- * @arg handle netlink handle
+ * @arg sk Netlink socket.
* @arg rule rule to delete
* @arg flags additional netlink message flags
*
@@ -632,22 +531,20 @@ struct nl_msg *rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags)
*
* @return 0 on sucess or a negative error if an error occured.
*/
-int rtnl_rule_delete(struct nl_handle *handle, struct rtnl_rule *rule,
- int flags)
+int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
{
- int err;
struct nl_msg *msg;
+ int err;
- msg = rtnl_rule_build_delete_request(rule, flags);
- if (!msg)
- return nl_errno(ENOMEM);
+ if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
+ return err;
- err = nl_send_auto_complete(handle, msg);
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
if (err < 0)
return err;
- nlmsg_free(msg);
- return nl_wait_for_ack(handle);
+ return wait_for_ack(sk);
}
/** @} */
@@ -764,7 +661,7 @@ static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
{
if (rule->ce_mask & RULE_ATTR_FAMILY) {
if (new->a_family != rule->r_family)
- return nl_error(EINVAL, "Address family mismatch");
+ return -NLE_AF_MISMATCH;
} else
rule->r_family = new->a_family;
@@ -811,7 +708,7 @@ struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
{
if (strlen(dev) > IFNAMSIZ-1)
- return nl_errno(ERANGE);
+ return -NLE_RANGE;
strcpy(rule->r_iif, dev);
rule->ce_mask |= RULE_ATTR_IIF;
@@ -837,16 +734,16 @@ int rtnl_rule_get_action(struct rtnl_rule *rule)
if (rule->ce_mask & RULE_ATTR_TYPE)
return rule->r_type;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
-void rtnl_rule_set_realms(struct rtnl_rule *rule, realm_t realms)
+void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
{
rule->r_realms = realms;
rule->ce_mask |= RULE_ATTR_REALMS;
}
-realm_t rtnl_rule_get_realms(struct rtnl_rule *rule)
+uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
{
if (rule->ce_mask & RULE_ATTR_REALMS)
return rule->r_realms;
@@ -861,11 +758,12 @@ static struct nl_object_ops rule_obj_ops = {
.oo_size = sizeof(struct rtnl_rule),
.oo_free_data = rule_free_data,
.oo_clone = rule_clone,
- .oo_dump[NL_DUMP_BRIEF] = rule_dump_brief,
- .oo_dump[NL_DUMP_FULL] = rule_dump_full,
- .oo_dump[NL_DUMP_STATS] = rule_dump_stats,
- .oo_dump[NL_DUMP_XML] = rule_dump_xml,
- .oo_dump[NL_DUMP_ENV] = rule_dump_env,
+ .oo_dump = {
+ [NL_DUMP_LINE] = rule_dump_line,
+ [NL_DUMP_DETAILS] = rule_dump_details,
+ [NL_DUMP_STATS] = rule_dump_stats,
+ [NL_DUMP_ENV] = rule_dump_env,
+ },
.oo_compare = rule_compare,
.oo_attrs2str = rule_attrs2str,
.oo_id_attrs = ~0,
diff --git a/lib/route/sch/cbq.c b/lib/route/sch/cbq.c
index 9808509..1aaa58d 100644
--- a/lib/route/sch/cbq.c
+++ b/lib/route/sch/cbq.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 <netlink-local.h>
@@ -99,7 +99,7 @@ static int cbq_msg_parser(struct rtnl_tca *tca)
cbq = cbq_alloc(tca);
if (!cbq)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
@@ -133,7 +133,7 @@ static int cbq_clone(struct rtnl_tca *_dst, struct rtnl_tca *_src)
struct rtnl_cbq *src = cbq_qdisc(_src);
if (src && !cbq_alloc(_dst))
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
else
return 0;
}
@@ -153,8 +153,7 @@ static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src)
return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
}
-static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p,
- int line)
+static void cbq_dump_line(struct rtnl_tca *tca, struct nl_dump_params *p)
{
struct rtnl_cbq *cbq;
double r, rbit;
@@ -162,32 +161,28 @@ static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p,
cbq = cbq_qdisc(tca);
if (!cbq)
- goto ignore;
+ return;
r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
- dp_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
+ nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
r, ru, rbit, rubit, cbq->cbq_wrr.priority);
-
-ignore:
- return line;
}
-static int cbq_qdisc_dump_brief(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void cbq_qdisc_dump_line(struct rtnl_qdisc *qdisc,
+ struct nl_dump_params *p)
{
- return cbq_dump_brief((struct rtnl_tca *) qdisc, p, line);
+ cbq_dump_line((struct rtnl_tca *) qdisc, p);
}
-static int cbq_class_dump_brief(struct rtnl_class *class,
- struct nl_dump_params *p, int line)
+static void cbq_class_dump_line(struct rtnl_class *class,
+ struct nl_dump_params *p)
{
- return cbq_dump_brief((struct rtnl_tca *) class, p, line);
+ cbq_dump_line((struct rtnl_tca *) class, p);
}
-static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p,
- int line)
+static void cbq_dump_details(struct rtnl_tca *tca, struct nl_dump_params *p)
{
struct rtnl_cbq *cbq;
char *unit, buf[32];
@@ -196,18 +191,18 @@ static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p,
cbq = cbq_qdisc(tca);
if (!cbq)
- goto ignore;
+ return;
w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
- dp_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
+ nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
cbq->cbq_lss.avpkt,
cbq->cbq_rate.mpu,
1 << cbq->cbq_rate.cell_log,
cbq->cbq_wrr.allot, w, unit);
el = cbq->cbq_lss.ewma_log;
- dp_dump_line(p, line++, " minidle %uus maxidle %uus offtime "
+ nl_dump_line(p, " minidle %uus maxidle %uus offtime "
"%uus level %u ewma_log %u\n",
nl_ticks2us(cbq->cbq_lss.minidle >> el),
nl_ticks2us(cbq->cbq_lss.maxidle >> el),
@@ -215,60 +210,53 @@ static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p,
cbq->cbq_lss.level,
cbq->cbq_lss.ewma_log);
- dp_dump_line(p, line++, " penalty %uus strategy %s ",
+ nl_dump_line(p, " penalty %uus strategy %s ",
nl_ticks2us(cbq->cbq_ovl.penalty),
nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
- dp_dump(p, "split %s defmap 0x%08x ",
+ nl_dump(p, "split %s defmap 0x%08x ",
rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
cbq->cbq_fopt.defmap);
- dp_dump(p, "police %s",
+ nl_dump(p, "police %s",
nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
-
-ignore:
- return line;
}
-static int cbq_qdisc_dump_full(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void cbq_qdisc_dump_details(struct rtnl_qdisc *qdisc,
+ struct nl_dump_params *p)
{
- return cbq_dump_full((struct rtnl_tca *) qdisc, p, line);
+ cbq_dump_details((struct rtnl_tca *) qdisc, p);
}
-static int cbq_class_dump_full(struct rtnl_class *class,
- struct nl_dump_params *p, int line)
+static void cbq_class_dump_details(struct rtnl_class *class,
+ struct nl_dump_params *p)
{
- return cbq_dump_full((struct rtnl_tca *) class, p, line);
+ cbq_dump_details((struct rtnl_tca *) class, p);
}
-static int cbq_dump_with_stats(struct rtnl_tca *tca, struct nl_dump_params *p,
- int line)
+static void cbq_dump_stats(struct rtnl_tca *tca, struct nl_dump_params *p)
{
struct tc_cbq_xstats *x = tca_xstats(tca);
if (!x)
- goto ignore;
+ return;
- dp_dump_line(p, line++, " borrows overact "
- " avgidle undertime\n");
- dp_dump_line(p, line++, " %10u %10u %10u %10u\n",
+ nl_dump_line(p, " borrows overact "
+ " avgidle undertime\n");
+ nl_dump_line(p, " %10u %10u %10u %10u\n",
x->borrows, x->overactions, x->avgidle, x->undertime);
-
-ignore:
- return line;
}
-static int cbq_qdisc_dump_with_stats(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void cbq_qdisc_dump_stats(struct rtnl_qdisc *qdisc,
+ struct nl_dump_params *p)
{
- return cbq_dump_with_stats((struct rtnl_tca *) qdisc, p, line);
+ cbq_dump_stats((struct rtnl_tca *) qdisc, p);
}
-static int cbq_class_dump_with_stats(struct rtnl_class *class,
- struct nl_dump_params *p, int line)
+static void cbq_class_dump_stats(struct rtnl_class *class,
+ struct nl_dump_params *p)
{
- return cbq_dump_with_stats((struct rtnl_tca *) class, p, line);
+ cbq_dump_stats((struct rtnl_tca *) class, p);
}
static struct rtnl_qdisc_ops cbq_qdisc_ops = {
@@ -276,9 +264,11 @@ static struct rtnl_qdisc_ops cbq_qdisc_ops = {
.qo_msg_parser = cbq_qdisc_msg_parser,
.qo_free_data = cbq_qdisc_free_data,
.qo_clone = cbq_qdisc_clone,
- .qo_dump[NL_DUMP_BRIEF] = cbq_qdisc_dump_brief,
- .qo_dump[NL_DUMP_FULL] = cbq_qdisc_dump_full,
- .qo_dump[NL_DUMP_STATS] = cbq_qdisc_dump_with_stats,
+ .qo_dump = {
+ [NL_DUMP_LINE] = cbq_qdisc_dump_line,
+ [NL_DUMP_DETAILS] = cbq_qdisc_dump_details,
+ [NL_DUMP_STATS] = cbq_qdisc_dump_stats,
+ },
};
static struct rtnl_class_ops cbq_class_ops = {
@@ -286,9 +276,11 @@ static struct rtnl_class_ops cbq_class_ops = {
.co_msg_parser = cbq_class_msg_parser,
.co_free_data = cbq_class_free_data,
.co_clone = cbq_class_clone,
- .co_dump[NL_DUMP_BRIEF] = cbq_class_dump_brief,
- .co_dump[NL_DUMP_FULL] = cbq_class_dump_full,
- .co_dump[NL_DUMP_STATS] = cbq_class_dump_with_stats,
+ .co_dump = {
+ [NL_DUMP_LINE] = cbq_class_dump_line,
+ [NL_DUMP_DETAILS] = cbq_class_dump_details,
+ [NL_DUMP_STATS] = cbq_class_dump_stats,
+ },
};
static void __init cbq_init(void)
diff --git a/lib/route/sch/dsmark.c b/lib/route/sch/dsmark.c
index 5ba6b92..61b0fea 100644
--- a/lib/route/sch/dsmark.c
+++ b/lib/route/sch/dsmark.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>
*/
/**
@@ -70,7 +70,7 @@ static int dsmark_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
dsmark = dsmark_qdisc_alloc(qdisc);
if (!dsmark)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
if (tb[TCA_DSMARK_INDICES]) {
dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]);
@@ -118,7 +118,7 @@ static int dsmark_class_msg_parser(struct rtnl_class *class)
dsmark = dsmark_class_alloc(class);
if (!dsmark)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
if (tb[TCA_DSMARK_MASK]) {
dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]);
@@ -133,51 +133,43 @@ static int dsmark_class_msg_parser(struct rtnl_class *class)
return 0;
}
-static int dsmark_qdisc_dump_brief(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void dsmark_qdisc_dump_line(struct rtnl_qdisc *qdisc,
+ struct nl_dump_params *p)
{
struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc);
if (dsmark && (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES))
- dp_dump(p, " indices 0x%04x", dsmark->qdm_indices);
-
- return line;
+ nl_dump(p, " indices 0x%04x", dsmark->qdm_indices);
}
-static int dsmark_qdisc_dump_full(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void dsmark_qdisc_dump_details(struct rtnl_qdisc *qdisc,
+ struct nl_dump_params *p)
{
struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc);
if (!dsmark)
- goto ignore;
+ return;
if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
- dp_dump(p, " default index 0x%04x", dsmark->qdm_default_index);
+ nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index);
if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
- dp_dump(p, " set-tc-index");
-
-ignore:
- return line;
+ nl_dump(p, " set-tc-index");
}
-static int dsmark_class_dump_brief(struct rtnl_class *class,
- struct nl_dump_params *p, int line)
+static void dsmark_class_dump_line(struct rtnl_class *class,
+ struct nl_dump_params *p)
{
struct rtnl_dsmark_class *dsmark = dsmark_class(class);
if (!dsmark)
- goto ignore;
+ return;
if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
- dp_dump(p, " value 0x%02x", dsmark->cdm_value);
+ nl_dump(p, " value 0x%02x", dsmark->cdm_value);
if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
- dp_dump(p, " mask 0x%02x", dsmark->cdm_bmask);
-
-ignore:
- return line;
+ nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask);
}
static struct nl_msg *dsmark_qdisc_get_opts(struct rtnl_qdisc *qdisc)
@@ -251,7 +243,7 @@ int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask)
dsmark = dsmark_class(class);
if (!dsmark)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
dsmark->cdm_bmask = mask;
dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
@@ -272,7 +264,7 @@ int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class)
if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
return dsmark->cdm_bmask;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -287,7 +279,7 @@ int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value)
dsmark = dsmark_class(class);
if (!dsmark)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
dsmark->cdm_value = value;
dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
@@ -308,7 +300,7 @@ int rtnl_class_dsmark_get_value(struct rtnl_class *class)
if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
return dsmark->cdm_value;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/** @} */
@@ -329,7 +321,7 @@ int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices)
dsmark = dsmark_qdisc(qdisc);
if (!dsmark)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
dsmark->qdm_indices = indices;
dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
@@ -350,7 +342,7 @@ int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc)
if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
return dsmark->qdm_indices;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -366,7 +358,7 @@ int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc,
dsmark = dsmark_qdisc(qdisc);
if (!dsmark)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
dsmark->qdm_default_index = default_index;
dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
@@ -387,7 +379,7 @@ int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc)
if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
return dsmark->qdm_default_index;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -402,7 +394,7 @@ int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag)
dsmark = dsmark_qdisc(qdisc);
if (!dsmark)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
dsmark->qdm_set_tc_index = !!flag;
dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
@@ -424,7 +416,7 @@ int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc)
if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
return dsmark->qdm_set_tc_index;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/** @} */
@@ -432,15 +424,17 @@ int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc)
static struct rtnl_qdisc_ops dsmark_qdisc_ops = {
.qo_kind = "dsmark",
.qo_msg_parser = dsmark_qdisc_msg_parser,
- .qo_dump[NL_DUMP_BRIEF] = dsmark_qdisc_dump_brief,
- .qo_dump[NL_DUMP_FULL] = dsmark_qdisc_dump_full,
+ .qo_dump = {
+ [NL_DUMP_LINE] = dsmark_qdisc_dump_line,
+ [NL_DUMP_DETAILS] = dsmark_qdisc_dump_details,
+ },
.qo_get_opts = dsmark_qdisc_get_opts,
};
static struct rtnl_class_ops dsmark_class_ops = {
.co_kind = "dsmark",
.co_msg_parser = dsmark_class_msg_parser,
- .co_dump[NL_DUMP_BRIEF] = dsmark_class_dump_brief,
+ .co_dump[NL_DUMP_LINE] = dsmark_class_dump_line,
.co_get_opts = dsmark_class_get_opts,
};
diff --git a/lib/route/sch/fifo.c b/lib/route/sch/fifo.c
index 4f8d202..464af30 100644
--- a/lib/route/sch/fifo.c
+++ b/lib/route/sch/fifo.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>
*/
/**
@@ -60,11 +60,11 @@ static int fifo_msg_parser(struct rtnl_qdisc *qdisc)
struct tc_fifo_qopt *opt;
if (qdisc->q_opts->d_size < sizeof(struct tc_fifo_qopt))
- return nl_error(EINVAL, "FIFO options size mismatch");
+ return -NLE_INVAL;
fifo = fifo_alloc(qdisc);
if (!fifo)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
opt = (struct tc_fifo_qopt *) qdisc->q_opts->d_data;
fifo->qf_limit = opt->limit;
@@ -78,19 +78,15 @@ static void fifo_free_data(struct rtnl_qdisc *qdisc)
free(qdisc->q_subdata);
}
-static int pfifo_dump_brief(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void pfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_fifo *fifo = fifo_qdisc(qdisc);
if (fifo)
- dp_dump(p, " limit %u packets", fifo->qf_limit);
-
- return line;
+ nl_dump(p, " limit %u packets", fifo->qf_limit);
}
-static int bfifo_dump_brief(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void bfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_fifo *fifo = fifo_qdisc(qdisc);
@@ -99,10 +95,8 @@ static int bfifo_dump_brief(struct rtnl_qdisc *qdisc,
double r;
r = nl_cancel_down_bytes(fifo->qf_limit, &unit);
- dp_dump(p, " limit %.1f%s", r, unit);
+ nl_dump(p, " limit %.1f%s", r, unit);
}
-
- return line;
}
static struct nl_msg *fifo_get_opts(struct rtnl_qdisc *qdisc)
@@ -148,7 +142,7 @@ int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit)
fifo = fifo_alloc(qdisc);
if (!fifo)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
fifo->qf_limit = limit;
fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT;
@@ -169,7 +163,7 @@ int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc)
if (fifo && fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)
return fifo->qf_limit;
else
- return nl_errno(ENOMEM);
+ return -NLE_NOATTR;
}
/** @} */
@@ -178,7 +172,7 @@ static struct rtnl_qdisc_ops pfifo_ops = {
.qo_kind = "pfifo",
.qo_msg_parser = fifo_msg_parser,
.qo_free_data = fifo_free_data,
- .qo_dump[NL_DUMP_BRIEF] = pfifo_dump_brief,
+ .qo_dump[NL_DUMP_LINE] = pfifo_dump_line,
.qo_get_opts = fifo_get_opts,
};
@@ -186,7 +180,7 @@ static struct rtnl_qdisc_ops bfifo_ops = {
.qo_kind = "bfifo",
.qo_msg_parser = fifo_msg_parser,
.qo_free_data = fifo_free_data,
- .qo_dump[NL_DUMP_BRIEF] = bfifo_dump_brief,
+ .qo_dump[NL_DUMP_LINE] = bfifo_dump_line,
.qo_get_opts = fifo_get_opts,
};
diff --git a/lib/route/sch/htb.c b/lib/route/sch/htb.c
index 6de87b3..a167136 100644
--- a/lib/route/sch/htb.c
+++ b/lib/route/sch/htb.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) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
* Copyright (c) 2005-2006 Siemens AG Oesterreich
*/
@@ -136,34 +136,31 @@ static void htb_class_free_data(struct rtnl_class *class)
free(class->c_subdata);
}
-static int htb_qdisc_dump_brief(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void htb_qdisc_dump_line(struct rtnl_qdisc *qdisc,
+ struct nl_dump_params *p)
{
struct rtnl_htb_qdisc *d = (struct rtnl_htb_qdisc *) qdisc->q_subdata;
if (d == NULL)
- goto ignore;
+ return;
if (d->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
- dp_dump(p, " r2q %u", d->qh_rate2quantum);
+ nl_dump(p, " r2q %u", d->qh_rate2quantum);
if (d->qh_mask & SCH_HTB_HAS_DEFCLS) {
char buf[32];
- dp_dump(p, " default %s",
+ nl_dump(p, " default %s",
rtnl_tc_handle2str(d->qh_defcls, buf, sizeof(buf)));
}
-
-ignore:
- return line;
}
-static int htb_class_dump_brief(struct rtnl_class *class,
- struct nl_dump_params *p, int line)
+static void htb_class_dump_line(struct rtnl_class *class,
+ struct nl_dump_params *p)
{
struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata;
if (d == NULL)
- goto ignore;
+ return;
if (d->ch_mask & SCH_HTB_HAS_RATE) {
double r, rbit;
@@ -172,21 +169,18 @@ static int htb_class_dump_brief(struct rtnl_class *class,
r = nl_cancel_down_bytes(d->ch_rate.rs_rate, &ru);
rbit = nl_cancel_down_bits(d->ch_rate.rs_rate*8, &rubit);
- dp_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
+ nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
r, ru, rbit, rubit, 1<<d->ch_rate.rs_cell_log);
}
-
-ignore:
- return line;
}
-static int htb_class_dump_full(struct rtnl_class *class,
- struct nl_dump_params *p, int line)
+static void htb_class_dump_details(struct rtnl_class *class,
+ struct nl_dump_params *p)
{
struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata;
if (d == NULL)
- goto ignore;
+ return;
/* line 1 */
if (d->ch_mask & SCH_HTB_HAS_CEIL) {
@@ -196,22 +190,22 @@ static int htb_class_dump_full(struct rtnl_class *class,
r = nl_cancel_down_bytes(d->ch_ceil.rs_rate, &ru);
rbit = nl_cancel_down_bits(d->ch_ceil.rs_rate*8, &rubit);
- dp_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
+ nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
r, ru, rbit, rubit, 1<<d->ch_ceil.rs_cell_log);
}
if (d->ch_mask & SCH_HTB_HAS_PRIO)
- dp_dump(p, " prio %u", d->ch_prio);
+ nl_dump(p, " prio %u", d->ch_prio);
if (d->ch_mask & SCH_HTB_HAS_MTU)
- dp_dump(p, " mtu %u", d->ch_mtu);
+ nl_dump(p, " mtu %u", d->ch_mtu);
if (d->ch_mask & SCH_HTB_HAS_RBUFFER) {
double b;
char *bu;
b = nl_cancel_down_bytes(d->ch_rbuffer, &bu);
- dp_dump(p, " rbuffer %.2f%s", b, bu);
+ nl_dump(p, " rbuffer %.2f%s", b, bu);
}
if (d->ch_mask & SCH_HTB_HAS_CBUFFER) {
@@ -219,20 +213,17 @@ static int htb_class_dump_full(struct rtnl_class *class,
char *bu;
b = nl_cancel_down_bytes(d->ch_cbuffer, &bu);
- dp_dump(p, " cbuffer %.2f%s", b, bu);
+ nl_dump(p, " cbuffer %.2f%s", b, bu);
}
if (d->ch_mask & SCH_HTB_HAS_QUANTUM)
- dp_dump(p, " quantum %u", d->ch_quantum);
+ nl_dump(p, " quantum %u", d->ch_quantum);
if (d->ch_mask & SCH_HTB_HAS_OVERHEAD)
- dp_dump(p, " overhead %u", d->ch_overhead);
+ nl_dump(p, " overhead %u", d->ch_overhead);
if (d->ch_mask & SCH_HTB_HAS_MPU)
- dp_dump(p, " mpu %u", d->ch_mpu);
-
-ignore:
- return line;
+ nl_dump(p, " mpu %u", d->ch_mpu);
}
static struct nl_msg *htb_qdisc_get_opts(struct rtnl_qdisc *qdisc)
@@ -525,7 +516,7 @@ static struct rtnl_qdisc_ops htb_qdisc_ops = {
.qo_kind = "htb",
.qo_msg_parser = htb_qdisc_msg_parser,
.qo_free_data = htb_qdisc_free_data,
- .qo_dump[NL_DUMP_BRIEF] = htb_qdisc_dump_brief,
+ .qo_dump[NL_DUMP_LINE] = htb_qdisc_dump_line,
.qo_get_opts = htb_qdisc_get_opts,
};
@@ -533,8 +524,10 @@ static struct rtnl_class_ops htb_class_ops = {
.co_kind = "htb",
.co_msg_parser = htb_class_msg_parser,
.co_free_data = htb_class_free_data,
- .co_dump[NL_DUMP_BRIEF] = htb_class_dump_brief,
- .co_dump[NL_DUMP_FULL] = htb_class_dump_full,
+ .co_dump = {
+ [NL_DUMP_LINE] = htb_class_dump_line,
+ [NL_DUMP_DETAILS] = htb_class_dump_details,
+ },
.co_get_opts = htb_class_get_opts,
};
diff --git a/lib/route/sch/netem.c b/lib/route/sch/netem.c
index e8b8913..18878a7 100644
--- a/lib/route/sch/netem.c
+++ b/lib/route/sch/netem.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>
*/
/**
@@ -27,17 +27,20 @@
#include <netlink/route/sch/netem.h>
/** @cond SKIP */
-#define SCH_NETEM_ATTR_LATENCY 0x001
-#define SCH_NETEM_ATTR_LIMIT 0x002
-#define SCH_NETEM_ATTR_LOSS 0x004
-#define SCH_NETEM_ATTR_GAP 0x008
-#define SCH_NETEM_ATTR_DUPLICATE 0x010
-#define SCH_NETEM_ATTR_JITTER 0x020
-#define SCH_NETEM_ATTR_DELAY_CORR 0x040
-#define SCH_NETEM_ATTR_LOSS_CORR 0x080
-#define SCH_NETEM_ATTR_DUP_CORR 0x100
-#define SCH_NETEM_ATTR_RO_PROB 0x200
-#define SCH_NETEM_ATTR_RO_CORR 0x400
+#define SCH_NETEM_ATTR_LATENCY 0x0001
+#define SCH_NETEM_ATTR_LIMIT 0x0002
+#define SCH_NETEM_ATTR_LOSS 0x0004
+#define SCH_NETEM_ATTR_GAP 0x0008
+#define SCH_NETEM_ATTR_DUPLICATE 0x0010
+#define SCH_NETEM_ATTR_JITTER 0x0020
+#define SCH_NETEM_ATTR_DELAY_CORR 0x0040
+#define SCH_NETEM_ATTR_LOSS_CORR 0x0080
+#define SCH_NETEM_ATTR_DUP_CORR 0x0100
+#define SCH_NETEM_ATTR_RO_PROB 0x0200
+#define SCH_NETEM_ATTR_RO_CORR 0x0400
+#define SCH_NETEM_ATTR_CORRUPT_PROB 0x0800
+#define SCH_NETEM_ATTR_CORRUPT_CORR 0x1000
+#define SCH_NETEM_ATTR_DIST 0x2000
/** @endcond */
static inline struct rtnl_netem *netem_qdisc(struct rtnl_qdisc *qdisc)
@@ -56,6 +59,7 @@ static inline struct rtnl_netem *netem_alloc(struct rtnl_qdisc *qdisc)
static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = {
[TCA_NETEM_CORR] = { .minlen = sizeof(struct tc_netem_corr) },
[TCA_NETEM_REORDER] = { .minlen = sizeof(struct tc_netem_reorder) },
+ [TCA_NETEM_CORRUPT] = { .minlen = sizeof(struct tc_netem_corrupt) },
};
static int netem_msg_parser(struct rtnl_qdisc *qdisc)
@@ -65,11 +69,11 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc)
struct tc_netem_qopt *opts;
if (qdisc->q_opts->d_size < sizeof(*opts))
- return nl_error(EINVAL, "Netem specific options size mismatch");
+ return -NLE_INVAL;
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
opts = (struct tc_netem_qopt *) qdisc->q_opts->d_data;
netem->qnm_latency = opts->latency;
@@ -89,7 +93,7 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc)
struct nlattr *tb[TCA_NETEM_MAX+1];
err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *)
- qdisc->q_opts->d_data + sizeof(*opts),
+ (qdisc->q_opts->d_data + sizeof(*opts)),
len, netem_policy);
if (err < 0) {
free(netem);
@@ -106,7 +110,7 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc)
netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR |
SCH_NETEM_ATTR_LOSS_CORR |
- SCH_NETEM_ATTR_DELAY_CORR);
+ SCH_NETEM_ATTR_DUP_CORR);
}
if (tb[TCA_NETEM_REORDER]) {
@@ -119,6 +123,21 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc)
netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB |
SCH_NETEM_ATTR_RO_CORR);
}
+
+ if (tb[TCA_NETEM_CORRUPT]) {
+ struct tc_netem_corrupt corrupt;
+
+ nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt));
+ netem->qnm_crpt.nmcr_probability = corrupt.probability;
+ netem->qnm_crpt.nmcr_correlation = corrupt.correlation;
+
+ netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB |
+ SCH_NETEM_ATTR_CORRUPT_CORR);
+ }
+
+ /* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */
+ netem->qnm_dist.dist_data = NULL;
+ netem->qnm_dist.dist_size = 0;
}
return 0;
@@ -126,29 +145,164 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc)
static void netem_free_data(struct rtnl_qdisc *qdisc)
{
- free(qdisc->q_subdata);
+ struct rtnl_netem *netem;
+
+ if ( ! qdisc ) return;
+
+ netem = netem_qdisc(qdisc);
+ if ( ! netem ) return;
+
+ if ( netem->qnm_dist.dist_data )
+ free(netem->qnm_dist.dist_data);
+
+ netem = NULL;
+
+ free (qdisc->q_subdata);
}
-static int netem_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void netem_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_netem *netem = netem_qdisc(qdisc);
if (netem)
- dp_dump(p, "limit %d", netem->qnm_limit);
-
- return line;
+ nl_dump(p, "limit %d", netem->qnm_limit);
}
-static int netem_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+int netem_build_msg(struct rtnl_qdisc *qdisc, struct nl_msg *msg)
{
- return line;
-}
+ int err = 0;
+ struct tc_netem_qopt opts;
+ struct tc_netem_corr cor;
+ struct tc_netem_reorder reorder;
+ struct tc_netem_corrupt corrupt;
+ struct rtnl_netem *netem;
+
+ unsigned char set_correlation = 0, set_reorder = 0,
+ set_corrupt = 0, set_dist = 0;
-static struct nl_msg *netem_get_opts(struct rtnl_qdisc *qdisc)
-{
- return NULL;
+ memset(&opts, 0, sizeof(opts));
+ memset(&cor, 0, sizeof(cor));
+ memset(&reorder, 0, sizeof(reorder));
+ memset(&corrupt, 0, sizeof(corrupt));
+
+ netem = netem_qdisc(qdisc);
+ if (!netem || !msg)
+ return EFAULT;
+
+ msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST;
+
+ if ( netem->qnm_ro.nmro_probability != 0 ) {
+ if (netem->qnm_latency == 0) {
+ return -NLE_MISSING_ATTR;
+ }
+ if (netem->qnm_gap == 0) netem->qnm_gap = 1;
+ }
+ else if ( netem->qnm_gap ) {
+ return -NLE_MISSING_ATTR;
+ }
+
+ if ( netem->qnm_corr.nmc_delay != 0 ) {
+ if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
+ return -NLE_MISSING_ATTR;
+ }
+ set_correlation = 1;
+ }
+
+ if ( netem->qnm_corr.nmc_loss != 0 ) {
+ if ( netem->qnm_loss == 0 ) {
+ return -NLE_MISSING_ATTR;
+ }
+ set_correlation = 1;
+ }
+
+ if ( netem->qnm_corr.nmc_duplicate != 0 ) {
+ if ( netem->qnm_duplicate == 0 ) {
+ return -NLE_MISSING_ATTR;
+ }
+ set_correlation = 1;
+ }
+
+ if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1;
+ else if ( netem->qnm_ro.nmro_correlation != 0 ) {
+ return -NLE_MISSING_ATTR;
+ }
+
+ if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1;
+ else if ( netem->qnm_crpt.nmcr_correlation != 0 ) {
+ return -NLE_MISSING_ATTR;
+ }
+
+ if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) {
+ if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
+ return -NLE_MISSING_ATTR;
+ }
+ else {
+ /* Resize to accomodate the large distribution table */
+ int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size *
+ sizeof(netem->qnm_dist.dist_data[0]);
+
+ msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len);
+ if ( msg->nm_nlh == NULL )
+ return -NLE_NOMEM;
+ msg->nm_size = new_msg_len;
+ set_dist = 1;
+ }
+ }
+
+ opts.latency = netem->qnm_latency;
+ opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000;
+ opts.loss = netem->qnm_loss;
+ opts.gap = netem->qnm_gap;
+ opts.duplicate = netem->qnm_duplicate;
+ opts.jitter = netem->qnm_jitter;
+
+ NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts);
+
+ if ( set_correlation ) {
+ cor.delay_corr = netem->qnm_corr.nmc_delay;
+ cor.loss_corr = netem->qnm_corr.nmc_loss;
+ cor.dup_corr = netem->qnm_corr.nmc_duplicate;
+
+ NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor);
+ }
+
+ if ( set_reorder ) {
+ reorder.probability = netem->qnm_ro.nmro_probability;
+ reorder.correlation = netem->qnm_ro.nmro_correlation;
+
+ NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
+ }
+
+ if ( set_corrupt ) {
+ corrupt.probability = netem->qnm_crpt.nmcr_probability;
+ corrupt.correlation = netem->qnm_crpt.nmcr_correlation;
+
+ NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
+ }
+
+ if ( set_dist ) {
+ NLA_PUT(msg, TCA_NETEM_DELAY_DIST,
+ netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]),
+ netem->qnm_dist.dist_data);
+ }
+
+ /* Length specified in the TCA_OPTIONS section must span the entire
+ * remainder of the message. That's just the way that sch_netem expects it.
+ * Maybe there's a more succinct way to do this at a higher level.
+ */
+ struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) +
+ NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO);
+
+ struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) +
+ NLMSG_ALIGN(msg->nm_nlh->nlmsg_len));
+
+ int old_len = head->nla_len;
+ head->nla_len = (void *)tail - (void *)head;
+ msg->nm_nlh->nlmsg_len += (head->nla_len - old_len);
+
+ return err;
+nla_put_failure:
+ return -NLE_MSGSIZE;
}
/**
@@ -168,7 +322,7 @@ int rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_limit = limit;
netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT;
@@ -189,7 +343,7 @@ int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT))
return netem->qnm_limit;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/** @} */
@@ -211,7 +365,7 @@ int rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_gap = gap;
netem->qnm_mask |= SCH_NETEM_ATTR_GAP;
@@ -232,7 +386,7 @@ int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_GAP))
return netem->qnm_gap;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -247,7 +401,7 @@ int rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_ro.nmro_probability = prob;
netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB;
@@ -268,7 +422,7 @@ int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB))
return netem->qnm_ro.nmro_probability;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -283,7 +437,7 @@ int rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_ro.nmro_correlation = prob;
netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR;
@@ -304,7 +458,86 @@ int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR))
return netem->qnm_ro.nmro_correlation;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Corruption
+ * @{
+ */
+
+/**
+ * Set corruption probability of netem qdisc.
+ * @arg qdisc Netem qdisc to be modified.
+ * @arg prob New corruption probability.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob)
+{
+ struct rtnl_netem *netem;
+
+ netem = netem_alloc(qdisc);
+ if (!netem)
+ return -NLE_NOMEM;
+
+ netem->qnm_crpt.nmcr_probability = prob;
+ netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB;
+
+ return 0;
+}
+
+/**
+ * Get corruption probability of netem qdisc.
+ * @arg qdisc Netem qdisc.
+ * @return Corruption probability or a negative error code.
+ */
+int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_netem *netem;
+
+ netem = netem_qdisc(qdisc);
+ if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB))
+ return netem->qnm_crpt.nmcr_probability;
+ else
+ return -NLE_NOATTR;
+}
+
+/**
+ * Set corruption correlation probability of netem qdisc.
+ * @arg qdisc Netem qdisc to be modified.
+ * @arg prob New corruption correlation probability.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+ struct rtnl_netem *netem;
+
+ netem = netem_alloc(qdisc);
+ if (!netem)
+ return -NLE_NOMEM;
+
+ netem->qnm_crpt.nmcr_correlation = prob;
+ netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR;
+
+ return 0;
+}
+
+/**
+ * Get corruption correlation probability of netem qdisc.
+ * @arg qdisc Netem qdisc.
+ * @return Corruption correlation probability or a negative error code.
+ */
+int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_netem *netem;
+
+ netem = netem_qdisc(qdisc);
+ if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR))
+ return netem->qnm_crpt.nmcr_correlation;
+ else
+ return -NLE_NOATTR;
}
/** @} */
@@ -326,7 +559,7 @@ int rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_loss = prob;
netem->qnm_mask |= SCH_NETEM_ATTR_LOSS;
@@ -347,7 +580,7 @@ int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS))
return netem->qnm_loss;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -362,7 +595,7 @@ int rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_corr.nmc_loss = prob;
netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR;
@@ -383,7 +616,7 @@ int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR))
return netem->qnm_corr.nmc_loss;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/** @} */
@@ -405,7 +638,7 @@ int rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_duplicate = prob;
netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE;
@@ -426,7 +659,7 @@ int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE))
return netem->qnm_duplicate;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -441,7 +674,7 @@ int rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_corr.nmc_duplicate = prob;
netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR;
@@ -462,7 +695,7 @@ int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR))
return netem->qnm_corr.nmc_duplicate;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/** @} */
@@ -484,7 +717,7 @@ int rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_latency = nl_us2ticks(delay);
netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY;
@@ -505,7 +738,7 @@ int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY))
return nl_ticks2us(netem->qnm_latency);
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -520,7 +753,7 @@ int rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_jitter = nl_us2ticks(jitter);
netem->qnm_mask |= SCH_NETEM_ATTR_JITTER;
@@ -541,7 +774,7 @@ int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_JITTER))
return nl_ticks2us(netem->qnm_jitter);
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -555,7 +788,7 @@ int rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob)
netem = netem_alloc(qdisc);
if (!netem)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
netem->qnm_corr.nmc_delay = prob;
netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR;
@@ -576,7 +809,110 @@ int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc)
if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR))
return netem->qnm_corr.nmc_delay;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
+}
+
+/**
+ * Get the size of the distribution table.
+ * @arg qdisc Netem qdisc.
+ * @return Distribution table size or a negative error code.
+ */
+int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_netem *netem;
+
+ netem = netem_qdisc(qdisc);
+ if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DIST))
+ return netem->qnm_dist.dist_size;
+ else
+ return -NLE_NOATTR;
+}
+
+/**
+ * Get a pointer to the distribution table.
+ * @arg qdisc Netem qdisc.
+ * @arg dist_ptr The pointer to set.
+ * @return Negative error code on failure or 0 on success.
+ */
+int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr)
+{
+ struct rtnl_netem *netem;
+
+ netem = netem_qdisc(qdisc);
+ if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DIST)) {
+ *dist_ptr = netem->qnm_dist.dist_data;
+ return 0;
+ }
+ else
+ return -NLE_NOATTR;
+}
+
+/**
+ * Set the delay distribution. Latency/jitter must be set before applying.
+ * @arg qdisc Netem qdisc.
+ * @arg dist_type The name of the distribution (type, file, path/file).
+ * @return 0 on success, error code on failure.
+ */
+int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) {
+ struct rtnl_netem *netem;
+
+ netem = netem_alloc(qdisc);
+ if (!netem)
+ return -NLE_NOMEM;
+
+ FILE *f = NULL;
+ int i, n = 0;
+ size_t len = 2048;
+ char *line;
+ char name[NAME_MAX];
+ char dist_suffix[] = ".dist";
+
+ /* If the given filename already ends in .dist, don't append it later */
+ char *test_suffix = strstr(dist_type, dist_suffix);
+ if (test_suffix != NULL && strlen(test_suffix) == 5)
+ strcpy(dist_suffix, "");
+
+ /* Check several locations for the dist file */
+ char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" };
+
+ for (i = 0; i < sizeof(test_path) && f == NULL; i++) {
+ snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix);
+ f = fopen(name, "r");
+ }
+
+ if ( f == NULL )
+ return -nl_syserr2nlerr(errno);
+
+ netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
+
+ line = (char *) calloc (sizeof(char), len + 1);
+
+ while (getline(&line, &len, f) != -1) {
+ char *p, *endp;
+
+ if (*line == '\n' || *line == '#')
+ continue;
+
+ for (p = line; ; p = endp) {
+ long x = strtol(p, &endp, 0);
+ if (endp == p) break;
+
+ if (n >= MAXDIST) {
+ free(line);
+ fclose(f);
+ return -NLE_INVAL;
+ }
+ netem->qnm_dist.dist_data[n++] = x;
+ }
+ }
+
+ free(line);
+
+ netem->qnm_dist.dist_size = n;
+ netem->qnm_mask |= SCH_NETEM_ATTR_DIST;
+
+ fclose(f);
+ return 0;
}
/** @} */
@@ -585,9 +921,9 @@ static struct rtnl_qdisc_ops netem_ops = {
.qo_kind = "netem",
.qo_msg_parser = netem_msg_parser,
.qo_free_data = netem_free_data,
- .qo_dump[NL_DUMP_BRIEF] = netem_dump_brief,
- .qo_dump[NL_DUMP_FULL] = netem_dump_full,
- .qo_get_opts = netem_get_opts,
+ .qo_dump[NL_DUMP_LINE] = netem_dump_line,
+ .qo_get_opts = 0,
+ .qo_build_msg = netem_build_msg
};
static void __init netem_init(void)
diff --git a/lib/route/sch/prio.c b/lib/route/sch/prio.c
index 4e3d624..4c9ebcf 100644
--- a/lib/route/sch/prio.c
+++ b/lib/route/sch/prio.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>
*/
/**
@@ -58,11 +58,11 @@ static int prio_msg_parser(struct rtnl_qdisc *qdisc)
struct tc_prio_qopt *opt;
if (qdisc->q_opts->d_size < sizeof(*opt))
- return nl_error(EINVAL, "prio specific option size mismatch");
+ return -NLE_INVAL;
prio = prio_alloc(qdisc);
if (!prio)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
opt = (struct tc_prio_qopt *) qdisc->q_opts->d_data;
prio->qp_bands = opt->bands;
@@ -77,55 +77,48 @@ static void prio_free_data(struct rtnl_qdisc *qdisc)
free(qdisc->q_subdata);
}
-static int prio_dump_brief(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void prio_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_prio *prio = prio_qdisc(qdisc);
if (prio)
- dp_dump(p, " bands %u", prio->qp_bands);
-
- return line;
+ nl_dump(p, " bands %u", prio->qp_bands);
}
-static int prio_dump_full(struct rtnl_qdisc *qdisc,
- struct nl_dump_params *p, int line)
+static void prio_dump_details(struct rtnl_qdisc *qdisc,struct nl_dump_params *p)
{
struct rtnl_prio *prio = prio_qdisc(qdisc);
int i, hp;
if (!prio)
- goto ignore;
+ return;
- dp_dump(p, "priomap [");
+ nl_dump(p, "priomap [");
for (i = 0; i <= TC_PRIO_MAX; i++)
- dp_dump(p, "%u%s", prio->qp_priomap[i],
+ nl_dump(p, "%u%s", prio->qp_priomap[i],
i < TC_PRIO_MAX ? " " : "");
- dp_dump(p, "]\n");
- dp_new_line(p, line++);
+ nl_dump(p, "]\n");
+ nl_new_line(p);
hp = (((TC_PRIO_MAX/2) + 1) & ~1);
for (i = 0; i < hp; i++) {
char a[32];
- dp_dump(p, " %18s => %u",
+ nl_dump(p, " %18s => %u",
rtnl_prio2str(i, a, sizeof(a)),
prio->qp_priomap[i]);
if (hp+i <= TC_PRIO_MAX) {
- dp_dump(p, " %18s => %u",
+ nl_dump(p, " %18s => %u",
rtnl_prio2str(hp+i, a, sizeof(a)),
prio->qp_priomap[hp+i]);
if (i < (hp - 1)) {
- dp_dump(p, "\n");
- dp_new_line(p, line++);
+ nl_dump(p, "\n");
+ nl_new_line(p);
}
}
}
-
-ignore:
- return line;
}
static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc)
@@ -173,7 +166,7 @@ int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
prio = prio_alloc(qdisc);
if (!prio)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
prio->qp_bands = bands;
prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
@@ -194,7 +187,7 @@ int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS)
return prio->qp_bands;
else
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
}
/**
@@ -212,18 +205,17 @@ int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
prio = prio_alloc(qdisc);
if (!prio)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
- return nl_error(EINVAL, "Set number of bands first");
+ return -NLE_MISSING_ATTR;
if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
- return nl_error(ERANGE, "priomap length out of bounds");
+ return -NLE_RANGE;
for (i = 0; i <= TC_PRIO_MAX; i++) {
if (priomap[i] > prio->qp_bands)
- return nl_error(ERANGE, "priomap element %d " \
- "out of bounds, increase bands number");
+ return -NLE_RANGE;
}
memcpy(prio->qp_priomap, priomap, len);
@@ -245,10 +237,8 @@ uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
prio = prio_qdisc(qdisc);
if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
return prio->qp_priomap;
- else {
- nl_errno(ENOENT);
+ else
return NULL;
- }
}
/** @} */
@@ -303,8 +293,10 @@ static struct rtnl_qdisc_ops prio_ops = {
.qo_kind = "prio",
.qo_msg_parser = prio_msg_parser,
.qo_free_data = prio_free_data,
- .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief,
- .qo_dump[NL_DUMP_FULL] = prio_dump_full,
+ .qo_dump = {
+ [NL_DUMP_LINE] = prio_dump_line,
+ [NL_DUMP_DETAILS] = prio_dump_details,
+ },
.qo_get_opts = prio_get_opts,
};
@@ -312,8 +304,10 @@ static struct rtnl_qdisc_ops pfifo_fast_ops = {
.qo_kind = "pfifo_fast",
.qo_msg_parser = prio_msg_parser,
.qo_free_data = prio_free_data,
- .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief,
- .qo_dump[NL_DUMP_FULL] = prio_dump_full,
+ .qo_dump = {
+ [NL_DUMP_LINE] = prio_dump_line,
+ [NL_DUMP_DETAILS] = prio_dump_details,
+ },
.qo_get_opts = prio_get_opts,
};
diff --git a/lib/route/sch/red.c b/lib/route/sch/red.c
index a31c358..e4cac79 100644
--- a/lib/route/sch/red.c
+++ b/lib/route/sch/red.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>
*/
/**
@@ -66,11 +66,11 @@ static int red_msg_parser(struct rtnl_qdisc *qdisc)
return err;
if (!tb[TCA_RED_PARMS])
- return nl_error(EINVAL, "Missing TCA_RED_PARMS");
+ return -NLE_MISSING_ATTR;
red = red_alloc(qdisc);
if (!red)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
opts = nla_data(tb[TCA_RED_PARMS]);
@@ -89,40 +89,31 @@ static int red_msg_parser(struct rtnl_qdisc *qdisc)
return 0;
}
-static int red_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void red_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_red *red = red_qdisc(qdisc);
if (red) {
/* XXX: limit, min, max, flags */
}
-
- return line;
}
-static int red_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void red_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_red *red = red_qdisc(qdisc);
if (red) {
/* XXX: wlog, plog, scell_log */
}
-
- return line;
}
-static int red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_red *red = red_qdisc(qdisc);
if (red) {
/* XXX: xstats */
}
-
- return line;
}
static struct nl_msg *red_get_opts(struct rtnl_qdisc *qdisc)
@@ -171,7 +162,7 @@ int rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit)
red = red_alloc(qdisc);
if (!red)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
red->qr_limit = limit;
red->qr_mask |= RED_ATTR_LIMIT;
@@ -192,7 +183,7 @@ int rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
if (red && (red->qr_mask & RED_ATTR_LIMIT))
return red->qr_limit;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/** @} */
@@ -200,9 +191,11 @@ int rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
static struct rtnl_qdisc_ops red_ops = {
.qo_kind = "red",
.qo_msg_parser = red_msg_parser,
- .qo_dump[NL_DUMP_BRIEF] = red_dump_brief,
- .qo_dump[NL_DUMP_FULL] = red_dump_full,
- .qo_dump[NL_DUMP_STATS] = red_dump_stats,
+ .qo_dump = {
+ [NL_DUMP_LINE] = red_dump_line,
+ [NL_DUMP_DETAILS] = red_dump_details,
+ [NL_DUMP_STATS] = red_dump_stats,
+ },
.qo_get_opts = red_get_opts,
};
diff --git a/lib/route/sch/sfq.c b/lib/route/sch/sfq.c
index d530c0f..4b47356 100644
--- a/lib/route/sch/sfq.c
+++ b/lib/route/sch/sfq.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>
*/
/**
@@ -61,11 +61,11 @@ static int sfq_msg_parser(struct rtnl_qdisc *qdisc)
return 0;
if (qdisc->q_opts->d_size < sizeof(*opts))
- return nl_error(EINVAL, "SFQ specific options size mismatch");
+ return -NLE_INVAL;
sfq = sfq_alloc(qdisc);
if (!sfq)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data;
@@ -87,29 +87,22 @@ static void sfq_free_data(struct rtnl_qdisc *qdisc)
free(qdisc->q_subdata);
}
-static int sfq_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void sfq_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
if (sfq)
- dp_dump(p, " quantum %u perturb %us",
- sfq->qs_quantum,
+ nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum,
nl_ticks2us(sfq->qs_perturb * nl_get_hz()));
-
- return line;
}
-static int sfq_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void sfq_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
if (sfq)
- dp_dump(p, "limit %u divisor %u",
+ nl_dump(p, "limit %u divisor %u",
sfq->qs_limit, sfq->qs_divisor);
-
- return line;
}
static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc)
@@ -157,7 +150,7 @@ int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
sfq = sfq_alloc(qdisc);
if (!sfq)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
sfq->qs_quantum = quantum;
sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
@@ -178,7 +171,7 @@ int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
return sfq->qs_quantum;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -193,7 +186,7 @@ int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
sfq = sfq_alloc(qdisc);
if (!sfq)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
sfq->qs_limit = limit;
sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
@@ -214,7 +207,7 @@ int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
return sfq->qs_limit;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -230,7 +223,7 @@ int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
sfq = sfq_alloc(qdisc);
if (!sfq)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
sfq->qs_perturb = perturb;
sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
@@ -251,7 +244,7 @@ int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
return sfq->qs_perturb;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/**
@@ -267,7 +260,7 @@ int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
return sfq->qs_divisor;
else
- return nl_errno(ENOENT);
+ return -NLE_NOATTR;
}
/** @} */
@@ -276,8 +269,10 @@ static struct rtnl_qdisc_ops sfq_ops = {
.qo_kind = "sfq",
.qo_msg_parser = sfq_msg_parser,
.qo_free_data = sfq_free_data,
- .qo_dump[NL_DUMP_BRIEF] = sfq_dump_brief,
- .qo_dump[NL_DUMP_FULL] = sfq_dump_full,
+ .qo_dump = {
+ [NL_DUMP_LINE] = sfq_dump_line,
+ [NL_DUMP_DETAILS] = sfq_dump_details,
+ },
.qo_get_opts = sfq_get_opts,
};
diff --git a/lib/route/sch/tbf.c b/lib/route/sch/tbf.c
index 04d1689..eccaf70 100644
--- a/lib/route/sch/tbf.c
+++ b/lib/route/sch/tbf.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>
*/
/**
@@ -62,9 +62,9 @@ static int tbf_msg_parser(struct rtnl_qdisc *q)
if (err < 0)
return err;
- tbf = tbf_qdisc(q);
+ tbf = tbf_alloc(q);
if (!tbf)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
if (tb[TCA_TBF_PARMS]) {
struct tc_tbf_qopt opts;
@@ -93,34 +93,34 @@ static int tbf_msg_parser(struct rtnl_qdisc *q)
return 0;
}
-static int tbf_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void tbf_free_data(struct rtnl_qdisc *qdisc)
+{
+ free(qdisc->q_subdata);
+}
+
+static void tbf_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
double r, rbit, lim;
char *ru, *rubit, *limu;
struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
if (!tbf)
- goto ignore;
+ return;
r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
- dp_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
+ nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
r, ru, rbit, rubit, lim, limu);
-
-ignore:
- return line;
}
-static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
- int line)
+static void tbf_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
{
struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
if (!tbf)
- goto ignore;
+ return;
if (1) {
char *bu, *cu;
@@ -128,7 +128,7 @@ static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
&cu);
- dp_dump(p, "mpu %u rate-bucket-size %1.f%s "
+ nl_dump(p, "mpu %u rate-bucket-size %1.f%s "
"rate-cell-size %.1f%s\n",
tbf->qt_mpu, bs, bu, cl, cu);
@@ -144,14 +144,11 @@ static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
&clu);
- dp_dump_line(p, line++, " peak-rate %.2f%s/s (%.0f%s) "
- "bucket-size %.1f%s cell-size %.1f%s",
- "latency %.1f%s",
+ nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) "
+ "bucket-size %.1f%s cell-size %.1f%s"
+ "latency %.1f%s",
pr, pru, prb, prbu, bs, bsu, cl, clu);
}
-
-ignore:
- return line;
}
static struct nl_msg *tbf_get_opts(struct rtnl_qdisc *qdisc)
@@ -226,7 +223,7 @@ int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
tbf = tbf_alloc(qdisc);
if (!tbf)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
tbf->qt_limit = limit;
tbf->qt_mask |= TBF_ATTR_LIMIT;
@@ -270,11 +267,10 @@ int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
tbf = tbf_alloc(qdisc);
if (!tbf)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
if (!(tbf->qt_mask & TBF_ATTR_RATE))
- return nl_error(EINVAL, "The rate must be specified before "
- "limit can be calculated based on latency.");
+ return -NLE_MISSING_ATTR;
limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
@@ -301,8 +297,8 @@ int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
tbf = tbf_qdisc(qdisc);
if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT))
return tbf->qt_limit;
- return
- nl_errno(ENOENT);
+ else
+ return -NLE_NOATTR;
}
/**
@@ -317,7 +313,7 @@ int rtnl_qdisc_tbf_set_mpu(struct rtnl_qdisc *qdisc, int mpu)
tbf = tbf_alloc(qdisc);
if (!tbf)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
tbf->qt_mpu = mpu;
tbf->qt_mask |= TBF_ATTR_MPU;
@@ -337,8 +333,8 @@ int rtnl_qdisc_tbf_get_mpu(struct rtnl_qdisc *qdisc)
tbf = tbf_qdisc(qdisc);
if (tbf && (tbf->qt_mask & TBF_ATTR_MPU))
return tbf->qt_mpu;
- return
- nl_errno(ENOENT);
+ else
+ return -NLE_NOATTR;
}
static inline int calc_cell_log(int cell, int bucket)
@@ -374,7 +370,7 @@ int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
tbf = tbf_alloc(qdisc);
if (!tbf)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
cell_log = calc_cell_log(cell, bucket);
if (cell_log < 0)
@@ -453,7 +449,7 @@ int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
tbf = tbf_alloc(qdisc);
if (!tbf)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
cell_log = calc_cell_log(cell, bucket);
if (cell_log < 0)
@@ -522,8 +518,11 @@ int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
static struct rtnl_qdisc_ops tbf_qdisc_ops = {
.qo_kind = "tbf",
.qo_msg_parser = tbf_msg_parser,
- .qo_dump[NL_DUMP_BRIEF] = tbf_dump_brief,
- .qo_dump[NL_DUMP_FULL] = tbf_dump_full,
+ .qo_dump = {
+ [NL_DUMP_LINE] = tbf_dump_line,
+ [NL_DUMP_DETAILS] = tbf_dump_details,
+ },
+ .qo_free_data = tbf_free_data,
.qo_get_opts = tbf_get_opts,
};
diff --git a/lib/route/tc.c b/lib/route/tc.c
index 1351fa2..97faef4 100644
--- a/lib/route/tc.c
+++ b/lib/route/tc.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>
*/
/**
@@ -66,7 +66,7 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g)
return err;
if (tb[TCA_KIND] == NULL)
- return nl_error(EINVAL, "Missing tca kind TLV");
+ return -NLE_MISSING_ATTR;
nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ);
@@ -81,9 +81,9 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g)
TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND);
if (tb[TCA_OPTIONS]) {
- g->tc_opts = nla_get_data(tb[TCA_OPTIONS]);
+ g->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
if (!g->tc_opts)
- return nl_errno(ENOMEM);
+ return -NLE_NOMEM;
g->ce_mask |= TCA_ATTR_OPTS;
}
@@ -126,9 +126,9 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g)
g->ce_mask |= TCA_ATTR_STATS;
if (tbs[TCA_STATS_APP]) {
- g->tc_xstats = nla_get_data(tbs[TCA_STATS_APP]);
+ g->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
if (g->tc_xstats == NULL)
- return -ENOMEM;
+ return -NLE_NOMEM;
} else
goto compat_xstats;
} else {
@@ -149,9 +149,9 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g)
compat_xstats:
if (tb[TCA_XSTATS]) {
- g->tc_xstats = nla_get_data(tb[TCA_XSTATS]);
+ g->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
if (g->tc_xstats == NULL)
- return -ENOMEM;
+ return -NLE_NOMEM;
g->ce_mask |= TCA_ATTR_XSTATS;
}
}
@@ -171,58 +171,53 @@ int tca_clone(struct rtnl_tca *dst, struct rtnl_tca *src)
if (src->tc_opts) {
dst->tc_opts = nl_data_clone(src->tc_opts);
if (!dst->tc_opts)
- goto errout;
+ return -NLE_NOMEM;
}
if (src->tc_xstats) {
dst->tc_xstats = nl_data_clone(src->tc_xstats);
if (!dst->tc_xstats)
- goto errout;
+ return -NLE_NOMEM;
}
return 0;
-errout:
- return nl_get_errno();
}
-int tca_dump_brief(struct rtnl_tca *g, const char *type,
- struct nl_dump_params *p, int line)
+void tca_dump_line(struct rtnl_tca *g, const char *type,
+ struct nl_dump_params *p)
{
char handle[32], parent[32];
struct nl_cache *link_cache;
link_cache = nl_cache_mngt_require("route/link");
- dp_dump(p, "%s %s ", g->tc_kind, type);
+ nl_dump_line(p, "%s %s ", g->tc_kind, type);
if (link_cache) {
char buf[32];
- dp_dump(p, "dev %s ",
+ nl_dump(p, "dev %s ",
rtnl_link_i2name(link_cache, g->tc_ifindex,
buf, sizeof(buf)));
} else
- dp_dump(p, "dev %u ", g->tc_ifindex);
+ nl_dump(p, "dev %u ", g->tc_ifindex);
- dp_dump(p, "handle %s parent %s",
+ nl_dump(p, "handle %s parent %s",
rtnl_tc_handle2str(g->tc_handle, handle, sizeof(handle)),
rtnl_tc_handle2str(g->tc_parent, parent, sizeof(parent)));
-
- return 1;
}
-int tca_dump_full(struct rtnl_tca *g, struct nl_dump_params *p, int line)
+void tca_dump_details(struct rtnl_tca *g, struct nl_dump_params *p)
{
- dp_dump_line(p, line++, " ");
- return line;
+ nl_dump_line(p, " ");
}
-int tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p, int line)
+void tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p)
{
char *unit, fmt[64];
float res;
strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n");
- dp_dump_line(p, line++,
+ nl_dump_line(p,
" Stats: bytes packets drops overlimits" \
" qlen backlog\n");
@@ -230,7 +225,7 @@ int tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p, int line)
if (*unit == 'B')
fmt[11] = '9';
- dp_dump_line(p, line++, fmt, res, unit,
+ nl_dump_line(p, fmt, res, unit,
g->tc_stats[RTNL_TC_PACKETS],
g->tc_stats[RTNL_TC_DROPS],
g->tc_stats[RTNL_TC_OVERLIMITS],
@@ -244,9 +239,7 @@ int tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p, int line)
if (*unit == 'B')
fmt[11] = '9';
- dp_dump_line(p, line++, fmt, res, unit, g->tc_stats[RTNL_TC_RATE_PPS]);
-
- return line;
+ nl_dump_line(p, fmt, res, unit, g->tc_stats[RTNL_TC_RATE_PPS]);
}
int tca_compare(struct nl_object *_a, struct nl_object *_b,
@@ -276,10 +269,7 @@ void tca_set_ifindex(struct rtnl_tca *t, int ifindex)
int tca_get_ifindex(struct rtnl_tca *t)
{
- if (t->ce_mask & TCA_ATTR_IFINDEX)
- return t->tc_ifindex;
- else
- return RTNL_LINK_NOT_FOUND;
+ return t->tc_ifindex;
}
void tca_set_handle(struct rtnl_tca *t, uint32_t handle)
@@ -332,7 +322,8 @@ uint64_t tca_get_stat(struct rtnl_tca *t, int id)
return t->tc_stats[id];
}
-struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags)
+int tca_build_msg(struct rtnl_tca *tca, int type, int flags,
+ struct nl_msg **result)
{
struct nl_msg *msg;
struct tcmsg tchdr = {
@@ -344,7 +335,7 @@ struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags)
msg = nlmsg_alloc_simple(type, flags);
if (!msg)
- goto nla_put_failure;
+ return -NLE_NOMEM;
if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
goto nla_put_failure;
@@ -352,11 +343,12 @@ struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags)
if (tca->ce_mask & TCA_ATTR_KIND)
NLA_PUT_STRING(msg, TCA_KIND, tca->tc_kind);
- return msg;
+ *result = msg;
+ return 0;
nla_put_failure:
nlmsg_free(msg);
- return NULL;
+ return -NLE_MSGSIZE;
}
/** @endcond */
@@ -425,7 +417,7 @@ int rtnl_tc_calc_cell_log(int cell_size)
if ((1 << i) == cell_size)
return i;
- return nl_errno(EINVAL);
+ return -NLE_INVAL;
}
@@ -546,13 +538,13 @@ int rtnl_tc_str2handle(const char *name, uint32_t *res)
/* :YYYY */
h = 0;
if (':' != *colon)
- return -EINVAL;
+ return -NLE_INVAL;
}
if (':' == *colon) {
/* check if we would lose bits */
if (TC_H_MAJ(h))
- return -ERANGE;
+ return -NLE_RANGE;
h <<= 16;
if ('\0' == colon[1]) {
@@ -564,10 +556,10 @@ int rtnl_tc_str2handle(const char *name, uint32_t *res)
/* check if we overlap with major part */
if (TC_H_MAJ(l))
- return -ERANGE;
+ return -NLE_RANGE;
if ('\0' != *end)
- return -EINVAL;
+ return -NLE_INVAL;
*res = (h | l);
}
@@ -575,7 +567,7 @@ int rtnl_tc_str2handle(const char *name, uint32_t *res)
/* XXXXYYYY */
*res = h;
} else
- return -EINVAL;
+ return -NLE_INVAL;
return 0;
}