Edited at

CentOS 6 の kernel で TIME_WAIT の値を変更して kernel の rpm を作り直す

More than 5 years have passed since last update.

netstat とかで出てくる TIME_WAIT ですが、デフォルトだと 60 秒になっています

今回はそれを 5 秒に変更しようと思います

せっかくなので rpm できちんと作ります(kernel-firmware も作る)

kernel src 内の TCP_TIMEWAIT_LEN の値を変更して rpmbuild します


前提


  • 今回は CentOS 6.5 (kernel-2.6.32-431.11.2) を例にしています

  • 出来上がる version は kernel-2.6.32-431.11.2.el6.timewait5 のようにしています


事前準備

本家のwikiに従って

$ sudo yum groupinstall "Development Tools"

$ sudo yum install ncurses-devel
$ sudo yum install hmaccalc zlib-devel binutils-devel elfutils-libelf-devel


rpmbuild 環境作成

いくつか方法があります


その1

$ mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

$ echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros


その2

$ sudo yum install rpmdevtools

$ rpmdev-setuptree



  • rpmdev-setuptree は mkdir してくれて ~/.rpmmacros を自動で生成してくれます


kernel の srpm を install

$ wget http://vault.centos.org/6.5/updates/Source/SPackages/kernel-2.6.32-431.11.2.el6.src.rpm

$ rpm -ivh kernel-2.6.32-431.11.2.el6.src.rpm


TCP_TIMEWAIT_LEN の patch ファイルを作る

今回いじるのは kernel の src の中にある include/net/tcp.h というファイルになります


include/net/tcp.h

#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT

* state, about 60 seconds */



src を展開する



  • kernel-2.6.32-431.11.2.el6.src.rpm を install したことによって ~/rpmbuild/SOURCES/linux-2.6.32-431.11.2.el6.tar.bz2 が配置されていると思います

  • その src を一旦 /tmp とかに解凍します

$ tar jxf ~/rpmbuild/SOURCES/linux-2.6.32-431.11.2.el6.tar.bz2 --directory=/tmp


tcp.h を編集して patch を作成する

$ cd /tmp/linux-2.6.32-431.11.2.el6

$ cp include/net/tcp.h include/net/tcp.h.org
$ vi include/net/tcp.h
$ diff -Naur include/net/tcp.h.org include/net/tcp.h > ~/rpmbuild/SOURCES/linux-kernel-timewait5.patch


  • linux-kernel-timewait5.patch の中身は下記のようになると思います


  • ~/rpmbuild/SOURCES/ に patch を置いて下さい

--- include/net/tcp.h.org       2014-04-09 19:46:13.823604279 +0900

+++ include/net/tcp.h 2014-04-09 19:46:44.227097917 +0900
@@ -111,7 +111,7 @@
*/

-#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
+#define TCP_TIMEWAIT_LEN (5*HZ) /* how long to wait to destroy TIME-WAIT
* state, about 60 seconds */
#define TCP_FIN_TIMEOUT TCP_TIMEWAIT_LEN
/* BSD style FIN_WAIT2 deadlock breaker.


spec を編集する



  • ~/rpmbuild/SPECS にある kernel.spec を編集します

$ cd ~/rpmbuild/SPECS

$ cp kernel.spec kernel_timewait5.spec
$ vi kernel_timewait5.spec


  • 変更箇所は下記 3 つです


define buildid

@@ -15,7 +15,7 @@

# that the kernel isn't the stock distribution kernel, for example,
# by setting the define to ".local" or ".bz123456"
#
-# % define buildid .local
+%define buildid .timewait5

%define distro_build 431.11.2
%define signmodules 1


patch1000 追加

@@ -610,6 +610,9 @@

Source85: config-powerpc64-debug-rhel
Source86: config-s390x-debug-rhel

+# TCP_TIMEWAIT_LEN patch (60 -> 5)
+Patch1000: linux-kernel-timewait5.patch
+
# empty final patch file to facilitate testing of kernel patches
Patch999999: linux-kernel-test.patch


ApplyOptionalPatch 追加

@@ -932,6 +935,7 @@

# Dynamically generate kernel .config files from config-* files
make -f %{SOURCE20} VERSION=%{version} configs

+ApplyOptionalPatch linux-kernel-timewait5.patch include/net/tcp.h
ApplyOptionalPatch linux-kernel-test.patch

# Any further pre-build tree manipulations happen here.


kernel-firmware の rpm を作成する


  • kernel の package は依存関係で同じ version の kernel-firmware を要求されます

  • これのせいで custom で kernel 作る時に以前と version 変えずに作ってしまうケースが多いようですが、横着しないで作ればいいと思います


  • norarchじゃないと作ってくれないので --target=noarch で作成します

$ rpmbuild -ba --target=noarch --without doc --with kernel_abi_whitelists --with firmware kernel_timewait5.spec


  • kernel-doc や kernel-abi-whitelists は今回は作成しないようにしました

これで ~/rpmbuild/RPMS/noarch/kernel-firmware-2.6.32-431.11.2.el6.timewait5.noarch.rpm が作成されていると思います


謎の挙動

ちょっと話がズレますが


kernel.spec

# kernel-abi-whitelists

%define with_kernel_abi_whitelists %{?_with_kernel_abi_whitelists: 0} %{?!_with_kernel_abi_whitelists: 1}


  • となっているので、--with kernel_abi_whitelists をつけると _with_kernel_abi_whitelists が 0 になる

  • なので --with kernel_abi_whitelists で rpmbuild すると kernel-abi-whitelists が作成されない

  • 逆に --without kernel_abi_whitelists で rpmbuild すると kernel-abi-whitelists が作成される

ということで 多分これ逆なんじゃないかな と思うんですが、意図してそうなっているかは不明・・


  • ちなみに似たような firmware の flag は 0 と 1 が逆になっている


kernel.spec

# kernel-firmware

%define with_firmware %{?_with_firmware: 1} %{?!_with_firmware: 0}


kernel の rpm を作成する

必要なものだけ rpm を作る

$ rpmbuild -ba --target=$(uname -m) --with baseonly --without debug --without debuginfo kernel_timewait5.spec

これで下記の rpm が作成されていると思います(x86_64 の場合)

~/rpmbuild/RPMS/kernel-2.6.32-431.11.2.el6.timewait5.x86_64.rpm

~/rpmbuild/RPMS/kernel-headers-2.6.32-431.11.2.el6.timewait5.x86_64.rpm
~/rpmbuild/RPMS/kernel-devel-2.6.32-431.11.2.el6.timewait5.x86_64.rpm


作成した rpm を適用する


  • yum の repository に置いたり rpm で直接入れたりしてください

  • 適用後、 /boot/grub/grub.conf に新しい kernel の設定が入っていることを確認してください

  • reboot !!


補足


  • 今回はいろいろ余計な rpm を作らないように --without とか多用してますが、必要に応じて flag を外して下さい

  • 何も指定しないで default の flag でも全然問題はないでしょう


IP_VS_TCP_S_TIME_WAIT も?

サーバーの用途によっては IP_VS_TCP_S_TIME_WAIT 等も変更したほうがいいかもしれませんね


net/netfilter/ipvs/ip_vs_proto_tcp.c

static int tcp_timeouts[IP_VS_TCP_S_LAST+1] = {

[IP_VS_TCP_S_NONE] = 2*HZ,
[IP_VS_TCP_S_ESTABLISHED] = 15*60*HZ,
[IP_VS_TCP_S_SYN_SENT] = 2*60*HZ,
[IP_VS_TCP_S_SYN_RECV] = 1*60*HZ,
[IP_VS_TCP_S_FIN_WAIT] = 2*60*HZ,
[IP_VS_TCP_S_TIME_WAIT] = 2*60*HZ,
[IP_VS_TCP_S_CLOSE] = 10*HZ,
[IP_VS_TCP_S_CLOSE_WAIT] = 60*HZ,
[IP_VS_TCP_S_LAST_ACK] = 30*HZ,
[IP_VS_TCP_S_LISTEN] = 2*60*HZ,
[IP_VS_TCP_S_SYNACK] = 120*HZ,
[IP_VS_TCP_S_LAST] = 2*HZ,
};


TCP_TIMEOUT_INIT も?

CentOS 6.5 では TCP 再送間隔の初期値が 1 秒なので特に変えないでいいと思いますが、古い OS とかだと 3 秒になっていることがありますので必要に応じて変えるのもいいと思います


include/net/tcp.h

#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))     /* RFC2988bis initial RTO value */