--- nono/vm/ethernet.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/vm/ethernet.cpp 2026/04/29 17:04:55 1.1.1.5 @@ -1,83 +1,38 @@ // // nono -// Copyright (C) 2019 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "configfile.h" #include "ethernet.h" -#include "netdriver_bpf.h" -#include "netdriver_tap.h" -#include "netdriver_none.h" +#include "config.h" +#include "netdriver_selector.h" #include -EthernetDevice *gEthernet; +std::unique_ptr gEthernet; // コンストラクタ -EthernetDevice::EthernetDevice() +EthernetDevice::EthernetDevice(const std::string& objname_) + : inherited(objname_) { } // デストラクタ EthernetDevice::~EthernetDevice() { - if (gNetDriver) { - delete gNetDriver; - gNetDriver = NULL; - } } // 動的なコンストラクション bool EthernetDevice::Create() { - const std::string key = "ethernet.hostdriver"; - const std::string type = gConfig->ReadStr(key, "none"); - if (type == "none") { - gNetDriver = new NetDriverNone(); - } else if (type == "tap") { -#if defined(NETDRIVER_TAP) - try { - gNetDriver = new NetDriverTap(this, &mtx, &cv); - } catch (...) { - warnx("Creating NetDriverTap failed"); - return false; - } -#else - gConfig->Err(key, "\"%s\" not supported", type.c_str()); - return false; -#endif - } else if (type == "bpf") { -#if defined(NETDRIVER_BPF) - try { - gNetDriver = new NetDriverBPF(this, &mtx, &cv); - } catch (...) { - warnx("Creating NetDriverBPF failed"); - return false; - } -#else - gConfig->Err(key, "\"%s\" not supported", type.c_str()); - return false; -#endif - } else { - gConfig->Err(key, "unknown \"%s\"", type.c_str()); - return false; - } - assert(gNetDriver); - - return true; -} - -// 初期化 -bool -EthernetDevice::Init() -{ - if (gNetDriver->Init() == false) { - delete gNetDriver; - gNetDriver = NULL; - return false; + try { + // ホストドライバをこのデバイスと紐付ける。 + gNetDriverSelector.reset(new NetDriverSelector(this)); + return true; + } catch (...) { } - - return true; + return false; } // MAC アドレスをてきとーに生成する。 @@ -139,5 +94,52 @@ EthernetDevice::ParseMacAddr(macaddr_t& bool EthernetDevice::SendPacket(const std::vector& buf) { + tx_pkts++; return gNetDriver->SendPacket(buf); } + +// パケット受信。 +// NetDriver スレッドから呼ばれる。 +// ロックは中で取るので、ロック解除状態で呼ぶこと。 +// XXX: 戻り値はなんだろう +bool +EthernetDevice::RecvPacket(RXPacket packet) +{ + 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; +}