--- nono/vm/virtio_net.cpp 2026/04/29 17:05:37 1.1.1.4 +++ nono/vm/virtio_net.cpp 2026/04/29 17:05:46 1.1.1.6 @@ -16,7 +16,6 @@ #include "memorystream.h" #include "monitor.h" #include "scheduler.h" -#include "syncer.h" // デバイス構成レイアウト class VirtIONetConfigWriter @@ -64,7 +63,7 @@ VirtIONetDevice::~VirtIONetDevice() { // EthernetDevice と同じ…。 if ((bool)hostnet) { - hostnet->SetRxCallback(NULL); + hostnet->ResetRxCallback(); } } @@ -77,9 +76,16 @@ VirtIONetDevice::Create() } // EthernetDevice とほぼ同じ…。 - hostnet.reset(new HostNetDevice(this, 0)); + try { + hostnet.reset(new HostNetDevice(this, 0, "VirtIO Network")); + } catch (...) { } + if ((bool)hostnet == false) { + warnx("Failed to initialize HostNetDevice at %s", __method__); + return false; + } - hostnet->SetRxCallback(ToDeviceCallback(&VirtIONetDevice::HostRxCallback)); + auto func = ToDeviceCallback(&VirtIONetDevice::HostRxCallback); + hostnet->SetRxCallback(func, 0); return true; } @@ -185,7 +191,7 @@ VirtIONetDevice::ProcessDesc(VirtIOReq& num_buffers = ReqReadLE16(req); putlog(2, "req.hdr $%08x: flags=%02x gso=%02x hdr_len=%04x gso_size=%04x " "csum_start=%04x offset=%04x num=%04x", - req.buf[0].addr, + req.rbuf[0].addr, flags, gso_type, hdr_len, @@ -195,42 +201,16 @@ VirtIONetDevice::ProcessDesc(VirtIOReq& num_buffers); NetPacket tx_packet; - while (req.pos < req.len) { - tx_packet.Append(ReqReadU8(req)); - } - - // パフォーマンス測定用のギミック。 - // VirtIO-Net を特定のパケットが通過すると、 - // VM 電源オン時から現在までの実時間をログに出力する。NetBSD の - // マルチユーザブートがあらかた終わってログインプロンプトが出る手前の - // /etc/rc.local に - // - // ping6 -X 1 -c 1 ff02::db8:db8:9090%vioif0 > /dev/null 2>&1 & - // - // と書いておくことで、ここまでにかかる時間を表示できる。 - // この値はホスト性能に依存するため、同一環境下での相対比較のみ可能。 - // - // この宛先はリンクローカルマルチキャストでドキュメント用に予約されて - // いるアドレスなので厳密には出すべきではないかもだが、知らずに - // ドキュメント通りにやってみた人のために、ちゃんとしたネットワークなら - // 安全に廃棄しているはずなので、事故は少ないかと。 - // このマルチキャストアドレスに対する宛先 MAC アドレスは - // 33:33:0d:b8:90:90 になる。 - static const std::array perf_dstaddr { - 0x33, 0x33, 0x0d, 0xb8, 0x90, 0x90 - }; - if (__predict_true(tx_packet.length >= 6) && - __predict_false(memcmp(&tx_packet[0], &perf_dstaddr[0], 6) == 0)) - { - GetSyncer()->PutlogRealtime(); - } + uint32 len = std::min((uint32)tx_packet.size(), req.rremain()); + uint32 rest = ReqReadRegion(req, tx_packet.data(), len); + tx_packet.length = len - rest; hostnet->Tx(tx_packet); } // これは Host スレッドから呼ばれる void -VirtIONetDevice::HostRxCallback() +VirtIONetDevice::HostRxCallback(uint32 dummy) { // スレッドを超えるためにメッセージを投げる scheduler->SendMessage(MessageID::HOSTNET_RX(0)); @@ -318,27 +298,20 @@ VirtIONetDevice::Rx(VirtQueue *q) hdr.hdr_len = htole16(sizeof(hdr)); // num_buffers は実際に使ったセグメント数らしい。 uint nseg = 0; - for (; nseg < req.buf.size(); nseg++) { - if (req.buf[nseg].pos >= sizeof(hdr) + rx_packet.length) + uint32 len = 0; + for (; nseg < req.wbuf.size(); nseg++) { + len += req.wbuf[nseg].len; + if (len >= sizeof(hdr) + rx_packet.length) { break; + } } hdr.num_buffers = htole16(nseg); // ヘッダを書き込む。 - const uint8 *s = (const uint8 *)&hdr; - for (int i = 0; i < sizeof(hdr); i++) { - ReqWriteU8(req, *s++); - } + ReqWriteRegion(req, (const uint8 *)&hdr, sizeof(hdr)); // パケット本体を書き込む。 - for (int i = 0; i < rx_packet.length; i++) { - if (ReqWriteU8(req, rx_packet[i]) == false) { - // どうする? - putlog(0, "buffer too small: buflen=%u rx_packet=%u", - req.len, rx_packet.length); - break; - } - } + ReqWriteRegion(req, rx_packet.data(), rx_packet.length); CommitDesc(req);