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