え?まだ1.1使ってるの?いやいやその前に今時XMLRPCなの?という本質的な疑問はとりあえず横に置いておいて。
XMLRPCを使ったプロトタイプをPythonで作る場合、Python付属のSimpleXMLRPCServerとxmlrpclibを使うのが一番簡単な方法ではないかと思います。Pythonのドキュメントにもこれらのライブラリを使ったXMLRPCサーバーおよびクライアントの解説があります。
ドキュメントに書かれている内容に従ってサーバーを実装すると、HTTPバージョンとして1.0が使われます。もちろん、普通に動作するのですが、RPCの度にTCP (HTTP) 接続を確立するので効率が気になります。短時間に大量のRPCを発行する場合は特にそうです。HTTPバージョン1.1では一度確立したHTTP接続で何度でもコマンドのやりとりが出きるので、できればHTTPバージョン1.1を使いたいと思っていたのですが、軽く検索してみてもなかなかこれといった情報が見つからず、かといって自前でHTTPバージョン1.1対応するのも面倒で放置していました。
先日Pythonのドキュメントを見ていたら、BaseHTTPRequestHandlerにprotocol_versionという変数があり、これをHTTP/1.1に設定することでBaseHTTPRequestHandlerを使っているSimpleHTTPServerなどがHTTPバージョン1.1対応になるという記述を公式ドキュメントに発見しました。対象ライブラリの説明だけでなく、きちんと親クラスの説明も読まないとダメですね。SimpleXMLRPCServerもPRCリクエストの処理にBaseHTTPRequestServer由来のSimpleXMLRPCRequestHandlerを使っているのでなんとかなりそうです。
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
class HTTP11SimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
protocol_version = 'HTTP/1.1'
class RPCMethods(object):
def add(self, a, b):
return a + b
server = SimpleXMLRPCServer(('', 8000), requestHandler=
HTTP11SimpleXMLRPCRequestHandler)
server.register_instance(RPCMethods())
server.serve_forever()
これでめでたくXMLRPCサーバーがHTTPバージョン1.1で応答するようになりました。xmlrpclibを用いたクライアントの方は、どうやら標準でHTTPバージョン1.1を使うらしく、サーバー側を対応するだけで永続接続が使えるようになります。
検索してでてこないということは、誰も使っていない (あるいは当たり前すぎて質問もされない) ということかもしれませんが、将来の自分のためのメモとして残しておきます。
2015年1月22日木曜日
2015年1月13日火曜日
Force10にOpen Network Linuxをインストール (その2)
Open Network Linux (ONL) で配布されている公式バイナリは、現在のところパケット転送機能を提供していません。これは2014年5月に開催されたOpen Compute Engineering WorkshopでBig Switch NetworksのRob Sherwood氏の資料にも明記してあります (14ページ)。実際、ONLのバイナリをForce10にインストールしただけの状態では管理用のイーサネットポートのみしか見えていなかったのは前回の記事に書いた通りです。
ハードウェアレベルでパケット転送をするためのルール設定にはASICとの通信が必要になります。通常、ASICへのアクセス情報を入手するためにはNDAの締結が必要になるため、ハードウェアアクセス部分を切り離してオープンソース化されているようです。
Rob Sherwood氏の資料によれば、以下の3種類のパケット転送モジュールが (2014年5月時点での) 近日中にリリースされると書かれています。
ハードウェアレベルでパケット転送をするためのルール設定にはASICとの通信が必要になります。通常、ASICへのアクセス情報を入手するためにはNDAの締結が必要になるため、ハードウェアアクセス部分を切り離してオープンソース化されているようです。
Rob Sherwood氏の資料によれば、以下の3種類のパケット転送モジュールが (2014年5月時点での) 近日中にリリースされると書かれています。
- Indigo2ベースのオープンフローエージェント
- OF-DPAベースの転送エージェント
- おもちゃの転送エージェントOpen Route Cache (ORC)
このうち、ORCは最新のONL配布物に含まれており、基本的な機能しか使えないものの、ONL箱をルータとして使うことができます。OF-DPAに関しては、githubで資料と参照コードが公開されているものの、現時点では簡単に利用できるものではなさそうです。
ORC自体のソースコードは公開されているのですが、Force10が採用しているBroadcomのASICにアクセスするためのライブラリはバイナリ状態でのみ提供されています。ORCはそのライブラリを動的にリンクし、ASICの操作を実現しています。
以下の手順でORCを起動します。
root@onl-powerpc:~# orc --daemon
ifconfig (もしくは ip link) コマンドでインターフェースを確認してみると、orcXXという名前で52個のインターフェースが作成されていることが確認できます。インターフェースにアドレスを設定すれば、他の機器と通信できます。また、ip routeコマンドなどで経路を設定すればパケット転送もできます。ハードウェア転送されていることを確認するには、tcpdumpコマンドでインターフェースをモニターしてみるとよいでしょう。Linuxカーネルにパケットが上がってこないため、tcpdumpでは転送されたパケットを観測することができないはずです。
ORCはLayer 3のパケット転送を補助するもので、Layer 2の機能は利用できません。スイッチ機器では複数のポートをひとつのブリッジにまとめて利用することが多いと思いますが、ORCではブリッジ設定ができません。残念ながら実用的な処理をさせることは難しいでしょう。
ORCのソースコードを見てみると、どうやって経路制御プログラムとASICの間で情報をやりとりすればよいかがうっすらと見えてきます。ORCでは、カーネルの経路制御操作時に発行されるNETLINKメッセージを観測し、インターフェースのアドレス情報、転送に必要となるFIBの情報などを適宜ASICライブラリを経由してハードウェアに落とし込んでいます。ASICライブラリはORC専用のもので、汎用的なアクセスライブラリが提供されているわけではないため、同じASICライブラリを別の用途で再利用するのは困難だと思われます。やはり本格的なスイッチを作ろうと思ったら、専用のアクセスライブラリを自作する必要があるようです。
Open Network Linuxは、ダウンドードしてきてそのまま使うソフトウェアというよりは、スイッチベンダー、SDN、NFV開発ベンダーが独自の機能を持った高性能なパケット転送装置を自作するための部品として考えるのが良さそうです。運用部分に慣れ親しんだLinuxを使い、なおかつ必要に応じてハードウェアアクセラレーション機能を組み込める箱が必要な場合には魅力的な選択肢になりそうでうs。
ORCのソースコードを見てみると、どうやって経路制御プログラムとASICの間で情報をやりとりすればよいかがうっすらと見えてきます。ORCでは、カーネルの経路制御操作時に発行されるNETLINKメッセージを観測し、インターフェースのアドレス情報、転送に必要となるFIBの情報などを適宜ASICライブラリを経由してハードウェアに落とし込んでいます。ASICライブラリはORC専用のもので、汎用的なアクセスライブラリが提供されているわけではないため、同じASICライブラリを別の用途で再利用するのは困難だと思われます。やはり本格的なスイッチを作ろうと思ったら、専用のアクセスライブラリを自作する必要があるようです。
Open Network Linuxは、ダウンドードしてきてそのまま使うソフトウェアというよりは、スイッチベンダー、SDN、NFV開発ベンダーが独自の機能を持った高性能なパケット転送装置を自作するための部品として考えるのが良さそうです。運用部分に慣れ親しんだLinuxを使い、なおかつ必要に応じてハードウェアアクセラレーション機能を組み込める箱が必要な場合には魅力的な選択肢になりそうでうs。
2014年12月8日月曜日
Force10にOpen Network Linuxをインストール
ONIE版Force10だと、Cumulus Linuxを使っている人が一般的(?)かと思いますが、同じONIE準拠ならONLも入るんじゃね?と言われ試してみることに。Force10にはx86系を使ったS6000-ONとPowerPCを使ったS4810-ONがあります。ONLでプリビルドされて配布されているものはPowerPC用になるので、S4810-ONが対象です。
素の状態のONIE版Force10なら、最初に起動したときにONIEプロンプトに落ちるはずですが、一旦Cumulus Linuxをインストールしてしまうと、そちらからブートしてしまいます。まずはブートプロンプトに落とすため、U-Bootのイメージブート待ちカウントダウンの段階で、なにかキーを押してU-Bootプロンプトに落とします。
U-Bootには、ONIEを実行するための環境変数がいくつか事前に設定されているので、それを使ってONIEを起動します。
dni_7448-> run onie_bootcmd
(ONIEブートメッセージ)
ONIE:/ #
ONIEプロンプトが出てきたら、ONLのインストール手順に従って作業を進めます。
ONIE:/ # wget http://opennetlinux.org/binaries/latest.installer
latest.installer 100% |*******************************| 188M 0:00:00 ETA
ONIE:/ # sh latest.installer
(インストールログメッセージ)
Partition Map for MMC device 0 -- Partition Type: DOS
Part Start Sector Num Sectors UUID Type
1 16 31280 00000000-01 83
2 31296 125056 00000000-02 83
3 156352 15883584 00000000-03 83
reading onl-loader
6775021 bytes read in 356 ms (18.1 MiB/s)
WARNING: adjusting available memory to 30000000
## Booting kernel from Legacy Image at 10000000 ...
Image Name:
Image Type: PowerPC Linux Multi-File Image (gzip compressed)
Data Size: 6774957 Bytes = 6.5 MiB
Load Address: 00000000
Entry Point: 00000000
Contents:
Image 0: 3384879 Bytes = 3.2 MiB
Image 1: 3382017 Bytes = 3.2 MiB
Image 2: 8041 Bytes = 7.9 KiB
Verifying Checksum ... OK
## Loading init Ramdisk from multi component Legacy Image at 10000000 ...
## Flattened Device Tree from multi component Image at 10000000
Booting using the fdt at 0x10674184
Uncompressing Multi-File Image ... OK
Loading Ramdisk to 2fcc6000, end 2ffffb01 ... OK
Loading Device Tree to 03ffb000, end 03ffff68 ... OK
setup_arch: bootmem
delta_7448_setup_arch()
arch: exit
Open Network Linux Loader [Open Network Linux 48f7842 (powerpc,2014.10.05.03.03,
48f7842bf909c43a4840e8d827e55edc113c299e)]
Open Network Linux installer [Open Network Linux 8f3e53e (powerpc.all,2014.11.04
.22.55,8f3e53ebcdcd5edea042e15ec852c904a6cafd6c)]
Press Control-C now to enter loader shell
Booting flash2:onl-powerpc.swi
FDT_ERR_NOSPACE: Unable to add reserve for cpu-release-addr!
Starting new kernel
setup_arch: bootmem
delta_7448_setup_arch()
arch: exit
INIT: version 2.88 booting
Using makefile-style concurrent boot in runlevel S.
Starting the hotplug events dispatcher: udevd.
Synthesizing the initial hotplug events...done.
Waiting for /dev to be fully populated...done.
Setting up block and net devices...done.
Setting kernel variables ...done.
Setting up sensors configuration...done.
Setting up resolvconf...done.
Configuring network interfaces...done.
Restoring persistent files...done.
Creating SSH2 RSA key...done.
Creating SSH2 DSA key...done.
Creating SSH2 ECDSA key...done.
INIT: Entering runlevel: 2
Using makefile-style concurrent boot in runlevel 2.
Not starting fancontrol; run pwmconfig first. ... (warning).
Starting enhanced syslogd: rsyslogd.
Starting Fault Agent: faultd.
Loading empty startup-config...failed.
Starting network management services: snmpd.
Starting OpenBSD Secure Shell server: sshd.
Open Network Linux 8f3e53e (powerpc.all,2014.11.04.22.24,8f3e53ebcdcd5edea042e1
5ec852c904a6cafd6c)
onl-powerpc login:
標準のブートイメージでは、ハードウェアに搭載されているスイッチポートは使えません。別途ライセンスを結ぶなどしてチップドライバーを組み入れる必要があります。素のONLをインストールした直後に見えているインターフェースは以下のものでした。
root@onl-powerpc:~# ifconfig -a
dummy0 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX
BROADCAST NOARP MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:456 (456.0 B) TX bytes:456 (456.0 B)
ma1 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Base address:0xa000
sit0 Link encap:IPv6-in-IPv4
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
ひとまず起動はしたということで。
2014年4月16日水曜日
OpenStackでNative VXLANテナントを使う
久方ぶりの更新でBloggerの使い方も忘れてるくらいの勢いです。
しばらく前からOpenStackなどが流行っているようですが、すっかり流れに乗り遅れてしまいました。諸般の事情により、最近ようやくOpenStackに触り始めています。とはいうものの、いまさらOpenStackの導入とか書いてもネットの海に埋もれるだけです。なので、まだあまり見かけないNative VXLANをテナントネットワークとして使う設定を、自分のメモという意味も含めて記録しておこうと思います。
ここではOpenStackの導入については「全く」述べません。そのあたりは、巷に溢れているブログなりを参考にしていただければと思います。もっとも、公式のドキュメントがかなりよくできているので、ゼロから一歩一歩導入を試したい人はそちらをご覧になることをお勧めします。簡単に導入したい人向きにはRed Hat Inc.のRDOなども人気が高いようです。
Native VXLAN (以後、単にVXLANと呼びます) をテナントネットワークとして使うためには、いくつか準備が必要です。
まず、/etc/neutron/neutron.confでML2プラグインを利用するように設定します。
core_plugin = neutron.plugins.ml2.plugin.Ml2Plugin
service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin
続いて、/etc/default/neutron-serverでneutron-serverが起動時に読み込む設定ファイルをML2プラグインにします。(Ubuntu 12.04の場合)
NEUTRON_PLUGIN_CONFIG="/etc/neutron/plugins/ml2/ml2_conf.ini"
これらの設定は、今後OpenStackでは標準設定になっていくと思われます。Icehouse以降では設定不要になっているかもしれません。
VXLANでテナントネットワークを構成するためには、L2エージェントとしてLinux Bridgeエージェントを使う必要があります。世にある情報の多くは、Open vSwitchエージェントとGREトンネルによるテナントネットワークの構成例となっているようですので、NeutornのL2エージェントを導入する際に気をつけてください。
ML2プラグインの設定ファイル/etc/neutron/plugins/ml2/ml2_conf.iniは以下のようになります。
[ml2]
tenant_network_types = vxlan,flat
type_drivers = vxlan,flat
mechanism_drivers = linuxbridge
[ml2_type_flat]
flat_networks = public0
[ml2_type_vxlan]
vni_ranges= 1000:2000
[securitygroup]
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
しばらく前からOpenStackなどが流行っているようですが、すっかり流れに乗り遅れてしまいました。諸般の事情により、最近ようやくOpenStackに触り始めています。とはいうものの、いまさらOpenStackの導入とか書いてもネットの海に埋もれるだけです。なので、まだあまり見かけないNative VXLANをテナントネットワークとして使う設定を、自分のメモという意味も含めて記録しておこうと思います。
ここではOpenStackの導入については「全く」述べません。そのあたりは、巷に溢れているブログなりを参考にしていただければと思います。もっとも、公式のドキュメントがかなりよくできているので、ゼロから一歩一歩導入を試したい人はそちらをご覧になることをお勧めします。簡単に導入したい人向きにはRed Hat Inc.のRDOなども人気が高いようです。
Native VXLAN (以後、単にVXLANと呼びます) をテナントネットワークとして使うためには、いくつか準備が必要です。
- iproute2がVXLANに対応している
- NeutronでML2プラグインが使え、かつML2プラグインがVXLANに対応している
まず、/etc/neutron/neutron.confでML2プラグインを利用するように設定します。
service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin
続いて、/etc/default/neutron-serverでneutron-serverが起動時に読み込む設定ファイルをML2プラグインにします。(Ubuntu 12.04の場合)
NEUTRON_PLUGIN_CONFIG="/etc/neutron/plugins/ml2/ml2_conf.ini"
これらの設定は、今後OpenStackでは標準設定になっていくと思われます。Icehouse以降では設定不要になっているかもしれません。
VXLANでテナントネットワークを構成するためには、L2エージェントとしてLinux Bridgeエージェントを使う必要があります。世にある情報の多くは、Open vSwitchエージェントとGREトンネルによるテナントネットワークの構成例となっているようですので、NeutornのL2エージェントを導入する際に気をつけてください。
ML2プラグインの設定ファイル/etc/neutron/plugins/ml2/ml2_conf.iniは以下のようになります。
[ml2]
tenant_network_types = vxlan,flat
type_drivers = vxlan,flat
mechanism_drivers = linuxbridge
flat_networks = public0
vni_ranges= 1000:2000
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
Linux Bridgeエージェントの設定ファイル/etc/neutron/plugins/linxbridge_conf.iniは以下のようになります。
[linux_bridge]
physical_interface_mappings = public0:eth0
[vxlan]
enable_vxlan = True
local_ip = (ノードのIPアドレス)
[securitygroup]
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
なお、ML2プラグインの設定はneutron-serverが動作するノード (通常は管理ノード) のみで大丈夫です。またLinux Bridgeエージェントの[linux_bridge]セクションの設定はゲートウェイとなるノード (L3エージェントやDHCPエージェントを動作させているノード) で設定するだけで大丈夫です。eth0はゲートウェノードのインターネット側の物理インターフェース名です。コンピュートノードには[vxlan]セクションの設定だけを入れておきます。
VXLANを使う上で注意しなければならないことは、VXLANのカプセル化のため、ペイロードが50バイト小さくなることです。Linuxで普通にVXLAN仮想インターフェースを構成すると、MTUが1450になっていると思います。このままだと、OpenStackの仮想ブリッジ内でMTU 1500のインターフェースと1450のインターフェースが混じることになり、パケットが通らない場合が発生します。これを回避するため、ゲートウェイノードとコンピュートノードが通信する物理インターフェースのMTUをあらかじめ1550に設定しておく必要があります。
テナント共用となる外部ネットワークを作成する場合、外部ネットワークをflatタイプで構成します。以下は外部ネットワーク名をexternal1として、external1-subnet1というサブネットに172.16.0.0/24が割り当てられている場合の構成例です。
neutron net-create external1 \
--tenant-id ${SERVICE_TENANT_ID} \
--provider:network_type flat \
--provider:physical_network public0 \
--router:external=True
neutron subnet-create external1 172.16.0.0/24 \
--name external1-subnet1 \
--tenant-id ${SERVICE_TENANT_ID} \
--gateway 172.16.0.1 \
--allocation-pool start=172.16.0.64,end=172.16.0.254 \
--disable-dhcp \
--dns-nameserver 172.16.0.1
テナントネットワークはVXLANで構成します。外部ネットワークが作成されていれば、テナントネットワークはDashboardからも作成できますが、コマンドラインで実行する場合は、例えば下のようになります。以下の例は、テナントネットワークとしてdemo-private1を構成し、demo-private1-subnet1という名前で10.0.0.0/24を割り当てる場合の構成例です。
neutron net-create demo-private1 \
--tenant-id ${TENANT_ID} \
--provider:network_type vxlan \
--provider:segmentation_id 1000
neutron subnet-create demo-private1 10.0.0.0/24 \
--name demo-private1-subnet1 \
--tenant-id ${TENANT_ID}
--tenant-id ${TENANT_ID} \
--provider:network_type vxlan \
--provider:segmentation_id 1000
neutron subnet-create demo-private1 10.0.0.0/24 \
--name demo-private1-subnet1 \
--tenant-id ${TENANT_ID}
2010年12月24日金曜日
App Inventorを使ってみた
Google Japan Developer Relations BlogでApp Inventorが公開βになったと紹介されていたので使ってみました。ちょうど、最近ブログの更新もさぼっていたし。
とりあえず、加速度センサーの値を表示させるアプリを作ってみます。iPhoneでも昔作ったけど、まぁそれなりに手間のかかるコーディングが必要でした。App Inventorでは、なるほど広告通り、あっという間にアプリが出来上がります。一昔前に流行った(いや、流行り損ねた?)Java Beansを彷彿とさせるプログラミング。
まず手元のコンピュータに必要なツール類をインストールする必要があります。ツールはApp Inventor Setupページからダウンロードしましょう。今のところ、Mac、Linux、Windowsをサポートしているようです。あと、Java環境も必要です。SetupページにJava環境のチェックができるページへのリンクが張られているので、手元のコンピュータのJava環境を整備しておきます。
次にAndroid端末の設定をします。エミュレータも提供されているようですが、ちょうど手元にNexus Oneがあるので、これを使うことにします。端末側の設定としては、「提供元不明のアプリ」を許可し、「USBデバッグ」モードをオン、「スリープモードにしない」をオンに設定するだけです。なお、コンピュータと接続中にUSBストレージモードになっているとうまく動作しないため、接続直後にストレージモードになる設定をしている場合は、コンピュータに接続後に手動でストレージモードをオフにする必要があります。
あとは、App Inventorホームでプログラム開始です。とりあえず加速度センサーの値が表示されればいいので、以下のような画面をデザインしました。

テーブルビューを配置して、その中にラベルを6つはめ込んだだけです。あと、不可視コンポーネントとしてAccelerometerSensor1を追加しています。
次に、これらの間の関係を定義するために、画面右上の(ちょっと切れていますが)Open the Blocks Editorをクリックしてブロックエディタを起動します。ここでビジュアルにプログラムするのですが、途中は省略して、最終的に以下のようなブロックダイアグラムを作ります。

AccelerometerSensor1.AccelerationChangedは、加速度センサーの値が変更されたときに実行されるモジュールですので、その中で、センサーの値を表示している3つのラベル(X、Y、Z軸)に各軸のセンサーの値を設定するだけです。
コンピュータに実端末を接続している場合は、ブロックエディタでConnect to Deviceをクリックすると、自動的にプログラムが走り始めます。
プログラムに問題がなければ、App Inventorのページに戻って、Package for Phoneをクリックすると、今作ったプログラムが端末に転送、インストールされます。
まぁ、とても簡単なのですが、果たしてこれ、どれくらいまで細かい内容をプログラムできるのか、もうちょっと遊んでみないと分からないですね。
とりあえず、加速度センサーの値を表示させるアプリを作ってみます。iPhoneでも昔作ったけど、まぁそれなりに手間のかかるコーディングが必要でした。App Inventorでは、なるほど広告通り、あっという間にアプリが出来上がります。一昔前に流行った(いや、流行り損ねた?)Java Beansを彷彿とさせるプログラミング。
まず手元のコンピュータに必要なツール類をインストールする必要があります。ツールはApp Inventor Setupページからダウンロードしましょう。今のところ、Mac、Linux、Windowsをサポートしているようです。あと、Java環境も必要です。SetupページにJava環境のチェックができるページへのリンクが張られているので、手元のコンピュータのJava環境を整備しておきます。
次にAndroid端末の設定をします。エミュレータも提供されているようですが、ちょうど手元にNexus Oneがあるので、これを使うことにします。端末側の設定としては、「提供元不明のアプリ」を許可し、「USBデバッグ」モードをオン、「スリープモードにしない」をオンに設定するだけです。なお、コンピュータと接続中にUSBストレージモードになっているとうまく動作しないため、接続直後にストレージモードになる設定をしている場合は、コンピュータに接続後に手動でストレージモードをオフにする必要があります。
あとは、App Inventorホームでプログラム開始です。とりあえず加速度センサーの値が表示されればいいので、以下のような画面をデザインしました。

テーブルビューを配置して、その中にラベルを6つはめ込んだだけです。あと、不可視コンポーネントとしてAccelerometerSensor1を追加しています。
次に、これらの間の関係を定義するために、画面右上の(ちょっと切れていますが)Open the Blocks Editorをクリックしてブロックエディタを起動します。ここでビジュアルにプログラムするのですが、途中は省略して、最終的に以下のようなブロックダイアグラムを作ります。

AccelerometerSensor1.AccelerationChangedは、加速度センサーの値が変更されたときに実行されるモジュールですので、その中で、センサーの値を表示している3つのラベル(X、Y、Z軸)に各軸のセンサーの値を設定するだけです。
コンピュータに実端末を接続している場合は、ブロックエディタでConnect to Deviceをクリックすると、自動的にプログラムが走り始めます。
プログラムに問題がなければ、App Inventorのページに戻って、Package for Phoneをクリックすると、今作ったプログラムが端末に転送、インストールされます。
まぁ、とても簡単なのですが、果たしてこれ、どれくらいまで細かい内容をプログラムできるのか、もうちょっと遊んでみないと分からないですね。
2010年4月13日火曜日
IPv4 to IPv6, IPv6 to IPv4 translator
ちょっとした必要に迫られて、IPv4とIPv6のプロトコル変換プログラムを作りました。動作は至ってシンプルで、あるひとつのIPv6アドレスを、別のユニークなIPv4アドレスに変換(また、その逆変換)を行うものです。最近流行っている、NAT64のような、複数のIPv6ノードがひとつのIPv4アドレスを共有して通信するものとは異なります。
そもそもの目的は、IPv6のみを使って構築運用されているネットワークの内部ノードを、外部に公開することでした。もちろん、IPv6を使えば、普通に外部からアクセスできるのですが、まだまだIPv6の利用が一般的ではない現在、IPv4での公開も考えなければなりません。こうした目的の場合、一般的にはIPv4とIPv6のデュアルスタック環境にするところです。しかしながら、必ずしもすべてのIPv6ノードがIPv4でアクセスできる必要はありません。運用されているIPv6ノードの中で、サーバとして公開されるものは極わずかであり、多くのノードはそのサーバのサポートをしているだけだからです。そのようなノードに、貴重なIPv4アドレスを割り当てるのはもったいないですし、またデュアルスタックにすることで運用のコストも大きくなりかねません。
そこで、公開サーバの数を収容するために必要十分なIPv4アドレスを用意して、単純に1対1で対応させてしまおう、ということになります。言ってみれば、IPv6への移行が完了するまでの、つなぎの技術ですね。
仕組み自体はNAT64とDNS64のものとほとんど変わりません。違いはトランスポート層のポート番号の変換処理が必要かどうかです。アドレスを1対1で対応させる場合、ポート番号を処理する必要がないので、変換サーバがNATのような状態を持つ必要がなくなります。状態を持たなくてよいので、負荷分散あるいは耐障害性の向上のために、簡単に多重化できるという利点があります。欠点はNAT64に比べてたくさんのIPv4アドレスが必要になることです。なにせ1対1対応ですから。
実装はtunデバイスを使っています。最近のOSなら標準でサポートしているものも多いのではないでしょうか。tunデバイスを使えば、read(2)システムコールとwrite(2)システムコールで生のIPパケットを読み書きできるので、今回のような目的にぴったりです。ユーザ空間で実装できるので、開発やデバッグも簡単になります。当然、転送速度は遅くなると思いますが、開発の簡単さ、もともとの目的がつなぎの技術であることを考えると、そう悪い選択でもないでしょう。
動作はちょっと複雑です。まず、IPv6ノードがIPv4ノードにアクセスする場合から考えてみます。IPv6ノードはIPv4アドレスを持っていないため、まずIPv4アドレスとIPv6アドレスの対応を定義します。ここでは例として、IPv6ネットワークのプレフィックスを2001:db8:0:0::/64、IPv4グローバルアドレス空間を192.0.2.0/24と仮定しましょう。以下のようなアドレスの対応を定義します。
つまり、外部のIPv4ノードが2001:db8:0:0::100と通信したいと思ったときは、192.0.2.1に対して接続すればよいということになります。192.0.2.1に届いたIPv4パケットは、IPv6に変換されて2001:db8:0:0::100に転送されます。このとき、変換後のIPv6パケットの始点アドレスには、通信相手のIPv4アドレスが識別できるよう、IPv6アドレスの一部にIPv4アドレスを埋め込んでおきます。始点アドレスとして使うIPv6プレフィックスはなんでもよいのですが、仮に64::/64を使うとしましょう。外部のIPv4ノードのアドレスが202.214.86.196だった場合、変換後の始点アドレスは64::cad6:56c4となります。IPv4アドレス4バイト分が、IPv6アドレスの下4バイトに埋め込まれた形になります。
逆方向の通信には、上記の手順を逆に適用します。2001:db8:0:0::100から64::cad6:56c4に対してパケットを送信すると、変換サーバでIPv6宛先アドレスの下4バイトからIPv4宛先アドレス202.214.86.196を取り出します。また、あらかじめ定義されたIPv4とIPv6アドレスの対応表から、始点アドレスとして使うIPv4アドレス(この場合は192.0.2.1)を取り出し、IPv4パケットとして転送するのです。
コードはgithubで公開しています。興味のある方は http://github.com/keiichishima/map646 にアクセスしてみてください。forkも大歓迎です。
そもそもの目的は、IPv6のみを使って構築運用されているネットワークの内部ノードを、外部に公開することでした。もちろん、IPv6を使えば、普通に外部からアクセスできるのですが、まだまだIPv6の利用が一般的ではない現在、IPv4での公開も考えなければなりません。こうした目的の場合、一般的にはIPv4とIPv6のデュアルスタック環境にするところです。しかしながら、必ずしもすべてのIPv6ノードがIPv4でアクセスできる必要はありません。運用されているIPv6ノードの中で、サーバとして公開されるものは極わずかであり、多くのノードはそのサーバのサポートをしているだけだからです。そのようなノードに、貴重なIPv4アドレスを割り当てるのはもったいないですし、またデュアルスタックにすることで運用のコストも大きくなりかねません。
そこで、公開サーバの数を収容するために必要十分なIPv4アドレスを用意して、単純に1対1で対応させてしまおう、ということになります。言ってみれば、IPv6への移行が完了するまでの、つなぎの技術ですね。
仕組み自体はNAT64とDNS64のものとほとんど変わりません。違いはトランスポート層のポート番号の変換処理が必要かどうかです。アドレスを1対1で対応させる場合、ポート番号を処理する必要がないので、変換サーバがNATのような状態を持つ必要がなくなります。状態を持たなくてよいので、負荷分散あるいは耐障害性の向上のために、簡単に多重化できるという利点があります。欠点はNAT64に比べてたくさんのIPv4アドレスが必要になることです。なにせ1対1対応ですから。
実装はtunデバイスを使っています。最近のOSなら標準でサポートしているものも多いのではないでしょうか。tunデバイスを使えば、read(2)システムコールとwrite(2)システムコールで生のIPパケットを読み書きできるので、今回のような目的にぴったりです。ユーザ空間で実装できるので、開発やデバッグも簡単になります。当然、転送速度は遅くなると思いますが、開発の簡単さ、もともとの目的がつなぎの技術であることを考えると、そう悪い選択でもないでしょう。
動作はちょっと複雑です。まず、IPv6ノードがIPv4ノードにアクセスする場合から考えてみます。IPv6ノードはIPv4アドレスを持っていないため、まずIPv4アドレスとIPv6アドレスの対応を定義します。ここでは例として、IPv6ネットワークのプレフィックスを2001:db8:0:0::/64、IPv4グローバルアドレス空間を192.0.2.0/24と仮定しましょう。以下のようなアドレスの対応を定義します。
- 192.0.2.1 <=> 2001:db8:0:0::100
つまり、外部のIPv4ノードが2001:db8:0:0::100と通信したいと思ったときは、192.0.2.1に対して接続すればよいということになります。192.0.2.1に届いたIPv4パケットは、IPv6に変換されて2001:db8:0:0::100に転送されます。このとき、変換後のIPv6パケットの始点アドレスには、通信相手のIPv4アドレスが識別できるよう、IPv6アドレスの一部にIPv4アドレスを埋め込んでおきます。始点アドレスとして使うIPv6プレフィックスはなんでもよいのですが、仮に64::/64を使うとしましょう。外部のIPv4ノードのアドレスが202.214.86.196だった場合、変換後の始点アドレスは64::cad6:56c4となります。IPv4アドレス4バイト分が、IPv6アドレスの下4バイトに埋め込まれた形になります。
逆方向の通信には、上記の手順を逆に適用します。2001:db8:0:0::100から64::cad6:56c4に対してパケットを送信すると、変換サーバでIPv6宛先アドレスの下4バイトからIPv4宛先アドレス202.214.86.196を取り出します。また、あらかじめ定義されたIPv4とIPv6アドレスの対応表から、始点アドレスとして使うIPv4アドレス(この場合は192.0.2.1)を取り出し、IPv4パケットとして転送するのです。
コードはgithubで公開しています。興味のある方は http://github.com/keiichishima/map646 にアクセスしてみてください。forkも大歓迎です。
2009年11月20日金曜日
自分で作るネットワークストレージ (2)
ファイルシステムを作ると言っても、OSネイティブのファイルシステムを作るのは大変です。しかしながら、最近はFUSE (Filesystem in Userspace)を使って手軽にファイルシステムを試作できるようになりました。以前だったら躊躇していたところですが、気軽に試せそうです。
FUSEはOS内部で発生したファイルシステムイベントをユーザー空間のプログラムに通知し、そこで必要な操作を代行させることでOSネイティブのファイルシステムと同様の操作性をファイルシステム利用者に提供しています。イベントの処理といっても、実際はイベントに対応したコールバック関数を記述する形になりますから、特に実装が複雑なわけではありません。FUSEでは様々なイベントに対応するコールバック関数が定義されていますが、すべての関数を実装しなければならないわけではありません。たとえば、シンボリックリンクをサポートしないのであれば、シンボリックリンクに関係する関数を実装する必要はありません。とりあえず今回対応するのは以下の関数です。試作にMacOS XのXcodeテンプレートを使うので、関数名がCocoa APIっぽく書かれていますが、簡単に読み替えることができると思います。
- ディレクトリ一覧 (contentsOfDirectoryAtPath:error:, opendir(2), readdir(2)など)
- ファイル情報取得 (attributesOfItemAtPath:userData:error:, stat(2))
- ファイル情報設定 (setAttributes:ofItemAtPath:userData:error:, chmod(2)など)
- ファイルオープン (openFileAtPath:mode:userData:error:, open(2))
- ファイルクローズ (releaseFileAtPath:userData:, close(2))
- ファイル読み込み (readFileAtPath:userData:buffer:size:offset:error:, read(2))
- ファイル書き込み (writeFileAtPath:userData:buffer:size:offset:error:, write(2))
- 新規ディレクトリ作成 (createDirectoryAtPath:attributes:error:, mkdir(2))
- 新規ファイル作成 (createFileAtPath:attributes:userData:error:, open(2))
- ファイル移動 (moveItemAtPath:toPath:error:, rename(2))
- ディレクトリ削除 (removeDirectoryAtPath:error:, rmdir(2))
- ファイル削除 (removeItemAtPath:error:, unlink(2))
FUSEで読み書き可能なファイルシステムを作る場合、上記の関数を実装すればとりあえず動きます。あとは、これらのイベントの裏で、適切に版管理システムと連携させてあげればよいわけです。版管理システムが提供するインターフェースは以下のようなものになるでしょう。
- チェックアウト (checkout)
- 更新 (update)
- 追加 (add)
- 複製 (copy)
- 移動 (move)
- 削除 (delete)
- コミット (commit)
今回、版管理システムとしてSubversionを念頭に置いています。ですが、Subversionと同様の概念で構築されているシステムであれば、上記のような抽象化された版管理インターフェースと実際の動作を対応させることで、差し替えもできるのではないかと思います。
FUSEが提供するファイル操作と、版管理システムが提供するファイル操作をじっと見比べてみると、お互いの機能が似ていることがわかります。FUSE側に存在せず、版管理側に存在する操作としてチェックアウトとコミット、逆にFUSEには存在し、版管理システムに存在しない操作としてはファイルのオープンやクローズ、ファイル情報の操作などがあります。これらの差を埋めれば二つのシステムが相互に繋がりそうです。Subversionを前提にがっつり実装してもよいのですが、将来の拡張性を考えて、版管理抽象層を定義し、以下のAPIを版管理抽象層からFUSEファイルシステム側に提供することにしました。
- 初期化 (revisionControlSetup:)
- チェックアウト (revisionControlSetup:)
- 追加 (revisionControllAdd:)
- 削除 (revisionControlRemove:)
- 複製 (revisionControlCopy:)
- 更新 (revisionControlUpdate:)
- コミット (revisionControlCommit:)
- タッチ (revisionControlTouch:)
- 終了処理 (revisionControlCleanup:)
- 実パス名取得 (revisionControlRealPathForPath:)
- 制限ファイル名取得 (revisionControlNameIsReservedAtPath:)
いくつか、版管理システムの操作一覧にないAPIを追加しています。初期化と終了処理はよいとして、タッチ、実パス名取得、制限ファイル名取得は、手元の作業コピーでの操作と版管理されているデータを結びつけるために必要となります。
今回、版管理システムを基礎としてファイルシステムを構築するので、ファイルへの操作はオリジナルのファイルではなく、手元に作られた作業コピーに対して行われます。作業結果は、最終的に版管理システムにコミットしなければならないので、どのファイルが操作されたのか履歴を記録しておく必要があります。タッチAPIは、作業コピーで修正されたファイルを版管理抽象層に通知します。
実パス名取得APIは、版管理システム内で使われているパス名を、作業コピー上でのパス名に変換するためのAPIです。今回の試作では、版管理システム内のディレクトリ構造を、手元のPCの特定ディレクトリにマウントして使うことを想定しています。FUSEから通知されるパスはマウントされたディレクトリからの総体パスになりますが、実際に操作できるファイルは作業コピーとして取り出したファイルパスになります。作業コピーを取り出した場所は版管理抽象層しか知らないので、実際のファイルパス名を知りたい場合に抽象層に問い合わせるAPIが必要になります。
制限ファイル名取得APIは、ファイルシステムとして利用できないファイル名を判断するためのAPIです。たとえば、版管理システムとしてSubversionを使う場合、.svnという名前のファイル名、ディレクトリ名は使えません。このAPIを通じて、後ろで使われている版管理システムで禁止されているファイル名を取得します。
とりあえずFUSE関数を上述の版管理抽象層APIで実装してみると、以下のようになります。
- (FUSE初期化関数)
- 初期化
- チェックアウトあるいは更新
- ディレクトリ一覧
- 更新
- ファイル情報取得
- (作業コピーのファイル情報を取得)
- ファイル情報設定
- (作業コピーのファイル情報を取得)
- ファイルオープン
- タッチ
- ファイルクローズ
- コミット
- ファイル読み込み
- (作業コピーのファイルを読み込み)
- ファイル書き込み
- (作業コピーのファイルに書き込み)
- 新規ディレクトリ作成
- (作業コピーにディレクトリ作成)
- 追加
- 新規ファイル作成
- (作業コピーにファイル作成)
- 追加
- ファイル移動
- (移動元を移動先に)複製
- (移動元を)削除
- ディレクトリ削除
- 削除
- ファイル削除
- 削除
- (FUSE終了関数)
- コミット
- 終了処理
まぁ、いろいろと問題はあるのですが、一応動くものにはなります。ソースコードをsourceforgeに公開していますので、興味のある人は覗いてみてください。sourceforgeに登録しているコードは、上記以上の機能も実装していますが、それはまた別の機会に。
次回に続きます。
登録:
投稿 (Atom)