Re: [PATCH 1/1] tidbits: net-udp: solicit new client for server mode
Philippe Gerum <[email protected]> Tue, 21 Jul 2026 09:51:00 +0200
| Newsgroups | dev.linux.lists.xenomai |
|---|---|
| Message-ID | <[email protected]> |
Hannes Diethelm <[email protected]> writes: > Am 20.07.26 um 16:27 schrieb Philippe Gerum: >> Hannes Diethelm <[email protected]> writes: >> >>> Am 04.07.26 um 19:52 schrieb Philippe Gerum: >>>> Hannes Diethelm <[email protected]> writes: >>>> >>>>> Am 20.06.26 um 19:28 schrieb Philippe Gerum: >>>>>> - Honor MSG_PROBE for oob_sendmsg(), so that only the general call >>>>>> sanity and route resolution to the destination host is performed when >>>>>> set in the request flags, without actually sending any data. On >>>>>> success of such call, we would know that the routing information is >>>>>> readily available from the oob caches, no offload to in-band would >>>>>> have happened if we had not given this flag. The absence of routing >>>>>> information to the destination from some oob cache would yield a >>>>>> specific error, so that the caller may decide what to do next. >>>>> >>>>> It seams the flag MSG_PROBE is kernel only? I did not find any occurrence >>>>> in /usr/include or in libevl. >>>>> >>>> Yep, my bad. Using MSG_PROBE is not the right way, since that would >>>> conflict with MSG_PROXY in userland which has a totally different >>>> meaning. I have revisited the implementation, simplifying it actually: >>>> since the evl netstack already accepts zero-sized messages, sending such >>>> a datagram to the UDP layer now amounts to returning early with the >>>> address resolution status, short-circuiting the logic before the actual >>>> transmission happens. >>>> IOW, passing a NULL or empty iov into the msghdr struct does what >>>> MSG_PROBE was intended to do. >>> >>> I tested this variant. It works. But I wonder: >>> If I use: >>> ret = oob_sendmsg(s, &msghdr, NULL, 0); errno is set to EHOSTUNREACH >>> If I use: >>> ret = oob_sendmsg(s, &msghdr, NULL, MSG_DONTWAIT); errno is set to EWOULDBLOCK >>> >>> Is this intended? EHOSTUNREACH is like halve correct. Yes, the host can not be reached >>> but only due to no ARP request is sent. >>> >> EHOSTUNREACH was intended as a way to distinguish from EWOULDBLOCK >> wrt >> lack of buffer space for the outgoing message, this code was the only >> option close enough to the idea to be conveyed available from the errno >> list that would not conflict with other situations. Now, since such >> probing mode needs no message space in the first place, this is guarding >> against the impossible, which does not make sense. Returning >> -EWOULDBLOCK in both cases above would still be >> practical. e.g. something along these lines: >> diff --git a/kernel/evl/net/ipv4/udp.c b/kernel/evl/net/ipv4/udp.c >> index d819616c3b5b..5912a1fbcfb5 100644 >> --- a/kernel/evl/net/ipv4/udp.c >> +++ b/kernel/evl/net/ipv4/udp.c >> @@ -417,22 +417,22 @@ static ssize_t send_udp(struct evl_socket *esk, >> * address. >> */ >> ret = find_egress_path(esk, daddr, &ert, &earp, &pseudo_earp, msg_flags); >> - if (ret == -EMULTIHOP) >> - return ret; /* MSG_DONTROUTE cannot be honored. */ >> - >> if (ret) { >> + if (ret != -EHOSTUNREACH) >> + return ret; >> + >> + if (datalen == 0) >> + return -EWOULDBLOCK; /* Address probe failed. */ >> + >> /* >> - * No route known from the front cache - bummer. We >> - * may have to offload the transmit operation to the >> - * in-band stack, unless only probing or MSG_DONTWAIT >> - * is set. >> + * We have a message to send but no route was found in >> + * the front cache - bummer. We may have to offload >> + * the transmit operation to the in-band stack, unless >> + * only probing or MSG_DONTWAIT is set. >> */ >> if (msg_flags & MSG_DONTWAIT) >> return -EWOULDBLOCK; >> - if (datalen == 0) >> - return ret; >> - >> /* >> * We always charge the socket even when offloading to >> * the in-band stack although we won't consume any >> > > I think in this case, it is fine as it is. You also won't expect EWOULDBLOCK or EAGAIN as long as you > don't set MSG_DONTWAIT. > > But now there are two ways of probing. Either with or withouth MSG_DONTWAIT that behave slightly different. > Might be just support MSG_DONTWAIT -> EWOULDBLOCK and drop the other > variant? You mean detect a probing request when receiving MSG_DONTWAIT and a zero-sized buffer? That is an option. Another option would be to always return EHOSTUNREACH/??? on failed probe regardless of whether MSG_DONTWAIT is set. I would preferably go for the second option iff we can settle on a unconfusing, unambiguous error status. > Or is there a reason > for the variant withouth MSG_DONTWAIT? > In fact, the original intent was to assume that receiving a zero-sized message should be considered as a probing request. Then the effect of detecting MSG_DONTWAIT too in this particular code path was overlooked, which unexpectedly introduced another variant, which is indeed one too many. >>> For oob-net-udp server mode, this variant is a bit wastefull due to oob_sendmsg() would >>> either always be called twice or I would have to keep the list of clients. >>> >> Which brings back the option of some MSG_xxx operation flag so that >> we >> could pass a valid buffer _and_ a probing flag, but then we'd need >> Dovetail to add one to the standard list (in userland) because I don't >> see any standard one to piggyback off of. >> > > Is there a reason to pass a valid buffer to only probe? Either you probe > with a NULL buffer / size 0 or you pass a buffer and set MSG_DONTWAIT so > the message is sent if possible. If not, evl_net_solicit() and retry. > > BTW: NULL buffer / size 1 fails. But it also makes no sense. > Yep, in this case, -EFAULT is a reasonable outcome since the key argument is the message size. If the core is told that at least one byte is valid, then a valid pointer to at least one byte should be given. >>>> >>>>>> - Extend the effect of receiving MSG_DONTWAIT (and more generally >>>>>> O_NONBLOCK on fildes) to what we would do upon missing routing >>>>>> information: if present, return with a specific error code _without_ >>>>>> relaying the packet to the in-band stack. The caller may then decide >>>>>> to handle the case locally. Otherwise, proceed as usual (i.e. relay to >>>>>> the in-band stack, then notify the caller with -EINPROGRESS). >>>>> >>>>> So the oob-net-udp server code can be changed to use MSG_DONTWAIT and >>>>> if the return value is EWOULDBLOCK, call evl_net_solicit() and try again instead >>>>> of holding a list of IP's right? >>>>> >>>> Yep. >>> >>> This works nicely, I will send a patch changing oob-net-udp server mode to use this. >>> >>> The only disadvantage is that if for what ever reason, the client is already in the ARP >>> cache but not permanent, it is cleared after a timeout, so evl_net_solicit() can happen >>> later than expected. >>> >> Yep, because at the moment, the core mirrors to the front cache all >> insertions and deletions happening into the inband cache >> unconditionally. We could force a permanent state for any entry we are >> about to insert into the front cache in order to prevent what you >> described, but I'm wary about unwanted side-effects. > > Right now you can use evl_net_solicit(..., EVL_NEIGH_PERMANENT) to make shure it is > permanent but this is an in band call according to the doc. So if you want to stay > out of band, you need to probe. > > Now the probing doesn't show if the arp entry is permanent or going to disapear soon. So it > can pass at the first try and fail later. Right now, you are better off doing evl_net_solicit() > for every client if you want to be shure. > > With ioctl(s, SIOCGARP, &arp_request), you can check if the entry is permanent > (arp_request.arp_flags & ATF_PERM) and then use evl_net_solicit(..., EVL_NEIGH_PERMANENT) if not. > But the ioctl is also in band. > > An option would be either to support of oob_ioctl() for SIOCGARP. Or create something like > evl_net_routeinfo(s, addr) returning flags would make probing obsolete. > > Flags could be: > EVL_ARP_COM Lookup complete (If this is not set, no ARP entry) > EVL_ARP_PERM Permanent entry > EVL_ROUTE_MULTIHOP More than one hop away (Will fail with MSG_DONTROUTE) > Having oob_ioctl(SIOCGARP) which would perform a lookup into the oob front cache managed by the core is perfectly doable, then we could provide evl_net_routeinfo() as syntactic sugar building on it. I would consider reusing the ATF_* flags directly instead of adding yet another set of EVL_* flags only to alias to the former, since both caches hold the very same routing entries, therefore do provide the same information. In that sense, EVL_NEIGH_PERMANENT seems redundant since it fundamentally means ATF_PERM. Documenting ATF_PERM in the API docs while aliasing EVL_NEIGH_PERMANENT to ATF_PERM for backward compat may be a reasonable trade-off, until we can drop the former in order to further reduce the namespace pollution. -- Philippe.