[Fwd: Panic: if_freemulti: protospec not NULL]
- From: "Bruce M. Simpson" <bms@xxxxxxxxxxx>
- Date: Tue, 27 Mar 2007 17:19:33 +0100
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
==== //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) {
--- Begin Message ---_______________________________________________
- From: Andre Oppermann <andre@xxxxxxxxxxx>
- Date: Tue, 27 Mar 2007 13:40:14 +0200
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 <Address 0x12 out of bounds>) 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' <repeats 12 times>, 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 <knlist_mtx_lock>, kl_unlock = 0xc06a8d94 <knlist_mtx_unlock>,
kl_locked = 0xc06a8db0 <knlist_mtx_locked>, 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 <looutput>, if_input = 0, if_start = 0,
if_ioctl = 0xc073ed14 <loioctl>, 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 <repeats 28 times>,
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 <if_start_deferred>, ta_context = 0xc50fd000}, if_linktask = {ta_link = {stqe_next = 0x0},
ta_pending = 0, ta_priority = 0, ta_func = 0xc07393f8 <do_link_state_change>, 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_simple_attach>, ifc_match = 0xc073c070 <ifc_simple_match>,
ifc_create = 0xc073c0d4 <ifc_simple_create>, ifc_destroy = 0xc073c18c <ifc_simple_destroy>, 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);
--- End Message ---
freebsd-current@xxxxxxxxxxx mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscribe@xxxxxxxxxxx"
- Follow-Ups:
- Re: [Fwd: Panic: if_freemulti: protospec not NULL]
- From: Andre Oppermann
- Re: [Fwd: Panic: if_freemulti: protospec not NULL]
- Prev by Date: Re: current panics when Netgear WG511T ejected (and other NICs too)
- Next by Date: Re: Latest -current complete lockup (tcp changes?)
- Previous by thread: panic related to ACPI
- Next by thread: Re: [Fwd: Panic: if_freemulti: protospec not NULL]
- Index(es):
Relevant Pages
|
|