summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/rt-table.c49
1 files changed, 46 insertions, 3 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index a934d3c3..f6d2ca0f 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -4831,6 +4831,39 @@ rt_update_hostcache(void *data)
rt_schedule_nhu(dst);
}
+struct hostentry_tmp_lock {
+ resource r;
+ rtable *tab;
+ struct hostentry *he;
+};
+
+static void
+hostentry_tmp_unlock(resource *r)
+{
+ struct hostentry_tmp_lock *l = SKIP_BACK(struct hostentry_tmp_lock, r, r);
+ RT_LOCKED(l->tab, tab)
+ {
+ l->he->uc--;
+ rt_unlock_table(tab);
+ }
+}
+
+static void
+hostentry_tmp_lock_dump(resource *r, unsigned indent UNUSED)
+{
+ struct hostentry_tmp_lock *l = SKIP_BACK(struct hostentry_tmp_lock, r, r);
+ debug("he=%p tab=%s\n", l->he, l->tab->name);
+}
+
+struct resclass hostentry_tmp_lock_class = {
+ .name = "Temporary hostentry lock",
+ .size = sizeof(struct hostentry_tmp_lock),
+ .free = hostentry_tmp_unlock,
+ .dump = hostentry_tmp_lock_dump,
+ .lookup = NULL,
+ .memsize = NULL,
+};
+
static struct hostentry *
rt_get_hostentry(struct rtable_private *tab, ip_addr a, ip_addr ll, rtable *dep)
{
@@ -4844,10 +4877,20 @@ rt_get_hostentry(struct rtable_private *tab, ip_addr a, ip_addr ll, rtable *dep)
struct hostcache *hc = tab->hostcache;
for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next)
if (ipa_equal(he->addr, a) && ipa_equal(he->link, link) && (he->tab == dep))
- return he;
+ break;
+
+ if (!he)
+ {
+ he = hc_new_hostentry(hc, tab->rp, a, link, dep, k);
+ rt_update_hostentry(tab, he);
+ }
+
+ struct hostentry_tmp_lock *l = ralloc(tmp_res.pool, &hostentry_tmp_lock_class);
+ l->he = he;
+ l->tab = RT_PUB(tab);
+ l->he->uc++;
+ rt_lock_table(tab);
- he = hc_new_hostentry(hc, tab->rp, a, link, dep, k);
- rt_update_hostentry(tab, he);
return he;
}