From c34a60f1c7c0bb08fbc20666f533e92363b4940b Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 16 Dec 2011 13:27:20 -0800 Subject: [PATCH 12/65] Account for IPv4 outgoing traffic within one interface. Submitted by: bz --- sys/netinet/in.c | 30 ++++++++++++++++++++++++++++++ sys/netinet/in.h | 1 + sys/netinet/ip_output.c | 7 +++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 36a0b30..a93c3b2 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -1655,3 +1655,33 @@ in_domifdetach(struct ifnet *ifp, void *aux) lltable_free(ii->ii_llt); free(ii, M_IFADDR); } + +struct in_ifaddr * +in_ifawithifp(struct ifnet *ifp, struct in_addr *ia) +{ + struct ifaddr *ifa; + struct in_ifaddr *ia2; + + KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); + + IF_ADDR_LOCK(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + ia2 = (struct in_ifaddr *)ifa; + if (ia2->ia_addr.sin_addr.s_addr == ia->s_addr) { + ifa_ref(ifa); + IF_ADDR_UNLOCK(ifp); + return (ia2); + } + if ((ifp->if_flags & IFF_BROADCAST) && + ia2->ia_broadaddr.sin_len != 0 && + ia2->ia_broadaddr.sin_addr.s_addr == ia->s_addr) { + ifa_ref(ifa); + IF_ADDR_UNLOCK(ifp); + return (ia2); + } + } + IF_ADDR_UNLOCK(ifp); + return (NULL); +} diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 52844f0..89232c4 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -731,6 +731,7 @@ char *inet_ntoa_r(struct in_addr ina, char *buf); /* in libkern */ char *inet_ntop(int, const void *, char *, socklen_t); /* in libkern */ int inet_pton(int af, const char *, void *); /* in libkern */ void in_ifdetach(struct ifnet *); +struct in_ifaddr *in_ifawithifp(struct ifnet *, struct in_addr *); #define in_hosteq(s, t) ((s).s_addr == (t).s_addr) #define in_nullhost(x) ((x).s_addr == INADDR_ANY) diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index a9008c5..f9bc097 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -294,8 +294,11 @@ again: error = EHOSTUNREACH; goto bad; } - ia = ifatoia(rte->rt_ifa); - ifa_ref(&ia->ia_ifa); + if (ip->ip_src.s_addr == INADDR_ANY || + (ia = in_ifawithifp(rte->rt_ifp, &ip->ip_src)) == NULL) { + ia = ifatoia(rte->rt_ifa); + ifa_ref(&ia->ia_ifa); + } ifp = rte->rt_ifp; rte->rt_rmx.rmx_pksent++; if (rte->rt_flags & RTF_GATEWAY) -- 1.7.8.3