summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2011-05-03 11:48:14 +0200
committerThomas Graf <tgraf@suug.ch>2011-05-03 11:48:14 +0200
commitd44c31da5f089372f911d498a5051dd7f7c25e3a (patch)
tree46a3a0d70235d3472231f51e63797ad4419dda21
parentcb6a089d80df51f8bcd1a1cf6637174fdf483954 (diff)
downloadlibnl-d44c31da5f089372f911d498a5051dd7f7c25e3a.tar.gz
addr: store link object and provide rtnl_addr_get()
stores rtnl_link object in address if cache is availble. Provide access via rtnl_addr_get_link() and rtnl_addr_set_link(). Add rtnl_addr_get() which searches a address cache for an address matching ifindex and local address.
-rw-r--r--include/netlink-types.h1
-rw-r--r--include/netlink/route/addr.h8
-rw-r--r--lib/route/addr.c78
3 files changed, 85 insertions, 2 deletions
diff --git a/include/netlink-types.h b/include/netlink-types.h
index 1cb7c0e..f842187 100644
--- a/include/netlink-types.h
+++ b/include/netlink-types.h
@@ -234,6 +234,7 @@ struct rtnl_addr
char a_label[IFNAMSIZ];
uint32_t a_flag_mask;
+ struct rtnl_link *a_link;
};
struct rtnl_nexthop
diff --git a/include/netlink/route/addr.h b/include/netlink/route/addr.h
index 1381486..df447f7 100644
--- a/include/netlink/route/addr.h
+++ b/include/netlink/route/addr.h
@@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
* Mediatrix Telecom, inc. <ericb@mediatrix.com>
*/
@@ -29,6 +29,8 @@ extern struct rtnl_addr *rtnl_addr_alloc(void);
extern void rtnl_addr_put(struct rtnl_addr *);
extern int rtnl_addr_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern struct rtnl_addr *
+ rtnl_addr_get(struct nl_cache *, int, struct nl_addr *);
extern int rtnl_addr_build_add_request(struct rtnl_addr *, int,
struct nl_msg **);
@@ -48,6 +50,10 @@ extern char * rtnl_addr_get_label(struct rtnl_addr *);
extern void rtnl_addr_set_ifindex(struct rtnl_addr *, int);
extern int rtnl_addr_get_ifindex(struct rtnl_addr *);
+extern void rtnl_addr_set_link(struct rtnl_addr *, struct rtnl_link *);
+extern struct rtnl_link *
+ rtnl_addr_get_link(struct rtnl_addr *);
+
extern void rtnl_addr_set_family(struct rtnl_addr *, int);
extern int rtnl_addr_get_family(struct rtnl_addr *);
diff --git a/lib/route/addr.c b/lib/route/addr.c
index b367883..fa6d76d 100644
--- a/lib/route/addr.c
+++ b/lib/route/addr.c
@@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
* Mediatrix Telecom, inc. <ericb@mediatrix.com>
*/
@@ -158,6 +158,11 @@ static int addr_clone(struct nl_object *_dst, struct nl_object *_src)
struct rtnl_addr *dst = nl_object_priv(_dst);
struct rtnl_addr *src = nl_object_priv(_src);
+ if (src->a_link) {
+ nl_object_get(OBJ_CAST(src->a_link));
+ dst->a_link = src->a_link;
+ }
+
if (src->a_peer)
if (!(dst->a_peer = nl_addr_clone(src->a_peer)))
return -NLE_NOMEM;
@@ -194,6 +199,7 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct ifaddrmsg *ifa;
struct nlattr *tb[IFA_MAX+1];
int err, peer_prefix = 0, family;
+ struct nl_cache *link_cache;
addr = rtnl_addr_alloc();
if (!addr)
@@ -288,6 +294,17 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
addr->ce_mask |= ADDR_ATTR_ANYCAST;
}
+ if ((link_cache = nl_cache_mngt_require("route/link"))) {
+ struct rtnl_link *link;
+
+ if ((link = rtnl_link_get(link_cache, addr->a_ifindex))) {
+ rtnl_addr_set_link(addr, link);
+
+ /* rtnl_addr_set_link incs refcnt */
+ rtnl_link_put(link);
+ }
+ }
+
err = pp->pp_cb((struct nl_object *) addr, pp);
errout:
rtnl_addr_put(addr);
@@ -478,6 +495,42 @@ int rtnl_addr_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
return nl_cache_alloc_and_fill(&rtnl_addr_ops, sk, result);
}
+/**
+ * Search address in cache
+ * @arg cache Address cache
+ * @arg ifindex Interface index of address
+ * @arg addr Local address part
+ *
+ * Searches address cache previously allocated with rtnl_addr_alloc_cache()
+ * for an address with a matching local address.
+ *
+ * The reference counter is incremented before returning the address, therefore
+ * the reference must be given back with rtnl_addr_put() after usage.
+ *
+ * @return Address object or NULL if no match was found.
+ */
+struct rtnl_addr *rtnl_addr_get(struct nl_cache *cache, int ifindex,
+ struct nl_addr *addr)
+{
+ struct rtnl_addr *a;
+
+ if (cache->c_ops != &rtnl_addr_ops)
+ return NULL;
+
+ nl_list_for_each_entry(a, &cache->c_items, ce_list) {
+ if (ifindex && a->a_ifindex != ifindex)
+ continue;
+
+ if (a->ce_mask & ADDR_ATTR_LOCAL &&
+ !nl_addr_cmp(a->a_local, addr)) {
+ nl_object_get((struct nl_object *) a);
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
/** @} */
static int build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags,
@@ -719,6 +772,29 @@ int rtnl_addr_get_ifindex(struct rtnl_addr *addr)
return addr->a_ifindex;
}
+void rtnl_addr_set_link(struct rtnl_addr *addr, struct rtnl_link *link)
+{
+ rtnl_link_put(addr->a_link);
+
+ if (!link)
+ return;
+
+ nl_object_get(OBJ_CAST(link));
+ addr->a_link = link;
+ addr->a_ifindex = link->l_index;
+ addr->ce_mask |= ADDR_ATTR_IFINDEX;
+}
+
+struct rtnl_link *rtnl_addr_get_link(struct rtnl_addr *addr)
+{
+ if (addr->a_link) {
+ nl_object_get(OBJ_CAST(addr->a_link));
+ return addr->a_link;
+ }
+
+ return NULL;
+}
+
void rtnl_addr_set_family(struct rtnl_addr *addr, int family)
{
addr->a_family = family;