Commit 9a158361 authored by Martin Mareš's avatar Martin Mareš

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.
parent ec8b579e
......@@ -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
......
This diff is collapsed.
......@@ -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
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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,
};
......@@ -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 );
}
......
......@@ -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);
}
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment