I'd really like more and heacy testing on this. has the potential for a great speedup on boxes with many IPs.
* Henning Brauer <[email protected]> [2010-09-23 13:51]: > oups, one superfluous check forgotten to remove. > > note to self: in main tree on anakin (ryan sez it's the next level of > krautcomputing) > > 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 23 Sep 2010 11:43:14 -0000 > @@ -157,6 +157,7 @@ int if_group_egress_build(void); > int ifai_cmp(struct ifaddr_item *, struct ifaddr_item *); > void ifa_item_insert(struct sockaddr *, struct ifaddr *, struct ifnet *); > void ifa_item_remove(struct sockaddr *, struct ifaddr *, struct ifnet *); > +void ifa_print_rb(void); /* XXX debug */ > RB_HEAD(ifaddr_items, ifaddr_item) ifaddr_items = > RB_INITIALIZER(&ifaddr_items); > RB_PROTOTYPE(ifaddr_items, ifaddr_item, ifai_entry, ifai_cmp); > RB_GENERATE(ifaddr_items, ifaddr_item, ifai_entry, ifai_cmp); > @@ -722,9 +723,11 @@ if_clone_destroy(const char *name) > return (EINVAL); > > ifp = ifunit(name); > - if (ifp == NULL) > - return (ENXIO); > + if (ifp == NULL) { > +ifa_print_rb(); > > + return (ENXIO); > +} > if (ifc->ifc_destroy == NULL) > return (EOPNOTSUPP); > > @@ -880,32 +883,22 @@ if_congestion_clear(void *arg) > struct ifaddr * > ifa_ifwithaddr(struct sockaddr *addr, u_int rdomain) > { > - struct ifnet *ifp; > - struct ifaddr *ifa; > + struct ifaddr_item *ifai, key; > + > + bzero(&key, sizeof(key)); > + key.ifai_addr = addr; > + key.ifai_rdomain = rtable_l2(rdomain); > + > + ifai = RB_FIND(ifaddr_items, &ifaddr_items, &key); > + if (ifai) > + return (ifai->ifai_ifa); > + return (NULL); > +} > > #define equal(a1, a2) \ > (bcmp((caddr_t)(a1), (caddr_t)(a2), \ > ((struct sockaddr *)(a1))->sa_len) == 0) > > - rdomain = rtable_l2(rdomain); > - TAILQ_FOREACH(ifp, &ifnet, if_list) { > - if (ifp->if_rdomain != rdomain) > - continue; > - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { > - if (ifa->ifa_addr->sa_family != addr->sa_family) > - continue; > - if (equal(addr, ifa->ifa_addr)) > - return (ifa); > - if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && > - /* IP6 doesn't have broadcast */ > - ifa->ifa_broadaddr->sa_len != 0 && > - equal(ifa->ifa_broadaddr, addr)) > - return (ifa); > - } > - } > - return (NULL); > -} > - > /* > * Locate the point to point interface with a given destination address. > */ > @@ -2188,12 +2181,26 @@ ifa_add(struct ifnet *ifp, struct ifaddr > TAILQ_INSERT_HEAD(&ifp->if_addrlist, ifa, ifa_list); > else > TAILQ_INSERT_TAIL(&ifp->if_addrlist, ifa, ifa_list); > + ifa_item_insert(ifa->ifa_addr, ifa, ifp); > + if (ifp->if_flags & IFF_BROADCAST && ifa->ifa_broadaddr) > + ifa_item_insert(ifa->ifa_broadaddr, ifa, ifp); > } > > void > ifa_del(struct ifnet *ifp, struct ifaddr *ifa) > { > TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list); > + ifa_item_remove(ifa->ifa_addr, ifa, ifp); > + if (ifp->if_flags & IFF_BROADCAST && ifa->ifa_broadaddr) > + ifa_item_remove(ifa->ifa_broadaddr, ifa, ifp); > +} > + > +void > +ifa_update_broadaddr(struct ifnet *ifp, struct ifaddr *ifa, struct sockaddr > *sa) > +{ > + ifa_item_remove(ifa->ifa_broadaddr, ifa, ifp); > + ifa->ifa_broadaddr = sa; > + ifa_item_insert(ifa->ifa_broadaddr, ifa, ifp); > } > > int > @@ -2251,6 +2258,31 @@ ifa_item_remove(struct sockaddr *sa, str > } else > ifai_last->ifai_next = ifai->ifai_next; > pool_put(&ifaddr_item_pl, ifai); > +} > + > +void > +ifa_print_rb(void) > +{ > + struct ifaddr_item *ifai, *p; > + RB_FOREACH(p, ifaddr_items, &ifaddr_items) { > + for (ifai = p; ifai; ifai = ifai->ifai_next) { > + switch (ifai->ifai_addr->sa_family) { > + case AF_INET: > + printf("%s", inet_ntoa((satosin( > + ifai->ifai_addr))->sin_addr)); > + break; > + case AF_INET6: > + printf("%s", ip6_sprintf(&(satosin6( > + ifai->ifai_addr))->sin6_addr)); > + break; > + case AF_LINK: > + printf("%s", > + ether_sprintf(ifai->ifai_addr->sa_data)); > + break; > + } > + printf(" on %s\n", ifai->ifai_ifa->ifa_ifp->if_xname); > + } > + } > } > > void > 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 23 Sep 2010 11:43:14 -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 23 Sep 2010 11:43:14 -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 23 Sep 2010 11:43:14 -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) { > @@ -381,7 +382,7 @@ in_control(so, cmd, data, ifp) > ifra->ifra_addr = ia->ia_addr; > hostIsNew = 0; > } else if (ifra->ifra_addr.sin_addr.s_addr == > - ia->ia_addr.sin_addr.s_addr) > + ia->ia_addr.sin_addr.s_addr && !newifaddr) > hostIsNew = 0; > } > if (ifra->ifra_mask.sin_len) { > @@ -396,13 +397,19 @@ in_control(so, cmd, data, ifp) > ia->ia_dstaddr = ifra->ifra_dstaddr; > maskIsNew = 1; /* We lie; but the effect's the same */ > } > + if ((ifp->if_flags & IFF_BROADCAST) && > + (ifra->ifra_broadaddr.sin_family == AF_INET)) { > + if (newifaddr) > + ia->ia_broadaddr = ifra->ifra_broadaddr; > + else > + ifa_update_broadaddr(ifp, (struct ifaddr *)ia, > + sintosa(&ifra->ifra_broadaddr)); > + } > if (ifra->ifra_addr.sin_family == AF_INET && > (hostIsNew || maskIsNew)) { > - error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); > + error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0, > + newifaddr); > } > - if ((ifp->if_flags & IFF_BROADCAST) && > - (ifra->ifra_broadaddr.sin_family == AF_INET)) > - ia->ia_broadaddr = ifra->ifra_broadaddr; > if (!error) > dohooks(ifp->if_addrhooks, 0); > else if (newifaddr) { > @@ -652,18 +659,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 +730,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 +741,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 23 Sep 2010 11:43:14 -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 *); > > > -- > Henning Brauer, [email protected], [email protected] > BS Web Services, http://bsws.de > Full-Service ISP - Secure Hosting, Mail and DNS Services > Dedicated Servers, Rootservers, Application Hosting > -- Henning Brauer, [email protected], [email protected] BS Web Services, http://bsws.de Full-Service ISP - Secure Hosting, Mail and DNS Services Dedicated Servers, Rootservers, Application Hosting
