summaryrefslogtreecommitdiffstats
path: root/sysdep/unix/krt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/unix/krt.c')
-rw-r--r--sysdep/unix/krt.c61
1 files changed, 59 insertions, 2 deletions
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 6208f68..488447b 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -151,6 +151,49 @@ kif_shutdown(struct proto *P)
return PS_DOWN;
}
+
+static inline int
+prefer_scope(struct ifa *a, struct ifa *b)
+{ return (a->scope > SCOPE_LINK) && (b->scope <= SCOPE_LINK); }
+
+static inline int
+prefer_addr(struct ifa *a, struct ifa *b)
+{ return ipa_compare(a->ip, b->ip) < 0; }
+
+static inline struct ifa *
+find_preferred_ifa(struct iface *i, ip_addr prefix, ip_addr mask)
+{
+ struct ifa *a, *b = NULL;
+
+ WALK_LIST(a, i->addrs)
+ {
+ if (!(a->flags & IA_SECONDARY) &&
+ ipa_equal(ipa_and(a->ip, mask), prefix) &&
+ (!b || prefer_scope(a, b) || prefer_addr(a, b)))
+ b = a;
+ }
+
+ return b;
+}
+
+struct ifa *
+kif_choose_primary(struct iface *i)
+{
+ struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf);
+ struct kif_primary_item *it;
+ struct ifa *a;
+
+ WALK_LIST(it, cf->primary)
+ {
+ if (!it->pattern || patmatch(it->pattern, i->name))
+ if (a = find_preferred_ifa(i, it->prefix, ipa_mkmask(it->pxlen)))
+ return a;
+ }
+
+ return find_preferred_ifa(i, IPA_NONE, IPA_NONE);
+}
+
+
static int
kif_reconfigure(struct proto *p, struct proto_config *new)
{
@@ -159,6 +202,7 @@ kif_reconfigure(struct proto *p, struct proto_config *new)
if (!kif_params_same(&o->iface, &n->iface))
return 0;
+
if (o->scan_time != n->scan_time)
{
tm_stop(kif_scan_timer);
@@ -166,6 +210,18 @@ kif_reconfigure(struct proto *p, struct proto_config *new)
kif_scan(kif_scan_timer);
tm_start(kif_scan_timer, n->scan_time);
}
+
+ if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary))
+ {
+ /* This is hack, we have to update a configuration
+ * to the new value just now, because it is used
+ * for recalculation of primary addresses.
+ */
+ p->cf = new;
+
+ ifa_recalc_all_primary_addresses();
+ }
+
return 1;
}
@@ -224,7 +280,7 @@ krt_learn_announce_update(struct krt_proto *p, rte *e)
ee->pflags = 0;
ee->pref = p->p.preference;
ee->u.krt = e->u.krt;
- rte_update(p->p.table, nn, &p->p, ee);
+ rte_update(p->p.table, nn, &p->p, &p->p, ee);
}
static void
@@ -232,7 +288,7 @@ krt_learn_announce_delete(struct krt_proto *p, net *n)
{
n = net_find(p->p.table, n->n.prefix, n->n.pxlen);
if (n)
- rte_update(p->p.table, n, &p->p, NULL);
+ rte_update(p->p.table, n, &p->p, &p->p, NULL);
}
static void
@@ -819,6 +875,7 @@ krt_init(struct proto_config *c)
{
struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
+ p->p.accept_ra_types = RA_OPTIMAL;
p->p.rt_notify = krt_notify;
p->p.min_scope = SCOPE_HOST;
return &p->p;