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

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

unix.superglobalmegacorp.com

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