add mtu options to network code

This commit is contained in:
ading2210 2025-11-05 13:07:21 -08:00 committed by Fabian
parent ec90cede42
commit d093088616
8 changed files with 31 additions and 22 deletions

View file

@ -62,6 +62,7 @@ Backends `fetch` and `wisp` support a couple of special settings in `config.net_
| **dns_method** | str | DNS method to use, either `static` or `doh`. `static`: use built-in DNS server, `doh`: use [DNS-over-HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) (DoH). Defaults to `static` for `fetch` and to `doh` for `wisp` backend. |
| **doh_server** | str | Host name or IP address (and optional port number) of the DoH server if `dns_method` is `doh`. The value is expanded to the URL `https://DOH_SERVER/dns-query`. Default: `cloudflare-dns.com`. |
| **cors_proxy** | str | CORS proxy server URL, do not use a proxy if undefined. Default: undefined (`fetch` backend only). |
| **mtu** | int | The MTU used for the virtual network. Increasing it can improve performance. This only works if the NIC type is `virtio`. Default: `1500` |
#### Example `net_device` settings

View file

@ -45,18 +45,16 @@ const TCP_DYNAMIC_PORT_RANGE = TCP_DYNAMIC_PORT_END - TCP_DYNAMIC_PORT_START;
const ETH_HEADER_SIZE = 14;
const ETH_PAYLOAD_OFFSET = ETH_HEADER_SIZE;
const ETH_PAYLOAD_SIZE = 1500;
const MTU_DEFAULT = 1500;
//const ETH_PAYLOAD_SIZE = 1500; //mtu
const ETH_TRAILER_SIZE = 4;
const ETH_FRAME_SIZE = ETH_HEADER_SIZE + ETH_PAYLOAD_SIZE + ETH_TRAILER_SIZE;
const IPV4_HEADER_SIZE = 20;
const IPV4_PAYLOAD_OFFSET = ETH_PAYLOAD_OFFSET + IPV4_HEADER_SIZE;
const IPV4_PAYLOAD_SIZE = ETH_PAYLOAD_SIZE - IPV4_HEADER_SIZE;
//const IPV4_PAYLOAD_SIZE = ETH_PAYLOAD_SIZE - IPV4_HEADER_SIZE;
const UDP_HEADER_SIZE = 8;
const UDP_PAYLOAD_OFFSET = IPV4_PAYLOAD_OFFSET + UDP_HEADER_SIZE;
const UDP_PAYLOAD_SIZE = IPV4_PAYLOAD_SIZE - UDP_HEADER_SIZE;
const TCP_HEADER_SIZE = 20;
const TCP_PAYLOAD_OFFSET = IPV4_PAYLOAD_OFFSET + TCP_HEADER_SIZE;
const TCP_PAYLOAD_SIZE = IPV4_PAYLOAD_SIZE - TCP_HEADER_SIZE;
const ICMP_HEADER_SIZE = 4;
const DEFAULT_DOH_SERVER = "cloudflare-dns.com";
@ -161,15 +159,19 @@ class GrowableRingbuffer
}
}
export function create_eth_encoder_buf()
export function create_eth_encoder_buf(mtu = MTU_DEFAULT)
{
const ETH_FRAME_SIZE = ETH_HEADER_SIZE + mtu + ETH_TRAILER_SIZE;
const IPV4_PAYLOAD_SIZE = mtu - IPV4_HEADER_SIZE;
const UDP_PAYLOAD_SIZE = IPV4_PAYLOAD_SIZE - UDP_HEADER_SIZE;
const eth_frame = new Uint8Array(ETH_FRAME_SIZE);
const buffer = eth_frame.buffer;
const offset = eth_frame.byteOffset;
return {
eth_frame: eth_frame,
eth_frame_view: new DataView(buffer),
eth_payload_view: new DataView(buffer, offset + ETH_PAYLOAD_OFFSET, ETH_PAYLOAD_SIZE),
eth_payload_view: new DataView(buffer, offset + ETH_PAYLOAD_OFFSET, mtu),
ipv4_payload_view: new DataView(buffer, offset + IPV4_PAYLOAD_OFFSET, IPV4_PAYLOAD_SIZE),
udp_payload_view: new DataView(buffer, offset + UDP_PAYLOAD_OFFSET, UDP_PAYLOAD_SIZE),
text_encoder: new TextEncoder()
@ -991,7 +993,7 @@ export function fake_tcp_connect(dport, adapter)
throw new Error("pool of dynamic TCP port numbers exhausted, connection aborted");
}
let conn = new TCPConnection();
let conn = new TCPConnection(adapter);
conn.tuple = tuple;
conn.hsrc = adapter.router_mac;
@ -1000,7 +1002,6 @@ export function fake_tcp_connect(dport, adapter)
conn.hdest = adapter.vm_mac;
conn.dport = dport;
conn.pdest = adapter.vm_ip;
conn.net = adapter;
adapter.tcp_conn[tuple] = conn;
conn.connect();
return conn;
@ -1017,10 +1018,13 @@ export function fake_tcp_probe(dport, adapter) {
/**
* @constructor
*/
export function TCPConnection()
export function TCPConnection(adapter)
{
const IPV4_PAYLOAD_SIZE = (adapter.mtu || MTU_DEFAULT) - IPV4_HEADER_SIZE;
const TCP_PAYLOAD_SIZE = IPV4_PAYLOAD_SIZE - TCP_HEADER_SIZE;
this.state = TCP_STATE_CLOSED;
this.net = null; // The adapter is stored here
this.net = adapter; // The adapter is stored here
this.send_buffer = new GrowableRingbuffer(2048, 0);
this.send_chunk_buf = new Uint8Array(TCP_PAYLOAD_SIZE);
this.in_active_close = false;

View file

@ -33,7 +33,8 @@ export function FetchNetworkAdapter(bus, config)
this.dns_method = config.dns_method || "static";
this.doh_server = config.doh_server;
this.tcp_conn = {};
this.eth_encoder_buf = create_eth_encoder_buf();
this.mtu = config.mtu;
this.eth_encoder_buf = create_eth_encoder_buf(this.mtu);
this.fetch = (...args) => fetch(...args);
// Ex: 'https://corsproxy.io/?'
@ -55,9 +56,8 @@ FetchNetworkAdapter.prototype.destroy = function()
FetchNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
{
if(packet.tcp.dport === 80) {
let conn = new TCPConnection();
let conn = new TCPConnection(this);
conn.state = TCP_STATE_SYN_RECEIVED;
conn.net = this;
conn.on("data", on_data_http);
conn.tuple = tuple;
conn.accept(packet);

View file

@ -2096,6 +2096,7 @@ function start_emulation(profile, query_args)
settings.relay_url = query_args.get("relay_url");
settings.disable_jit = bool_arg(query_args.get("disable_jit"));
settings.disable_audio = bool_arg(query_args.get("mute"));
settings.mtu = parseInt(query_args.get("mtu"), 10) || undefined;
}
if(!settings.relay_url)
@ -2255,7 +2256,8 @@ function start_emulation(profile, query_args)
net_device: {
type: settings.net_device_type || "ne2k",
relay_url: settings.relay_url,
cors_proxy: settings.cors_proxy
cors_proxy: settings.cors_proxy,
mtu: settings.mtu
},
autostart: true,

View file

@ -36,8 +36,9 @@ export function WispNetworkAdapter(wisp_url, bus, config)
this.dns_method = config.dns_method || "doh";
this.doh_server = config.doh_server;
this.tcp_conn = {};
this.eth_encoder_buf = create_eth_encoder_buf();
this.mtu = config.mtu;
this.eth_encoder_buf = create_eth_encoder_buf(this.mtu);
this.bus.register("net" + this.id + "-mac", function(mac) {
this.vm_mac = new Uint8Array(mac.split(":").map(function(x) { return parseInt(x, 16); }));
}, this);
@ -190,9 +191,8 @@ WispNetworkAdapter.prototype.destroy = function()
*/
WispNetworkAdapter.prototype.on_tcp_connection = function(packet, tuple)
{
let conn = new TCPConnection();
let conn = new TCPConnection(this);
conn.state = TCP_STATE_SYN_RECEIVED;
conn.net = this;
conn.tuple = tuple;
conn.stream_id = this.last_stream++;
this.tcp_conn[tuple] = conn;

View file

@ -1210,7 +1210,7 @@ CPU.prototype.init = function(settings, device_bus)
}
else if(settings.net_device.type === "virtio")
{
this.devices.virtio_net = new VirtioNet(this, device_bus, settings.preserve_mac_from_state_image);
this.devices.virtio_net = new VirtioNet(this, device_bus, settings.preserve_mac_from_state_image, settings.net_device.mtu);
}
if(settings.fs9p)

View file

@ -24,8 +24,9 @@ const VIRTIO_NET_CTRL_MAC_ADDR_SET = 1;
* @param {CPU} cpu
* @param {BusConnector} bus
* @param {Boolean} preserve_mac_from_state_image
* @param {Number} mtu
*/
export function VirtioNet(cpu, bus, preserve_mac_from_state_image)
export function VirtioNet(cpu, bus, preserve_mac_from_state_image, mtu = 1500)
{
/** @const @type {BusConnector} */
this.bus = bus;
@ -177,7 +178,7 @@ export function VirtioNet(cpu, bus, preserve_mac_from_state_image)
{
bytes: 2,
name: "mtu",
read: () => 1500,
read: () => mtu,
write: data => {},
}
])

1
v86.d.ts vendored
View file

@ -333,6 +333,7 @@ export interface V86Options {
dns_method?: "static" | "doh";
doh_server?: string;
cors_proxy?: string;
mtu?: number;
};
}