4.5. TCPモジュール
自作プロトコルスタックの最後のモジュール、TCPを移植します。
TCPモジュールのコードのコピー
TCPモジュールのコードをmicropsからコピーします。修正は不要で、そのまま利用できます。
$ cp $MICROPS/tcp.{h,c} kernel/net/
乱数関数の追加
TCPは初期シーケンス番号(ISS)の生成にrandom()を使用します。簡易libcにrandom()とsrand()を追加します。
📝 kernel/net/platform/xv6-riscv/libc/stdlib.c
#include <stdlib.h>
long
strtol(const char *s, char **endptr, int base)
{
...
}
+
+static unsigned int seed = 1;
+
+void
+srand(unsigned int newseed)
+{
+ seed = newseed;
+}
+
+long
+random(void)
+{
+ /* Linear Congruential Generator (LCG) */
+ seed = (seed * 1103515245 + 12345) % 0x7fffffff;
+ return seed;
+}
📝 kernel/net/platform/xv6-riscv/libc/stdlib.h
#ifndef STDLIB_H
#define STDLIB_H
#include <sys/types.h>
extern long
strtol(const char *s, char **endptr, int base);
+extern void
+srand(unsigned int newseed);
+extern long
+random(void);
+
#endif
初期化関数の呼び出し
net.cでTCPモジュールのヘッダをインクルードし、net_init()からtcp_init()を呼び出すようにします。これで、コメントアウトしていた全モジュールの初期化が揃います。
📝 kernel/net/net.c
...
-//#include "tcp.h"
+#include "tcp.h"
int
net_init(void)
{
...
-// if (tcp_init() == -1) {
-// errorf("tcp_init() failure");
-// return -1;
-// }
+ if (tcp_init() == -1) {
+ errorf("tcp_init() failure");
+ return -1;
+ }
infof("success");
return 0;
}
...
Makefileの修正
tcp.oをビルド対象に追加します。
📝 Makefile
...
$N/icmp.o \
$N/udp.o \
+ $N/tcp.o \
$P/platform.o \
...
動作確認
再ビルドした後、make qemuを実行してxv6を起動します。起動ログから、プロトコル番号6(TCP)がIPモジュールに登録されていることが確認できます。
10:00:00.101 [I] ip_protocol_register: success, protocol=1 (kernel/net/ip.c:290)
10:00:00.102 [I] ip_protocol_register: success, protocol=17 (kernel/net/ip.c:290)
10:00:00.103 [I] ip_protocol_register: success, protocol=6 (kernel/net/ip.c:290)
TCPの接続を試すアプリケーションはまだ無いので、ここではプロトコルの登録とビルドが通ることの確認までとします。ホストから192.0.2.2のTCPポートへ接続を試みると、そのポートでlistenしているアプリケーションが無いためxv6側はRSTを返します。この挙動からTCPモジュールがセグメントを受信・応答していることが分かります。
$ nc -v 192.0.2.2 7
10:00:05.301 [D] tcp_input: 192.0.2.1:xxxxx => 192.0.2.2:7, len=24, dev=net0 (kernel/net/tcp.c:975)
10:00:05.302 [D] tcp_output_segment: 192.0.2.2:7 => 192.0.2.1:xxxxx, len=20 (kernel/net/tcp.c:394)
Note
これで自作プロトコルスタックの全モジュールの移植が完了しました。次の章では、アプリケーションがこれらのプロトコルを利用して通信するための「ソケット」を実装します。