On 26/10/15(Mon) 10:45, Vincent Gross wrote:
> regress/sys/net/rdomains still passes with this diff.
MP is hard! Let me comment on your diff, you're taking the right
direction.
> Index: net/if.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if.c,v
> retrieving revision 1.398
> diff -u -p -r1.398 if.c
> --- net/if.c 25 Oct 2015 21:58:04 -0000 1.398
> +++ net/if.c 26 Oct 2015 09:44:10 -0000
> @@ -1143,31 +1143,19 @@ if_congested(void)
You're forgetting the most interesting part of this function! Its
comment:
/*
* Locate an interface based on a complete address.
*/
Historically this function was returning an ``ifp'' and in most of the
cases that's exactly what we want. So the code is dereferencing an
``ifa'' just to get ``ifp''. The diff below changes some of this
call just to give you an idea.
> struct ifaddr *
> ifa_ifwithaddr(struct sockaddr *addr, u_int rtableid)
> {
> - struct ifnet *ifp;
> struct ifaddr *ifa;
> + struct rtentry *rt;
> u_int rdomain;
>
> + /*
> + * Local routes corresponding to ifas are in rdomain's
> + * default rtable.
> + */
> rdomain = rtable_l2(rtableid);
> - 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);
> -
> - /* IPv6 doesn't have broadcast */
> - if ((ifp->if_flags & IFF_BROADCAST) &&
> - ifa->ifa_broadaddr &&
> - ifa->ifa_broadaddr->sa_len != 0 &&
> - equal(ifa->ifa_broadaddr, addr))
> - return (ifa);
> - }
> - }
> - return (NULL);
> + rt = rtalloc(addr, 0, rdomain);
> + ifa = rt && (rt->rt_flags & RTF_LOCAL) ? rt->rt_ifa : NULL;
Here you're forgetting RTF_BROADCAST and you should probably call
rtisvalid(9) instead of checking for (rt != NULL).
> + rtfree(rt);
> + return ifa;
This is currently correct but that's what we do not want. As soon as
rtfree(9) is called ``ifa'' might be freed.
But let's take a step back. All the ifa_if*() functions are a good hint
that some work has to be done for MP-safeness. Accessing "&ifnet" MUST
not be done in the hot path (only in ioctl path).
There's two types of codes calling ifa_ifwithaddr(). Those that want
an ifp index (like divert) should probably use rt->rt_ifidx. Those that
want a destination should use rt_key(rt) on a RTF_LOCAL|RTF_BROADCAST
route.
I'd better see an audit of all the functions calling ifa_if*() to see
if they are called in hot path and need to be rewritten or if we can
deal with them later.
The diff below is just a hint, I don't want to introduce a new
interface.
Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.393
diff -u -p -r1.393 if.c
--- net/if.c 22 Oct 2015 17:48:34 -0000 1.393
+++ net/if.c 23 Oct 2015 13:19:50 -0000
@@ -1138,12 +1138,38 @@ if_congested(void)
/*
* Locate an interface based on a complete address.
*/
+struct ifnet *
+if_withaddr(struct sockaddr *addr, unsigned int rtableid)
+{
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ unsigned int rdomain;
+
+ rdomain = rtable_l2(rtableid);
+ 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 (ifp);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Locate an ``ifa'' based on a unicast or broadcast address.
+ */
struct ifaddr *
-ifa_ifwithaddr(struct sockaddr *addr, u_int rtableid)
+ifa_ifwithaddr(struct sockaddr *addr, unsigned int rtableid)
{
struct ifnet *ifp;
struct ifaddr *ifa;
- u_int rdomain;
+ unsigned int rdomain;
rdomain = rtable_l2(rtableid);
TAILQ_FOREACH(ifp, &ifnet, if_list) {
Index: net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.258
diff -u -p -r1.258 route.c
--- net/route.c 22 Oct 2015 17:19:38 -0000 1.258
+++ net/route.c 23 Oct 2015 13:27:31 -0000
@@ -443,7 +443,7 @@ rtredirect(struct sockaddr *dst, struct
if (!(flags & RTF_DONE) && rt &&
(!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
error = EINVAL;
- else if (ifa_ifwithaddr(gateway, rdomain) != NULL)
+ else if (if_withaddr(gateway, rdomain) != NULL)
error = EHOSTUNREACH;
if (error)
goto done;
Index: net/if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.49
diff -u -p -r1.49 if_var.h
--- net/if_var.h 22 Oct 2015 17:48:34 -0000 1.49
+++ net/if_var.h 23 Oct 2015 13:20:14 -0000
@@ -408,6 +408,7 @@ void if_start(struct ifnet *);
int if_enqueue(struct ifnet *, struct mbuf *);
void if_input(struct ifnet *, struct mbuf_list *);
int if_input_local(struct ifnet *, struct mbuf *, sa_family_t);
+struct ifnet *if_withaddr(struct sockaddr *, unsigned int);
void ether_ifattach(struct ifnet *);
void ether_ifdetach(struct ifnet *);
Index: net/if_vxlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vxlan.c,v
retrieving revision 1.32
diff -u -p -r1.32 if_vxlan.c
--- net/if_vxlan.c 23 Oct 2015 01:19:04 -0000 1.32
+++ net/if_vxlan.c 23 Oct 2015 13:23:41 -0000
@@ -210,7 +210,6 @@ vxlan_multicast_join(struct ifnet *ifp,
{
struct vxlan_softc *sc = ifp->if_softc;
struct ip_moptions *imo = &sc->sc_imo;
- struct ifaddr *ifa;
struct ifnet *mifp;
if (!IN_MULTICAST(dst->sin_addr.s_addr))
@@ -219,8 +218,7 @@ vxlan_multicast_join(struct ifnet *ifp,
if (src->sin_addr.s_addr == INADDR_ANY ||
IN_MULTICAST(src->sin_addr.s_addr))
return (EINVAL);
- if ((ifa = ifa_ifwithaddr(sintosa(src), sc->sc_rdomain)) == NULL ||
- (mifp = ifa->ifa_ifp) == NULL ||
+ if ((mifp = if_withaddr(sintosa(src), sc->sc_rdomain)) == NULL ||
(mifp->if_flags & IFF_MULTICAST) == 0)
return (EADDRNOTAVAIL);
Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.258
diff -u -p -r1.258 ip_input.c
--- netinet/ip_input.c 19 Oct 2015 11:59:26 -0000 1.258
+++ netinet/ip_input.c 23 Oct 2015 13:23:24 -0000
@@ -1051,9 +1051,8 @@ ip_dooptions(struct mbuf *m, struct ifne
ipaddr.sin_family = AF_INET;
ipaddr.sin_len = sizeof(ipaddr);
ipaddr.sin_addr = ip->ip_dst;
- ia = ifatoia(ifa_ifwithaddr(sintosa(&ipaddr),
- m->m_pkthdr.ph_rtableid));
- if (ia == NULL) {
+ if (if_withaddr(sintosa(&ipaddr),
+ m->m_pkthdr.ph_rtableid) == NULL) {
if (opt == IPOPT_SSRR) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_SRCFAIL;
@@ -1187,7 +1186,7 @@ ip_dooptions(struct mbuf *m, struct ifne
ipaddr.sin_family = AF_INET;
ipaddr.sin_len = sizeof(ipaddr);
ipaddr.sin_addr = sin;
- if (ifa_ifwithaddr(sintosa(&ipaddr),
+ if (if_withaddr(sintosa(&ipaddr),
m->m_pkthdr.ph_rtableid) == NULL)
continue;
ipt.ipt_ptr += sizeof(struct in_addr);
Index: netinet/ip_divert.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_divert.c,v
retrieving revision 1.38
diff -u -p -r1.38 ip_divert.c
--- netinet/ip_divert.c 9 Sep 2015 20:15:52 -0000 1.38
+++ netinet/ip_divert.c 23 Oct 2015 13:22:10 -0000
@@ -84,7 +84,7 @@ divert_output(struct inpcb *inp, struct
{
struct sockaddr_in *sin;
struct socket *so;
- struct ifaddr *ifa;
+ struct ifnet *ifp;
int error = 0, min_hdrlen = 0, dir;
struct ip *ip;
u_int16_t off;
@@ -140,12 +140,12 @@ divert_output(struct inpcb *inp, struct
if (dir == PF_IN) {
ipaddr.sin_addr = sin->sin_addr;
- ifa = ifa_ifwithaddr(sintosa(&ipaddr), m->m_pkthdr.ph_rtableid);
- if (ifa == NULL) {
+ ifp = if_withaddr(sintosa(&ipaddr), m->m_pkthdr.ph_rtableid);
+ if (ifp == NULL) {
error = EADDRNOTAVAIL;
goto fail;
}
- m->m_pkthdr.ph_ifidx = ifa->ifa_ifp->if_index;
+ m->m_pkthdr.ph_ifidx = ifp->if_index;
/*
* Recalculate IP and protocol checksums for the inbound packet
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.303
diff -u -p -r1.303 ip_output.c
--- netinet/ip_output.c 20 Oct 2015 20:22:42 -0000 1.303
+++ netinet/ip_output.c 23 Oct 2015 13:23:01 -0000
@@ -1324,7 +1324,6 @@ ip_setmoptions(int optname, struct ip_mo
u_int rtableid)
{
struct in_addr addr;
- struct in_ifaddr *ia;
struct ip_mreq *mreq;
struct ifnet *ifp = NULL;
struct ip_moptions *imo = *imop;
@@ -1381,9 +1380,7 @@ ip_setmoptions(int optname, struct ip_mo
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr = addr;
- ia = ifatoia(ifa_ifwithaddr(sintosa(&sin), rtableid));
- if (ia && in_hosteq(sin.sin_addr, ia->ia_addr.sin_addr))
- ifp = ia->ia_ifp;
+ ifp = if_withaddr(sintosa(&sin), rtableid);
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
error = EADDRNOTAVAIL;
break;
@@ -1451,9 +1448,7 @@ ip_setmoptions(int optname, struct ip_mo
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr = mreq->imr_interface;
- ia = ifatoia(ifa_ifwithaddr(sintosa(&sin), rtableid));
- if (ia && in_hosteq(sin.sin_addr, ia->ia_addr.sin_addr))
- ifp = ia->ia_ifp;
+ ifp = if_withaddr(sintosa(&sin), rtableid);
}
/*
* See if we found an interface, and confirm that it
@@ -1546,10 +1541,8 @@ ip_setmoptions(int optname, struct ip_mo
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr = mreq->imr_interface;
- ia = ifatoia(ifa_ifwithaddr(sintosa(&sin), rtableid));
- if (ia && in_hosteq(sin.sin_addr, ia->ia_addr.sin_addr))
- ifp = ia->ia_ifp;
- else {
+ ifp = if_withaddr(sintosa(&sin), rtableid);
+ if (ifp == NULL) {
error = EADDRNOTAVAIL;
break;
}
Index: netinet/ip_mroute.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_mroute.c,v
retrieving revision 1.82
diff -u -p -r1.82 ip_mroute.c
--- netinet/ip_mroute.c 12 Sep 2015 13:34:12 -0000 1.82
+++ netinet/ip_mroute.c 23 Oct 2015 13:09:38 -0000
@@ -827,7 +827,6 @@ add_vif(struct mbuf *m)
{
struct vifctl *vifcp;
struct vif *vifp;
- struct ifaddr *ifa;
struct ifnet *ifp;
struct ifreq ifr;
int error, s;
@@ -857,8 +856,9 @@ add_vif(struct mbuf *m)
#endif
{
sin.sin_addr = vifcp->vifc_lcl_addr;
- ifa = ifa_ifwithaddr(sintosa(&sin), /* XXX */ 0);
- if (ifa == NULL)
+ /* Use the physical interface associated with the address. */
+ ifp = if_withaddr(sintosa(&sin), /* XXX */ 0);
+ if (ifp == NULL)
return (EADDRNOTAVAIL);
}
@@ -881,9 +881,6 @@ add_vif(struct mbuf *m)
}
#endif
} else {
- /* Use the physical interface associated with the address. */
- ifp = ifa->ifa_ifp;
-
/* Make sure the interface supports multicast. */
if ((ifp->if_flags & IFF_MULTICAST) == 0)
return (EOPNOTSUPP);
Index: netinet6/ip6_divert.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_divert.c,v
retrieving revision 1.38
diff -u -p -r1.38 ip6_divert.c
--- netinet6/ip6_divert.c 11 Sep 2015 08:17:06 -0000 1.38
+++ netinet6/ip6_divert.c 23 Oct 2015 13:22:34 -0000
@@ -88,7 +88,7 @@ divert6_output(struct inpcb *inp, struct
{
struct sockaddr_in6 *sin6;
struct socket *so;
- struct ifaddr *ifa;
+ struct ifnet *ifp;
int error = 0, min_hdrlen = 0, nxt = 0, off, dir;
struct ip6_hdr *ip6;
@@ -149,13 +149,12 @@ divert6_output(struct inpcb *inp, struct
if (dir == PF_IN) {
ip6addr.sin6_addr = sin6->sin6_addr;
- ifa = ifa_ifwithaddr(sin6tosa(&ip6addr),
- m->m_pkthdr.ph_rtableid);
- if (ifa == NULL) {
+ ifp = if_withaddr(sin6tosa(&ip6addr), m->m_pkthdr.ph_rtableid);
+ if (ifp == NULL) {
error = EADDRNOTAVAIL;
goto fail;
}
- m->m_pkthdr.ph_ifidx = ifa->ifa_ifp->if_index;
+ m->m_pkthdr.ph_ifidx = ifp->if_index;
/*
* Recalculate the protocol checksum for the inbound packet