I rewrote the interface handling code, so that it supports multiple
addresses per interface (needed for example for IPv6 support). Visible changes: o struct iface now contains a list of all interface addresses (represented by struct ifa), iface->addr points to the primary address (if any). o Interface has IF_UP set iff it's up and it has a primary address. o IF_UP is now independent on IF_IGNORED (i.e., you need to test IF_IGNORED in the protocols; I've added this, but please check). o The if_notify_change hook has been simplified (only one interface pointer etc.). o Introduced a ifa_notify_change hook. (For now, only the Direct protocol does use it -- it's wise to just listen to device routes in all other protocols.) o Removed IF_CHANGE_FLAGS notifier flag (it was meaningless anyway). o Updated all the code except netlink (I'll look at it tomorrow) to match the new semantics (please look at your code to ensure I did it right). Things to fix: o Netlink. o Make krt-iface interpret "eth0:1"-type aliases as secondary addresses.
This commit is contained in:
parent
ec8b579e9c
commit
9a158361da
11 changed files with 368 additions and 168 deletions
2
TODO
2
TODO
|
@ -27,6 +27,8 @@ Core
|
||||||
- iface: we always need ifindex at least for PtP links (OSPF)
|
- iface: we always need ifindex at least for PtP links (OSPF)
|
||||||
- iface: interface filters should support filtering by IP address as well
|
- iface: interface filters should support filtering by IP address as well
|
||||||
|
|
||||||
|
- socket: Use IP_RECVERR for BGP TCP sockets?
|
||||||
|
|
||||||
Cleanup
|
Cleanup
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
- right usage of DBG vs. debug
|
- right usage of DBG vs. debug
|
||||||
|
|
333
nest/iface.c
333
nest/iface.c
|
@ -31,17 +31,22 @@ static list neigh_list;
|
||||||
static int
|
static int
|
||||||
if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
|
if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
|
||||||
{
|
{
|
||||||
|
struct ifa *b;
|
||||||
|
|
||||||
if (!(i->flags & IF_UP))
|
if (!(i->flags & IF_UP))
|
||||||
return 0;
|
return 0;
|
||||||
if ((i->flags & IF_UNNUMBERED) && ipa_equal(*a, i->opposite))
|
if ((i->flags & IF_UNNUMBERED) && ipa_equal(*a, i->addr->opposite))
|
||||||
return 1;
|
return 1;
|
||||||
if (!ipa_in_net(*a, i->prefix, i->pxlen))
|
WALK_LIST(b, i->addrs)
|
||||||
return 0;
|
if (ipa_in_net(*a, b->prefix, b->pxlen))
|
||||||
if (ipa_equal(*a, i->prefix) || /* Network address */
|
{
|
||||||
ipa_equal(*a, i->brd) || /* Broadcast */
|
if (ipa_equal(*a, b->prefix) || /* Network address */
|
||||||
ipa_equal(*a, i->ip)) /* Our own address */
|
ipa_equal(*a, b->brd) || /* Broadcast */
|
||||||
|
ipa_equal(*a, b->ip)) /* Our own address */
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
neighbor *
|
neighbor *
|
||||||
|
@ -69,7 +74,7 @@ neigh_find(struct proto *p, ip_addr *a, unsigned flags)
|
||||||
case -1:
|
case -1:
|
||||||
return NULL;
|
return NULL;
|
||||||
case 1:
|
case 1:
|
||||||
if (!j || j->pxlen > i->pxlen)
|
if (!j) /* FIXME: Search for _optimal_ iface route? */
|
||||||
j = i;
|
j = i;
|
||||||
/* Fall-thru */
|
/* Fall-thru */
|
||||||
}
|
}
|
||||||
|
@ -187,9 +192,19 @@ neigh_prune(void)
|
||||||
|
|
||||||
list iface_list;
|
list iface_list;
|
||||||
|
|
||||||
|
void
|
||||||
|
ifa_dump(struct ifa *a)
|
||||||
|
{
|
||||||
|
debug("\t%I, net %I/%-2d bc %I -> %I%s%s\n", a->ip, a->prefix, a->pxlen, a->brd, a->opposite,
|
||||||
|
(a->flags & IF_UP) ? "" : " DOWN",
|
||||||
|
(a->flags & IA_PRIMARY) ? "" : " SEC");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
if_dump(struct iface *i)
|
if_dump(struct iface *i)
|
||||||
{
|
{
|
||||||
|
struct ifa *a;
|
||||||
|
|
||||||
debug("IF%d: %s", i->index, i->name);
|
debug("IF%d: %s", i->index, i->name);
|
||||||
if (i->flags & IF_ADMIN_DOWN)
|
if (i->flags & IF_ADMIN_DOWN)
|
||||||
debug(" ADMIN-DOWN");
|
debug(" ADMIN-DOWN");
|
||||||
|
@ -213,8 +228,14 @@ if_dump(struct iface *i)
|
||||||
debug(" LOOP");
|
debug(" LOOP");
|
||||||
if (i->flags & IF_IGNORE)
|
if (i->flags & IF_IGNORE)
|
||||||
debug(" IGN");
|
debug(" IGN");
|
||||||
|
if (i->flags & IF_TMP_DOWN)
|
||||||
|
debug(" TDOWN");
|
||||||
debug(" MTU=%d\n", i->mtu);
|
debug(" MTU=%d\n", i->mtu);
|
||||||
debug("\t%I, net %I/%-2d bc %I -> %I\n", i->ip, i->prefix, i->pxlen, i->brd, i->opposite);
|
WALK_LIST(a, i->addrs)
|
||||||
|
{
|
||||||
|
ifa_dump(a);
|
||||||
|
ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -228,138 +249,180 @@ if_dump_all(void)
|
||||||
debug("Router ID: %08x\n", config->router_id);
|
debug("Router ID: %08x\n", config->router_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline unsigned
|
||||||
if_change_too_big_p(struct iface *i, struct iface *j)
|
if_what_changed(struct iface *i, struct iface *j)
|
||||||
{
|
{
|
||||||
if (!ipa_equal(i->ip, j->ip) || /* Address change isn't */
|
unsigned c;
|
||||||
!ipa_equal(i->prefix, j->prefix) ||
|
|
||||||
i->pxlen != j->pxlen ||
|
if (((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
|
||||||
!ipa_equal(i->brd, j->brd) ||
|
|| i->index != j->index)
|
||||||
!ipa_equal(i->opposite, j->opposite))
|
return IF_CHANGE_TOO_MUCH;
|
||||||
return 1;
|
c = 0;
|
||||||
if ((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP))
|
if ((i->flags ^ j->flags) & IF_UP)
|
||||||
return 1; /* Interface type change isn't as well */
|
c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP;
|
||||||
return 0;
|
if (i->mtu != j->mtu)
|
||||||
|
c |= IF_CHANGE_MTU;
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
if_copy(struct iface *to, struct iface *from)
|
if_copy(struct iface *to, struct iface *from)
|
||||||
{
|
{
|
||||||
to->flags = from->flags;
|
to->flags = from->flags | (to->flags & IF_TMP_DOWN);
|
||||||
to->mtu = from->mtu;
|
to->mtu = from->mtu;
|
||||||
to->index = from->index;
|
|
||||||
to->neigh = from->neigh;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned
|
|
||||||
if_changed(struct iface *i, struct iface *j)
|
|
||||||
{
|
|
||||||
unsigned f = 0;
|
|
||||||
|
|
||||||
if (i->mtu != j->mtu)
|
|
||||||
f |= IF_CHANGE_MTU;
|
|
||||||
if ((i->flags ^ j->flags) & ~IF_UPDATED)
|
|
||||||
{
|
|
||||||
f |= IF_CHANGE_FLAGS;
|
|
||||||
if ((i->flags ^ j->flags) & IF_UP)
|
|
||||||
if (i->flags & IF_UP)
|
|
||||||
f |= IF_CHANGE_DOWN;
|
|
||||||
else
|
|
||||||
f |= IF_CHANGE_UP;
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
if_notify_change(unsigned c, struct iface *old, struct iface *new, struct iface *real)
|
ifa_notify_change(unsigned c, struct ifa *a)
|
||||||
{
|
{
|
||||||
struct proto *p;
|
struct proto *p;
|
||||||
|
|
||||||
debug("Interface change notification (%x) for %s\n", c, new->name);
|
debug("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
|
||||||
if (old)
|
WALK_LIST(p, proto_list)
|
||||||
if_dump(old);
|
if (p->ifa_notify)
|
||||||
if (new)
|
p->ifa_notify(p, c, a);
|
||||||
if_dump(new);
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
if_notify_change(unsigned c, struct iface *i)
|
||||||
|
{
|
||||||
|
struct proto *p;
|
||||||
|
struct ifa *a;
|
||||||
|
|
||||||
|
if (i->flags & IF_JUST_CREATED)
|
||||||
|
{
|
||||||
|
i->flags &= ~IF_JUST_CREATED;
|
||||||
|
c |= IF_CHANGE_CREATE | IF_CHANGE_MTU;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Interface change notification (%x) for %s\n", c, i->name);
|
||||||
|
if_dump(i);
|
||||||
|
|
||||||
if (c & IF_CHANGE_UP)
|
if (c & IF_CHANGE_UP)
|
||||||
neigh_if_up(real);
|
neigh_if_up(i);
|
||||||
|
if (c & IF_CHANGE_DOWN)
|
||||||
|
WALK_LIST(a, i->addrs)
|
||||||
|
{
|
||||||
|
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||||
|
ifa_notify_change(IF_CHANGE_DOWN, a);
|
||||||
|
}
|
||||||
|
|
||||||
WALK_LIST(p, proto_list)
|
WALK_LIST(p, proto_list)
|
||||||
if (p->if_notify)
|
if (p->if_notify)
|
||||||
p->if_notify(p, c, new, old);
|
p->if_notify(p, c, i);
|
||||||
|
|
||||||
|
if (c & IF_CHANGE_UP)
|
||||||
|
WALK_LIST(a, i->addrs)
|
||||||
|
{
|
||||||
|
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||||
|
ifa_notify_change(IF_CHANGE_UP, a);
|
||||||
|
}
|
||||||
if (c & IF_CHANGE_DOWN)
|
if (c & IF_CHANGE_DOWN)
|
||||||
neigh_if_down(real);
|
neigh_if_down(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static unsigned
|
||||||
|
if_recalc_flags(struct iface *i, unsigned flags)
|
||||||
|
{
|
||||||
|
if ((flags & (IF_ADMIN_DOWN | IF_TMP_DOWN)) ||
|
||||||
|
!(flags & IF_LINK_UP) ||
|
||||||
|
!i->addr)
|
||||||
|
flags &= ~IF_UP;
|
||||||
|
else
|
||||||
|
flags |= IF_UP;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
if_change_flags(struct iface *i, unsigned flags)
|
||||||
|
{
|
||||||
|
unsigned of = i->flags;
|
||||||
|
|
||||||
|
i->flags = if_recalc_flags(i, flags);
|
||||||
|
if ((i->flags ^ of) & IF_UP)
|
||||||
|
if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iface *
|
||||||
if_update(struct iface *new)
|
if_update(struct iface *new)
|
||||||
{
|
{
|
||||||
struct iface *i;
|
struct iface *i;
|
||||||
|
struct ifa *a, *b;
|
||||||
unsigned c;
|
unsigned c;
|
||||||
|
|
||||||
if ((new->flags & IF_LINK_UP) && !(new->flags & IF_ADMIN_DOWN) && ipa_nonzero(new->ip))
|
|
||||||
new->flags |= IF_UP;
|
|
||||||
else
|
|
||||||
new->flags &= ~IF_UP;
|
|
||||||
|
|
||||||
WALK_LIST(i, iface_list)
|
WALK_LIST(i, iface_list)
|
||||||
if (!strcmp(new->name, i->name))
|
if (!strcmp(new->name, i->name))
|
||||||
{
|
{
|
||||||
if (if_change_too_big_p(i, new)) /* Changed a lot, convert it to down/up */
|
new->addr = i->addr;
|
||||||
|
new->flags = if_recalc_flags(new, new->flags);
|
||||||
|
c = if_what_changed(i, new);
|
||||||
|
if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */
|
||||||
{
|
{
|
||||||
DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
|
DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
|
||||||
if (i->flags & IF_UP)
|
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||||
{
|
|
||||||
struct iface j;
|
|
||||||
memcpy(&j, i, sizeof(struct iface));
|
|
||||||
i->flags &= ~IF_UP;
|
|
||||||
if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i, i);
|
|
||||||
}
|
|
||||||
rem_node(&i->n);
|
rem_node(&i->n);
|
||||||
|
WALK_LIST_DELSAFE(a, b, i->addrs)
|
||||||
|
ifa_delete(a);
|
||||||
goto newif;
|
goto newif;
|
||||||
}
|
}
|
||||||
c = if_changed(i, new);
|
else if (c)
|
||||||
if (c)
|
{
|
||||||
if_notify_change(c, i, new, i);
|
if_copy(i, new);
|
||||||
if_copy(i, new); /* Even if c==0 as we might need to update i->index et al. */
|
if_notify_change(c, i);
|
||||||
i->flags |= IF_UPDATED;
|
}
|
||||||
return;
|
i->flags |= IF_UPDATED;
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = mb_alloc(if_pool, sizeof(struct iface));
|
i = mb_alloc(if_pool, sizeof(struct iface));
|
||||||
newif:
|
newif:
|
||||||
memcpy(i, new, sizeof(*i));
|
memcpy(i, new, sizeof(*i));
|
||||||
i->flags |= IF_UPDATED;
|
init_list(&i->addrs);
|
||||||
|
i->flags |= IF_UPDATED | IF_TMP_DOWN; /* Tmp down as we don't have addresses yet */
|
||||||
add_tail(&iface_list, &i->n);
|
add_tail(&iface_list, &i->n);
|
||||||
if_notify_change(IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0)
|
return i;
|
||||||
| IF_CHANGE_FLAGS | IF_CHANGE_MTU, NULL, i, i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
if_start_update(void)
|
if_start_update(void)
|
||||||
{
|
{
|
||||||
struct iface *i;
|
struct iface *i;
|
||||||
|
struct ifa *a;
|
||||||
|
|
||||||
WALK_LIST(i, iface_list)
|
WALK_LIST(i, iface_list)
|
||||||
|
{
|
||||||
i->flags &= ~IF_UPDATED;
|
i->flags &= ~IF_UPDATED;
|
||||||
|
WALK_LIST(a, i->addrs)
|
||||||
|
a->flags &= ~IF_UPDATED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
if_end_partial_update(struct iface *i)
|
||||||
|
{
|
||||||
|
if (i->flags & IF_TMP_DOWN)
|
||||||
|
if_change_flags(i, i->flags & ~IF_TMP_DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
if_end_update(void)
|
if_end_update(void)
|
||||||
{
|
{
|
||||||
struct iface *i, j;
|
struct iface *i, j;
|
||||||
|
struct ifa *a, *b;
|
||||||
|
|
||||||
if (!config->router_id)
|
if (!config->router_id)
|
||||||
auto_router_id();
|
auto_router_id();
|
||||||
|
|
||||||
WALK_LIST(i, iface_list)
|
WALK_LIST(i, iface_list)
|
||||||
if (!(i->flags & IF_UPDATED))
|
|
||||||
{
|
{
|
||||||
memcpy(&j, i, sizeof(struct iface));
|
if (!(i->flags & IF_UPDATED))
|
||||||
i->flags = (i->flags & ~(IF_LINK_UP | IF_UP)) | IF_ADMIN_DOWN;
|
if_change_flags(i, (i->flags & ~IF_LINK_UP) | IF_ADMIN_DOWN);
|
||||||
if (i->flags != j.flags)
|
else
|
||||||
if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i, i);
|
{
|
||||||
|
WALK_LIST_DELSAFE(a, b, i->addrs)
|
||||||
|
if (!(a->flags & IF_UPDATED))
|
||||||
|
ifa_delete(a);
|
||||||
|
if_end_partial_update(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,12 +430,19 @@ void
|
||||||
if_feed_baby(struct proto *p)
|
if_feed_baby(struct proto *p)
|
||||||
{
|
{
|
||||||
struct iface *i;
|
struct iface *i;
|
||||||
|
struct ifa *a;
|
||||||
|
|
||||||
if (!p->if_notify)
|
if (!p->if_notify && !p->ifa_notify)
|
||||||
return;
|
return;
|
||||||
debug("Announcing interfaces to new protocol %s\n", p->name);
|
debug("Announcing interfaces to new protocol %s\n", p->name);
|
||||||
WALK_LIST(i, iface_list)
|
WALK_LIST(i, iface_list)
|
||||||
p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i, NULL);
|
{
|
||||||
|
if (p->if_notify)
|
||||||
|
p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
|
||||||
|
if (p->ifa_notify && (i->flags & IF_UP))
|
||||||
|
WALK_LIST(a, i->addrs)
|
||||||
|
p->ifa_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iface *
|
struct iface *
|
||||||
|
@ -386,6 +456,96 @@ if_find_by_index(unsigned idx)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct iface *
|
||||||
|
if_find_by_name(char *name)
|
||||||
|
{
|
||||||
|
struct iface *i;
|
||||||
|
|
||||||
|
WALK_LIST(i, iface_list)
|
||||||
|
if (!strcmp(i->name, name))
|
||||||
|
return i;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ifa_recalc_primary(struct iface *i)
|
||||||
|
{
|
||||||
|
struct ifa *a, *b = NULL;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
WALK_LIST(a, i->addrs)
|
||||||
|
{
|
||||||
|
if (!(a->flags & IA_SECONDARY) && (!b || a->scope > b->scope))
|
||||||
|
b = a;
|
||||||
|
a->flags &= ~IA_PRIMARY;
|
||||||
|
}
|
||||||
|
res = (b != i->addr);
|
||||||
|
i->addr = b;
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
b->flags |= IA_PRIMARY;
|
||||||
|
rem_node(&b->n);
|
||||||
|
add_head(&i->addrs, &b->n);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ifa *
|
||||||
|
ifa_update(struct ifa *a)
|
||||||
|
{
|
||||||
|
struct iface *i = a->iface;
|
||||||
|
struct ifa *b;
|
||||||
|
|
||||||
|
WALK_LIST(b, i->addrs)
|
||||||
|
if (ipa_equal(b->ip, a->ip))
|
||||||
|
{
|
||||||
|
if (ipa_equal(b->prefix, a->prefix) &&
|
||||||
|
b->pxlen == a->pxlen &&
|
||||||
|
ipa_equal(b->brd, a->brd) &&
|
||||||
|
ipa_equal(b->opposite, a->opposite) &&
|
||||||
|
b->scope == a->scope)
|
||||||
|
{
|
||||||
|
b->flags |= IF_UPDATED;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
ifa_delete(b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
b = mb_alloc(if_pool, sizeof(struct ifa));
|
||||||
|
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_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||||
|
if (b->flags & IF_UP)
|
||||||
|
ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ifa_delete(struct ifa *a)
|
||||||
|
{
|
||||||
|
struct iface *i = a->iface;
|
||||||
|
struct ifa *b;
|
||||||
|
|
||||||
|
WALK_LIST(b, i->addrs)
|
||||||
|
if (ipa_equal(b->ip, a->ip))
|
||||||
|
{
|
||||||
|
rem_node(&b->n);
|
||||||
|
if (b->flags & IF_UP)
|
||||||
|
{
|
||||||
|
b->flags &= ~IF_UP;
|
||||||
|
ifa_notify_change(IF_CHANGE_DOWN, b);
|
||||||
|
}
|
||||||
|
if (b->flags & IA_PRIMARY)
|
||||||
|
{
|
||||||
|
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||||
|
ifa_recalc_primary(i);
|
||||||
|
}
|
||||||
|
mb_free(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
auto_router_id(void) /* FIXME: What if we run IPv6??? */
|
auto_router_id(void) /* FIXME: What if we run IPv6??? */
|
||||||
{
|
{
|
||||||
|
@ -393,14 +553,15 @@ auto_router_id(void) /* FIXME: What if we run IPv6??? */
|
||||||
|
|
||||||
j = NULL;
|
j = NULL;
|
||||||
WALK_LIST(i, iface_list)
|
WALK_LIST(i, iface_list)
|
||||||
if ((i->flags & IF_UP) &&
|
if ((i->flags & IF_LINK_UP) &&
|
||||||
!(i->flags & (IF_UNNUMBERED | IF_IGNORE)) &&
|
!(i->flags & (IF_UNNUMBERED | IF_IGNORE | IF_ADMIN_DOWN)) &&
|
||||||
(!j || ipa_to_u32(i->ip) < ipa_to_u32(j->ip)))
|
i->addr &&
|
||||||
|
(!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip)))
|
||||||
j = i;
|
j = i;
|
||||||
if (!j)
|
if (!j)
|
||||||
die("Cannot determine router ID (no suitable network interface found), please configure it manually");
|
die("Cannot determine router ID (no suitable network interface found), please configure it manually");
|
||||||
debug("Guessed router ID %I (%s)\n", j->ip, j->name);
|
debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name);
|
||||||
config->router_id = ipa_to_u32(j->ip);
|
config->router_id = ipa_to_u32(j->addr->ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
53
nest/iface.h
53
nest/iface.h
|
@ -15,48 +15,69 @@ extern list iface_list;
|
||||||
|
|
||||||
struct proto;
|
struct proto;
|
||||||
|
|
||||||
|
struct ifa { /* Interface address */
|
||||||
|
node n;
|
||||||
|
struct iface *iface; /* Interface this address belongs to */
|
||||||
|
ip_addr ip; /* IP address of this host */
|
||||||
|
ip_addr prefix; /* Network prefix */
|
||||||
|
unsigned pxlen; /* Prefix length */
|
||||||
|
ip_addr brd; /* Broadcast address */
|
||||||
|
ip_addr opposite; /* Opposite end of a point-to-point link */
|
||||||
|
unsigned scope; /* Interface address scope */
|
||||||
|
unsigned flags; /* Analogous to iface->flags */
|
||||||
|
};
|
||||||
|
|
||||||
struct iface {
|
struct iface {
|
||||||
node n;
|
node n;
|
||||||
char name[16];
|
char name[16];
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
unsigned mtu;
|
unsigned mtu;
|
||||||
unsigned index; /* OS-dependent interface index */
|
unsigned index; /* OS-dependent interface index */
|
||||||
ip_addr ip; /* IP address of this host (0=unset) */
|
list addrs; /* Addresses assigned to this interface */
|
||||||
ip_addr prefix; /* Network prefix */
|
struct ifa *addr; /* Primary address */
|
||||||
unsigned pxlen; /* Prefix length */
|
|
||||||
ip_addr brd; /* Broadcast address */
|
|
||||||
ip_addr opposite; /* Opposite end of a point-to-point link */
|
|
||||||
struct neighbor *neigh; /* List of neighbors on this interface */
|
struct neighbor *neigh; /* List of neighbors on this interface */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IF_UP 1 /* IF_LINK_UP, not IF_IGNORE and IP address known */
|
#define IF_UP 1 /* IF_LINK_UP and IP address known */
|
||||||
#define IF_MULTIACCESS 2
|
#define IF_MULTIACCESS 2
|
||||||
#define IF_UNNUMBERED 4
|
#define IF_UNNUMBERED 4
|
||||||
#define IF_BROADCAST 8
|
#define IF_BROADCAST 8
|
||||||
#define IF_MULTICAST 16
|
#define IF_MULTICAST 0x10
|
||||||
#define IF_TUNNEL 32
|
#define IF_TUNNEL 0x20
|
||||||
#define IF_ADMIN_DOWN 64
|
#define IF_ADMIN_DOWN 0x40
|
||||||
#define IF_LOOPBACK 128
|
#define IF_LOOPBACK 0x80
|
||||||
#define IF_IGNORE 256
|
#define IF_IGNORE 0x100 /* Not to be used by routing protocols (loopbacks etc.) */
|
||||||
#define IF_LINK_UP 512
|
#define IF_LINK_UP 0x200
|
||||||
|
|
||||||
|
#define IA_PRIMARY 0x10000 /* This address is primary */
|
||||||
|
#define IA_SECONDARY 0x20000 /* This address has been reported as secondary by the kernel */
|
||||||
|
#define IA_FLAGS 0xff0000
|
||||||
|
|
||||||
|
#define IF_JUST_CREATED 0x10000000 /* Send creation event as soon as possible */
|
||||||
|
#define IF_TMP_DOWN 0x20000000 /* Temporary shutdown due to interface reconfiguration */
|
||||||
#define IF_UPDATED 0x40000000 /* Touched in last scan */
|
#define IF_UPDATED 0x40000000 /* Touched in last scan */
|
||||||
|
|
||||||
/* Interface change events */
|
/* Interface change events */
|
||||||
|
|
||||||
#define IF_CHANGE_UP 1
|
#define IF_CHANGE_UP 1
|
||||||
#define IF_CHANGE_DOWN 2
|
#define IF_CHANGE_DOWN 2
|
||||||
#define IF_CHANGE_FLAGS 4 /* Can be converted to down/up internally */
|
#define IF_CHANGE_MTU 4
|
||||||
#define IF_CHANGE_MTU 8
|
#define IF_CHANGE_CREATE 8 /* Seen this interface for the first time */
|
||||||
#define IF_CHANGE_CREATE 16 /* Seen this interface for the first time */
|
#define IF_CHANGE_TOO_MUCH 0x40000000 /* Used internally */
|
||||||
|
|
||||||
void if_init(void);
|
void if_init(void);
|
||||||
void if_dump(struct iface *);
|
void if_dump(struct iface *);
|
||||||
void if_dump_all(void);
|
void if_dump_all(void);
|
||||||
void if_update(struct iface *);
|
void ifa_dump(struct ifa *);
|
||||||
|
struct iface *if_update(struct iface *);
|
||||||
|
struct ifa *ifa_update(struct ifa *);
|
||||||
|
void ifa_delete(struct ifa *);
|
||||||
void if_start_update(void);
|
void if_start_update(void);
|
||||||
void if_end_update(void);
|
void if_end_update(void);
|
||||||
|
void if_end_partial_update(struct iface *);
|
||||||
void if_feed_baby(struct proto *);
|
void if_feed_baby(struct proto *);
|
||||||
struct iface *if_find_by_index(unsigned);
|
struct iface *if_find_by_index(unsigned);
|
||||||
|
struct iface *if_find_by_name(char *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Neighbor Cache. We hold (direct neighbor, protocol) pairs we've seen
|
* Neighbor Cache. We hold (direct neighbor, protocol) pairs we've seen
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
|
|
||||||
struct iface;
|
struct iface;
|
||||||
|
struct ifa;
|
||||||
struct rte;
|
struct rte;
|
||||||
struct neighbor;
|
struct neighbor;
|
||||||
struct rta;
|
struct rta;
|
||||||
|
@ -96,6 +97,7 @@ struct proto {
|
||||||
* General protocol hooks:
|
* General protocol hooks:
|
||||||
*
|
*
|
||||||
* if_notify Notify protocol about interface state changes.
|
* if_notify Notify protocol about interface state changes.
|
||||||
|
* ifa_notify Notify protocol about interface address changes.
|
||||||
* rt_notify Notify protocol about routing table updates.
|
* rt_notify Notify protocol about routing table updates.
|
||||||
* neigh_notify Notify protocol about neighbor cache events.
|
* neigh_notify Notify protocol about neighbor cache events.
|
||||||
* make_tmp_attrs Construct ea_list from private attrs stored in rte.
|
* make_tmp_attrs Construct ea_list from private attrs stored in rte.
|
||||||
|
@ -106,7 +108,8 @@ struct proto {
|
||||||
* 0=process it through the import filter set by the user.
|
* 0=process it through the import filter set by the user.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void (*if_notify)(struct proto *, unsigned flags, struct iface *new, struct iface *old);
|
void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
|
||||||
|
void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
|
||||||
void (*rt_notify)(struct proto *, struct network *net, struct rte *new, struct rte *old);
|
void (*rt_notify)(struct proto *, struct network *net, struct rte *new, struct rte *old);
|
||||||
void (*neigh_notify)(struct neighbor *neigh);
|
void (*neigh_notify)(struct neighbor *neigh);
|
||||||
struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
|
struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
|
||||||
|
|
|
@ -19,19 +19,18 @@
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_if_notify(struct proto *p, unsigned c, struct iface *new, struct iface *old)
|
dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
|
||||||
{
|
{
|
||||||
struct rt_dev_config *P = (void *) p->cf;
|
struct rt_dev_config *P = (void *) p->cf;
|
||||||
|
|
||||||
if (old && !iface_patt_match(&P->iface_list, old) ||
|
if (!iface_patt_match(&P->iface_list, ad->iface))
|
||||||
new && !iface_patt_match(&P->iface_list, new))
|
|
||||||
return;
|
return;
|
||||||
if (c & IF_CHANGE_DOWN)
|
if (c & IF_CHANGE_DOWN)
|
||||||
{
|
{
|
||||||
net *n;
|
net *n;
|
||||||
|
|
||||||
debug("dev_if_notify: %s going down\n", old->name);
|
DBG("dev_if_notify: %s:%I going down\n", ad->iface->name, ad->ip);
|
||||||
n = net_find(p->table, old->prefix, old->pxlen);
|
n = net_find(p->table, ad->prefix, ad->pxlen);
|
||||||
if (!n)
|
if (!n)
|
||||||
{
|
{
|
||||||
debug("dev_if_notify: device shutdown: prefix not found\n");
|
debug("dev_if_notify: device shutdown: prefix not found\n");
|
||||||
|
@ -45,20 +44,20 @@ dev_if_notify(struct proto *p, unsigned c, struct iface *new, struct iface *old)
|
||||||
net *n;
|
net *n;
|
||||||
rte *e;
|
rte *e;
|
||||||
|
|
||||||
debug("dev_if_notify: %s going up\n", new->name);
|
debug("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
|
||||||
bzero(&A, sizeof(A));
|
bzero(&A, sizeof(A));
|
||||||
A.proto = p;
|
A.proto = p;
|
||||||
A.source = RTS_DEVICE;
|
A.source = RTS_DEVICE;
|
||||||
A.scope = (new->flags & IF_LOOPBACK) ? SCOPE_HOST : SCOPE_UNIVERSE;
|
A.scope = ad->scope;
|
||||||
A.cast = RTC_UNICAST;
|
A.cast = RTC_UNICAST;
|
||||||
A.dest = RTD_DEVICE;
|
A.dest = RTD_DEVICE;
|
||||||
A.iface = new;
|
A.iface = ad->iface;
|
||||||
A.attrs = NULL;
|
A.attrs = NULL;
|
||||||
a = rta_lookup(&A);
|
a = rta_lookup(&A);
|
||||||
if (new->flags & IF_UNNUMBERED)
|
if (ad->flags & IF_UNNUMBERED)
|
||||||
n = net_get(p->table, new->opposite, new->pxlen);
|
n = net_get(p->table, ad->opposite, ad->pxlen);
|
||||||
else
|
else
|
||||||
n = net_get(p->table, new->prefix, new->pxlen);
|
n = net_get(p->table, ad->prefix, ad->pxlen);
|
||||||
e = rte_get_temp(a);
|
e = rte_get_temp(a);
|
||||||
e->net = n;
|
e->net = n;
|
||||||
e->pflags = 0;
|
e->pflags = 0;
|
||||||
|
@ -71,7 +70,7 @@ dev_init(struct proto_config *c)
|
||||||
{
|
{
|
||||||
struct proto *p = proto_new(c, sizeof(struct proto));
|
struct proto *p = proto_new(c, sizeof(struct proto));
|
||||||
|
|
||||||
p->if_notify = dev_if_notify;
|
p->ifa_notify = dev_ifa_notify;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ wait_timer_hook(timer *timer)
|
||||||
{
|
{
|
||||||
debug(" OSPF: Changing state into DR.\n");
|
debug(" OSPF: Changing state into DR.\n");
|
||||||
ifa->state=OSPF_IS_DR;
|
ifa->state=OSPF_IS_DR;
|
||||||
ifa->drip=ifa->iface->ip;
|
ifa->drip=ifa->iface->addr->ip;
|
||||||
/* FIXME: Set ifa->drid */
|
/* FIXME: Set ifa->drid */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -221,7 +221,7 @@ find_iface(struct proto_ospf *p, struct iface *what)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_if_notify(struct proto *p, unsigned flags, struct iface *new, struct iface *old)
|
ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
|
||||||
{
|
{
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface *ifa;
|
||||||
sock *mcsk, *newsk;
|
sock *mcsk, *newsk;
|
||||||
|
@ -231,13 +231,15 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *new, struct iface
|
||||||
c=(struct ospf_config *)(p->cf);
|
c=(struct ospf_config *)(p->cf);
|
||||||
|
|
||||||
DBG(" OSPF: If notify called\n");
|
DBG(" OSPF: If notify called\n");
|
||||||
|
if (iface->flags & IF_IGNORE)
|
||||||
|
return;
|
||||||
|
|
||||||
if((flags & IF_CHANGE_UP) && is_good_iface(p, new))
|
if((flags & IF_CHANGE_UP) && is_good_iface(p, iface))
|
||||||
{
|
{
|
||||||
debug(" OSPF: using interface %s.\n", new->name);
|
debug(" OSPF: using interface %s.\n", iface->name);
|
||||||
/* FIXME: Latter I'll use config - this is incorrect */
|
/* FIXME: Latter I'll use config - this is incorrect */
|
||||||
ifa=mb_alloc(p->pool, sizeof(struct ospf_iface));
|
ifa=mb_alloc(p->pool, sizeof(struct ospf_iface));
|
||||||
ifa->iface=new;
|
ifa->iface=iface;
|
||||||
add_tail(&((struct proto_ospf *)p)->iface_list, NODE ifa);
|
add_tail(&((struct proto_ospf *)p)->iface_list, NODE ifa);
|
||||||
ospf_iface_default(ifa);
|
ospf_iface_default(ifa);
|
||||||
/* FIXME: This should read config */
|
/* FIXME: This should read config */
|
||||||
|
@ -253,17 +255,17 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *new, struct iface
|
||||||
|
|
||||||
if(flags & IF_CHANGE_DOWN)
|
if(flags & IF_CHANGE_DOWN)
|
||||||
{
|
{
|
||||||
if((ifa=find_iface((struct proto_ospf *)p, old))!=NULL)
|
if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
|
||||||
{
|
{
|
||||||
debug(" OSPF: killing interface %s.\n", old->name);
|
debug(" OSPF: killing interface %s.\n", iface->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(flags & IF_CHANGE_MTU)
|
if(flags & IF_CHANGE_MTU)
|
||||||
{
|
{
|
||||||
if((ifa=find_iface((struct proto_ospf *)p, old))!=NULL)
|
if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
|
||||||
{
|
{
|
||||||
debug(" OSPF: changing MTU on interface %s.\n", old->name);
|
debug(" OSPF: changing MTU on interface %s.\n", iface->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,6 +323,4 @@ struct protocol proto_ospf = {
|
||||||
start: ospf_start,
|
start: ospf_start,
|
||||||
preconfig: ospf_preconfig,
|
preconfig: ospf_preconfig,
|
||||||
postconfig: ospf_postconfig,
|
postconfig: ospf_postconfig,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -491,9 +491,9 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags)
|
||||||
if (want_multicast)
|
if (want_multicast)
|
||||||
rif->sock->daddr = ipa_from_u32(0x7f000001); /* FIXME: must lookup address in rfc's */
|
rif->sock->daddr = ipa_from_u32(0x7f000001); /* FIXME: must lookup address in rfc's */
|
||||||
if (flags & IF_BROADCAST)
|
if (flags & IF_BROADCAST)
|
||||||
rif->sock->daddr = new->brd;
|
rif->sock->daddr = new->addr->brd;
|
||||||
if (flags & IF_UNNUMBERED)
|
if (flags & IF_UNNUMBERED)
|
||||||
rif->sock->daddr = new->opposite;
|
rif->sock->daddr = new->addr->opposite;
|
||||||
|
|
||||||
if (!ipa_nonzero(rif->sock->daddr))
|
if (!ipa_nonzero(rif->sock->daddr))
|
||||||
log( L_WARN "RIP: interface %s is too strange for me", rif->iface ? rif->iface->name : "(dummy)" );
|
log( L_WARN "RIP: interface %s is too strange for me", rif->iface ? rif->iface->name : "(dummy)" );
|
||||||
|
@ -507,24 +507,26 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rip_if_notify(struct proto *p, unsigned c, struct iface *new, struct iface *old)
|
rip_if_notify(struct proto *p, unsigned c, struct iface *iface)
|
||||||
{
|
{
|
||||||
DBG( "RIP: if notify\n" );
|
DBG( "RIP: if notify\n" );
|
||||||
if (old) {
|
if (iface->flags & IF_IGNORE)
|
||||||
|
return;
|
||||||
|
if (c & IF_CHANGE_DOWN) {
|
||||||
struct rip_interface *i;
|
struct rip_interface *i;
|
||||||
i = find_interface(p, old);
|
i = find_interface(p, iface);
|
||||||
if (i) {
|
if (i) {
|
||||||
rem_node(NODE i);
|
rem_node(NODE i);
|
||||||
kill_iface(p, i);
|
kill_iface(p, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (new) {
|
if (c & IF_CHANGE_UP) {
|
||||||
struct rip_interface *rif;
|
struct rip_interface *rif;
|
||||||
struct iface_patt *k = iface_patt_match(&P_CF->iface_list, new);
|
struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface);
|
||||||
|
|
||||||
if (!k) return; /* We are not interested in this interface */
|
if (!k) return; /* We are not interested in this interface */
|
||||||
DBG("adding interface %s\n", new->name );
|
DBG("adding interface %s\n", iface->name );
|
||||||
rif = new_iface(p, new, new->flags);
|
rif = new_iface(p, iface, iface->flags);
|
||||||
rif->patt = (void *) k;
|
rif->patt = (void *) k;
|
||||||
add_head( &P->interfaces, NODE rif );
|
add_head( &P->interfaces, NODE rif );
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ static_dump(struct proto *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
static_if_notify(struct proto *p, unsigned flags, struct iface *new, struct iface *old)
|
static_if_notify(struct proto *p, unsigned flags, struct iface *i)
|
||||||
{
|
{
|
||||||
struct static_route *r;
|
struct static_route *r;
|
||||||
struct static_config *c = (void *) p->cf;
|
struct static_config *c = (void *) p->cf;
|
||||||
|
@ -142,13 +142,13 @@ static_if_notify(struct proto *p, unsigned flags, struct iface *new, struct ifac
|
||||||
if (flags & IF_CHANGE_UP)
|
if (flags & IF_CHANGE_UP)
|
||||||
{
|
{
|
||||||
WALK_LIST(r, c->iface_routes)
|
WALK_LIST(r, c->iface_routes)
|
||||||
if (!strcmp(r->if_name, new->name))
|
if (!strcmp(r->if_name, i->name))
|
||||||
static_install(p, r, new);
|
static_install(p, r, i);
|
||||||
}
|
}
|
||||||
else if (flags & IF_CHANGE_DOWN)
|
else if (flags & IF_CHANGE_DOWN)
|
||||||
{
|
{
|
||||||
WALK_LIST(r, c->iface_routes)
|
WALK_LIST(r, c->iface_routes)
|
||||||
if (!strcmp(r->if_name, old->name))
|
if (!strcmp(r->if_name, i->name))
|
||||||
static_remove(p, r);
|
static_remove(p, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,12 +407,16 @@ krt_if_scan(struct kif_proto *p)
|
||||||
* Routes
|
* Routes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int /* FIXME: Check use of this function in krt.c */
|
int
|
||||||
krt_capable(rte *e)
|
krt_capable(rte *e)
|
||||||
{
|
{
|
||||||
rta *a = e->attrs;
|
rta *a = e->attrs;
|
||||||
|
|
||||||
if (a->cast != RTC_UNICAST) /* FIXME: For IPv6, we might support anycasts as well */
|
if (a->cast != RTC_UNICAST
|
||||||
|
#ifdef IPV6
|
||||||
|
&& a->cast != RTC_ANYCAST
|
||||||
|
#endif
|
||||||
|
)
|
||||||
return 0;
|
return 0;
|
||||||
if (a->source == RTS_DEVICE) /* Kernel takes care of device routes itself */
|
if (a->source == RTS_DEVICE) /* Kernel takes care of device routes itself */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -597,7 +601,7 @@ nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
|
||||||
net = net_get(&master_table, dst, i->rtm_dst_len);
|
net = net_get(&master_table, dst, i->rtm_dst_len);
|
||||||
ra.proto = &p->p;
|
ra.proto = &p->p;
|
||||||
ra.source = RTS_INHERIT;
|
ra.source = RTS_INHERIT;
|
||||||
ra.scope = SCOPE_UNIVERSE; /* FIXME: Use kernel scope? */
|
ra.scope = SCOPE_UNIVERSE;
|
||||||
ra.cast = RTC_UNICAST;
|
ra.cast = RTC_UNICAST;
|
||||||
ra.flags = ra.aflags = 0;
|
ra.flags = ra.aflags = 0;
|
||||||
ra.from = IPA_NONE;
|
ra.from = IPA_NONE;
|
||||||
|
|
|
@ -414,14 +414,14 @@ sk_open(sock *s)
|
||||||
#ifdef HAVE_STRUCT_IP_MREQN
|
#ifdef HAVE_STRUCT_IP_MREQN
|
||||||
struct ip_mreqn mreq;
|
struct ip_mreqn mreq;
|
||||||
#define mreq_add mreq
|
#define mreq_add mreq
|
||||||
ASSERT(s->iface);
|
ASSERT(s->iface && s->iface->addr);
|
||||||
mreq.imr_ifindex = s->iface->index;
|
mreq.imr_ifindex = s->iface->index;
|
||||||
set_inaddr(&mreq.imr_address, s->iface->ip);
|
set_inaddr(&mreq.imr_address, s->iface->addr->ip);
|
||||||
#else
|
#else
|
||||||
struct in_addr mreq;
|
struct in_addr mreq;
|
||||||
struct ip_mreq mreq_add;
|
struct ip_mreq mreq_add;
|
||||||
ASSERT(s->iface);
|
ASSERT(s->iface && s->iface->addr);
|
||||||
set_inaddr(&mreq, s->iface->ip);
|
set_inaddr(&mreq, s->iface->addr->ip);
|
||||||
#ifdef SO_BINDTODEVICE
|
#ifdef SO_BINDTODEVICE
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
|
@ -30,7 +30,8 @@ int if_scan_sock = -1;
|
||||||
static void
|
static void
|
||||||
scan_ifs(struct ifreq *r, int cnt)
|
scan_ifs(struct ifreq *r, int cnt)
|
||||||
{
|
{
|
||||||
struct iface i;
|
struct iface i, *pi;
|
||||||
|
struct ifa a;
|
||||||
char *err;
|
char *err;
|
||||||
unsigned fl;
|
unsigned fl;
|
||||||
ip_addr netmask;
|
ip_addr netmask;
|
||||||
|
@ -40,6 +41,7 @@ scan_ifs(struct ifreq *r, int cnt)
|
||||||
for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
|
for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
|
||||||
{
|
{
|
||||||
bzero(&i, sizeof(i));
|
bzero(&i, sizeof(i));
|
||||||
|
bzero(&a, sizeof(a));
|
||||||
DBG("%s\n", r->ifr_name);
|
DBG("%s\n", r->ifr_name);
|
||||||
if (strchr(r->ifr_name, ':'))
|
if (strchr(r->ifr_name, ':'))
|
||||||
{
|
{
|
||||||
|
@ -48,18 +50,22 @@ scan_ifs(struct ifreq *r, int cnt)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
strncpy(i.name, r->ifr_name, sizeof(i.name) - 1);
|
strncpy(i.name, r->ifr_name, sizeof(i.name) - 1);
|
||||||
get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.ip, NULL);
|
get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL);
|
||||||
if (ipa_nonzero(i.ip))
|
if (ipa_nonzero(a.ip))
|
||||||
{
|
{
|
||||||
l = ipa_classify(i.ip);
|
l = ipa_classify(a.ip);
|
||||||
if (l < 0 || !(l & IADDR_HOST))
|
if (l < 0 || !(l & IADDR_HOST))
|
||||||
{
|
{
|
||||||
log(L_ERR "%s: Invalid interface address", i.name);
|
log(L_ERR "%s: Invalid interface address", i.name);
|
||||||
i.ip = IPA_NONE;
|
a.ip = IPA_NONE;
|
||||||
}
|
}
|
||||||
else if ((l & IADDR_SCOPE_MASK) == SCOPE_HOST)
|
else
|
||||||
|
{
|
||||||
|
a.scope = l & IADDR_SCOPE_MASK;
|
||||||
|
if (a.scope == SCOPE_HOST)
|
||||||
i.flags |= IF_LOOPBACK | IF_IGNORE;
|
i.flags |= IF_LOOPBACK | IF_IGNORE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
|
if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
|
||||||
{
|
{
|
||||||
|
@ -83,15 +89,15 @@ scan_ifs(struct ifreq *r, int cnt)
|
||||||
log(L_ERR "%s: Invalid netmask", i.name);
|
log(L_ERR "%s: Invalid netmask", i.name);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
i.pxlen = l;
|
a.pxlen = l;
|
||||||
|
|
||||||
if (fl & IFF_POINTOPOINT)
|
if (fl & IFF_POINTOPOINT)
|
||||||
{
|
{
|
||||||
i.flags |= IF_UNNUMBERED;
|
i.flags |= IF_UNNUMBERED;
|
||||||
i.pxlen = BITS_PER_IP_ADDRESS;
|
a.pxlen = BITS_PER_IP_ADDRESS;
|
||||||
if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
|
if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
|
||||||
{ err = "SIOCGIFDSTADDR"; goto faulty; }
|
{ err = "SIOCGIFDSTADDR"; goto faulty; }
|
||||||
get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.opposite, NULL);
|
get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL);
|
||||||
}
|
}
|
||||||
if (fl & IFF_LOOPBACK)
|
if (fl & IFF_LOOPBACK)
|
||||||
i.flags |= IF_LOOPBACK | IF_IGNORE;
|
i.flags |= IF_LOOPBACK | IF_IGNORE;
|
||||||
|
@ -100,24 +106,24 @@ scan_ifs(struct ifreq *r, int cnt)
|
||||||
#endif
|
#endif
|
||||||
i.flags |= IF_MULTICAST;
|
i.flags |= IF_MULTICAST;
|
||||||
|
|
||||||
i.prefix = ipa_and(i.ip, ipa_mkmask(i.pxlen));
|
a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));
|
||||||
if (i.pxlen < 32)
|
if (a.pxlen < 32)
|
||||||
{
|
{
|
||||||
i.brd = ipa_or(i.prefix, ipa_not(ipa_mkmask(i.pxlen)));
|
a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen)));
|
||||||
if (ipa_equal(i.ip, i.prefix) || ipa_equal(i.ip, i.brd))
|
if (ipa_equal(a.ip, a.prefix) || ipa_equal(a.ip, a.brd))
|
||||||
{
|
{
|
||||||
log(L_ERR "%s: Using network or broadcast address for interface", i.name);
|
log(L_ERR "%s: Using network or broadcast address for interface", i.name);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
if (fl & IFF_BROADCAST)
|
if (fl & IFF_BROADCAST)
|
||||||
i.flags |= IF_BROADCAST;
|
i.flags |= IF_BROADCAST;
|
||||||
if (i.pxlen < 30)
|
if (a.pxlen < 30)
|
||||||
i.flags |= IF_MULTIACCESS;
|
i.flags |= IF_MULTIACCESS;
|
||||||
else
|
else
|
||||||
i.opposite = ipa_opposite(i.ip);
|
a.opposite = ipa_opposite(a.ip);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
i.brd = i.opposite;
|
a.brd = a.opposite;
|
||||||
|
|
||||||
if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0)
|
if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0)
|
||||||
{ err = "SIOCGIFMTU"; goto faulty; }
|
{ err = "SIOCGIFMTU"; goto faulty; }
|
||||||
|
@ -132,7 +138,9 @@ scan_ifs(struct ifreq *r, int cnt)
|
||||||
/* FIXME: What else? Guess ifindex (we need it at least for OSPF on unnumbered links)? */
|
/* FIXME: What else? Guess ifindex (we need it at least for OSPF on unnumbered links)? */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if_update(&i);
|
pi = if_update(&i);
|
||||||
|
a.iface = pi;
|
||||||
|
ifa_update(&a);
|
||||||
}
|
}
|
||||||
if_end_update();
|
if_end_update();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue