Don't iterate over the ifnet addr list in ip_output()

For almost every packet that is transmitted through ip_output(),
a call to in_broadcast() was made to decide if the destination
IP was a broadcast address.  in_broadcast() iterates over the
ifnet's address to find a source IP matching the subnet of the
destination IP, and then checks if the IP is a broadcast in that
subnet.

This is completely redundant as we have already performed the
route lookup, so the source IP is already known.  Just use that
address to directly check whether the destination IP is a
broadcast address or not.

MFC after:	2 months
Sponsored By:	EMC / Isilon Storage Division
Differential Revision: https://reviews.freebsd.org/D7266
This commit is contained in:
Ryan Stone 2016-08-18 22:59:00 +00:00
parent be9cb745bc
commit 90cc51a1ab
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=304435
3 changed files with 24 additions and 19 deletions

View File

@ -928,6 +928,25 @@ in_ifscrub_all(void)
IFNET_RUNLOCK();
}
int
in_ifaddr_broadcast(struct in_addr in, struct in_ifaddr *ia)
{
return ((in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
/*
* Check for old-style (host 0) broadcast, but
* taking into account that RFC 3021 obsoletes it.
*/
(ia->ia_subnetmask != IN_RFC3021_MASK &&
ntohl(in.s_addr) == ia->ia_subnet)) &&
/*
* Check for an all one subnetmask. These
* only exist when an interface gets a secondary
* address.
*/
ia->ia_subnetmask != (u_long)0xffffffff);
}
/*
* Return 1 if the address might be a local broadcast address.
*/
@ -935,37 +954,21 @@ int
in_broadcast(struct in_addr in, struct ifnet *ifp)
{
register struct ifaddr *ifa;
u_long t;
if (in.s_addr == INADDR_BROADCAST ||
in.s_addr == INADDR_ANY)
return (1);
if ((ifp->if_flags & IFF_BROADCAST) == 0)
return (0);
t = ntohl(in.s_addr);
/*
* Look through the list of addresses for a match
* with a broadcast address.
*/
#define ia ((struct in_ifaddr *)ifa)
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (ifa->ifa_addr->sa_family == AF_INET &&
(in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
/*
* Check for old-style (host 0) broadcast, but
* taking into account that RFC 3021 obsoletes it.
*/
(ia->ia_subnetmask != IN_RFC3021_MASK &&
t == ia->ia_subnet)) &&
/*
* Check for an all one subnetmask. These
* only exist when an interface gets a secondary
* address.
*/
ia->ia_subnetmask != (u_long)0xffffffff)
in_ifaddr_broadcast(in, (struct in_ifaddr *)ifa))
return (1);
return (0);
#undef ia
}
/*

View File

@ -637,8 +637,10 @@ int getsourcefilter(int, uint32_t, struct sockaddr *, socklen_t,
#ifdef _KERNEL
struct ifnet; struct mbuf; /* forward declarations for Standard C */
struct in_ifaddr;
int in_broadcast(struct in_addr, struct ifnet *);
int in_ifaddr_broadcast(struct in_addr, struct in_ifaddr *);
int in_canforward(struct in_addr);
int in_localaddr(struct in_addr);
int in_localip(struct in_addr);

View File

@ -350,7 +350,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
have_ia_ref = 1;
ifp = ia->ia_ifp;
ip->ip_ttl = 1;
isbroadcast = in_broadcast(dst->sin_addr, ifp);
isbroadcast = in_ifaddr_broadcast(dst->sin_addr, ia);
} else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) &&
imo != NULL && imo->imo_multicast_ifp != NULL) {
/*
@ -404,7 +404,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
if (rte->rt_flags & RTF_HOST)
isbroadcast = (rte->rt_flags & RTF_BROADCAST);
else
isbroadcast = in_broadcast(gw->sin_addr, ifp);
isbroadcast = in_ifaddr_broadcast(gw->sin_addr, ia);
}
/*