|
|
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.5 ! root 58: HostNetDevice::HostNetDevice(Device *parent_, uint n)
1.1.1.3 root 59: : inherited(parent_, OBJ_HOSTNET(n))
1.1 root 60: {
61: monitor.func = ToMonitorCallback(&HostNetDevice::MonitorUpdate);
1.1.1.5 ! root 62: monitor.SetSize(48, 23);
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: {
1.1.1.5 ! root 271: // 長さ 0 のパケットは破棄する。バグでもないと通常は起きない。
! 272: // runt frame はどうするか?
! 273: if (packet.length < 1) {
! 274: stat.txzero_pkts++;
! 275: putlog(1, "Tx: drop empty packet");
! 276: return true;
! 277: }
! 278:
1.1 root 279: // 送信キューに入れて..
280: if (txq.Enqueue(packet) == false) {
281: stat.txqfull_pkts++;
282: stat.txqfull_bytes += packet.length;
283: putlog(2, "txq exhausted");
284: return false;
285: }
286:
287: stat.tx_pkts++;
288: stat.tx_bytes += packet.length;
289:
290: // ざっくりピーク値
1.1.1.5 ! root 291: stat.txq_peak = std::max((uint)txq.Length(), stat.txq_peak);
1.1 root 292:
293: // パイプに通知 (値はダミー)
294: return WritePipe(0);
295: }
296:
297: // rxq への投入を行う場合は true
298: void
299: HostNetDevice::EnableRx(bool enable)
300: {
301: rx_enable = enable;
302: }
303:
1.1.1.3 root 304: // 受信用の自身の MAC アドレスを設定する。
1.1 root 305: void
306: HostNetDevice::SetMyAddr(const macaddr_t& myaddr_)
307: {
308: myaddr = myaddr_;
309: }
310:
1.1.1.4 root 311: // マルチキャストフィルタを設定する。
312: void
313: HostNetDevice::SetMCastFilter(uint64 filter_)
314: {
315: multicast_filter = filter_;
316: }
317:
1.1 root 318: // プロミスキャスモードを設定する。
319: void
320: HostNetDevice::SetPromisc(bool promisc_)
321: {
322: promisc = promisc_;
323: }
324:
325: // パケットをキューから取り出す。
326: // VM 側から呼ばれる。
327: bool
328: HostNetDevice::Rx(NetPacket *dst)
329: {
330: if (rxq.Dequeue(dst) == false) {
331: // キューが空
332: return false;
333: }
334: stat.rx_pkts++;
335: stat.rx_bytes += dst->length;
1.1.1.3 root 336: if (__predict_false(loglevel >= 2)) {
1.1.1.5 ! root 337: putlogn("Recv %u bytes", dst->length);
1.1.1.3 root 338: if (loglevel >= 3) {
339: std::string buf;
1.1.1.5 ! root 340: for (uint i = 0; i < dst->length; i++) {
1.1.1.3 root 341: if (i % 16 == 0) {
342: buf += string_format("%04x:", i);
343: }
344: buf += string_format(" %02x", (*dst)[i]);
345: if (i % 16 == 7) {
346: buf += " ";
347: } else if (i % 16 == 15) {
348: putlogn("%s", buf.c_str());
349: buf = "";
350: }
351: }
352: if (buf.empty() == false) {
353: putlogn("%s", buf.c_str());
354: }
355: }
356: }
1.1 root 357:
358: return true;
359: }
360:
361: // 外部からの読み込み (パケットを受信)。
362: // 戻り値はキューに投入したパケット数。
363: int
364: HostNetDevice::Read()
365: {
366: int queued = 0;
367: int left = 0;
368:
369: assert((bool)driver);
370:
371: do {
372: NetPacket *p;
373:
374: p = rxq.BeginWrite();
375: if (p == NULL) {
376: NetPacket discard;
377: left = driver->Read(&discard);
378: if (left < 0) {
379: break;
380: }
381: stat.rxqfull_pkts++;
382: stat.rxqfull_bytes += discard.length;
383: continue;
384: }
385:
386: // driver->Read() は VM に投入すべきパケットがなければ負数を返す。
387: // パケットがあれば p に書き戻して、driver 側のバッファに残っている
388: // パケット数 (といっても 0 か 1以上) を返してくる。
389: left = driver->Read(p);
390: if (left < 0) {
391: rxq.CancelWrite();
392: break;
393: }
394:
395: NetPacket& packet = *p;
396:
397: stat.read_pkts++;
398: stat.read_bytes += packet.length;
399:
400: if (rx_enable == false) {
401: rxq.CancelWrite();
402: stat.rxdisable_pkts++;
403: stat.rxdisable_bytes += packet.length;
404: continue;
405: }
406:
407: // イーサネットフレームより長いパケットはゲスト OS が期待していない。
408: // ここでドロップしてみる。
409: // これによりゲストでの dropping chained buffer が出なくなる。
410: if (packet.length > 1518) {
411: rxq.CancelWrite();
412: stat.rxjumbo_pkts++;
413: stat.rxjumbo_bytes += packet.length;
414: continue;
415: }
416:
417: // ホストカーネルから直接着信したパケット(というかフレームか)は
418: // 60バイトパディングされないまま読み出せるので、ここでパディングする。
419: while (packet.length < 60) {
420: packet.Append(0x00);
421: }
422:
423: // パケットフィルタリング
424: if (__predict_true(promisc == false)) {
1.1.1.4 root 425: static std::array<uint8, 6> bcast {
426: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
427: };
428: if (memcmp(&packet[0], &bcast[0], bcast.size()) == 0) {
429: // ブロードキャストは素通し。
430: } else if (__predict_false(packet[0] & 1)) {
431: // マルチキャスト。
1.1 root 432: // LANCE では LADRF レジスタ、NE2000 では MAR0-7 レジスタで
1.1.1.4 root 433: // データシートを見る限りはロジックは同じもののようだ。
1.1 root 434:
1.1.1.4 root 435: // 宛先アドレスの CRC32 を計算する。
436: // イーサネットの CRC は zlib の crc32() と同じもの。
1.1.1.5 ! root 437: uint32 crc = crc32(0, Z_NULL, 0);
1.1.1.4 root 438: crc = crc32(crc, &packet[0], 6);
439:
440: // crc の上位6ビットをとりだして検査ビット位置とする(=pos)。
441: // multicast_filter の pos の位置のビットが 1 なら受信、
442: // 0 なら破棄。
443: // multicast_filter は64ビットで LSB が0番目、MSB が63番目
444: // としたもの (NIC 側でこの通りに並べ替えて渡してある)。
445: uint pos = (crc >> 26) & 0x3f;
446: uint64 bit = 1U << pos;
1.1 root 447: if ((multicast_filter & bit) == 0) {
1.1.1.4 root 448: putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d drop",
449: packet[0], packet[1], packet[2],
450: packet[3], packet[4], packet[5], pos);
451: stat.rxmcast_pkts++;
452: stat.rxmcast_bytes += packet.length;
453: rxq.CancelWrite();
454: continue;
1.1 root 455: }
1.1.1.4 root 456: putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d pass",
457: packet[0], packet[1], packet[2],
458: packet[3], packet[4], packet[5], pos);
1.1 root 459: } else {
460: // ユニキャスト
461: if (memcmp(&packet[0], &myaddr[0], 6) != 0) {
1.1.1.4 root 462: stat.rxnotme_pkts++;
463: stat.rxnotme_bytes += packet.length;
464: rxq.CancelWrite();
465: continue;
1.1 root 466: }
467: }
468: }
469:
470: // CRC XXX 計算すること
471: for (int i = 0; i < 4; i++) {
472: packet.Append(0x00);
473: }
474:
475: rxq.EndWrite();
476: queued++;
477: } while (left > 0);
478:
479: // ざっくりピーク値
1.1.1.5 ! root 480: stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak);
1.1 root 481:
482: return queued;
483: }
484:
485: // 外部への書き出し(パケットを送信)
486: void
487: HostNetDevice::Write(uint32 data)
488: {
489: const NetPacket *p;
490:
491: assert((bool)driver);
492:
493: // 送信キューから取り出す
494: while ((p = txq.BeginRead()) != NULL) {
495: const NetPacket& packet = *p;
496:
1.1.1.3 root 497: if (__predict_false(loglevel >= 2)) {
1.1.1.5 ! root 498: putlogn("Send %u bytes", packet.length);
1.1.1.3 root 499: if (loglevel >= 3) {
500: std::string buf;
1.1.1.5 ! root 501: for (uint i = 0; i < packet.length; i++) {
1.1.1.3 root 502: if (i % 16 == 0) {
503: buf += string_format("%04x:", i);
504: }
505: buf += string_format(" %02x", packet[i]);
506: if (i % 16 == 7) {
507: buf += " ";
508: } else if (i % 16 == 15) {
509: putlogn("%s", buf.c_str());
510: buf = "";
511: }
512: }
513: if (buf.empty() == false) {
514: putlogn("%s", buf.c_str());
515: }
516: }
517: }
1.1 root 518: stat.write_pkts++;
519: stat.write_bytes += packet.length;
520:
521: driver->Write(packet.data(), packet.length);
522: txq.EndRead();
523: }
524: }
525:
526: // ドライバ名を返す
527: const std::string
528: HostNetDevice::GetDriverName() const
529: {
530: assert((bool)driver);
531: return driver->GetDriverName();
532: }
533:
534: // モニタ
535: void
536: HostNetDevice::MonitorUpdate(Monitor *, TextScreen& screen)
537: {
538: screen.Clear();
539:
1.1.1.3 root 540: screen.Print(0, 0, "Parent Device : %s", parent->GetName().c_str());
541: screen.Print(0, 1, "HostNet Driver: %s", driver->GetDriverName());
1.1 root 542: // 次の2行はドライバ依存情報
1.1.1.3 root 543: driver->MonitorUpdateMD(screen, 2);
1.1 root 544:
545: // 01234567890123456
546: // Write to host
547: // Drop:TxQ Full
548: // Drop:Rx Disabled
549: // Drop:Jumbo Frame
550: // Drop:Addr Filter
551:
1.1.1.3 root 552: int y = 5;
1.1 root 553: screen.Print(0, y++, "%-17s%13s %17s", "<Tx>", "Packets", "Bytes");
554: screen.Print(0, y++, "%-17s%13s %17s", "VM sends",
555: format_number(stat.tx_pkts).c_str(),
556: format_number(stat.tx_bytes).c_str());
557: screen.Print(0, y++, "%-17s%13s %17s", "Write to host",
558: format_number(stat.write_pkts).c_str(),
559: format_number(stat.write_bytes).c_str());
1.1.1.5 ! root 560: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Empty Frame",
! 561: format_number(stat.txzero_pkts).c_str(),
! 562: "0");
1.1 root 563: screen.Print(0, y++, "%-17s%13s %17s", "Drop:TxQ Full",
564: format_number(stat.txqfull_pkts).c_str(),
565: format_number(stat.txqfull_bytes).c_str());
566: y++;
567:
568: screen.Print(0, y++, "%-17s%13s %17s", "<Rx>", "Packets", "Bytes");
569: screen.Print(0, y++, "%-17s%13s %17s", "Read from host",
570: format_number(stat.read_pkts).c_str(),
571: format_number(stat.read_bytes).c_str());
572: screen.Print(0, y++, "%-17s%13s %17s", "VM receives",
573: format_number(stat.rx_pkts).c_str(),
574: format_number(stat.rx_bytes).c_str());
575: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Rx Disabled",
576: format_number(stat.rxdisable_pkts).c_str(),
577: format_number(stat.rxdisable_bytes).c_str());
578: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Jumbo Frame",
579: format_number(stat.rxjumbo_pkts).c_str(),
580: format_number(stat.rxjumbo_bytes).c_str());
581: screen.Print(0, y++, "%-17s%13s %17s", "Drop:RxQ Full",
582: format_number(stat.rxqfull_pkts).c_str(),
583: format_number(stat.rxqfull_bytes).c_str());
1.1.1.4 root 584: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unicast",
585: format_number(stat.rxnotme_pkts).c_str(),
586: format_number(stat.rxnotme_bytes).c_str());
587: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Multicast",
588: format_number(stat.rxmcast_pkts).c_str(),
589: format_number(stat.rxmcast_bytes).c_str());
1.1 root 590: y++;
591:
592: screen.Print(5, y++, "Capacity Peak");
1.1.1.5 ! root 593: screen.Print(0, y++, "TxQ %4u/%4u %4u",
! 594: (uint)txq.Length(), (uint)txq.Capacity(), stat.txq_peak);
! 595: screen.Print(0, y++, "RxQ %4u/%4u %4u",
! 596: (uint)rxq.Length(), (uint)rxq.Capacity(), stat.rxq_peak);
1.1 root 597: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.