--- nono/vm/ethernet.cpp 2026/04/29 17:04:55 1.1.1.5 +++ nono/vm/ethernet.cpp 2026/04/29 17:05:10 1.1.1.6 @@ -4,12 +4,16 @@ // Licensed under nono-license.txt // +// +// Ethernet 基本クラス +// + #include "ethernet.h" -#include "config.h" -#include "netdriver_selector.h" -#include +#include "hostnet.h" +#include "scheduler.h" -std::unique_ptr gEthernet; +// グローバル参照用 +EthernetDevice *gEthernet; // コンストラクタ EthernetDevice::EthernetDevice(const std::string& objname_) @@ -20,126 +24,29 @@ EthernetDevice::EthernetDevice(const std // デストラクタ EthernetDevice::~EthernetDevice() { + if ((bool)hostnet) { + hostnet->SetCallbackDevice(NULL); + } + gEthernet = NULL; } // 動的なコンストラクション bool EthernetDevice::Create() { - try { - // ホストドライバをこのデバイスと紐付ける。 - gNetDriverSelector.reset(new NetDriverSelector(this)); - return true; - } catch (...) { - } - return false; -} - -// MAC アドレスをてきとーに生成する。 -// 02:00:01 はローカルだし割り当てもされてなさそうなので使っちゃえ。 -// 下3バイトは乱数。 -/*static*/ void -EthernetDevice::GenerateMacAddr(macaddr_t *addrp) -{ - std::random_device rnd; - uint32 x = rnd(); - - macaddr_t& addr = *addrp; - addr[0] = 0x02; - addr[1] = 0x00; - addr[2] = 0x01; - addr[3] = (x >> 16) & 0xff; - addr[4] = (x >> 8) & 0xff; - addr[5] = x & 0xff; -} + // ホストドライバを作成してこのデバイスと紐付ける + hostnet.reset(new HostNetDevice()); -// MAC アドレス文字列をバイナリに変換して返す。 -// "HH:HH:HH:HH:HH:HH" 形式のみ。 -// 成功すれば true を返す。 -/*static*/ bool -EthernetDevice::ParseMacAddr(macaddr_t& dst, const std::string& src) -{ - const char *p; - char *e; + hostnet->SetRxCallback(ToDeviceCallback(&EthernetDevice::HostRxCallback)); + hostnet->SetCallbackDevice(this); - p = src.data(); - for (int i = 0; ; ) { - unsigned long val = strtoul(p, &e, 16); - - if (p == e) { - return false; - } - if (val > 0xff) { - return false; - } - dst[i++] = val; - p = e; - - // 最後だけ ':' をチェックしないので - if (i == 6) { - break; - } - - if (*p++ != ':') { - return false; - } - } - if (*p != '\0') { - return false; - } return true; } -// パケットを送信する (VM から呼ばれる) -bool -EthernetDevice::SendPacket(const std::vector& buf) -{ - tx_pkts++; - return gNetDriver->SendPacket(buf); -} - -// パケット受信。 -// NetDriver スレッドから呼ばれる。 -// ロックは中で取るので、ロック解除状態で呼ぶこと。 -// XXX: 戻り値はなんだろう -bool -EthernetDevice::RecvPacket(RXPacket packet) +// これは Host スレッドから呼ばれる +void +EthernetDevice::HostRxCallback() { - std::lock_guard lock(mtx); - - if (RecvEnabled == false) { - // 受信禁止状態 - putlog(2, "%s: receive disabled", __func__); - return true; - } - - // イーサネットフレームより長いパケットはゲスト OS が期待していない。 - // ここでドロップしてみる。 - // これによりゲストでの dropping chained buffer が出なくなる。 - // 1518(EthernetII) にするか 1522(802.1Q) にするかは未定。 - if (packet->size() > 1518) { - // TODO: 統計とりたい - putlog(1, "%s: drop long packet(%zd)", __func__, packet->size()); - return true; - } - - // XXX とりあえず 16 パケットをキューする。 - // 入り切らないときは捨てる。 - if (rxq.size() > 16) { - // 前のパケットをまだ処理中なので、このパケットは捨てる - putlog(1, "%s: discard %zd bytes, pending %zd packets", __func__, - packet->size(), rxq.size()); - return true; - } - putlog(1, "%s: enqueue %zd bytes, pending %zd packets", __func__, - packet->size(), rxq.size()); - - // キューへ投入 - rxq.push(std::move(packet)); - rx_pkts++; - - // 継承クラスに通知 - NotifyRecvPacket(); - - return true; + // スレッドを超えるためにメッセージを投げる + gScheduler->SendMessage(MessageID::HOSTNET_RX); }