Skip to content

Abstract class for network support - #149

Merged
gdwnldsKSC merged 4 commits into
ES40-Emu:mainfrom
jbglaw:jbglaw/tap-support
Jul 25, 2026
Merged

gdwnldsKSC merged 4 commits into
ES40-Emu:mainfrom
jbglaw:jbglaw/tap-support

Conversation

@jbglaw

@jbglaw jbglaw commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Pull all libpcap code out of the Tulip emulator and place it into a "pcap" implementation. Also add a "tap" implementation that can work on Linux and *BSD.

The initial patch was taken from lenticularis39/axpbox#124
and, afaict, was created by Claude AI.

This is tested to work on Linux with a bridge. Need to test is on some BSD,
and the pcap code is untested right now.

Jan-Benedict Glaw and others added 2 commits July 25, 2026 17:47
Pull all libpcap code out of the Tulip emulator and place it into a
"pcap" implementation. Also add a "tap" implementation that can work
on Linux and *BSD.

  The initial patch was taken from lenticularis39/axpbox#124
and, afaict, was created by Claude AI.

  This is tested to work on Linux with a bridge. Need to test is on some BSD,
and the pcap code is untested right now.
Added NetworkBackend.cpp and NetworkPcap.cpp to project.
@gdwnldsKSC

Copy link
Copy Markdown
Collaborator

We'll see if that lets it compile, then once I have it locally after I validate it works, I'll do the full VS proj file fixups as a separate commit to deal with the IDE views/filters etc.

@gdwnldsKSC

Copy link
Copy Markdown
Collaborator

"
%GUI-I-INS: Installing sdl module as the ES40 GUI
sys0(tsunami): $Id$
%FLS-I-RESTST: Flash restored from rom\flash.rom
sys0(tsunami): $Id$
fdc0(floppy): $Id$
pci0.17(ali_pmu): $Id$
pci0.3(sym53c810).disk0.0(file): Mounted file img\jbgflaw.img, 52428800 512-byte blocks, 65536/16/50.
CD FILE
pci0.3(sym53c810).disk0.4(file): Mounted file iso\DIGITAL UNIX - V4.0E - Operating System.iso, 320300 2048-byte blocks, 3203/10/10.
dma: $Id$
dpr: 16384 bytes restored.
%DPR-I-RESTST: DPR state restored from rom\dpr.rom
sys0(tsunami): $Id$
cpu0(ev68cb)(0): $Id$
serial0(serial): Waiting for connection on port 21264.
serial0(serial): $Id$
serial1(serial): Waiting for connection on port 21265.
serial1(serial): $Id$
pci0.15(ali_ide).0 PCI BAR 0 set to IO 801fc0001f0, len 8.
pci0.15(ali_ide).0 PCI BAR 1 set to IO 801fc0003f4, len 4.
pci0.15(ali_ide).0 PCI BAR 2 set to IO 801fc000170, len 8.
pci0.15(ali_ide).0 PCI BAR 3 set to IO 801fc000374, len 4.
pci0.15(ali_ide).0 PCI BAR 4 set to IO 801fc00f000, len 10.
%IDE-I-INIT: New IDE emulator initialized.
pci0.2(s3): LFB INACTIVE(BAR) - MSE=0 CR58=ff base=00000000 size=400000 (reason=PCI BAR0)
pci0.2(s3): LFB INACTIVE(BAR) - MSE=0 CR58=00 base=00000000 size=10000 (reason=PCI BAR0)
pci0.2(s3): $Id$
pci0.3(sym53c810): $Id$
Emulator Failure: Runtime exception: Could not create a network backend (see messages above): D:\a\es40\es40\src\DEC21143.cpp, line 449"

Gotta love it. :) Yes, the totally relevant messages above! Hah. I'll figure that part out.

@gdwnldsKSC

Copy link
Copy Markdown
Collaborator

Ah, I see! NIC config needs to specify a type now.

I think I'll default it to pcap out of the box as that's what everyone's used to so config changes/confusion aren't needed.

@gdwnldsKSC

Copy link
Copy Markdown
Collaborator

Alright, the pcap side looks good @jbglaw - this looks ready to go pretty much. Tested out all nice and fine.

With the pcap default modification I made, no existing configs will need modification, so that's good there.

Do you know if the TAP code is OS specific? I know qemu has separate TAP backend code for some kind of generic (i think? it's just tap.c) and AIX, BSD, Haiku, Linux, Win32, and Solaris (in tap-OS.c variants). tap-win32.c compiles fine without tap.c so I'm kind of unclear on that (not a side of qemu I've ever dug into)

The build failures that remain were just workflow fetch errors, so nothing to worry about there.

@jbglaw

jbglaw commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

The BSDs and Linux are almost identical by just read()ing/write()ing frames. The initial device open is slightly different.

Solaris IIRC has recvmsg()/sendmsg() along with metadata, and setup is quite different as well. Can be done, but I don't have any practical means of getting that tested. Wouldn't want to place a completely heuristic implementation...

@gdwnldsKSC

Copy link
Copy Markdown
Collaborator

@jbglaw Oh, I only asked so I know what to potentially write or document about, as long as this works for both, that's good enough.

When I get to adding solaris and AIX support, I'll handle all that myself, I have the testing resources right next to me ;)

@gdwnldsKSC
gdwnldsKSC merged commit c536738 into ES40-Emu:main Jul 25, 2026
@jbglaw
jbglaw deleted the jbglaw/tap-support branch July 25, 2026 20:47
@kleinmatic

Copy link
Copy Markdown
Contributor

Claude weighing in (Opus 5 this time — the WTINT PR was Fable; Scott is posting this for me) —

You asked for a BSD tester for this. We ran it on FreeBSD 15.1 amd64 (razrez, a Proxmox guest) against an OpenVMS Alpha 8.4 guest, on the v0.77 tag (96c134a), built with asmjit/JIT enabled. Short version: the TAP backend works on FreeBSD.

  • type = "tap"; adapter = "/dev/tap5"; opens cleanly. procstat -f shows es40 holding the fd read-write; ifconfig tap5 reports UP,BROADCAST,RUNNING,PROMISC,LOWER_UP and Opened by PID <es40>.
  • Bidirectional traffic confirmed: 4/4 ICMP with the host across a bridge, and a full TCP session (telnet into the guest, banner + login). ARP resolves to the guest's DECnet-derived MAC.
  • Attached to an if_bridge(4) member; also fine after moving the tap between bridges live, with no emulator restart.
  • No packet lost at the default queue under ~10 pps of LAN broadcast. Worth noting a tap only receives what the bridge forwards, where pcap on a physical NIC sniffed everything — so this path is quieter than pcap by construction.

One real bug while we were in there, in CNetworkTap::init():

char *adapter = cfg->get_text_value("adapter");
const char *tap_name = adapter ? adapter : "tap0";
if (!tap_open(devid_string, adapter))   // <-- passes adapter, not tap_name

tap_name is computed and never used (probably a -Wunused-variable), so the "tap0" default is dead. On Linux that's benign — tap_open guards with if (name && name[0]) and the kernel picks a name. On FreeBSD/NetBSD the same path is open(name, O_RDWR), so omitting adapter with type = "tap" passes NULL to open() — undefined behaviour rather than the intended default. One-character fix.

Also worth a line in the docs: adapter means an interface name on Linux (bound via TUNSETIFF) but a full device path on BSD (/dev/tapN). Same config key, non-portable value — we lost a few minutes to that before reading the source.

Happy to test anything else on FreeBSD; it seems to be the platform with the fewest eyes on it.

@gdwnldsKSC

gdwnldsKSC commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

huh? We already knew it worked on BSD. I had just asked for clarification about the new code if it needed to be noted or documented that it behaved differently or not, we didn't need any testing or anything - that's why this is closed and complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants