summaryrefslogtreecommitdiff
path: root/nest/rt-attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'nest/rt-attr.c')
-rw-r--r--nest/rt-attr.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index ce6fe85d..c1f9c793 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -57,9 +57,65 @@
pool *rta_pool;
static slab *rta_slab;
+static slab *mpnh_slab;
struct protocol *attr_class_to_protocol[EAP_MAX];
+static inline unsigned int
+mpnh_hash(struct mpnh *x)
+{
+ unsigned int h = 0;
+ for (; x; x = x->next)
+ h ^= ipa_hash(x->gw);
+
+ return h;
+}
+
+int
+mpnh__same(struct mpnh *x, struct mpnh *y)
+{
+ for (; x && y; x = x->next, y = y->next)
+ if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight))
+ return 0;
+
+ return x == y;
+}
+
+static struct mpnh *
+mpnh_copy(struct mpnh *o)
+{
+ struct mpnh *first = NULL;
+ struct mpnh **last = &first;
+
+ for (; o; o = o->next)
+ {
+ struct mpnh *n = sl_alloc(mpnh_slab);
+ n->gw = o->gw;
+ n->iface = o->iface;
+ n->next = NULL;
+ n->weight = o->weight;
+
+ *last = n;
+ last = &(n->next);
+ }
+
+ return first;
+}
+
+static void
+mpnh_free(struct mpnh *o)
+{
+ struct mpnh *n;
+
+ while (o)
+ {
+ n = o->next;
+ sl_free(mpnh_slab, o);
+ o = n;
+ }
+}
+
+
/*
* Extended Attributes
*/
@@ -587,7 +643,8 @@ rta_alloc_hash(void)
static inline unsigned int
rta_hash(rta *a)
{
- return (a->proto->hash_key ^ ipa_hash(a->gw) ^ ea_hash(a->eattrs)) & 0xffff;
+ return (a->proto->hash_key ^ ipa_hash(a->gw) ^
+ mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
}
static inline int
@@ -604,6 +661,7 @@ rta_same(rta *x, rta *y)
ipa_equal(x->from, y->from) &&
x->iface == y->iface &&
x->hostentry == y->hostentry &&
+ mpnh_same(x->nexthops, y->nexthops) &&
ea_same(x->eattrs, y->eattrs));
}
@@ -614,6 +672,7 @@ rta_copy(rta *o)
memcpy(r, o, sizeof(rta));
r->uc = 1;
+ r->nexthops = mpnh_copy(o->nexthops);
r->eattrs = ea_list_copy(o->eattrs);
return r;
}
@@ -707,6 +766,7 @@ rta__free(rta *a)
a->next->pprev = a->pprev;
a->aflags = 0; /* Poison the entry */
rt_unlock_hostentry(a->hostentry);
+ mpnh_free(a->nexthops);
ea_free(a->eattrs);
sl_free(rta_slab, a);
}
@@ -798,6 +858,7 @@ rta_init(void)
{
rta_pool = rp_new(&root_pool, "Attributes");
rta_slab = sl_new(rta_pool, sizeof(rta));
+ mpnh_slab = sl_new(rta_pool, sizeof(struct mpnh));
rta_alloc_hash();
}