Spark -> Cloud Bandwidth Requirements

Thanks for the ping @kennethlimcp — and good question @ibebbs.

TL;DR:

  • TCP packet from cloud to core depends on length of variable name
    • 1–7 characters: TCP payload is 18 bytes
    • 8–12 characters: TCP payload is 34 bytes
  • TCP ACK
  • 18-byte TCP packet from core to cloud with variable value
  • TCP ACK

Add all the various framing overhead, and if packets get dropped then things get repeated at the TCP level.

All the Detail

There’s an ASCII chart in the CoAP spec that I often go to as a reminder of the format. The first four bytes (version, type, token length, code, message ID) are always present; the minimum message size in CoAP is 4 bytes.

Every message is encrypted with AES-128-CBC, which means that the ciphertext length will always be a multiple of 128 bits, which is 16 bytes.

Additionally, the first 2 bytes of every message is the length of the rest of the encrypted message.

  • A plaintext of 1–15 bytes will get encrypted to a single 16-byte block and prefixed with hex 0010 to say that the length of the ciphertext is 16. That’s 18 total bytes.
  • A plaintext of 16–31 bytes will get encrypted to two 16-byte blocks, a total of 32 bytes, and prefixed with 0020 to say the length of the ciphertext is 32. That’s 34 total bytes.

This ultimately means that most messages on the wire in the Spark protocol are 18 bytes. They get longer when long strings are involved, and they’re always a multiple of 16, plus 2: 18, 34, 50, 66…

These are the TCP payload lengths, so then there’s framing overhead and a TCP ACK each time in the happy case or some repeated messages if things get dropped.

Variable Request

You can see in received_message that a variable request from the cloud to the core is a confirmable GET request with the first path option set to v.

There is a single-byte token that is used to correlate the request with the response.

The name of a variable may be 1–12 characters long.

Here’s an example of the shortest possible variable request CoAP message in xxd format:

0000000: 4101 8877 66b1 7601 76                   A..wf.v.v

Here, 4101 means this is a confirmable GET request with a single-byte token. The message ID is hex 8877 and the token is hex 66. The next b176 makes this a variable request because the first Uri-Path option is v. The name of the variable is as short as possible, a single character: v; that’s the final Uri-Path option 0176.

Now here’s an example of the longest possible variable request message, where the name of the variable is 12 characters long.

0000000: 4101 beef cab1 760c 6177 6573 6f6d 6573  A.....v.awesomes
0000010: 6175 6365                                auce

Here 4101 is the same, indicating a confirmable GET request with a single-byte token. The message ID is beef, and the token is ca. The next two bytes are still the same Uri-Path option of v: b176.

The remaining 13 bytes are the second Uri-Path option, representing the variable name. The first byte 0c means the option value length is 12 bytes. The final 12 bytes are the variable name: awesomesauce.

If the name of the variable is 7 characters long, then the whole CoAP message is 15 bytes long, the maximum plaintext that fits in a single AES-128-CBC block. If the variable name is 8 characters or longer, we need a second encrypted block.

Variable Value Response

The current value of the variable is returned to the server in what the CoAP specification refers to as a “piggy-backed response”. There’s no separate CoAP ACK; the ACK contains the response.

Side note: We do this with variables because retrieving them is fast. However, when calling Spark.functions we send an empty CoAP ACK, followed by a separate response since we don’t know how long the user code may take to execute.

The variable_value function with the final parameter type double shows exactly what the response looks like.

  • 4-byte header
  • 1-byte token
  • 1-byte payload marker
  • 8-byte payload of double-precision floating point value

That totals 14 bytes which gets AES encrypted into a single 16-byte block, plus the 2-byte length prefix, giving an actual encrypted TCP payload of 18 bytes.

1 Like