diff options
Diffstat (limited to 'content/en/blog/news/20200502-frcp.md')
-rw-r--r-- | content/en/blog/news/20200502-frcp.md | 236 |
1 files changed, 0 insertions, 236 deletions
diff --git a/content/en/blog/news/20200502-frcp.md b/content/en/blog/news/20200502-frcp.md deleted file mode 100644 index 28c5794..0000000 --- a/content/en/blog/news/20200502-frcp.md +++ /dev/null @@ -1,236 +0,0 @@ ---- -date: 2020-05-02 -title: "Flow and Retransmission Control Protocol (FRCP) implementation" -linkTitle: "Flow and Retransmission Control Protocol (FRCP)" -description: "A quick demo of FRCP" -author: Dimitri Staessens ---- - -With the longer weekend I had some fun implementing (parts of) the -[Flow and Retransmission Control Protocol (FRCP)](/docs/concepts/protocols/#flow-and-retransmission-control-protocol-frcp) -to the point that it's stable enough to bring you a very quick demo of it. - -FRCP is the Ouroboros alternative to TCP / QUIC / LLC. It assures -delivery of packets when the network itself isn't very reliable. - -The setup is simple: we run Ouroboros over the Ethernet loopback -adapter _lo_, -``` -systemctl restart ouroboros -irm i b t eth-dix l dix n dix dev lo -``` -to which we add some impairment -[_qdisc_](http://man7.org/linux/man-pages/man8/tc-netem.8.html): - -``` -$ sudo tc qdisc add dev lo root netem loss 8% duplicate 3% reorder 10% delay 1 -``` - -This causes the link to lose, duplicate and reorder packets. - -We can use the oping tool to uses different [QoS -specs](https://ouroboros.rocks/cgit/ouroboros/tree/include/ouroboros/qos.h) -and watch the behaviour. Quality-of-Service (QoS) specs are a -technology-agnostic way to request a network service (current -status - not finalized yet). I'll also capture tcpdump output. - -We start an oping server and tell Ouroboros for it to listen to the _name_ "oping": -``` -#bind the program oping to the name oping -irm b prog oping n oping -#register the name oping in the Ethernet layer that is attached to the loopback -irm n r oping l dix -#run the oping server -oping -l -``` - -We'll now send 20 pings. If you try this, it can be that the flow -allocation fails, due to the loss of a flow allocation packet (a bit -similar to TCP losing the first SYN). The oping client currently -doesn't retry flow allocation. The default payload for oping is 64 -bytes (of zeros); oping waits 2 seconds for all packets it has -sent. It doesn't detect duplicates. - -Let's first look at the _raw_ QoS cube. That's like best-effort -UDP/IP. In Ouroboros, however, it doesn't require a packet header at -all. - -First, the output of the client using a _raw_ QoS cube: -``` -$ oping -n oping -c 20 -i 200ms -q raw -Pinging oping with 64 bytes of data (20 packets): - -64 bytes from oping: seq=0 time=0.880 ms -64 bytes from oping: seq=1 time=0.742 ms -64 bytes from oping: seq=4 time=1.303 ms -64 bytes from oping: seq=6 time=0.739 ms -64 bytes from oping: seq=6 time=0.771 ms [out-of-order] -64 bytes from oping: seq=6 time=0.789 ms [out-of-order] -64 bytes from oping: seq=7 time=0.717 ms -64 bytes from oping: seq=8 time=0.759 ms -64 bytes from oping: seq=9 time=0.716 ms -64 bytes from oping: seq=10 time=0.729 ms -64 bytes from oping: seq=11 time=0.720 ms -64 bytes from oping: seq=12 time=0.718 ms -64 bytes from oping: seq=13 time=0.722 ms -64 bytes from oping: seq=14 time=0.700 ms -64 bytes from oping: seq=16 time=0.670 ms -64 bytes from oping: seq=17 time=0.712 ms -64 bytes from oping: seq=18 time=0.716 ms -64 bytes from oping: seq=19 time=0.674 ms -Server timed out. - ---- oping ping statistics --- -20 packets transmitted, 18 received, 2 out-of-order, 10% packet loss, time: 6004.273 ms -rtt min/avg/max/mdev = 0.670/0.765/1.303/0.142 ms -``` - -The _netem_ did a good job of jumbling up the traffic! There were a -couple out-of-order, duplicates, and quite some packets lost. - -Let's dig into an Ethernet frame captured from the "wire". The most -interesting thing its small total size: 82 bytes. - -``` -13:37:25.875092 00:00:00:00:00:00 (oui Ethernet) > 00:00:00:00:00:00 (oui Ethernet), ethertype Unknown (0xa000), length 82: - 0x0000: 0042 0040 0000 0001 0000 0011 e90c 0000 .B.@............ - 0x0010: 0000 0000 203f 350f 0000 0000 0000 0000 .....?5......... - 0x0020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ - 0x0030: 0000 0000 0000 0000 0000 0000 0000 0000 ................ - 0x0040: 0000 0000 -``` - -The first 12 bytes are the two MAC addresses (all zeros), then 2 bytes -for the "Ethertype" (the default for an Ouroboros layer is 0xa000, so -you can create more layers and seperate them by Ethertype[^1]. The -Ethernet Payload is thus 68 bytes. The Ouroboros _ipcpd-eth-dix_ adds -and extra header of 4 bytes with 2 extra "fields". The first field we -needed to take over from our [Data -Transfer](/docs/concepts/protocols/) protocol: the Endpoint Identifier -that identifies the flow. The _ipcpd-eth-dix_ has two endpoints, one -for the client and one for the server. 0x0042 (66) is the destination -EID of the server, 0x0043 (67) is the destination EID of the client. -The second field is the _length_ of the payload in octets, 0x0040 = -64. This is needed because Ethernet II has a minimum frame size of 64 -bytes and pads smaller frames (called _runt frames_)[^2]. The -remaining 64 bytes are the oping payload, giving us an 82 byte packet. - -That's it for the raw QoS. The next one is _voice_. A voice service -usually requires packets to be delivered with little delay and jitter -(i.e. ASAP). Out-of-order packets are rejected since they cause -artifacts in the audio output. The voice QoS will enable FRCP, because -it needs to track sequence numbers. - -``` -$ oping -n oping -c 20 -i 200ms -q voice -Pinging oping with 64 bytes of data (20 packets): - -64 bytes from oping: seq=0 time=0.860 ms -64 bytes from oping: seq=2 time=0.704 ms -64 bytes from oping: seq=3 time=0.721 ms -64 bytes from oping: seq=4 time=0.706 ms -64 bytes from oping: seq=5 time=0.721 ms -64 bytes from oping: seq=6 time=0.710 ms -64 bytes from oping: seq=7 time=0.721 ms -64 bytes from oping: seq=8 time=0.691 ms -64 bytes from oping: seq=10 time=0.691 ms -64 bytes from oping: seq=12 time=0.702 ms -64 bytes from oping: seq=13 time=0.730 ms -64 bytes from oping: seq=14 time=0.716 ms -64 bytes from oping: seq=15 time=0.725 ms -64 bytes from oping: seq=16 time=0.709 ms -64 bytes from oping: seq=17 time=0.703 ms -64 bytes from oping: seq=18 time=0.693 ms -64 bytes from oping: seq=19 time=0.666 ms -Server timed out. - ---- oping ping statistics --- -20 packets transmitted, 17 received, 0 out-of-order, 15% packet loss, time: 6004.243 ms -rtt min/avg/max/mdev = 0.666/0.716/0.860/0.040 ms -``` - -As you can see, packets are delivered in-order, and some packets are -missing. Nothing fancy. Let's look at a data packet: - -``` -14:06:05.607699 00:00:00:00:00:00 (oui Ethernet) > 00:00:00:00:00:00 (oui Ethernet), ethertype Unknown (0xa000), length 94: - 0x0000: 0045 004c 0100 0000 eb1e 73ad 0000 0000 .E.L......s..... - 0x0010: 0000 0000 0000 0012 a013 0000 0000 0000 ................ - 0x0020: 705c e53a 0000 0000 0000 0000 0000 0000 p\.:............ - 0x0030: 0000 0000 0000 0000 0000 0000 0000 0000 ................ - 0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................ - -``` - -The same 18-byte header is present. The flow endpoint ID is a -different one, and the length is also different. The packet is 94 -bytes, the payload length for the _ipcp-eth_dix_ is 0x004c = 76 -octets. So the FRCP header adds 12 bytes, the total overhead is 30 -bytes. Maybe a bit more detail on the FRCP header contents (more depth -is available the protocol documentation). The first 2 bytes are the -FLAGS (0x0100). There are only 7 flags, it's 16 bits for memory -alignment. This packet only has the DATA bit set. Then follows the -flow control window, which is 0 (not implemented yet). Then we have a -4 byte sequence number (eb1e 73ae = 3944641454)[^3] and a 4 byte ACK -number, which is 0. The remaining 64 bytes are the oping payload. - -Next, the data QoS: - -``` -$ oping -n oping -c 20 -i 200ms -q data -Pinging oping with 64 bytes of data (20 packets): - -64 bytes from oping: seq=0 time=0.932 ms -64 bytes from oping: seq=1 time=0.701 ms -64 bytes from oping: seq=2 time=200.949 ms -64 bytes from oping: seq=3 time=0.817 ms -64 bytes from oping: seq=4 time=0.753 ms -64 bytes from oping: seq=5 time=0.730 ms -64 bytes from oping: seq=6 time=0.726 ms -64 bytes from oping: seq=7 time=0.887 ms -64 bytes from oping: seq=8 time=0.878 ms -64 bytes from oping: seq=9 time=0.883 ms -64 bytes from oping: seq=10 time=0.865 ms -64 bytes from oping: seq=11 time=401.192 ms -64 bytes from oping: seq=12 time=201.047 ms -64 bytes from oping: seq=13 time=0.872 ms -64 bytes from oping: seq=14 time=0.966 ms -64 bytes from oping: seq=15 time=0.856 ms -64 bytes from oping: seq=16 time=0.849 ms -64 bytes from oping: seq=17 time=0.843 ms -64 bytes from oping: seq=18 time=0.797 ms -64 bytes from oping: seq=19 time=0.728 ms - ---- oping ping statistics --- -20 packets transmitted, 20 received, 0 out-of-order, 0% packet loss, time: 4004.491 ms -rtt min/avg/max/mdev = 0.701/40.864/401.192/104.723 ms -``` - -With the data spec, we have no packet loss, but some packets have been -retransmitted (hence the higher latency). The reason for the very high -latency is that the current implementation only ACKs on data packets, -this will be fixed soon. - -Looking at an Ethernet frame, it's again 94 bytes: - -``` -14:35:42.612066 00:00:00:00:00:00 (oui Ethernet) > 00:00:00:00:00:00 (oui Ethernet), ethertype Unknown (0xa000), length 94: - 0x0000: 0044 004c 0700 0000 81b8 0259 e2f3 eb59 .D.L.......Y...Y - 0x0010: 0000 0000 0000 0012 911a 0000 0000 0000 ................ - 0x0020: 86b3 273b 0000 0000 0000 0000 0000 0000 ..';............ - 0x0030: 0000 0000 0000 0000 0000 0000 0000 0000 ................ - 0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................ - -``` - -The main difference is that it has 2 flags set (DATA + ACK), and it -thus contains both a sequence number (81b8 0259) and an -acknowledgement (e2f3 eb59). - -That's about it for now. More to come soon. - -Dimitri - -[^1]: Don't you love standards? One of the key design objectives for Ouroboros is exactly to avoid such shenanigans. Modify/abuse a header and Ouroboros should reject it because it _cannot work_, not because some standard says one shouldn't do it. -[^2]: Lesser known fact: Gigabit Ethernet has a 512 byte minimum frame size; but _carrier extension_ handles this transparently. -[^3]: In _network byte order_.
\ No newline at end of file |