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

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

unix.superglobalmegacorp.com

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