Subject: [core] draft-ietf-core-block-03 review

From: Cullen Jennings <[email-masked]>
Date: Mon, 9 May 2011 12:27:43 -0700

What happens if the resource changes part way through a GET?  For devices that make a virtual snapshot of the resource, I'd like the it so that if the resources changes while the transfer is happing, the value the client receives is the value of resources when the server received the first get. There need to be some sort of minimum timeout so that the client knows the server will not discard the snapshot while the transfer is happening. For servers that don't do a snapshot, then I think an ETAG should be mandatory. Current draft seems to say the client MUST check it but it only has an SHOULD on the server sending it. 

More complicated is the PUT / POST. On these, I think they should be required to be atomic. Designing systems with clients that can deal with non atomic requests is very hard. I understand this has consequences on servers but not saying that has consequences on clients and overall system stability. A node may be willing to have some resource in an inconsistent state, but another node that does a GET of that resource may not be able to deal with the inconsistent state.  Again with PUT/ POST, need some sort of overall timeout where the server can discard the state  if the client dies. 

I think the client should explicitly signal support for blocks to the sever before the server starts using this extension. 

I think we need a provisional response code that indicates the far end is simply buffering. Using 2.04 until the block m=0 seems like lots of things could go wrong in a bad way. 

Can you use non confirmed requests when doing block? The way 4.08 works, this is going to be pretty dicey. I'm a bit confused around if the 4.08 is a missing fragment error or a timeout error. Needs some clarification and perhaps two codes. 

Imagine a large download such as an XML or JSON config for a device or the firmware example. Should there be any advice on trickling or slowing down large transfers? If 20 devices on a small 802.15.4 mesh network with only one link the rest of the internet started doing a firmware download at the same time, I suspect that it badly impact the other traffic on this network. 

On the size of the blocks ... given MTU are raising and make a huge difference to high performance networks, I'd prefer to see support for 8K or 16K block size as well as the smaller ones. I'm also  sympathetic to the power of 2 are not optimal given we can pick any number we want. It might be a good idea to pick some sizes that seemed optimal for MTU we would get on 802.15.4 network, some of the cellular data networks, an 1280 MTU network, and something in the Jumbo gram space. I also get the point this looks like over optimization, I'm on the fence :-) 

Need an example where we have block transfer in request and responses. Like it if it showed ETags and Tokens too. 

In mention you use C pseudo code, I'd just remove that part as it can bring up old arguments from other WG and your mathematical formulas are perfectly clear without mentioning C. 

You say the block options are optional to implement but that's not the right way to think about it. The draft is an extensions to CoAP and it's optional if you decide to implement the RFC this becomes or not, but if you implement this RFC, then you MUST implement these so they are not optional in the context of this draft. 

The three bullet points paragraphs at the end of section 2.1 are very hard to understand. 

When you say that future requests have to have the same block size as the earlier one, who is responsible for enforcing this. Does the server need to remember and reject or is it the responsibility of the client to do the right thing.

I don't like the "m" nomenclature - I know where it comes from but it seems meaningless. I'd prefer a LastBlock field or something like that.

In the HTTP mapping section, I'd delete the stuff about problems of implementing HTTP (and the HTTP to CoAP mapping) on a constrained node. I don't think our goal is to make HTTP work on the constrained node. 

In section 5.1, the advice to not create state seems sort of useless.  I'd rather see the draft get clear about where implementations SHOULD create state and where they don't need to and more importantly, how to clean up and timeout any state that does get created. 

Cullen (in my individual contributor role)

---

From: Carsten Bormann <[email-masked]>
Date: Mon, 9 May 2011 22:07:21 +0200

> What happens if the resource changes part way through a GET?  For devices that make a virtual snapshot of the resource, I'd like the it so that if the resources changes while the transfer is happin…

The philosophy behind CoAP is to leave many decisions up to the server.
E.g., whether a frozen copy is made when a block-wise transfer starts or the server simply operates in a stateless fashion.
Yes, you can implement a server that makes it really hard to get a resource representation.
We can try to create a jungle of MUSTs and SHOULDs here, which in the end will do the wrong things for some specific situation.
Leave that up to the server, I'd say.

> More complicated is the PUT / POST. On these, I think they should be required to be atomic. Designing systems with clients that can deal with non atomic requests is very hard. I understand this has…

That depends, again.
A server that provides a REST protocol that creates a specific instance for each client to PUT into does not need to do any of this.
I have no idea how to come up with a reasonable value for such a timeout.
Different applications will need quite different values.
Leave all that up to the server, I'd say.

> I think the client should explicitly signal support for blocks to the sever before the server starts using this extension. 

(See last message.)

> I think we need a provisional response code that indicates the far end is simply buffering. Using 2.04 until the block m=0 seems like lots of things could go wrong in a bad way. 

The echoed m bit in the Block1 option is that provisional code.
(Yes, that could be re-enforced with a different response code as well, but that we'd lose the distinction between 2.01 and 2.04.)

> Can you use non confirmed requests when doing block? The way 4.08 works, this is going to be pretty dicey. I'm a bit confused around if the 4.08 is a missing fragment error or a timeout error. Need…

We need a ton more examples.

4.08 is a missing fragment error.  A timeout simply isn't signalled (where would you signal it) and then leads to a missing fragment error.  So, in the end, 4.08 also is a timeout error.

> Imagine a large download such as an XML or JSON config for a device or the firmware example. Should there be any advice on trickling or slowing down large transfers? If 20 devices on a small 802.15…

That's handled by the lock-step congestion control.

> On the size of the blocks ... given MTU are raising and make a huge difference to high performance networks, I'd prefer to see support for 8K or 16K block size as well as the smaller ones. I'm also…

We just killed 2048, and I think that was the right decision (high-performance networks are out of scope).
I tried to define a size that would be optimal, but there are so many variables in header compression efficiency, security overhead etc., that this doesn't work too well (well, actually 64 is pretty good in most cases -- anything beyond that is premature optimization).

> Need an example where we have block transfer in request and responses. Like it if it showed ETags and Tokens too. 

Yes, we need a ton more examples!
This one was already requested by Guido, and we definitely need to put it in.

> In mention you use C pseudo code, I'd just remove that part as it can bring up old arguments from other WG and your mathematical formulas are perfectly clear without mentioning C. 

Without that sentence, the formulae are not well-defined.
(Let's fight that windmill when we encounter it :-)

> You say the block options are optional to implement but that's not the right way to think about it. The draft is an extensions to CoAP and it's optional if you decide to implement the RFC this beco…

I hate the word optional, because it never means anything useful.
But, now, a node might implement Block2 and not Block1, so some text to this effect is actually required.

> The three bullet points paragraphs at the end of section 2.1 are very hard to understand. 

Yes, they need a serious editorial round.

> When you say that future requests have to have the same block size as the earlier one, who is responsible for enforcing this. Does the server need to remember and reject or is it the responsibility…

This is a mandate to make some potential server implementations simpler, not to complicate them.
Note that there are no error codes defined...
(I would be prepared to completely delete that mandate, by the way.)

> I don't like the "m" nomenclature - I know where it comes from but it seems meaningless. I'd prefer a LastBlock field or something like that.

Well, it would be NotLastBlock (otherwise we would change the wire protocol).
Is that better than "m"?

> In the HTTP mapping section, I'd delete the stuff about problems of implementing HTTP (and the HTTP to CoAP mapping) on a constrained node. I don't think our goal is to make HTTP work on the constr…

Well, the whole section is implementation advice, and it is not about implementing HTTP, but about what a mapper might need to do to do Block.
But, apart from this advice, it helps in understanding why the protocol is defined as it is.
Deleting the text would go some way towards the typical trapdoor standard (i.e., we'll tell you how it works if you already understand that).

> In section 5.1, the advice to not create state seems sort of useless.  I'd rather see the draft get clear about where implementations SHOULD create state and where they don't need to and more impor…

If you want to counter resource exhaustion, not creating state is the best defense there is -- yes, that's trivial, but it is still good advice.
Apart from that, leave that up to the server, I'd say.

Gruesse, Carsten

---

From: Carsten Bormann <[email-masked]>
Date: Mon, 9 May 2011 21:40:15 +0200

> I think the client should explicitly signal support for blocks to the sever before the server starts using this extension. 

We had that discussion a couple of times. I find it interesting that this specific case runs counter to the intuition of most experienced protocol designers (it sure did when I thought this through the first time).

What would a server do if there is no such signal and it needs to split?
Send an error.
As defined now, it sends a critical option not implemented by the client, which is an error.
(Yes, there is also a payload sent that would be saved by having a special kind of error.  Trying to get rid of that payload is a typical case of premature optimization.)

So what's the point?
Since most clients will implement Block, most clients will always send this signal, for zero gain.
Really bad design.

Gruesse, Carsten

---

From: Cullen Jennings <[email-masked]>
Date: Mon, 9 May 2011 18:24:40 -0700

lets think about the case with IP level fragmentation a bit. Let's say the client has a MTU of 1280 and the server has a MTU of  128. The client requests a resources which is 300 bytes long. I doubt the server sends an error - I suspect it tries to send the the result as a single response that gets fragmented at the IP layer. Having the GET come along with with an indication that the client supports block and would prefer less than 1250 or so then having the server send the result in three responses that are have an size under the 128 MTU seems like an OK design. A design like with would also avoid the latency of a full round trip when the client supports block and the server does not. 

I also question the assumption that most  servers would implement block - it's true that the current design more or less forces them to implement it or the clients get a constant flow of errors. I suspect that the reason a server would not want to implement block would have to do with the buffering that the implementation will probably require. 

> Since most clients will implement Block, most clients will always send this signal, for zero gain.

Cullen Jennings
For corporate legal information go to:
http://www.cisco.com/web/about/doing_business/legal/cri/index.html

---

From: Cullen Jennings <[email-masked]>
Date: Mon, 9 May 2011 18:24:46 -0700

> Leave that up to the server, I'd say.

well, the same problem applies of how does the client know if it got a atomic representation of the state or some broken intermediate representation. I don't think you can leave this up to the server and still build systems that function in the way you want the system to function. 

> A server that provides a REST protocol that creates a specific instance for each client to PUT into does not need to do any of this.

Could you expand a bit more on how this solves the problem, I'm not getting it. 

> I have no idea how to come up with a reasonable value for such a timeout.

The problem here is that unless that client and server have a coordinated view of the timeouts, the system is not going to interoperate. If the client thinks it should wait 30 seconds to time out a single request that did not get a responses, and the server thinks it should through away the state of any block buffer after 25 seconds, we have a problem. (I also am not a fan of situation where the implementor of a protocol, with even less information than the designers of the protocol, has to figure out how to do something the designers could not figure out.)

> (Yes, that could be re-enforced with a different response code as well, but that we'd lose the distinction between 2.01 and 2.04.)

hmm - I missed that in my read of the draft. It's an interesting point, so you are saying the first block could have a 2.01 with a location returned yet the last block may still result in an error. Probably need to specify what happens to the location returned validity in that case.  Seems like one more good reason to have PUT be atomic. 

> 4.08 is a missing fragment error.  A timeout simply isn't signalled (where would you signal it) and then leads to a missing fragment error.  So, in the end, 4.08 also is a timeout error.

When using proxies, you often need to signal timeouts so if it is useful for the client to understand if the error was a timeout or a missing fragment, it would probably be best to have an explicit error code for it.

---

From: Likepeng <[email-masked]>
Date: Tue, 10 May 2011 02:01:44 +0000

> The problem here is that unless that client and server have a coordinated view of the timeouts, the system is not going to interoperate. If the client thinks it should wait 30 seconds to time out a single request that did not get a responses, and the server thinks it should through away the state of any block buffer after 25 seconds, we have a problem. 

+1. The client does not know how long it should wait for the response, and has to keep the state for the request. It can choose to give up the request after its own defined timeout, then the received response after the timeout will be useless. 

Kind Regards
Kepeng
-----Original Message-----
From: [email-masked] [mailto:[email-masked]] On Behalf Of Cullen Jennings
Sent: Tuesday, May 10, 2011 9:25 AM
To: Carsten Bormann
Cc: core WG
Subject: Re: [core] draft-ietf-core-block-03 review

> Apart from that, leave that up to the server, I'd say.

_______________________________________________
core mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/core

---

From: "Angelo P. Castellani" <[email-masked]>
Date: Tue, 10 May 2011 09:36:29 +0200

> The problem here is that unless that client and server have a coordinated view of the timeouts, the system is not going to interoperate. If the client thinks it should wait 30 seconds to time out a…

+1

---

From: Carsten Bormann <[email-masked]>
Date: Tue, 10 May 2011 14:24:13 +0200

On May 10, 2011, at 03:24, Cullen Jennings wrote:

> The problem here is that unless that client and server have a coordinated view of the timeouts, the system is not going to interoperate. If the client thinks it should wait 30 seconds to time out a single request that did not get a responses,

Wait a minute -- *why* did that request not get a response?

If I'm a client in a block-wise transfer and I never get a response for my request for block 37, this block-wise transfer is hosed.
(Note that we have a message layer below that that makes sure this is not just happening because of a random packet loss.)

This is like a TCP connection going away mid-transfer.

Of course, in CoAP, I can simply request block 37 again whenever I want, but then I get whatever the server has at that later point in time -- if the ETags match, I can recover the transfer, otherwise I can't.

> and the server thinks it should through away the state of any block buffer after 25 seconds, we have a problem. 

General comment:
Much of this becomes clearer when you think about HTTP and how an HTTP client does *not* set the parameters for the server-side TCP implementation.  Somehow, HTTP still works pretty well.

Gruesse, Carsten

---

From: Carsten Bormann <[email-masked]>
Date: Tue, 10 May 2011 14:45:30 +0200

> Could you expand a bit more on how this solves the problem, I'm not getting it. 

If there is no way for two clients to interfere because they are using different resources, there is no need to provide atomicity.

Example 1: You put into a resource the name of which is derived from a hash of the resource representation.
Example 2: You ask the server for a resource name before starting to put into it.
Example 3: Only one client is authorized to access the resource and that client knows what it is doing.

These are just examples.  All I'm trying to say is that making requirements on the protocol that are not needed by the application is not helpful.  (All this kind of feels like locking the whole table before executing an SQL statement...  There are many strategies, and the protocol should not limit the choice.)

Gruesse, Carsten

---

From: "Kovatsch Matthias" <[email-masked]>
Date: Wed, 11 May 2011 19:30:56 +0000

Would it be possible to provide meaningful names for the Block options? 1 and 2 in the order 2 (=17), 1 (=19) might cause a lot of confusion...
Block2 corresponds to server-side generated blocks and Block1 to client-side generated blocks, right?

So, what about Block-Server and Block-Client or suchlike instead?

Regards
Matthias

---

From: Zach Shelby <[email-masked]>
Date: Wed, 11 May 2011 22:38:12 +0300

> So, what about Block-Server and Block-Client or suchlike instead?

Good idea! 

Zach

-- 
Zach Shelby, Chief Nerd, Sensinode Ltd.
http://zachshelby.org  - My blog "On the Internet of Things"
http://6lowpan.net - My book "6LoWPAN: The Wireless Embedded Internet"
Mobile: +358 40 7796297

---

From: Carsten Bormann <[email-masked]>
Date: Wed, 11 May 2011 21:44:45 +0200

> So, what about Block-Server and Block-Client or suchlike instead?

As long as people don't start to think Block-Server options are always sent from the server and Block-Client options are sent from a client...

We went through a couple of these (Block-Request, Block-Response...) and decided Block1 and Block2 actually had the smallest confusion factor.  But I'm open to any suggestion.  If people like B-S and B-C, I'm all for it.  (Spec reception, again, is a funny thing.)  But let's brainstorm for good names for a little more.

Now, why did we propose to number Block1 19 and Block2 17?  Because Block2 is more likely, and 17 might mean fewer fenceposts than 19 (this is more of an issue for responses, since requests usually at least have an Uri-Path).  But this is rather theoretical...

Gruesse, Carsten

---

From: "Kovatsch Matthias" <[email-masked]>
Date: Wed, 11 May 2011 20:15:06 +0000

> As long as people don't start to think Block-Server options are always sent
> from the server and Block-Client options are sent from a client...

Also a good point.
How about the classic Block-Down(stream/load/{}) and Block-Up(stream/load/{})?

> Now, why did we propose to number Block1 19 and Block2 17?  Because
> Block2 is more likely, and 17 might mean fewer fenceposts than 19 (this is
> more of an issue for responses, since requests usually at least have an Uri-
> Path).  But this is rather theoretical...

Yes, I saw it that way. I wondered why the more likely one got second, though ;)

Bye
Matthias