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;
>               }

Reply via email to