ip: nexthop: add cache helpers
Add a static nexthop cache in a hash with 1024 buckets and helpers to manage it (link, unlink, find, add nexthop, del nexthop). Adding new nexthops is done by creating a new rtnl handle and using it to retrieve the nexthop so the helper is safe to use while already reading a response (i.e. using the global rth). Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com> Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
parent
53d7c43bd3
commit
60a9703032
|
|
@ -34,6 +34,8 @@ enum {
|
||||||
#define RTM_NHA(h) ((struct rtattr *)(((char *)(h)) + \
|
#define RTM_NHA(h) ((struct rtattr *)(((char *)(h)) + \
|
||||||
NLMSG_ALIGN(sizeof(struct nhmsg))))
|
NLMSG_ALIGN(sizeof(struct nhmsg))))
|
||||||
|
|
||||||
|
static struct hlist_head nh_cache[NH_CACHE_SIZE];
|
||||||
|
|
||||||
static void usage(void) __attribute__((noreturn));
|
static void usage(void) __attribute__((noreturn));
|
||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
|
|
@ -504,6 +506,102 @@ static int __ipnh_get_id(struct rtnl_handle *rthp, __u32 nh_id,
|
||||||
return rtnl_talk(rthp, &req.n, answer);
|
return rtnl_talk(rthp, &req.n, answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct hlist_head *ipnh_cache_head(__u32 nh_id)
|
||||||
|
{
|
||||||
|
nh_id ^= nh_id >> 20;
|
||||||
|
nh_id ^= nh_id >> 10;
|
||||||
|
|
||||||
|
return &nh_cache[nh_id % NH_CACHE_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ipnh_cache_link_entry(struct nh_entry *nhe)
|
||||||
|
{
|
||||||
|
struct hlist_head *head = ipnh_cache_head(nhe->nh_id);
|
||||||
|
|
||||||
|
hlist_add_head(&nhe->nh_hash, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ipnh_cache_unlink_entry(struct nh_entry *nhe)
|
||||||
|
{
|
||||||
|
hlist_del(&nhe->nh_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nh_entry *ipnh_cache_get(__u32 nh_id)
|
||||||
|
{
|
||||||
|
struct hlist_head *head = ipnh_cache_head(nh_id);
|
||||||
|
struct nh_entry *nhe;
|
||||||
|
struct hlist_node *n;
|
||||||
|
|
||||||
|
hlist_for_each(n, head) {
|
||||||
|
nhe = container_of(n, struct nh_entry, nh_hash);
|
||||||
|
if (nhe->nh_id == nh_id)
|
||||||
|
return nhe;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __ipnh_cache_parse_nlmsg(const struct nlmsghdr *n,
|
||||||
|
struct nh_entry *nhe)
|
||||||
|
{
|
||||||
|
int err, len;
|
||||||
|
|
||||||
|
len = n->nlmsg_len - NLMSG_SPACE(sizeof(struct nhmsg));
|
||||||
|
if (len < 0) {
|
||||||
|
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ipnh_parse_nhmsg(stderr, NLMSG_DATA(n), len, nhe);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "Error parsing nexthop: %s\n", strerror(-err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nh_entry *ipnh_cache_add(__u32 nh_id)
|
||||||
|
{
|
||||||
|
struct rtnl_handle cache_rth = { .fd = -1 };
|
||||||
|
struct nlmsghdr *answer = NULL;
|
||||||
|
struct nh_entry *nhe = NULL;
|
||||||
|
|
||||||
|
if (rtnl_open(&cache_rth, 0) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (__ipnh_get_id(&cache_rth, nh_id, &answer) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
nhe = malloc(sizeof(*nhe));
|
||||||
|
if (!nhe)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (__ipnh_cache_parse_nlmsg(answer, nhe))
|
||||||
|
goto out_free_nhe;
|
||||||
|
|
||||||
|
ipnh_cache_link_entry(nhe);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (answer)
|
||||||
|
free(answer);
|
||||||
|
rtnl_close(&cache_rth);
|
||||||
|
|
||||||
|
return nhe;
|
||||||
|
|
||||||
|
out_free_nhe:
|
||||||
|
free(nhe);
|
||||||
|
nhe = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ipnh_cache_del(struct nh_entry *nhe)
|
||||||
|
{
|
||||||
|
ipnh_cache_unlink_entry(nhe);
|
||||||
|
ipnh_destroy_entry(nhe);
|
||||||
|
free(nhe);
|
||||||
|
}
|
||||||
|
|
||||||
int print_nexthop(struct nlmsghdr *n, void *arg)
|
int print_nexthop(struct nlmsghdr *n, void *arg)
|
||||||
{
|
{
|
||||||
struct nhmsg *nhm = NLMSG_DATA(n);
|
struct nhmsg *nhm = NLMSG_DATA(n);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
#ifndef __NH_COMMON_H__
|
#ifndef __NH_COMMON_H__
|
||||||
#define __NH_COMMON_H__ 1
|
#define __NH_COMMON_H__ 1
|
||||||
|
|
||||||
|
#include <list.h>
|
||||||
|
|
||||||
|
#define NH_CACHE_SIZE 1024
|
||||||
|
|
||||||
struct nha_res_grp {
|
struct nha_res_grp {
|
||||||
__u16 buckets;
|
__u16 buckets;
|
||||||
__u32 idle_timer;
|
__u32 idle_timer;
|
||||||
|
|
@ -10,6 +14,8 @@ struct nha_res_grp {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nh_entry {
|
struct nh_entry {
|
||||||
|
struct hlist_node nh_hash;
|
||||||
|
|
||||||
__u32 nh_id;
|
__u32 nh_id;
|
||||||
__u32 nh_oif;
|
__u32 nh_oif;
|
||||||
__u32 nh_flags;
|
__u32 nh_flags;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue