--- nono/host/hostnet.cpp 2026/04/29 17:05:11 1.1.1.1 +++ nono/host/hostnet.cpp 2026/04/29 17:05:34 1.1.1.6 @@ -13,16 +13,16 @@ // | | | // v v v // Lance -> HostNetDevice -> NetDriver*** -// 表示名 (Lance) (HostNet) (HostNet.***) -// 識別名 "lance" "hostnet" "hostnet" +// 表示名 (Lance) (HostNet0) (HostNet0.***) +// 識別名 "lance" "hostnet0" "hostnet0" // -// HostNet は 1VM あたり高々1つなので COMDriver のように同じインスタンス間で -// 互いを区別する必要がないのと、NetDriver 派生クラス選択時はフォールバックも -// 含めて、どれが選択されるか複雑なこともあるのでログ表示名に自分のドライバ名 +// HostNet は、特に NetDriver 派生クラス選択時はフォールバックも含めて +// どれが選択されるか複雑なこともあるので、ログ表示名に自分のドライバ名 // も表示したい。 #include "hostnet.h" #include "config.h" +#include "monitor.h" #include "netdriver_none.h" #if defined(HAVE_HOSTNET_AFPACKET) #include "netdriver_afpacket.h" @@ -33,6 +33,7 @@ #if defined(HAVE_HOSTNET_TAP) #include "netdriver_tap.h" #endif +#include // コンパイル済みのドライバ名一覧を返す (MainApp から呼ばれる) /*static*/ std::vector @@ -55,12 +56,12 @@ HostNetDevice::GetDrivers() // コンストラクタ -HostNetDevice::HostNetDevice() - : inherited("HostNet") +HostNetDevice::HostNetDevice(Device *parent_, uint n) + : inherited(parent_, OBJ_HOSTNET(n)) { - monitor.func = ToMonitorCallback(&HostNetDevice::MonitorUpdate); - monitor.SetSize(48, 20); - monitor.Regist(ID_MONITOR_HOSTNET); + monitor = gMonitorManager->Regist(ID_MONITOR_HOSTNET(n), this); + monitor->func = ToMonitorCallback(&HostNetDevice::MonitorUpdate); + monitor->SetSize(48, 23); } // デストラクタ @@ -98,9 +99,12 @@ HostNetDevice::Init() bool HostNetDevice::SelectDriver() { - const ConfigItem& item = gConfig->Find("hostnet-driver"); + int n = GetId() - OBJ_HOSTNET0; + const std::string key_driver = string_format("hostnet%d-driver", n); + const std::string key_fallback = string_format("hostnet%d-fallback", n); + const ConfigItem& item = gConfig->Find(key_driver); const std::string& type = item.AsString(); - bool fallback = gConfig->Find("hostnet-fallback").AsInt(); + bool fallback = gConfig->Find(key_fallback).AsInt(); driver.reset(); @@ -109,21 +113,21 @@ HostNetDevice::SelectDriver() #if defined(HAVE_HOSTNET_TAP) CreateTap(); #else - item.Err("hostnet driver %s not compiled", type.c_str()); + item.Err("Hostnet driver %s not compiled", type.c_str()); #endif } else if (type == "bpf") { #if defined(HAVE_HOSTNET_BPF) CreateBPF(); #else - item.Err("hostnet driver %s not compiled", type.c_str()); + item.Err("Hostnet driver %s not compiled", type.c_str()); #endif } else if (type == "afpacket") { #if defined(HAVE_HOSTNET_AFPACKET) CreateAFPacket(); #else - item.Err("hostnet driver %s not compiled", type.c_str()); + item.Err("Hostnet driver %s not compiled", type.c_str()); #endif } else if (type == "auto") { @@ -197,7 +201,9 @@ bool HostNetDevice::CreateTap() { #if defined(HAVE_HOSTNET_TAP) - const ConfigItem& item = gConfig->Find("hostnet-tap-devpath"); + int n = GetId() - OBJ_HOSTNET0; + const std::string keyname = string_format("hostnet%d-tap-devpath", n); + const ConfigItem& item = gConfig->Find(keyname); const std::string& devpath = item.AsString(); driver.reset(new NetDriverTap(this, devpath)); @@ -218,7 +224,9 @@ bool HostNetDevice::CreateBPF() { #if defined(HAVE_HOSTNET_BPF) - const ConfigItem& item = gConfig->Find("hostnet-bpf-ifname"); + int n = GetId() - OBJ_HOSTNET0; + const std::string keyname = string_format("hostnet%d-bpf-ifname", n); + const ConfigItem& item = gConfig->Find(keyname); const std::string& ifname = item.AsString(); driver.reset(new NetDriverBPF(this, ifname)); @@ -239,7 +247,9 @@ bool HostNetDevice::CreateAFPacket() { #if defined(HAVE_HOSTNET_AFPACKET) - const ConfigItem& item = gConfig->Find("hostnet-afpacket-ifname"); + int n = GetId() - OBJ_HOSTNET0; + const std::string keyname = string_format("hostnet%d-afpacket-ifname", n); + const ConfigItem& item = gConfig->Find(keyname); const std::string& ifname = item.AsString(); driver.reset(new NetDriverAFPacket(this, ifname)); @@ -259,6 +269,14 @@ HostNetDevice::CreateAFPacket() bool HostNetDevice::Tx(const NetPacket& packet) { + // 長さ 0 のパケットは破棄する。バグでもないと通常は起きない。 + // runt frame はどうするか? + if (packet.length < 1) { + stat.txzero_pkts++; + putlog(1, "Tx: drop empty packet"); + return true; + } + // 送信キューに入れて.. if (txq.Enqueue(packet) == false) { stat.txqfull_pkts++; @@ -271,26 +289,45 @@ HostNetDevice::Tx(const NetPacket& packe stat.tx_bytes += packet.length; // ざっくりピーク値 - stat.txq_peak = std::max((int)txq.Length(), stat.txq_peak); + stat.txq_peak = std::max((uint)txq.Length(), stat.txq_peak); // パイプに通知 (値はダミー) return WritePipe(0); } -// rxq への投入を行う場合は true +// rxq への投入を行う場合は true。 +// VM スレッドから呼ばれる。 void HostNetDevice::EnableRx(bool enable) { rx_enable = enable; + + // 受信を停止した時はキューに残っているのを破棄する。 + // (ゲスト再起動によるデバイスリセット時とか) + if (rx_enable == false) { + // 統計情報に足すためだけに一旦取り出す。 + NetPacket drop; + while (rxq.Dequeue(&drop)) { + stat.rxdisable_pkts++; + stat.rxdisable_bytes += drop.length; + } + } } -// 自身の MAC アドレスを設定する。 +// 受信用の自身の MAC アドレスを設定する。 void HostNetDevice::SetMyAddr(const macaddr_t& myaddr_) { myaddr = myaddr_; } +// マルチキャストフィルタを設定する。 +void +HostNetDevice::SetMCastFilter(uint64 filter_) +{ + multicast_filter = filter_; +} + // プロミスキャスモードを設定する。 void HostNetDevice::SetPromisc(bool promisc_) @@ -309,7 +346,27 @@ HostNetDevice::Rx(NetPacket *dst) } stat.rx_pkts++; stat.rx_bytes += dst->length; - putlog(2, "Recv %d bytes", dst->length); + if (__predict_false(loglevel >= 2)) { + putlogn("Recv %u bytes", dst->length); + if (loglevel >= 3) { + std::string buf; + for (uint i = 0; i < dst->length; i++) { + if (i % 16 == 0) { + buf += string_format("%04x:", i); + } + buf += string_format(" %02x", (*dst)[i]); + if (i % 16 == 7) { + buf += " "; + } else if (i % 16 == 15) { + putlogn("%s", buf.c_str()); + buf = ""; + } + } + if (buf.empty() == false) { + putlogn("%s", buf.c_str()); + } + } + } return true; } @@ -378,35 +435,49 @@ HostNetDevice::Read() // パケットフィルタリング if (__predict_true(promisc == false)) { - bool filter = false; - if (__predict_false(packet[0] & 1)) { - // マルチキャスト - // XXX いまのところ全部通す -#if 0 + static std::array bcast { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + if (memcmp(&packet[0], &bcast[0], bcast.size()) == 0) { + // ブロードキャストは素通し。 + } else if (__predict_false(packet[0] & 1)) { + // マルチキャスト。 // LANCE では LADRF レジスタ、NE2000 では MAR0-7 レジスタで - // データシートを見る限りはロジックは同じものに見える... + // データシートを見る限りはロジックは同じもののようだ。 - // 宛先アドレスの CRC32 を計算する - uint32 crc = ~crc32(~0U, &packet[0], 6); - // crc 上位 6bit をとりだして検査ビット位置とする - uint bit = 1 << (crc >> 26); - // LADRF,MAR の検査ビット位置が 1 ならば受信、0 ならば破棄 + // 宛先アドレスの CRC32 を計算する。 + // イーサネットの CRC は zlib の crc32() と同じもの。 + uint32 crc = crc32(0, Z_NULL, 0); + crc = crc32(crc, &packet[0], 6); + + // crc の上位6ビットをとりだして検査ビット位置とする(=pos)。 + // multicast_filter の pos の位置のビットが 1 なら受信、 + // 0 なら破棄。 + // multicast_filter は64ビットで LSB が0番目、MSB が63番目 + // としたもの (NIC 側でこの通りに並べ替えて渡してある)。 + uint pos = (crc >> 26) & 0x3f; + uint64 bit = 1U << pos; if ((multicast_filter & bit) == 0) { - filter = true; + putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d drop", + packet[0], packet[1], packet[2], + packet[3], packet[4], packet[5], pos); + stat.rxmcast_pkts++; + stat.rxmcast_bytes += packet.length; + rxq.CancelWrite(); + continue; } -#endif + putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d pass", + packet[0], packet[1], packet[2], + packet[3], packet[4], packet[5], pos); } else { // ユニキャスト if (memcmp(&packet[0], &myaddr[0], 6) != 0) { - filter = true; + stat.rxnotme_pkts++; + stat.rxnotme_bytes += packet.length; + rxq.CancelWrite(); + continue; } } - if (filter) { - stat.rxfilter_pkts++; - stat.rxfilter_bytes += packet.length; - rxq.CancelWrite(); - continue; - } } // CRC XXX 計算すること @@ -419,7 +490,7 @@ HostNetDevice::Read() } while (left > 0); // ざっくりピーク値 - stat.rxq_peak = std::max((int)rxq.Length(), stat.rxq_peak); + stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak); return queued; } @@ -436,7 +507,27 @@ HostNetDevice::Write(uint32 data) while ((p = txq.BeginRead()) != NULL) { const NetPacket& packet = *p; - putlog(2, "Send %d bytes", packet.length); + if (__predict_false(loglevel >= 2)) { + putlogn("Send %u bytes", packet.length); + if (loglevel >= 3) { + std::string buf; + for (uint i = 0; i < packet.length; i++) { + if (i % 16 == 0) { + buf += string_format("%04x:", i); + } + buf += string_format(" %02x", packet[i]); + if (i % 16 == 7) { + buf += " "; + } else if (i % 16 == 15) { + putlogn("%s", buf.c_str()); + buf = ""; + } + } + if (buf.empty() == false) { + putlogn("%s", buf.c_str()); + } + } + } stat.write_pkts++; stat.write_bytes += packet.length; @@ -459,9 +550,10 @@ HostNetDevice::MonitorUpdate(Monitor *, { screen.Clear(); - screen.Print(0, 0, "HostNet Driver: %s", driver->GetDriverName()); + screen.Print(0, 0, "Parent Device : %s", parent->GetName().c_str()); + screen.Print(0, 1, "HostNet Driver: %s", driver->GetDriverName()); // 次の2行はドライバ依存情報 - driver->MonitorUpdateMD(screen); + driver->MonitorUpdateMD(screen, 2); // 01234567890123456 // Write to host @@ -470,7 +562,7 @@ HostNetDevice::MonitorUpdate(Monitor *, // Drop:Jumbo Frame // Drop:Addr Filter - int y = 4; + int y = 5; screen.Print(0, y++, "%-17s%13s %17s", "", "Packets", "Bytes"); screen.Print(0, y++, "%-17s%13s %17s", "VM sends", format_number(stat.tx_pkts).c_str(), @@ -478,6 +570,9 @@ HostNetDevice::MonitorUpdate(Monitor *, screen.Print(0, y++, "%-17s%13s %17s", "Write to host", format_number(stat.write_pkts).c_str(), format_number(stat.write_bytes).c_str()); + screen.Print(0, y++, "%-17s%13s %17s", "Drop:Empty Frame", + format_number(stat.txzero_pkts).c_str(), + "0"); screen.Print(0, y++, "%-17s%13s %17s", "Drop:TxQ Full", format_number(stat.txqfull_pkts).c_str(), format_number(stat.txqfull_bytes).c_str()); @@ -499,14 +594,17 @@ HostNetDevice::MonitorUpdate(Monitor *, screen.Print(0, y++, "%-17s%13s %17s", "Drop:RxQ Full", format_number(stat.rxqfull_pkts).c_str(), format_number(stat.rxqfull_bytes).c_str()); - screen.Print(0, y++, "%-17s%13s %17s", "Drop:Addr Filter", - format_number(stat.rxfilter_pkts).c_str(), - format_number(stat.rxfilter_bytes).c_str()); + screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unicast", + format_number(stat.rxnotme_pkts).c_str(), + format_number(stat.rxnotme_bytes).c_str()); + screen.Print(0, y++, "%-17s%13s %17s", "Drop:Multicast", + format_number(stat.rxmcast_pkts).c_str(), + format_number(stat.rxmcast_bytes).c_str()); y++; screen.Print(5, y++, "Capacity Peak"); - screen.Print(0, y++, "TxQ %4d/%4d %4d", - (int)txq.Length(), (int)txq.Capacity(), stat.txq_peak); - screen.Print(0, y++, "RxQ %4d/%4d %4d", - (int)rxq.Length(), (int)rxq.Capacity(), stat.rxq_peak); + screen.Print(0, y++, "TxQ %4u/%4u %4u", + (uint)txq.Length(), (uint)txq.Capacity(), stat.txq_peak); + screen.Print(0, y++, "RxQ %4u/%4u %4u", + (uint)rxq.Length(), (uint)rxq.Capacity(), stat.rxq_peak); }