Implements primary address selection base on 'primary' option.
This commit is contained in:
parent
51f4469f03
commit
874b868544
5 changed files with 94 additions and 17 deletions
|
@ -57,6 +57,7 @@ CF_DECLS
|
|||
%type <time> datetime
|
||||
%type <a> ipa
|
||||
%type <px> prefix prefix_or_ipa
|
||||
%type <t> text_or_none
|
||||
|
||||
%nonassoc PREFIX_DUMMY
|
||||
%nonassoc '=' '<' '>' '~' '.' GEQ LEQ NEQ AND OR PO PC
|
||||
|
@ -153,6 +154,11 @@ datetime:
|
|||
}
|
||||
;
|
||||
|
||||
text_or_none:
|
||||
TEXT { $$ = $1; }
|
||||
| { $$ = NULL; }
|
||||
;
|
||||
|
||||
CF_CODE
|
||||
|
||||
CF_END
|
||||
|
|
42
nest/iface.c
42
nest/iface.c
|
@ -399,29 +399,43 @@ if_find_by_name(char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct ifa *kif_choose_primary(struct iface *i);
|
||||
|
||||
static int
|
||||
ifa_recalc_primary(struct iface *i)
|
||||
{
|
||||
struct ifa *a, *b = NULL;
|
||||
int res;
|
||||
struct ifa *a = kif_choose_primary(i);
|
||||
|
||||
WALK_LIST(a, i->addrs)
|
||||
if (a == i->addr)
|
||||
return 0;
|
||||
|
||||
if (i->addr)
|
||||
i->addr->flags &= ~IA_PRIMARY;
|
||||
|
||||
if (a)
|
||||
{
|
||||
if (!(a->flags & IA_SECONDARY) && (!b || a->scope > b->scope))
|
||||
b = a;
|
||||
a->flags &= ~IA_PRIMARY;
|
||||
a->flags |= IA_PRIMARY;
|
||||
rem_node(&a->n);
|
||||
add_head(&i->addrs, &a->n);
|
||||
}
|
||||
res = (b != i->addr);
|
||||
i->addr = b;
|
||||
if (b)
|
||||
|
||||
i->addr = a;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ifa_recalc_all_primary_addresses(void)
|
||||
{
|
||||
b->flags |= IA_PRIMARY;
|
||||
rem_node(&b->n);
|
||||
add_head(&i->addrs, &b->n);
|
||||
struct iface *i;
|
||||
|
||||
WALK_LIST(i, iface_list)
|
||||
{
|
||||
if (ifa_recalc_primary(i))
|
||||
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ifa_update - update interface address
|
||||
* @a: new interface address
|
||||
|
@ -464,7 +478,7 @@ ifa_update(struct ifa *a)
|
|||
memcpy(b, a, sizeof(struct ifa));
|
||||
add_tail(&i->addrs, &b->n);
|
||||
b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||
if ((!i->addr || i->addr->scope < b->scope) && ifa_recalc_primary(i))
|
||||
if (ifa_recalc_primary(i))
|
||||
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||
if (b->flags & IF_UP)
|
||||
ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
|
||||
|
|
|
@ -80,6 +80,7 @@ void if_end_partial_update(struct iface *);
|
|||
void if_feed_baby(struct proto *);
|
||||
struct iface *if_find_by_index(unsigned);
|
||||
struct iface *if_find_by_name(char *);
|
||||
void ifa_recalc_all_primary_addresses(void);
|
||||
|
||||
/* The Neighbor Cache */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue