RaspberryPI のブートローダ読込時点で IPv6 を無効化する

余分なメモリを消費したくない!
プライベートIPv4 の NAT 環境でしか動かすことのない RaspberryPI に IPv6 モジュールなんか不要!
ということでまとめてみた。
(注意:グローバル環境に置くPCやRaspberryPI ではやめてくださいね。そして ipv6 モジュールは firewalld 等のデーモンを起動すると bridge 等の他モジュールからの依存性で強制ロードされる可能性があるので、メモリ消費量削減に関しては意味ないかも・・・)

# 序：フツーの PC Linux で IPv6 を無効化する方法
各種PC向けディストリビューションで IPv6 を無効化する方法をググって出てくる内容は、概ね次の方法である

## 一時的に停止する場合

これらの方法は RaspberryPI でも有効な方法であり、再起動なしで即座に反映されるものの、再起動で無効化されてしまう。
そしてこの方法を行っても ipv6 カーネルモジュールは読み込まれたままである

### その1: /proc に直接値書き込み
 
```shell-session
[root@fuga]# echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6
[root@fuga]# echo 1 > /proc/sys/net/ipv6/conf/default/disable_ipv6
```

### その2: sysctl -w コマンドで即座に反映 )

```shell-session
[root@fuga]# sysctl -w net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.all.disable_ipv6 = 1
[root@fuga]# sysctl -w net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6 = 1
```


## 恒久的に停止する場合

### その1: /etc/sysctl.d/ に設定ファイルを作成して、即座に反映する

この方法は上に挙げた「即時に反映させる方法」の設定ファイルをあらかじめ作成しておいて、作成後に sysctl コマンドを使って反映させる方法である。
再起動な困難な本番環境でも、次回の再起動に備えてこの設定を書き込んでおくことをお勧めする。
本来、この方法はディストリビューションに依存しないはずである。しかしディストリビューションによっては、再起動時にユーザーが指定したこの設定ファイルよりも後から読み込んだ、別の設定ファイルの内容を優先させ、ユーザー指定を無効化してしまうものもある。その際は設定ファイルの名前を、ディレクトリ内でファイル名を昇順で並べ変えた時に後ろに来るようにすること。

```shell-session
[root@fuga]# echo 'net.ipv6.conf.all.disable_ipv6 = 1' > /etc/sysctl.d/30-disable-IPv6.conf
[root@fuga]# echo 'net.ipv6.conf.default.disable_ipv6 = 1' >> /etc/sysctl.d/30-disable-IPv6.conf
[root@fuga]# sysctl -p /etc/sysctl.d/30-disable-IPv6.conf 
```

### その2: GRUB等のブートローダの設定ファイルで、ipv6.disable=1 を起動時のカーネルパラメータに追加

ここでは各種ディストリビューションで最も一般的なブートローダ GRUB2 の場合に限って説明する。
この方法+その3の modprobe.d 配下に "blacklist ipv6" 行を含む設定ファイルを作成すれば確実に IPv6 を無効化できるものの、再起動するまで有効にならないので、再起動が事実上困難な本番環境で行ってはならない。
GRUB2 の場合、/etc/default/grub を編集後、grub-mkconfig コマンドで /boot/grub/grub.cfg ファイルを生成し、再起動.
（尚、ディストリビューションにより、コマンド/ディレクトリ名に含まれている “grub” 部分文字列を “grub2” と読み替える必要がある）

```shell-session
[root@fuga ~]# vi /etc/default/grub
# /etc/default/grub ファイルの抜粋
...
GRUB_LINUX_CMDLINE=
...
```

この部分に値が設定されていない場合は

```shell-session
# /etc/default/grub ファイルの抜粋
...
GRUB_LINUX_CMDLINE="ipv6.disable=1"
...
```

とする。既に何らかの値が設定されている場合は" ipv6.disable=1" を追加する。
そして grub-mkconfig コマンドで GRUB 設定ファイルを生成して再起動。

```shell-session
[root@fuga ~]# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-x.y.z-p-amd64
Found initrd image: /boot/initrd.img-x.y.z-p-amd64
done
[root@fuga ~]# /sbin/reboot
```

### その3: カーネルの IPv6 モジュールを読み込まないようにする
各種ディストリビューションが配布している Linux カーネルは、各種デバイス/プロトコルドライバについてそれぞれ

- 「組み込み」状態(ブート時に必要となるので最初から組み込まれているタイプ)
- 「モジュール」状態(あとから必要に応じて読み込むタイプ)
- 「完全無効化」状態(今となっては絶対に使わないであろう超旧式ハードウェアや特種用途のデバイスなどが対象)

のいずれかを選択してコンパイルされている。

ごくまれにサーバ用として配布されている ISO イメージの中には「組み込み状態」で提供されているものが存在するものの、IPv6 ドライバはカスタムビルドが前提の Gentoo を除いた各種ディストリビューションにおいては、「モジュール化」された状態でコンパイル/配布されているのが常である。
そこで、ブート処理中に「IPv6モジュールは絶対に読み込むな」という指令を与えて IPv6 を無効化しよう、という方針を取ることができる。具体的には /etc/modprobe.d/ 配下の設定ファイルをどうにかするのだが、デバイスドライバ間の依存性なんてものが存在する上に、先に述べたように IPv6 ドライバが最初から組み込まれたカーネルイメージを採用している環境ではこの方法は全く無意味なので、ハマる可能性が出てくる。
よって、この方法も解説しないが、詳細は[ここ](https://wiki.archlinux.jp/index.php/%E3%82%AB%E3%83%BC%E3%83%8D%E3%83%AB%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)で。



### その4: IPv6 を無効化した状態でカーネルをカスタムビルド

最も根源的な解決方法ではあるものの、Gentoo 以外のディストリビューションでは他のパッケージとの依存性を破壊する恐れがあることからお勧めできない。よってこの方法も説明しない。そして Gentoo を使っている人ならばこの方法が最強ですし、わざわざこんなページを見るまでもなく知っていることでしょう8-P

# 本題: RaspberryPI のブートローダーで IPv6 を無効化する
貧弱な環境でカーネルコンパイルなんてしたくないし、わざわざクロスコンパイル環境を作るのも面倒なので、できればディストリビューションから配布されるファイルを極力いじることなく確実に IPv6 を無効化したい、というモノグサな人間なうえに幸い「再起動不可能な本番環境の RaspberryPI」なんてものは所有していないので、「ブートローダの設定で無効化する」ことが私にとっての最適解であると思われる。

但し、RaspberryPI のモデル、OS 選択の組み合わせにより実現方法は異なってくるので以下、状況に合わせた実現方法メモ。

## 32bit版 OS ( 公式 Raspbian, ArchLinux ARM 等 )を使っている場合

/boot/cmdline.txt の末尾に " ipv6.disable=1" を追加するだけ。ただし既存の全パラメータと合わせて確実に1行に収まっている必要があるので
echo コマンドでリダイレクトするよりも、エディタで編集したほうがベター。

```shell-session
# UUID は適当に改変しています
[root@fuga ~]# vi /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=GHIJKLMN-OP rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait  ipv6.disable=1
[root@fuga ~]# /sbin/reboot
```

## RaspberryPI 3B 以降で aarch64 版 ( ArchLinux,Fedora 等) を使っている場合
### ArchLinux aarch64 (U-boot 使用)
設定ファイル編集後に /boot/mkscr コマンドを実行するために、 uboot-tools パッケージが必要。
インストールしていないならば

```shell-session
[hoge@fuga ~]# sudo pacman -S uboot-tools
```

/boot/boot.txt を編集(setenv bootargs 行に ipv6.disable=1 を追加)後、mkscr コマンドを実行,再起動

```shell-session
[root@fuga ~]# cd /boot
[root@fuga /boot]# vi /boot/boot.txt
...(コメント部省略)
part uuid ${devtype} ${devnum}:2 uuid

setenv bootargs console=ttyS1,115200 console=tty0 root=PARTUUID=${uuid} rw rootwait smsc95xx.macaddr="${usbethaddr}" ipv6.disable=1
(以下略)...
[root@fuga /boot]# ./mkscr
Image Name:   U-Boot boot script
Created:      Mon Jul  2 11:26:58 2018
Image Type:   ARM Linux Script (uncompressed)
Data Size:    659 Bytes = 0.64 KiB = 0.00 MiB
Load Address: 00000000
Entry Point:  00000000
Contents:
   Image 0: 651 Bytes = 0.64 KiB = 0.00 MiB
[root@fuga /boot]# /sbin/reboot
```

### Fedora28 aarch64 (EFI → GRUB2)
Fedora28 の起動シーケンスは 

- RaspberryPI公式ブートローダ
- EFI
- GRUB2
- Linuxカーネル

の順、とかなり変態的なので起動はめっちゃ遅い。そして GRUB の設定ファイル出力先も変態的。出来れば使いたくないのだが、2018/7/2 現在、3B+ の WiFi がまともに動作する aarch64 版ディストリビューションは Gentoo か Fedora だけなので仕方なく利用している。

まずは /etc/default/grub を編集後、grub2-mkconfig コマンドで設定ファイル出力、そして再起動。

```shell-session
[root@fuga ~]# vi /etc/default/grub
(編集内容は PC における GRUB 設定ファイル変更内容と同じ)
[root@fuga ~]# /usr/sbin/grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg
(出力内容省略)
done
[root@fuga ~]# /sbin/reboot
```

### OpenSuSE Tumbleweed aarch64 版
一時期使用していた「ローリングアップデート版 OpenSuSE」。
ローリングと言いつつ、ArchLinux のように毎日コツコツ少数のパッケージがアップデートされるのではなく、
アップデートされる際には100から200個のパッケージが一気にアップデートされるのが常で、
容量の少ない SD カードでの運用は無理、と見切りをつけたので忘れましたが、たしか GRUB だったはずですw

### Gentoo aarch64 版
ええ、PC では私も使ってますよ。Gentoo.
でも、たとえ distcc で分散コンパイルしたとしても、ラズパイで全部コンパイルするのはねぇ・・・
ということでお察しください。

以上