From owner-freebsd-current@FreeBSD.ORG Tue Mar 27 16:19:36 2007 Return-Path: X-Original-To: freebsd-current@freebsd.org Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 48AA816A404 for ; Tue, 27 Mar 2007 16:19:36 +0000 (UTC) (envelope-from bms@FreeBSD.org) Received: from out4.smtp.messagingengine.com (out4.smtp.messagingengine.com [66.111.4.28]) by mx1.freebsd.org (Postfix) with ESMTP id D89C013C4D3 for ; Tue, 27 Mar 2007 16:19:35 +0000 (UTC) (envelope-from bms@FreeBSD.org) Received: from compute1.internal (compute1.internal [10.202.2.41]) by out1.messagingengine.com (Postfix) with ESMTP id BD7C421068E for ; Tue, 27 Mar 2007 12:19:35 -0400 (EDT) Received: from heartbeat1.messagingengine.com ([10.202.2.160]) by compute1.internal (MEProxy); Tue, 27 Mar 2007 12:19:36 -0400 X-Sasl-enc: 0uY+DolnyhiCZLSpVSWAwzrTvJVllZasu+decs+tH9GC 1175012375 Received: from [192.168.123.18] (82-35-112-254.cable.ubr07.dals.blueyonder.co.uk [82.35.112.254]) by mail.messagingengine.com (Postfix) with ESMTP id 639831D344 for ; Tue, 27 Mar 2007 12:19:35 -0400 (EDT) Message-ID: <46094415.3050704@FreeBSD.org> Date: Tue, 27 Mar 2007 17:19:33 +0100 From: "Bruce M. Simpson" User-Agent: Thunderbird 1.5.0.9 (X11/20070125) MIME-Version: 1.0 To: FreeBSD Current Content-Type: multipart/mixed; boundary="------------080000050300080700070504" Subject: [Fwd: Panic: if_freemulti: protospec not NULL] X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Mar 2007 16:19:36 -0000 This is a multi-part message in MIME format. --------------080000050300080700070504 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Patch for this condition is attached. This particular bug is irritating: the IPv4 stack joins 224.0.0.1 once for every IPv4 unicast address configured in the stack. This is incorrect behaviour. The implementation of refcounting has exposed this bug. The fix is not particularly elegant. It is most likely a left-over from the FreeBSD 2.x/3.x era when IPv4 'aliases' were first introduced. At that point in time the IGMP code in FreeBSD would allow groups to be joined on a per-IPv4-address basis, which is inconsistent with the IGMPv2/v3 specified behaviour (and indeed that addressed in future multicast RFCs). It seems that there are other situations where the stack is not adequately equipped to deal with interfaces going away unexpectedly. We can't afford to be complacent about multicast code on the basis of 'it's not the critical path', because it is an integral component of IPv6, and many ideas which people are trying to implement in IPv4 also require that the multicast code is fit for purpose. We would do well to have more people available to help on reviewing and possibly rewriting parts of the network stack from a perspective of correctness, not just performance. If this interests you please consider signing up to the Wiki and updating the page at http://wiki.freebsd.org/NetworkRFCCompliance. Regards, BMS --------------080000050300080700070504 Content-Type: text/x-patch; name="ifa_detach.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ifa_detach.diff" ==== //depot/user/bms/netdev/sys/netinet/in.c#11 - /home/bms/p4/netdev/sys/netinet/in.c ==== --- /tmp/tmp.1127.0 Tue Mar 27 16:43:56 2007 +++ /home/bms/p4/netdev/sys/netinet/in.c Tue Mar 27 16:40:04 2007 @@ -212,6 +212,11 @@ /* * Generic internet control operations (ioctl's). * Ifp is 0 if not an interface-specific ioctl. + * + * XXX: This code has some nice big juicy bugs related to interface + * attach and detach. Specifically, the 224.0.0.1 group is now only + * joined on the first IPv4 address configured on an interface, and + * only left when all IPv4 state is torn down for an interface. */ /* ARGSUSED */ int @@ -230,7 +235,9 @@ struct in_aliasreq *ifra = (struct in_aliasreq *)data; struct sockaddr_in oldaddr; int error, hostIsNew, iaIsNew, maskIsNew, s; + int iaIsFirst; + iaIsFirst = 0; iaIsNew = 0; switch (cmd) { @@ -282,6 +289,8 @@ break; } } + if (ia == NULL) + iaIsFirst = 1; } switch (cmd) { @@ -423,8 +432,20 @@ (struct sockaddr_in *) &ifr->ifr_addr, 1); if (error != 0 && iaIsNew) break; - if (error == 0) + if (error == 0) { + /* + * Only join 224.0.0.1 if this is the very first + * IPv4 unicast address which has been configured + * on this ifnet. + */ + if (iaIsFirst && (ifp->if_flags & IFF_MULTICAST) != 0) { + struct in_addr addr; + + addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + in_addmulti(&addr, ifp); + } EVENTHANDLER_INVOKE(ifaddr_event, ifp); + } return (0); case SIOCSIFNETMASK: @@ -467,8 +488,20 @@ if ((ifp->if_flags & IFF_BROADCAST) && (ifra->ifra_broadaddr.sin_family == AF_INET)) ia->ia_broadaddr = ifra->ifra_broadaddr; - if (error == 0) + if (error == 0) { + /* + * Only join 224.0.0.1 if this is the very first + * IPv4 unicast address which has been configured + * on this ifnet. + */ + if (iaIsFirst && (ifp->if_flags & IFF_MULTICAST) != 0) { + struct in_addr addr; + + addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + in_addmulti(&addr, ifp); + } EVENTHANDLER_INVOKE(ifaddr_event, ifp); + } return (error); case SIOCDIFADDR: @@ -503,8 +536,33 @@ s = splnet(); TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link); - if (ia->ia_addr.sin_family == AF_INET) + if (ia->ia_addr.sin_family == AF_INET) { + struct in_ifaddr *pia; + LIST_REMOVE(ia, ia_hash); + /* + * Only purge the 224.0.0.1 membership if the last IPv4 + * unicast address configured on this ifnet is removed. + * + * XXX: This currently involves trawling through the + * in_ifaddrhead list looking for a match, which is + * inefficient, though this is only done when an interface + * address goes away. This could be done much more elegantly. + */ + pia = NULL; + IFP_TO_IA(ifp, pia); + if (pia == NULL) { + struct in_multi *inm; + struct in_addr addr; + + addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + IN_MULTI_LOCK(); + IN_LOOKUP_MULTI(addr, ifp, inm); + if (inm != NULL) + in_delmulti(inm); + IN_MULTI_UNLOCK(); + } + } IFAFREE(&ia->ia_ifa); splx(s); @@ -793,16 +851,6 @@ if ((error = in_addprefix(ia, flags)) != 0) return (error); - /* - * If the interface supports multicast, join the "all hosts" - * multicast group on that interface. - */ - if (ifp->if_flags & IFF_MULTICAST) { - struct in_addr addr; - - addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - in_addmulti(&addr, ifp); - } return (error); } @@ -1114,6 +1162,9 @@ igmp_leavegroup(inm); ifma = inm->inm_ifma; +#ifdef DIAGNOSTIC + printf("%s: purging ifma %p\n", __func__, ifma); +#endif KASSERT(ifma->ifma_protospec == inm, ("%s: ifma_protospec != inm", __func__)); ifma->ifma_protospec = NULL; @@ -1135,6 +1186,9 @@ struct in_multi *inm; struct in_multi *oinm; +#ifdef DIAGNOSTIC + printf("%s: purging ifp %p\n", __func__, ifp); +#endif IFF_LOCKGIANT(ifp); IN_MULTI_LOCK(); LIST_FOREACH_SAFE(inm, &in_multihead, inm_link, oinm) { --------------080000050300080700070504 Content-Type: message/rfc822; name="Panic: if_freemulti: protospec not NULL" Content-Transfer-Encoding: 8bit Content-Disposition: inline; filename="Panic: if_freemulti: protospec not NULL" Received: from compute1.internal (compute1.internal [10.202.2.41]) by store23m.internal (Cyrus v2.3.8-fmsvn11108) with LMTPA; Tue, 27 Mar 2007 07:43:01 -0400 X-Sieve: CMU Sieve 2.3 X-Spam-score: 0.0 X-Spam-source: IP='69.147.83.53', Country='US', FromHeader='org', MailFrom='org' X-Delivered-to: bms@fastmail.net Received: from mx2.freebsd.org (mx2.freebsd.org [69.147.83.53]) by mx2.messagingengine.com (Postfix) with ESMTP id 404E91E04EE for ; Tue, 27 Mar 2007 07:42:58 -0400 (EDT) Received: from hub.freebsd.org (hub.freebsd.org [69.147.83.54]) by mx2.freebsd.org (Postfix) with ESMTP id 1855019D60 for ; Tue, 27 Mar 2007 11:40:16 +0000 (UTC) (envelope-from andre@freebsd.org) Received: by hub.freebsd.org (Postfix) id 1469A16A404; Tue, 27 Mar 2007 11:40:16 +0000 (UTC) Delivered-To: bms@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id EEBA816A403 for ; Tue, 27 Mar 2007 11:40:15 +0000 (UTC) (envelope-from andre@freebsd.org) Received: from c00l3r.networx.ch (c00l3r.networx.ch [62.48.2.2]) by mx1.freebsd.org (Postfix) with ESMTP id 2057413C457 for ; Tue, 27 Mar 2007 11:40:14 +0000 (UTC) (envelope-from andre@freebsd.org) Received: (qmail 7080 invoked from network); 27 Mar 2007 11:08:10 -0000 Received: from dotat.atdotat.at (HELO [62.48.0.47]) ([62.48.0.47]) (envelope-sender ) by c00l3r.networx.ch (qmail-ldap-1.03) with SMTP for ; 27 Mar 2007 11:08:10 -0000 Message-ID: <4609029E.8070604@freebsd.org> Date: Tue, 27 Mar 2007 13:40:14 +0200 From: Andre Oppermann User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050217 MIME-Version: 1.0 To: bms@freebsd.org Subject: Panic: if_freemulti: protospec not NULL Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit fxp0: 62.48.0.50/24 sysctl net.link. ifconfig lo1 create ifconfig lo1 inet 62.48.0.39/32 ifconfig lo1 inet 62.48.0.38/32 alias # ping tests etc. ifconfig lo1 delete 62.48.0.39 ifconfig lo1 delete 62.48.0.38 ifconfig lo1 destroy # panic Unread portion of the kernel message buffer: panic: if_freemulti: protospec not NULL cpuid = 1 KDB: enter: panic Physical memory: 2035 MB Dumping 103 MB: 88 72 56 40 24 8 #0 doadump () at pcpu.h:172 172 pcpu.h: No such file or directory. in pcpu.h (kgdb) bt #0 doadump () at pcpu.h:172 #1 0xc0477a3f in db_fncall (dummy1=-406202100, dummy2=0, dummy3=-1062950496, dummy4=0xe7c9d8e8 "\200DŽĀ") at ../../../ddb/db_command.c:486 #2 0xc047784b in db_command (last_cmdp=0xc0a23244, cmd_table=0x0) at ../../../ddb/db_command.c:401 #3 0xc0477906 in db_command_loop () at ../../../ddb/db_command.c:453 #4 0xc0479551 in db_trap (type=3, code=0) at ../../../ddb/db_main.c:222 #5 0xc06e1f0c in kdb_trap (type=3, code=0, tf=0xe7c9da80) at ../../../kern/subr_kdb.c:502 #6 0xc08c0529 in trap (frame=0xe7c9da80) at ../../../i386/i386/trap.c:621 #7 0xc08aa47b in calltrap () at ../../../i386/i386/exception.s:139 #8 0xc06e1c33 in kdb_enter (msg=0x12
) at cpufunc.h:60 #9 0xc06c2fc0 in panic (fmt=0xc0956e98 "if_freemulti: protospec not NULL") at ../../../kern/kern_shutdown.c:547 #10 0xc073aa18 in if_freemulti (ifma=0xc548f360) at ../../../net/if.c:2251 #11 0xc073b036 in if_delmulti_locked (ifp=0xc50fd000, ifma=0xc548f360, detaching=1) at ../../../net/if.c:2552 #12 0xc0737dd7 in if_purgemaddrs (ifp=0xc50fd000) at ../../../net/if.c:636 #13 0xc0737f0b in if_detach (ifp=0xc50fd000) at ../../../net/if.c:701 #14 0xc073e939 in lo_clone_destroy (ifp=0xc50fd000) at ../../../net/if_loop.c:131 #15 0xc073c1aa in ifc_simple_destroy (ifc=0xc0a015e0, ifp=0xc1433000) at ../../../net/if_clone.c:560 #16 0xc073b753 in if_clone_destroyif (ifc=0xc0a015e0, ifp=0xc50fd000) at ../../../net/if_clone.c:218 #17 0xc073b685 in if_clone_destroy (name=0xc548f9e0 "lo1") at ../../../net/if_clone.c:196 #18 0xc073a370 in ifioctl (so=0xc558ec3c, cmd=2149607801, data=0xc548f9e0 "lo1", td=0xc5529a20) at ../../../net/if.c:1849 #19 0xc06f4b2f in soo_ioctl (fp=0x12, cmd=2149607801, data=0xc548f9e0, active_cred=0xc5899880, td=0xc5529a20) at ../../../kern/sys_socket.c:202 #20 0xc06ef872 in kern_ioctl (td=0xc5529a20, fd=3, com=2149607801, data=0xc548f9e0 "lo1") at file.h:266 #21 0xc06ef595 in ioctl (td=0xc5529a20, uap=0xe7c9dd00) at ../../../kern/sys_generic.c:544 #22 0xc08c0d72 in syscall (frame=0xe7c9dd38) at ../../../i386/i386/trap.c:1010 #23 0xc08aa4e0 in Xint0x80_syscall () at ../../../i386/i386/exception.s:196 #24 0x00000033 in ?? () Previous frame inner to this frame (corrupt stack?) (kgdb) frame 10 #10 0xc073aa18 in if_freemulti (ifma=0xc548f360) at ../../../net/if.c:2251 2251 KASSERT(ifma->ifma_protospec == NULL, (kgdb) list 2246 if_freemulti(struct ifmultiaddr *ifma) 2247 { 2248 2249 KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d", 2250 ifma->ifma_refcount)); 2251 KASSERT(ifma->ifma_protospec == NULL, 2252 ("if_freemulti: protospec not NULL")); 2253 2254 if (ifma->ifma_lladdr != NULL) 2255 FREE(ifma->ifma_lladdr, M_IFMADDR); (kgdb) inspect *ifma $2 = {ifma_link = {tqe_next = 0x0, tqe_prev = 0xc50fd0bc}, ifma_addr = 0xc53210d0, ifma_lladdr = 0x0, ifma_ifp = 0x0, ifma_refcount = 0, ifma_protospec = 0xc5716180, ifma_llifma = 0x0} (kgdb) up #11 0xc073b036 in if_delmulti_locked (ifp=0xc50fd000, ifma=0xc548f360, detaching=1) at ../../../net/if.c:2552 2552 if_freemulti(ifma); (kgdb) inspect *ifp $3 = {if_softc = 0xc548c990, if_l2com = 0x0, if_link = {tqe_next = 0x0, tqe_prev = 0xc530b808}, if_xname = "lo1", '\0' , if_dname = 0xc0909303 "lo", if_dunit = 1, if_addrhead = { tqh_first = 0xc59b7600, tqh_last = 0xc59b7660}, if_klist = {kl_list = {slh_first = 0x0}, kl_lock = 0xc06a8d78 , kl_unlock = 0xc06a8d94 , kl_locked = 0xc06a8db0 , kl_lockarg = 0xc0a4d7f8}, if_pcount = 0, if_carp = 0x0, if_bpf = 0xc5716b80, if_index = 8, if_timer = 0, if_vlantrunk = 0x0, if_flags = 32776, if_capabilities = 0, if_capenable = 0, if_linkmib = 0x0, if_linkmiblen = 0, if_data = {ifi_type = 24 '\030', ifi_physical = 0 '\0', ifi_addrlen = 0 '\0', ifi_hdrlen = 0 '\0', ifi_link_state = 0 '\0', ifi_recvquota = 0 '\0', ifi_xmitquota = 0 '\0', ifi_datalen = 80 'P', ifi_mtu = 16384, ifi_metric = 0, ifi_baudrate = 0, ifi_ipackets = 0, ifi_ierrors = 0, ifi_opackets = 0, ifi_oerrors = 0, ifi_collisions = 0, ifi_ibytes = 0, ifi_obytes = 0, ifi_imcasts = 0, ifi_omcasts = 0, ifi_iqdrops = 0, ifi_noproto = 0, ifi_hwassist = 0, ifi_epoch = 7771, ifi_lastchange = {tv_sec = 1174954038, tv_usec = 187825}}, if_multiaddrs = {tqh_first = 0x0, tqh_last = 0xc50fd0bc}, if_amcount = 0, if_output = 0xc073eadc , if_input = 0, if_start = 0, if_ioctl = 0xc073ed14 , if_watchdog = 0, if_init = 0, if_resolvemulti = 0, if_addr = 0xc59b7600, if_spare2 = 0x0, if_spare3 = 0x0, if_drv_flags = 64, if_spare_flags2 = 0, if_snd = {ifq_head = 0x0, ifq_tail = 0x0, ifq_len = 0, ifq_maxlen = 50, ifq_drops = 0, ifq_mtx = {lock_object = {lo_name = 0xc50fd010 "lo1", lo_type = 0xc0956c03 "if send queue", lo_flags = 16973824, lo_witness_data = {lod_list = { stqe_next = 0xc0a5de98}, lod_witness = 0xc0a5de98}}, mtx_lock = 4, mtx_recurse = 0}, ifq_drv_head = 0x0, ifq_drv_tail = 0x0, ifq_drv_len = 0, ifq_drv_maxlen = 0, altq_type = 0, altq_flags = 0, altq_disc = 0x0, altq_ifp = 0xc50fd000, altq_enqueue = 0, altq_dequeue = 0, altq_request = 0, altq_clfier = 0x0, altq_classify = 0, altq_tbr = 0x0, altq_cdnr = 0x0}, if_broadcastaddr = 0x0, if_bridge = 0x0, lltables = 0x0, if_label = 0x0, if_prefixhead = {tqh_first = 0x0, tqh_last = 0xc50fd170}, if_afdata = {0x0 , 0xc548c720, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, if_afdata_initialized = 2, if_afdata_mtx = { lock_object = {lo_name = 0xc0956bf9 "if_afdata", lo_type = 0xc0956bf9 "if_afdata", lo_flags = 16973824, lo_witness_data = {lod_list = {stqe_next = 0xc0a5dec0}, lod_witness = 0xc0a5dec0}}, mtx_lock = 4, mtx_recurse = 0}, if_starttask = {ta_link = {stqe_next = 0x0}, ta_pending = 0, ta_priority = 0, ta_func = 0xc073b2b0 , ta_context = 0xc50fd000}, if_linktask = {ta_link = {stqe_next = 0x0}, ta_pending = 0, ta_priority = 0, ta_func = 0xc07393f8 , ta_context = 0xc50fd000}, if_addr_mtx = {lock_object = {lo_name = 0xc094f3db "if_addr_mtx", lo_type = 0xc094f3db "if_addr_mtx", lo_flags = 16973824, lo_witness_data = {lod_list = {stqe_next = 0xc0a5f388}, lod_witness = 0xc0a5f388}}, mtx_lock = 3310524960, mtx_recurse = 0}, if_clones = {le_next = 0xc530b800, le_prev = 0xc0a01628}, if_groups = { tqh_first = 0xc548c6f0, tqh_last = 0xc548c6f4}, if_pf_kif = 0x0} kgdb) inspect *ifma $4 = {ifma_link = {tqe_next = 0x0, tqe_prev = 0xc50fd0bc}, ifma_addr = 0xc53210d0, ifma_lladdr = 0x0, ifma_ifp = 0x0, ifma_refcount = 0, ifma_protospec = 0xc5716180, ifma_llifma = 0x0} (kgdb) up #12 0xc0737dd7 in if_purgemaddrs (ifp=0xc50fd000) at ../../../net/if.c:636 636 if_delmulti_locked(ifp, ifma, 1); (kgdb) up #13 0xc0737f0b in if_detach (ifp=0xc50fd000) at ../../../net/if.c:701 701 if_purgemaddrs(ifp); (kgdb) up #14 0xc073e939 in lo_clone_destroy (ifp=0xc50fd000) at ../../../net/if_loop.c:131 131 if_detach(ifp); (kgdb) up #15 0xc073c1aa in ifc_simple_destroy (ifc=0xc0a015e0, ifp=0xc1433000) at ../../../net/if_clone.c:560 560 ifcs->ifcs_destroy(ifp); (kgdb) inspect *ifc $5 = {ifc_list = {le_next = 0xc0a01400, le_prev = 0xc0a9d034}, ifc_name = 0xc0909303 "lo", ifc_maxunit = 32767, ifc_units = 0xc5316000 "\003", ifc_bmlen = 4096, ifc_data = 0xc0a015c4, ifc_attach = 0xc073bfe4 , ifc_match = 0xc073c070 , ifc_create = 0xc073c0d4 , ifc_destroy = 0xc073c18c , ifc_refcnt = 3, ifc_mtx = {lock_object = {lo_name = 0xc0957019 "if_clone lock", lo_type = 0xc0957019 "if_clone lock", lo_flags = 16973824, lo_witness_data = {lod_list = {stqe_next = 0xc0a5dbc8}, lod_witness = 0xc0a5dbc8}}, mtx_lock = 4, mtx_recurse = 0}, ifc_iflist = {lh_first = 0xc530b800}} (kgdb) up #16 0xc073b753 in if_clone_destroyif (ifc=0xc0a015e0, ifp=0xc50fd000) at ../../../net/if_clone.c:218 218 err = (*ifc->ifc_destroy)(ifc, ifp); (kgdb) up #17 0xc073b685 in if_clone_destroy (name=0xc548f9e0 "lo1") at ../../../net/if_clone.c:196 196 return (if_clone_destroyif(ifc, ifp)); (kgdb) up #18 0xc073a370 in ifioctl (so=0xc558ec3c, cmd=2149607801, data=0xc548f9e0 "lo1", td=0xc5529a20) at ../../../net/if.c:1849 1849 return if_clone_destroy(ifr->ifr_name); --------------080000050300080700070504--