so, eventually i want to move us to use an rb tree for interface
addresses instead of a stupid list which is linerily walked. the
basics have been discussed, there is no downside for the "one real
interface with one real IP" usage case, but the "lots of addresses in
the system" case would eventually profit a lot. this was partly in for
a short while after n2k10 in ajanuary but had to be backed out because
of issues - because the ifa_add call was in the wrong spot.
i believe i got the right one now. this diff does not (yet) re-enable
the maintainance of the rb tree but moves the ifa_add to the "right"
spot. needs extensive testing. preferably with many IPs in the system
and services bind()ing to them.
pls test and report back to me, not the list.
Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.225
diff -u -p -r1.225 if.c
--- net/if.c 27 Aug 2010 17:08:01 -0000 1.225
+++ net/if.c 22 Sep 2010 12:32:28 -0000
@@ -2196,6 +2196,12 @@ ifa_del(struct ifnet *ifp, struct ifaddr
TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
}
+void
+ifa_update_broadaddr(struct ifnet *ifp, struct ifaddr *ifa, struct sockaddr
*sa)
+{
+ ifa->ifa_broadaddr = sa;
+}
+
int
ifai_cmp(struct ifaddr_item *a, struct ifaddr_item *b)
{
@@ -2210,6 +2216,8 @@ ifa_item_insert(struct sockaddr *sa, str
{
struct ifaddr_item *ifai, *p;
+ if (!sa->sa_family)
+ return;
ifai = pool_get(&ifaddr_item_pl, PR_WAITOK);
ifai->ifai_addr = sa;
ifai->ifai_ifa = ifa;
Index: net/if.h
===================================================================
RCS file: /cvs/src/sys/net/if.h,v
retrieving revision 1.118
diff -u -p -r1.118 if.h
--- net/if.h 27 Aug 2010 17:08:01 -0000 1.118
+++ net/if.h 22 Sep 2010 12:32:28 -0000
@@ -848,5 +848,7 @@ int looutput(struct ifnet *,
void lortrequest(int, struct rtentry *, struct rt_addrinfo *);
void ifa_add(struct ifnet *, struct ifaddr *);
void ifa_del(struct ifnet *, struct ifaddr *);
+void ifa_update_broadaddr(struct ifnet *, struct ifaddr *,
+ struct sockaddr *);
#endif /* _KERNEL */
#endif /* _NET_IF_H_ */
Index: net/if_spppsubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_spppsubr.c,v
retrieving revision 1.82
diff -u -p -r1.82 if_spppsubr.c
--- net/if_spppsubr.c 13 Sep 2010 08:53:06 -0000 1.82
+++ net/if_spppsubr.c 22 Sep 2010 12:32:28 -0000
@@ -4743,7 +4743,7 @@ sppp_set_ip_addrs(struct sppp *sp, u_int
*dest = new_dst; /* fix dstaddr in place */
}
}
- if (!(error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0)))
+ if (!(error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0)))
dohooks(ifp->if_addrhooks, 0);
if (debug && error) {
log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addrs: in_ifinit "
@@ -4795,7 +4795,7 @@ sppp_clear_ip_addrs(struct sppp *sp)
if (sp->ipcp.flags & IPCP_HISADDR_DYN)
/* replace peer addr in place */
dest->sin_addr.s_addr = sp->ipcp.saved_hisaddr;
- if (!in_ifinit(ifp, ifatoia(ifa), &new_sin, 0))
+ if (!in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0))
dohooks(ifp->if_addrhooks, 0);
sppp_update_gw(ifp);
}
Index: netinet/in.c
===================================================================
RCS file: /cvs/src/sys/netinet/in.c,v
retrieving revision 1.60
diff -u -p -r1.60 in.c
--- netinet/in.c 13 Jan 2010 10:45:21 -0000 1.60
+++ netinet/in.c 22 Sep 2010 12:32:28 -0000
@@ -271,7 +271,6 @@ in_control(so, cmd, data, ifp)
LIST_INIT(&ia->ia_multiaddrs);
if ((ifp->if_flags & IFF_LOOPBACK) == 0)
in_interfaces++;
- ifa_add(ifp, (struct ifaddr *)ia);
splx(s);
newifaddr = 1;
@@ -351,12 +350,14 @@ in_control(so, cmd, data, ifp)
case SIOCSIFBRDADDR:
if ((ifp->if_flags & IFF_BROADCAST) == 0)
return (EINVAL);
- ia->ia_broadaddr = *satosin(&ifr->ifr_broadaddr);
+ ifa_update_broadaddr(ifp, (struct ifaddr *)ia,
+ &ifr->ifr_broadaddr);
break;
case SIOCSIFADDR:
s = splsoftnet();
- error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1);
+ error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1,
+ newifaddr);
if (!error)
dohooks(ifp->if_addrhooks, 0);
else if (newifaddr) {
@@ -396,13 +397,14 @@ in_control(so, cmd, data, ifp)
ia->ia_dstaddr = ifra->ifra_dstaddr;
maskIsNew = 1; /* We lie; but the effect's the same */
}
- if (ifra->ifra_addr.sin_family == AF_INET &&
- (hostIsNew || maskIsNew)) {
- error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
- }
if ((ifp->if_flags & IFF_BROADCAST) &&
(ifra->ifra_broadaddr.sin_family == AF_INET))
ia->ia_broadaddr = ifra->ifra_broadaddr;
+ if (ifra->ifra_addr.sin_family == AF_INET &&
+ (hostIsNew || maskIsNew)) {
+ error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0,
+ hostIsNew);
+ }
if (!error)
dohooks(ifp->if_addrhooks, 0);
else if (newifaddr) {
@@ -652,18 +654,22 @@ in_ifscrub(ifp, ia)
* and routing table entry.
*/
int
-in_ifinit(ifp, ia, sin, scrub)
+in_ifinit(ifp, ia, sin, scrub, newaddr)
struct ifnet *ifp;
struct in_ifaddr *ia;
struct sockaddr_in *sin;
int scrub;
+ int newaddr;
{
u_int32_t i = sin->sin_addr.s_addr;
struct sockaddr_in oldaddr;
int s = splnet(), flags = RTF_UP, error;
+ if (!newaddr)
+ ifa_del(ifp, (struct ifaddr *)ia);
oldaddr = ia->ia_addr;
ia->ia_addr = *sin;
+
/*
* Give the interface a chance to initialize
* if this is its first address,
@@ -719,6 +725,7 @@ in_ifinit(ifp, ia, sin, scrub)
flags |= RTF_HOST;
}
error = in_addprefix(ia, flags);
+
/*
* If the interface supports multicast, join the "all hosts"
* multicast group on that interface.
@@ -729,6 +736,9 @@ in_ifinit(ifp, ia, sin, scrub)
addr.s_addr = INADDR_ALLHOSTS_GROUP;
ia->ia_allhosts = in_addmulti(&addr, ifp);
}
+
+ ifa_add(ifp, (struct ifaddr *)ia);
+
return (error);
}
Index: netinet/in_var.h
===================================================================
RCS file: /cvs/src/sys/netinet/in_var.h,v
retrieving revision 1.15
diff -u -p -r1.15 in_var.h
--- netinet/in_var.h 13 Jan 2010 07:05:28 -0000 1.15
+++ netinet/in_var.h 22 Sep 2010 12:32:28 -0000
@@ -207,7 +207,7 @@ do {
\
} while (/* CONSTCOND */ 0)
int in_ifinit(struct ifnet *,
- struct in_ifaddr *, struct sockaddr_in *, int);
+ struct in_ifaddr *, struct sockaddr_in *, int, int);
struct in_multi *in_addmulti(struct in_addr *, struct ifnet *);
void in_delmulti(struct in_multi *);
void in_ifscrub(struct ifnet *, struct in_ifaddr *);