Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

これで自作プロトコルスタックの全モジュールの移植が完了しました。次の章では、アプリケーションがこれらのプロトコルを利用して通信するための「ソケット」を実装します。