Network API task force

Hi,

at the last Network Stack Task Force meeting, we came to the conclusion that a task force for defining API's for network functionality like sockets or coap would be useful.

So I'd like to start this and invite everyone to join!

I'll start the discussion with my opinion on the need for a new socket API.

It was discussed if we couldn't just adopt the BSD/POSIX socket API, as we would need that API anyways.

In my opinion, it has some drawbacks for embedded usage. Best example: (From "man 7 socket"): --- snip --- SYNOPSIS        #include <sys/socket.h>

       sockfd = socket(int socket_family, int socket_type, int protocol); --- snip ---

This is the function that creates a socket and returns a handle. In malloc-capable systems, this is perfectly fine. In RIOT, the question arises, what does the returned fd mean?

The socket will definately need some state. This needs to be somewhere in memory. Using that API, we'd need to either preallocate a certain amount of socket state structures, or use malloc. Both ways suck.

So a new socket library might more look like:

--- snip --- socket = socket(socket_t *sock, blah) ... --- snip --- That way, the caller has to provide all memory needed for managing the socket.

We do it like that all over RIOT, so I'd like to see this adopted for sockets.

I also believe that it is very easy to implement BSD sockets once these RIOT sockets are in place, adding the memory burden. It is not possible to do it the other way around...

Thoughts?

Kaspar

Hi Kaspar, just to state the “opposite” opinion, too: while I see the need for an API suitable for embedded use only and other stacks than the default one too, I’m of the opinion, that the POSIX sockets (needed for library and application ports) should also be as slim as possible. This means: A wrapper (POSIX sockets) around a wrapper (the new new network API) around some API (e. g. netapi) seems like overkill to me.

Cheers, Martine

Hi,

Hi Kaspar,

Hi,

Actually, yes. But I'm still trying to get my head around why netapi (or it's wrapper functions [1], slightly renamed) could not be that API.

Because it requires the use of messages, which implicitly requires using seperate threads. This is not feasable for low-memory systems.

If you check out my nanonet branch [1], there's a monolithic stack that does Ethernet/IPV4/UDP/CoAP in about 5k RAM, with room for improvement.

If netapi would be used even just for CoAP, that stack would unnecessarily be forced to put CoAP in its own thread, with all the memory implications.

I'd like to avoid that.

Kaspar [1] GitHub - kaspar030/RIOT at nanonet

Hi,

Hey,

Hi Kaspar,

Hi!

If you agree that we need an API for embedded use, would you agree that this API should be the one that all RIOT internal libraries (e.g., for CoAP) should use?

I still wonder how sensible this is. To me, it seems that application layer protocols such as CoAP have a fundamentally different semantic than lower layer protocols such as UDP or IP (GET/SET/PUT/DELETE vs. send/receive) and targeting a fundamentally different developer group (application developers or even "users" that don't care about network internals vs. network protocol developers that may live with a somewhat less abstracted API as long as it is powerful and efficient enough).

IMO it is sensible to have a unified API with the feature set of netapi (or at least similar) for everything *below* application layer. If I want to send a payload from A to B, it should be matter of seconds to modify the send-call from transmitting this payload over transport layer to transmitting over, let's say, link layer.

Cheers, Oleg

Hi,

protocols such as CoAP have a fundamentally different semantic than lower layer protocols such as UDP or IP (GET/SET/PUT/DELETE vs. send/receive) and

sorry, of course I meant POST and not SET.

Cheers, Oleg

Hey,

Hi Kaspar!

> int ng_netapi_send(kernel_pid_t pid, ng_pktsnip_t *pkt);

How do I use this without pktbuf or at least two threads?

Well, the memory for the packet (at least for the payload) has to be stored somewhere - at least until it is copied into the transceiver buffer.

Cheers, Oleg

Hi,

Hi,

int ng_netapi_send(kernel_pid_t pid, ng_pktsnip_t *pkt);

How do I use this without pktbuf or at least two threads?

Well, the memory for the packet (at least for the payload) has to be stored somewhere - at least until it is copied into the transceiver buffer.

That doesn't answer the question.

A "udp_send" could in one implementation fill a pktbuf and use netapi, in another implementation just call the underlying send functions and return only when the payload has been copied into the send buffer, not malloc'ing extra memory. That should be abstracted from the user, but in a way that doesn't force a stack to use netapi/pktbuf.

Kaspar

Hi Kaspar!

Actually, how a network stack internally communicates should be kept to that stack. I was talking exactly for the upper layers, e.g., applications.

How do I bind to a UDP or TCP port? How do I write to a TCP connection?

Well, no, than you're talking exactly about the second type of API. One (an application or an application layer protocol) wants to send or receive something over or from the network. At this point you have already a notion about the network itself. From an application developer perspective you don't care about this (sockets and so on), you basically only want to request or share data.

From the caller perspective, what's so different between sending over UDP than sending over raw IP? Even POSIX socket API allows that. As a sender I want to specify the destination and the protocol (for both cases it should IMO be possible to specify a best effort default).

My point was, that I don't see how it makes sense to design one API that can be used for this purpose *and* protocols on top.

My point is that something like

--- udp_socket_t s; udp_bind(&s, address, port);

udp_read(&s); ---

should be available. If the stack below is netapi based, then those calls should map to netapi calls. If not, whatever.

Sure, from the caller perspective you don't care what's happening inside the stack, but what's so wrong in having the same API at all layers, i.e. inside and on top of the stack? (Assuming that it can be implemented without (or very, very, very little overhead.)

I'm not say that netapi is necessarily the API, we want to use on top, and I agree with you, Kaspar, that we should look very carefully at it and eliminate any hard dependency to threads or the packetbuffer and so on. But I agree with Martine, that we shouldn't discard the idea of using netapi for this so quickly.

Remember, netapi is very, very young. It's a good point in time to change it *now*, in order to make it fit all our needs. If it turns out to be impossible, well, then we have to look for something else.

My first mail explains why I think that POSIX sockets are not suited for this.

And I think, there we all agree.

Cheers, Oleg

Hi!

That doesn't answer the question.

A "udp_send" could in one implementation fill a pktbuf and use netapi, in another implementation just call the underlying send functions and return only when the payload has been copied into the send buffer, not malloc'ing extra memory. That should be abstracted from the user, but in a way that doesn't force a stack to use netapi/pktbuf.

I don't see the problem. In implementation A (the nameless stack) udp_send() calls netapi_send(UDP_THREAD_PID, pointers_to(ip_header+udp_header+payload)) and in implementation B (nanonet) udp_send() calls netapi_send(active_pid, pointer_to(payload)).

Cheers, Oleg

Hi,

Sure, from the caller perspective you don't care what's happening inside the stack, but what's so wrong in having the same API at all layers, i.e. inside and on top of the stack? (Assuming that it can be implemented without (or very, very, very little overhead.)

Well, netapi right now is

int ng_netapi_send(kernel_pid_t pid, ng_pktsnip_t *pkt);

If we omit the messaging, and the pktbuf dependency, it is not "netapi" anymore.

Also, the default stack's whole design is based on threads passing messages containing pktsnips. Changing that would change the whole concept.

Applications now should be written in a network stack agnostic way. So if the stack implementor decides to go for the benefits of having clear module seperation and flexibility through using messages and threads, that still shouldn't force our application interfaces to that decision.

Kaspar

Hi,

Hi Kaspar!

int ng_netapi_send(kernel_pid_t pid, ng_pktsnip_t *pkt);

If we omit the messaging, and the pktbuf dependency, it is not "netapi" anymore.

For me netapi are basically four functions send(), set_receive_cb(), get() and set(). This can be implemented as wrapper functions around IPC (as in the nameless stack) or as direct function calls.

Also, the default stack's whole design is based on threads passing messages containing pktsnips. Changing that would change the whole concept.

And nobody wants to do this.

Applications now should be written in a network stack agnostic way. So if the stack implementor decides to go for the benefits of having clear module seperation and flexibility through using messages and threads, that still shouldn't force our application interfaces to that decision.

Agreed.

Cheers, Oleg

Hi!

Exactly. In this case "udp_send" is part of the API I'd like to define.

But why couldn't udp_send(vargs) not be wrapper/macro for X_send(PROTO_UDP, vargs)?

Any application should just use udp_send,

Yes!

and this udp_send shouldn't have a pktsnip as parameter.

Well, you will have to specify a pointer to data. I guess the most stack agnostic way is using a void pointer than.

Cheers, Oleg