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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // ネットワークのホストデバイス
                      9: //
                     10: 
1.1.1.7 ! root       11: // 送信時のフロー
        !            12: //
        !            13: // VM thread                :     Host thread
        !            14: //
        !            15: // 各デバイス::送信()       :
        !            16: //     |
        !            17: // HostNetDevice::Tx()      :   HostDevice::ThreadRun
        !            18: //     |
        !            19: //     +-------------->| queue |----+         … 送信キューに追加し
        !            20: //     +-------------->| pipe  |----+         … パイプでホストスレッドに通知
        !            21: //     |                            |
        !            22: //   <-+                    :       v
        !            23: //                                 --- kevent
        !            24: //                          :       |
        !            25: //                              HostNetDevice::Write()
        !            26: //                          :       |
        !            27: //                              NetDriver*::Write()
        !            28: //                          :       |
        !            29: //                                  +-----> Send to the real world
        !            30: 
        !            31: // 受信のフロー
        !            32: //
        !            33: // VM thread                :     Host thread
        !            34: //
        !            35: //                          :   HostDevice::ThreadRun
        !            36: //
        !            37: //                          :       +-----< Recv from the real world
        !            38: //                                  |
        !            39: //                          :       v
        !            40: //                                 --- kevent
        !            41: //                          :       |
        !            42: //                              HostNetDevice::Read()
        !            43: //                                  |
        !            44: //                     | queue |<---+         … 受信キューに追加
        !            45: //                         ‖
        !            46: //                         ‖    HostNetDevice::*(rx_func)()
        !            47: //                                  |
        !            48: //     +-------------| Message |<---+         … メッセージで VM スレッドに通知
        !            49: //     v
        !            50: // 各デバイス::RxMessage() ‖                 … メッセージコールバック
        !            51: //     |                   ‖
        !            52: // 各デバイス::Rx()        ‖                 … イベントコールバック
        !            53: //     |                   ‖
        !            54: // HostCOMDevice::Rx()  <==++                 … ここで queue から読み出す
        !            55: 
1.1       root       56: // ログ名
                     57: //       Ethernet    HostDevice       NetDriver
                     58: //         |          |                |
                     59: //         v          v                v
                     60: //        Lance   -> HostNetDevice -> NetDriver***
1.1.1.3   root       61: // 表示名 (Lance)    (HostNet0)      (HostNet0.***)
                     62: // 識別名 "lance"    "hostnet0"      "hostnet0"
1.1       root       63: //
1.1.1.3   root       64: // HostNet は、特に NetDriver 派生クラス選択時はフォールバックも含めて
                     65: // どれが選択されるか複雑なこともあるので、ログ表示名に自分のドライバ名
1.1       root       66: // も表示したい。
                     67: 
                     68: #include "hostnet.h"
                     69: #include "config.h"
1.1.1.6   root       70: #include "monitor.h"
1.1       root       71: #include "netdriver_none.h"
                     72: #if defined(HAVE_HOSTNET_AFPACKET)
                     73: #include "netdriver_afpacket.h"
                     74: #endif
                     75: #if defined(HAVE_HOSTNET_BPF)
                     76: #include "netdriver_bpf.h"
                     77: #endif
1.1.1.7 ! root       78: #if defined(HAVE_HOSTNET_SLIRP)
        !            79: #include "netdriver_slirp.h"
        !            80: #endif
1.1       root       81: #if defined(HAVE_HOSTNET_TAP)
                     82: #include "netdriver_tap.h"
                     83: #endif
1.1.1.7 ! root       84: #include <sys/socket.h>
        !            85: #include <netdb.h>
        !            86: #include <arpa/inet.h>
        !            87: #include <netinet/in.h>
1.1       root       88: 
                     89: // コンパイル済みのドライバ名一覧を返す (MainApp から呼ばれる)
                     90: /*static*/ std::vector<std::string>
                     91: HostNetDevice::GetDrivers()
                     92: {
                     93:        std::vector<std::string> list;
                     94: 
                     95: #if defined(HAVE_HOSTNET_AFPACKET)
                     96:        list.emplace_back("afpacket");
                     97: #endif
                     98: #if defined(HAVE_HOSTNET_BPF)
                     99:        list.emplace_back("bpf");
                    100: #endif
1.1.1.7 ! root      101: #if defined(HAVE_HOSTNET_SLIRP)
        !           102:        list.emplace_back("usermode");
        !           103: #endif
1.1       root      104: #if defined(HAVE_HOSTNET_TAP)
                    105:        list.emplace_back("tap");
                    106: #endif
                    107: 
                    108:        return list;
                    109: }
                    110: 
                    111: 
                    112: // コンストラクタ
1.1.1.5   root      113: HostNetDevice::HostNetDevice(Device *parent_, uint n)
1.1.1.3   root      114:        : inherited(parent_, OBJ_HOSTNET(n))
1.1       root      115: {
1.1.1.7 ! root      116:        ihwaddrfilter = dynamic_cast<IHWAddrFilter *>(parent);
        !           117:        assert(ihwaddrfilter);
        !           118: 
1.1.1.6   root      119:        monitor = gMonitorManager->Regist(ID_MONITOR_HOSTNET(n), this);
                    120:        monitor->func = ToMonitorCallback(&HostNetDevice::MonitorUpdate);
1.1.1.7 ! root      121:        monitor->SetSize(48, 24);
1.1       root      122: }
                    123: 
                    124: // デストラクタ
                    125: HostNetDevice::~HostNetDevice()
                    126: {
                    127: }
                    128: 
                    129: // ログレベル設定
                    130: void
                    131: HostNetDevice::SetLogLevel(int loglevel_)
                    132: {
                    133:        inherited::SetLogLevel(loglevel_);
                    134: 
                    135:        if ((bool)driver) {
                    136:                driver->SetLogLevel(loglevel_);
                    137:        }
                    138: }
                    139: 
1.1.1.7 ! root      140: // 動的コンストラクションその2
1.1       root      141: bool
1.1.1.7 ! root      142: HostNetDevice::Create2()
1.1       root      143: {
1.1.1.7 ! root      144:        if (inherited::Create2() == false) {
1.1       root      145:                return false;
                    146:        }
                    147: 
                    148:        if (SelectDriver() == false) {
                    149:                return false;
                    150:        }
                    151: 
                    152:        return true;
                    153: }
                    154: 
                    155: // ドライバ(再)選択
                    156: bool
                    157: HostNetDevice::SelectDriver()
                    158: {
1.1.1.3   root      159:        int n = GetId() - OBJ_HOSTNET0;
                    160:        const std::string key_driver = string_format("hostnet%d-driver", n);
                    161:        const std::string key_fallback = string_format("hostnet%d-fallback", n);
                    162:        const ConfigItem& item = gConfig->Find(key_driver);
1.1.1.7 ! root      163:        std::string type = item.AsString();
1.1.1.3   root      164:        bool fallback = gConfig->Find(key_fallback).AsInt();
1.1       root      165: 
                    166:        driver.reset();
                    167: 
1.1.1.7 ! root      168:        // auto は usermode か none と同義にする。
        !           169:        if (type == "auto") {
        !           170: #if defined(HAVE_HOSTNET_SLIRP)
        !           171:                type = "usermode";
        !           172: #else
        !           173:                type = "none";
        !           174: #endif
        !           175:        }
        !           176: 
1.1       root      177:        if (type != "none") {
1.1.1.7 ! root      178:                if (type == "usermode") {
        !           179: #if defined(HAVE_HOSTNET_SLIRP)
        !           180:                        CreateSlirp();
        !           181: #else
        !           182:                        item.Err("Hostnet driver %s not compiled", type.c_str());
        !           183: #endif
        !           184: 
        !           185:                } else if (type == "tap") {
1.1       root      186: #if defined(HAVE_HOSTNET_TAP)
                    187:                        CreateTap();
                    188: #else
1.1.1.2   root      189:                        item.Err("Hostnet driver %s not compiled", type.c_str());
1.1       root      190: #endif
                    191: 
                    192:                } else if (type == "bpf") {
                    193: #if defined(HAVE_HOSTNET_BPF)
                    194:                        CreateBPF();
                    195: #else
1.1.1.2   root      196:                        item.Err("Hostnet driver %s not compiled", type.c_str());
1.1       root      197: #endif
                    198: 
                    199:                } else if (type == "afpacket") {
                    200: #if defined(HAVE_HOSTNET_AFPACKET)
                    201:                        CreateAFPacket();
                    202: #else
1.1.1.2   root      203:                        item.Err("Hostnet driver %s not compiled", type.c_str());
1.1       root      204: #endif
                    205: 
                    206:                } else {
                    207:                        // 知らないドライバ種別
                    208:                        item.Err();
                    209:                }
                    210: 
                    211:                if ((bool)driver == false) {
                    212:                        putmsg(1, "hostnet-fallback=%d", fallback ? 1 : 0);
                    213: 
                    214:                        if (fallback == false) {
                    215:                                // フォールバックしないならエラー終了
                    216:                                errmsg = "No host network driver found";
                    217:                                putmsg(1, "%s", errmsg.c_str());
                    218:                                warnx("%s (See details with options -C -Lhostnet=1)",
                    219:                                        errmsg.c_str());
                    220: 
                    221:                                return false;
                    222:                        }
                    223:                }
                    224:        }
                    225: 
                    226:        if ((bool)driver == false) {
                    227:                CreateNone();
                    228:        }
                    229:        assert((bool)driver);
                    230: 
                    231:        // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
                    232:        putmsg(1, "selected host driver: %s",
                    233:                string_tolower(driver->GetDriverName()).c_str());
                    234: 
                    235:        return true;
                    236: }
                    237: 
                    238: // None ドライバを生成する
                    239: bool
                    240: HostNetDevice::CreateNone()
                    241: {
                    242:        driver.reset(new NetDriverNone(this));
                    243:        if ((bool)driver) {
                    244:                if (driver->InitDriver()) {
                    245:                        // 成功
                    246:                        return true;
                    247:                }
                    248:                errmsg = driver->errmsg;
                    249:                driver.reset();
                    250:        }
                    251:        return false;
                    252: }
                    253: 
1.1.1.7 ! root      254: // Slirp ドライバを生成する
        !           255: bool
        !           256: HostNetDevice::CreateSlirp()
        !           257: {
        !           258: #if defined(HAVE_HOSTNET_SLIRP)
        !           259:        driver.reset(new NetDriverSlirp(this));
        !           260:        if ((bool)driver) {
        !           261:                if (driver->InitDriver()) {
        !           262:                        // 成功
        !           263:                        return true;
        !           264:                }
        !           265:                errmsg = driver->errmsg;
        !           266:                driver.reset();
        !           267:        }
        !           268: #endif
        !           269:        return false;
        !           270: }
        !           271: 
1.1       root      272: // Tap ドライバを生成する
                    273: bool
                    274: HostNetDevice::CreateTap()
                    275: {
                    276: #if defined(HAVE_HOSTNET_TAP)
1.1.1.3   root      277:        int n = GetId() - OBJ_HOSTNET0;
                    278:        const std::string keyname = string_format("hostnet%d-tap-devpath", n);
                    279:        const ConfigItem& item = gConfig->Find(keyname);
1.1       root      280:        const std::string& devpath = item.AsString();
                    281: 
                    282:        driver.reset(new NetDriverTap(this, devpath));
                    283:        if ((bool)driver) {
                    284:                if (driver->InitDriver()) {
                    285:                        // 成功
                    286:                        return true;
                    287:                }
                    288:                errmsg = driver->errmsg;
                    289:                driver.reset();
                    290:        }
                    291: #endif
                    292:        return false;
                    293: }
                    294: 
                    295: // bpf ドライバを生成する
                    296: bool
                    297: HostNetDevice::CreateBPF()
                    298: {
                    299: #if defined(HAVE_HOSTNET_BPF)
1.1.1.3   root      300:        int n = GetId() - OBJ_HOSTNET0;
                    301:        const std::string keyname = string_format("hostnet%d-bpf-ifname", n);
                    302:        const ConfigItem& item = gConfig->Find(keyname);
1.1       root      303:        const std::string& ifname = item.AsString();
                    304: 
                    305:        driver.reset(new NetDriverBPF(this, ifname));
                    306:        if ((bool)driver) {
                    307:                if (driver->InitDriver()) {
                    308:                        // 成功
                    309:                        return true;
                    310:                }
                    311:                errmsg = driver->errmsg;
                    312:                driver.reset();
                    313:        }
                    314: #endif
                    315:        return false;
                    316: }
                    317: 
                    318: // AFPacket ドライバを生成する
                    319: bool
                    320: HostNetDevice::CreateAFPacket()
                    321: {
                    322: #if defined(HAVE_HOSTNET_AFPACKET)
1.1.1.3   root      323:        int n = GetId() - OBJ_HOSTNET0;
                    324:        const std::string keyname = string_format("hostnet%d-afpacket-ifname", n);
                    325:        const ConfigItem& item = gConfig->Find(keyname);
1.1       root      326:        const std::string& ifname = item.AsString();
                    327: 
                    328:        driver.reset(new NetDriverAFPacket(this, ifname));
                    329:        if ((bool)driver) {
                    330:                if (driver->InitDriver()) {
                    331:                        // 成功
                    332:                        return true;
                    333:                }
                    334:                errmsg = driver->errmsg;
                    335:                driver.reset();
                    336:        }
                    337: #endif
                    338:        return false;
                    339: }
                    340: 
                    341: // VM からの送信 (VM スレッドで呼ばれる)
                    342: bool
                    343: HostNetDevice::Tx(const NetPacket& packet)
                    344: {
1.1.1.5   root      345:        // 長さ 0 のパケットは破棄する。バグでもないと通常は起きない。
                    346:        // runt frame はどうするか?
                    347:        if (packet.length < 1) {
                    348:                stat.txzero_pkts++;
                    349:                putlog(1, "Tx: drop empty packet");
                    350:                return true;
                    351:        }
                    352: 
1.1       root      353:        // 送信キューに入れて..
                    354:        if (txq.Enqueue(packet) == false) {
                    355:                stat.txqfull_pkts++;
                    356:                stat.txqfull_bytes += packet.length;
                    357:                putlog(2, "txq exhausted");
                    358:                return false;
                    359:        }
                    360: 
                    361:        stat.tx_pkts++;
                    362:        stat.tx_bytes += packet.length;
                    363: 
                    364:        // ざっくりピーク値
1.1.1.5   root      365:        stat.txq_peak = std::max((uint)txq.Length(), stat.txq_peak);
1.1       root      366: 
                    367:        // パイプに通知 (値はダミー)
                    368:        return WritePipe(0);
                    369: }
                    370: 
1.1.1.6   root      371: // rxq への投入を行う場合は true。
                    372: // VM スレッドから呼ばれる。
1.1       root      373: void
                    374: HostNetDevice::EnableRx(bool enable)
                    375: {
                    376:        rx_enable = enable;
1.1.1.6   root      377: 
                    378:        // 受信を停止した時はキューに残っているのを破棄する。
                    379:        // (ゲスト再起動によるデバイスリセット時とか)
                    380:        if (rx_enable == false) {
                    381:                // 統計情報に足すためだけに一旦取り出す。
                    382:                NetPacket drop;
                    383:                while (rxq.Dequeue(&drop)) {
                    384:                        stat.rxdisable_pkts++;
                    385:                        stat.rxdisable_bytes += drop.length;
                    386:                }
                    387:        }
1.1       root      388: }
                    389: 
                    390: // パケットをキューから取り出す。
                    391: // VM 側から呼ばれる。
                    392: bool
                    393: HostNetDevice::Rx(NetPacket *dst)
                    394: {
                    395:        if (rxq.Dequeue(dst) == false) {
                    396:                // キューが空
                    397:                return false;
                    398:        }
                    399:        stat.rx_pkts++;
                    400:        stat.rx_bytes += dst->length;
1.1.1.3   root      401:        if (__predict_false(loglevel >= 2)) {
1.1.1.5   root      402:                putlogn("Recv %u bytes", dst->length);
1.1.1.7 ! root      403:                if (loglevel >= 4) {
1.1.1.3   root      404:                        std::string buf;
1.1.1.5   root      405:                        for (uint i = 0; i < dst->length; i++) {
1.1.1.3   root      406:                                if (i % 16 == 0) {
                    407:                                        buf += string_format("%04x:", i);
                    408:                                }
                    409:                                buf += string_format(" %02x", (*dst)[i]);
                    410:                                if (i % 16 == 7) {
                    411:                                        buf += " ";
                    412:                                } else if (i % 16 == 15) {
                    413:                                        putlogn("%s", buf.c_str());
                    414:                                        buf = "";
                    415:                                }
                    416:                        }
                    417:                        if (buf.empty() == false) {
                    418:                                putlogn("%s", buf.c_str());
                    419:                        }
                    420:                }
                    421:        }
1.1       root      422: 
                    423:        return true;
                    424: }
                    425: 
                    426: // 外部からの読み込み (パケットを受信)。
                    427: // 戻り値はキューに投入したパケット数。
                    428: int
                    429: HostNetDevice::Read()
                    430: {
                    431:        int queued = 0;
                    432:        int left = 0;
                    433: 
                    434:        assert((bool)driver);
                    435: 
                    436:        do {
                    437:                NetPacket *p;
                    438: 
                    439:                p = rxq.BeginWrite();
                    440:                if (p == NULL) {
                    441:                        NetPacket discard;
                    442:                        left = driver->Read(&discard);
                    443:                        if (left < 0) {
                    444:                                break;
                    445:                        }
                    446:                        stat.rxqfull_pkts++;
                    447:                        stat.rxqfull_bytes += discard.length;
                    448:                        continue;
                    449:                }
                    450: 
                    451:                // driver->Read() は VM に投入すべきパケットがなければ負数を返す。
                    452:                // パケットがあれば p に書き戻して、driver 側のバッファに残っている
                    453:                // パケット数 (といっても 0 か 1以上) を返してくる。
                    454:                left = driver->Read(p);
                    455:                if (left < 0) {
                    456:                        rxq.CancelWrite();
                    457:                        break;
                    458:                }
                    459: 
                    460:                NetPacket& packet = *p;
                    461: 
                    462:                stat.read_pkts++;
                    463:                stat.read_bytes += packet.length;
                    464: 
                    465:                if (rx_enable == false) {
                    466:                        rxq.CancelWrite();
                    467:                        stat.rxdisable_pkts++;
                    468:                        stat.rxdisable_bytes += packet.length;
                    469:                        continue;
                    470:                }
                    471: 
                    472:                // イーサネットフレームより長いパケットはゲスト OS が期待していない。
                    473:                // ここでドロップしてみる。
                    474:                // これによりゲストでの dropping chained buffer が出なくなる。
                    475:                if (packet.length > 1518) {
                    476:                        rxq.CancelWrite();
                    477:                        stat.rxjumbo_pkts++;
                    478:                        stat.rxjumbo_bytes += packet.length;
                    479:                        continue;
                    480:                }
                    481: 
                    482:                // ホストカーネルから直接着信したパケット(というかフレームか)は
                    483:                // 60バイトパディングされないまま読み出せるので、ここでパディングする。
                    484:                while (packet.length < 60) {
                    485:                        packet.Append(0x00);
                    486:                }
                    487: 
1.1.1.7 ! root      488:                // デバイスがこのアドレス宛のフレームを受け取るか。
        !           489:                // 受け取らないと分かっているフレームは VM へのキューに入れる前に
        !           490:                // 落としておきたい。
        !           491:                MacAddr dstaddr(&packet[0]);
        !           492:                auto res = ihwaddrfilter->HWAddrFilter(dstaddr);
        !           493:                if (res != 0) {
        !           494:                        switch (res) {
        !           495:                         case IHWAddrFilter::HPF_DROP_UNICAST:
        !           496:                                stat.rxnotme_pkts++;
        !           497:                                stat.rxnotme_bytes += packet.length;
        !           498:                                break;
        !           499:                         case IHWAddrFilter::HPF_DROP_MULTICAST:
        !           500:                                stat.rxmcast_pkts++;
        !           501:                                stat.rxmcast_bytes += packet.length;
        !           502:                                break;
        !           503:                         default:
        !           504:                                assertmsg(false, "corrupted res=%u", res);
1.1       root      505:                        }
1.1.1.7 ! root      506:                        rxq.CancelWrite();
        !           507:                        continue;
1.1       root      508:                }
                    509: 
                    510:                // CRC XXX 計算すること
                    511:                for (int i = 0; i < 4; i++) {
                    512:                        packet.Append(0x00);
                    513:                }
                    514: 
                    515:                rxq.EndWrite();
                    516:                queued++;
                    517:        } while (left > 0);
                    518: 
                    519:        // ざっくりピーク値
1.1.1.5   root      520:        stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak);
1.1       root      521: 
                    522:        return queued;
                    523: }
                    524: 
                    525: // 外部への書き出し(パケットを送信)
                    526: void
                    527: HostNetDevice::Write(uint32 data)
                    528: {
                    529:        const NetPacket *p;
                    530: 
                    531:        assert((bool)driver);
                    532: 
                    533:        // 送信キューから取り出す
                    534:        while ((p = txq.BeginRead()) != NULL) {
                    535:                const NetPacket& packet = *p;
                    536: 
1.1.1.3   root      537:                if (__predict_false(loglevel >= 2)) {
1.1.1.5   root      538:                        putlogn("Send %u bytes", packet.length);
1.1.1.7 ! root      539:                        if (loglevel >= 4) {
1.1.1.3   root      540:                                std::string buf;
1.1.1.5   root      541:                                for (uint i = 0; i < packet.length; i++) {
1.1.1.3   root      542:                                        if (i % 16 == 0) {
                    543:                                                buf += string_format("%04x:", i);
                    544:                                        }
                    545:                                        buf += string_format(" %02x", packet[i]);
                    546:                                        if (i % 16 == 7) {
                    547:                                                buf += " ";
                    548:                                        } else if (i % 16 == 15) {
                    549:                                                putlogn("%s", buf.c_str());
                    550:                                                buf = "";
                    551:                                        }
                    552:                                }
                    553:                                if (buf.empty() == false) {
                    554:                                        putlogn("%s", buf.c_str());
                    555:                                }
                    556:                        }
                    557:                }
1.1       root      558:                stat.write_pkts++;
                    559:                stat.write_bytes += packet.length;
                    560: 
                    561:                driver->Write(packet.data(), packet.length);
                    562:                txq.EndRead();
                    563:        }
                    564: }
                    565: 
                    566: // ドライバ名を返す
                    567: const std::string
                    568: HostNetDevice::GetDriverName() const
                    569: {
                    570:        assert((bool)driver);
                    571:        return driver->GetDriverName();
                    572: }
                    573: 
1.1.1.7 ! root      574: // 統計情報に1パケット分加算する。
        !           575: // これだけ SLIRP 裏スレッドから呼ばれるため。
        !           576: // 現状書き込むのが SLIRP スレッドだけなのでロックとかはしていない。
        !           577: void
        !           578: HostNetDevice::CountTXUnsupp(size_t bytes)
        !           579: {
        !           580:        stat.txunsupp_pkts++;
        !           581:        stat.txunsupp_bytes += bytes;
        !           582: }
        !           583: 
1.1       root      584: // モニタ
                    585: void
                    586: HostNetDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    587: {
                    588:        screen.Clear();
                    589: 
1.1.1.3   root      590:        screen.Print(0, 0, "Parent Device : %s", parent->GetName().c_str());
                    591:        screen.Print(0, 1, "HostNet Driver: %s", driver->GetDriverName());
1.1       root      592:        // 次の2行はドライバ依存情報
1.1.1.3   root      593:        driver->MonitorUpdateMD(screen, 2);
1.1       root      594: 
                    595:        // 01234567890123456
                    596:        // Write to host
                    597:        // Drop:TxQ Full
                    598:        // Drop:Rx Disabled
                    599:        // Drop:Jumbo Frame
                    600:        // Drop:Addr Filter
                    601: 
1.1.1.3   root      602:        int y = 5;
1.1       root      603:        screen.Print(0, y++, "%-17s%13s %17s", "<Tx>", "Packets", "Bytes");
                    604:        screen.Print(0, y++, "%-17s%13s %17s", "VM sends",
                    605:                format_number(stat.tx_pkts).c_str(),
                    606:                format_number(stat.tx_bytes).c_str());
                    607:        screen.Print(0, y++, "%-17s%13s %17s", "Write to host",
                    608:                format_number(stat.write_pkts).c_str(),
                    609:                format_number(stat.write_bytes).c_str());
1.1.1.5   root      610:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Empty Frame",
                    611:                format_number(stat.txzero_pkts).c_str(),
                    612:                "0");
1.1.1.7 ! root      613:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unsupported",
        !           614:                format_number(stat.txunsupp_pkts).c_str(),
        !           615:                format_number(stat.txunsupp_bytes).c_str());
1.1       root      616:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:TxQ Full",
                    617:                format_number(stat.txqfull_pkts).c_str(),
                    618:                format_number(stat.txqfull_bytes).c_str());
                    619:        y++;
                    620: 
                    621:        screen.Print(0, y++, "%-17s%13s %17s", "<Rx>", "Packets", "Bytes");
                    622:        screen.Print(0, y++, "%-17s%13s %17s", "Read from host",
                    623:                format_number(stat.read_pkts).c_str(),
                    624:                format_number(stat.read_bytes).c_str());
                    625:        screen.Print(0, y++, "%-17s%13s %17s", "VM receives",
                    626:                format_number(stat.rx_pkts).c_str(),
                    627:                format_number(stat.rx_bytes).c_str());
                    628:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Rx Disabled",
                    629:                format_number(stat.rxdisable_pkts).c_str(),
                    630:                format_number(stat.rxdisable_bytes).c_str());
                    631:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Jumbo Frame",
                    632:                format_number(stat.rxjumbo_pkts).c_str(),
                    633:                format_number(stat.rxjumbo_bytes).c_str());
                    634:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:RxQ Full",
                    635:                format_number(stat.rxqfull_pkts).c_str(),
                    636:                format_number(stat.rxqfull_bytes).c_str());
1.1.1.4   root      637:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unicast",
                    638:                format_number(stat.rxnotme_pkts).c_str(),
                    639:                format_number(stat.rxnotme_bytes).c_str());
                    640:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Multicast",
                    641:                format_number(stat.rxmcast_pkts).c_str(),
                    642:                format_number(stat.rxmcast_bytes).c_str());
1.1       root      643:        y++;
                    644: 
                    645:        screen.Print(5, y++, "Capacity Peak");
1.1.1.5   root      646:        screen.Print(0, y++, "TxQ %4u/%4u %4u",
                    647:                (uint)txq.Length(), (uint)txq.Capacity(), stat.txq_peak);
                    648:        screen.Print(0, y++, "RxQ %4u/%4u %4u",
                    649:                (uint)rxq.Length(), (uint)rxq.Capacity(), stat.rxq_peak);
1.1       root      650: }
1.1.1.7 ! root      651: 
        !           652: // 16進ダンプに整形して、文字列の配列(改行を含まない)を返す。
        !           653: /*static*/ std::vector<std::string>
        !           654: HostNetDevice::DumpHex(const void *src, size_t srclen)
        !           655: {
        !           656:        std::vector<std::string> lines;
        !           657:        std::string buf;
        !           658: 
        !           659:        for (size_t i = 0; i < srclen; i++) {
        !           660:                buf += string_format(" %02x", ((const uint8 *)src)[i]);
        !           661:                if (i % 16 == 7) {
        !           662:                        buf += ' ';
        !           663:                }
        !           664:                if (i % 16 == 15) {
        !           665:                        lines.emplace_back(buf);
        !           666:                        buf.clear();
        !           667:                }
        !           668:        }
        !           669:        if (buf.empty() == false) {
        !           670:                lines.emplace_back(buf);
        !           671:        }
        !           672:        return lines;
        !           673: }
        !           674: 
        !           675: // イーサネットフレームを整形して、文字列の配列(改行は含まない)を返す。
        !           676: /*static*/ std::vector<std::string>
        !           677: HostNetDevice::DumpFrame(const void *src, size_t srclen)
        !           678: {
        !           679:        std::vector<std::string> lines;
        !           680:        struct eth_header {
        !           681:                uint8 dst[6];
        !           682:                uint8 src[6];
        !           683:                uint16 type;
        !           684:        } __packed;
        !           685: 
        !           686:        const eth_header& eh = *(const eth_header *)src;
        !           687:        uint16 type = ntohs(eh.type);
        !           688:        std::string ethtype;
        !           689:        switch (type) {
        !           690:         case 0x0800:   ethtype = "IPv4";       break;
        !           691:         case 0x0806:   ethtype = "ARP";        break;
        !           692:         case 0x86dd:   ethtype = "IPv6";       break;
        !           693:         default:
        !           694:                ethtype = string_format("%04x", type);
        !           695:                break;
        !           696:        }
        !           697:        lines.emplace_back(string_format("Eth: %02x:%02x:%02x:%02x:%02x:%02x -> "
        !           698:                "%02x:%02x:%02x:%02x:%02x:%02x (%s)",
        !           699:                eh.src[0], eh.src[1], eh.src[2], eh.src[3], eh.src[4], eh.src[5],
        !           700:                eh.dst[0], eh.dst[1], eh.dst[2], eh.dst[3], eh.dst[4], eh.dst[5],
        !           701:                ethtype.c_str()));
        !           702: 
        !           703:        // ペイロードは次の行につなげる。
        !           704:        const uint8 *payload = (const uint8 *)src + sizeof(eth_header);
        !           705:        size_t payloadlen = srclen - sizeof(eth_header);
        !           706:        std::vector<std::string> lines2;
        !           707:        switch (type) {
        !           708:         case 0x0800:
        !           709:                lines2 = DumpIPv4(payload, payloadlen);
        !           710:                break;
        !           711:         case 0x0806:
        !           712:                lines2 = DumpARP(payload, payloadlen);
        !           713:                break;
        !           714:         case 0x86dd:
        !           715:                lines2 = DumpIPv6(payload, payloadlen);
        !           716:                break;
        !           717:         default:
        !           718:                break;
        !           719:        }
        !           720:        if (lines2.empty() == false) {
        !           721:                for (auto& buf : lines2) {
        !           722:                        lines.emplace_back(buf);
        !           723:                }
        !           724:        }
        !           725: 
        !           726:        return lines;
        !           727: }
        !           728: 
        !           729: // ARP パケットを整形して、文字列の配列(改行は含まない)を返す。
        !           730: /*static*/ std::vector<std::string>
        !           731: HostNetDevice::DumpARP(const void *src, size_t srclen)
        !           732: {
        !           733:        std::vector<std::string> lines;
        !           734:        struct arp_header {
        !           735:                uint16 hwtype;
        !           736:                uint16 prototype;
        !           737:                uint8  hwsize;
        !           738:                uint8  protosize;
        !           739:                enum : uint16 {
        !           740:                        ARP_REQUEST = 1,
        !           741:                        ARP_REPLY       = 2,
        !           742:                } opcode;
        !           743:                uint8  dstmac[6];
        !           744:                uint8  dstip[4];
        !           745:                uint8  srcmac[6];
        !           746:                uint8  srcip[4];
        !           747:        } __packed;
        !           748: 
        !           749:        const arp_header& a = *(const arp_header *)src;
        !           750:        uint16 opcode = ntohs(a.opcode);
        !           751:        std::string opstr;
        !           752:        switch (opcode) {
        !           753:         case arp_header::ARP_REQUEST:
        !           754:                lines.emplace_back(string_format(
        !           755:                        " ARP: Who has %u.%u.%u.%u? Tell %u.%u.%u.%u",
        !           756:                        a.dstip[0], a.dstip[1], a.dstip[2], a.dstip[3],
        !           757:                        a.srcip[0], a.srcip[1], a.srcip[2], a.srcip[3]));
        !           758:                break;
        !           759:         case arp_header::ARP_REPLY:
        !           760:                lines.emplace_back(string_format(
        !           761:                        " ARP: Reply %u.%u.%u.%u is at %02x:%02x:%02x:%02x:%02x:%02x",
        !           762:                        a.dstip[0], a.dstip[1], a.dstip[2], a.dstip[3],
        !           763:                        a.dstmac[0], a.dstmac[1], a.dstmac[2],
        !           764:                        a.dstmac[3], a.dstmac[4], a.dstmac[5]));
        !           765:                break;
        !           766:         default:
        !           767:                lines.emplace_back(string_format(" ARP: unknown op 0x%04x", opcode));
        !           768:                break;
        !           769:        }
        !           770: 
        !           771:        return lines;
        !           772: }
        !           773: 
        !           774: // IPv4 パケットを整形して、文字列の配列(改行は含まない)を返す。
        !           775: /*static*/ std::vector<std::string>
        !           776: HostNetDevice::DumpIPv4(const void *src, size_t srclen)
        !           777: {
        !           778:        std::vector<std::string> lines;
        !           779:        struct ipv4_header {
        !           780:                uint8  ver_len;
        !           781:                uint8  tos;
        !           782:                uint16 total_len;
        !           783:                uint16 id;
        !           784:                uint16 fragment;
        !           785:                uint8  ttl;
        !           786:                uint8  proto;
        !           787:                uint16 cksum;
        !           788:                uint8  src[4];
        !           789:                uint8  dst[4];
        !           790:        } __packed;
        !           791: 
        !           792:        const ipv4_header& ip = *(const ipv4_header *)src;
        !           793:        const uint8 *payload = (const uint8 *)src + sizeof(ipv4_header);
        !           794:        size_t payloadlen = srclen - sizeof(ipv4_header);
        !           795: 
        !           796:        char srcname[INET_ADDRSTRLEN];
        !           797:        char dstname[INET_ADDRSTRLEN];
        !           798:        srcname[0] = '\0';
        !           799:        dstname[0] = '\0';
        !           800:        inet_ntop(AF_INET, &ip.src[0], srcname, (socklen_t)sizeof(srcname));
        !           801:        inet_ntop(AF_INET, &ip.dst[0], dstname, (socklen_t)sizeof(dstname));
        !           802: 
        !           803:        switch (ip.proto) {
        !           804:         case 1:
        !           805:                lines = DumpICMPv4(srcname, dstname, payload, payloadlen);
        !           806:                break;
        !           807:         case 6:
        !           808:                lines = DumpTCPv4(srcname, dstname, payload, payloadlen);
        !           809:                break;
        !           810:         case 17:
        !           811:                lines = DumpUDPv4(srcname, dstname, payload, payloadlen);
        !           812:                break;
        !           813:         default:
        !           814:         {
        !           815:                std::string protoname;
        !           816:                const struct protoent *pent = getprotobynumber(ip.proto);
        !           817:                if (pent) {
        !           818:                        protoname = string_format("(%s)", pent->p_name);
        !           819:                }
        !           820:                lines.emplace_back(string_format(" IPv4 %s -> %s 0x%02x%s",
        !           821:                        srcname, dstname, ip.proto, protoname.c_str()));
        !           822:                break;
        !           823:         }
        !           824:        }
        !           825: 
        !           826:        return lines;
        !           827: }
        !           828: 
        !           829: // ICMP(v4) パケットを整形して、文字列の配列(改行は含まない)を返す。
        !           830: /*static*/ std::vector<std::string>
        !           831: HostNetDevice::DumpICMPv4(const char *srcname, const char *dstname,
        !           832:        const void *src, size_t srclen)
        !           833: {
        !           834:        std::vector<std::string> lines;
        !           835:        struct icmp_header {
        !           836:                uint8  type;
        !           837:                uint8  code;
        !           838:                uint16 cksum;
        !           839:        } __packed;
        !           840: 
        !           841:        const icmp_header& icmp = *(const icmp_header *)src;
        !           842:        size_t payloadlen = srclen - sizeof(icmp_header);
        !           843: 
        !           844:        std::string msg = string_format(" ICMP %s -> %s ", srcname, dstname);
        !           845:        uint type = icmp.type;
        !           846:        uint code = icmp.code;
        !           847: 
        !           848:        switch (type) {
        !           849:         case 0:        // ICMP_ECHOREPLY
        !           850:                msg += string_format("Echo Reply %zu bytes", payloadlen);
        !           851:                break;
        !           852: 
        !           853:         case 3:        // ICMP_UNREACH
        !           854:         {
        !           855:                static const char * const reasons[] = {
        !           856:                        "Destination Network Unreachable",      // 0
        !           857:                        "Destination Host Unreachable",         // 1
        !           858:                        "Destination Protocol Unreachable",     // 2
        !           859:                        "Destination Port Unreachable",         // 3
        !           860:                        "Fragment needed and DF set",           // 4
        !           861:                        "Source Route Failed",                          // 5
        !           862:                        "Destination Network Unknown",          // 6
        !           863:                        "Destination Host Unknown",                     // 7
        !           864:                        "Source Host Isolated",                         // 8
        !           865:                        "Communication with Destination Network is prohibited", // 9
        !           866:                        "Communication with Destination Host is prohibited",    // 10
        !           867:                        "Bad ToS for Destination Network",      // 11
        !           868:                        "Bad ToS for Destination Host",         // 12
        !           869:                        "Communication is Administratively prohibited",         // 13
        !           870:                        "Host Precedence Violation",            // 14
        !           871:                        "Precedence cutoff",                            // 15
        !           872:                };
        !           873:                if (code < countof(reasons)) {
        !           874:                        msg += reasons[code];
        !           875:                } else {
        !           876:                        msg += string_format("Network Unreachable: code=%02x", code);
        !           877:                }
        !           878:                break;
        !           879:         }
        !           880: 
        !           881:         case 5:        // ICMP_REDIRECT
        !           882:                msg += string_format("Redirect code=%x", code);
        !           883:                break;
        !           884: 
        !           885:         case 8:        // ICMP_ECHO
        !           886:                msg += string_format("Echo Request %zu bytes", payloadlen);
        !           887:                break;
        !           888: 
        !           889:         default:
        !           890:                msg += string_format("Type=0x%02x Code=0x%02x", type, code);
        !           891:                break;
        !           892:        }
        !           893:        lines.emplace_back(msg);
        !           894: 
        !           895:        return lines;
        !           896: }
        !           897: 
        !           898: // TCPv4 パケットを整形して、文字列の配列(改行は含まない)を返す。
        !           899: /*static*/ std::vector<std::string>
        !           900: HostNetDevice::DumpTCPv4(const char *srcname, const char *dstname,
        !           901:        const void *src, size_t srclen)
        !           902: {
        !           903:        std::vector<std::string> lines;
        !           904:        struct tcp_header {
        !           905:                uint16 sport;
        !           906:                uint16 dport;
        !           907:                uint32 seq;
        !           908:                uint32 ack;
        !           909:                uint8  off;
        !           910:                uint8  flags;
        !           911:                uint16 window;
        !           912:                uint16 cksum;
        !           913:                uint16 urp;
        !           914:        } __packed;
        !           915: 
        !           916:        const tcp_header& tcp = *(const tcp_header *)src;
        !           917:        size_t payloadlen = srclen - sizeof(tcp_header);
        !           918: 
        !           919:        std::string flagstr;
        !           920:        if (tcp.flags != 0) {
        !           921:                flagstr = ' ';
        !           922:                if ((tcp.flags & 0x01)) flagstr += ",FIN";
        !           923:                if ((tcp.flags & 0x02)) flagstr += ",SYN";
        !           924:                if ((tcp.flags & 0x04)) flagstr += ",RST";
        !           925:                if ((tcp.flags & 0x08)) flagstr += ",PUSH";
        !           926:                if ((tcp.flags & 0x10)) flagstr += ",ACK";
        !           927:                if ((tcp.flags & 0x20)) flagstr += ",URG";
        !           928:                if ((tcp.flags & 0x40)) flagstr += ",ECE";
        !           929:                if ((tcp.flags & 0x80)) flagstr += ",CWR";
        !           930:                flagstr[1] = '<';
        !           931:                flagstr += '>';
        !           932:        }
        !           933:        std::string sserv = GetServByPort(tcp.sport, "tcp");
        !           934:        std::string dserv = GetServByPort(tcp.dport, "tcp");
        !           935:        lines.emplace_back(string_format(" TCP %s:%u%s -> %s:%u%s%s %zu bytes",
        !           936:                srcname, ntohs(tcp.sport), sserv.c_str(),
        !           937:                dstname, ntohs(tcp.dport), dserv.c_str(),
        !           938:                flagstr.c_str(), payloadlen));
        !           939: 
        !           940:        return lines;
        !           941: }
        !           942: 
        !           943: // UDPv4 パケットを整形して、文字列の配列(改行は含まない)を返す。
        !           944: /*static*/ std::vector<std::string>
        !           945: HostNetDevice::DumpUDPv4(const char *srcname, const char *dstname,
        !           946:        const void *src, size_t srclen)
        !           947: {
        !           948:        std::vector<std::string> lines;
        !           949:        struct udp_header {
        !           950:                uint16 sport;
        !           951:                uint16 dport;
        !           952:                uint16 len;
        !           953:                uint16 cksum;
        !           954:        } __packed;
        !           955: 
        !           956:        const udp_header& udp = *(const udp_header *)src;
        !           957:        const uint8 *payload = (const uint8 *)src + sizeof(udp_header);
        !           958:        size_t payloadlen = srclen - sizeof(udp_header);
        !           959: 
        !           960:        std::string sserv = GetServByPort(udp.sport, "udp");
        !           961:        std::string dserv = GetServByPort(udp.dport, "udp");
        !           962:        int sport = ntohs(udp.sport);
        !           963:        int dport = ntohs(udp.dport);
        !           964:        lines.emplace_back(string_format(" UDP %s:%u%s -> %s:%u%s %zu bytes",
        !           965:                srcname, sport, sserv.c_str(),
        !           966:                dstname, dport, dserv.c_str(),
        !           967:                payloadlen));
        !           968: 
        !           969:        if (dport == 67 || dport == 68) {
        !           970:                auto lines2 = DumpDHCP(payload, payloadlen);
        !           971:                for (auto& buf : lines2) {
        !           972:                        lines.emplace_back(buf);
        !           973:                }
        !           974:        }
        !           975: 
        !           976:        return lines;
        !           977: }
        !           978: 
        !           979: // BOOTP/DHCP パケットを整形して、文字列の配列(改行は含まない)を返す。
        !           980: /*static*/ std::vector<std::string>
        !           981: HostNetDevice::DumpDHCP(const void *src, size_t srclen)
        !           982: {
        !           983:        std::vector<std::string> lines;
        !           984:        struct bootp_msg {
        !           985:                uint8 op;                       // Message Operation Code
        !           986:                uint8 htype;            // Hardware Type
        !           987:                uint8 hlen;                     // Hardware Address Length
        !           988:                uint8 hops;
        !           989:                uint32 xid;                     // Transaction ID
        !           990:                uint16 secs;            // Seconds Elapsed (払い出し期間)
        !           991:                uint16 flags;
        !           992:                uint32 ciaddr;          // Client IP Address (クライアントが使用)
        !           993:                uint32 yiaddr;          // Your IP Address (払い出し IP)
        !           994:                uint32 siaddr;          // Server IP Address (BOOTP)
        !           995:                uint32 giaddr;          // Gateway IP Address
        !           996:                uint8 chaddr[16];       // Client Hardware Address
        !           997:                uint8 sname[64];        // Server Name (BOOTP)
        !           998:                uint8 file[128];        // Boot Filename (BOOTP)
        !           999:                // ここから options
        !          1000:        } __packed;
        !          1001: 
        !          1002:        const bootp_msg& bootp = *(const bootp_msg *)src;
        !          1003: 
        !          1004:        std::string msg = "  DHCP ";    // IP,UDP の次のインデント
        !          1005:        if (bootp.op == 1) {
        !          1006:                msg += "Request";
        !          1007:        } else if (bootp.op == 2) {
        !          1008:                msg += "Reply";
        !          1009:        } else {
        !          1010:                msg += string_format("OP=0x%02x?", bootp.op);
        !          1011:        }
        !          1012: 
        !          1013:        if (bootp.htype != 1) {
        !          1014:                msg += string_format(" htype=0x%02x?", bootp.htype);
        !          1015:        }
        !          1016:        if (bootp.hlen != 6) {
        !          1017:                msg += string_format(" hlen=0x%02x?", bootp.hlen);
        !          1018:        }
        !          1019:        if (bootp.ciaddr != 0) {
        !          1020:                char ci[INET_ADDRSTRLEN];
        !          1021:                inet_ntop(AF_INET, &bootp.ciaddr, ci, (socklen_t)sizeof(ci));
        !          1022:                msg += " Client=";
        !          1023:                msg += ci;
        !          1024:        }
        !          1025:        if (bootp.yiaddr != 0) {
        !          1026:                char yi[INET_ADDRSTRLEN];
        !          1027:                inet_ntop(AF_INET, &bootp.yiaddr, yi, (socklen_t)sizeof(yi));
        !          1028:                msg += " YourIP=";
        !          1029:                msg += yi;
        !          1030:        }
        !          1031:        lines.emplace_back(msg);
        !          1032: 
        !          1033:        const uint8 *options = (const uint8 *)src + sizeof(bootp_msg);
        !          1034:        size_t optionslen = srclen - sizeof(bootp_msg);
        !          1035:        // オプションの先頭4バイトはマジック。
        !          1036:        if (optionslen >= 4 && memcmp(options, "\x63\x82\x53\x63", 4) == 0) {
        !          1037:                // 以降は Code-Length-Value 形式。
        !          1038:                const uint8 *s = options + 4;
        !          1039:                optionslen -= 4;
        !          1040:                while (s - options < optionslen) {
        !          1041:                        uint8 code = *s++;
        !          1042:                        if (code == 255) {                      // End
        !          1043:                                break;
        !          1044:                        }
        !          1045:                        if (code == 0) {                        // Pad
        !          1046:                                continue;
        !          1047:                        }
        !          1048:                        static const char * const optnames[] = {
        !          1049:                                "",                                             // 0
        !          1050:                                "Subnet Mask",                  // 1
        !          1051:                                "Time Offset",                  // 2
        !          1052:                                "Router",                               // 3
        !          1053:                                "Time Server",                  // 4
        !          1054:                                "IEN116 Name Server",   // 5
        !          1055:                                "DNS Server",                   // 6
        !          1056:                                "Log Server",                   // 7
        !          1057:                                "Quotes Server",                // 8
        !          1058:                                "LPR Server",                   // 9
        !          1059:                                "Impress Server",               // 10
        !          1060:                                "RLP Server",                   // 11
        !          1061:                                "Hostname",                             // 12
        !          1062:                                "Boot File Size",               // 13
        !          1063:                                "Merit Dump File",              // 14
        !          1064:                                "Domain Name",                  // 15
        !          1065:                                "Swap Server",                  // 16
        !          1066:                                "Root Path",                    // 17
        !          1067:                                "Extension File",               // 18
        !          1068:                                "Forward Enable",               // 19
        !          1069:                                "Source Route Enable",  // 20
        !          1070:                                "Policy Filter",                // 21
        !          1071:                                "Max DG Assembly",              // 22
        !          1072:                                "Default IP TTL",               // 23
        !          1073:                                "MTU Timeout",                  // 24
        !          1074:                                "MTU Plateau",                  // 25
        !          1075:                                "MTU Interface",                // 26
        !          1076:                                "MTU Subnet",                   // 27
        !          1077:                                "Broadcast Address",    // 28
        !          1078:                                "Mask Discovery",               // 29
        !          1079:                                "Mask Supplier",                // 30
        !          1080:                                "Router Discovery",             // 31
        !          1081:                                "Router Request",               // 32
        !          1082:                                "Static Route",                 // 33
        !          1083:                                "Trailers",                             // 34
        !          1084:                                "ARP Timeout",                  // 35
        !          1085:                                "Ethernet",                             // 36
        !          1086:                                "Default TCP TTL",              // 37
        !          1087:                                "Keepalive Time",               // 38
        !          1088:                                "Keepalive Data",               // 39
        !          1089:                                "NIS Domain",                   // 40
        !          1090:                                "NIS Servers",                  // 41
        !          1091:                                "NTP Servers",                  // 42
        !          1092:                                "Vendor Specific",              // 43
        !          1093:                                "NETBIOS Name Server",  // 44
        !          1094:                                "NETBIOS Dist Server",  // 45
        !          1095:                                "NETBIOS Node Type",    // 46
        !          1096:                                "NETBIOS Scope",                // 47
        !          1097:                                "X Window Font",                // 48
        !          1098:                                "X Window Manager",             // 49
        !          1099:                                "Requested Address",    // 50
        !          1100:                                "Lease Time",                   // 51
        !          1101:                                "Overload",                             // 52
        !          1102:                                "DHCP Message Type",    // 53
        !          1103:                                "DHCP Server Id",               // 54
        !          1104:                                "Parameter List",               // 55
        !          1105:                                "DHCP Message",                 // 56
        !          1106:                                "DHCP Max Msg Size",    // 57
        !          1107:                                "Renewal Time",                 // 58
        !          1108:                                "Rebinding Time",               // 59
        !          1109:                                "Class Id",                             // 60
        !          1110:                                "Client Id",                    // 61
        !          1111:                                "Netware/IP Domain",    // 62
        !          1112:                                "Netware/IP Option",    // 63
        !          1113:                                "NIS Domain Name",              // 64
        !          1114:                                "NIS Server Addr",              // 65
        !          1115:                                "TFTP Server Name",             // 66
        !          1116:                                "Bootfile Name",                // 67
        !          1117:                                "Home Agent Addrs",             // 68
        !          1118:                                "SMTP Server",                  // 69
        !          1119:                                "POP3 Server",                  // 70
        !          1120:                                "NNTP Server",                  // 71
        !          1121:                                "WWW Server",                   // 72
        !          1122:                                "Finger Server",                // 73
        !          1123:                                "IRC Server",                   // 74
        !          1124:                                "StreetTalk Server",    // 75
        !          1125:                                "STDA Server",                  // 76
        !          1126:                                "User Class",                   // 77
        !          1127:                                "Directory Agent",              // 78
        !          1128:                                "Service Scope",                // 79
        !          1129:                                "Naming Authority",             // 80
        !          1130:                                "Client FQDN",                  // 81
        !          1131:                                "Agent Circuit ID",             // 82
        !          1132:                                "Agent Remote ID",              // 83
        !          1133:                                "Agent Subnet Mask",    // 84
        !          1134:                                "NDS Servers",                  // 85
        !          1135:                                "NDS Tree Name",                // 86
        !          1136:                                "NDS Context",                  // 87
        !          1137:                                "TimeZone",                             // 88
        !          1138:                                "FQDN",                                 // 89
        !          1139:                                "Authentication",               // 90
        !          1140:                                "Vines TCP/IP",                 // 91
        !          1141:                                "Server Selection",             // 92
        !          1142:                                "Client System",                // 93
        !          1143:                                "Client NDI",                   // 94
        !          1144:                                "LDAP",                                 // 95
        !          1145:                                "IPv6 Transitions",             // 96
        !          1146:                                "UUID/GUID",                    // 97
        !          1147:                                "User-Auth",                    // 98
        !          1148:                                "",                                             // 99
        !          1149:                                "Printer Name",                 // 100
        !          1150:                                "MDHCP",                                // 101
        !          1151:                                "",                                             // 102
        !          1152:                                "",                                             // 103
        !          1153:                                "",                                             // 104
        !          1154:                                "",                                             // 105
        !          1155:                                "",                                             // 106
        !          1156:                                "",                                             // 107
        !          1157:                                "Swap Path",                    // 108
        !          1158:                                "",                                             // 109
        !          1159:                                "IPX Compatability",    // 110
        !          1160:                                "",                                             // 111
        !          1161:                                "Netinfo Address",              // 112
        !          1162:                                "Netinfo Tag",                  // 113
        !          1163:                                "URL",                                  // 114
        !          1164:                                "DHCP Failover",                // 115
        !          1165:                                "DHCP AutoConfig",              // 116
        !          1166:                                "Name Service Search",  // 117
        !          1167:                                "Subnet Selection",             // 118
        !          1168:                        };
        !          1169:                        std::string opt = "   ";
        !          1170:                        if (code < countof(optnames) && optnames[code][0] != '\0') {
        !          1171:                                opt += optnames[code];
        !          1172:                        } else {
        !          1173:                                opt += '?';
        !          1174:                        }
        !          1175:                        opt += string_format("(%d): ", code);
        !          1176:                        size_t len = *s++;
        !          1177:                        switch (code) {
        !          1178:                         case 1:                // Subnet Mask
        !          1179:                         case 50:               // Requested Address
        !          1180:                         case 54:               // DHCP Server Id
        !          1181:                                // 単一アドレス
        !          1182:                                opt += DumpDHCPAddrList(s, 1);
        !          1183:                                break;
        !          1184: 
        !          1185:                         case 3:                // Router
        !          1186:                         case 6:                // DNS Server
        !          1187:                                // アドレスリスト
        !          1188:                                opt += DumpDHCPAddrList(s, len / 4);
        !          1189:                                break;
        !          1190: 
        !          1191:                         case 12:               // Hostname
        !          1192:                         case 15:               // Domain Name
        !          1193:                         {
        !          1194:                                // 文字列 (終端文字なし)
        !          1195:                                std::vector<char> buf(len + 1);
        !          1196:                                memcpy(buf.data(), s, len);
        !          1197:                                opt += buf.data();
        !          1198:                                break;
        !          1199:                         }
        !          1200: 
        !          1201:                         case 51:               // Lease Time
        !          1202:                         {
        !          1203:                                uint32 sec =
        !          1204:                                          (s[0] << 24)
        !          1205:                                        | (s[1] << 16)
        !          1206:                                        | (s[2] <<  8)
        !          1207:                                        | (s[3]);
        !          1208:                                opt += string_format("%d sec", sec);
        !          1209:                                break;
        !          1210:                         }
        !          1211: 
        !          1212:                         case 53:               // DHCP Message Type
        !          1213:                         {
        !          1214:                                static const char * const msgtypes[] = {
        !          1215:                                        "0",
        !          1216:                                        "DHCP DISCOVER",
        !          1217:                                        "DHCP OFFER",
        !          1218:                                        "DHCP REQUEST",
        !          1219:                                        "DHCP DECLINE",
        !          1220:                                        "DHCP ACK",
        !          1221:                                        "DHCP NAK",
        !          1222:                                        "DHCP RELEASE",
        !          1223:                                        "DHCP INFORM",
        !          1224:                                };
        !          1225:                                int type = s[0];
        !          1226:                                if (type < countof(msgtypes)) {
        !          1227:                                        opt += msgtypes[type];
        !          1228:                                } else {
        !          1229:                                        opt += string_format("0x%02x", type);
        !          1230:                                }
        !          1231:                                break;
        !          1232:                         }
        !          1233: 
        !          1234:                         default:
        !          1235:                                // 簡易ダンプしとくか。
        !          1236:                                for (size_t i = 0; i < len; i++) {
        !          1237:                                        opt += string_format("%02x", s[i]);
        !          1238:                                        if (i % 4 == 3) {
        !          1239:                                                opt += ' ';
        !          1240:                                        }
        !          1241:                                }
        !          1242:                                break;
        !          1243:                        }
        !          1244:                        lines.emplace_back(opt);
        !          1245:                        s += len;
        !          1246:                }
        !          1247:        }
        !          1248: 
        !          1249:        return lines;
        !          1250: }
        !          1251: 
        !          1252: // s から num 個の IPv4 アドレスリストを文字列にして返す。
        !          1253: // DumpDHCP() の下請け。
        !          1254: /*static*/ std::string
        !          1255: HostNetDevice::DumpDHCPAddrList(const uint8 *s, size_t num)
        !          1256: {
        !          1257:        std::string buf;
        !          1258: 
        !          1259:        for (size_t i = 0; i < num; i++) {
        !          1260:                char addr[INET_ADDRSTRLEN];
        !          1261:                inet_ntop(AF_INET, s, addr, (socklen_t)sizeof(addr));
        !          1262:                if (i != 0) {
        !          1263:                        buf += ' ';
        !          1264:                }
        !          1265:                buf += addr;
        !          1266:        }
        !          1267: 
        !          1268:        return buf;
        !          1269: }
        !          1270: 
        !          1271: // IPv6 パケットを整形して、文字列の配列(改行は含まない)を返す。
        !          1272: /*static*/ std::vector<std::string>
        !          1273: HostNetDevice::DumpIPv6(const void *src, size_t srclen)
        !          1274: {
        !          1275:        std::vector<std::string> lines;
        !          1276:        struct ipv6_header {
        !          1277:                uint8  ver_cls;
        !          1278:                uint8  cls_flow;
        !          1279:                uint16 flowlabel;
        !          1280:                uint16 payload_len;
        !          1281:                uint8  nexthdr;
        !          1282:                uint8  hoplimit;
        !          1283:                uint8  src[16];
        !          1284:                uint8  dst[16];
        !          1285:        } __packed;
        !          1286: 
        !          1287:        const ipv6_header& ip6 = *(const ipv6_header *)src;
        !          1288:        const uint8 *payload = (const uint8 *)src + sizeof(ipv6_header);
        !          1289:        size_t payloadlen = srclen - sizeof(ipv6_header);
        !          1290: 
        !          1291:        char srcname[INET6_ADDRSTRLEN];
        !          1292:        char dstname[INET6_ADDRSTRLEN];
        !          1293:        srcname[0] = '\0';
        !          1294:        dstname[0] = '\0';
        !          1295:        inet_ntop(AF_INET6, &ip6.src[0], srcname, (socklen_t)sizeof(srcname));
        !          1296:        inet_ntop(AF_INET6, &ip6.dst[0], dstname, (socklen_t)sizeof(dstname));
        !          1297: 
        !          1298:        switch (ip6.nexthdr) {
        !          1299:         case 58:
        !          1300:                lines = DumpICMPv6(srcname, dstname, payload, payloadlen);
        !          1301:                break;
        !          1302:         default:
        !          1303:         {
        !          1304:                std::string protoname;
        !          1305:                const struct protoent *pent = getprotobynumber(ip6.nexthdr);
        !          1306:                if (pent) {
        !          1307:                        protoname = string_format("(%s)", pent->p_name);
        !          1308:                }
        !          1309:                lines.emplace_back(string_format(" IPv6 %s -> %s 0x%02x%s",
        !          1310:                        srcname, dstname, ip6.nexthdr, protoname.c_str()));
        !          1311:                break;
        !          1312:         }
        !          1313:        }
        !          1314: 
        !          1315:        return lines;
        !          1316: }
        !          1317: 
        !          1318: // ICMPv6 パケットを整形して、文字列の配列(改行は含まない)を返す。
        !          1319: /*static*/ std::vector<std::string>
        !          1320: HostNetDevice::DumpICMPv6(const char *srcname, const char *dstname,
        !          1321:        const void *src, size_t srclen)
        !          1322: {
        !          1323:        std::vector<std::string> lines;
        !          1324:        // フォーマット自体は ICMPv4 と同じ。
        !          1325:        struct icmp_header {
        !          1326:                uint8  type;
        !          1327:                uint8  code;
        !          1328:                uint16 cksum;
        !          1329:        } __packed;
        !          1330: 
        !          1331:        const icmp_header& icmp6 = *(const icmp_header *)src;
        !          1332: 
        !          1333:        std::string msg = string_format(" ICMPv6 %s -> %s ", srcname, dstname);
        !          1334:        uint type = icmp6.type;
        !          1335:        uint code = icmp6.code;
        !          1336: 
        !          1337:        switch (type) {
        !          1338:         case 1:
        !          1339:                static const char * const reasons[] = {
        !          1340:                        "No route to destination",                      // 0
        !          1341:                        "Administratively prohibited",          // 1
        !          1342:                        "Beyond scope of source address",       // 2
        !          1343:                        "Address unreachable",                          // 3
        !          1344:                        "Port unreachable",                                     // 4
        !          1345:                        "Source address failed ingress/egress policy",  // 5
        !          1346:                        "Reject route to destination",          // 6
        !          1347:                        "Error in source routing header",       // 7
        !          1348:                };
        !          1349:                if (code < countof(reasons)) {
        !          1350:                        msg += reasons[code];
        !          1351:                } else {
        !          1352:                        msg += string_format("Destination Unreachable: code=%02x", code);
        !          1353:                }
        !          1354:                break;
        !          1355: 
        !          1356:         case 2:
        !          1357:                msg += "Packet too big";
        !          1358:                break;
        !          1359:         case 3:
        !          1360:                msg += "Time exceeded";
        !          1361:                break;
        !          1362:         case 4:
        !          1363:                msg += "Parameter Problem";
        !          1364:                break;
        !          1365:         case 128:
        !          1366:                msg += "Echo Request";
        !          1367:                break;
        !          1368:         case 129:
        !          1369:                msg += "Echo Reply";
        !          1370:                break;
        !          1371:         case 130:
        !          1372:                msg += "Multicast Listener Query";
        !          1373:                break;
        !          1374:         case 131:
        !          1375:                msg += "Multicast Listener Report";
        !          1376:                break;
        !          1377:         case 132:
        !          1378:                msg += "Multicast Listener Done";
        !          1379:                break;
        !          1380:         case 133:
        !          1381:                msg += "NDP Router Solicitation";
        !          1382:                break;
        !          1383:         case 134:
        !          1384:                msg += "NDP Router Advertisement";
        !          1385:                break;
        !          1386:         case 135:
        !          1387:                msg += "NDP Neighbor Solicitation";
        !          1388:                break;
        !          1389:         case 136:
        !          1390:                msg += "NDP Neighbor Advertisement";
        !          1391:                break;
        !          1392:         case 137:
        !          1393:                msg += "NDP Redirect";
        !          1394:                break;
        !          1395:         case 138:
        !          1396:                msg += "Router Renumber";
        !          1397:                break;
        !          1398:         case 139:
        !          1399:                msg += "ICMP Node Information Query";
        !          1400:                break;
        !          1401:         case 140:
        !          1402:                msg += "ICMP Node Information Reply";
        !          1403:                break;
        !          1404:         default:
        !          1405:                msg += string_format("Type=0x%02x Code=0x%02x", type, code);
        !          1406:                break;
        !          1407:        }
        !          1408:        lines.emplace_back(msg);
        !          1409: 
        !          1410:        return lines;
        !          1411: }
        !          1412: 
        !          1413: // ポート番号に対する名前を括弧をつけて返す。表示用。
        !          1414: // 名前が引けなければ空文字列を返す。
        !          1415: /*static*/ std::string
        !          1416: HostNetDevice::GetServByPort(uint16 port_be, const char *protoname)
        !          1417: {
        !          1418:        std::string name;
        !          1419: 
        !          1420:        // getservbyport() の引数はネットワークバイトオーダ…。
        !          1421:        // かつ、戻り値は内部のスタティックな領域を指している可能性がある。
        !          1422:        const struct servent *serv = getservbyport(port_be, protoname);
        !          1423:        if (serv) {
        !          1424:                name = string_format("(%s)", serv->s_name);
        !          1425:        }
        !          1426:        return name;
        !          1427: }
        !          1428: 
        !          1429: 
        !          1430: // IHWAddrFilter の デストラクタ
        !          1431: IHWAddrFilter::~IHWAddrFilter()
        !          1432: {
        !          1433: }

unix.superglobalmegacorp.com

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