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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // ネットワークのホストデバイス
                      9: //
                     10: 
                     11: // ログ名
                     12: //       Ethernet    HostDevice       NetDriver
                     13: //         |          |                |
                     14: //         v          v                v
                     15: //        Lance   -> HostNetDevice -> NetDriver***
1.1.1.3   root       16: // 表示名 (Lance)    (HostNet0)      (HostNet0.***)
                     17: // 識別名 "lance"    "hostnet0"      "hostnet0"
1.1       root       18: //
1.1.1.3   root       19: // HostNet は、特に NetDriver 派生クラス選択時はフォールバックも含めて
                     20: // どれが選択されるか複雑なこともあるので、ログ表示名に自分のドライバ名
1.1       root       21: // も表示したい。
                     22: 
                     23: #include "hostnet.h"
                     24: #include "config.h"
1.1.1.6 ! root       25: #include "monitor.h"
1.1       root       26: #include "netdriver_none.h"
                     27: #if defined(HAVE_HOSTNET_AFPACKET)
                     28: #include "netdriver_afpacket.h"
                     29: #endif
                     30: #if defined(HAVE_HOSTNET_BPF)
                     31: #include "netdriver_bpf.h"
                     32: #endif
                     33: #if defined(HAVE_HOSTNET_TAP)
                     34: #include "netdriver_tap.h"
                     35: #endif
1.1.1.4   root       36: #include <zlib.h>
1.1       root       37: 
                     38: // コンパイル済みのドライバ名一覧を返す (MainApp から呼ばれる)
                     39: /*static*/ std::vector<std::string>
                     40: HostNetDevice::GetDrivers()
                     41: {
                     42:        std::vector<std::string> list;
                     43: 
                     44: #if defined(HAVE_HOSTNET_AFPACKET)
                     45:        list.emplace_back("afpacket");
                     46: #endif
                     47: #if defined(HAVE_HOSTNET_BPF)
                     48:        list.emplace_back("bpf");
                     49: #endif
                     50: #if defined(HAVE_HOSTNET_TAP)
                     51:        list.emplace_back("tap");
                     52: #endif
                     53: 
                     54:        return list;
                     55: }
                     56: 
                     57: 
                     58: // コンストラクタ
1.1.1.5   root       59: HostNetDevice::HostNetDevice(Device *parent_, uint n)
1.1.1.3   root       60:        : inherited(parent_, OBJ_HOSTNET(n))
1.1       root       61: {
1.1.1.6 ! root       62:        monitor = gMonitorManager->Regist(ID_MONITOR_HOSTNET(n), this);
        !            63:        monitor->func = ToMonitorCallback(&HostNetDevice::MonitorUpdate);
        !            64:        monitor->SetSize(48, 23);
1.1       root       65: }
                     66: 
                     67: // デストラクタ
                     68: HostNetDevice::~HostNetDevice()
                     69: {
                     70: }
                     71: 
                     72: // ログレベル設定
                     73: void
                     74: HostNetDevice::SetLogLevel(int loglevel_)
                     75: {
                     76:        inherited::SetLogLevel(loglevel_);
                     77: 
                     78:        if ((bool)driver) {
                     79:                driver->SetLogLevel(loglevel_);
                     80:        }
                     81: }
                     82: 
                     83: // 初期化
                     84: bool
                     85: HostNetDevice::Init()
                     86: {
                     87:        if (inherited::Init() == false) {
                     88:                return false;
                     89:        }
                     90: 
                     91:        if (SelectDriver() == false) {
                     92:                return false;
                     93:        }
                     94: 
                     95:        return true;
                     96: }
                     97: 
                     98: // ドライバ(再)選択
                     99: bool
                    100: HostNetDevice::SelectDriver()
                    101: {
1.1.1.3   root      102:        int n = GetId() - OBJ_HOSTNET0;
                    103:        const std::string key_driver = string_format("hostnet%d-driver", n);
                    104:        const std::string key_fallback = string_format("hostnet%d-fallback", n);
                    105:        const ConfigItem& item = gConfig->Find(key_driver);
1.1       root      106:        const std::string& type = item.AsString();
1.1.1.3   root      107:        bool fallback = gConfig->Find(key_fallback).AsInt();
1.1       root      108: 
                    109:        driver.reset();
                    110: 
                    111:        if (type != "none") {
                    112:                if (type == "tap") {
                    113: #if defined(HAVE_HOSTNET_TAP)
                    114:                        CreateTap();
                    115: #else
1.1.1.2   root      116:                        item.Err("Hostnet driver %s not compiled", type.c_str());
1.1       root      117: #endif
                    118: 
                    119:                } else if (type == "bpf") {
                    120: #if defined(HAVE_HOSTNET_BPF)
                    121:                        CreateBPF();
                    122: #else
1.1.1.2   root      123:                        item.Err("Hostnet driver %s not compiled", type.c_str());
1.1       root      124: #endif
                    125: 
                    126:                } else if (type == "afpacket") {
                    127: #if defined(HAVE_HOSTNET_AFPACKET)
                    128:                        CreateAFPacket();
                    129: #else
1.1.1.2   root      130:                        item.Err("Hostnet driver %s not compiled", type.c_str());
1.1       root      131: #endif
                    132: 
                    133:                } else if (type == "auto") {
                    134:                        // auto なら Tap -> { BPF, AFPacket } の順で試す。
                    135:                        //
                    136:                        // Tap は事前の準備が面倒だが制約がない。
                    137:                        // BPF, AFPacket (この2つは OS の違いだけでほぼ同じもの) は
                    138:                        // 準備に手間がかからないが自ホストと通信できない制約がある。
                    139:                        // そのためどの環境でも Tap が使えれば Tap を、そうでなければ
                    140:                        // BPF, AFPacket を使う、という順にしておく。
                    141:                        bool r;
                    142: 
                    143:                        r = CreateTap();
                    144:                        if (r == false) {
                    145:                                r = CreateAFPacket();
                    146:                        }
                    147:                        if (r == false) {
                    148:                                r = CreateBPF();
                    149:                        }
                    150: 
                    151:                } else {
                    152:                        // 知らないドライバ種別
                    153:                        item.Err();
                    154:                }
                    155: 
                    156:                if ((bool)driver == false) {
                    157:                        putmsg(1, "hostnet-fallback=%d", fallback ? 1 : 0);
                    158: 
                    159:                        if (fallback == false) {
                    160:                                // フォールバックしないならエラー終了
                    161:                                errmsg = "No host network driver found";
                    162:                                putmsg(1, "%s", errmsg.c_str());
                    163:                                warnx("%s (See details with options -C -Lhostnet=1)",
                    164:                                        errmsg.c_str());
                    165: 
                    166:                                return false;
                    167:                        }
                    168:                }
                    169:        }
                    170: 
                    171:        if ((bool)driver == false) {
                    172:                CreateNone();
                    173:        }
                    174:        assert((bool)driver);
                    175: 
                    176:        // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
                    177:        putmsg(1, "selected host driver: %s",
                    178:                string_tolower(driver->GetDriverName()).c_str());
                    179: 
                    180:        return true;
                    181: }
                    182: 
                    183: // None ドライバを生成する
                    184: bool
                    185: HostNetDevice::CreateNone()
                    186: {
                    187:        driver.reset(new NetDriverNone(this));
                    188:        if ((bool)driver) {
                    189:                if (driver->InitDriver()) {
                    190:                        // 成功
                    191:                        return true;
                    192:                }
                    193:                errmsg = driver->errmsg;
                    194:                driver.reset();
                    195:        }
                    196:        return false;
                    197: }
                    198: 
                    199: // Tap ドライバを生成する
                    200: bool
                    201: HostNetDevice::CreateTap()
                    202: {
                    203: #if defined(HAVE_HOSTNET_TAP)
1.1.1.3   root      204:        int n = GetId() - OBJ_HOSTNET0;
                    205:        const std::string keyname = string_format("hostnet%d-tap-devpath", n);
                    206:        const ConfigItem& item = gConfig->Find(keyname);
1.1       root      207:        const std::string& devpath = item.AsString();
                    208: 
                    209:        driver.reset(new NetDriverTap(this, devpath));
                    210:        if ((bool)driver) {
                    211:                if (driver->InitDriver()) {
                    212:                        // 成功
                    213:                        return true;
                    214:                }
                    215:                errmsg = driver->errmsg;
                    216:                driver.reset();
                    217:        }
                    218: #endif
                    219:        return false;
                    220: }
                    221: 
                    222: // bpf ドライバを生成する
                    223: bool
                    224: HostNetDevice::CreateBPF()
                    225: {
                    226: #if defined(HAVE_HOSTNET_BPF)
1.1.1.3   root      227:        int n = GetId() - OBJ_HOSTNET0;
                    228:        const std::string keyname = string_format("hostnet%d-bpf-ifname", n);
                    229:        const ConfigItem& item = gConfig->Find(keyname);
1.1       root      230:        const std::string& ifname = item.AsString();
                    231: 
                    232:        driver.reset(new NetDriverBPF(this, ifname));
                    233:        if ((bool)driver) {
                    234:                if (driver->InitDriver()) {
                    235:                        // 成功
                    236:                        return true;
                    237:                }
                    238:                errmsg = driver->errmsg;
                    239:                driver.reset();
                    240:        }
                    241: #endif
                    242:        return false;
                    243: }
                    244: 
                    245: // AFPacket ドライバを生成する
                    246: bool
                    247: HostNetDevice::CreateAFPacket()
                    248: {
                    249: #if defined(HAVE_HOSTNET_AFPACKET)
1.1.1.3   root      250:        int n = GetId() - OBJ_HOSTNET0;
                    251:        const std::string keyname = string_format("hostnet%d-afpacket-ifname", n);
                    252:        const ConfigItem& item = gConfig->Find(keyname);
1.1       root      253:        const std::string& ifname = item.AsString();
                    254: 
                    255:        driver.reset(new NetDriverAFPacket(this, ifname));
                    256:        if ((bool)driver) {
                    257:                if (driver->InitDriver()) {
                    258:                        // 成功
                    259:                        return true;
                    260:                }
                    261:                errmsg = driver->errmsg;
                    262:                driver.reset();
                    263:        }
                    264: #endif
                    265:        return false;
                    266: }
                    267: 
                    268: // VM からの送信 (VM スレッドで呼ばれる)
                    269: bool
                    270: HostNetDevice::Tx(const NetPacket& packet)
                    271: {
1.1.1.5   root      272:        // 長さ 0 のパケットは破棄する。バグでもないと通常は起きない。
                    273:        // runt frame はどうするか?
                    274:        if (packet.length < 1) {
                    275:                stat.txzero_pkts++;
                    276:                putlog(1, "Tx: drop empty packet");
                    277:                return true;
                    278:        }
                    279: 
1.1       root      280:        // 送信キューに入れて..
                    281:        if (txq.Enqueue(packet) == false) {
                    282:                stat.txqfull_pkts++;
                    283:                stat.txqfull_bytes += packet.length;
                    284:                putlog(2, "txq exhausted");
                    285:                return false;
                    286:        }
                    287: 
                    288:        stat.tx_pkts++;
                    289:        stat.tx_bytes += packet.length;
                    290: 
                    291:        // ざっくりピーク値
1.1.1.5   root      292:        stat.txq_peak = std::max((uint)txq.Length(), stat.txq_peak);
1.1       root      293: 
                    294:        // パイプに通知 (値はダミー)
                    295:        return WritePipe(0);
                    296: }
                    297: 
1.1.1.6 ! root      298: // rxq への投入を行う場合は true。
        !           299: // VM スレッドから呼ばれる。
1.1       root      300: void
                    301: HostNetDevice::EnableRx(bool enable)
                    302: {
                    303:        rx_enable = enable;
1.1.1.6 ! root      304: 
        !           305:        // 受信を停止した時はキューに残っているのを破棄する。
        !           306:        // (ゲスト再起動によるデバイスリセット時とか)
        !           307:        if (rx_enable == false) {
        !           308:                // 統計情報に足すためだけに一旦取り出す。
        !           309:                NetPacket drop;
        !           310:                while (rxq.Dequeue(&drop)) {
        !           311:                        stat.rxdisable_pkts++;
        !           312:                        stat.rxdisable_bytes += drop.length;
        !           313:                }
        !           314:        }
1.1       root      315: }
                    316: 
1.1.1.3   root      317: // 受信用の自身の MAC アドレスを設定する。
1.1       root      318: void
                    319: HostNetDevice::SetMyAddr(const macaddr_t& myaddr_)
                    320: {
                    321:        myaddr = myaddr_;
                    322: }
                    323: 
1.1.1.4   root      324: // マルチキャストフィルタを設定する。
                    325: void
                    326: HostNetDevice::SetMCastFilter(uint64 filter_)
                    327: {
                    328:        multicast_filter = filter_;
                    329: }
                    330: 
1.1       root      331: // プロミスキャスモードを設定する。
                    332: void
                    333: HostNetDevice::SetPromisc(bool promisc_)
                    334: {
                    335:        promisc = promisc_;
                    336: }
                    337: 
                    338: // パケットをキューから取り出す。
                    339: // VM 側から呼ばれる。
                    340: bool
                    341: HostNetDevice::Rx(NetPacket *dst)
                    342: {
                    343:        if (rxq.Dequeue(dst) == false) {
                    344:                // キューが空
                    345:                return false;
                    346:        }
                    347:        stat.rx_pkts++;
                    348:        stat.rx_bytes += dst->length;
1.1.1.3   root      349:        if (__predict_false(loglevel >= 2)) {
1.1.1.5   root      350:                putlogn("Recv %u bytes", dst->length);
1.1.1.3   root      351:                if (loglevel >= 3) {
                    352:                        std::string buf;
1.1.1.5   root      353:                        for (uint i = 0; i < dst->length; i++) {
1.1.1.3   root      354:                                if (i % 16 == 0) {
                    355:                                        buf += string_format("%04x:", i);
                    356:                                }
                    357:                                buf += string_format(" %02x", (*dst)[i]);
                    358:                                if (i % 16 == 7) {
                    359:                                        buf += " ";
                    360:                                } else if (i % 16 == 15) {
                    361:                                        putlogn("%s", buf.c_str());
                    362:                                        buf = "";
                    363:                                }
                    364:                        }
                    365:                        if (buf.empty() == false) {
                    366:                                putlogn("%s", buf.c_str());
                    367:                        }
                    368:                }
                    369:        }
1.1       root      370: 
                    371:        return true;
                    372: }
                    373: 
                    374: // 外部からの読み込み (パケットを受信)。
                    375: // 戻り値はキューに投入したパケット数。
                    376: int
                    377: HostNetDevice::Read()
                    378: {
                    379:        int queued = 0;
                    380:        int left = 0;
                    381: 
                    382:        assert((bool)driver);
                    383: 
                    384:        do {
                    385:                NetPacket *p;
                    386: 
                    387:                p = rxq.BeginWrite();
                    388:                if (p == NULL) {
                    389:                        NetPacket discard;
                    390:                        left = driver->Read(&discard);
                    391:                        if (left < 0) {
                    392:                                break;
                    393:                        }
                    394:                        stat.rxqfull_pkts++;
                    395:                        stat.rxqfull_bytes += discard.length;
                    396:                        continue;
                    397:                }
                    398: 
                    399:                // driver->Read() は VM に投入すべきパケットがなければ負数を返す。
                    400:                // パケットがあれば p に書き戻して、driver 側のバッファに残っている
                    401:                // パケット数 (といっても 0 か 1以上) を返してくる。
                    402:                left = driver->Read(p);
                    403:                if (left < 0) {
                    404:                        rxq.CancelWrite();
                    405:                        break;
                    406:                }
                    407: 
                    408:                NetPacket& packet = *p;
                    409: 
                    410:                stat.read_pkts++;
                    411:                stat.read_bytes += packet.length;
                    412: 
                    413:                if (rx_enable == false) {
                    414:                        rxq.CancelWrite();
                    415:                        stat.rxdisable_pkts++;
                    416:                        stat.rxdisable_bytes += packet.length;
                    417:                        continue;
                    418:                }
                    419: 
                    420:                // イーサネットフレームより長いパケットはゲスト OS が期待していない。
                    421:                // ここでドロップしてみる。
                    422:                // これによりゲストでの dropping chained buffer が出なくなる。
                    423:                if (packet.length > 1518) {
                    424:                        rxq.CancelWrite();
                    425:                        stat.rxjumbo_pkts++;
                    426:                        stat.rxjumbo_bytes += packet.length;
                    427:                        continue;
                    428:                }
                    429: 
                    430:                // ホストカーネルから直接着信したパケット(というかフレームか)は
                    431:                // 60バイトパディングされないまま読み出せるので、ここでパディングする。
                    432:                while (packet.length < 60) {
                    433:                        packet.Append(0x00);
                    434:                }
                    435: 
                    436:                // パケットフィルタリング
                    437:                if (__predict_true(promisc == false)) {
1.1.1.4   root      438:                        static std::array<uint8, 6> bcast {
                    439:                                0xff, 0xff, 0xff, 0xff, 0xff, 0xff
                    440:                        };
                    441:                        if (memcmp(&packet[0], &bcast[0], bcast.size()) == 0) {
                    442:                                // ブロードキャストは素通し。
                    443:                        } else if (__predict_false(packet[0] & 1)) {
                    444:                                // マルチキャスト。
1.1       root      445:                                // LANCE では LADRF レジスタ、NE2000 では MAR0-7 レジスタで
1.1.1.4   root      446:                                // データシートを見る限りはロジックは同じもののようだ。
1.1       root      447: 
1.1.1.4   root      448:                                // 宛先アドレスの CRC32 を計算する。
                    449:                                // イーサネットの CRC は zlib の crc32() と同じもの。
1.1.1.5   root      450:                                uint32 crc = crc32(0, Z_NULL, 0);
1.1.1.4   root      451:                                crc = crc32(crc, &packet[0], 6);
                    452: 
                    453:                                // crc の上位6ビットをとりだして検査ビット位置とする(=pos)。
                    454:                                // multicast_filter の pos の位置のビットが 1 なら受信、
                    455:                                // 0 なら破棄。
                    456:                                // multicast_filter は64ビットで LSB が0番目、MSB が63番目
                    457:                                // としたもの (NIC 側でこの通りに並べ替えて渡してある)。
                    458:                                uint pos = (crc >> 26) & 0x3f;
                    459:                                uint64 bit = 1U << pos;
1.1       root      460:                                if ((multicast_filter & bit) == 0) {
1.1.1.4   root      461:                                        putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d drop",
                    462:                                                packet[0], packet[1], packet[2],
                    463:                                                packet[3], packet[4], packet[5], pos);
                    464:                                        stat.rxmcast_pkts++;
                    465:                                        stat.rxmcast_bytes += packet.length;
                    466:                                        rxq.CancelWrite();
                    467:                                        continue;
1.1       root      468:                                }
1.1.1.4   root      469:                                putlog(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%d pass",
                    470:                                        packet[0], packet[1], packet[2],
                    471:                                        packet[3], packet[4], packet[5], pos);
1.1       root      472:                        } else {
                    473:                                // ユニキャスト
                    474:                                if (memcmp(&packet[0], &myaddr[0], 6) != 0) {
1.1.1.4   root      475:                                        stat.rxnotme_pkts++;
                    476:                                        stat.rxnotme_bytes += packet.length;
                    477:                                        rxq.CancelWrite();
                    478:                                        continue;
1.1       root      479:                                }
                    480:                        }
                    481:                }
                    482: 
                    483:                // CRC XXX 計算すること
                    484:                for (int i = 0; i < 4; i++) {
                    485:                        packet.Append(0x00);
                    486:                }
                    487: 
                    488:                rxq.EndWrite();
                    489:                queued++;
                    490:        } while (left > 0);
                    491: 
                    492:        // ざっくりピーク値
1.1.1.5   root      493:        stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak);
1.1       root      494: 
                    495:        return queued;
                    496: }
                    497: 
                    498: // 外部への書き出し(パケットを送信)
                    499: void
                    500: HostNetDevice::Write(uint32 data)
                    501: {
                    502:        const NetPacket *p;
                    503: 
                    504:        assert((bool)driver);
                    505: 
                    506:        // 送信キューから取り出す
                    507:        while ((p = txq.BeginRead()) != NULL) {
                    508:                const NetPacket& packet = *p;
                    509: 
1.1.1.3   root      510:                if (__predict_false(loglevel >= 2)) {
1.1.1.5   root      511:                        putlogn("Send %u bytes", packet.length);
1.1.1.3   root      512:                        if (loglevel >= 3) {
                    513:                                std::string buf;
1.1.1.5   root      514:                                for (uint i = 0; i < packet.length; i++) {
1.1.1.3   root      515:                                        if (i % 16 == 0) {
                    516:                                                buf += string_format("%04x:", i);
                    517:                                        }
                    518:                                        buf += string_format(" %02x", packet[i]);
                    519:                                        if (i % 16 == 7) {
                    520:                                                buf += " ";
                    521:                                        } else if (i % 16 == 15) {
                    522:                                                putlogn("%s", buf.c_str());
                    523:                                                buf = "";
                    524:                                        }
                    525:                                }
                    526:                                if (buf.empty() == false) {
                    527:                                        putlogn("%s", buf.c_str());
                    528:                                }
                    529:                        }
                    530:                }
1.1       root      531:                stat.write_pkts++;
                    532:                stat.write_bytes += packet.length;
                    533: 
                    534:                driver->Write(packet.data(), packet.length);
                    535:                txq.EndRead();
                    536:        }
                    537: }
                    538: 
                    539: // ドライバ名を返す
                    540: const std::string
                    541: HostNetDevice::GetDriverName() const
                    542: {
                    543:        assert((bool)driver);
                    544:        return driver->GetDriverName();
                    545: }
                    546: 
                    547: // モニタ
                    548: void
                    549: HostNetDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    550: {
                    551:        screen.Clear();
                    552: 
1.1.1.3   root      553:        screen.Print(0, 0, "Parent Device : %s", parent->GetName().c_str());
                    554:        screen.Print(0, 1, "HostNet Driver: %s", driver->GetDriverName());
1.1       root      555:        // 次の2行はドライバ依存情報
1.1.1.3   root      556:        driver->MonitorUpdateMD(screen, 2);
1.1       root      557: 
                    558:        // 01234567890123456
                    559:        // Write to host
                    560:        // Drop:TxQ Full
                    561:        // Drop:Rx Disabled
                    562:        // Drop:Jumbo Frame
                    563:        // Drop:Addr Filter
                    564: 
1.1.1.3   root      565:        int y = 5;
1.1       root      566:        screen.Print(0, y++, "%-17s%13s %17s", "<Tx>", "Packets", "Bytes");
                    567:        screen.Print(0, y++, "%-17s%13s %17s", "VM sends",
                    568:                format_number(stat.tx_pkts).c_str(),
                    569:                format_number(stat.tx_bytes).c_str());
                    570:        screen.Print(0, y++, "%-17s%13s %17s", "Write to host",
                    571:                format_number(stat.write_pkts).c_str(),
                    572:                format_number(stat.write_bytes).c_str());
1.1.1.5   root      573:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Empty Frame",
                    574:                format_number(stat.txzero_pkts).c_str(),
                    575:                "0");
1.1       root      576:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:TxQ Full",
                    577:                format_number(stat.txqfull_pkts).c_str(),
                    578:                format_number(stat.txqfull_bytes).c_str());
                    579:        y++;
                    580: 
                    581:        screen.Print(0, y++, "%-17s%13s %17s", "<Rx>", "Packets", "Bytes");
                    582:        screen.Print(0, y++, "%-17s%13s %17s", "Read from host",
                    583:                format_number(stat.read_pkts).c_str(),
                    584:                format_number(stat.read_bytes).c_str());
                    585:        screen.Print(0, y++, "%-17s%13s %17s", "VM receives",
                    586:                format_number(stat.rx_pkts).c_str(),
                    587:                format_number(stat.rx_bytes).c_str());
                    588:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Rx Disabled",
                    589:                format_number(stat.rxdisable_pkts).c_str(),
                    590:                format_number(stat.rxdisable_bytes).c_str());
                    591:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Jumbo Frame",
                    592:                format_number(stat.rxjumbo_pkts).c_str(),
                    593:                format_number(stat.rxjumbo_bytes).c_str());
                    594:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:RxQ Full",
                    595:                format_number(stat.rxqfull_pkts).c_str(),
                    596:                format_number(stat.rxqfull_bytes).c_str());
1.1.1.4   root      597:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unicast",
                    598:                format_number(stat.rxnotme_pkts).c_str(),
                    599:                format_number(stat.rxnotme_bytes).c_str());
                    600:        screen.Print(0, y++, "%-17s%13s %17s", "Drop:Multicast",
                    601:                format_number(stat.rxmcast_pkts).c_str(),
                    602:                format_number(stat.rxmcast_bytes).c_str());
1.1       root      603:        y++;
                    604: 
                    605:        screen.Print(5, y++, "Capacity Peak");
1.1.1.5   root      606:        screen.Print(0, y++, "TxQ %4u/%4u %4u",
                    607:                (uint)txq.Length(), (uint)txq.Capacity(), stat.txq_peak);
                    608:        screen.Print(0, y++, "RxQ %4u/%4u %4u",
                    609:                (uint)rxq.Length(), (uint)rxq.Capacity(), stat.rxq_peak);
1.1       root      610: }

unix.superglobalmegacorp.com

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