From 9a158361da249e0eab1e0f7bd2c7dbe9f32eddfa Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Thu, 6 May 1999 21:38:11 +0000 Subject: [PATCH] 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. --- TODO | 2 + nest/iface.c | 341 ++++++++++++++++++++++++--------- nest/iface.h | 53 +++-- nest/protocol.h | 5 +- nest/rt-dev.c | 23 ++- proto/ospf/ospf.c | 22 +-- proto/rip/rip.c | 20 +- proto/static/static.c | 8 +- sysdep/linux/netlink/netlink.c | 10 +- sysdep/unix/io.c | 8 +- sysdep/unix/krt-iface.c | 44 +++-- 11 files changed, 368 insertions(+), 168 deletions(-) diff --git a/TODO b/TODO index f001bd4b..ce658851 100644 --- a/TODO +++ b/TODO @@ -27,6 +27,8 @@ Core - iface: we always need ifindex at least for PtP links (OSPF) - iface: interface filters should support filtering by IP address as well +- socket: Use IP_RECVERR for BGP TCP sockets? + Cleanup ~~~~~~~ - right usage of DBG vs. debug diff --git a/nest/iface.c b/nest/iface.c index 002646ba..069b740c 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -31,17 +31,22 @@ static list neigh_list; static int if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */ { + struct ifa *b; + if (!(i->flags & IF_UP)) 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; - if (!ipa_in_net(*a, i->prefix, i->pxlen)) - return 0; - if (ipa_equal(*a, i->prefix) || /* Network address */ - ipa_equal(*a, i->brd) || /* Broadcast */ - ipa_equal(*a, i->ip)) /* Our own address */ - return -1; - return 1; + WALK_LIST(b, i->addrs) + if (ipa_in_net(*a, b->prefix, b->pxlen)) + { + if (ipa_equal(*a, b->prefix) || /* Network address */ + ipa_equal(*a, b->brd) || /* Broadcast */ + ipa_equal(*a, b->ip)) /* Our own address */ + return -1; + return 1; + } + return 0; } neighbor * @@ -69,7 +74,7 @@ neigh_find(struct proto *p, ip_addr *a, unsigned flags) case -1: return NULL; case 1: - if (!j || j->pxlen > i->pxlen) + if (!j) /* FIXME: Search for _optimal_ iface route? */ j = i; /* Fall-thru */ } @@ -187,9 +192,19 @@ neigh_prune(void) 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 if_dump(struct iface *i) { + struct ifa *a; + debug("IF%d: %s", i->index, i->name); if (i->flags & IF_ADMIN_DOWN) debug(" ADMIN-DOWN"); @@ -213,8 +228,14 @@ if_dump(struct iface *i) debug(" LOOP"); if (i->flags & IF_IGNORE) debug(" IGN"); + if (i->flags & IF_TMP_DOWN) + debug(" TDOWN"); 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 @@ -228,151 +249,200 @@ if_dump_all(void) debug("Router ID: %08x\n", config->router_id); } -static inline int -if_change_too_big_p(struct iface *i, struct iface *j) +static inline unsigned +if_what_changed(struct iface *i, struct iface *j) { - if (!ipa_equal(i->ip, j->ip) || /* Address change isn't */ - !ipa_equal(i->prefix, j->prefix) || - i->pxlen != j->pxlen || - !ipa_equal(i->brd, j->brd) || - !ipa_equal(i->opposite, j->opposite)) - return 1; - if ((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP)) - return 1; /* Interface type change isn't as well */ - return 0; + unsigned c; + + if (((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED)) + || i->index != j->index) + return IF_CHANGE_TOO_MUCH; + c = 0; + if ((i->flags ^ j->flags) & IF_UP) + c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP; + if (i->mtu != j->mtu) + c |= IF_CHANGE_MTU; + return c; } static inline void 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->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 -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; - debug("Interface change notification (%x) for %s\n", c, new->name); - if (old) - if_dump(old); - if (new) - if_dump(new); + debug("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip); + WALK_LIST(p, proto_list) + if (p->ifa_notify) + p->ifa_notify(p, c, a); +} + +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) - 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) 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) - 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) { struct iface *i; + struct ifa *a, *b; 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) 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); - if (i->flags & IF_UP) - { - 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); - } + if_change_flags(i, i->flags | IF_TMP_DOWN); rem_node(&i->n); + WALK_LIST_DELSAFE(a, b, i->addrs) + ifa_delete(a); goto newif; } - c = if_changed(i, new); - if (c) - if_notify_change(c, i, new, i); - if_copy(i, new); /* Even if c==0 as we might need to update i->index et al. */ + else if (c) + { + if_copy(i, new); + if_notify_change(c, i); + } i->flags |= IF_UPDATED; - return; + return i; } - i = mb_alloc(if_pool, sizeof(struct iface)); newif: 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); - if_notify_change(IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0) - | IF_CHANGE_FLAGS | IF_CHANGE_MTU, NULL, i, i); + return i; } void if_start_update(void) { struct iface *i; + struct ifa *a; 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 if_end_update(void) { struct iface *i, j; + struct ifa *a, *b; if (!config->router_id) auto_router_id(); WALK_LIST(i, iface_list) - if (!(i->flags & IF_UPDATED)) - { - memcpy(&j, i, sizeof(struct iface)); - i->flags = (i->flags & ~(IF_LINK_UP | IF_UP)) | IF_ADMIN_DOWN; - if (i->flags != j.flags) - if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i, i); - } + { + if (!(i->flags & IF_UPDATED)) + if_change_flags(i, (i->flags & ~IF_LINK_UP) | IF_ADMIN_DOWN); + else + { + WALK_LIST_DELSAFE(a, b, i->addrs) + if (!(a->flags & IF_UPDATED)) + ifa_delete(a); + if_end_partial_update(i); + } + } } void if_feed_baby(struct proto *p) { struct iface *i; + struct ifa *a; - if (!p->if_notify) + if (!p->if_notify && !p->ifa_notify) return; debug("Announcing interfaces to new protocol %s\n", p->name); 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 * @@ -386,6 +456,96 @@ if_find_by_index(unsigned idx) 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 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; WALK_LIST(i, iface_list) - if ((i->flags & IF_UP) && - !(i->flags & (IF_UNNUMBERED | IF_IGNORE)) && - (!j || ipa_to_u32(i->ip) < ipa_to_u32(j->ip))) + if ((i->flags & IF_LINK_UP) && + !(i->flags & (IF_UNNUMBERED | IF_IGNORE | IF_ADMIN_DOWN)) && + i->addr && + (!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip))) j = i; if (!j) 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); - config->router_id = ipa_to_u32(j->ip); + debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name); + config->router_id = ipa_to_u32(j->addr->ip); } void diff --git a/nest/iface.h b/nest/iface.h index 8677be0d..1d26e7b8 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -15,48 +15,69 @@ extern list iface_list; 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 { node n; char name[16]; unsigned flags; unsigned mtu; unsigned index; /* OS-dependent interface index */ - ip_addr ip; /* IP address of this host (0=unset) */ - 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 */ + list addrs; /* Addresses assigned to this interface */ + struct ifa *addr; /* Primary address */ 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_UNNUMBERED 4 #define IF_BROADCAST 8 -#define IF_MULTICAST 16 -#define IF_TUNNEL 32 -#define IF_ADMIN_DOWN 64 -#define IF_LOOPBACK 128 -#define IF_IGNORE 256 -#define IF_LINK_UP 512 +#define IF_MULTICAST 0x10 +#define IF_TUNNEL 0x20 +#define IF_ADMIN_DOWN 0x40 +#define IF_LOOPBACK 0x80 +#define IF_IGNORE 0x100 /* Not to be used by routing protocols (loopbacks etc.) */ +#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 */ /* Interface change events */ #define IF_CHANGE_UP 1 #define IF_CHANGE_DOWN 2 -#define IF_CHANGE_FLAGS 4 /* Can be converted to down/up internally */ -#define IF_CHANGE_MTU 8 -#define IF_CHANGE_CREATE 16 /* Seen this interface for the first time */ +#define IF_CHANGE_MTU 4 +#define IF_CHANGE_CREATE 8 /* Seen this interface for the first time */ +#define IF_CHANGE_TOO_MUCH 0x40000000 /* Used internally */ void if_init(void); void if_dump(struct iface *); 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_end_update(void); +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 *); /* * Neighbor Cache. We hold (direct neighbor, protocol) pairs we've seen diff --git a/nest/protocol.h b/nest/protocol.h index c203f252..5e1e2ce9 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -13,6 +13,7 @@ #include "lib/resource.h" struct iface; +struct ifa; struct rte; struct neighbor; struct rta; @@ -96,6 +97,7 @@ struct proto { * General protocol hooks: * * if_notify Notify protocol about interface state changes. + * ifa_notify Notify protocol about interface address changes. * rt_notify Notify protocol about routing table updates. * neigh_notify Notify protocol about neighbor cache events. * 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. */ - 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 (*neigh_notify)(struct neighbor *neigh); struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool); diff --git a/nest/rt-dev.c b/nest/rt-dev.c index d6035f56..1225f1d7 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -19,19 +19,18 @@ #include "lib/resource.h" 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; - if (old && !iface_patt_match(&P->iface_list, old) || - new && !iface_patt_match(&P->iface_list, new)) + if (!iface_patt_match(&P->iface_list, ad->iface)) return; if (c & IF_CHANGE_DOWN) { net *n; - debug("dev_if_notify: %s going down\n", old->name); - n = net_find(p->table, old->prefix, old->pxlen); + DBG("dev_if_notify: %s:%I going down\n", ad->iface->name, ad->ip); + n = net_find(p->table, ad->prefix, ad->pxlen); if (!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; 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)); A.proto = p; A.source = RTS_DEVICE; - A.scope = (new->flags & IF_LOOPBACK) ? SCOPE_HOST : SCOPE_UNIVERSE; + A.scope = ad->scope; A.cast = RTC_UNICAST; A.dest = RTD_DEVICE; - A.iface = new; + A.iface = ad->iface; A.attrs = NULL; a = rta_lookup(&A); - if (new->flags & IF_UNNUMBERED) - n = net_get(p->table, new->opposite, new->pxlen); + if (ad->flags & IF_UNNUMBERED) + n = net_get(p->table, ad->opposite, ad->pxlen); 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->net = n; e->pflags = 0; @@ -71,7 +70,7 @@ dev_init(struct proto_config *c) { struct proto *p = proto_new(c, sizeof(struct proto)); - p->if_notify = dev_if_notify; + p->ifa_notify = dev_ifa_notify; return p; } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 6aedb2ae..486ddbfa 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -155,7 +155,7 @@ wait_timer_hook(timer *timer) { debug(" OSPF: Changing state into DR.\n"); ifa->state=OSPF_IS_DR; - ifa->drip=ifa->iface->ip; + ifa->drip=ifa->iface->addr->ip; /* FIXME: Set ifa->drid */ } else @@ -221,7 +221,7 @@ find_iface(struct proto_ospf *p, struct iface *what) } 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; 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); 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 */ 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); ospf_iface_default(ifa); /* 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((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((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, preconfig: ospf_preconfig, postconfig: ospf_postconfig, - }; - diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 24d2e82b..f7978ce2 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -491,9 +491,9 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags) if (want_multicast) rif->sock->daddr = ipa_from_u32(0x7f000001); /* FIXME: must lookup address in rfc's */ if (flags & IF_BROADCAST) - rif->sock->daddr = new->brd; + rif->sock->daddr = new->addr->brd; if (flags & IF_UNNUMBERED) - rif->sock->daddr = new->opposite; + rif->sock->daddr = new->addr->opposite; if (!ipa_nonzero(rif->sock->daddr)) 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 -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" ); - if (old) { + if (iface->flags & IF_IGNORE) + return; + if (c & IF_CHANGE_DOWN) { struct rip_interface *i; - i = find_interface(p, old); + i = find_interface(p, iface); if (i) { rem_node(NODE i); kill_iface(p, i); } } - if (new) { + if (c & IF_CHANGE_UP) { 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 */ - DBG("adding interface %s\n", new->name ); - rif = new_iface(p, new, new->flags); + DBG("adding interface %s\n", iface->name ); + rif = new_iface(p, iface, iface->flags); rif->patt = (void *) k; add_head( &P->interfaces, NODE rif ); } diff --git a/proto/static/static.c b/proto/static/static.c index 871438a6..b136b314 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -134,7 +134,7 @@ static_dump(struct proto *p) } 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_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) { WALK_LIST(r, c->iface_routes) - if (!strcmp(r->if_name, new->name)) - static_install(p, r, new); + if (!strcmp(r->if_name, i->name)) + static_install(p, r, i); } else if (flags & IF_CHANGE_DOWN) { WALK_LIST(r, c->iface_routes) - if (!strcmp(r->if_name, old->name)) + if (!strcmp(r->if_name, i->name)) static_remove(p, r); } } diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c index 31dd608d..5a15607a 100644 --- a/sysdep/linux/netlink/netlink.c +++ b/sysdep/linux/netlink/netlink.c @@ -407,12 +407,16 @@ krt_if_scan(struct kif_proto *p) * Routes */ -int /* FIXME: Check use of this function in krt.c */ +int krt_capable(rte *e) { 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; if (a->source == RTS_DEVICE) /* Kernel takes care of device routes itself */ 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); ra.proto = &p->p; ra.source = RTS_INHERIT; - ra.scope = SCOPE_UNIVERSE; /* FIXME: Use kernel scope? */ + ra.scope = SCOPE_UNIVERSE; ra.cast = RTC_UNICAST; ra.flags = ra.aflags = 0; ra.from = IPA_NONE; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 7764d3df..6d44f809 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -414,14 +414,14 @@ sk_open(sock *s) #ifdef HAVE_STRUCT_IP_MREQN struct ip_mreqn mreq; #define mreq_add mreq - ASSERT(s->iface); + ASSERT(s->iface && s->iface->addr); mreq.imr_ifindex = s->iface->index; - set_inaddr(&mreq.imr_address, s->iface->ip); + set_inaddr(&mreq.imr_address, s->iface->addr->ip); #else struct in_addr mreq; struct ip_mreq mreq_add; - ASSERT(s->iface); - set_inaddr(&mreq, s->iface->ip); + ASSERT(s->iface && s->iface->addr); + set_inaddr(&mreq, s->iface->addr->ip); #ifdef SO_BINDTODEVICE { struct ifreq ifr; diff --git a/sysdep/unix/krt-iface.c b/sysdep/unix/krt-iface.c index bca70cca..57692ebc 100644 --- a/sysdep/unix/krt-iface.c +++ b/sysdep/unix/krt-iface.c @@ -30,7 +30,8 @@ int if_scan_sock = -1; static void scan_ifs(struct ifreq *r, int cnt) { - struct iface i; + struct iface i, *pi; + struct ifa a; char *err; unsigned fl; ip_addr netmask; @@ -40,6 +41,7 @@ scan_ifs(struct ifreq *r, int cnt) for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++) { bzero(&i, sizeof(i)); + bzero(&a, sizeof(a)); DBG("%s\n", r->ifr_name); if (strchr(r->ifr_name, ':')) { @@ -48,17 +50,21 @@ scan_ifs(struct ifreq *r, int cnt) continue; } strncpy(i.name, r->ifr_name, sizeof(i.name) - 1); - get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.ip, NULL); - if (ipa_nonzero(i.ip)) + get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL); + if (ipa_nonzero(a.ip)) { - l = ipa_classify(i.ip); + l = ipa_classify(a.ip); if (l < 0 || !(l & IADDR_HOST)) { log(L_ERR "%s: Invalid interface address", i.name); - i.ip = IPA_NONE; + a.ip = IPA_NONE; + } + else + { + a.scope = l & IADDR_SCOPE_MASK; + if (a.scope == SCOPE_HOST) + i.flags |= IF_LOOPBACK | IF_IGNORE; } - else if ((l & IADDR_SCOPE_MASK) == SCOPE_HOST) - i.flags |= IF_LOOPBACK | IF_IGNORE; } 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); goto bad; } - i.pxlen = l; + a.pxlen = l; if (fl & IFF_POINTOPOINT) { i.flags |= IF_UNNUMBERED; - i.pxlen = BITS_PER_IP_ADDRESS; + a.pxlen = BITS_PER_IP_ADDRESS; if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0) { 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) i.flags |= IF_LOOPBACK | IF_IGNORE; @@ -100,24 +106,24 @@ scan_ifs(struct ifreq *r, int cnt) #endif i.flags |= IF_MULTICAST; - i.prefix = ipa_and(i.ip, ipa_mkmask(i.pxlen)); - if (i.pxlen < 32) + a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen)); + if (a.pxlen < 32) { - i.brd = ipa_or(i.prefix, ipa_not(ipa_mkmask(i.pxlen))); - if (ipa_equal(i.ip, i.prefix) || ipa_equal(i.ip, i.brd)) + a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen))); + 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); goto bad; } if (fl & IFF_BROADCAST) i.flags |= IF_BROADCAST; - if (i.pxlen < 30) + if (a.pxlen < 30) i.flags |= IF_MULTIACCESS; else - i.opposite = ipa_opposite(i.ip); + a.opposite = ipa_opposite(a.ip); } else - i.brd = i.opposite; + a.brd = a.opposite; if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0) { 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)? */ #endif - if_update(&i); + pi = if_update(&i); + a.iface = pi; + ifa_update(&a); } if_end_update(); }