summaryrefslogtreecommitdiff
path: root/sysdep
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2009-05-29 22:49:30 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2009-05-29 22:49:30 +0200
commit874b868544c3a6ba45ace062091cc3aee007b719 (patch)
treedc9558c4e5e1537ea11469bb4be93bf941b9ee28 /sysdep
parent51f4469f03759642870a45634d9b53054e3deb92 (diff)
Implements primary address selection base on 'primary' option.
Diffstat (limited to 'sysdep')
-rw-r--r--sysdep/unix/krt.Y2
-rw-r--r--sysdep/unix/krt.c56
2 files changed, 57 insertions, 1 deletions
diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y
index 24f2dd27..40f1af9f 100644
--- a/sysdep/unix/krt.Y
+++ b/sysdep/unix/krt.Y
@@ -82,7 +82,7 @@ kif_item:
/* Scan time of 0 means scan on startup only */
THIS_KIF->scan_time = $3;
}
- | PRIMARY TEXT prefix_or_ipa {
+ | PRIMARY text_or_none prefix_or_ipa {
struct kif_primary_item *kpi = cfg_alloc(sizeof (struct kif_primary_item));
kpi->pattern = $2;
kpi->prefix = $3.addr;
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 6208f689..a60e7f91 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;
}