v86 icon indicating copy to clipboard operation
v86 copied to clipboard

Is it possible to network v86 instances together inside the browser?

Open Darin755 opened this issue 1 year ago • 10 comments

I am looking for a way to network multiple instances together without having to do anything server side. This will be a part of a virtual networking lab for educational purposes. It might be possible to use serial to setup an connection but it would be tricky and not ideal. Ideally it would be nice to have a local network interface that can be used to make a virtual switch in the browser. You could have some sort of hook that runs a handler program when a frame is received. From there I could write a proper switch that could do routing based on mac.

Darin755 avatar Jul 27 '24 20:07 Darin755

Yes, see https://github.com/copy/v86/blob/master/examples/two_instances.html (haven't tested it in a while, but it should still be working)

copy avatar Jul 28 '24 10:07 copy

I am looking for a way to network multiple instances together without having to do anything server side. This will be a part of a virtual networking lab for educational purposes. It might be possible to use serial to setup an connection but it would be tricky and not ideal. Ideally it would be nice to have a local network interface that can be used to make a virtual switch in the browser. You could have some sort of hook that runs a handler program when a frame is received. From there I could write a proper switch that could do routing based on mac.

I've been playing around with the new fetch based network driver and have to say, its really friendly to begin work on (I even made my own handler for TCP in a day that uses https://github.com/MercuryWorkshop/wsproxy and is much faster than the relay based networking available), you could probably play around with that + webrtc if you're looking for cross computer communication.

alternatively you could hook virtio console and serial and send messages that way, it would be a form of networking, just not through the NIC

ProgrammerIn-wonderland avatar Jul 28 '24 20:07 ProgrammerIn-wonderland

Yes, see https://github.com/copy/v86/blob/master/examples/two_instances.html (haven't tested it in a while, but it should still be working)

Is it possible to have multiple interfaces? I am looking to have a mini web based network. For now I am looking into possibly writing a switch program that matches Mac addresses.

Darin755 avatar Jul 29 '24 01:07 Darin755

Is it possible to have multiple interfaces? I am looking to have a mini web based network. For now I am looking into possibly writing a switch program that matches Mac addresses.

I think the switch is the best idea here, there doesn't seem to be a way to create multiple NICs in v86 in starter.js, you'd probably need to do substantial modifications

ProgrammerIn-wonderland avatar Jul 30 '24 18:07 ProgrammerIn-wonderland

I might just use premade simulators. This is starting to seem way more ambitious than I realized.

Thanks

Darin755 avatar Jul 31 '24 01:07 Darin755

I'd accept a PR to support multiple adapters in the constructor. We'll soon have three network backends (wsproxy, fetch and wisp) and two adapters (ne2k and virtio-net), and it would be nice to support arbitrary combinations too.

copy avatar Aug 03 '24 14:08 copy

I am looking for a way to network multiple instances together without having to do anything server side.

If you need to connect instances within in a browser frame without server side, you can try to use Broadcast Channel API to receive/send Ethernet frames. Here I'm tried to make simple example:

v86-mesh

<!doctype html>
<script src="libv86.js"></script>
<script>
"use strict";

// from src/browser/fetch_network.js
function a2ethaddr(bytes) {
    return [0,1,2,3,4,5].map((i) => bytes[i].toString(16)).map(x => x.length === 1 ? "0" + x : x).join(":");
};

window.onload = function()
{
    var emulator = window.emulator = new V86({
        ...
    });

    emulator.add_listener("net0-mac", function(mac) {
        emulator.mac = mac; 
        document.title = "mesh: " + emulator.mac;
    });

    // [connecting to a channel (or creating a new one)]
    var broadcast = new BroadcastChannel("v86-mesh");

    // [receiving]
    broadcast.addEventListener("message", function(e) {
        const packet = e.data;
        const eth = {
            dest: a2ethaddr(packet.subarray(0, 6)),
            src: a2ethaddr(packet.subarray(6, 12))
        };
        
        // don't accept packets not addressed to us
        // ff:ff:ff:ff:ff:ff - broadcast
        if((eth.dest === emulator.mac) || (eth.dest === "ff:ff:ff:ff:ff:ff")) {
            console.log("packet from %s to %s", eth.src, eth.dest);
            emulator.bus.send("net0-receive", packet);
        };
    });

    // [sending]
    emulator.add_listener("net0-send", function(packet) {
        broadcast.postMessage(packet);
    });
}
</script>

<div id="screen_container">
    <div style="white-space: pre; font: 14px monospace; line-height: 14px"></div>
    <canvas style="display: none"></canvas>
</div>

Partly based on examples/two_instances.html and you also need to set a static IP for each VM, Currently it uses one network adapter, but could probably be redesigned for multiple network adapters.

SuperMaxusa avatar Aug 06 '24 14:08 SuperMaxusa

Well that is not an approach that I had considered. It would be closer to a hub instead of switch and I would need to come up with some sort of lock to prevent two instances broadcasting at the same time but it might be feasible.

Thanks

Darin755 avatar Aug 06 '24 18:08 Darin755

I have a working proof of concept. Thanks @SuperMaxusa

Darin755 avatar Aug 14 '24 14:08 Darin755

https://darin755.codeberg.page/netemu/src/

to run commands on the web worker you can run window.worker1.postMessage({cmd: "ip neigh"}) in the browser debug console. (there is a connection between the web worker and browser instance. Eventually it will be just web workers with the browser main just running switch/hub code)

Darin755 avatar Aug 15 '24 02:08 Darin755

@SuperMaxusa That is pretty cool, could you send a PR to add as an example?

Just a comment, I believe the following check is not necessary (it's already done in the network card)

        // don't accept packets not addressed to us
        // ff:ff:ff:ff:ff:ff - broadcast
        if((eth.dest === emulator.mac) || (eth.dest === "ff:ff:ff:ff:ff:ff")) {

copy avatar Dec 10 '24 17:12 copy

Just a comment, I believe the following check is not necessary (it's already done in the network card)

Indeed, thanks for your comment! Seems that I left this for clear logging on each VM.

SuperMaxusa avatar Dec 13 '24 06:12 SuperMaxusa