Annotation of nono/host/hostnet.cpp, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.