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.
Some comments below.
> Index: sys/net/if_pfsync.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pfsync.c,v
> retrieving revision 1.238
> diff -u -p -r1.238 if_pfsync.c
> --- sys/net/if_pfsync.c 22 Nov 2016 19:29:54 -0000 1.238
> +++ sys/net/if_pfsync.c 10 Dec 2016 10:31:08 -0000
> @@ -313,10 +313,7 @@ pfsync_clone_create(struct if_clone *ifc
> 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,9 +1315,11 @@ pfsyncioctl(struct ifnet *ifp, u_long cm
> 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]);
> + 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;
> }
This is all correct but I'd suggest to keep the difference with other
multicast code as small as possible. If I take carp(4)'s example, it
becomes:
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_ifidx = 0;
> @@ -1345,13 +1343,17 @@ pfsyncioctl(struct ifnet *ifp, u_long cm
> sc->sc_lhcookie);
> sc->sc_sync_if = sifp;
>
> - if (imo->imo_num_memberships > 0) {
> -
> in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
> + 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;
> }
Same here ;)
> @@ -1362,16 +1364,15 @@ pfsyncioctl(struct ifnet *ifp, u_long cm
>
> 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) {
Isn't this line longer than 80 chars?
> Index: sys/netinet/in_var.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet/in_var.h,v
> retrieving revision 1.39
> diff -u -p -r1.39 in_var.h
> --- sys/netinet/in_var.h 15 Jun 2016 19:39:34 -0000 1.39
> +++ sys/netinet/in_var.h 10 Dec 2016 10:31:08 -0000
> @@ -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 */
> +};
Be careful about long lines! :)
> Index: sys/netinet/ip_output.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/ip_output.c,v
> retrieving revision 1.331
> diff -u -p -r1.331 ip_output.c
> --- sys/netinet/ip_output.c 28 Nov 2016 10:14:00 -0000 1.331
> +++ sys/netinet/ip_output.c 10 Dec 2016 10:31:08 -0000
> @@ -1480,65 +1475,28 @@ ip_setmoptions(int optname, struct ip_mo
> 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)
Long line here too :)
> 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,15 +1534,12 @@ ip_setmoptions(int optname, struct ip_mo
> /*
> * Find the membership in the membership array.
> */
> - 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)
And here.
> break;
> - }
> - if (i == imo->imo_num_memberships) {
> + if (imm == NULL) {
> error = EADDRNOTAVAIL;
> break;
> }