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