[riot-notifications] [RIOT-OS/RIOT] netbuf: add initial support (#12315)

José Alamos notifications at github.com
Fri Sep 27 14:48:32 CEST 2019


<!--
The RIOT community cares a lot about code quality.
Therefore, before describing what your contribution is about, we would like
you to make sure that your modifications are compliant with the RIOT
coding conventions, see https://github.com/RIOT-OS/RIOT/wiki/Coding-conventions.
-->

### Contribution description
This PR adds an abstraction for allocating packets from a network stack or static buffer.
The motivation behind this is:
- To keep zero copy, the network stack is the one who in practice allocates the buffer for the packet. 
At the same time if we want to have MAC and PHY layers that are independent to the network stack, we need an interface for allocation.
- We can "instruct" the lower layers to allocate packets so the PHY layer can allocate a packet just right after reading the pkt_len (e.g first byte of the IEEE802.15.4 PHY frame). So we could think of dropping the "get packet lengh" and "drop packet" behavior of `dev->driver->recv` (see https://github.com/RIOT-OS/RIOT/issues/11652)

If CONFIG_NETBUF_DISABLE_STACK_ALLOC==0, it's necessary to define a `netbuf_stack_alloc` function for every stack.

### How to use
Let's assume there's a radio API for reading data from the framebuffer:
```c
int radio_read_packet(radio_t radio, netbuf_t *netbuf)
{
    char pkt_len;
    radio_read_framebuffer(radio, &pkt_len, 1);

    /* Allocate pkt of "pkt_len" bytes long */
    void *pkt = netbuf_alloc(&netbuf, pkt_len);
    if(!pkt) {
        return -ENOBUFS;
    }
    radio_read_framebuffer(radio, pkt, pkt_len);
    return pkt_len;
}
```
Depending on how the netbuf is initialized, it's possible to either get a buffer from the stack allocator or from a static buffer.
Let's assume GNRC has the following `netbuf_stack_alloc` function:
```c
void *netbuf_stack_alloc(netbuf_t *netbuf, size_t size)
{
    gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, size, GNRC_NETTYPE_UNDEF);
    if(!pkt) {
        return NULL;
    }
    netbuf->ctx = pkt;
    netbuf->data = pkt->data;
    netbuf->size = size;
    return pkt->data;
}
```
Some examples:
- Dynamically allocate packet when receiving:
```c
netbuf_t netbuf;
netbuf_init(&netbuf, NULL, 0); /* Pass NULL to ask the stack to allocate a packet when calling netbuf_alloc */
radio_read_packet(radio, &netbuf);
/* if everything is OK, netbuf.data contains the packet of length netbuf.size. */
/* If using GNRC, netbuf.ctx has a pointer to the pkt snip so it can be released afterwards */
```
- Pass a fixed buffer (useful when the size of the packet is known, e.g IEEE802.15.4 ACK packet)
```c
netbuf_t netbuf;
char ack[5]; /* Allocate space for the IEEE802.15.4 ACK */
netbuf_init(&netbuf, ack, 5); /* Pass the ACK buffer to the netbuf */
radio_read_packet(radio, &netbuf);
/*The ACK should be in the ack buffer*/
```

### Considerations about the RX procedure
I wrote [this patch](https://gist.github.com/jia200x/01fde55f1733ac5c6a8957b8e50c2d21) that overloads the "recv" function of netdev to receive a `netbuf` instead of a buffer, and removed the "drop" and "get packet length" logic. 

The "recv" function will read the pkt_len, try to get a buffer from the netbuf and write directly to that buffer. The frame buffer is read once and the logic is simpler now.

It also makes the binary smaller from:
```
   text    data     bss     dec     hex filename
  42864     508    6232   49604    c1c4 /home/jialamos/Development/RIOT/examples/default/bin/iotlab-m3/default.elf
```
to
```
   text    data     bss     dec     hex filename
  42716     508    6232   49456    c130 /home/jialamos/Development/RIOT/examples/default/bin/iotlab-m3/default.elf
```

And calling `netif->ops->recv()` is 6-8% faster with this method.
<!--
Put here the description of your contribution:
- describe which part(s) of RIOT is (are) involved
- if it's a bug fix, describe the bug that it solves and how it is solved
- you can also give more information to reviewers about how to test your changes
-->

### Testing procedure
- Check the documentation is OK with `make doc`
- Try the proposed patch.
- TBD: I will add some tests soon.
<!--
Details steps to test your contribution:
- which test/example to compile for which board and is there a 'test' command
- how to know that it was not working/available in master
- the expected success test output
-->


### Issues/PRs references
It's related to the PHY/MAC rework proposed in #11483
#11652
<!--
Examples: Fixes #1234. See also #5678. Depends on PR #9876.

Please use keywords (e.g., fixes, resolve) with the links to the issues you
resolved, this way they will be automatically closed when your pull request
is merged. See https://help.github.com/articles/closing-issues-using-keywords/.
-->

You can view, comment on, or merge this pull request online at:

  https://github.com/RIOT-OS/RIOT/pull/12315

-- Commit Summary --

  * netbuf: add initial support

-- File Changes --

    M sys/Makefile (3)
    A sys/include/net/netbuf.h (108)
    A sys/net/netbuf/Makefile (2)
    A sys/net/netbuf/netbuf.c (46)

-- Patch Links --

https://github.com/RIOT-OS/RIOT/pull/12315.patch
https://github.com/RIOT-OS/RIOT/pull/12315.diff

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/RIOT-OS/RIOT/pull/12315
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.riot-os.org/pipermail/notifications/attachments/20190927/994058c5/attachment.htm>


More information about the notifications mailing list