[Bug 242677] multicast: setsockopt(...IP_DROP_MEMBERSHIP...) doesn't lead to sending IGMP packet.

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Tue Dec 17 07:26:54 UTC 2019


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=242677

            Bug ID: 242677
           Summary: multicast: setsockopt(...IP_DROP_MEMBERSHIP...)
                    doesn't lead to sending IGMP packet.
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Many People
          Priority: ---
         Component: kern
          Assignee: bugs at FreeBSD.org
          Reporter: aleksandr.fedorov at itglobal.com
 Attachment #210002 text/plain
         mime type:

Created attachment 210002
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=210002&action=edit
Test code.

Revision 355322 fixes multicast in case of closing the socket.

But the problem remains if you try to exit the multicast group before closing
the socket.

If you run test code from attachment.
#./mcasttest
Add membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 239.0.0.5 mode exclude
                        mcast-macaddr 01:00:5e:00:00:05
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01
Drop membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01
Add membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 239.0.0.5 mode exclude
                        mcast-macaddr 01:00:5e:00:00:05
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01
Drop membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01


As you can see, the ADD/DROP membership to/from the group is successful.

But, there are no IGMP leave packets on igb1:
# tcpdump -i igb1 -vvv
tcpdump: listening on igb1, link-type EN10MB (Ethernet), capture size 262144
bytes
08:14:31.403346 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has
192.168.1.55 tell 192.168.1.55, length 28
08:14:33.678193 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]
08:14:34.526191 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]
08:14:37.905173 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]
08:14:39.177149 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]

It seems that the function inp_leave_group() is broken:

2409            if (is_final) {
2410                    ip_mfilter_remove(&imo->imo_head, imf);

(1) For IP_DROP_MEMBERSHIP is_final is true. Mark socket-layer filter set as
INCLUDE {} at t1.

2411                    imf_leave(imf);
2412            } else {
2413                    if (imf->imf_st[0] == MCAST_EXCLUDE) {
2414                            error = EADDRNOTAVAIL;
2415                            goto out_inp_locked;
2416                    }
2417                    ims = imo_match_source(imf, &ssa->sa);
2418                    if (ims == NULL) {
2419                            CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent",
2420                                __func__, ntohl(ssa->sin.sin_addr.s_addr),
"not ");
2421                            error = EADDRNOTAVAIL;
2422                            goto out_inp_locked;
2423                    }
2424                    CTR2(KTR_IGMPV3, "%s: %s source", __func__, "block");
2425                    error = imf_prune(imf, &ssa->sin);
2426                    if (error) {
2427                            CTR1(KTR_IGMPV3, "%s: merge imf state failed",
2428                                __func__);
2429                            goto out_inp_locked;
2430                    }
2431            }
2432    
....

(2) Commit and reap socket filter deltas.

2460            imf_commit(imf);
2461            imf_reap(imf);
2462    
2463    out_inp_locked:
2464            INP_WUNLOCK(inp);
2465    
2466            if (is_final && imf) {

2467                    /*
2468                     * Give up the multicast address record to which
2469                     * the membership points.
2470                     */

(3) in_leavegroup_locked() call igmp_change_state(). But, because source filter
deltas already committed and reaped, the call igmp_change_state() doesn't lead
to IGMP state transition and sending IGMP packets.

2471                    (void) in_leavegroup_locked(imf->imf_inm, imf);
2472                    ip_mfilter_free(imf);
2473            }
2474    
2475            IN_MULTI_UNLOCK();
2476            return (error);
2477    }

What do you think about move the in_leavegroup_locked() call before commit and
reap?
Something like this:

Index: sys/netinet/in_mcast.c
===================================================================
--- sys/netinet/in_mcast.c      (revision 355800)
+++ sys/netinet/in_mcast.c      (working copy)
@@ -2409,6 +2409,7 @@
        if (is_final) {
                ip_mfilter_remove(&imo->imo_head, imf);
                imf_leave(imf);
+               (void) in_leavegroup_locked(imf->imf_inm, imf);
        } else {
                if (imf->imf_st[0] == MCAST_EXCLUDE) {
                        error = EADDRNOTAVAIL;
@@ -2468,7 +2469,6 @@
                 * Give up the multicast address record to which
                 * the membership points.
                 */
-               (void) in_leavegroup_locked(imf->imf_inm, imf);
                ip_mfilter_free(imf);
        }

With this patch.

# ./mcasttest
Add membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 239.0.0.5 mode exclude
                        mcast-macaddr 01:00:5e:00:00:05
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01
Drop membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01
Add membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 239.0.0.5 mode exclude
                        mcast-macaddr 01:00:5e:00:00:05
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01
Drop membership
igb1:
        inet 192.168.1.55
        igmpv3 rv 2 qi 125 qri 10 uri 3
                group 224.0.0.1 mode exclude
                        mcast-macaddr 01:00:5e:00:00:01

And tcpdump shows:
# tcpdump -i igb1 -vvv
tcpdump: listening on igb1, link-type EN10MB (Ethernet), capture size 262144
bytes
10:19:22.059334 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has
192.168.1.55 tell 192.168.1.55, length 28
10:19:24.232247 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]
10:19:24.861942 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]
10:19:29.502570 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_in { }]
10:19:31.807624 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_in { }]
10:19:34.747646 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]
10:19:35.595604 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_ex { }]
10:19:39.818577 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_in { }]
10:19:40.242591 IP (tos 0xc0, ttl 1, id 0, offset 0, flags [DF], proto IGMP
(2), length 40, options (RA))
    192.168.1.55 > igmp.mcast.net: igmp v3 report, 1 group record(s) [gaddr
239.0.0.5 to_in { }]

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the freebsd-bugs mailing list