One of the checks missing to have an unlocked forwarding path is related
to multicast. We must ensure that the list of multicast groups attached
to an ifp is not modified when the CPU processing a packet is traversing
it.
In order to prepare for such change the diff below introduces a new
function to abstract the list traversal.
It is a simple refactoring but multiples reviews are more than welcome
at this stage of the release cycle.
ok?
Index: netinet/in.c
===================================================================
RCS file: /cvs/src/sys/netinet/in.c,v
retrieving revision 1.125
diff -u -p -r1.125 in.c
--- netinet/in.c 3 Dec 2015 21:57:59 -0000 1.125
+++ netinet/in.c 15 Jan 2016 10:33:36 -0000
@@ -880,6 +880,21 @@ in_delmulti(struct in_multi *inm)
}
}
+/*
+ * Return 1 if the multicast group represented by ``ap'' has been
+ * joined by interface ``ifp'', 0 otherwise.
+ */
+int
+in_hasmulti(struct in_addr *ap, struct ifnet *ifp)
+{
+ struct in_multi *inm;
+ int joined;
+
+ IN_LOOKUP_MULTI(*ap, ifp, inm);
+ joined = (inm != NULL);
+
+ return (joined);
+}
void
in_ifdetach(struct ifnet *ifp)
Index: netinet/in_var.h
===================================================================
RCS file: /cvs/src/sys/netinet/in_var.h,v
retrieving revision 1.37
diff -u -p -r1.37 in_var.h
--- netinet/in_var.h 3 Dec 2015 21:57:59 -0000 1.37
+++ netinet/in_var.h 15 Jan 2016 10:34:02 -0000
@@ -154,6 +154,7 @@ int in_ifinit(struct ifnet *,
struct in_ifaddr *, struct sockaddr_in *, int);
struct in_multi *in_addmulti(struct in_addr *, struct ifnet *);
void in_delmulti(struct in_multi *);
+int in_hasmulti(struct in_addr *, struct ifnet *);
void in_ifscrub(struct ifnet *, struct in_ifaddr *);
int in_control(struct socket *, u_long, caddr_t, struct ifnet *);
void in_prefixlen2mask(struct in_addr *, int);
Index: netinet/ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.285
diff -u -p -r1.285 ip_carp.c
--- netinet/ip_carp.c 12 Jan 2016 09:22:01 -0000 1.285
+++ netinet/ip_carp.c 15 Jan 2016 10:47:19 -0000
@@ -1809,17 +1809,13 @@ carp_addr_updated(void *v)
/* We received address changes from if_addrhooks callback */
if (new_naddrs != sc->sc_naddrs || new_naddrs6 != sc->sc_naddrs6) {
- struct in_addr mc_addr;
- struct in_multi *inm;
sc->sc_naddrs = new_naddrs;
sc->sc_naddrs6 = new_naddrs6;
/* Re-establish multicast membership removed by in_control */
if (IN_MULTICAST(sc->sc_peer.s_addr)) {
- mc_addr.s_addr = sc->sc_peer.s_addr;
- IN_LOOKUP_MULTI(mc_addr, &sc->sc_if, inm);
- if (inm == NULL) {
+ if (!in_hasmulti(&sc->sc_peer, &sc->sc_if)) {
struct in_multi **imm =
sc->sc_imo.imo_membership;
u_int16_t maxmem =
Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.265
diff -u -p -r1.265 ip_input.c
--- netinet/ip_input.c 3 Dec 2015 21:11:53 -0000 1.265
+++ netinet/ip_input.c 15 Jan 2016 10:34:30 -0000
@@ -346,8 +346,6 @@ ipv4_input(struct mbuf *m)
}
if (IN_MULTICAST(ip->ip_dst.s_addr)) {
- struct in_multi *inm;
-
/*
* Make sure M_MCAST is set. It should theoretically
* already be there, but let's play safe because upper
@@ -402,8 +400,7 @@ ipv4_input(struct mbuf *m)
* See if we belong to the destination multicast group on the
* arrival interface.
*/
- IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
- if (inm == NULL) {
+ if (!in_hasmulti(&ip->ip_dst, ifp)) {
ipstat.ips_notmember++;
if (!IN_LOCAL_GROUP(ip->ip_dst.s_addr))
ipstat.ips_cantforward++;
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.316
diff -u -p -r1.316 ip_output.c
--- netinet/ip_output.c 13 Jan 2016 09:38:36 -0000 1.316
+++ netinet/ip_output.c 15 Jan 2016 10:43:47 -0000
@@ -241,7 +241,6 @@ reroute:
if (IN_MULTICAST(ip->ip_dst.s_addr) ||
(ip->ip_dst.s_addr == INADDR_BROADCAST)) {
- struct in_multi *inm;
m->m_flags |= (ip->ip_dst.s_addr == INADDR_BROADCAST) ?
M_BCAST : M_MCAST;
@@ -295,9 +294,8 @@ reroute:
ip->ip_src = ia->ia_addr.sin_addr;
}
- IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
- if (inm != NULL &&
- (imo == NULL || imo->imo_loop)) {
+ if ((imo == NULL || imo->imo_loop) &&
+ in_hasmulti(&ip->ip_dst, ifp)) {
/*
* If we belong to the destination multicast group
* on the outgoing interface, and the caller did not
Index: netinet6/in6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.182
diff -u -p -r1.182 in6.c
--- netinet6/in6.c 22 Dec 2015 10:01:01 -0000 1.182
+++ netinet6/in6.c 15 Jan 2016 10:43:04 -0000
@@ -1378,6 +1378,22 @@ in6_delmulti(struct in6_multi *in6m)
}
}
+/*
+ * Return 1 if the multicast group represented by ``maddr6'' has been
+ * joined by interface ``ifp'', 0 otherwise.
+ */
+int
+in6_hasmulti(struct in6_addr *maddr6, struct ifnet *ifp)
+{
+ struct in6_multi *in6m;
+ int joined;
+
+ IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
+ joined = (in6m != NULL);
+
+ return (joined);
+}
+
struct in6_multi_mship *
in6_joingroup(struct ifnet *ifp, struct in6_addr *addr, int *errorp)
{
Index: netinet6/in6_var.h
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_var.h,v
retrieving revision 1.58
diff -u -p -r1.58 in6_var.h
--- netinet6/in6_var.h 18 Nov 2015 13:58:02 -0000 1.58
+++ netinet6/in6_var.h 15 Jan 2016 10:37:33 -0000
@@ -495,6 +495,7 @@ do {
\
struct in6_multi *in6_addmulti(struct in6_addr *, struct ifnet *, int *);
void in6_delmulti(struct in6_multi *);
+int in6_hasmulti(struct in6_addr *, struct ifnet *);
struct in6_multi_mship *in6_joingroup(struct ifnet *, struct in6_addr *, int
*);
int in6_leavegroup(struct in6_multi_mship *);
int in6_control(struct socket *, u_long, caddr_t, struct ifnet *);
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.153
diff -u -p -r1.153 ip6_input.c
--- netinet6/ip6_input.c 6 Jan 2016 10:02:42 -0000 1.153
+++ netinet6/ip6_input.c 15 Jan 2016 10:39:08 -0000
@@ -388,7 +388,6 @@ ip6_input(struct mbuf *m)
* Multicast check
*/
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
- struct in6_multi *in6m = NULL;
/*
* Make sure M_MCAST is set. It should theoretically
@@ -401,8 +400,7 @@ ip6_input(struct mbuf *m)
* See if we belong to the destination multicast group on the
* arrival interface.
*/
- IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
- if (in6m)
+ if (in6_hasmulti(&ip6->ip6_dst, ifp))
ours = 1;
#ifdef MROUTING
else if (!ip6_mforwarding || !ip6_mrouter)
Index: netinet6/ip6_mroute.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_mroute.c,v
retrieving revision 1.101
diff -u -p -r1.101 ip6_mroute.c
--- netinet6/ip6_mroute.c 3 Dec 2015 13:13:42 -0000 1.101
+++ netinet6/ip6_mroute.c 15 Jan 2016 10:48:16 -0000
@@ -1372,7 +1372,6 @@ phyint_send6(struct ip6_hdr *ip6, struct
int error = 0;
int s = splsoftnet();
static struct route_in6 ro;
- struct in6_multi *in6m;
struct sockaddr_in6 *dst6;
/*
@@ -1416,8 +1415,7 @@ phyint_send6(struct ip6_hdr *ip6, struct
* on the outgoing interface, loop back a copy.
*/
dst6 = &ro.ro_dst;
- IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
- if (in6m != NULL) {
+ if (in6_hasmulti(&ip6->ip6_dst, ifp)) {
dst6->sin6_len = sizeof(struct sockaddr_in6);
dst6->sin6_family = AF_INET6;
dst6->sin6_addr = ip6->ip6_dst;
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.203
diff -u -p -r1.203 ip6_output.c
--- netinet6/ip6_output.c 13 Jan 2016 09:38:37 -0000 1.203
+++ netinet6/ip6_output.c 15 Jan 2016 10:40:56 -0000
@@ -566,7 +566,6 @@ reroute:
m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
} else {
/* Multicast */
- struct in6_multi *in6m;
m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
@@ -579,9 +578,8 @@ reroute:
goto bad;
}
- IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
- if (in6m != NULL &&
- (im6o == NULL || im6o->im6o_loop)) {
+ if ((im6o == NULL || im6o->im6o_loop) &&
+ in6_hasmulti(&ip6->ip6_dst, ifp)) {
/*
* If we belong to the destination multicast group
* on the outgoing interface, and the caller did not