Subject: Question regarding RFC3810 in MLDv1 mode

From: Daniel Borkmann <[email-masked]>
Date: Tue, 09 Sep 2014 12:09:47 +0200

Hi IPv6 list,

if possible, I'd like to have a clarification regarding MLDv2 when
it's in MLDv1 fallback mode:

RFC2710 for MLDv1, section 3.7. says:

   The length of a received MLD message is computed by taking the
   IPv6 Payload Length value and subtracting the length of any IPv6
   extension headers present between the IPv6 header and the MLD
   message. If that length is greater than 24 octets, that indicates
   that there are other fields present beyond the fields described
   above, perhaps belonging to a *future backwards-compatible* version
   of MLD. An implementation of the version of MLD specified in this
   document MUST NOT send an MLD message longer than 24 octets and
   MUST ignore anything past the first 24 octets of a received MLD
   message.

RFC3810 for MLDv2, section 8.2.1. says regarding presence of MLDv1
routers:

   In order to be compatible with MLDv1 routers, MLDv2 hosts MUST
   operate in version 1 compatibility mode. [...] When Host Compatibility
   Mode is MLDv2, a host acts using the MLDv2 protocol on that interface.
   When Host Compatibility Mode is MLDv1, a host acts in MLDv1 compatibility
   mode, using *only* the MLDv1 protocol, on that interface. [...]

It's a bit vaguely described what exactly should happen when in MLDv1
mode and MLDv2 queries are received :

As I understand, given we operate *only* in MLDv1 mode, MLDv1 RFC says
that we MUST ignore everything beyond the 24 octets. That would mean
that we also have to process MLDv2 queries, correct?

If that's the case, we would need to send out an MLDv1 response as an
answer to that MLDv2 query that has been processed in MLDv1 mode, correct?

When we are in MLDv1 mode, we actually expect MLDv1 queries (== 24 octets
length), but when receiving an MLDv2 query (>= 28 octets length), we
only must process the first 24 octets. E.g. in Linux that would be:

   MLDv1 query header:                    MLDv2 query header:

   struct mld_msg {                       struct mld2_query {
     struct icmp6hdr  mld_hdr;              struct icmp6hdr  mld2q_hdr;
     struct in6_addr  mld_mca;              struct in6_addr  mld2q_mca;
   };                                       ...
                                          };
   Members/mappings:

   #define mld{,2q}_type                 mld_hdr.icmp6_type
   #define mld{,2q}_code                 mld_hdr.icmp6_code
   #define mld{,2q}_cksum                mld_hdr.icmp6_cksum
   #define mld{,2q}_{mrc,maxdelay}       mld_hdr.icmp6_maxdelay

While type, code, cksum all map just fine into each other, the only
issue I see where the newer RFC remains silent is (if I didn't miss
anything), that there's a difference in how we interpret the maximum
response/delay time field:

RFC2710 for MLDv1, section 3.4. Maximum Response Delay:

   The Maximum Response Delay field is meaningful only in Query
   messages, and specifies the maximum allowed delay before
   sending a responding Report, in units of milliseconds. In all
   other messages, it is set to zero by the sender and ignored by
   receivers.

   Varying this value allows the routers to tune the "leave latency"
   (the time between the moment the last node on a link ceases
   listening to a particular multicast address and moment the
   routing protocol is notified that there are no longer any
   listeners for that address), as discussed in section 7.8. It
   also allows tuning of the burstiness of MLD traffic on a link,
   as discussed in section 7.3.

RFC3810, section 5.1.3. Maximum Response Code however interprets the
same header field as:

   The Maximum Response Code field specifies the maximum time allowed
   before sending a responding Report. The actual time allowed, called
   the Maximum Response Delay, is represented in units of milliseconds,
   and is derived from the Maximum Response Code as follows:

   If Maximum Response Code < 32768,
      Maximum Response Delay = Maximum Response Code

   If Maximum Response Code >= 32768, Maximum Response Code represents
   a floating-point value as follows:

     0 1 2 3 4 5 6 7 8 9 A B C D E F
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |1| exp |          mant         |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   Maximum Response Delay = (mant | 0x1000) << (exp+3)

   Small values of Maximum Response Delay allow MLDv2 routers to tune
   the "leave latency" (the time between the moment the last node on a
   link ceases to listen to a specific multicast address and the moment
   the routing protocol is notified that there are no more listeners for
   that address). Larger values, especially in the exponential range,
   allow the tuning of the burstiness of MLD traffic on a link.

Strictly speaking, if I see this correctly, that would mean if we *only*
operate in MLDv1 mode that MLDv1 doesn't know how to interpret this field
correctly. It would work 'most of the time' just fine as we could expect
the Maximum Response Code < 32768, but in case Maximum Response Code >= 32768
we would interpret that field differently, correct?

We could, of course, work around that since we know that the number of
octets differ in the two versions, and thus could use MLDv2's Maximum
Response Delay calculation, but actually MLDv1 is *unaware* of this.

I'm asking since right now, Linux behaviour on that regard has always
been (I believe for ~10 years) to drop MLDv2 queries when in MLDv1
compatibility mode, that means, everything != 24 octets has been
dropped in MLDv1. Are we still RFC conform by just dropping MLDv2 queries
when in MLDv1 mode, iow, with the current (Linux) behaviour as is?

Thanks for any clarification on that matter,

Daniel

---

From: Brian Haberman <[email-masked]>
Date: Tue, 09 Sep 2014 12:11:04 -0400

Hi Daniel,

> that we also have to process MLDv2 queries, correct?

Section 8.2.1 is describing the interaction between MLDv1 routers and
MLDv2 hosts.  In that situation, you will hear MLDv1 Queries.  Section
8.1 describes how the host knows the difference between the two types of
queries (message lengths are different).

There are potential situations where routers on the same network are
running different versions of MLD. Section 8.3.1 clearly states that the
lowest version of MLD should be used. This prevents a host from
receiving Queries from different versions.

> answer to that MLDv2 query that has been processed in MLDv1 mode, correct?

You are only in MLDv1 mode if the Query is also MLDv1.

> only must process the first 24 octets. E.g. in Linux that would be:

Given the logic in section 8.3.1, you should not get Queries from
different versions of MLD.

> RFC3810, section 5.1.3. Maximum Response Code however interprets the

Section 8.3.1 says that the logic in 5.1.3 is not used when in MLDv1
compatibility mode.

>     0 1 2 3 4 5 6 7 8 9 A B C D E F

Correct, *if* the spec allowed for mixing versions of MLD.  It doesn't.

Regards,
Brian

---

From: Daniel Borkmann <[email-masked]>
Date: Fri, 12 Sep 2014 10:23:08 +0200

On 09/09/2014 06:11 PM, Brian Haberman wrote:
...
> On 9/9/14 6:09 AM, Daniel Borkmann wrote:
...
>> it's in MLDv1 fallback mode:
...

Thanks a lot for the quick answer, Brian, that would confirm
my actual view on this matter.

Thanks,
Daniel

---

From: Timothy Winters <[email-masked]>
Date: Fri, 12 Sep 2014 09:28:05 -0400

Hi Brian,
	What about the case when an MLDv2 Router starts up and transmits MLDv2 Startup Query messages, before realizing there are MLDv1 Listeners?

	Shouldn't the MLDv1 Listener send a v1 Report to the Router when the MLD Query is received?

Regards,
Tim

On Sep 9, 2014, at 12:11 PM, Brian Haberman <[email-masked]> wrote:

> --------------------------------------------------------------------
> IETF IPv6 working group mailing list
> [email-masked]
> Administrative Requests: https://www.ietf.org/mailman/listinfo/ipv6
> --------------------------------------------------------------------

---

From: Brian Haberman <[email-masked]>
Date: Fri, 12 Sep 2014 10:22:42 -0400

Hi Tim,

On 9/12/14 9:28 AM, Timothy Winters wrote:
> Hi Brian, What about the case when an MLDv2 Router starts up and
> transmits MLDv2 Startup Query messages, before realizing there are
> MLDv1 Listeners?
> 

Yes, an MLDv1 Listener will respond to the MLDv2 Query.  The generated
report will force the router to move to MLDv1 Compatibility mode for the
specified multicast group.

The above case is the opposite of the one first mentioned, that of MLDv1
routers and MLDv2 hosts.

Regards,
Brian

> Regards, Tim
>>> if possible, I'd like to have a clarification regarding MLDv2
>>> when it's in MLDv1 fallback mode:
>>> 
>>> message. If that length is greater than 24 octets, that
>>> indicates that there are other fields present beyond the fields
>>> described above, perhaps belonging to a *future
>>> backwards-compatible* version of MLD. An implementation of the
>>> version of MLD specified in this document MUST NOT send an MLD
>>> message longer than 24 octets and MUST ignore anything past the
>>> first 24 octets of a received MLD message.
>>> 
>>> RFC3810 for MLDv2, section 8.2.1. says regarding presence of
>>> MLDv1 routers:
>>> 
>>> operate in version 1 compatibility mode. [...] When Host
>>> Compatibility Mode is MLDv2, a host acts using the MLDv2 protocol
>>> on that interface. When Host Compatibility Mode is MLDv1, a host
>>> acts in MLDv1 compatibility mode, using *only* the MLDv1
>>> protocol, on that interface. [...]
>>> 
>>> It's a bit vaguely described what exactly should happen when in
>>> MLDv1 mode and MLDv2 queries are received :
>>> 
>>> As I understand, given we operate *only* in MLDv1 mode, MLDv1 RFC
>>> says that we MUST ignore everything beyond the 24 octets. That
>>> would mean that we also have to process MLDv2 queries, correct?
>> 
>> Section 8.2.1 is describing the interaction between MLDv1 routers
>> and MLDv2 hosts.  In that situation, you will hear MLDv1 Queries.
>> Section 8.1 describes how the host knows the difference between the
>> two types of queries (message lengths are different).
>> 
>> There are potential situations where routers on the same network
>> are running different versions of MLD. Section 8.3.1 clearly states
>> that the lowest version of MLD should be used. This prevents a host
>> from receiving Queries from different versions.
>> 
>>> 
>>> If that's the case, we would need to send out an MLDv1 response
>>> as an answer to that MLDv2 query that has been processed in MLDv1
>>> mode, correct?
>> 
>>> When we are in MLDv1 mode, we actually expect MLDv1 queries (==
>>> 24 octets length), but when receiving an MLDv2 query (>= 28
>>> octets length), we only must process the first 24 octets. E.g. in
>>> Linux that would be:
>> 
>>> struct mld_msg {                       struct mld2_query { struct
>>> icmp6hdr  mld_hdr;              struct icmp6hdr  mld2q_hdr; 
>>> struct in6_addr  mld_mca;              struct in6_addr
>>> mld2q_mca; };                                       ... }; 
>>> Members/mappings:
>>> 
>>> #define mld{,2q}_type                 mld_hdr.icmp6_type #define
>>> mld{,2q}_code                 mld_hdr.icmp6_code #define
>>> mld{,2q}_cksum                mld_hdr.icmp6_cksum #define
>>> mld{,2q}_{mrc,maxdelay}       mld_hdr.icmp6_maxdelay
>>> 
>>> While type, code, cksum all map just fine into each other, the
>>> only issue I see where the newer RFC remains silent is (if I
>>> didn't miss anything), that there's a difference in how we
>>> interpret the maximum response/delay time field:
>>> 
>>> messages, and specifies the maximum allowed delay before sending
>>> a responding Report, in units of milliseconds. In all other
>>> messages, it is set to zero by the sender and ignored by 
>>> receivers.
>>> 
>>> Varying this value allows the routers to tune the "leave
>>> latency" (the time between the moment the last node on a link
>>> ceases listening to a particular multicast address and moment
>>> the routing protocol is notified that there are no longer any 
>>> listeners for that address), as discussed in section 7.8. It also
>>> allows tuning of the burstiness of MLD traffic on a link, as
>>> discussed in section 7.3.
>>> 
>>> RFC3810, section 5.1.3. Maximum Response Code however interprets
>>> the same header field as:
>> 
>> Section 8.3.1 says that the logic in 5.1.3 is not used when in
>> MLDv1 compatibility mode.
>> 
>>> 
>>> The Maximum Response Code field specifies the maximum time
>>> allowed before sending a responding Report. The actual time
>>> allowed, called the Maximum Response Delay, is represented in
>>> units of milliseconds, and is derived from the Maximum Response
>>> Code as follows:
>>> 
>>> If Maximum Response Code < 32768, Maximum Response Delay =
>>> Maximum Response Code
>>> 
>>> If Maximum Response Code >= 32768, Maximum Response Code
>>> represents a floating-point value as follows:
>>> 
>>> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| exp |          mant
>>> | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
>>> 
>>> Small values of Maximum Response Delay allow MLDv2 routers to
>>> tune the "leave latency" (the time between the moment the last
>>> node on a link ceases to listen to a specific multicast address
>>> and the moment the routing protocol is notified that there are no
>>> more listeners for that address). Larger values, especially in
>>> the exponential range, allow the tuning of the burstiness of MLD
>>> traffic on a link.
>>> 
>>> Strictly speaking, if I see this correctly, that would mean if we
>>> *only* operate in MLDv1 mode that MLDv1 doesn't know how to
>>> interpret this field correctly. It would work 'most of the time'
>>> just fine as we could expect the Maximum Response Code < 32768,
>>> but in case Maximum Response Code >= 32768 we would interpret
>>> that field differently, correct?
>> 
>> Regards, Brian
>> [email-masked] Administrative Requests:
>> https://www.ietf.org/mailman/listinfo/ipv6