--- nono/vm/virtio_net.cpp 2026/04/29 17:05:28 1.1.1.2 +++ nono/vm/virtio_net.cpp 2026/04/29 17:05:37 1.1.1.4 @@ -14,6 +14,7 @@ #include "ethernet.h" #include "macaddr.h" #include "memorystream.h" +#include "monitor.h" #include "scheduler.h" #include "syncer.h" @@ -39,8 +40,8 @@ VirtIONetDevice::VirtIONetDevice(uint sl AddAlias("Ethernet"); device_id = VirtIO::DEVICE_ID_NETWORK; - vqueues.emplace_back(0, "ReceiveQ1", 8); - vqueues.emplace_back(1, "TransmitQ1", 16); + vqueues.emplace_back(this, 0, "ReceiveQ1", 8); + vqueues.emplace_back(this, 1, "TransmitQ1", 16); // 割り込み名 strlcpy(intrname, "VIONet", sizeof(intrname)); @@ -53,9 +54,9 @@ VirtIONetDevice::VirtIONetDevice(uint sl vqlines += 7 + q.num_max; } - monitor.func = ToMonitorCallback(&VirtIONetDevice::MonitorUpdate); - monitor.SetSize(MONITOR_WIDTH, 3 + vqlines); - monitor.Regist(ID_MONITOR_VIRTIO_NET); + monitor = gMonitorManager->Regist(ID_MONITOR_VIRTIO_NET, this); + monitor->func = ToMonitorCallback(&VirtIONetDevice::MonitorUpdate); + monitor->SetSize(MONITOR_WIDTH, 3 + vqlines); } // デストラクタ @@ -92,13 +93,10 @@ VirtIONetDevice::Init() } // MAC アドレスを取得。 - macaddr_t macaddr; if (EthernetDevice::GetConfigMacAddr(0, &macaddr, false) == false) { // エラーメッセージ表示済み。 return false; } - // この先設定するタイミングがないのでここで設定する? - hostnet->SetMyAddr(macaddr); // 表示用。 macaddr_str = macaddr.ToString(':'); @@ -106,7 +104,7 @@ VirtIONetDevice::Init() VirtIONetConfigWriter cfg; SetDeviceFeatures(VIRTIO_NET_F_CSUM); SetDeviceFeatures(VIRTIO_NET_F_GUEST_CSUM); - SetDeviceFeatures(VIRTIO_NET_F_MTU), cfg.mac = macaddr; + SetDeviceFeatures(VIRTIO_NET_F_MTU), macaddr.ExportTo(&cfg.mac[0]); SetDeviceFeatures(VIRTIO_NET_F_MAC), cfg.mtu = 1500; SetDeviceFeatures(VIRTIO_NET_F_MRG_RXBUF); cfg.WriteTo(&device_config[0]); @@ -145,12 +143,18 @@ VirtIONetDevice::MonitorUpdate(Monitor * } } +// QUEUE_READY が変化したら呼ばれる。 void -VirtIONetDevice::QueueReady() +VirtIONetDevice::QueueReadyChanged(VirtQueue *q) { - if (vq->idx == 0) { - // ここで受信開始だろうか。 - hostnet->EnableRx(true); + if (q->idx == 0) { + // 受信開始/停止 + if (q->GetReady() != 0) { + hostnet->EnableRx(true); + } else { + scheduler->StopEvent(event); + hostnet->EnableRx(false); + } } } @@ -236,6 +240,12 @@ VirtIONetDevice::HostRxCallback() void VirtIONetDevice::RxMessage(MessageID msgid_, uint32 arg) { + VirtQueue *q = &vqueues[0]; + + if (__predict_false(q->GetReady() == 0)) { + return; + } + // 受信イベントが止まっていれば動かす。 // 受信イベントがすでに動いていれば、1パケット受信完了後に // ホストキューを確認するので、ここでは何もしなくてよい。 @@ -251,6 +261,10 @@ VirtIONetDevice::RxEvent(Event& ev) { VirtQueue *q = &vqueues[0]; + if (__predict_false(q->GetReady() == 0)) { + return; + } + // 空きディスクリプタがなければ、空くまでポーリングで待ち続ける。 uint16 avail_idx = ReadLE16(q->driver + 2); if (q->last_avail_idx == avail_idx) { @@ -332,6 +346,22 @@ VirtIONetDevice::Rx(VirtQueue *q) Done(q); } +// この宛先アドレスを受信するかどうか。 +// これは HostNet スレッドで呼ばれる。 +int +VirtIONetDevice::HWAddrFilter(const MacAddr& dstaddr) const +{ + if (dstaddr.IsUnicast()) { + if (dstaddr != macaddr) { + return HPF_DROP_UNICAST; + } + } + // マルチキャストをホストデバイス側でフィルタする機構は + // CTRLQ 内にあるが、NetBSD のドライバは CTRLQ を実装していない。 + + return HPF_PASS; +} + const char * VirtIONetDevice::GetFeatureName(uint feature) const {