The IPv4 code should clean up multicast group state when an interface

goes away. Without this change, it leaks in_multi (and often ether_multi
state) if many clonable interfaces are created and destroyed in quick
succession.

The concept of this fix is borrowed from KAME. Detailed information about
this behaviour, as well as test cases, are available in the PR.

PR:		kern/78227
MFC after:	1 week
This commit is contained in:
Bruce M Simpson 2006-09-28 10:04:07 +00:00
parent 2d78e8c5f1
commit d966841427
2 changed files with 33 additions and 2 deletions

View File

@ -1025,13 +1025,23 @@ void
in_delmulti(inm)
register struct in_multi *inm;
{
struct ifmultiaddr *ifma;
struct in_multi my_inm;
struct ifnet *ifp;
ifp = inm->inm_ifp;
IFF_LOCKGIANT(ifp);
IN_MULTI_LOCK();
in_delmulti_locked(inm);
IN_MULTI_UNLOCK();
IFF_UNLOCKGIANT(ifp);
}
void
in_delmulti_locked(inm)
register struct in_multi *inm;
{
struct ifmultiaddr *ifma;
struct in_multi my_inm;
ifma = inm->inm_ifma;
my_inm.inm_ifp = NULL ; /* don't send the leave msg */
if (ifma->ifma_refcount == 1) {
@ -1050,6 +1060,24 @@ in_delmulti(inm)
if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
if (my_inm.inm_ifp != NULL)
igmp_leavegroup(&my_inm);
}
/*
* Delete all multicast address records associated with the ifp.
*/
void
in_delmulti_ifp(ifp)
register struct ifnet *ifp;
{
struct in_multi *inm;
struct in_multi *oinm;
IFF_LOCKGIANT(ifp);
IN_MULTI_LOCK();
LIST_FOREACH_SAFE(inm, &in_multihead, inm_link, oinm) {
if (inm->inm_ifp == ifp)
in_delmulti_locked(inm);
}
IN_MULTI_UNLOCK();
IFF_UNLOCKGIANT(ifp);
}
@ -1064,4 +1092,5 @@ in_ifdetach(ifp)
in_pcbpurgeif0(&ripcbinfo, ifp);
in_pcbpurgeif0(&udbinfo, ifp);
in_delmulti_ifp(ifp);
}

View File

@ -247,6 +247,8 @@ do { \
struct route;
struct in_multi *in_addmulti(struct in_addr *, struct ifnet *);
void in_delmulti(struct in_multi *);
void in_delmulti_locked(struct in_multi *);
void in_delmulti_ifp(struct ifnet *ifp);
int in_control(struct socket *, u_long, caddr_t, struct ifnet *,
struct thread *);
void in_rtqdrain(void);