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