gvanem / Watt-32

Watt-32 TCP/IP library and samples.
https://www.watt-32.net/
18 stars 8 forks source link

Handle jumbo frames (possibly as WATTCP.CFG option) #69

Open maraakate opened 2 years ago

maraakate commented 2 years ago

Hello,

We've been using WATTCP for years in some DJGPP DOS applications, but I have noticed that UDP DGRAM fragments are sent as EWOULDBLOCK. This is a problem for old games like Quake 2 where sometimes this stupidity does happen, and we can't send them broken up on the server side because it breaks some client parsing. Unfortunately, some of these engines relied on the routers to take care of the problem.

I did some simple test by removing the DGRAM check in check_non_block_tx() but it appears WATTCP just ends up doing the same thing behind the scenes (i.e. breaking up the sendto()s to be less than MAX_MTU - overhead) and the same problem happens.

It would be great if there was a jumbo frames option to just send the whole thing unfragmented and it's up to the clients router to take care of it.

Thanks for all your hard work over the years, we've really gotten a lot of great use out of the library. Frank

maraakate commented 2 years ago

Giles,

I did a bit more poking around, and found out the hard way that even if you change MTU in WATTCP.CFG that there is a hard limit of about 1500. This is from MAX_ETH and friends. Maybe the code could be refactored to allow MAX_ETH, etc. to be controlled by a JUMBO_PACKETS config option?

gvanem commented 2 years ago

UDP DGRAM fragments are sent as EWOULDBLOCK.

Not sure what this means.

A Jumbo frame-size would depend on the Ethernet card. There is no way AFAICS to obtain the size of that. How is that obtained on other OSes like Windows or Linux? Some DeviceIoControl() call on Windows for sure. Or do you mean a JUMBO_PACKETS = 3000 setting should be accepted just like that w/o check what the real jumbo frame-size is?

maraakate commented 2 years ago

Hi, i mean the JUMBO_PACKETS=3000 just sends it this way and if it fails its the users fault because they explicitly set it and was incompatible. I think this is a decent compromise for the scope of the project.

Referring to EWOULDBLOCK. It just appears to get stuck in that limbo more or less with the software I've been using it with. But again, I think a way to force attempting to send 3000 or some other value beyond MAX_ETH would help in my cases.

gvanem commented 2 years ago

I think this is a decent compromise for the scope of the project.

Jumbo-frames can only work reliably on a LAN. So the code will need to check the destination before using such a JUMBO_PACKETS setting. Besides, I've never seen a Packet-driver supporting such Jumbo-frames. Have you?

Referring to EWOULDBLOCK. It just appears to get stuck in that limbo more or less with the software I've been using it with.

The reason is that IPv4 fragmentation (ref. ip4_frag.c) does not work so well. But you need this in Quake? On a LAN only, or what?

maraakate commented 2 years ago

Hi,

It's not so much that it needs be jumbo frames that need to be 9000 bytes. The problem is a bit more like this... some packets go over 1400 bytes (which is the default in these engines) and some packets in situations with a lot of action/entities on the screen will produce a packet that could be anywhere from 1500-1800 bytes on average (this is kind of rare, but happens enough). I've reduced this issue by reducing the amount of traffic that's being sent out. It's about as optimized as it can get, and if the frame is still over 1400 bytes then it's compressed with an on-the-fly compression scheme (we use quicklzf for this). This usually gets thing sane more than 90% of the time. However, there are corner cases where it's still too large.

In the old days, it kind of depended on your ISP, if you had dial-up or a DSL/Cable modem with router, etc. on how this would work. I've tested these kind of overflows before on a true dial-up and what happens is the packet is just discarded entirely. The player may be "stuck" for about 2-3 seconds until it can receive a frame of the proper size again. DSL/Cable modems will just do what they need to do to fix this and it assembles it properly.

With Watt-32 what happens is EWOULDBLOCK gets set because its a datagram (we are using UDP for all of this). Then this is spammed non-stop. So the packet is discarded, which is fine (not ideal, I'd like to see it be re-assembled, but this is an OK work around because it's not implemented) but the EWOULDBLOCK is still there, so every FD_SELECT it has the real packet of the next frame thats OK, but then there's still that EWOULDBLOCK as well and it never goes away unless I close the socket entirely.

I know this is all more a problem with the engine, and mappers and modders not respecting the limits of MTU being ~1400. And we've done all we can, but the socket driver should also help out in some way as well. With that said, I think allowing the code to go past that MAX_ETH hard limit of 1500 AND fixing UDP datagrams to work with the fragmentation instead of just EWOULDBLOCK would work OK. I have no experience in Watt-32, but I have looked around a bit since opening this issue. It appears that we should send EWOULDBLOCK the one time then just ignore and completely discard it. Otherwise it continues to get spammed and this actually bogs the machine down because every other frame its receiving junk it can do nothing with.

I may have misspoke and it's not that we need 9000 bytes of a jumbo frame, but we need to somehow gracefully handle if we get some UDP packet thats got 1800 bytes because someone forgot to check before sending. And possibly allow the user explicitly in WATTCP.CFG to allow setting that as the max limit. If it works, great, if not because the packet driver doesn't allow it... well too bad that's why it's an option and not a default.

gvanem commented 2 years ago

I've studied this a bit. It's impossible with WinPcap or any PacketDriver to send any frames > 1514 bytes. And if could be possible, all references to the constant ETH_MAX would be replaced with a global variable Jumbo_frame_size for all IP-packets. A major rewrite. Hence a won't fix label. But I'll keep it open.

maraakate commented 2 years ago

Hi gisle,

I need it in quake and on the internet mostly, but lan too. Yes, its a problem with crap mappers not respecting the limits and quake engine should have discarded entirely or something. But ethernet drivers even on win9x somehow handle these fragments at what I assume is on the router level. Thats why I'm curious if you just allow it to go through the router will handle it but wattcp is just receiving a larger buffer. The problem with ewouldblock is that it seems to be spammed continously and I may be missing something here but there is no way to consume it. I'd be okay with consuming and discarding it because at that point its too stale to be useful data. Can I do this with wattcp in it is current state? If no could we simply have a configuration option to discard the fragmented packet entirely for UDP or others in wattcp for these kind of situations?

Thanks, Frank

On Saturday, May 14, 2022, Gisle Vanem @.***> wrote:

I've studied this a bit. It's impossible with WinPcap or any PacketDriver to send any frames > 1514 bytes. And if could be possible, all references to the constant ETH_MAX would be replaced with a global variable Jumbo_frame_size for all IP-packets. A major rewrite. Hence a won't fix label. But I'll keep it open.

— Reply to this email directly, view it on GitHub https://github.com/gvanem/Watt-32/issues/69#issuecomment-1126781019, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADF6TOG4WRRWDEV6BAOTQ6TVJ7PLXANCNFSM5U2A3QNA . You are receiving this because you authored the thread.Message ID: @.***>