#author("2019-08-15T23:51:41+09:00","default:nowsky","nowsky")
#author("2020-10-11T22:30:59+09:00","default:nowsky","nowsky")
*Kernel [#t94d3946]
OSの中核となる基本コンポーネントプログラム。
実デバイスとプログラムの中継をしたり、デバイス制御を行う為に必要となる。
 
Linuxの場合は [[Kernel Archives:+https://www.kernel.org/]] で公開されている物を使っている事が多い。
他UNIXの場合は独自ビルドしたカーネルを利用している場合もある

~
*PCI-E ASPM [#jaaeecb8]
PCI-Expressには省電力機能としてASPM(Active State Power Management)が実装されている。
対応しているマザーボード・OSを利用する事で、利用していない&color(#ff0000){PCI-Eデバイスを停止させて省電力化};する事が出来るが、
対応していない環境や仮想環境で利用すると、&font(b){&color(#ff0000){意図しないシステムダウンが発生};};する。
 
特に、古いサーバに最新のOSを利用した時に発生する事が多いのと、
ログが残らずにシステムダウンする為、原因特定に時間のかかる場合が多い
システムダウンを回避するには、ASPMをDisableした後にOSを再起動をする必要がある。
 
#region(&color(#ff0000){ASPMの停止手順};)
-&font(b){参考サイト};
[[CentOS6.2を使っていて突然ネットワークがダウンした話:+http://tsunokawa.hatenablog.com/entry/20120912/p1]]
 
-&font(b){[GRUB1]}; /etc/grub.conf
kernel行の最後に &color(#ff0000){"pcie_aspm=off"}; を追記してOS再起動
 title CentOS (2.6.32-xxx.yyy.x86_64)
    root (hd0,0)
    kernel /vmlinuz-2.6.32-xxx.yyy.x86_64 【中略】 rhgb quiet pcie_aspm=off
    initrd /initramfs-2.6.32-xxx.yyy.x86_64.img
 
-&font(b){[GRUB2]}; /etc/default/grub
GRUB_CMDLINE_LINUXの最後に &color(#ff0000){"pcie_aspm=off"}; を追記した後、grub2-mkconfigで設定を作り直してOS再起動
 GRUB_TIMEOUT=5
 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
 GRUB_DEFAULT=saved
 GRUB_DISABLE_SUBMENU=true
 GRUB_TERMINAL_OUTPUT="console"
 GRUB_CMDLINE_LINUX="【中略】 rhgb quiet pcie_aspm=off"
 GRUB_DISABLE_RECOVERY="true"
 ---
 # grub2-mkconfig -o /boot/grub2/grub.cfg
 
-&font(b){確認コマンド};
下記の実行結果が表示されれば、ASPMが無効化されている
 # dmesg | egrep -i "PCIE ASPM"
 ---
 PCIe ASPM is disabled
#endregion

~
*Jool NAT64 [#rbc2d01e]
IPv6限定ネットワークからIPv4へ通信を行うには様々な手段が存在するが、
その内の一つとしてDNS64+NAT64によるL3+L4変換が存在する。
Linuxで実装する場合はDNSキャッシュサーバをDNS64モードで動作させた上で、
KernelModuleにNAT64を組み込む必要がある。
 
[[Jool:+https://www.jool.mx/en/index.html]]は、LinuxKernel用NAT64モジュールの一種であり、
RedHat、Debian、openSUSE、Raspbianなど様々な環境で動かす事が出来る。
 
#region(&color(#ff0000){Jool組み込み方法};)
-&font(b){参考サイト};
[[iOS向けIPv6なNAT64/DNS64の試験ネットワークをRaspberry Pi 3で作る:+http://pslabo.hatenablog.com/entry/2016/07/30/iOS%E5%90%91%E3%81%91IPv6%E3%81%AANAT64/DNS64%E3%81%AE%E8%A9%A6%E9%A8%93%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%92Raspberry_Pi_3%E3%81%A7%E4%BD%9C%E3%82%8B]]
[[Linuxだけで実装するNAT64:+http://qiita.com/onifinger/items/45390f414db23adcf2b9]]
 
-&font(b){Kernel再構築};
Raspbian(Raspberry Pi3)でJoolを実装する為には、Kernel再構築(リビルド)が必要となる。
コンパイル時間は、Kernelに組み込むモジュール量に応じて処理時間が増減するが、
ラズパイの処理をコンパイルのみに限定させれば、3~6時間で処理が完了する。
 # git clone --depth=1 https://github.com/raspberrypi/linux
 # cd linux
 # KERNEL=kernel7
 # make bcm2709_defconfig
 # make -j4 zImage modules dtbs
 # make modules_install
 # cp arch/arm/boot/dts/*.dtb /boot/
 # cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
 # cp arch/arm/boot/dts/overlays/README /boot/overlays/
 # scripts/mkknlimg arch/arm/boot/zImage /boot/$KERNEL.img
 
-&font(b){アップデート無効化};
パッケージ管理によるKernel自動アップデートを無効化する
 # apt-mark hold raspberrypi-bootloader
 # apt-mark hold raspberrypi-kernel
 # apt-mark hold raspberrypi-sys-mods
 # dpkg --get-selections | grep hold
 
-&font(b){Kernel調整};
Kernelパラメータを修正した後に再起動する事で、Joolモジュールを読み込ませる
 # echo "jool"                            >> /etc/modules
 # echo "options jool pool6=64:ff9b::/96" >> /etc/modprobe.d/jool.conf
 # reboot
 
-&font(b){Joolステータス};
[[Joolドキュメント:+https://jool.mx/en/documentation.html]]に詳細は書いてあるが、主に下記コマンドを使うのでメモ
 1).Poolの一覧出力
 # jool --pool4 --display
 
 2).セッション数確認
 # jool -c -s
#endregion

~
*Kernel Build [#w364bb1f]
最新のKernelを利用する時や、通常はサポートしていないモジュールを使う時、
Kernelを自前で再構成(ビルド)する事がある。
ビルドはスクリプトで自動化されているが、新規モジュールのON/OFFは自前で設定する必要がある。
なお、最新Kernelの機能追加・バグ修正は[[LKML:+https://lkml.org/]]で公開されているので読んでおく。
 
#region(&color(#ff0000){ビルド手順};)
-&font(b){参考サイト};
[[The Linux Kernel Archives:+https://www.kernel.org/]]
[[LKML.ORG - the Linux Kernel Mailing List Archive:+https://lkml.org/]]
 
-&font(b){ソースコード入手};
Kernelのソースコード&color(#ff0000){(バニラ・カーネル)};は、上記のオリジナルサイトで公開している。
旧バージョンのソースについても[[Web上で公開:+https://mirrors.edge.kernel.org/pub/linux/kernel/]]されている。
 # cd /usr/local/src
 # wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.18.8.tar.xz
 # tar Jxvf linux-4.18.8.tar.xz
 # cd linux-4.18.8
 
-&font(b){設定インポート};
一からビルドオプションを作るのは大変な為、稼働中のKernel設定をインポートして簡略化する。
新規の設定項目は &color(#ff0000){"make oldconfig"}; 実行時にダイアログで設定確認が行われる。
GUIでビルドオプションを作り直したい場合は &color(#ff0000){"make menuconfig"}; を実行して設定し直す。
 # make mrproper
 # cp /boot/config-2.6.32-754.3.5.* .config
 # make oldconfig
 # make menuconfig
 
-&font(b){ソースビルド};
ビルドオプションを作成したら、実際にソースコードをビルドする。
ビルドには時間がかかる為、makeコマンドをCPUコア数に応じて並列処理させる。
 # make -j 4 bzImage
 # make -j 4 modules
 
-&font(b){インストール};
ビルドしたKernelをインストールするには様々な方法が存在するが、
汎用性が高い従来の手順でインストールするには下記コマンドを実行する。
下記はver4.18.8のバニラ・カーネルをインストールした場合の手順となる。
 # make modules_install
 # ls /lib/modules
 # mkinitrd /boot/initramfs-4.18.8.img 4.18.8
 # cp .config /boot/config-4.18.8
 # cp arch/x86_64/boot/bzImage /boot/vmlinuz-4.18.8
 # cp System.map /boot/System.map-4.18.8
 # gzip -c Module.symvers > /boot/symvers-4.18.8.gz
 
-&font(b){ブートローダ変更};
新しいバージョンのKernelから起動させる為、GRUBなどのブートローダを書き換える。
この時、Kernelが起動しなかった場合に備え&color(#ff0000){正常起動する設定は残しておく。}:
下記はGRUBv1でのブートローダ記述例となる。
 # vi /boot/grub/grub.conf
 ---
 title Vanilla-Kernel v4.18.8
     root (hd0,0)
     kernel /vmlinuz-4.18.8 ro root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rd_NO_LUKS rd_NO_MD <以下略>
     initrd /initramfs-4.18.8.img
 
-&font(b){旧Kernelの削除};
旧Kernelの削除は&color(#ff0000){新しいKernelで起動確認が完了したら};実行する。
そうしないと、タイミングによっては起動するKernelが無くなり復旧に時間を要する事になる。
削除対象ファイルのPATHはディストリビューション毎に違う為、ファイルが無い場合は探しつつ作業する。
下記は、v4.18.7のアンインストール手順となる。
 # rm -rf /lib/modules/4.18.7
 # rm /boot/config-4.18.7
 # rm /boot/vmlinuz-4.18.7
 # rm /boot/System.map-4.18.7
 # rm /boot/initramfs-4.18.7.img
 # rm /boot/symvers-4.18.7.gz
 
-&font(b){手抜きインストール};
最近(2018年ごろ)のKernelはイメージ・モジュールビルド、インストールを自動で実行してくれる。
細かい設定を行わない場合は下記コマンドを実行すれば、上記の作業を自動で実行出来る。
 # cd linux-4.18.8
 # make mrproper
 # cp /boot/config-2.6.32-754.3.5.* .config
 # make oldconfig
 # make -j4
 # make install
#endregion

~
*ip conntrack [#z1cd45c7]
コンテンツ配信サーバ・ロードバランサ等でiptablesを用いてFirewall制御を行っている場合、
iptablesのセッション管理テーブルを使い切り、次の様なエラーがログが出る事がある。
 ip_conntrack: table full, dropping packet
 nf_conntrack: table full, dropping packet
この状態では新規のセッションを張る事が出来なくなり、NW通信速度が極端に低下してしまう。
事前に管理テーブル最大値を拡張する事でエラー発生を抑制する事が出来る。
 
#region(&color(#ff0000){パラメータ};)
-&font(b){参考サイト};
[[DMMツチノコブログ:+https://tsuchinoko.dmmlabs.com/?p=755]]
[[iptables ip_conntrack/nf_conntrack 拡張:+https://nazx.jp/x/CentOS_TIPS_002]]
[[Conntrack tuning:+http://wiki.khnet.info/index.php/Conntrack_tuning]]
 
-&font(b){CentOS6/7 設定例};
CentOS5・CentOS6/7で設定するパラメータが変化する。
sysctlを書き換えた後は「sysctl -p」で適用する必要がある。
 # vi /etc/sysctl.conf
 ---
 net.nf_conntrack_max                  = 1048576
 net.netfilter.nf_conntrack_max        = 1048576
 net.netfilter.nf_conntrack_buckets    = 131072
 net.netfilter.nf_conntrack_expect_max = 2048
 
-&font(b){パラメータ解説};
conntrackは1セッションで、200~400Byte(概ね350Byte)のメモリを利用する。
セッションテーブルはswapで代用が出来ない点に注意する。
 # net.nf_conntrack_max
 システムが利用出来るconntrackテーブル最大数
 下記の「net.netfilter.nf_conntrack_max」と同じ値にする
 
 # net.netfilter.nf_conntrack_max
 システムが利用出来るconntrackテーブル最大数
 Firewall系サーバならば「2の20倍」に設定
 Applicationサーバならば「2の16倍」程度が良い
 
 # net.netfilter.nf_conntrack_buckets
 conntrackテーブルの実行結果を管理するハッシュテーブル(バケット)サイズ
 処理を高効率化する為に「nf_conntrack_max / 8」の値を設定する必要がある
 
 # net.netfilter.nf_conntrack_expect_max
 音声通信などリアルタイム性が求められるセッション用のテーブル
 使わない環境では「2の10~12倍」、音声通信を使う場合は「2の16倍」に設定
#endregion

~
*nonlocal bind [#p904cc25]
LinuxKernelではローカルバインドしているIPアドレスのみ接続待受(LISTEN)出来るが、
keepalivedでHA構成を取る場合、バインドしていないIPアドレスでLISTENするケースがある。
その時は、sysctl.confに下記を追記する事で、非バインドIPアドレスでもLISTEN可能になる。
 
#region(&color(#ff0000){パラメータ};)
-&font(b){パラメータ解説};
デフォルトは"0"が設定されており、ローカルバインドが出来ない様になっている。
パラメータを"1"に変更する事で、非ローカルバインドIPアドレスのLISTENが可能となる。
"net.ipv4.ip_nonlocal_bind"はIPv4用、"net.ipv6.ip_nonlocal_bind"はIPv6用なので注意。
 # vi /etc/sysctl.conf
 ---
 # Uncomment the next line to enable nonlocal bind for IPv4/6
 #  Enabling this option allows processes to bind to non-local address
 #  Note: May break some applications. Default parameter is '0'
 net.ipv4.ip_nonlocal_bind=0
 net.ipv6.ip_nonlocal_bind=0
#endregion

~
*accept dad [#r0f03e74]
IPv6アドレスを固定設定したインターフェースがある時、
重複アドレス検出(Duplication Address Detection)でIPv6アドレス重複を確認した後に割り当てられる。
 
サーバにIPv6アドレス指定でLISTENするアプリケーションがある場合、
&color(#ff0000){DAD待ちによってIPv6アドレスの割り当てが行われていない状態で起動};してしまい、
IPv6アドレス割り当て不備と判断されエラー終了する場合がある。
様々な環境で発生する可能性があるのが、NSDで発生した場合は次のエラーログが出力され停止する。
 notice: nsd starting (NSD 4.3.3)
 error: can't bind udp socket 2001:db8::1@53: Cannot assign requested address
 error: server initialization failed, nsd could not be started
DAD待ちはsystemdの"network-online.target"でも発生する為、解決に向けて議論が交わされている。
暫定対処するにはKernelパラメータを変更して重複アドレス検出待ちを無効化する方法がある。
 
#region(&color(#ff0000){パラメータ};)
-&font(b){参考サイト};
Red Hat Bugzilla - [[Bug 1243958:+https://bugzilla.redhat.com/show_bug.cgi?id=1243958]]
Linux Kernel - [[Networking:+https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt]]
 

-&font(b){パラメータ解説};
パラメータに"0"を設定する事で、アドレス重複機能をインターフェース毎に無効化出来る。
ただし"all"で設定をしても反映されないケースがあるので、個別に設定すると安定する。
 # vi /etc/sysctl.conf
 ---
 # Whether to accept DAD (Duplicate Address Detection)
 #   0: Disable DAD
 #   1: Enable DAD (default)
 #   2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
 #      link-local address has been found
 #
 # DAD operation and mode on a given interface will be selected according
 # to the maximum value of conf/{all,interface}/accept_dad
 net.ipv6.conf.eth0.accept_dad=0
#endregion