From d44c31da5f089372f911d498a5051dd7f7c25e3a Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 3 May 2011 11:48:14 +0200 Subject: 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. --- include/netlink-types.h | 1 + include/netlink/route/addr.h | 8 ++++- lib/route/addr.c | 78 +++++++++++++++++++++++++++++++++++++++++++- 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 + * Copyright (c) 2003-2011 Thomas Graf * Copyright (c) 2003-2006 Baruch Even , * Mediatrix Telecom, inc. */ @@ -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 + * Copyright (c) 2003-2011 Thomas Graf * Copyright (c) 2003-2006 Baruch Even , * Mediatrix Telecom, inc. */ @@ -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; -- cgit v1.2.1