|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ネットワークのホストデバイス
9: //
10:
11: // ログ名
12: // Ethernet HostDevice NetDriver
13: // | | |
14: // v v v
15: // Lance -> HostNetDevice -> NetDriver***
1.1.1.3 root 16: // 表示名 (Lance) (HostNet0) (HostNet0.***)
17: // 識別名 "lance" "hostnet0" "hostnet0"
1.1 root 18: //
1.1.1.3 root 19: // HostNet は、特に NetDriver 派生クラス選択時はフォールバックも含めて
20: // どれが選択されるか複雑なこともあるので、ログ表示名に自分のドライバ名
1.1 root 21: // も表示したい。
22:
23: #include "hostnet.h"
24: #include "config.h"
25: #include "netdriver_none.h"
26: #if defined(HAVE_HOSTNET_AFPACKET)
27: #include "netdriver_afpacket.h"
28: #endif
29: #if defined(HAVE_HOSTNET_BPF)
30: #include "netdriver_bpf.h"
31: #endif
32: #if defined(HAVE_HOSTNET_TAP)
33: #include "netdriver_tap.h"
34: #endif
1.1.1.4 ! root 35: #include <zlib.h>
1.1 root 36:
37: // コンパイル済みのドライバ名一覧を返す (MainApp から呼ばれる)
38: /*static*/ std::vector<std::string>
39: HostNetDevice::GetDrivers()
40: {
41: std::vector<std::string> list;
42:
43: #if defined(HAVE_HOSTNET_AFPACKET)
44: list.emplace_back("afpacket");
45: #endif
46: #if defined(HAVE_HOSTNET_BPF)
47: list.emplace_back("bpf");
48: #endif
49: #if defined(HAVE_HOSTNET_TAP)
50: list.emplace_back("tap");
51: #endif
52:
53: return list;
54: }
55:
56:
57: // コンストラクタ
1.1.1.3 root 58: HostNetDevice::HostNetDevice(Device *parent_, int n)
59: : inherited(parent_, OBJ_HOSTNET(n))
1.1 root 60: {
61: monitor.func = ToMonitorCallback(&HostNetDevice::MonitorUpdate);
1.1.1.4 ! root 62: monitor.SetSize(48, 22);
1.1.1.3 root 63: monitor.Regist(ID_MONITOR_HOSTNET(n));
1.1 root 64: }
65:
66: // デストラクタ
67: HostNetDevice::~HostNetDevice()
68: {
69: }
70:
71: // ログレベル設定
72: void
73: HostNetDevice::SetLogLevel(int loglevel_)
74: {
75: inherited::SetLogLevel(loglevel_);
76:
77: if ((bool)driver) {
78: driver->SetLogLevel(loglevel_);
79: }
80: }
81:
82: // 初期化
83: bool
84: HostNetDevice::Init()
85: {
86: if (inherited::Init() == false) {
87: return false;
88: }
89:
90: if (SelectDriver() == false) {
91: return false;
92: }
93:
94: return true;
95: }
96:
97: // ドライバ(再)選択
98: bool
99: HostNetDevice::SelectDriver()
100: {
1.1.1.3 root 101: int n = GetId() - OBJ_HOSTNET0;
102: const std::string key_driver = string_format("hostnet%d-driver", n);
103: const std::string key_fallback = string_format("hostnet%d-fallback", n);
104: const ConfigItem& item = gConfig->Find(key_driver);
1.1 root 105: const std::string& type = item.AsString();
1.1.1.3 root 106: bool fallback = gConfig->Find(key_fallback).AsInt();
1.1 root 107:
108: driver.reset();
109:
110: if (type != "none") {
111: if (type == "tap") {
112: #if defined(HAVE_HOSTNET_TAP)
113: CreateTap();
114: #else
1.1.1.2 root 115: item.Err("Hostnet driver %s not compiled", type.c_str());
1.1 root 116: #endif
117:
118: } else if (type == "bpf") {
119: #if defined(HAVE_HOSTNET_BPF)
120: CreateBPF();
121: #else
1.1.1.2 root 122: item.Err("Hostnet driver %s not compiled", type.c_str());
1.1 root 123: #endif
124:
125: } else if (type == "afpacket") {
126: #if defined(HAVE_HOSTNET_AFPACKET)
127: CreateAFPacket();
128: #else
1.1.1.2 root 129: item.Err("Hostnet driver %s not compiled", type.c_str());
1.1 root 130: #endif
131:
132: } else if (type == "auto") {
133: // auto なら Tap -> { BPF, AFPacket } の順で試す。
134: //
135: // Tap は事前の準備が面倒だが制約がない。
136: // BPF, AFPacket (この2つは OS の違いだけでほぼ同じもの) は
137: // 準備に手間がかからないが自ホストと通信できない制約がある。
138: // そのためどの環境でも Tap が使えれば Tap を、そうでなければ
139: // BPF, AFPacket を使う、という順にしておく。
140: bool r;
141:
142: r = CreateTap();
143: if (r == false) {
144: r = CreateAFPacket();
145: }
146: if (r == false) {
147: r = CreateBPF();
148: }
149:
150: } else {
151: // 知らないドライバ種別
152: item.Err();
153: }
154:
155: if ((bool)driver == false) {
156: putmsg(1, "hostnet-fallback=%d", fallback ? 1 : 0);
157:
158: if (fallback == false) {
159: // フォールバックしないならエラー終了
160: errmsg = "No host network driver found";
161: putmsg(1, "%s", errmsg.c_str());
162: warnx("%s (See details with options -C -Lhostnet=1)",
163: errmsg.c_str());
164:
165: return false;
166: }
167: }
168: }
169:
170: if ((bool)driver == false) {
171: CreateNone();
172: }
173: assert((bool)driver);
174:
175: // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
176: putmsg(1, "selected host driver: %s",
177: string_tolower(driver->GetDriverName()).c_str());
178:
179: return true;
180: }
181:
182: // None ドライバを生成する
183: bool
184: HostNetDevice::CreateNone()
185: {
186: driver.reset(new NetDriverNone(this));
187: if ((bool)driver) {
188: if (driver->InitDriver()) {
189: // 成功
190: return true;
191: }
192: errmsg = driver->errmsg;
193: driver.reset();
194: }
195: return false;
196: }
197:
198: // Tap ドライバを生成する
199: bool
200: HostNetDevice::CreateTap()
201: {
202: #if defined(HAVE_HOSTNET_TAP)
1.1.1.3 root 203: int n = GetId() - OBJ_HOSTNET0;
204: const std::string keyname = string_format("hostnet%d-tap-devpath", n);
205: const ConfigItem& item = gConfig->Find(keyname);
1.1 root 206: const std::string& devpath = item.AsString();
207:
208: driver.reset(new NetDriverTap(this, devpath));
209: if ((bool)driver) {
210: if (driver->InitDriver()) {
211: // 成功
212: return true;
213: }
214: errmsg = driver->errmsg;
215: driver.reset();
216: }
217: #endif
218: return false;
219: }
220:
221: // bpf ドライバを生成する
222: bool
223: HostNetDevice::CreateBPF()
224: {
225: #if defined(HAVE_HOSTNET_BPF)
1.1.1.3 root 226: int n = GetId() - OBJ_HOSTNET0;
227: const std::string keyname = string_format("hostnet%d-bpf-ifname", n);
228: const ConfigItem& item = gConfig->Find(keyname);
1.1 root 229: const std::string& ifname = item.AsString();
230:
231: driver.reset(new NetDriverBPF(this, ifname));
232: if ((bool)driver) {
233: if (driver->InitDriver()) {
234: // 成功
235: return true;
236: }
237: errmsg = driver->errmsg;
238: driver.reset();
239: }
240: #endif
241: return false;
242: }
243:
244: // AFPacket ドライバを生成する
245: bool
246: HostNetDevice::CreateAFPacket()
247: {
248: #if defined(HAVE_HOSTNET_AFPACKET)
1.1.1.3 root 249: int n = GetId() - OBJ_HOSTNET0;
250: const std::string keyname = string_format("hostnet%d-afpacket-ifname", n);
251: const ConfigItem& item = gConfig->Find(keyname);
1.1 root 252: const std::string& ifname = item.AsString();
253:
254: driver.reset(new NetDriverAFPacket(this, ifname));
255: if ((bool)driver) {
256: if (driver->InitDriver()) {
257: // 成功
258: return true;
259: }
260: errmsg = driver->errmsg;
261: driver.reset();
262: }
263: #endif
264: return false;
265: }
266:
267: // VM からの送信 (VM スレッドで呼ばれる)
268: bool
269: HostNetDevice::Tx(const NetPacket& packet)
270: {
271: // 送信キューに入れて..
272: if (txq.Enqueue(packet) == false) {
273: stat.txqfull_pkts++;
274: stat.txqfull_bytes += packet.length;
275: putlog(2, "txq exhausted");
276: return false;
277: }
278:
279: stat.tx_pkts++;
280: stat.tx_bytes += packet.length;
281:
282: // ざっくりピーク値
283: stat.txq_peak = std::max((int)txq.Length(), stat.txq_peak);
284:
285: // パイプに通知 (値はダミー)
286: return WritePipe(0);
287: }
288:
289: // rxq への投入を行う場合は true
290: void
291: HostNetDevice::EnableRx(bool enable)
292: {
293: rx_enable = enable;
294: }
295:
1.1.1.3 root 296: // 受信用の自身の MAC アドレスを設定する。
1.1 root 297: void
298: HostNetDevice::SetMyAddr(const macaddr_t& myaddr_)
299: {
300: myaddr = myaddr_;
301: }
302:
1.1.1.4 ! root 303: // マルチキャストフィルタを設定する。
! 304: void
! 305: HostNetDevice::SetMCastFilter(uint64 filter_)
! 306: {
! 307: multicast_filter = filter_;
! 308: }
! 309:
1.1 root 310: // プロミスキャスモードを設定する。
311: void
312: HostNetDevice::SetPromisc(bool promisc_)
313: {
314: promisc = promisc_;
315: }
316:
317: // パケットをキューから取り出す。
318: // VM 側から呼ばれる。
319: bool
320: HostNetDevice::Rx(NetPacket *dst)
321: {
322: if (rxq.Dequeue(dst) == false) {
323: // キューが空
324: return false;
325: }
326: stat.rx_pkts++;
327: stat.rx_bytes += dst->length;
1.1.1.3 root 328: if (__predict_false(loglevel >= 2)) {
329: putlogn("Recv %d bytes", dst->length);
330: if (loglevel >= 3) {
331: std::string buf;
332: for (int i = 0; i < dst->length; i++) {
333: if (i % 16 == 0) {
334: buf += string_format("%04x:", i);
335: }
336: buf += string_format(" %02x", (*dst)[i]);
337: if (i % 16 == 7) {
338: buf += " ";
339: } else if (i % 16 == 15) {
340: putlogn("%s", buf.c_str());
341: buf = "";
342: }
343: }
344: if (buf.empty() == false) {
345: putlogn("%s", buf.c_str());
346: }
347: }
348: }
1.1 root 349:
350: return true;
351: }
352:
353: // 外部からの読み込み (パケットを受信)。
354: // 戻り値はキューに投入したパケット数。
355: int
356: HostNetDevice::Read()
357: {
358: int queued = 0;
359: int left = 0;
360:
361: assert((bool)driver);
362:
363: do {
364: NetPacket *p;
365:
366: p = rxq.BeginWrite();
367: if (p == NULL) {
368: NetPacket discard;
369: left = driver->Read(&discard);
370: if (left < 0) {
371: break;
372: }
373: stat.rxqfull_pkts++;
374: stat.rxqfull_bytes += discard.length;
375: continue;
376: }
377:
378: // driver->Read() は VM に投入すべきパケットがなければ負数を返す。
379: // パケットがあれば p に書き戻して、driver 側のバッファに残っている
380: // パケット数 (といっても 0 か 1以上) を返してくる。
381: left = driver->Read(p);
382: if (left < 0) {
383: rxq.CancelWrite();
384: break;
385: }
386:
387: NetPacket& packet = *p;
388:
389: stat.read_pkts++;
390: stat.read_bytes += packet.length;
391:
392: if (rx_enable == false) {
393: rxq.CancelWrite();
394: stat.rxdisable_pkts++;
395: stat.rxdisable_bytes += packet.length;
396: continue;
397: }
398:
399: // イーサネットフレームより長いパケットはゲスト OS が期待していない。
400: // ここでドロップしてみる。
401: // これによりゲストでの dropping chained buffer が出なくなる。
402: if (packet.length > 1518) {
403: rxq.CancelWrite();
404: stat.rxjumbo_pkts++;
405: stat.rxjumbo_bytes += packet.length;
406: continue;
407: }
408:
409: // ホストカーネルから直接着信したパケット(というかフレームか)は
410: // 60バイトパディングされないまま読み出せるので、ここでパディングする。
411: while (packet.length < 60) {
412: packet.Append(0x00);
413: }
414:
415: // パケットフィルタリング
416: if (__predict_true(promisc == false)) {
1.1.1.4 ! root 417: static std::array<uint8, 6> bcast {
! 418: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
! 419: };
! 420: if (memcmp(&packet[0], &bcast[0], bcast.size()) == 0) {
! 421: // ブロードキャストは素通し。
! 422: } else if (__predict_false(packet[0] & 1)) {
! 423: // マルチキャスト。
1.1 root 424: // LANCE では LADRF レジスタ、NE2000 では MAR0-7 レジスタで
1.1.1.4 ! root 425: // データシートを見る限りはロジックは同じもののようだ。
1.1 root 426:
1.1.1.4 ! root 427: // 宛先アドレスの CRC32 を計算する。
! 428: // イーサネットの CRC は zlib の crc32() と同じもの。
! 429: ulong crc = crc32(0, Z_NULL, 0);
! 430: crc = crc32(crc, &packet[0], 6);
! 431:
! 432: // crc の上位6ビットをとりだして検査ビット位置とする(=pos)。
! 433: // multicast_filter の pos の位置のビットが 1 なら受信、
! 434: // 0 なら破棄。
! 435: // multicast_filter は64ビットで LSB が0番目、MSB が63番目
! 436: // としたもの (NIC 側でこの通りに並べ替えて渡してある)。
! 437: uint pos = (crc >> 26) & 0x3f;
! 438: uint64 bit = 1U << pos;
1.1 root 439: if ((multicast_filter & bit) == 0) {
1.1.1.4 ! root 440: putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d drop",
! 441: packet[0], packet[1], packet[2],
! 442: packet[3], packet[4], packet[5], pos);
! 443: stat.rxmcast_pkts++;
! 444: stat.rxmcast_bytes += packet.length;
! 445: rxq.CancelWrite();
! 446: continue;
1.1 root 447: }
1.1.1.4 ! root 448: putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d pass",
! 449: packet[0], packet[1], packet[2],
! 450: packet[3], packet[4], packet[5], pos);
1.1 root 451: } else {
452: // ユニキャスト
453: if (memcmp(&packet[0], &myaddr[0], 6) != 0) {
1.1.1.4 ! root 454: stat.rxnotme_pkts++;
! 455: stat.rxnotme_bytes += packet.length;
! 456: rxq.CancelWrite();
! 457: continue;
1.1 root 458: }
459: }
460: }
461:
462: // CRC XXX 計算すること
463: for (int i = 0; i < 4; i++) {
464: packet.Append(0x00);
465: }
466:
467: rxq.EndWrite();
468: queued++;
469: } while (left > 0);
470:
471: // ざっくりピーク値
472: stat.rxq_peak = std::max((int)rxq.Length(), stat.rxq_peak);
473:
474: return queued;
475: }
476:
477: // 外部への書き出し(パケットを送信)
478: void
479: HostNetDevice::Write(uint32 data)
480: {
481: const NetPacket *p;
482:
483: assert((bool)driver);
484:
485: // 送信キューから取り出す
486: while ((p = txq.BeginRead()) != NULL) {
487: const NetPacket& packet = *p;
488:
1.1.1.3 root 489: if (__predict_false(loglevel >= 2)) {
490: putlogn("Send %d bytes", packet.length);
491: if (loglevel >= 3) {
492: std::string buf;
493: for (int i = 0; i < packet.length; i++) {
494: if (i % 16 == 0) {
495: buf += string_format("%04x:", i);
496: }
497: buf += string_format(" %02x", packet[i]);
498: if (i % 16 == 7) {
499: buf += " ";
500: } else if (i % 16 == 15) {
501: putlogn("%s", buf.c_str());
502: buf = "";
503: }
504: }
505: if (buf.empty() == false) {
506: putlogn("%s", buf.c_str());
507: }
508: }
509: }
1.1 root 510: stat.write_pkts++;
511: stat.write_bytes += packet.length;
512:
513: driver->Write(packet.data(), packet.length);
514: txq.EndRead();
515: }
516: }
517:
518: // ドライバ名を返す
519: const std::string
520: HostNetDevice::GetDriverName() const
521: {
522: assert((bool)driver);
523: return driver->GetDriverName();
524: }
525:
526: // モニタ
527: void
528: HostNetDevice::MonitorUpdate(Monitor *, TextScreen& screen)
529: {
530: screen.Clear();
531:
1.1.1.3 root 532: screen.Print(0, 0, "Parent Device : %s", parent->GetName().c_str());
533: screen.Print(0, 1, "HostNet Driver: %s", driver->GetDriverName());
1.1 root 534: // 次の2行はドライバ依存情報
1.1.1.3 root 535: driver->MonitorUpdateMD(screen, 2);
1.1 root 536:
537: // 01234567890123456
538: // Write to host
539: // Drop:TxQ Full
540: // Drop:Rx Disabled
541: // Drop:Jumbo Frame
542: // Drop:Addr Filter
543:
1.1.1.3 root 544: int y = 5;
1.1 root 545: screen.Print(0, y++, "%-17s%13s %17s", "<Tx>", "Packets", "Bytes");
546: screen.Print(0, y++, "%-17s%13s %17s", "VM sends",
547: format_number(stat.tx_pkts).c_str(),
548: format_number(stat.tx_bytes).c_str());
549: screen.Print(0, y++, "%-17s%13s %17s", "Write to host",
550: format_number(stat.write_pkts).c_str(),
551: format_number(stat.write_bytes).c_str());
552: screen.Print(0, y++, "%-17s%13s %17s", "Drop:TxQ Full",
553: format_number(stat.txqfull_pkts).c_str(),
554: format_number(stat.txqfull_bytes).c_str());
555: y++;
556:
557: screen.Print(0, y++, "%-17s%13s %17s", "<Rx>", "Packets", "Bytes");
558: screen.Print(0, y++, "%-17s%13s %17s", "Read from host",
559: format_number(stat.read_pkts).c_str(),
560: format_number(stat.read_bytes).c_str());
561: screen.Print(0, y++, "%-17s%13s %17s", "VM receives",
562: format_number(stat.rx_pkts).c_str(),
563: format_number(stat.rx_bytes).c_str());
564: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Rx Disabled",
565: format_number(stat.rxdisable_pkts).c_str(),
566: format_number(stat.rxdisable_bytes).c_str());
567: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Jumbo Frame",
568: format_number(stat.rxjumbo_pkts).c_str(),
569: format_number(stat.rxjumbo_bytes).c_str());
570: screen.Print(0, y++, "%-17s%13s %17s", "Drop:RxQ Full",
571: format_number(stat.rxqfull_pkts).c_str(),
572: format_number(stat.rxqfull_bytes).c_str());
1.1.1.4 ! root 573: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unicast",
! 574: format_number(stat.rxnotme_pkts).c_str(),
! 575: format_number(stat.rxnotme_bytes).c_str());
! 576: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Multicast",
! 577: format_number(stat.rxmcast_pkts).c_str(),
! 578: format_number(stat.rxmcast_bytes).c_str());
1.1 root 579: y++;
580:
581: screen.Print(5, y++, "Capacity Peak");
582: screen.Print(0, y++, "TxQ %4d/%4d %4d",
583: (int)txq.Length(), (int)txq.Capacity(), stat.txq_peak);
584: screen.Print(0, y++, "RxQ %4d/%4d %4d",
585: (int)rxq.Length(), (int)rxq.Capacity(), stat.rxq_peak);
586: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.