On Thu, May 23, 2019 at 03:51:15PM +0200, David Jander wrote: > On Thu, 23 May 2019 14:50:20 +0200 > Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> wrote: > > > On Thu, May 23, 2019 at 12:54:40PM +0200, Oleksij Rempel wrote: > > > On 23.05.19 12:20, Kurt Van Dijck wrote: > > > > On do, 23 mei 2019 11:41:22 +0200, Oleksij Rempel wrote: > > > > > This patch series is a preparation and actual session queue support. > > > > > From now, we are able to use full available wmem of the socket and > > > > > queue all requests if it is needed. The stack will process > > > > > all queued requests in the FIFO order and notify user space application > > > > > about error or completion over the errqueue interface. > > > > > > > > I don't understand why it is necessary to queue single messages into a > > > > FIFO and notify user space later on? > > > > > > I'm not sure I understand this question. What type of message is "single > > > messages" in your case? > > > 1. Notification in user space are optional and should be enabled by > > > application - there are no necessity in it. > > > 2. If we need to keep order of queued messages there is no way you can > > > predict if user space will put one or 100 messages in it, so every message > > > go through the FIFO. > > > 3. The feedback mechanism is provided for every type of message since it is > > > possible to drop complete queue, so we are still able to notify user space > > > about doped or send messages. > > > > > > > Are you sure that different sockets still send asynchronous from each > > > > other as long as TP/ETP is not involved? > > > > > > Yes. It is per socket queue. First message in the queue are currently activated > > > independent of each other. > > > As soon as different sockets have same address and trying to start or queue a transfer > > > with conflicting type, address and direction, current stack implementation > > > will block/prevent second transfer to start. > > > > > > The next step would be to implement dequeuing mechanism for conflicting > > > transfers queued in different sockets. > > > > A bit more information about implementation. > > > > The stack creates a new session for each new send*()/write() request, independent > > of the message size. Each session is queued in to the socket sk_session_queue. > > The first entry of the queue is always the active/transferring session. > > If the queue is empty, the session is immediately activated (start of transmission). > > Activated session is registered in the per interface list of active sessions to > > avoid start of conflicting transmissions. > > After end of transfer the session will activate next session of the > > parent socket, if any session is available. > > > > ASCII art would looks as follow: > > /* socket queue */ > > [...10K..Pending][.8B.Pending][....1M...Active session] > > > > The challenges will start as soon as user will decide to use different sockets > > with same addresses, so we will have conflicting (E)TPs in different socket queues. > > > > Here is one possible horror scenario: > > Socket 1 [...N1] [|D|xxx.........A1] > > Socket 2 [p2...B1] > > Socket 3 [p1..B1]-> > > Socket 4 [...B1] > > > > A1 - is currently active (E)TP session > > B1 - is a queued conflicting session which is blocked by A1. > > p1 and p2 are priority set for different sockets or sessions. > > In this use case all 4 sockets was bind() and connect()ed to same > > addresses or sessions was configured with same addresses and have conflicting > > message types. > > Current implementation will abort conflicting transfers. The idea was to resolve > > this conflicts in stack and activate them in per time and priority order. We should > > guarantee only per socket order. > > > > The question to is, do we actually need it? With current implementation the user space > > application has all needed information to avoid this kind of conflicts. And a system > > with multiple applications and same address seems to be a rare use case. > > > > What is your experience with it? > > > > David? > > Like I explained previously, scenarios I can come up with are related to > possibly an IsoBus file-server and -clients. If a file-server has more than one > client connected, we can have a situation where the server sends two (E)TP > sessions simultaneously to two different clients each, while also at the same > time broadcast status messages at a fixed interval (so in-between the two > (E)TP sessions). > The big question is: how to accomplish that exactly? Some possibilities: > > 1.- Server bind()s to his NAME and client-to-server PGN. Each request he > receives from a client is replied with a send_to() on that socket. The above > solution, AFAICS, would not allow that, because replies to two different > clients could not be sent simultaneously if there is one queue per socket. ACK - the (E)TP sessions and now also the < 9 bytes frames (which are now internally sessions as well) are send strictly in order. The next session is started as soon as a session finishes. > 2.- Server bind()s to his NAME and client-to-server PGN. When a request from > a new client comes in, a new socket is opened and connect()ed to that client > with the server-to-client PGN. This socket is kept open as long as the client > connection lasts. How long you keep the socket open depends on your higher level protocol. > The connection is defined to last as long as there is no > time-out on the periodic "Client Connection Maintenance" messages incoming > from the client. As the original socket and the new socket are both bind() to the _same_ client-to-server PGN, messages from the client will end up in _both_ sockets. However, if your new socket connect()s to a client NAME/DST and the Server-to-client PGN, on this socket you'll not receive messages from other clients (however the main socket will receive messages for _all_ client, so these messages, too[1]). [1] We've not reworked the RX path, yet. > So this might work with the proposed queueing. The server > would possess as many open socket as there are clients connected plus one > (for broadcast messages (status) and incoming data). AFAICS this is pretty > similar to how a TCP/IP server would do this also, except for the > listen/accept part, You have to take care of listen/accept yourself, TCP defines this on the protocol level and so the kernel helps you. > and the fact that on TCP/IP one receives data on the same > socket as one sends, right? In J1939 after bind() + connect() you have a bi-directional connection, where you can rx/tx data on the same socket. The only downside I see is the duplicate reception (on the original and the new socket). But we have not reworked the RX-path. > Option 2 above brings me to another question: > What happens when said server bind()s to the client-to-server PGN on more than > one socket? Which one will receive incoming data? Both? Or is this not allowed? For now, yes. > As for a use-case of simultaneous TP + ETP from the same source to the same > destination, I don't have a use-case right now, but since it is _technically_ > possible according to the standard, I still believe that it is desirable to > have that possibility in the kernel implementation. TP + ETP for the same tuple (SRC/DST/PGN) is still possible. In fact the session type is part of the tuple now: SRC/DST/PGN/EP-or-ETP. My previous question was related to the TX path with a situation where two sockets are sending from the same SRC to the same DST and same session type (ETP + ETP or TP + TP) and PGN doesn't matter. Currently we try to refuse the second send*() with a -EBUSY regardless of blocking or non-blocking socket as early as possible, but with queuing this is rather complex. We'll try to outline the scenario tomorrow in another mail :) regards, Oleksij and Marc -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |