JJUG CCC 2019 Springの懇親会でもらったOracle Code Cardを使ってみる

やること

JJUG CCC 2019 Springの懇親会でもらったOracle Code Cardを使ってみる。

f:id:rixwwd:20190605203305j:plain
Code Card

準備

とりあえず、この辺を読んで準備する。

Fn Serverを用意する

この解説によると、JSONをCode Cardに返すことができればよいみたい。 JSONを返すだけなら、適当なWebサーバーでもOKなのだが、JavaでFunctionを作ってみる。 Fn Serverは、Oracle CloudにLinux Instanceを作れって書いてあるが、Ubuntu Serverにインストールした。

  1. 普通にUUbuntu Server 18.04 LTSをインストールする
  2. Dockerは最新のDokcerをインストールする。
  3. Fnはこの手順でインストールする。

Fn ServerにAppをデプロイする。

アプリはGithubにコミットした。 github.com

git clone https://github.com/rixwwd/mycodecard.git
cd mycodecard
fn deploy --create-app --local --all

こうすると結果が返ってくるのがわかる。

$ curl http://localhost:8080/t/mycodecard/mycodecard
{"template":"template1","title":"My Code Card","subtitle":"Duke","bodytext":"Hello world","icon":"duke","backgroundColor":"white"}

Code Cardの設定

USBでPCに接続してscreenで接続する。

sudo screen /dev/ttyUSB0 115200

横の電源スイッチをONにして、2つのボタンを同時に押すと設定ができるようになる。

Code CardにWifiの設定

Code Cardのの設定モード?になったら以下を入力する。

ssid=myssid
password=wifipassword

Code Cardのボタンを押した時に呼ばれるURLの設定

Wifiの設定に続いて、以下を入力する。この場合は、ボタンAを短く押した時のURL。(1:短く押した時、2:長く押した時)

buttona1=http://192.168.1.14:8080/t/mycodecard/mycodecard

設定できたら、ボタンを押した時の動作確認を行う。設定モード?のままで以下を入力するとボタンAを短く押した時の動作をシミュレートできる。 設定モードではボタンを押しても効かず、設定モードを抜けるのは面倒なので、これで確認する。

shortpressa

エラーの対処

これで動くと見せかけでエラーになる。

Unexpected response: HTTP/1.0 200 OK

調べてみると、HTTP/1.0のレスポンスが返ってきたときはエラーになる。 Githubのこのコミットではエラーが出ないように変更されているが、使っているCode Cardはちょっと古いやつなのかもしれない。

そこで、Nginxをリバースプロキシとして、HTTP/1.0でレスポンスを返されないようにした。 ちなみに、Code CardからのHTTPリクエストをtcpdumpで確認するとHTTP/1.0で送っている。自分で送ったバージョンを受け取れないなんて残念。

nginxの設定は、

Nginx reverse proxy settings for fn server.

nginxはDockerでサクッと準備した。

docker run --rm -v $HOME/nginx.conf:/etc/nginx/nginx.conf:ro -p 80:80 nginx

再度Code Cardの設定をする。今度はnginxの経由のURLに変更した。

buttona1=http://192.168.1.14/t/mycodecard/mycodecard

これでとりあえず動いた。 結果を表示するだけだけど、電源の供給がなくても表示したまま。

ひかり電話のホームゲートウェイにFreeBSDなルーターを接続する

やること

ひかり電話のホームゲートウェイFreeBSDルーターを接続して、

  1. DHCPv6で/60のIPv6のprefixをHGWからもらう
  2. RAで/64のprefixを配布する

構成

+--------+        +---------+       +---------+
|   HGW  |        | FreeBSD |       | Xubuntu |
|        +--------+         +-------+         |
+--------+        +---------+       +---------+
  • HGWはDHCPv6 PDで/56をもらう。
  • FreeBSDのHGW側のインターフェースは、HGWからのRAを元にアドレスを設定する。(FreeBSDはRAを受信する)
  • FreeBSDXubuntu側のインターフェースは、HGWからのDHCPv6 PDでもらった/60を元にアドレスを設定する。(FreeBSDはDHCPv6のIA_PDの要求を送る)
  • XubuntuFreeBSD側のインターフェースは、FreeBSDからのRAを元にアドレスを設定する。(FreeBSDはRAを送信する)

FreeBSDのインターフェースは、

  • HGW側が、vtnet0
  • Xubuntu側が、vtnet1

とりあえずルーター用の設定

echo 'ipv6_activate_all_interfaces="YES"' >> /etc/rc.conf
echo 'ifconfig_vtnet0_ipv6="inet6 accept_rtadv" >> /etc/rc.conf
echo 'ifconfig_vtnet1_ipv6="inet6 -accept_rtadv" >> /etc/rc.conf
echo 'ipv6_cpe_wanif="vtnet0" >> /etc/rc.conf
echo 'ipv6_gateway_enable="YES" >> /etc/rc.conf

以下の設定をしておかないと、チェックサムが正しく計算されなくてうまく動かなかった。これに気がつくのに時間がかかった。 ハードウェアによるチェックサムの計算等はやらないようにしておく。

echo hw.vtnet.csum_disable=1 >> /boot/loader.conf
echo hw.vtnet.tso_disable=1 >> /boot/loader.conf
echo hw.vtnet.lro_disable=1 >> /boot/loader.conf

vtnetではない場合は、ifconfigでも設定可能。rc.confに書いておくと起動時に設定される。

ifconfig vtnet0 -rxcsum -txcsum -rxcsum6 -txcsum6 -tso -lro
ifconfig vtnet1 -rxcsum -txcsum -rxcsum6 -txcsum6 -tso -lro

設定しておかないと、tcpdumpでchecksumがincorrectになる。

01:05:47.438901 IP6 (flowlabel 0xca7c6, hlim 64, next-header TCP (6) payload length: 40) 2001:0db8:1234:5678:1234:5678:0000:001.34824 > 2001:0db8:1234:5678:1234:5678:0000:0002.3000: Flags [S], cksum 0x29e4 (incorrect -> 0xb731), seq 4096995977, win 64800, options [mss 1440,sackOK,TS val 1028813372 ecr 0,nop,wscale 7], length 0

DHCPv6で/60のIPv6のprefixをHGWからもらう

FreeBSDには標準でIPv6対応のDHCPクライアントが入っていないため、インストールする。

pkg install dhcp6

設定ファイルを作る。

# vtnet0に要求を出して、戻ってきたらvtnet1に設定する。/60をもらえるので、4ビット分IDをつけて、/64を配下に割り当てる。
cat <<EOF > /usr/local/etc/dhcp6c.conf
interface vtnet0 {
  send ia-pd 0;
  send rapid-commit;
};

id-assoc pd 0 {
  prefix-interface vtnet1 {
    sla-id 0;
    sla-len 4;
  };
};
EOF

起動時に動くようにする。&起動

echo 'dhcp6c_enable="YES"' >> /etc/rc.conf

# vtnet0はHGWに接続しているインターフェース
echo 'dhcp6c_interfaces="vtnet0"' >> /etc/rc.conf

service dhcp6c start

RAで/64のprefixを配布する

RAのデーモンを起動する。

echo 'rtadvd_enable="YES"' >> /etc/rc.conf

# vtnet1はRAする側のインターフェース
echo 'rtadvd_interfaces="vtnet1"' >> /etc/rc.conf

# raflagsはDNSサーバーのアドレスをDHCPで配布する用。
cat << EOF > /etc/rtadvd.conf 
vtnet1:\
       :raflags="o":\
       :prefixlen#64:
EOF
service rtadvd start

DHCPDNSサーバーのアドレスを配布する

echo 'option domain-name-servers 2606:4700:4700::1111;' > /usr/local/etc/dhcp6s.conf
echo 'dhcp6s_enable="YES"' >> /etc/rc.conf
echo 'dhcp6s_interface="vtnet1"' >> /etc/rc.conf
service dhcp6s start

もし、最後の起動のところで、

failed to open /usr/local/etc/dhcp6sctlkey: No such file or directory

になった場合は、このファイルを作成する。

openssl rand -base64 -out /usr/local/etc/dhcp6sctlkey 16

NanoPi NEO2用のNanoBSDのSDイメージにmDNSResponderを入れる

やること

NanoPi NEO2用のNanoBSDのSDイメージにmDNSResponderを入れる。 DHCPIPアドレスを割り当てる環境下で、sshで接続するときにIPアドレスがわからなくなってnmapで探していたのを解消する。

pkgでmDNSResponderを入れる

# SDをマウント。
mkdir /tmp/nanopi-root
mount /dev/da0s2a /tmp/nanopi-root

# chrootしたときに名前解決できないのを防ぐ?(crochetのスクリプトの真似)
cp -i /etc/resolv.conf /tmp/nanopi-root/etc/

# ルートディレクトリを指定してpkgを実行する
pkg -c /tmp/nanopi-root install -y -r FreeBSD mDNSResponder mDNSResponder_nss howl
rm -i /tmp/nanopi-root/etc/resolv.conf

設定

# 設定ファイルのパーティションをマウント
mkdir /tmp/nanopi-cfg
mount /dev/da0s2d /tmp/nanopi-cfg

# 設定書き換え
cp -i /tmp/nanopi-root/etc/nsswitch.conf /tmp/nanopi-cfg
sed -i -e 's/^hosts: files dns/hosts: files mdns dns/' /tmp/nanopi-cfg/nsswitch.conf

# 自動起動するようにしておく
echo 'mdnsd_enable="YES"' >> /tmp/nanopi-cfg/rc.conf
echo 'mdnsresponder_enable="YES"' >> /tmp/nanopi-cfg/rc.conf

crochetで作ったNanoBSDは/conf/base/etc/localに/usr/local/etcのコピーを持っているので、コピーする。この辺りの詳細はdiskless(8)参照。

cp -pv /tmp/nanopi-root/usr/local/etc/rc.d/mdnsd \
   /tmp/nanopi-root/usr/local/etc/rc.d/mdnsresponderposix \
   /tmp/nanopi-root/usr/local/etc/rc.d/mdnsresponder \
   /tmp/nanopi-root/conf/base/etc/local/rc.d

後始末

umount /tmp/nanopi-cfg
umount /tmp/nanopi-root

pingでDUP!って出る件の続き

少しまえから気になっていた、pingDUP!って出る件について。

rixwwd.hatenablog.jp

原因は、Aterm WG1200HSっぽい。

pingの元は、ブリッジモードで動作しているWS1200HSにWifiで接続している。 WS1200HSのWANポートにHUBを接続していて、そのHUBにpingの宛先がある。

WS1200HSを別のやつに取り替えたら、DUPは出なくなった。そして元に戻すとまたDUP!ってなる。

WS1200HSをルーターモードにして、WANポートではない普通のポートをHUBに接続してみたら、DUPにはならなかった。今のところは。 というわけでこの構成で放置して様子を見る。

KVMのためのブリッジ作成

やること

KVMで使うためのブリッジを作る。 KVM仮想マシンからホストと同じネットワークにアクセスしたい。

コマンド

nmcli c add type bridge ifname mybridge con-name mybridge autoconnect yes stp no multicast-snooping no
nmcli c up mybridge
nmcli c add type bridge-slave ifname enp0s31f6 master mybridge
nmcli c up bridge-slave-enp0s31f6

ブリッジができたら

KVM仮想マシンNICにブリッジを指定する。

ubldrの起動パーティションの切り替え

やること

crochetでNanoBSDを作ると、/dev/mmcsd0s2aと/dev/mmcsd0s2bができる。

mmcsd0s2a: 今のバージョンのFreeBSD
mmcsd0s2b: 未使用

なので、mmcsd0s2bに新しいバージョンのFreeBSDをインストールしてみたメモ。

OSの準備

crochetを使って準備する。

u-bootからubldrを呼び出すスクリプトの準備

ubldrのソースを見ると環境変数loaderdevで起動パーティションを切り替えていた。boot.scrでloaderdevを設定するようにした。

boota.cmdとする。

setenv loaderdev mmc0:1.0;fatload ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} ubldr.bin && go ${kernel_addr_r}
echo "Cannot load ubldr.bin"

bootb.cmdはmmc0:1.0の部分をmmc0:1.1として作る。

それができたら、mkimageを使ってu-bootで読み込めるファイルを作る。

mkimage -A arm -O FreeBSD -T script -c none -d boota.cmd boota.scr
mkimage -A arm -O FreeBSD -T script -c none -d bootb.cmd bootb.scr

SDカード書き込み

ここからRaspberry Piでの作業。 イメージをネットワーク経由で取得して書き込む。イメージのaをSDのbに書き込むのは注意。

mount_smbfs -I 192.168.1.13 //foo@192.168.1.13/public /mnt
mdconfig -f /mnt/FreeBSD-armv6-12.0-RPI-B-344277P-RaspberryPi.img
dd status=progress if=/dev/md0s2a of=/dev/mmcsd0s2b bs=1m
mdconfig -d -u 0

# ついでにboot scriptも転送
cp /mnt/boota.scr /mnt/bootb.scr /tmp
umount /mnt

ブートのスクリプトを変える

mount -tmsdosfs -o noatime /dev/mmcsd0s1 /mnt
mv -i /mnt/boot.scr /mnt/boot.scr.original
cp -ip /tmp/boota.scr /tmp/bootb.scr /mnt

# bから起動したいのでbootbをコピーする。
cp -ip /tmp/bootb.scr /mnt/boot.scr
sync
umount /mnt

fstabの書き換え

/dev/mmcsd0s2aから起動しないようにfstabを書き換える。

mount -o noatime /dev/mmcsd0s2b /mnt
cp -ip /mnt/etc/fstab /mnt/etc/fstab.original
sed -i -e 's|mmcsd0s2a|ufs/rootfs|g' /mnt/etc/fstab
sync
umount /mnt

tunefs -L '' /dev/mmcsd0s2a
tunefs -L 'rootfs' /dev/mmcsd0s2b

最後に再起動。

reboot

起動したら新しいバージョンで起動しているのを確認する。

unman -a

前のバージョンに戻したくなったら、FATバーティションのboot.scrをboota.scrに戻せばOK。 aとbのパーティションに交互に使うことで、常に前のバージョンに戻せる状態を維持しながらアップデートできる。 あと、アップデートがRaspberry Pi単独でできる。