On Tue, Dec 13, 2016 at 12:35:07PM +0100, Martin Pieuchot wrote:
> Hello,
>
> On 10/12/16(Sat) 11:08, Dimitris Papastamos wrote:
> > While I was playing around with the ip4 multicast code, I thought
> > I would attempt to make the membership data structure similar to that
> > of ip6. This means changing from a dynamic array to a linked list.
>
> I like this a lot. Coherency is good.
>
> > The max membership limit has been lifted (I did not see a similar limit
> > in the ip6 code). I am not sure if this is appropriate for ip4 though.
> > I can add the limit back if necessary.
>
> I can't think of a reason why it was there in the first place.
>
> > My system seems to work with this patch but I have not explicitly
> > tested all the code paths I have modified. I am working on some small
> > tests to prove that it works.
>
> carp(4), pfsync(4) and vxlan(4) as well as ports using multicast like
> avahi-daemon should be tested.
Updated diff based on your comments below. I am still testing this though.
If anyone can help with the testing, it would be great!
diff --git a/share/man/man4/ip.4 b/share/man/man4/ip.4
index 82ad06c..607c500 100644
--- a/share/man/man4/ip.4
+++ b/share/man/man4/ip.4
@@ -431,10 +431,6 @@ the host is multihomed.
Membership is associated with a single interface;
programs running on multihomed hosts may need to
join the same group on more than one interface.
-Up to
-.Dv IP_MAX_MEMBERSHIPS
-(currently 4095) memberships may be added on a
-single socket.
.Pp
To drop a membership, use:
.Bd -literal -offset indent
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
index 117d03f..079a593 100644
--- a/sys/net/if_pfsync.c
+++ b/sys/net/if_pfsync.c
@@ -313,10 +313,7 @@ pfsync_clone_create(struct if_clone *ifc, int unit)
sc->sc_len = PFSYNC_MINPKT;
sc->sc_maxupdates = 128;
- sc->sc_imo.imo_membership = (struct in_multi **)malloc(
- (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
- M_WAITOK | M_ZERO);
- sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+ LIST_INIT(&sc->sc_imo.imo_memberships);
ifp = &sc->sc_if;
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
@@ -378,7 +375,6 @@ pfsync_clone_destroy(struct ifnet *ifp)
}
pool_destroy(&sc->sc_pool);
- free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
free(sc, M_DEVBUF, sizeof(*sc));
pfsyncif = NULL;
@@ -1319,11 +1315,14 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_sync_if->if_linkstatehooks,
sc->sc_lhcookie);
sc->sc_sync_if = NULL;
- if (imo->imo_num_memberships > 0) {
- in_delmulti(imo->imo_membership[
- --imo->imo_num_memberships]);
- imo->imo_ifidx = 0;
+ if (!LIST_EMPTY(&imo->imo_memberships)) {
+ struct in_multi_mship *imm =
+ LIST_FIRST(&imo->imo_memberships);
+
+ LIST_REMOVE(imm, imm_chain);
+ in_leavegroup(imm);
}
+ imo->imo_ifidx = 0;
splx(s);
break;
}
@@ -1345,13 +1344,18 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_lhcookie);
sc->sc_sync_if = sifp;
- if (imo->imo_num_memberships > 0) {
-
in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
- imo->imo_ifidx = 0;
+ if (!LIST_EMPTY(&imo->imo_memberships)) {
+ struct in_multi_mship *imm =
+ LIST_FIRST(&imo->imo_memberships);
+
+ LIST_REMOVE(imm, imm_chain);
+ in_leavegroup(imm);
}
+ imo->imo_ifidx = 0;
if (sc->sc_sync_if &&
sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
+ struct in_multi_mship *imm;
struct in_addr addr;
if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) {
@@ -1362,16 +1366,16 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
addr.s_addr = INADDR_PFSYNC_GROUP;
- if ((imo->imo_membership[0] =
- in_addmulti(&addr, sc->sc_sync_if)) == NULL) {
+ if ((imm = in_joingroup(&addr,
+ sc->sc_sync_if)) == NULL) {
sc->sc_sync_if = NULL;
splx(s);
return (ENOBUFS);
}
- imo->imo_num_memberships++;
imo->imo_ifidx = sc->sc_sync_if->if_index;
imo->imo_ttl = PFSYNC_DFLTTL;
imo->imo_loop = 0;
+ LIST_INSERT_HEAD(&imo->imo_memberships, imm, imm_chain);
}
ip = &sc->sc_template;
diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c
index e9bc1cb..b9acae1 100644
--- a/sys/net/if_vxlan.c
+++ b/sys/net/if_vxlan.c
@@ -129,10 +129,7 @@ vxlan_clone_create(struct if_clone *ifc, int unit)
M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
return (ENOMEM);
- sc->sc_imo.imo_membership = malloc(
- (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
- M_WAITOK|M_ZERO);
- sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+ LIST_INIT(&sc->sc_imo.imo_memberships);
sc->sc_dstport = htons(VXLAN_PORT);
sc->sc_vnetid = VXLAN_VNI_UNSET;
@@ -190,7 +187,6 @@ vxlan_clone_destroy(struct ifnet *ifp)
ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
ether_ifdetach(ifp);
if_detach(ifp);
- free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
free(sc, M_DEVBUF, sizeof(*sc));
return (0);
@@ -223,10 +219,14 @@ vxlan_multicast_cleanup(struct ifnet *ifp)
if_put(mifp);
}
- if (imo->imo_num_memberships > 0) {
- in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
- imo->imo_ifidx = 0;
+ if (!LIST_EMPTY(&imo->imo_memberships)) {
+ struct in_multi_mship *imm =
+ LIST_FIRST(&imo->imo_memberships);
+
+ LIST_REMOVE(imm, imm_chain);
+ in_leavegroup(imm);
}
+ imo->imo_ifidx = 0;
}
int
@@ -241,6 +241,7 @@ vxlan_multicast_join(struct ifnet *ifp, struct sockaddr
*src,
#endif /* INET6 */
struct ifaddr *ifa;
struct ifnet *mifp;
+ struct in_multi_mship *imm;
switch (dst->sa_family) {
case AF_INET:
@@ -272,17 +273,16 @@ vxlan_multicast_join(struct ifnet *ifp, struct sockaddr
*src,
(mifp->if_flags & IFF_MULTICAST) == 0)
return (EADDRNOTAVAIL);
- if ((imo->imo_membership[0] =
- in_addmulti(&dst4->sin_addr, mifp)) == NULL)
+ if ((imm = in_joingroup(&dst4->sin_addr, mifp)) == NULL)
return (ENOBUFS);
- imo->imo_num_memberships++;
imo->imo_ifidx = mifp->if_index;
if (sc->sc_ttl > 0)
imo->imo_ttl = sc->sc_ttl;
else
imo->imo_ttl = IP_DEFAULT_MULTICAST_TTL;
imo->imo_loop = 0;
+ LIST_INSERT_HEAD(&imo->imo_memberships, imm, imm_chain);
/*
* Use interface hooks to track any changes on the interface
diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
index f1b142c..a5eabe9 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -668,6 +668,7 @@ igmp_sendpkt(struct ifnet *ifp, struct in_multi *inm, int
type,
#else
imo.imo_loop = 0;
#endif /* MROUTING */
+ LIST_INIT(&imo.imo_memberships);
ip_output(m, router_alert, NULL, IP_MULTICASTOPTS, &imo, NULL, 0);
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 2513b31..b5380f5 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -908,6 +908,32 @@ in_hasmulti(struct in_addr *ap, struct ifnet *ifp)
return (joined);
}
+struct in_multi_mship *
+in_joingroup(struct in_addr *ap, struct ifnet *ifp)
+{
+ struct in_multi_mship *imm;
+
+ imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT);
+ if (imm == NULL)
+ return NULL;
+
+ imm->imm_maddr = in_addmulti(ap, ifp);
+ if (imm->imm_maddr == NULL) {
+ free(imm, M_IPMADDR, sizeof(*imm));
+ return NULL;
+ }
+
+ return imm;
+}
+
+void
+in_leavegroup(struct in_multi_mship *imm)
+{
+ if (imm->imm_maddr != NULL)
+ in_delmulti(imm->imm_maddr);
+ free(imm, M_IPMADDR, sizeof(*imm));
+}
+
void
in_ifdetach(struct ifnet *ifp)
{
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 4b2b0f5..19b753e 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -342,13 +342,6 @@ struct ip_opts {
*/
#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1
hop */
#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a
member */
-/*
- * The imo_membership vector for each socket starts at IP_MIN_MEMBERSHIPS
- * and is dynamically allocated at run-time, bounded by IP_MAX_MEMBERSHIPS,
- * and is reallocated when needed, sized according to a power-of-two increment.
- */
-#define IP_MIN_MEMBERSHIPS 15
-#define IP_MAX_MEMBERSHIPS 4095
/*
* Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index d7de540..12df2b4 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -109,6 +109,7 @@
#include <net/rtable.h>
#include <netinet/in.h>
+#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
index a265580..b8db50b 100644
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -123,6 +123,12 @@ struct in_multi {
struct router_info *inm_rti; /* router version info */
};
+/* multicast membership entry */
+struct in_multi_mship {
+ struct in_multi *imm_maddr; /* multicast address pointer */
+ LIST_ENTRY(in_multi_mship) imm_chain; /* multicast options chain */
+};
+
static __inline struct in_multi *
ifmatoinm(struct ifmaddr *ifma)
{
@@ -155,6 +161,8 @@ int in_ifinit(struct ifnet *,
struct in_multi *in_addmulti(struct in_addr *, struct ifnet *);
void in_delmulti(struct in_multi *);
int in_hasmulti(struct in_addr *, struct ifnet *);
+struct in_multi_mship *in_joingroup(struct in_addr *, struct ifnet *);
+void in_leavegroup(struct in_multi_mship *);
void in_ifscrub(struct ifnet *, struct in_ifaddr *);
int in_control(struct socket *, u_long, caddr_t, struct ifnet *);
int in_ioctl(u_long, caddr_t, struct ifnet *, int);
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 8165216..926cf1e 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -789,10 +789,7 @@ carp_clone_create(struct if_clone *ifc, int unit)
#ifdef INET6
sc->sc_im6o.im6o_hlim = CARP_DFLTTL;
#endif /* INET6 */
- sc->sc_imo.imo_membership = (struct in_multi **)malloc(
- (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
- M_WAITOK|M_ZERO);
- sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+ LIST_INIT(&sc->sc_imo.imo_memberships);
LIST_INIT(&sc->carp_mc_listhead);
ifp = &sc->sc_if;
@@ -869,7 +866,6 @@ carp_clone_destroy(struct ifnet *ifp)
if_detach(ifp);
carp_destroy_vhosts(ifp->if_softc);
refcnt_finalize(&sc->sc_refcnt, "carpdtor");
- free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
free(sc, M_DEVBUF, sizeof(*sc));
return (0);
}
@@ -1641,16 +1637,14 @@ carp_multicast_cleanup(struct carp_softc *sc)
#ifdef INET6
struct ip6_moptions *im6o = &sc->sc_im6o;
#endif
- u_int16_t n = imo->imo_num_memberships;
- /* Clean up our own multicast memberships */
- while (n-- > 0) {
- if (imo->imo_membership[n] != NULL) {
- in_delmulti(imo->imo_membership[n]);
- imo->imo_membership[n] = NULL;
- }
+ while (!LIST_EMPTY(&imo->imo_memberships)) {
+ struct in_multi_mship *imm =
+ LIST_FIRST(&imo->imo_memberships);
+
+ LIST_REMOVE(imm, imm_chain);
+ in_leavegroup(imm);
}
- imo->imo_num_memberships = 0;
imo->imo_ifidx = 0;
#ifdef INET6
@@ -1837,21 +1831,10 @@ carp_addr_updated(void *v)
sc->sc_naddrs6 = new_naddrs6;
/* Re-establish multicast membership removed by in_control */
- if (IN_MULTICAST(sc->sc_peer.s_addr)) {
- if (!in_hasmulti(&sc->sc_peer, &sc->sc_if)) {
- struct in_multi **imm =
- sc->sc_imo.imo_membership;
- u_int16_t maxmem =
- sc->sc_imo.imo_max_memberships;
-
- memset(&sc->sc_imo, 0, sizeof(sc->sc_imo));
- sc->sc_imo.imo_membership = imm;
- sc->sc_imo.imo_max_memberships = maxmem;
-
+ if (IN_MULTICAST(sc->sc_peer.s_addr))
+ if (!in_hasmulti(&sc->sc_peer, &sc->sc_if))
if (sc->sc_carpdev != NULL && sc->sc_naddrs > 0)
carp_join_multicast(sc);
- }
- }
if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) {
sc->sc_if.if_flags &= ~IFF_UP;
@@ -1889,21 +1872,20 @@ int
carp_join_multicast(struct carp_softc *sc)
{
struct ip_moptions *imo = &sc->sc_imo;
- struct in_multi *imm;
+ struct in_multi_mship *imm;
struct in_addr addr;
if (!IN_MULTICAST(sc->sc_peer.s_addr))
return (0);
addr.s_addr = sc->sc_peer.s_addr;
- if ((imm = in_addmulti(&addr, &sc->sc_if)) == NULL)
+ if ((imm = in_joingroup(&addr, &sc->sc_if)) == NULL)
return (ENOBUFS);
- imo->imo_membership[0] = imm;
- imo->imo_num_memberships = 1;
imo->imo_ifidx = sc->sc_if.if_index;
imo->imo_ttl = CARP_DFLTTL;
imo->imo_loop = 0;
+ LIST_INSERT_HEAD(&imo->imo_memberships, imm, imm_chain);
return (0);
}
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index e48ded8..abad4c7 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -80,6 +80,7 @@
#include <net/route.h>
#include <netinet/in.h>
+#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/in_pcb.h>
@@ -1599,6 +1600,7 @@ send_packet(struct vif *vifp, struct mbuf *m)
imo.imo_ifidx = vifp->v_ifp->if_index;
imo.imo_ttl = mtod(m, struct ip *)->ip_ttl - IPTTLDEC;
imo.imo_loop = 1;
+ LIST_INIT(&imo.imo_memberships);
s = splsoftnet();
ip_output(m, NULL, NULL, IP_FORWARDING, &imo, NULL, 0);
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 10b4ada..603d45d 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1342,10 +1342,10 @@ ip_setmoptions(int optname, struct ip_moptions **imop,
struct mbuf *m,
struct ip_mreq *mreq;
struct ifnet *ifp = NULL;
struct ip_moptions *imo = *imop;
- struct in_multi **immp;
+ struct in_multi_mship *imm;
struct rtentry *rt;
struct sockaddr_in sin;
- int i, error = 0;
+ int error = 0;
u_char loop;
if (imo == NULL) {
@@ -1354,16 +1354,11 @@ ip_setmoptions(int optname, struct ip_moptions **imop,
struct mbuf *m,
* allocate one and initialize to default values.
*/
imo = malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK|M_ZERO);
- immp = (struct in_multi **)malloc(
- (sizeof(*immp) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
- M_WAITOK|M_ZERO);
*imop = imo;
imo->imo_ifidx = 0;
imo->imo_ttl = IP_DEFAULT_MULTICAST_TTL;
imo->imo_loop = IP_DEFAULT_MULTICAST_LOOP;
- imo->imo_num_memberships = 0;
- imo->imo_max_memberships = IP_MIN_MEMBERSHIPS;
- imo->imo_membership = immp;
+ LIST_INIT(&imo->imo_memberships);
}
switch (optname) {
@@ -1482,65 +1477,29 @@ ip_setmoptions(int optname, struct ip_moptions **imop,
struct mbuf *m,
break;
}
/*
- * See if the membership already exists or if all the
- * membership slots are full.
+ * See if the membership already exists.
*/
- for (i = 0; i < imo->imo_num_memberships; ++i) {
- if (imo->imo_membership[i]->inm_ifidx
- == ifp->if_index &&
- imo->imo_membership[i]->inm_addr.s_addr
- == mreq->imr_multiaddr.s_addr)
+ LIST_FOREACH(imm, &imo->imo_memberships, imm_chain)
+ if (imm->imm_maddr->inm_ifidx == ifp->if_index &&
+ imm->imm_maddr->inm_addr.s_addr ==
+ mreq->imr_multiaddr.s_addr)
break;
- }
- if (i < imo->imo_num_memberships) {
+ if (imm != NULL) {
error = EADDRINUSE;
if_put(ifp);
break;
}
- if (imo->imo_num_memberships == imo->imo_max_memberships) {
- struct in_multi **nmships, **omships;
- size_t newmax;
- /*
- * Resize the vector to next power-of-two minus 1. If
the
- * size would exceed the maximum then we know we've
really
- * run out of entries. Otherwise, we reallocate the
vector.
- */
- nmships = NULL;
- omships = imo->imo_membership;
- newmax = ((imo->imo_max_memberships + 1) * 2) - 1;
- if (newmax <= IP_MAX_MEMBERSHIPS) {
- nmships = (struct in_multi **)malloc(
- sizeof(*nmships) * newmax, M_IPMOPTS,
- M_NOWAIT|M_ZERO);
- if (nmships != NULL) {
- memcpy(nmships, omships,
- sizeof(*omships) *
- imo->imo_max_memberships);
- free(omships, M_IPMOPTS,
- sizeof(*omships) *
- imo->imo_max_memberships);
- imo->imo_membership = nmships;
- imo->imo_max_memberships = newmax;
- }
- }
- if (nmships == NULL) {
- error = ENOBUFS;
- if_put(ifp);
- break;
- }
- }
/*
* Everything looks good; add a new record to the multicast
* address list for the given interface.
*/
- if ((imo->imo_membership[i] =
- in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
+ if ((imm = in_joingroup(&mreq->imr_multiaddr, ifp)) == NULL) {
error = ENOBUFS;
if_put(ifp);
break;
}
- ++imo->imo_num_memberships;
if_put(ifp);
+ LIST_INSERT_HEAD(&imo->imo_memberships, imm, imm_chain);
break;
case IP_DROP_MEMBERSHIP:
@@ -1576,17 +1535,15 @@ ip_setmoptions(int optname, struct ip_moptions **imop,
struct mbuf *m,
ifp = ia->ia_ifp;
}
/*
- * Find the membership in the membership array.
+ * Find the membership in the membership list.
*/
- for (i = 0; i < imo->imo_num_memberships; ++i) {
+ LIST_FOREACH(imm, &imo->imo_memberships, imm_chain)
if ((ifp == NULL ||
- imo->imo_membership[i]->inm_ifidx ==
- ifp->if_index) &&
- imo->imo_membership[i]->inm_addr.s_addr ==
- mreq->imr_multiaddr.s_addr)
+ imm->imm_maddr->inm_ifidx == ifp->if_index) &&
+ imm->imm_maddr->inm_addr.s_addr ==
+ mreq->imr_multiaddr.s_addr)
break;
- }
- if (i == imo->imo_num_memberships) {
+ if (imm == NULL) {
error = EADDRNOTAVAIL;
break;
}
@@ -1594,13 +1551,8 @@ ip_setmoptions(int optname, struct ip_moptions **imop,
struct mbuf *m,
* Give up the multicast address record to which the
* membership points.
*/
- in_delmulti(imo->imo_membership[i]);
- /*
- * Remove the gap in the membership array.
- */
- for (++i; i < imo->imo_num_memberships; ++i)
- imo->imo_membership[i-1] = imo->imo_membership[i];
- --imo->imo_num_memberships;
+ LIST_REMOVE(imm, imm_chain);
+ in_leavegroup(imm);
break;
default:
@@ -1614,8 +1566,7 @@ ip_setmoptions(int optname, struct ip_moptions **imop,
struct mbuf *m,
if (imo->imo_ifidx == 0 &&
imo->imo_ttl == IP_DEFAULT_MULTICAST_TTL &&
imo->imo_loop == IP_DEFAULT_MULTICAST_LOOP &&
- imo->imo_num_memberships == 0) {
- free(imo->imo_membership , M_IPMOPTS, 0);
+ LIST_EMPTY(&imo->imo_memberships)) {
free(*imop, M_IPMOPTS, sizeof(**imop));
*imop = NULL;
}
@@ -1677,14 +1628,17 @@ ip_getmoptions(int optname, struct ip_moptions *imo,
struct mbuf **mp)
void
ip_freemoptions(struct ip_moptions *imo)
{
- int i;
+ struct in_multi_mship *imm;
+
+ if (imo == NULL)
+ return;
- if (imo != NULL) {
- for (i = 0; i < imo->imo_num_memberships; ++i)
- in_delmulti(imo->imo_membership[i]);
- free(imo->imo_membership, M_IPMOPTS, 0);
- free(imo, M_IPMOPTS, sizeof(*imo));
+ while (!LIST_EMPTY(&imo->imo_memberships)) {
+ imm = LIST_FIRST(&imo->imo_memberships);
+ LIST_REMOVE(imm, imm_chain);
+ in_leavegroup(imm);
}
+ free(imo, M_IPMOPTS, sizeof(*imo));
}
/*
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 7d1663d..6e1d2cc 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -148,12 +148,10 @@ ipstat_inc(enum ipstat_counters c)
* passed to ip_output when IP multicast options are in use.
*/
struct ip_moptions {
- struct in_multi **imo_membership; /* group memberships */
+ LIST_HEAD(, in_multi_mship) imo_memberships; /* group memberships */
unsigned short imo_ifidx; /* ifp index for outgoing multicasts */
u_int8_t imo_ttl; /* TTL for outgoing multicasts */
u_int8_t imo_loop; /* 1 => hear sends if a member */
- u_int16_t imo_num_memberships; /* no. memberships this socket */
- u_int16_t imo_max_memberships; /* max memberships this socket */
};
#include <sys/queue.h>
--
2.9.0