Multicast problems [PATCH]

Bruce M. Simpson bms at incunabulum.net
Mon Jun 18 18:39:46 UTC 2007


Bruce M. Simpson wrote:
>
> The condition we've seen is a side-effect of ip_multicast_if() being 
> removed. Support for scoped addresses in the IPv4 stack will mean this 
> code has to change again.

Here is a patch which explicitly looks for an interface supporting 
multicast, if no default route exists. The KASSERT should only be 
triggered if the routing trie code is broken; it is still possible for 
the last-resort interface lookup to fail if no loopback interface 
exists, if none of the interfaces have IPv4 addresses, or if no 
interfaces in the system support multicast.

regards,
BMS
-------------- next part --------------
--- in_mcast.c.orig	Mon Jun 18 20:08:48 2007
+++ in_mcast.c	Mon Jun 18 20:36:33 2007
@@ -996,8 +996,16 @@
 
 		/*
 		 * Obtain ifp. If no interface address was provided,
-		 * use the interface of the route to the given multicast
-		 * address (usually this is the default route).
+		 * use the interface of the route in the unicast FIB for
+		 * the given multicast destination; usually, this is the
+		 * default route.
+		 * If this lookup fails, attempt to use the first non-loopback
+		 * interface with multicast capability in the system as a
+		 * last resort. The legacy IPv4 ASM API requires that we do
+		 * this in order to allow groups to be joined when the routing
+		 * table has not yet been populated during boot.
+		 * If all of these conditions fail, return EADDRNOTAVAIL, and
+		 * reject the IPv4 multicast join.
 		 */
 		if (mreqs.imr_interface.s_addr != INADDR_ANY) {
 			INADDR_TO_IFP(mreqs.imr_interface, ifp);
@@ -1007,16 +1015,23 @@
 			ro.ro_rt = NULL;
 			*(struct sockaddr_in *)&ro.ro_dst = gsa->sin;
 			rtalloc_ign(&ro, RTF_CLONING);
-			if (ro.ro_rt == NULL) {
-#ifdef DIAGNOSTIC
-				printf("%s: no route to %s\n", __func__,
-				    inet_ntoa(gsa->sin.sin_addr));
-#endif
-				return (EADDRNOTAVAIL);
+			if (ro.ro_rt != NULL) {
+				ifp = ro.ro_rt->rt_ifp;
+				KASSERT(ifp != NULL, ("%s: null ifp",
+				    __func__));
+				RTFREE(ro.ro_rt);
+			} else {
+				struct in_ifaddr *ia;
+				struct ifnet *mfp = NULL;
+				TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
+					mfp = ia->ia_ifp;
+					if (!(mfp->if_flags & IFF_LOOPBACK) &&
+					     (mfp->if_flags & IFF_MULTICAST)) {
+						ifp = mfp;
+						break;
+					}
+				}
 			}
-			ifp = ro.ro_rt->rt_ifp;
-			KASSERT(ifp != NULL, ("%s: null ifp", __func__));
-			RTFREE(ro.ro_rt);
 		}
 #ifdef DIAGNOSTIC
 		if (bootverbose) {


More information about the freebsd-current mailing list