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