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

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

unix.superglobalmegacorp.com

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