📘

GoでTFTPサーバ自作(blksize, ロールオーバー編)

に公開

この記事の内容

この記事ではRFC 2347およびRFC 2348に従ってTFTPサーバを拡張します
また、ロールオーバー機能を追加します
ただし、ロールオーバー機能に対応するRFCは存在しません(2025年3月現在)
学習目的の記事なのでAIは使用しません

TFTPのオプション

RFC 2347ではTFTPのオプションが定義されています
オプションはRRQのフォーマットを変更することで実現されます
クライアントはオプションを付与してサーバにRRQを送ります
サーバはオプションを受け入れる場合はこのRFCで定義されるOACKを送ります
クライアントはOACKに対してブロック番号0番のACKを送ります
以降の挙動はオプションにより異なります

詳細

RFC 2347では新しい一つのOpcodeと一つのErrorCodeが追加されています
それぞれ以下です

種類 Opcode 内容
OACK 06 サーバが受け入れるオプションと具体的な値
ErrorCode 内容
8 the request has been denied.

オプションを付与する場合のRRQおよびOACKのフォーマットは以下です

種類 フォーマット
RRQ Opcode: 2 bytes
Filename: string
0: 1 byte
Mode: string
0: 1 byte
opt1: string
0: 1 byte
value1: string
0: 1 byte
...
optN: string
0: 1 byte
valueN: string
0: 1 byte
OACK Opcode: 2 bytes
opt1: string
0: 1 byte
value1: string
0: 1 byte
...
optN: string
0: 1 byte
valueN: string
0: 1 byte

blksize

RFC 2348ではオプションとしてblksizeが定義されています
このオプションで指定したブロックサイズでファイルを転送します

名前 有効な値
blksize 8-65464

ロールオーバー

TFTPで転送できるファイルサイズはブロックサイズ×65536が限界です
ブロックサイズは512 bytesの場合は32MBです
この限界を解決するための機能がロールオーバーです
中身は簡単で65536番目のブロック送信後に0番目のブロックを送信するだけです

実装

概要

大雑把なシーケンスは以下です

https://github.com/callus-corn/tao/tree/v1.1.0/internal/tftp

おまけ:速度比較

blksize=512,1468,8192で速度比較します
参考にscp(sftp)も加えます
測定環境

測定手順
ファイルの生成

head -c 1000000000 /dev/urandom > file1g

tftp blksize=512

$ curl tftp://192.168.1.101/file1g --tftp-blksize 512 -o file1g

tftp blksize=1468

$ curl tftp://192.168.1.101/file1g --tftp-blksize 1468 -o file1g

tftp blksize=8192

$ curl tftp://192.168.1.101/file1g --tftp-blksize 8192 -o file1g

scp(sftp)

$ scp -v 192.168.1.101:/home/ubuntu/file1g .

結果

ブロックサイズを大きくすることで性能低下する様子が確認できます
これはパケットの往復回数が減ることによる効果なはずなのでそれも確かめておきます
パケットの往復回数の削減率と転送時間の削減率を比較すると以下です

パケットの往復回数の削減が転送時間の削減に影響しているといってよさそうです

おまけのおまけ

ブロックの読み込みはブロックを送信するタイミングで別にいい気がしたので変更してみました

https://github.com/callus-corn/tao/tree/v1.3.0/internal/tftp

若干転送時間の増加が見えます
微妙なところですが許容範囲かなと思います
メモリ使用量の観点から今後はこちらの実装で進めていきます

Discussion