うたカモ技術ブログ

Linux OpenWrt ネットワーク

【第 8 回】 OpenWrt開発入門   Coffee Break

post:     update: 

この記事は、OpenWrt開発入門の連載記事(第1~7回)で取り上げようとして、結局ボツになった内容やその他のTipsをまとめたものです。 言わば、Coffee Break的な記事になります。

「記事のネタは無限にある、されど1つ1つ作り上げるのに相当な時間が掛かる」ということで、メインとなる記事作成の片手間でサイド記事 を書いて、投稿頻度もある程度維持しようという魂胆でこの記事は作成されています。

この記事はTips集という性質上、随時加筆される可能性があります。

目次

  1. パスワード設定について
  2. アクセスポイント(AP)って何?
  3. ルーターって何?
  4. WLANとLANインタフェースのブリッジ設定について
  5. 一般的なインタフェース構成に対応したルーターのネットワーク設定
  6. /etc/init.d/xxxxx {disable/enable}の作用
  7. UCIコンフィグレーションファイルはただのテキストファイル?
  8. UCIコンフィグレーションファイルの使用は絶対ではない?
  9. ファームウェアイメージ作成時に初期設定を上書きするuci-defaults
  10. Gitリポジトリにあるパッケージをbuildrootに認識させる方法
  11. おわりに

パスワード設定について

OpenWrtのデフォルト設定では、コンソールログインにパスワードはありません。なので、通常はpasswdコマンドを 使用して任意のログインパスワードを掛け、ユーザー自身で最低限のセキュリティ対策をする必要があります。

次はpasswdコマンドの実行例です。
新たなパスワードを聞かれますので、任意のものを打ち込んでOpenWrtに登録しましょう。

root@OpenWrt:~# passwd
Changing password for root
New password:
Retype password:
passwd: password for root changed by root
root@OpenWrt:~#

私のブログ記事はやたらと長いので、文字数を減らすために記事の題材から外れた内容は省く方針です。 そのため、パスワード設定の実施は常識として今まで取り上げませんでした(このブログはエンジニア向けというのもあります)。

しかし、OpenWrtはネットワークと繋がるデバイス上で動作し、SSH接続もデフォルトでサポートしています。 そのため、ここでパスワードの設定方法について紹介してみました。

まだパスワード設定をしていない人はぜひこの機会に。

アクセスポイント(AP)って何?

アクセスポイントは一般的に、無線LANを利用して既存のネットワークにスマホやPCなどの無線通信機器を繋げる役割を持つものです。 現在、無線LANを確立するために広く使われている通信規格はWi-Fiです。

最近ではルーターにAP機能が搭載されていますので、一般ユーザーからは「ルーター=Wi-Fi(2.4/5GHz)が使えるようになる機器」のように感じられるはずです。 しかし、Wi-Fi機能の提供は本来、APの役目なのです。

例えば、この連載記事の第3回第4回でRaspberry Piをアクセスポイントとして動作させるための設定方法を取り上げました。 このときに掲載したアクセスポイントの配置図が以下のものです。

ホームゲートウェイ(メインルーター)が管理するネットワーク(192.168.3.0/24)にアクセスポイントとしてRaspberry Piが 所属することで、Raspberry Piはスマホなどの端末がWi-Fiによる無線通信で192.168.3.0/24のネットワークにアクセスする際のポイントになります。

もし、このホームゲートウェイが有線のみをサポートし、Wi-Fiを提供していない場合、このRaspberry PiがWi-Fiでネットワークに入ることができる唯一のアクセスポイントです。

現在、市販されている家庭用ルーターでは、アクセスポイント(AP)機能が搭載され、ルーター機能と併用して運用されています。 そのため、エンドユーザーの方にとってはルーターとアクセスポイントの違いが曖昧になり、理解しにくい状況となっています。

ルーターって何?

ルーターとは、複数のネットワークを跨いでデータ通信を実現する転送装置です。
異なる複数のネットワーク間でデータを転送するために、通信経路の選択(ルーティング)をします。

例えば、この連載記事の第3回第4回でRaspberry Piをルーターとして動作させるための設定方法を取り上げました。 このときに掲載したルーターの配置図が以下のものです。

ホームゲートウェイ(メインルーター)が管理するネットワーク(192.168.3.0/24)にルーターとしてRaspberry PiのWAN側が 接続されると、上記の例ではRapsberry PiはLAN側ネットワーク(192.168.4.0/24)を管理しながら、それらネットワークを繋ぐ中継 点となります。

これにより、192.168.3.0/24と192.168.4.0/24の間でパケット転送が可能になります。

最近のルーターはHub機能(L2スイッチ)やAP機能を持っていますので、一般ユーザーの方からは様々な機能を有していると感じられるはずです。 しかし、ルーター本来の存在目的は異なるネットワークを繋ぎ、IPパケットを転送する機能の提供です。

ちなみに似た製品としてL3スイッチというものがあります。

L3スイッチは、ルーターと同じようにルーティング機能があります。 しかし、パケット処理においてISPプロバイダとの間でやり取りされるプロトコルには対応していません。

そのため、一般的にはワイドエリアネットワーク(ISP事業者が提供する回線網)への出入口(つまり、ホームゲートウェイ)としては使用できません。 L3スイッチは主にイントラネット内などで構築されたネットワークを分けたいときに使用されます。上図を見ると、ちょうどRaspberry Piと同じ配置 であればL3スイッチは正常に機能します。

UCIコンフィグレーションファイルはただのテキストファイル?

このブログのOpenWrt関連記事で度々出てくるUCIコンフィグレーションファイルとは、ひとことで言ってしまえば「意味付けをしたキーワードによって アプリケーションデータを文字列として表現した、ただのテキストファイル」です。

「意味付けをしたキーワード」とは、データの論理階層を示すセクション、オプション、リストなどを指します。※詳しくは「UCIコマンドの使い方」を見ると良いと思います。

root@OpenWrt:~# cat /etc/config/coffee

config beans 'arabica'             # タイプ:beans、セクション:arabica
        option scent 'very good'   # オプション:scent、値:'very good'
        option taste 'excellent'   # オプション:taste、値:'excellent'

config beans 'robusta'
        option scent 'good'
        option taste 'good'

root@OpenWrt:~#

ただのテキストファイルなので、touchコマンドでファイル作成をした後に、上記のルールを守った文字列の集まりをエディタツールでタイピングしても 、UCIシステムはそのファイルをUCIコンフィグレーションファイルとして認識します。試しに上記の例を参考に/etc/config直下にcoffeeファイルを作り、データを手打ちした後、 「root@OpenWrt:~# uci show coffee」などを実行すれば、その意味が実感できるでしょう。

このように、UCIコンフィグレーションファイルと言っても、あるルールに従って文字列が書かれたファイルと考えればその仕組みが単純なことが分かります。 初学者の方は、難しく考えているかもしれないので取り上げてみました。

※エディタツールを使ったUCIコンフィグレーションファイルの手打ち編集は第3回記事の「UCIシステムの仕組み」で説明したステージング領域を介しません。そのため、 WebUIのLuCIを使いながら、手動でファイルを弄っているとステージング領域とフラッシュ領域との間でコンフリクトが発生する場合がありますので注意が必要です。

UCIコンフィグレーションファイルの使用は絶対ではない?

UCIコンフィグレーションファイルはOpenWrt専用アプリケーションの環境変数です。

このように言ってしまうと 「それでは、OpenWrt上で動作するアプリケーションは環境変数として必ずUCIコンフィグレーションファイルを使わなければならないのか?」 という疑問が生まれます。

結論から言うと、そのアプリケーションがUCIコンフィグレーションファイルを使用するかは、そのアプリケーションの開発者次第です。 他のLinuxディストリビューションでもそうですが、開発元のプロジェクトによってアプリケーション開発で推奨される方法が提供されます。

OpenWrtは、ネットワーク設定などが代表する「一度間違うと以降の接続ができなくなって文鎮化する」シビアな設定を数多く持っています。そのため、OpenWrtプロジェクトはステージング領域 とフラッシュ領域を構築し、電源断やrevertをすれば元の正常な設定に戻れる仕組みを持つUCIシステムを提供しています。

この理由により、OpenWrt専用アプリケーションの大半はUCIコンフィグレーションファイルを環境変数として使用しているのです。

逆に言えば、ステージング領域による効果を完全に無視して良いということであれば、UCIコンフィグレーションファイルをそのアプリケーションの環境変数として 採用する理由はありません。その場合は、他ディストリビューションのアプリケーションが良く使用している拡張子「.conf」から始まるファイルを環境変数とし扱っても良いでしょう。

様々なシステムに触れると、基本的ななことを忘れて視野が狭くなりがちです。ここでは、UCIシステムが環境変数管理の仕組みであるということを知ると、そもそもな話として「環境変数として使えれば方法・実装は何でも良い」 ということを忘れてしまうのです。その仕組みが実現する本質的な目的・役割を忘れないようにしましょう。大体のものは単純です。

OpenWrt関連記事でUCIコマンド系の記事をさんざん書いておいて今さら言うのも何ですが。

WLANとLANインタフェースのブリッジ設定について

この内容は、第3回記事のアクセスポイント設定の最後に掲載していた補足説明です。 記事全体の見通しが悪くなるため、第3回記事から本記事に移動になりました。

WLANインタフェース(例:wlan0)が所属するネットワークは、wireless.default_radio0.network(※)で指定されるnetworkコンフィグのセクションのものです。 第3回記事のアクセスポイント設定の例では、wireless.default_radio0.network=lanが設定されていますので、これにより、network.lanのネットワーク設定情報にwlan0が紐づきます。

このとき、network.lan.deviceに指定されたインタフェースとブリッジできるか確認されます。もし、network.lan.deviceが示すインタフェースがブリッジ用 の仮想インタフェース(例:br-lan)であり、その所属インタフェースとしてeth0が予めnetwork.@device[0].portsで指定されていた場合、WLANインタフェース(wlan0)はbr-lan/eth0と ブリッジされます。(もし、network.lan.device=eth0となっていた場合、eth0とwlan0はブリッジされず、eth0のみに対してnetwork.lan.ipaddrが示すIPアドレスが付与されます。 また、このときにnetwork.lan.proto='dhcp'の設定があった場合、動的IPアドレスがeth0のみに配信されます。)

第3回記事で取り上げたAP設定では、network.lanは動的IPアドレス割り当てを指定(network.lan.proto='dhcp')しており、適用対象デバイスとしてeth0が所属するbr-lanを指定(network.lan.device='br-lan')しています。 これにより、wlan0とeth0はbr-lanの所属インタフェースとしてブリッジされ、ホームゲートウェイのdhcpサーバーによる動的IPアドレス割り当てをbr-lanが受けます。

なお、ブリッジ設定はbrctl showコマンドを使うことで確認できます。

root@OpenWrt:~# brctl show
bridge name    bridge id           STP enabled	    interfaces
br-lan         7fff.b827ebb87a04   no               eth0
                                                    wlan0

参考情報はこちら

※default_radio0のradio0とはWi-Fiの2.4GHzを指します。対してradio1は5GHzを指します。5GHzのRF(Radio Frequency)チップを搭載するデバイスにはradio1の設定が存在するかもしれません。

一般的なインタフェース構成に対応したルーターのネットワーク設定

この内容は、第3回記事のルーター設定の所で掲載していた補足説明です。 記事全体の見通しが悪くなるため、第3回記事から本記事に移動になりました。

第3回記事で紹介したルーターのネットワーク設定は、Raspberry Pi3B用に合わせたものです。
Raspberry PiはLANポートと2.4GHz Wi-Fiモジュールが1個ずつなので、それぞれをWANとLANに分けて設定しました。

しかし、一般的なルーター機器ではWAN側LANポートが1個、LAN側のLANポートとWi-Fiモジュールが複数個存在します。 そのため、LAN側の対応インタフェースをブリッジして1つの仮想インタフェース(br-lan)に束ね、それをLAN側インタフェースとして 指定する必要があります。

ブリッジ対象インタフェースは、上図右側の設定例に掲載したnetwork.@device[0].portsで管理されます。

ただし、このportsリストはeth0などの有線デバイス(物理ポート)をブリッジ対象に含めるときに使用するだけです。

無線デバイスを表すWLANインタフェース(例:wlan0)をeth0などの有線デバイスとブリッジしたい場合は、それらの有線デバイスを管理する ブリッジ用仮想インタフェース(例:br-lan)が設定されたnetworkコンフィグのセクション設定とWLANインタフェースを紐づける必要があります。

設定の紐づけは、networkコンフィグが持つinterfaceタイプの任意セクションの名前をwlan0とwlan1のwireless.default_radio{0,1}.networkで指定することで 可能です。

例として、wlan0(2.4GHz)とwlan1(5GHz)をeth1とブリッジしたい場合、まず有線デバイスが例え1つであろうと ブリッジデバイス(network.@device.type='bridge'を持った@deviceセクション)を作成し、そのportsリストにeth1を含めます。 これにより、システムがeth0をブリッジ可能インタフェースとして認識します。

そして、ブリッジデバイスの名前(例:br-lan)を適用対象のネットワーク設定セクションがもつdeviceオプション(例:network.lan.device='br-lan') に指定します。

最後に、WLANインタフェースのwlan0とwlan1がその設定を見に行くように、それぞれのwireles.default_radio{0,1}.networkに対して、そのネットワーク 設定を管理するセクションの名前を値として設定します。デフォルトではLANネットワークの設定はnetwork.lanで管理されますので、 wireless.default_radio0{0,1}.network='lan'を設定するはずです。

後は、「/etc/init.d/network [reload or restart]」などを実行することで、wlan0とwlan1がeth1と自動的にブリッジされます。

※network.@device[0].portsはUCIコンフィグレーションファイルのリストデータです。このリストデータに有線デバイスを追加・削除 することで有線ブリッジ設定を変更できます。

インタフェースの追加
uci add_listコマンドでリストデータを追加します。次はeth2を追加する例です。
root@OpenWrt:~# uci add_list network.@device[0].ports=wlan0
root@OpenWrt:~# uci show network.@device[0].ports
root@OpenWrt:~# network.cfg030f15.ports='eth1' 'eth2' ※eth1は元からあったもの
root@OpenWrt:~# uci commit
root@OpenWrt:~# /etc/init.d/network reload  ※もしくはrestart、システム再起動
[補足1]: これでnetwork.@device[0].nameで指定した仮想インタフェース名でブリッジします。
[補足2]: brctl showでブリッジ状態を確認するとeth1とeth2がブリッジされていることが確認できます。
[補足3]: network.{lan or wan}.deviceで仮想インタフェースを指定していないとブリッジされません。
インタフェースの削除
uci del_listコマンドでリストデータを削除します。次はeth2を削除する例です。
root@OpenWrt:~# uci del_list network.@device[0].ports=eth2
root@OpenWrt:~# uci show network.@device[0].ports
root@OpenWrt:~# network.cfg030f15.ports='eth1'
root@OpenWrt:~# uci commit
root@OpenWrt:~# /etc/init.d/network reload  ※もしくはrestartまたはシステム再起動

上記コマンドについて詳細な使い方を知りたり方はこちら。

  1. リストデータの追加(add_list)
  2. リストデータの削除(del_list)

/etc/init.d/xxxxx {disable/enable}の作用

この内容は、第3回記事のアクセスポイント設定の最後に掲載していた補足説明です。 記事全体の見通しが悪くなるため、第3回記事から本記事に移動になりました。

このコマンドは初期化プロセス(procd)がシステムブート時にロードする/etc/rc.d直下のアプリケーション用初期化スクリプト(シンボリックリンク)を 削除(disable)・再作成(enable)する操作です。

このコマンドを実行することで、システムブート時の起動対象からそのアプリケーションを除外・再登録することができます。 第3回のアクセスポイント設定では、最後にDHCPサーバーのdnsmasq用起動スクリプト(シンボリックリンク)を/etc/rc.dから削除しています。(※)

※2024/4/20追記

修正前の第3回記事では、DHCPサーバーを停止する例として/etc/init.d/dnsmasq stopを使っていましたが、このコマンドを実行するとSSL通信が禁止になるようです。DHCPサーバーのみをOFFにしたい場合はuci set dhcp.@dnsmasq[0].disabled=1 とした上で/etc/init.d/dnsmasq restartを実行してください。

1つ注意してほしいのは、そのアプリケーションが持つUCIコンフィグレーションファイルのオプションに有効・無効を 表すenable(d)・disable(d)があるときです。

procdにロードさせないことで事実上無効にしているのか、はたまたアプリケーション自体が無効設定を適用しているのか を意識する必要があります。

この違いを考えたくない場合は有効・無効に関連する全ての操作・パラメータを合わせるか、有効・無効は できるだけUCIコンフィグレーションファイルのパラメータで制御させ、/etc/init.d/xxxx {disable/enable}は 極力使わないなどの指針を予め定めておくと良いと思います。

ファームウェアイメージ作成時に初期設定を上書きするuci-defaults

buildrootからOpenWrtファームウェアを毎回作っていると任意のUCIコンフィグレーションファイルの初期設定を変更したいという欲が出てきます。

そんなときはOpenWrtのbuildrootに対してuci-defaultsディレクトリを作成し、その中に設定上書き用のスクリプトを入れましょう。

まず、buildrootのディレクトリ(~/openwrt)直下にfiles/etc/uci-defaultsを作成します。

次に設定上書き用スクリプトを/openwrt/files/etc/uci-defaults直下に作成します。 今回はAP設定用スクリプトの99-ap-settingを作成しました。

kamo@kamo:~/openwrt$ cat << "EOF" > ./files/etc/uci-defaults/99-ap-setting
uci -q batch << EOI
set wireless.radio0.disabled=0
set wireless.radio0.country=JP
set wireless.radio0.txpower=10
set wireless.default_radio0.encryption=psk2
set wireless.default_radio0.key=utakamo1234
set network.lan.proto=dhcp
set dhcp.@dnsmasq[0].disabled=1
set system.@system[0].zonename=Asia/Tokyo
set system.@system[0].timezone=JST-9
EOI
EOF

後はいつも通りにファームウェアイメージをmakeコマンドで作成するたけです。

kamo@kamo:~/openwrt$ make V=s

~/openwrt/bin/targets内に作成されたファームウェアをデバイスにインストールすれば、上記の設定上書き用スクリプト(99-ap-setting)が適用されていることが確認できます。

なお、uci-defaultsについてはOpenWrt公式サイトのこちらのページに詳しく書いてありますので、詳細の情報はここを参照してください。

おまけ

ルーター設定のスクリプト
network.lan.deviceはWLANインタフェース名です。 最近のOpenWrtのバージョンだとphy0-ap0という名前ですが、確認が必要です。

uci -q batch << EOI
set wireless.radio0.disabled=0
set wireless.radio0.country=JP
set wireless.radio0.txpower=10
set wireless.default_radio0.encryption=psk2
set wireless.default_radio0.key=utakamo1234
set network.lan.device=phy0-ap0    <--- 最近の環境だとphy0-ap0だけど要確認
set network.lan.ipaddr=192.168.4.1
set network.wan=interface
set network.wan.device=eth0
set network.wan.proto=dhcp
set dhcp.@dnsmasq[0].disabled=1
set system.@system[0].zonename=Asia/Tokyo
set system.@system[0].timezone=JST-9
EOI

Gitリポジトリにあるパッケージをbuildrootに認識させる方法

【第6回】OpenWrt開発入門 自作アプリのパッケージ作成とインストールでは、サンプルアプリ(duckdump)のパッケージ構成ファイル本体をローカル環境内にgit cloneで手動でダウンロードしてもらい、 その中のMakefileなどを見てもらうことでパッケージ構成について紹介しました。

アプリケーションの開発者がパッケージをビルドしてそれを外部に公開するだけなら、開発者本人 だけが自身が持つOpenWrtのbuildroot内だけでパッケージ構成ファイルを管理していれば済みます。

ただし、この場合、ターゲットシステム(ハードウェア)別にアプリケーションパッケージを開発者本人がビルドしなければなりません。 OpenWrtがサポートするハードウェアは数多くありますので、すべてに対応しようとすると非常に多くの作業が必要になります。

そこで、Gitリポジトリを介して各ユーザーにパッケージ構成ファイルを配布し、各自が用意したOpenWrtのbuildroot環境で固有ハードウェア向けの パッケージをビルドしてもらう方法があります。

この方法では、ユーザーはGitリポジトリのURLを知っていれば良く、自身のbuildroot環境内に明示してパッケージ構成ファイル一式をダウンロード する手間は発生しません。

OpenWrtでは、buildrootのfeeds.confにパッケージ構成ファイルを管理するGitリポジトリのURLを書くことができます。 これによって、ファームウェアや特定パッケージのビルド時にパッケージ構成ファイルを自動ダウンロードするようになります。

例えば、私のOpenWrt用GitリポジトリのURLを~/openwrt/feeds.confに次のように書きます。

# ~/openwrt/feeds.conf
# 初期状態だとファイル名がfeeds.conf.defaultとなっています
# cpコマンドで同階層(~/openwrt)にfeeds.confの名でコピーすること
src-git packages https://git.openwrt.org/feed/packages.git
src-git luci https://git.openwrt.org/project/luci.git
src-git routing https://git.openwrt.org/feed/routing.git
src-git telephony https://git.openwrt.org/feed/telephony.git
#src-git video https://github.com/openwrt/video.git
#src-git targets https://github.com/openwrt/targets.git
#src-git oldpackages http://git.openwrt.org/packages.git
#src-link custom /usr/src/openwrt/custom-feed
src-git utakamo https://github.com/utakamo/UtakamoStudyApps.git   # 私のGitリポジトリURL
# Format: src-git <feed name> <Git URL>
# <feed name> ... URLが示すリポジトリ名と被らなければ好きな名前でOK

そして、次のコマンドでフィード情報をbuildrootに認識させます。

kamo@kamo:~/openwrt$ ./scripts/feeds update -p utakamo
kamo@kamo:~/openwrt$ ./scripts/feeds install -a -p utakamo

後はmake menuconfigでメニューコンフィグを開くと、utakamoという項目名で私のGitリポジトリ上に 存在するパッケージが認識されていることが確認できます。

この項目内の特定パッケージをビルドしたい場合、対象パッケージ(例:uci-sample01)にチェック<*>を入れた後にメニューコンフィグを終了<Exit>します。

そして、次のmakeコマンドを実行することで特定パッケージ(例:uci-sample01)のビルドが始まります。

kamo@kamo:~/openwrt$ make package/uci-sample01/compile
 make[1] package/uci-sample01/compile
 make[2] -C package/libs/toolchain compile
 make[2] -C package/libs/libjson-c compile
 make[2] -C package/utils/lua compile
 make[2] -C package/libs/libubox compile
 make[2] -C package/system/uci compile
 make[2] -C /home/kamo/UtakamoStudyApps/libuci-c/uci-sample01 compile

出来上がったパッケージ(.ipk)は~/openwrt/bin/packages/<ターゲットシステム名>/<フィード名(今回はutakamo)>の中に存在します。

OpenWrtデバイスにインストールしたいのであれば、パッケージをSCPコマンドなどでOpenWrtデバイスの任意のディレクトリ にアップロードした上で、OpenWrtデバイスのコンソール上で次のopkgコマンドを実行します。

root@OpenWrt:~# ls
uci-sample01_1.0-r1_aarch64_cortex-a76.ipk
root@OpenWrt:~# opkg install uci-sample01_1.0-r1_aarch64_cortex-a76.ipk
Installing uci-sample01 (1.0-r1) to root...
Configuring uci-sample01.
root@OpenWrt:~# 

作成したOpenWrtのアプリケーションパッケージをGit Hubなどに公開し、他のユーザーに使ってもらう時にfeeds.confへの記述方法を案内すると良いかもしれません。

おわり

こんな感じで、今回はOpenWrt開発入門のCoffee Break(もしくはTips集)的なことについて取り上げてみました。 少しでも、OpenWrtについて理解するための助けになれば幸いです。

ところで、この技術ブログ、OpenWrt専門ブログになっちゃっていますが、そういうわけではありません。

まだ作成中ですが今後、Raspberry Piに組み込めるリモートコントロール型の自動車ロボットの作成方法について取り上げるつもりです。 各処理単位ごとにモジュールを作り、それらがプロセス間通信によって連携することで、ユーザーによるロボット操作を可能にします。 また、ネットワークを経由してロボットカメラの視覚情報をユーザーのPC画面に映すことで、リッチなユーザービリティを提供しようと考えています。

各処理をモジュール(プロセス)化して管理しますので、機能の取り外しができることを想定しています。最近話題のchatgptとの対話機能 を追加オプションモジュールとして実装することも考えています。

ソフトウェアだけでなく、ハードウェアも絡んでくるので記事完成がいつになるやら。。。