File:  [Isaki's NoNo m68k/m88k emulator] / nono / host / hostnet.h
Revision 1.1.1.9 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:02 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// ネットワークのホストデバイス
//

#pragma once

#include "hostdevice.h"
#include "macaddr.h"
#include "netdriver.h"
#include "spscqueue.h"

// パケット。
class NetPacket
{
 public:
	NetPacket() {
		Clear();
	}

	// バッファをクリアする
	void Clear() {
		length = 0;
		readpos = 0;
	}

	// このパケットの内容を置き換える。
	void Assign(const void *src, uint srclen);

	// バッファサイズ (パケット長) を変更する。
	void Resize(uint newlength);

	// パケットに1バイト追加する
	void Append(uint8 data);

	// 読み出し開始位置を設定
	void Seek(size_t readpos_) { readpos = readpos_; }

	// バッファの先頭を返す。
	uint8 *Data() { return buf.data(); }
	const uint8 *Data() const { return buf.data(); }

	// パケットサイズを取得。
	// NetDriver で受信してから HostNet で破棄されるまでの間だけ
	// Length() が buf.size() を上回ることを許容する。
	// データは buf に収まる分だけ書いておくが、実際には Length バイトの
	// パケットだったことを示す。どのみち捨てられるのでデータが尻切れなことは
	// 気にしない。あわよくばモニタ上で長いパケットだと示唆できるかも知れない
	// という程度。
	uint Length() const { return length; }

	// 読み出しの残りバイト数を返す
	uint GetRemain() const { return Length() - readpos; }

	// 1バイト読み出す。EOP なら -1 を返す
	uint32 Read() {
		if (readpos < Length()) {
			return buf[readpos++];
		} else {
			return (uint32)-1;
		}
	}

	// ポインタを進めず指定の位置のデータを読み出す。
	// pos が不正なら -1 を返す。
	uint32 Peek(uint pos) const {
		if (pos < Length()) {
			return buf[pos];
		} else {
			return (uint32)-1;
		}
	}

 private:
	// 有効長
	uint length {};
	// 現在の読み出し位置
	uint readpos {};

	std::array<uint8, 1536> buf {};
};

// MAC アドレスフィルタ。
// VM 側デバイスはこれを多重継承して実装すること。
class IHWAddrFilter
{
	// インタフェース風にするため、メンバ変数を持たせないこと。
 public:
	enum {
		HPF_PASS = 0,		// このフレームを受信する。
		HPF_DROP_UNICAST,	// このユニキャストフレームを破棄する。
		HPF_DROP_MULTICAST,	// このマルチキャストフレームを破棄する。
	};

 public:
	virtual ~IHWAddrFilter();

	// デバイスがこの dstaddr 宛のフレームを受け付けるかどうかを返す。
	// デバイスは、自分宛て、ブロードキャスト、マルチキャスト
	// (おそらくハッシュ)、プロミスキャスなどの状態を考慮すること。
	virtual int HWAddrFilter(const MacAddr& dstaddr) const = 0;
};

class HostNetDevice : public HostDevice
{
	using inherited = HostDevice;
	using NetTxQueue = SPSCQueue<NetPacket, 32>;
	using NetRxQueue = SPSCQueue<NetPacket, 64>;

	// 統計情報
	struct stat_t {
		uint64 tx_pkts;
		uint64 tx_bytes;
		uint64 rx_pkts;
		uint64 rx_bytes;
		uint64 read_pkts;
		uint64 read_bytes;
		uint64 write_pkts;
		uint64 write_bytes;
		uint64 txzero_pkts;			// 送信長0で破棄したパケット数
		uint64 txunsupp_pkts;		// 送信先が未対応で破棄したパケット数
		uint64 txunsupp_bytes;		// 送信先が未対応で破棄したバイト数
		uint64 txqfull_pkts;		// キューが一杯だった回数
		uint64 txqfull_bytes;		// キューに入れられなかったバイト数
		uint64 rxdisable_pkts;		// 上位層が受信無効
		uint64 rxdisable_bytes;		// 上位層が受信無効
		uint64 rxjumbo_pkts;		// 受信したジャンボパケット数
		uint64 rxjumbo_bytes;		// 受信したジャンボパケットのバイト数
		uint64 rxqfull_pkts;		// キューが一杯だった回数
		uint64 rxqfull_bytes;		// キューに入れられなかったバイト数
		uint64 rxnotme_pkts;		// ユニキャストで破棄したパケット数
		uint64 rxnotme_bytes;		// フィルタされたバイト数
		uint64 rxmcast_pkts;		// マルチキャストで破棄したパケット数
		uint64 rxmcast_bytes;		// フィルタされたバイト数

		uint txq_peak;				// キューのおおよその最大使用量
		uint rxq_peak;				// キューのおおよその最大使用量
	};

 public:
	HostNetDevice(Device *parent_, uint n, const std::string& portname_);
	~HostNetDevice() override;

	void SetLogLevel(int loglevel_) override;
	bool Create2() override;

	// パケットを送信する。
	// data はプリアンブルを含まず、イーサネットフレームヘッダ(14バイト)、
	// データ(46-1500バイト) からなる。FCS(CRC) (4バイト) は含まない。
	// 送信キューに追加できれば true、出来なければ false を返す。
	bool Tx(const NetPacket& packet);

	// パケットを引き取るために VM から呼ばれる。
	// パケットが受信キューにあるときは packet にコピーして true を返す。
	// キューが空なら false を返す。
	bool Rx(NetPacket *packet);

	// 受信キューへの投入を許可/禁止する。
	void EnableRx(bool enable);

	// マルチキャストフィルタを設定する。
	void SetMCastFilter(uint64 filter);

	// ドライバ名を返す。
	const std::string& GetDriverName();

	// 統計情報を返す (ステータスパネルから呼ばれる)
	uint64 GetTXPkts() const { return stat.tx_pkts; }
	uint64 GetRXPkts() const { return stat.rx_pkts; }

	// 統計情報に1パケット分加算する (これだけ SLIRP の裏スレッドから呼ばれる)
	void CountTXUnsupp(size_t bytes);

	// コンパイル済みのドライバ名一覧を返す
	static std::vector<std::string> GetDrivers();

	// libslirp のバージョン文字列を返す
	static const char *GetSlirpVersion();

	// デバッグ用。
	static std::vector<std::string> DumpHex(const void *, size_t);
	static std::vector<std::string> DumpFrame(const void *, size_t);

 private:
	bool SelectDriver(bool startup) override;
	void CreateNone();
	void CreateSlirp(bool startup);
	void CreateTap();
	void CreateBPF();
	void CreateAFPacket();

	int Read() override;

	// 外部への書き出し(パケットを送信)
	void Write() override;

	DECLARE_MONITOR_SCREEN(MonitorScreen);

	// デバッグ用 (下請け)
	static std::vector<std::string> DumpARP(const void *, size_t);
	static std::vector<std::string> DumpIPv4(const void *, size_t);
	static std::vector<std::string> DumpICMPv4(const char *, const char *,
		const void *, size_t);
	static std::vector<std::string> DumpTCPv4(const char *, const char *,
		const void *, size_t);
	static std::vector<std::string> DumpUDPv4(const char *, const char *,
		const void *, size_t);
	static std::vector<std::string> DumpDHCP(const void *, size_t);
	static std::vector<std::string> DumpIPv6(const void *, size_t);
	static std::vector<std::string> DumpICMPv6(const char *, const char *,
		const void *, size_t);
	static std::string DumpDHCPAddrList(const uint8 *, size_t);
	static std::string GetServByPort(uint16 port_be, const char *protoname);

	std::unique_ptr<NetDriver> driver {};

	bool rx_enable {};

	// キュー
	NetTxQueue txq {};
	NetRxQueue rxq {};

	// 統計情報
	struct stat_t stat {};

	Monitor *monitor {};

	IHWAddrFilter *ihwaddrfilter {};
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.