PicoTCP
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Vincent, Maxime
PicoTCP is a fully featured TCP/IP stack designed for embedded devices and released under the terms of GNU GPL. Our purpose is to propose it as the reference TCP/IP stack for IoT, especially due to its high portability and modularity. This talk will explain the architecture of the stack, the way we have been developing it and the many features we support. Moreover, we will briefly show how easy it is to port the stack to a complete new architecture in no time. After the presentation, as a test scenario, we would like to show a demo illustrating how it is possible to transport MIDI flows over WiFi with a PIC24 based board using ZMTP protocol.
 Okay, hello everyone. I'm Maxime Versailles and I'm presenting to you the Pico TCP stack which we want to present here as the reference TCP IP stack for the Internet of Things. I'm going to try to fix that first. That should be better. Alright, we're good to go. So first let me do some shameless publicity for the company I'm working for. It's called TAS. We are a leading embedded technology company. We're located in Lüven and Hient and what we're doing is we're providing consultancy training. We're doing projects together with our customers and doing outsourced services. What we want to do is ensure that our clients in co-creation with us can launch innovative and better quality products in a shorter time to market. But another important point is that we believe that connected devices are going to improve the quality of our lives in an innovative way. So that is why we have made this. Pico TCP, it's a fully featured and highly portable TCP IP stack. It's designed really for small footprints embedded systems. So we're targeting the lower end microcontrollers here up until bigger targets. So why should we be the reference TCP IP stack for the Internet of Things? That is because we have four areas which we focused on during the development of Pico TCP and that is modularity, portability, performance and quality. I'm going to tell you about all these four focus areas a little more in detail. First important for this conference I think is that we are, our software is free as in free speech. So we have a dual licensing policy in place. Firstly, really release the Pico TCP stack under the GNU GPL version 2. But then for the customers who are not really very happy with this kind of licensing, we also have a proprietary licensing possible because we are a full copyright owner of Pico TCP. Yes. It is V2 only. The question was is that V2 only or V2 and later? No, we're sticking to GPL V2. So what does this stack look like? This is the first point modularity. We've built up the stack from the beginning as a very modular stack because that's important for small and better targets. There is one big bubble in the middle which is the gray Pico TCP core. That one of course is mandatory but all the other modules around it are optional and you can choose whether you want to compile them in or not. Of course there's some dependencies between them but that's logical I think. Then just to give you an idea of how big this stack is in terms of flash memory, we try to compile the complete stack with for an ARM target which is the embed board in this case. We compiled all the options in and then we get somewhere around 68 kilobytes for all the modules you can see here. We think that's pretty small. Then let's see how we can build this up in a modular way. So we removed everything except TCP, UDP and then we want to use only IPv4 because we're also implementing IPv6 and both can be used at the same time. When we built this full host mode config we are somewhere around 30 kilobytes of flash. So how does it work? You select the bubbles, the modules and you can do this just with a simple make command to see all the available modules just have a look inside our make file. I made the command I used here for the 30 kilobytes version of the stack which I have just showed you. I have explicitly mentioned all the modules. If you don't mention any of them you will just get all the modules. Then for the small lip size I've also stripped the module here to see what it will finally take in your flash but you shouldn't do that if you still want to link the library. Next point is portability. We thought of portability since the beginning so we are really CPU architecture independent. We run on 8-bit cores on 16, on 32-bit, 64-bit, little or big endian. We have also thought of the smaller systems which have no operating system at all so bare metal, small operating systems or schedulers, things like free RTOS, real operating systems or more complete operating systems up until real-time operating systems. Right now at this moment we have about 10 or more different platforms which we already support and we believe that it's very easy to port Pico TCP to a new board and I will show you this in a minute how it's done. New operating systems should also be easy to support because we wrote our own operating system abstraction layer so you should just implement this layer and all the rest stays the same. To show you a few of the architectures we support, 64-bit is not mentioned because we only tested this on POSIX clients so basically on a Linux machine because we don't have any 64-bit embedded targets at our place but then in 32-bit there's really a lot of ARM variants and I think almost every month there's a new one being introduced, it's really easy to port. So we have a few LPC chips, Cortex M0, M3, M4, a lot of STM32 variants also. On the 16-bit side we have the MSP, low power microcontroller from TI. Also the PIC24F which I will demo here later on. This is a target with really small resources, it has only 16 kilobytes of RAM and we're running a complete stack inside of that and then we even have one 8-bit target so that's 80Mega 128 which is doing painless TCP IP communication. More portability even so the communication chips, we support this set of communication channels, we have Wi-Fi chips running, we have Ethernet, we have USB CDC drivers and then a bunch of virtual drivers which we use a lot during development or testing on Linux for example. So we have Tuntup drivers, VDE and LibPcap which Wireshark is also using. Then the different operating system which we can run on. At this moment we use a lot of bare metal targets so there's no operating system running so all the calls are non-blocking. Then FreeRTOS is an operating system which is popping up a lot on the small devices. Of course we have the Embed RTOS which is CMSys RTOS compliant so other CMSys variants should work painlessly as well and then we do a lot of testing on Linux and other posix targets as well. So what does our OS abstraction layer do exactly? We have abstraction from the mutex and the signals which are used for synchronization between the threads. Then the threads themselves or the processes are abstracted and we have a BSD blocking socket interface. Now let's talk about the performance. These tests have been run on the Embed LPC 1768 I think. That's a target running at 100 megahertz. We get a throughput for transmission of about 10 megabits and downstream about 20 megabits which is not bad for an embedded target I think. Then the CPU time here is stated in amount of microseconds per loop because our stack has a stack tick and you can really choose yourself how many stack ticks or the period of one tick. So in idle state we have only 45 microseconds and then at the maximum throughput which was here the 10 megabits or 20 megabits we have something like 800 microseconds per tick. Then the RAM is something we're proud of also the dynamic memory. During these tests was maximum 8 kilobytes of memory and on average around 4 kilobytes. The static memory here is the biggest one. That's 16 kilobytes and that's actually just because we're allocating a lot of buffers statically allocating a lot of buffer for the driver so that we can buffer more incoming packets at once. You could also reduce that but then your throughput goes down a little bit so it's a trade-off you should make but you can get these figures even lower. In the stack 2 kilobytes and on this peak target we're even below 1 kilobytes of stack. Quality is something we're constantly focusing on so the way we develop the stack is in an agile way using scrum and we do test driven development so we make the test beforehand and then we implement the code which should make these test green. We're also having continuous integration and automated testing so whenever something breaks we get a big red screen and everyone should jump on the problem to get this up and running as quickly as possible. At the right you can see a kind of eco label but then for code quality. This is a tool we're using it's called T-O-B-T-X and it gives you an idea if you're writing decent code or not. The first time we run this tool I think we were somewhere around an E and so this gives you a constant reminder of write good code, document it, don't make it too complex, write unit tests and things like that so we're planning on getting even higher hopefully. So at the bottom you see a big list of RFC standards that's not intended to be readable but just to show you how many standards we comply to and we tend to take these standards pretty literal so we don't make any loose implementations of these like some other stags do. We are also community driven so we're on GitHub, please visit us there, you're free to file any bug you can find. As I said before we are GPL v2 licensed so use our stag 4kid, do whatever you want with it as long as you stick to the GPL. We're also on OLO which does analysis of open source projects and they're saying about PQTCP that we have a young but established code base. We started first time on GitHub, first commit was around October 2012 and we have a large development team, we have stable year over year commits so we're constantly working on this thing and we're trying to make it better every day. So now more concrete or more interesting is how to port this actually to a new platform. That's easy, you need just three things, that's memory management which often isn't a big problem so you just grab the malloc and the free functions from your C library. You need a few timing functions, just two actually and then a driver for your hardware to get the packets really on your physical interface. So how do we do this? Memory management also is already said that you can use the malloc and the free functions from your C library if they are decent enough, if they are available. If you're using an operating system then you could use the memory allocation from the operating system and we're also right now implementing our own memory manager because we believe that we can allocate and free memory more efficient than most C libraries do. Also coping with fragmentation when transmitting small packets and things like that. So that's a new development that's on its way. I think it almost made its way into the stable, there is an active pull request, great. So next thing you need is timing functions. The way we set this up is a timer interrupt which will every millisecond increment in 64 bit integer so that we get a big enough time base and then you need two functions, picotime and mess and picotime which will return the elapsed time in milliseconds or in seconds. So how do we do this? This is an example from the embed implementation I think again. So the picozaloc is actually the wrapper around the malloc function which we'll use. So here you can see that it simply uses the malloc from the C library and a requirement for picotcp is that you really zero all the memory explicitly so if your C library doesn't do it or you could have a calloc available for example. Next thing is the picotime and mess. We're doing a trick here with 32 bit integer which is being incremented because it's a little bit faster and then we're detecting when it overflows and picotime is just returning the same value divided by 1000. The last statement here is optional. You could use that as a blocking function which just wait until another millisecond has elapsed but it's not mandatory. Now we get down to the device driver. This API we tend to make it very generic and very simple also so there's only a few things needed. That's the picodef create which will return a struct to a picodevice and then you have its opposite at the bottom which is picodef destroy which will do all the cleanup and then you have a send function and a pull function so you want to transmit a packet or you want to see if there's new data available or not on your physical interface. So the header is really simple. There's only two functions exposed which are the embed create and the embed destroy in this case. All the rest is underneath which you can see here so this is the create function which will allocate some memory at the top for the device driver then we will set the MAC address because this is an Ethernet device. We will init the device and then set a few function pointers which will do the actual work. These are callbacks which are put into a struct. Actually what we've done here and what is a way that's easy to get started on new platforms is you make wrappers around the existing driver or implementation. In the embed system we had Ethernet read available so this is actually just a wrapper around this function and then you can get started with a one page function or even a half page function and the Pico TCP driver is working. The send function is just the same story we're using the Ethernet write and Ethernet send API from the embed. So let's get down to a demo. What we've done here is we've taken a small MIDI keyboard. Actually it's meant as a toy for the Wii I think but it wasn't a great success so you can find them really cheap on eBay. The great thing is they have a MIDI port which we will use. This MIDI port, the MIDI protocol is really simple so you just need a level translator and then with a UART you can read out the bytes which are on the MIDI channel. What we're doing is, you can see this here, we take the keyboard, we translate this to a serial stream, the microchip pick controller will read this out, use Pico TCP to put this on a Wi-Fi channel. Over the Wi-Fi we are actually transmitting a TCP stream with on top zero MQ which is a great message queueing protocol which makes it really easy to send and publish messages actually. So the keyboard here is a publisher and my laptop will subscribe to this publisher and get every message that it makes available. So these messages will be the MIDI notes which are played on the keyboard. Then I can receive them with a tiny Python script on my laptop and then I put these bytes again into a virtual MIDI device and this virtual MIDI device can then be hooked up to any synthesizer on my laptop. So I can show you the Python script which will read these binary packages. So that's about it. I think there's a few more lines at the bottom. Most of them are print functions just to see what's going on. So this is just to show how easy it is to do TCP IP communication by using zero MQ. Yeah, I will just power up the device meanwhile and let it connect to the Wi-Fi network and I don't know if there is anybody here who can actually play the piano because I can't so that we can do this demo. Is there anyone who wants to play a few notes? Yeah, come along. Yeah, except that the board is USB powered indeed. So the board is connected. I will now connect the Python script and you can see that it's immediately receiving MIDI messages and now I have this virtual MIDI device and I should connect it to a synthesizer and now you should be able to play the piano. Maybe. Thank you. Yes. Let's see. I'll make the connection again. Okay, go ahead. Great song. Thanks. So I don't know if there's any time left for two minutes, two questions. Yes. So this is a great project. I'm very impressed and I'd like to use it but my project's GPLv3 so I can't. Why have you done that? Why do you think that's a good idea? That's a good question. We think the V3 is a little bit too restrictive for the purpose. Yeah, it's true. I don't know. Maybe I can call the help of an expert on this matter. I would reply with another question actually. So what was the need exactly of the GPL3 if we already had the two which was working pretty well? I think we can take this offline. Okay, so we're going to cut this discussion about GPL licensing. I think if you simply say GPL2 or later and then I think the problem is solved but we can discuss this later. Thank you very much for the demo. If anybody wants to carry on playing the piano, we have an open slots after the next speech but we're going to stick to our timing here. Thank you very much for this amazing piece of work. Awesome. We have a five minute break and then we have our last formal talk for today.
 Okay, hello everyone. I'm Maxime Versailles and I'm presenting to you the Pico TCP stack  which we want to present here as the reference TCP IP stack for the Internet of Things. I'm  going to try to fix that first. That should be better. Alright, we're good to go. So first  let me do some shameless publicity for the company I'm working for. It's called TAS. We  are a leading embedded technology company. We're located in Lüven and Hient and what we're doing  is we're providing consultancy training. We're doing projects together with our customers and  doing outsourced services. What we want to do is ensure that our clients in co-creation with us  can launch innovative and better quality products in a shorter time to market. But another important  point is that we believe that connected devices are going to improve the quality of our lives in  an innovative way. So that is why we have made this. Pico TCP, it's a fully featured and highly  portable TCP IP stack. It's designed really for small footprints embedded systems. So we're targeting  the lower end microcontrollers here up until bigger targets. So why should we be the reference  TCP IP stack for the Internet of Things? That is because we have four areas which we focused on  during the development of Pico TCP and that is modularity, portability, performance and quality.  I'm going to tell you about all these four focus areas a little more in detail. First important  for this conference I think is that we are, our software is free as in free speech. So we have  a dual licensing policy in place. Firstly, really release the Pico TCP stack under the GNU GPL version  2. But then for the customers who are not really very happy with this kind of licensing, we also  have a proprietary licensing possible because we are a full copyright owner of Pico TCP. Yes.  It is V2 only. The question was is that V2 only or V2 and later? No, we're sticking to GPL V2.  So what does this stack look like? This is the first point modularity. We've built up the stack  from the beginning as a very modular stack because that's important for small and better targets.  There is one big bubble in the middle which is the gray Pico TCP core. That one of course is  mandatory but all the other modules around it are optional and you can choose whether you want to  compile them in or not. Of course there's some dependencies between them but that's logical  I think. Then just to give you an idea of how big this stack is in terms of flash memory, we try  to compile the complete stack with for an ARM target which is the embed board in this case.  We compiled all the options in and then we get somewhere around 68 kilobytes for all the modules  you can see here. We think that's pretty small. Then let's see how we can build this up in a  modular way. So we removed everything except TCP, UDP and then we want to use only IPv4 because  we're also implementing IPv6 and both can be used at the same time. When we built this full  host mode config we are somewhere around 30 kilobytes of flash. So how does it work? You  select the bubbles, the modules and you can do this just with a simple make command to see all  the available modules just have a look inside our make file. I made the command I used here for  the 30 kilobytes version of the stack which I have just showed you. I have explicitly mentioned  all the modules. If you don't mention any of them you will just get all the modules. Then for the  small lip size I've also stripped the module here to see what it will finally take in your flash  but you shouldn't do that if you still want to link the library. Next point is portability. We  thought of portability since the beginning so we are really CPU architecture independent. We run  on 8-bit cores on 16, on 32-bit, 64-bit, little or big endian. We have also thought of the smaller  systems which have no operating system at all so bare metal, small operating systems or schedulers,  things like free RTOS, real operating systems or more complete operating systems up until real-time  operating systems. Right now at this moment we have about 10 or more different platforms which  we already support and we believe that it's very easy to port Pico TCP to a new board and I will  show you this in a minute how it's done. New operating systems should also be easy to support  because we wrote our own operating system abstraction layer so you should just implement this  layer and all the rest stays the same. To show you a few of the architectures we support,  64-bit is not mentioned because we only tested this on POSIX clients so basically on a Linux  machine because we don't have any 64-bit embedded targets at our place but then in 32-bit there's  really a lot of ARM variants and I think almost every month there's a new one being introduced,  it's really easy to port. So we have a few LPC chips, Cortex M0, M3, M4, a lot of STM32 variants  also. On the 16-bit side we have the MSP, low power microcontroller from TI. Also the PIC24F  which I will demo here later on. This is a target with really small resources, it has only 16  kilobytes of RAM and we're running a complete stack inside of that and then we even have  one 8-bit target so that's 80Mega 128 which is doing painless TCP IP communication. More  portability even so the communication chips, we support this set of communication channels,  we have Wi-Fi chips running, we have Ethernet, we have USB CDC drivers and then a bunch of  virtual drivers which we use a lot during development or testing on Linux for example. So we have  Tuntup drivers, VDE and LibPcap which Wireshark is also using. Then the different operating  system which we can run on. At this moment we use a lot of bare metal targets so there's  no operating system running so all the calls are non-blocking. Then FreeRTOS is an operating  system which is popping up a lot on the small devices. Of course we have the Embed RTOS  which is CMSys RTOS compliant so other CMSys variants should work painlessly as well and  then we do a lot of testing on Linux and other posix targets as well. So what does our OS  abstraction layer do exactly? We have abstraction from the mutex and the signals which are used  for synchronization between the threads. Then the threads themselves or the processes are  abstracted and we have a BSD blocking socket interface. Now let's talk about the performance.  These tests have been run on the Embed LPC 1768 I think. That's a target running at 100  megahertz. We get a throughput for transmission of about 10 megabits and downstream about 20  megabits which is not bad for an embedded target I think. Then the CPU time here is  stated in amount of microseconds per loop because our stack has a stack tick and you  can really choose yourself how many stack ticks or the period of one tick. So in idle  state we have only 45 microseconds and then at the maximum throughput which was here the  10 megabits or 20 megabits we have something like 800 microseconds per tick. Then the RAM  is something we're proud of also the dynamic memory. During these tests was maximum 8 kilobytes  of memory and on average around 4 kilobytes. The static memory here is the biggest one.  That's 16 kilobytes and that's actually just because we're allocating a lot of buffers  statically allocating a lot of buffer for the driver so that we can buffer more incoming  packets at once. You could also reduce that but then your throughput goes down a little  bit so it's a trade-off you should make but you can get these figures even lower. In the  stack 2 kilobytes and on this peak target we're even below 1 kilobytes of stack. Quality  is something we're constantly focusing on so the way we develop the stack is in an agile  way using scrum and we do test driven development so we make the test beforehand and then we  implement the code which should make these test green. We're also having continuous integration  and automated testing so whenever something breaks we get a big red screen and everyone  should jump on the problem to get this up and running as quickly as possible. At the  right you can see a kind of eco label but then for code quality. This is a tool we're  using it's called T-O-B-T-X and it gives you an idea if you're writing decent code or not.  The first time we run this tool I think we were somewhere around an E and so this gives  you a constant reminder of write good code, document it, don't make it too complex, write  unit tests and things like that so we're planning on getting even higher hopefully.  So at the bottom you see a big list of RFC standards that's not intended to be readable  but just to show you how many standards we comply to and we tend to take these standards  pretty literal so we don't make any loose implementations of these like some other stags do.  We are also community driven so we're on GitHub, please visit us there, you're free  to file any bug you can find. As I said before we are GPL v2 licensed so use our stag 4kid,  do whatever you want with it as long as you stick to the GPL. We're also on OLO which  does analysis of open source projects and they're saying about PQTCP that we have a  young but established code base. We started first time on GitHub, first commit was around  October 2012 and we have a large development team, we have stable year over year commits  so we're constantly working on this thing and we're trying to make it better every day.  So now more concrete or more interesting is how to port this actually to a new platform.  That's easy, you need just three things, that's memory management which often isn't a big  problem so you just grab the malloc and the free functions from your C library. You need  a few timing functions, just two actually and then a driver for your hardware to get  the packets really on your physical interface. So how do we do this? Memory management also  is already said that you can use the malloc and the free functions from your C library  if they are decent enough, if they are available. If you're using an operating system then you  could use the memory allocation from the operating system and we're also right now implementing  our own memory manager because we believe that we can allocate and free memory more efficient  than most C libraries do. Also coping with fragmentation when transmitting small packets  and things like that. So that's a new development that's on its way. I think it almost made  its way into the stable, there is an active pull request, great. So next thing you need  is timing functions. The way we set this up is a timer interrupt which will every millisecond  increment in 64 bit integer so that we get a big enough time base and then you need two  functions, picotime and mess and picotime which will return the elapsed time in milliseconds  or in seconds. So how do we do this? This is an example from the embed implementation  I think again. So the picozaloc is actually the wrapper around the malloc function which  we'll use. So here you can see that it simply uses the malloc from the C library and a requirement  for picotcp is that you really zero all the memory explicitly so if your C library doesn't  do it or you could have a calloc available for example. Next thing is the picotime and  mess. We're doing a trick here with 32 bit integer which is being incremented because  it's a little bit faster and then we're detecting when it overflows and picotime is just returning  the same value divided by 1000. The last statement here is optional. You could use that as a  blocking function which just wait until another millisecond has elapsed but it's not mandatory.  Now we get down to the device driver. This API we tend to make it very generic and very  simple also so there's only a few things needed. That's the picodef create which will return  a struct to a picodevice and then you have its opposite at the bottom which is picodef  destroy which will do all the cleanup and then you have a send function and a pull function  so you want to transmit a packet or you want to see if there's new data available or not  on your physical interface. So the header is really simple. There's only two functions  exposed which are the embed create and the embed destroy in this case. All the rest is  underneath which you can see here so this is the create function which will allocate  some memory at the top for the device driver then we will set the MAC address because this  is an Ethernet device. We will init the device and then set a few function pointers which  will do the actual work. These are callbacks which are put into a struct. Actually what  we've done here and what is a way that's easy to get started on new platforms is you make  wrappers around the existing driver or implementation. In the embed system we had Ethernet read available  so this is actually just a wrapper around this function and then you can get started  with a one page function or even a half page function and the Pico TCP driver is working.  The send function is just the same story we're using the Ethernet write and Ethernet send  API from the embed. So let's get down to a demo. What we've done here is we've taken  a small MIDI keyboard. Actually it's meant as a toy for the Wii I think but it wasn't  a great success so you can find them really cheap on eBay. The great thing is they have  a MIDI port which we will use. This MIDI port, the MIDI protocol is really simple so you  just need a level translator and then with a UART you can read out the bytes which are  on the MIDI channel. What we're doing is, you can see this here, we take the keyboard,  we translate this to a serial stream, the microchip pick controller will read this out,  use Pico TCP to put this on a Wi-Fi channel. Over the Wi-Fi we are actually transmitting  a TCP stream with on top zero MQ which is a great message queueing protocol which makes  it really easy to send and publish messages actually. So the keyboard here is a publisher  and my laptop will subscribe to this publisher and get every message that it makes available.  So these messages will be the MIDI notes which are played on the keyboard. Then I can receive  them with a tiny Python script on my laptop and then I put these bytes again into a virtual  MIDI device and this virtual MIDI device can then be hooked up to any synthesizer on my  laptop. So I can show you the Python script which will read these binary packages. So  that's about it. I think there's a few more lines at the bottom. Most of them are print  functions just to see what's going on. So this is just to show how easy it is to do  TCP IP communication by using zero MQ. Yeah, I will just power up the device meanwhile  and let it connect to the Wi-Fi network and I don't know if there is anybody here who  can actually play the piano because I can't so that we can do this demo. Is there anyone  who wants to play a few notes? Yeah, come along. Yeah, except that the board is USB powered  indeed. So the board is connected. I will now connect the Python script and you can see  that it's immediately receiving MIDI messages and now I have this virtual MIDI device and  I should connect it to a synthesizer and now you should be able to play the piano. Maybe.  Thank you. Yes. Let's see. I'll make the connection again. Okay, go ahead.  Great song. Thanks. So I don't know if there's any time left for two minutes, two questions.  Yes. So this is a great project. I'm very impressed and I'd like to use it but my project's  GPLv3 so I can't. Why have you done that? Why do you think that's a good idea? That's  a good question. We think the V3 is a little bit too restrictive for the purpose. Yeah,  it's true. I don't know. Maybe I can call the help of an expert on this matter. I would  reply with another question actually. So what was the need exactly of the GPL3 if we already  had the two which was working pretty well? I think we can take this offline. Okay, so  we're going to cut this discussion about GPL licensing. I think if you simply say GPL2  or later and then I think the problem is solved but we can discuss this later. Thank you very  much for the demo. If anybody wants to carry on playing the piano, we have an open slots  after the next speech but we're going to stick to our timing here. Thank you very much for  this amazing piece of work. Awesome. We have a five minute break and then we have our last  formal talk for today.
_FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_0_191.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_192_239.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_240_1079.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_1080_1739.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_1740_2183.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_2184_3179.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_3180_4355.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_4356_5339.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_5340_5795.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_5796_5891.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_5892_7547.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_7548_8567.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_8568_12923.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_12924_15359.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_15360_17399.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_17400_18719.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_18720_21275.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_21276_23603.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_23604_24743.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_24744_24815.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_24816_24875.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_24876_25091.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_25092_27755.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_27756_28439.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_28440_29111.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_29112_29747.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_29748_30299.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_30300_31223.png _FOSDEM_2014__PicoTCP_AO4liMJZ0Qg_31224_33621.png