|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "netdriver.h"
1.1.1.6 ! root 8: #include "autofd.h"
! 9: #include "cvprompt.h"
1.1.1.2 root 10: #include "mainapp.h"
1.1.1.3 root 11: #include "mythread.h"
1.1.1.6 ! root 12: #include <sys/wait.h>
! 13: #if defined(HAVE_SYS_EVENT_H)
! 14: #include <sys/event.h>
! 15: #endif
! 16: #if defined(HAVE_KQUEUE_SYS_EVENT_H)
! 17: #include <kqueue/sys/event.h>
! 18: #endif
1.1 root 19:
20: static void *netdriver_run(void *);
21:
1.1.1.2 root 22: std::unique_ptr<NetDriver> gNetDriver;
1.1 root 23:
24: // コンストラクタ
1.1.1.3 root 25: NetDriver::NetDriver(const char *drivername_, EthernetDevice *parent_,
1.1.1.6 ! root 26: int loglevel_)
! 27: : inherited(std::string("HostNet") + drivername_)
1.1 root 28: {
1.1.1.6 ! root 29: loglevel = loglevel_;
1.1.1.3 root 30: drivername = drivername_;
31: parent = parent_;
1.1.1.6 ! root 32: fd = -1;
! 33:
! 34: monitor.func = (MonitorCallback_t)&NetDriver::MonitorUpdate;
! 35: monitor.SetSize(30, 7);
! 36: monitor.Regist(ID_MONITOR_HOSTNET);
1.1 root 37: }
38:
39: // デストラクタ
40: NetDriver::~NetDriver()
41: {
42: }
43:
1.1.1.6 ! root 44: // 初期化
! 45: bool
! 46: NetDriver::Init()
1.1 root 47: {
1.1.1.6 ! root 48: // 対応する EthernetDevice があれば受信スレッド起動。
! 49: // NetDriverNone は連携不要なので parent == NULL になっている。
! 50: if (parent) {
! 51: pthread_t th;
! 52: int error;
! 53:
! 54: error = pthread_create(&th, NULL, netdriver_run, NULL);
! 55: if (error) {
! 56: putmsg(0, "pthread_create: %s", strerror(error));
! 57: return false;
! 58: }
! 59: }
! 60: return true;
1.1 root 61: }
62:
1.1.1.6 ! root 63: // モニタ
! 64: void
! 65: NetDriver::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 66: {
1.1.1.6 ! root 67: screen.Clear();
1.1 root 68:
1.1.1.6 ! root 69: screen.Print(0, 0, "HostNet Driver: %s", drivername);
! 70: // 次の2行はドライバ依存情報
! 71: MonitorUpdateMD(screen);
! 72:
! 73: screen.Print(5, 4, "%9s %9s", "Packets", "Bytes");
! 74: screen.Print(0, 5, "Send %9" PRIu64 " %9" PRIu64, tx_pkts, tx_bytes);
! 75: screen.Print(0, 6, "Recv %9" PRIu64 " %9" PRIu64, rx_pkts, rx_bytes);
1.1 root 76: }
77:
78: // 受信スレッドのエントリポイント
79: void *
80: netdriver_run(void *dummy)
81: {
1.1.1.6 ! root 82: PTHREAD_SETNAME("NetDriver");
1.1 root 83: pthread_detach(pthread_self());
84:
85: gNetDriver->ThreadRun();
86: return NULL;
87: }
88:
89: // ifup スクリプト実行
90: bool
91: NetDriver::Run_ifup()
92: {
93: return RunScript("nono-ifup");
94: }
95:
96: // ifdown スクリプト実行
97: bool
98: NetDriver::Run_ifdown()
99: {
100: return RunScript("nono-ifdown");
101: }
102:
103: // スクリプトを実行
104: bool
105: NetDriver::RunScript(const char *filename)
106: {
1.1.1.6 ! root 107: std::string cmd;
! 108: int r;
! 109:
1.1 root 110: // ファイルが存在するか
1.1.1.2 root 111: std::string path = gMainApp.SearchFile(filename);
1.1 root 112: if (path.empty()) {
1.1.1.6 ! root 113: errmsg = string_format("%s not found", filename);
! 114: goto abort;
1.1 root 115: }
116:
117: // コマンドラインを作成
1.1.1.6 ! root 118: cmd = path + " " + ifname;
! 119: putmsg(1, "%s: command: %s", __func__, cmd.c_str());
1.1 root 120:
121: // 実行
1.1.1.6 ! root 122: r = system(cmd.c_str());
! 123: if (r == -1) {
! 124: errmsg = string_format("system(\"%s\"): %s",
! 125: cmd.c_str(), strerror(errno));
! 126: goto abort;
! 127: }
! 128:
! 129: if (WIFEXITED(r)) {
! 130: int exitcode = WEXITSTATUS(r);
! 131: if (exitcode == 0) {
! 132: // ここが正常終了
! 133: putmsg(1, "%s: \"%s\" exited successfully", __func__, cmd.c_str());
! 134: return true;
! 135: }
! 136: if (exitcode == 127) {
! 137: errmsg = string_format("\"%s\": shell execution failed",
! 138: cmd.c_str());
! 139: } else {
! 140: errmsg = string_format("\"%s\" exited with code %d",
! 141: cmd.c_str(), exitcode);
! 142: }
! 143: } else if (WIFSIGNALED(r)) {
! 144: int signo = WTERMSIG(r);
! 145: errmsg = string_format("\"%s\" terminated with signal %d",
! 146: cmd.c_str(), signo);
! 147: } else {
! 148: // どうしたらいいかよく分からんのでとりあえず表示だけ。
! 149: errmsg = string_format("\"%s\" terminated:"
! 150: "IFSTOPPED=%d STOPSIG=%d IFCONTINUED=%d COREDUMP=%d",
! 151: cmd.c_str(),
! 152: WIFSTOPPED(r), WSTOPSIG(r), WIFCONTINUED(r), WCOREDUMP(r));
! 153: }
! 154:
! 155: abort:
! 156: putmsg(1, "%s: %s", __func__, errmsg.c_str());
! 157: return false;
! 158: }
! 159:
! 160: // VM 側の受信パケットキューにパケットを一つ追加する
! 161: void
! 162: NetDriver::RecvEnqueue(uint8 *ptr, size_t len)
! 163: {
! 164: RXPacket packet { new qvector<uint8>(ptr, ptr + len) };
! 165:
! 166: // ホストカーネルから直接着信したパケット(というかフレームか)は
! 167: // 60バイトパディングされないまま読み出せるので、ここでパディングする。
! 168: if (len < 60) {
! 169: for (int i = len ; i < 60; i++) {
! 170: packet->append(0);
! 171: }
! 172: }
! 173:
! 174: // CRC XXX 計算すること
! 175: for (int i = 0; i < 4; i++) {
! 176: packet->append(0);
! 177: }
! 178:
! 179: size_t n = packet->size();
! 180:
! 181: // 受信処理に引き渡す
! 182: // ただしデバッガプロンプトで停止してる状態なら VM に干渉しない。
! 183: if (gCVPrompt->IsPrompt() == false) {
! 184: putlog(2, "RecvPacket %zd bytes", n);
! 185: rx_pkts++;
! 186: rx_bytes += n;
! 187: parent->RecvPacket(std::move(packet));
! 188: }
! 189: }
! 190:
! 191: // 受信スレッド
! 192: void
! 193: NetDriver::ThreadRun()
! 194: {
! 195: struct kevent kev;
! 196: autofd kq;
! 197: int r;
! 198:
! 199: kq = kqueue();
! 200: if (kq == -1) {
! 201: warn("NetDriver: kqueue");
! 202: return;
! 203: }
! 204:
! 205: EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, (kevent_udata_t)0);
! 206: r = kevent_set(kq, &kev, 1);
! 207: if (r == -1) {
! 208: warn("NetDriver: kevent_set(fd=%d)", fd);
! 209: return;
! 210: }
! 211:
! 212: for (;;) {
! 213: ssize_t n;
! 214:
! 215: // 何か起きるまで待つ
! 216: r = kevent_poll(kq, &kev, 1, NULL);
! 217: if (r == -1) {
! 218: if (errno == EINTR) {
! 219: continue;
! 220: }
! 221: // XXX ?
! 222: warn("NetDriver: kevent_poll");
! 223: break;
! 224: }
! 225:
! 226: // 自動的にデバイスに着信があったことになるはず
! 227: assert(r > 0);
! 228:
! 229: // パケットを読み込んで VM に引き渡す。
! 230: n = RecvPacket();
! 231: if (n == -1) {
! 232: if (errno == EINTR) {
! 233: continue;
! 234: }
! 235: warn("NetDriver: read");
! 236: break;
! 237: }
! 238: if (n == 0) { // EOF
! 239: return;
! 240: }
1.1 root 241: }
242: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.