|
|
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 {};
};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.