Subject: [tsvwg] UDP Options: how to do FRAG without LITE and forced UDP CS=0

From: "C. M. Heard" <[email-masked]>
Date: Fri, 28 Jun 2019 09:23:02 -0700

Greetings,

The version of FRAG defined in draft-ietf-tsvwg-udp-options-07 suffers
from the following disadvantages:

1) A legacy host that does not understand UDP options will erroneously
interpret FRAG without LITE as a complete UDP datagram.
2) The same is true for an options-aware host if OCS fails.
3) Because LITE data (by design) is not covered by OCS/CCO, FRAG+LITE
will have very poor middlebox traversal properties unless the UDP
checksum is set to zero.  For IPv6, even that will not work well,
because UDP CS=0 is often blocked by the network (this happened on
26%-36% of the paths in Raffaele Zullo's recent measurements)

All of these disadvantages can be avoided if the fragment data is
pulled into the option. That can be done as follows: instead of having
the FRAG option capture preceding conventional or LITE user data as
fragment data, insist that the FRAG option appear ***last*** in the
option list and have it capture all remaining octets in the packet as
fragment data. The length field is no longer needed (it is implicit),
so it can be replaced by a More Fragments (MF) flag. By convention, if
this option appears, OCS would cover all UDP options as well as all
octets in the UDP trailer that follow the FRAG option; thus, there
would be no need for a separate overall checksum -- the reassembled
datagram would be protected in a manner equivalent to the way TCP user
data is protected by the checksums on individual segments.

The revised FRAG option formats would be as follows:

                   +--------+--------+--------+--------+
                   | Kind=6 | MF=1  |  Frag. Offset   |
                   +--------+--------+--------+--------+
                   |          Identification           |
                   +--------+--------+--------+--------+
                   |       ... Fragment Data ...       |
                   +--------+--------+--------+--------+

               UDP non-terminal FRAG option format

                   +--------+--------+--------+--------+
                   | Kind=6 | MF=0  |  Frag. Offset   |
                   +--------+--------+--------+--------+
                   |          Identification           |
                   +--------+--------+--------+--------+
                   |       ... Fragment Data ...       |
                   +--------+--------+--------+--------+

                     UDP terminal FRAG option format

The following requirements would apply:

   >> When the FRAG option appears, it MUST come last in the UDP options
   list.  All remaining octets in the packet are interpreted as fragment
   data.

   >> OCS, if present, covers both the FRAG option and the trailing
   fragment data.

   >> A host that wishes to signal that it is able to accept and process
   the FRAG option MAY do so by transmitting an unfragmented datagram
   with an empty terminal FRAG option whose Offset field is set to zero.

   >> Non-empty FRAG options MUST NOT be present in packets with ordinary
   UDP user data or LITE data. Any such options MUST be silently dropped.

   >> UDP options other than OCS and padding MUST NOT accompany the FRAG
   option in non-terminal fragments.  Any such options MUST be silently
   dropped.  All other options that apply to a reassembled packet must
   accompany the FRAG header in the terminal fragment.

To handle the case when the user UDP CS setting specifies that the UDP
checksum should be zero, we just omit the OCS option (in line with the
proposal to always tie the presence or absence of OCS to the user UCP CS
setting). By not having a distinct overall checksum for the reassembled
packet, this version of FRAG avoids duplicate work (just as FRAG+LITE does
in the -07 draft). Having the OCS cover the data in each fragment provides
protection that is essentially the same as what TCP provides with
checksums and sequence numbers on individual segments, if the user has
requested a checksum. For in order to deliver the reassembled data, we
require all fragments to be present and to fit together exactly, with no
gaps and no overlap. The result is essentially equivalent to what is
provided by the post-reassembly checksum in the -07 draft, the main
difference being that the options are also included. Note that ACS is
still available if a stronger post-reassembly checksum is wanted.

I believe that this proposal squarely addresses the disadvantages of the
-07 version of FRAG that are enumerated at the beginning of this message.
It offers a solution that provides protection equivalent to conventional
IP fragmentation coupled with the standard UDP checksum, allows for
middlebox traversal, and avoids duplicate checksum computations.

Mike Heard

---

From: Joe Touch <[email-masked]>
Date: Fri, 28 Jun 2019 11:05:23 -0700

Hi, Mike, 

Intriguing as this is, I think you've overlooked two key design goals: 

1) we're not here to fix UDP CS=0. it either works or it doesn't. if
middleboxes are broken, they need to be fixed. 

in short, we cannot - and should not try to - make protocols robust to
arbitrary implementation errors. UDP isn't "byzantine robust" 

2) the FRAG+LITE current design moves only a small, fixed number of
bytes. 

The solution below doesn't appear to avoid copying/moving large amounts
of data. 

At a minimum, can you address #2? If we can do this without moving
around a lot of data, it might be viable. 

Some further points embedded below... 

Joe

> interpret FRAG without LITE as a complete UDP datagram.

I thought we converged to "don't use FRAG without LITE until you confirm
the other end speaks UDP options". What's the reason for needing FRAG
without LITE? 

> 2) The same is true for an options-aware host if OCS fails.

If OCS fails, why would an options-aware host do anything further with
the packet? 

> 26%-36% of the paths in Raffaele Zullo's recent measurements)

That's a significant bug, but we really shouldn't design protocols
simply to get around bugs. 

At least one reason is that IPv6 UDP CS=0 is valid for tunnels and needs
to be supported. 

> data is protected by the checksums on individual segments.

Frag reassembly is not the same as TCP reconstitution. Our IDs do not
operate in sequence,

---

From: "C. M. Heard" <[email-masked]>
Date: Fri, 28 Jun 2019 23:30:06 -0700

> around a lot of data, it might be viable.

Joe, unless I am missing something quite fundamental, my proposal
involves essentially the same amount of data movement as does the
current FRAG proposal (and even avoids the small, and I agree
insignificant, data movement that come with LITE). Here's how I see it:

- In my proposal, each fragment is preceded by a UDP header, an OCS
option (if enabled), NOP options as desired for alignment, and a
FRAG header. In the -07 draft, FRAG+LITE has the fragment data preceded
by a UDP header, with the fragment data following that, and the LITE,
OCS, and FRAG options at the end (this is after the LITE move on receive
or before the LITE move on transmit). In either case, some preceding
headers and/or options and (in the -07 draft) some trailing options need
to be trimmed off prior to reassembly. If the incoming packet data is
stored in some form of scatter/gather storage (e.g., mbufs) these are
fairly inexpensive operations, and more to the point, the cost is
comparable for the two approaches.

- In both my proposal and FRAG+LITE in the -07 draft. the individual
fragments need to be recombined into the complete user data field and
passed to the application layer. I see no difference at all between
the approaches in this phase of the processing. In a typical
implementation it involves copying the data from kernel scatter-gather
storage (e.g., mbufs) into a continguous user-supplied buffer.

If this does not sound right, please let me know what I've gotten wrong.

> Some further points embedded below...
[...]
> I thought we converged to "don't use FRAG without LITE until you
> confirm the other end speaks UDP options". What's the reason for
> needing FRAG without LITE?

We don't need, or want, FRAG without LITE. I regard it as a
disadvantage that FRAG without LITE can exist, if we don't need or
want it; we end up with a waste case that creates opportunities for
errors (i.e., erroneously sending it to legacy implementations).
This could be forgiven if it were necessary. I believe that my
proposal offers an existence proof that it is not.

> If OCS fails, why would an options-aware host do anything further
> with the packet?

Because the spec (as of -07) says that if OCS fails the options will
discarded and the packet will be processed as it would be if the were
no options present. In the case of FRAG without LITE that means that
the fragment data would be processed as if it were a complete datagram.

> At least one reason is that IPv6 UDP CS=0 is valid for tunnels and
> needs to be supported.

And I am not proposing to drop support for IPv6 UDP CS=0. I am,
however, insisting that it must not be a mandatory precondition
for UDP FRAG.

> Frag reassembly is not the same as TCP reconstitution. Our IDs do not

The IDs don't, but the fragment offsets do. The proper way to think of
this is that the Fragment ID singles out a stream. The Fragment Offset
within that stream is equivalent to the TCP sequence number.

Mike Heard