cygwin+vagrant(virtualbox)+ansibleの動作確認メモ

virtual boxとvagrantのインストール

まず、virtual boxとvagrantのバイナリを公式サイトからDLしてインストールする。 特にハマリポイントはなし。

cygwinからvagrantを操作

vagrantの実行パスが環境変数に追加されており、cygwinのために 何も設定をすることなく普通にcygwinターミナルからvagrantコマンド実行可能。

ansibleのインストール

以下を参考に。

まず、以下をcygwinのsetup.exeを使ってインストール。

次に、setuptoolsのeasy_installコマンドを使ってpipをインストール。 単純に、easy_install pipとすると以下の様な感じでなぜかエラーになるので注意。

$ easy_install-2.7 pip
Couldn't find a setup script in /c/Users/kj".

以下の様にして直接tar ballをインターネットからDLする。

$ easy_install https://pypi.python.org/packages/source/p/pip/pip-1.4.1.tar.gz

そして、pipを使ってansibleをインストール

$ pip ansible

ansibleの動作確認

下記を参考に。

vagrantでhost01という名前のVMを起動しているとき、以下のようにすることでansibleでhost01へアクセス、操作ができる。

  • host01へのssh接続情報を.ssh/configに保存。
$ vagrant ssh-config >> ~/.ssh/config
$ sed -i 's/Host default/Host host01/' ~/.ssh/config
  • ansibleでアクセスするhostの一覧を列挙。ここではhost01のみ列挙。
$ cat << EOS > hosts
host01

EOS
  • ansibleコマンドの入力省力化。 cygwinの場合、ssh_argsとしてControlMster=noを設定しないとうまくsshできない。
$ cat << EOS > ansible.cfg
[defaults]
hostfile = hosts

[ssh_connection]
ssh_args = -o ControlMaster=no

EOS

動作確認。

$ ansible host01 -m ping
host01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
$ ansible host01 -a 'uname -a'
host01 | SUCCESS | rc=0 >>
Linux ubuntu 4.2.0-30-generic #36-Ubuntu SMP Fri Feb 26 00:58:07 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

以上。

PythonでバイナリデータをパックしてUDPメッセージを送ってみる

はじめに

PythonバイナリデータをパックしてUDPメッセージを送るには、structモジュールを使う。簡単な使い方はPy MOTW: struct – Working with Binary Dataで確認できる。本エントリでは、structモジュールの使い方を押さえ、UDP上のバイナリデータで構成されたプロトコルであるGTPv2のEcho Requestメッセージを試しに送信してみる。 GTPv2のEcho RequestメッセージのプロトコルフォーマットはドコモのネットワークにGTP接続(レイヤー2)するためのメモのエントリで参照した以下のドキュメントで確認できる。

structモジュールでバイナリデータをパック、アンパック

前準備として、structモジュールの使い方を押さえる。

structモジュールはデータのパック方法として、関数レベルとクラスレベルの2つを用意している。データをパックするときには、フォーマット文字列(例えば、データがネットワークバイトオーダで4オクテットである、とか)を指定する必要がある。Py MOTW: struct – Working with Binary Dataによると、関数レベルのパッキングを利用する場合、フォーマット文字列はパッキングの際に毎度コンパイルされるのに対し、クラスレベルのパッキングを利用する場合、オブジェクトをインスタンス化するときにフォーマット文字列をコンパイルするため、データのパッキングが高速になるとのこと。 よって、ここでは、クラスベースのパッキングをしてみる。

まず、フォーマット文字列として、データがネットワークバイトオーダで4オクテットであることを指定してオブジェクトをインスタンス化するには以下のように、ネットワークバイトオーダを示す"!"と4オクテットであることを示す"i"をコンストラクタの引数に与える。フォーマット文字列の詳細はpythonのマニュアルで確認することができる。

>>> import struct
>>> s = struct.Struct("!i")
>>> s
<Struct object at 0x7f7e09518880>

例えばバイナリデータとして、"0x04 0x03 0x02 0x01"で構成される4オクテットのデータを作り、上記のフォーマット文字列でパッキングするには以下のようにする。

>>> data = (0x04 << 24) + (0x03 << 16) + (0x02 << 8) + 0x01
>>> packed_data = s.pack(data)
>>> packed_data
b'\x04\x03\x02\x01'

上記の例は、フォーマット文字列として、ネットワークバイトオーダで1オクテットを4つ並べ、以下のようにもできる。

>>> s = struct.Struct("!BBBB")
>>> data = [0x04, 0x03, 0x02, 0x01]
>>> packed_data = s.pack(*data)
>>> packed_data
b'\x04\x03\x02\x01'

パックしたデータををUDPで送信するには、socketモジュールのsendtoの引数にパックしたデータを渡せば良い。

パックしたデータをアンパックするときもパックするときと同様に、まずフォーマット文字列を指定してオブジェクトをインスタンス化し、パックされたデータをunpackメソッドの引数に渡せば良い。

>>> s1 = struct.Struct("!BBBB")
>>> packed_data = s1.pack(*data)
>>> s1.unpack(packed_data)
(4, 3, 2, 1)

GTPv2のEcho RequestメッセージをUDPで送信

それでは、試しにGTPv2のEcho Requestメッセージをバイナリデータとして構成し、パッキングし、UDPで送信してみる。 用意したプログラムは下記の2つ。 * gtpv2c.py - GTPv2のメッセージは、ヘッダと情報要素(Information Element, IE)で構成される。本ファイルでは、これらのデータを定義する。 - 本ファイルでは、パッキングするフォーマット文字列とバイナリデータの構築のみを行う。 * send_gtpv2c.py - 本ファイルにおいて、gtpv2c.pyを読み込み、そこで定義されたEcho RequestのヘッダとIEを組み立て、パッキングし、UDPでデータ送信する。

gtpv2c.py

#!/usr/bin/env python3

PORT = 2123

ECHO_REQUEST = 1
# ...

RECOVERY_TYPE = 3
# ...

def header(msg_type, msg_len, teid=None, seq_no=None):
    version = 2
    p = 0 # piggyback off
    formatter = "!i"

    octets = []
    octets1_4 = 0
    octets1_4 += version << 29
    octets1_4 += p << 28
    if teid != None:
        octets1_4 += 1 << 27
    octets1_4 += msg_type << 16
    octets1_4 += msg_len
    octets.append(octets1_4)

    if teid != None:
        formatter += "i"
        octets.append(teid)

    if seq_no != None:
        formatter += "i"
        octets.append(seq_no << 8)

    return [ formatter, octets ]


def recovery_ie(ins_id, recovery_val):
    ie_len = 5
    formatter = 'ib'
    octets = []
    octets1_4 = 0
    octets1_4 += RECOVERY_TYPE << 24
    octets1_4 += 1 << 8
    octets1_4 += ins_id
    octets.append(octets1_4)
    octets.append(recovery_val)

    return [ ie_len, formatter, octets ]

send_gtpv2c.py

#!/usr/bin/env python3

import socket
import time
from contextlib import closing

import gtpv2c
import struct

if __name__ == '__main__':
    host = '127.0.0.1'
    port = gtpv2c.PORT
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    with closing(sock):
        ie_len, ie_f, ie_msg = gtpv2c.recovery_ie(0, 100)
        hdr_f, hdr_msg = gtpv2c.header(gtpv2c.ECHO_REQUEST, ie_len, None, 1234)

        s = struct.Struct(hdr_f + ie_f)
        msg = hdr_msg + ie_msg
        packed_data = s.pack(*msg)
        sock.sendto(packed_data, (host, port))

サンプルプログラムの実行

以下のようにコマンドを実行し、ローカルホストにgtpv2 echoメッセージを送信し、

$ chmod +x send_gtpv2c.py
$ ./send_gtpv2c.py

loデバイスをwiresharkでみてみると、うまくecho requestメッセージが送信できている:) f:id:kj_xxx:20160114014605j:plain

ドコモのネットワークにGTP接続(レイヤー2)するためのメモ

ドコモMVNOのSORACOMも使っているGTP接続について信号レベルのメモ。

参考URL

  • ドコモ 技術的条件集
    • 700ページ以上に渡る長大なドキュメントだけど、うまく整理されていて、ポイントが押さえられている感じ

はじめに

ドコモのネットワーク、具体的にはドコモのServing GW (SGW)にGTP接続するためには PDN GW (PGW)を用意する必要がある。 GTPプロトコルは、C-planeプロトコル (GTPv2-C)とU-planeプロトコル (GTPv1-U)がある。 ドコモが準拠しているプロトコル仕様は、2016.1.7現在、以下のとおり。

なお、GTPv2-Cに関するシーケンスは3GPP TS23.401v8.7.0に準拠している。

技術的条件集で使わている装置の用語と3GPPで使われている用語の対応 - 直収パケット交換機: SGW - 直収回線等接続事業者ノード: PGW

GTPv2-C

  • 技術的条件集の別表10-1-1 アクセス制御プロトコル仕様 (pp.581-624)に詳細仕様の記述がある
    • TS29.274を参照しなくても、基本的にここに書かれている情報で大体のことがわかる
  • サポートする必要がある信号
    • ノード監視処理(Echo Request/Echo Response)
    • セッション設定処理(Create Session Request/Create Session Response)
    • ベアラ更新処理(Modify Bearer Request/Modify Bearer Response)
    • セッション削除処理(Delete Session Request/Delete Session Response)
    • ベアラ切断処理(Delete Bearer Request/Delete Bearer Response)

複数のPGWノードと接続させたい場合

技術的条件集によると

ユーザが接続先として指定するAPN1アドレスに対し最大8台(※1)の直収回線 等接続事業者ノードに分散させることが可能です。 ... ※1 直収回線等接続事業者1ノードにつき1つのGTPv2-C用ノードIPアドレスを 付与することを前提とします。(複数のノードを論理的に1つのノードとして GTPv2-C用ノードアドレスを1つ付与する場合は、直収パケット交換機で分散し ません。)

つまり、APN 1アドレスにつき、8つのPGW (C-plane) IPアドレスをドコモネットワーク側で 登録してもらえる(のだと思う)。

GTPv1-U

  • 技術的条件集の別表10-1-2 ユーザデータ転送プロトコル仕様 (pp.625-640)に詳細仕様の記述がある
    • TS29.281を参照しなくても、基本的にここに書かれている情報で大体のことがわかる
  • サポートする必要がある信号
    • ユーザデータ転送処理(G-PDU)
    • エラーデータ処理(Error Indication)
    • ノード監視処理(Echo Request/Echo Response)

シーケンス

  • 技術的条件集別表10-1-3 シーケンス (pp.662-676)に正常系・準正常系のシーケンス図が描かれている
  • GTPv2-C関連 (カギカッコ内はTS23.401のInformation flow名に対応)
    • 接続処理 [Attach]
    • 接続終了処理(移動無線装置起動)[Detach]
    • 接続終了処理(直収回線等接続事業者網起動)[PDN GW initiated bearer deactivation]
    • 直収パケット交換機変更 [Tracking/Routing Area Update, Service Request, Handover]
    • 監視制御(GTPv2-U) [対応なし]
    • 再開 (対応なし) [対応なし]
  • GTPv1-U関連
    • ユーザデータ転送 [対応なし]
    • 監視制御(GTPv1-U) [対応なし]

openstack+lxdのインストールメモ

参考URL

前提条件

ubuntu 15.10 server editionを使用。

ubuntu server上でintel vtが有効になっているか確認

※lxcを使うなら不要かも

stack@devstack00:~$ cat /proc/cpuinfo |grep vmx
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc aperfmperf eagerfpu pni pclmulqdq vmx ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt aes xsave avx f16c rdrand hypervisor lahf_lm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi ept vpid fsgsbase smep

ubuntu serverの設定(IPアドレスの固定化)

/etc/network/interfaceを以下のように編集

※以下でethXとしている部分は、enoxxxに読み替える

auto eth0
iface eth0 inet static
address 192.168.1.20
netmask 255.255.255.0
gateway 192.168.1.2
dns-nameservers 192.168.1.2

auto eth1
iface eth1 inet static
address 0.0.0.0

ネットワークの再起動

sudo ifdown eth0 && sudo ifup eth0
sudo ifdown eth1 && sudo ifup eth1

githubからdevstackのDL

$ cd ~
$ git clone https://github.com/openstack-dev/devstack.git -b stable/liberty

local.confの編集

$ cat << _EOT_ > ~/devstack/local.conf
[[local|localrc]]
SERVICE_TOKEN=azertytoken
ADMIN_PASSWORD=nomoresecrete
MYSQL_PASSWORD=stackdb
RABBIT_PASSWORD=stackqueue
SERVICE_PASSWORD=$ADMIN_PASSWORD
HOST_IP=192.168.1.20
FIXED_RANGE=10.0.0.0/24
FIXED_NETWORK_SIZE=256
FLAT_INTERFACE=eth1
ENABLED_SERVICES=rabbit,mysql,key
ENABLED_SERVICES+=,n-api,n-crt,n-obj,n-cpu,n-cond,n-sch,n-novnc,n-cauth
ENABLED_SERVICES+=,neutron,q-svc,q-agt,q-dhcp,q-l3,q-meta
ENABLED_SERVICES+=,g-api,g-reg
ENABLED_SERVICES+=,horizon
Q_PLUGIN=ml2
Q_AGENT=openvswitch
Q_USE_DEBUG_COMMAND=True
Q_L3_ENABLED=True
Q_L3_ROUTER_PER_TENANT=True
ENABLE_TENANT_TUNNELS=True
LOGFILE=$DEST/logs/stack.sh.log
LOGDAYS=2
enable_plugin nova-lxd https://github.com/lxc/nova-compute-lxd
FORCE=yes
GIT_BASE=https://git.openstack.org
_EOT_

lxc用のイメージ登録

wget -O vivid-server-cloudimg-amd64-root.tar.gz https://cloud-images.ubuntu.com/vivid/current/vivid-server-cloudimg-amd64-root.tar.gz
glance image-create --name='lxc' --container-format=bare --disk-format=raw < vivid-server-cloudimg-amd64-root.tar.gz

※このイメージには/etc/network/interfaces.d配下に、eth0.cfgしかない。 複数NICdhcp使うなら、eth[1-N].cfgの設定ファイルも入れておく必要あり。

トラブルシューティング

コンテナが起動できない

No valid host was found. There are not enough hosts available を回避する方法。 n-condをみると、config-driveを使おうとしている模様。 nova.confでconfig-driveが強制的に使用するようになっているので、 それをやめる。

vi /etc/nova/nova.conf
...
force_config_drive = False
...

screenに入って、n-condのプロセスを再起動

ダッシュボードからconsoleアクセス出来ない

TODO: novncの設定を見直す。未対処。 ただし、ubuntu cloudイメージはconsoleアクセスを許容していなかったような。 コンソールアクセスしたかったらイメージ側も対処する必要があるかもしれない。

openstack-lxdのコンテナをlxc-lsで確認

lxc-ls -P /var/lib/lxd/containers/ --fancy

openstack-lxdのコンテナの内部に入る

sudo lxc-attach -P /var/lib/lxd/containers -n instance-00000007

参考: - http://stackoverflow.com/questions/17903705/is-it-possible-to-start-a-shell-session-in-a-running-container-without-ssh

Nexus 7 (2012)をAndroid 5(公式)からAndroid 6 (カスタムROM)にするメモ

Nexus 7 (2012)をAndroid 5 Lollipopに更新してから、動作のモッサリ感が半端無く、 使用に耐えられなかったため、カスタムROM (pure nexus project)を使ってNexus 7Android 6 Marshmallowにしてみたら、動作が非常に軽くなった!

今のところYoutubeくらいしか使っていないので、動作の安定性のほどはよく わかっていない使っているとアプリが落ちたり、急にリブートしたりというような ことにはなっていない。

以下はnexus 7 (2012)をandroid 5(公式)からandroid 6 (カスタムROM)にするメモ。

参考URL

現在のnexus 7 (2012)のタブレット情報

  • Androidバージョン: 5.1.1
  • カーネルバージョン: 3.1.10-gf5d7b8b
  • ビルド番号: LMY47V
  • 未root化

事前準備

nexus 7から必要なデータをPCにバックアップしておく。

PC上でADBコマンドを使えるようにする

以下のページを参考に、PC (windows 10)にJDKAndroid SDKをインストールする。 - 【ADB】Java(JDK)とAndroid SDKを導入してADBコマンドを使えるようにする - ADB,Bootloaderのドライバについては、自分でインストールせずとも自動的に 入る?ようだったので特にインストール作業をしていない

Bootloader(ブートローダ)のUnlock(アンロック)

以下のページを参考に、bootloaderをアンロックする。 - Bootloader(ブートローダー)の起動手順 - Bootloader(ブートローダー)のUnlock(アンロック) - NOTE: 参考ページでは、「※Android 5.0以上の端末では、あらかじめOS起動状態で 「開発者向けオプション」の「OEMロック解除」にチェックを入れておいて下さい。」と 書かれていたが、自分のNexus 7には「OEMロック解除」の項目が見当たらなかったので、 この手順はスキップ。

具体的には、 - Nexus 7をUSBでPCにつなぎ、PCのコマンドプロンプトから、下記のコマンドを実行 することでNexus 7ブートローダを起動する。

adb reboot bootloader
fastboot oem unlock
  • この時点で全てのデータが消される。
  • アンロックが完了して、Nexus 7が再起動すると5~10分程度たったあと、 "Welcome"のページが出る。
    • 日本語を選択し、インストールを続行して、完了させるが、このインストールは 一時的なもので、再度カスタムROMをインストールするときにデータを消去するため 諸々の手続きはスキップしてよい

カスタムリカバリ(TWRP: Team Win Recovery Project)のインストール

下記のページを参考に、TWRPをNexus 7にインストールする。 - 【TWRP】Team Win Recovery Project(チームウィンリカバリプロジェクト:TWRP)の起動と操作・使用

具体的には、 - PCを使い、最新版のtwrp 2.8.7.0をDLする。 - TWRPをダウンロードしたフォルダでコマンドプロンプトを起動し、下記のコマンドを 実行することでTWRPを起動する。

fastboot boot twrp-2.8.7.0-grouper.img
  • TWRP起動後、Backupのボタンをタップし、バックアップ
    • デフォルトの選択状態(System, Data, Boot)でSwipe to Back Up
      • データは/DATA/MEDIA/0/twrp/BACKUS/...配下に保存される
      • 124秒でバックアップ完了→Reboot Systemをタップ。
      • SuperSUをインストールされるか聞かれるので"Swipe to install"
        • ※custom ROMを後でインストールするので、このタイミングでsuperSUのインストールは不要だったかも。
    • 再起動後、念のため、PCにバックアップファイルをコピーする

SuperSUのインストール

TWRPでインストール時に部分的にSuperSUのインストールができている。 Nexus 7起動後、アプリのドロワー画面を開くと、SuperSu Installerがあるので タップ→Playを選択し、インストールを完了させる。 - あとから見返すと、このタイミングでsuperSUのインストールは不要だったかも。

カスタムROMのインストールに必要なデータをPCにDLし、Nexus 7にコピー

PCで[UNOFFICIAL][ROM][GROUPER][6.0.1_r3]★ The Pure Nexus Project ★ Layers ★ [12/21/15]Rom Builds からpure_nexus_grouper-6.0.1-20151221.zip をDL。

同様に [UNOFFICIAL][ROM][GROUPER][6.0.1_r3]★ The Pure Nexus Project ★ Layers ★ [12/21/15]Recommended Gapps: Open Gapps (Nano or Pico) からPlaform: ARM, Android: 6.0, Variant: nano をDL。

DLしたファイルをNexsus 7のDownloadsフォルダにコピー。PCからNexus 7のフォルダが見えなかったので、 下記のページを参考にNexus 7の設定で開発者向けオプションを表示させてUSBデバッグをオンにして実施。 - Android 5.0 LollipopのNexus9の開発者向けオプションを表示させてUSBデバッグをオンにする方法。

TWRPでAndroidシステムをwipeし、DLしたAndoid6とGappsをインストール

以下を参考にwipe, インストール。インストール完了後、システムを再起動。 - Android端末(Nexus)のroot化・カスタムROMの導入と更新 - インストールするときには、android6とgappsのzipファイル両方を選択する。 - 【TWRP】Team Win Recovery Project(TWRP)でのカスタムROMの書き込み(ROM焼き)

具体的には、 - PC上で、TWRPをダウンロードしたフォルダでコマンドプロンプトを起動し、下記のコマンドを 実行することでTWRPを起動する。

fastboot boot twrp-2.8.7.0-grouper.img
  • TWRP起動後、Wipeのボタンをタップし、更にAdvanced Wipeをタップする
    • Internal Storage以外の項目にチェックを入れ、Swipe to Wipe
    • Wipeが完了したらBackボタンをタップ
  • Installボタンをタップし、DownloaddsフォルダにコピーしておいたAndroid 6 (pure_nexus_grouper-6.0.1-20151221.zip)を選択
  • Add More Zipsボタンをタップし、DownloaddsフォルダにコピーしておいたGapp (open_gapps-arm-6.0-nano-20151225.zip)を選択
  • Swipe to Confirm FlashAndroid 6とGappをNexus 7に書き込む
  • 書き込みが完了したら、Reboot Systemボタンをタップし、Nexus 7を再起動。

上記の手順を踏むことで、Nexus 7にカスタムROMのAnroid 6が起動する。