|
|
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);
135: monitor->func = ToMonitorCallback(&HostNetDevice::MonitorUpdate);
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 はどうするか?
406: if (packet.length < 1) {
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++;
415: stat.txqfull_bytes += packet.length;
416: putlog(2, "txq exhausted");
417: return false;
418: }
419:
420: stat.tx_pkts++;
421: stat.tx_bytes += packet.length;
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++;
444: stat.rxdisable_bytes += drop.length;
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: }
458: stat.rx_pkts++;
459: stat.rx_bytes += dst->length;
1.1.1.3 root 460: if (__predict_false(loglevel >= 2)) {
1.1.1.5 root 461: putlogn("Recv %u bytes", dst->length);
1.1.1.7 root 462: if (loglevel >= 4) {
1.1.1.3 root 463: std::string buf;
1.1.1.5 root 464: for (uint i = 0; i < dst->length; i++) {
1.1.1.3 root 465: if (i % 16 == 0) {
466: buf += string_format("%04x:", i);
467: }
468: buf += string_format(" %02x", (*dst)[i]);
469: if (i % 16 == 7) {
470: buf += " ";
471: } else if (i % 16 == 15) {
472: putlogn("%s", buf.c_str());
473: buf = "";
474: }
475: }
476: if (buf.empty() == false) {
477: putlogn("%s", buf.c_str());
478: }
479: }
480: }
1.1 root 481:
482: return true;
483: }
484:
485: // 外部からの読み込み (パケットを受信)。
486: // 戻り値はキューに投入したパケット数。
487: int
488: HostNetDevice::Read()
489: {
490: int queued = 0;
491: int left = 0;
492:
1.1.1.10 root 493: RWLockGuard_Read guard(driverlock);
1.1 root 494: assert((bool)driver);
495:
496: do {
497: NetPacket *p;
498:
499: p = rxq.BeginWrite();
500: if (p == NULL) {
501: NetPacket discard;
502: left = driver->Read(&discard);
503: if (left < 0) {
504: break;
505: }
506: stat.rxqfull_pkts++;
507: stat.rxqfull_bytes += discard.length;
508: continue;
509: }
510:
511: // driver->Read() は VM に投入すべきパケットがなければ負数を返す。
512: // パケットがあれば p に書き戻して、driver 側のバッファに残っている
513: // パケット数 (といっても 0 か 1以上) を返してくる。
514: left = driver->Read(p);
515: if (left < 0) {
516: rxq.CancelWrite();
517: break;
518: }
519:
520: NetPacket& packet = *p;
521:
522: stat.read_pkts++;
523: stat.read_bytes += packet.length;
524:
525: if (rx_enable == false) {
526: rxq.CancelWrite();
527: stat.rxdisable_pkts++;
528: stat.rxdisable_bytes += packet.length;
529: continue;
530: }
531:
532: // イーサネットフレームより長いパケットはゲスト OS が期待していない。
533: // ここでドロップしてみる。
534: // これによりゲストでの dropping chained buffer が出なくなる。
535: if (packet.length > 1518) {
536: rxq.CancelWrite();
537: stat.rxjumbo_pkts++;
538: stat.rxjumbo_bytes += packet.length;
539: continue;
540: }
541:
542: // ホストカーネルから直接着信したパケット(というかフレームか)は
543: // 60バイトパディングされないまま読み出せるので、ここでパディングする。
544: while (packet.length < 60) {
545: packet.Append(0x00);
546: }
547:
1.1.1.7 root 548: // デバイスがこのアドレス宛のフレームを受け取るか。
549: // 受け取らないと分かっているフレームは VM へのキューに入れる前に
550: // 落としておきたい。
551: MacAddr dstaddr(&packet[0]);
552: auto res = ihwaddrfilter->HWAddrFilter(dstaddr);
553: if (res != 0) {
554: switch (res) {
555: case IHWAddrFilter::HPF_DROP_UNICAST:
556: stat.rxnotme_pkts++;
557: stat.rxnotme_bytes += packet.length;
558: break;
559: case IHWAddrFilter::HPF_DROP_MULTICAST:
560: stat.rxmcast_pkts++;
561: stat.rxmcast_bytes += packet.length;
562: break;
563: default:
564: assertmsg(false, "corrupted res=%u", res);
1.1 root 565: }
1.1.1.7 root 566: rxq.CancelWrite();
567: continue;
1.1 root 568: }
569:
570: // CRC XXX 計算すること
571: for (int i = 0; i < 4; i++) {
572: packet.Append(0x00);
573: }
574:
575: rxq.EndWrite();
576: queued++;
577: } while (left > 0);
578:
579: // ざっくりピーク値
1.1.1.5 root 580: stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak);
1.1 root 581:
582: return queued;
583: }
584:
585: // 外部への書き出し(パケットを送信)
586: void
1.1.1.9 root 587: HostNetDevice::Write()
1.1 root 588: {
589: const NetPacket *p;
590:
1.1.1.10 root 591: RWLockGuard_Read guard(driverlock);
1.1 root 592: assert((bool)driver);
593:
594: // 送信キューから取り出す
595: while ((p = txq.BeginRead()) != NULL) {
596: const NetPacket& packet = *p;
597:
1.1.1.3 root 598: if (__predict_false(loglevel >= 2)) {
1.1.1.5 root 599: putlogn("Send %u bytes", packet.length);
1.1.1.7 root 600: if (loglevel >= 4) {
1.1.1.3 root 601: std::string buf;
1.1.1.5 root 602: for (uint i = 0; i < packet.length; i++) {
1.1.1.3 root 603: if (i % 16 == 0) {
604: buf += string_format("%04x:", i);
605: }
606: buf += string_format(" %02x", packet[i]);
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++;
620: stat.write_bytes += packet.length;
621:
622: driver->Write(packet.data(), packet.length);
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
648: HostNetDevice::MonitorUpdate(Monitor *, TextScreen& screen)
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行はドライバ依存情報
658: driver->MonitorUpdateMD(screen, 2);
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:
1496: // IHWAddrFilter の デストラクタ
1497: IHWAddrFilter::~IHWAddrFilter()
1498: {
1499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.