池の上にも

平均以下の理解力で、色々アウトプットしてみるブログ

Namespace では OvS が動かないらしい

Mininet 上で検証 NW を作ろうとしていて、各スイッチの Namespace を分けつつ、更に OvS を個々の Namespace 上で動作させたいと思っていたのですが、どうやら動作しないようです。

$ sudo mn --switch=ovs --innamespace
:
--------------------------------------------------------------------------------
Caught exception. Cleaning up...

Exception: OVS kernel switch does not work in a namespace
--------------------------------------------------------------------------------
:


ソースコード上でも、Mininet の OvSSwitch クラスを走らせる際に、Namespace のフラグが立っていたら Exception 飛ばすようになっていました。

https://github.com/mininet/mininet/blob/f65e1ab9361632f8ba83b296e27f1fecc257d4f9/mininet/node.py#L1167-L1169

それっぽい PDF が転がっていて、Kernel API が提供されていないため Namespace 上での OvS 利用には制限事項(新規追加した Namespace を OvS で検知する手段がないとか)が多いみたいです。

http://openvswitch.org/support/ovscon2015/17/1555-benc.pdf

Mininet 上の Namespace で OpenFlow に対応したスイッチを利用する場合は、UserSwitch を使用するしかなさそうです。Indigo Virtual Switch は、インストールに手間かかりそうだったので、使えるか試せていません。

quagga + mininet で BGP 検証環境を作る その②

前回のあらすじ

tawaku.hatenablog.com

1ヶ月前に quagga + mininet で作る BGP 検証環境の構成方法をまとめてみたのですが、色々触っていくうちに分かった事があるので記録を取っておきます。
実は前回のエントリで間違っていた箇所があり、修正したところを自戒も込めて経緯を残しておこうかと思いました。

修正したところ

前回のエントリで修正した箇所で、最も良くなかったのが以下の箇所です。

加えて、zebra/bgpd が使う Zserv API のソケットのパス(-z オプションで指定)を追加しておきます。

quagga + mininet で BGP 検証環境を作る その① - 池の上にも


quagga では、bgpd が受け取ったルート情報を zebra に渡して、zebra がルーティングテーブルに反映するという動作をします。その際に、bgpd は zebra が提供する Zserv API を使ってルート情報を伝えるらしいです。
前回は上述の仕組みが分かっていなかったのもあり、bgpd で show ip bgp 叩いたら、ルートの交換ができていたので、うまく行ったと思い、確認を終えました。後日 zebra で show ip route 叩いたらルートが載って来ておらず、間違いが発覚しました。ちゃんと確認しろという話です。

Zserv API がおかしい

zebra のログを見たら、ちゃんとエラーが出てました。zerv.api が作られていないようです。

$ sudo cat /tmp/R1.log 
2017/10/28 19:31:07 ZEBRA: Can't bind to unix socket /var/run/zserv.api: Permission denied
2017/10/28 19:31:07 ZEBRA: zebra can't provide full functionality due to above error


bgpd 側でも zserv.api にアクセスできていないことが分かるエラーが、strace で確認できました(26967 は bgpd の PID です)。

$ sudo strace -f -p 26967
connect(14, {sa_family=AF_LOCAL, sun_path="/var/run/zserv.api"}, 20) = -1 ENOENT (No such file or directory)


/var/run/ に quagga グループからの書き込み許可を追加する方法もあるかと思ったのですが、複数の quagga を動かしているのでファイル名がかぶってしまうとおかしな事になります。なので、zserv.api のパスを指定する方法を探しました。

zebra/bgpd のオプション -z

取り敢えず、起動時のオプションを確認してみます。

$ zebra --help
 :
-z, --socket       Set path of zebra socket
 :


-z オプションが怪しいのですが、この説明だと分かりません。公式ドキュメントもざっと検索したのですが、説明が見つからず。仕方ないので、以下のソースコード読んでみました。

quagga.git - quagga

./zebra/main.c に -z オプションに対応するコードがありました。

        case 'z':
          zserv_path = optarg;
          break;


zserv_path を追っかけて行くと、./zebra/zserv.cpath 変数に -z オプションに指定した値が入るようです。path が指定されていないと ZEBRA_SERV_PATH の値が使われるみたいです。

  zebra_serv_un (path ? path : ZEBRA_SERV_PATH);


ZEBRA_SERV_PATH を検索してみると、configure.ac に以下の記述がありました。

$ grep "ZEBRA_SERV_PATH" ./configure.ac 
AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$quagga_statedir/zserv.api",zebra api socket)


ZEBRA_SERV_PATHzserv.api のパスが指定されています。-z オプションにパスを指定すれば、$quagga_statedir/zserv.api に変わるパスを設定できるみたいです。

おわりに

show ip route くらい確認しろという話でした。
quagga を触るのが初めてだったので、bgpd で show ip route が叩けなかった時点でこんなものかなと思い、調べるのをやめたのが良くなかったです。

今更 Go を触ってみた

Docker のランダムな文字列を作るやつが、ふと気になったのでインストールしてみることにしました。Go 言語で書かれているらしいです。

moby/names-generator.go at master · moby/moby · GitHub

Go インストール

Downloads - The Go Programming Language

上の URL から環境にあったバイナリをダウンロードします。

$ wget https://storage.googleapis.com/golang/go1.9.1.linux-amd64.tar.gz
$ sha256sum go1.9.1.linux-amd64.tar.gz


展開してインストール。

$ ls /usr/local/go
ls: cannot access '/usr/local/go': No such file or directory

$ sudo tar -C /usr/local -xzf go1.9.1.linux-amd64.tar.gz


PATH を追加します。

$ sudo vim /etc/profile.d/go.sh
#!/bin/bash
export PATH=$PATH:/usr/local/go/bin

$ source /etc/profile


Go がインストールできました。

$ go version
go version go1.9.1 linux/amd64

names-generator の導入

ソースコードをダウンロードします。

$ wget https://raw.githubusercontent.com/moby/moby/master/pkg/namesgenerator/names-generator.go


内容を少し書き換えます。

$ vim names-generator.go

1. package を namesgenerator から main に変更
< package main
---
> package namesgenerator

2. import に "time" を追加
<    "time"

3. main 関数を追加
< func main() {
<    rand.Seed(time.Now().UnixNano())
<    fmt.Println(GetRandomName(0))
< }


ビルドします。

$ go build names-generator.go


動かしてみます。問題なく動いたら、バイナリを移動していつでも使えるようにしておきます。

$ ./names-generator 
optimistic_liskov
$ sudo mv names-generator /usr/local/bin/

おわりに

names-generator.go のソースコードに以下の記載があります。
退屈なウォズニアックは存在しないので、やり直しだそうです。

  if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
    goto begin
  }

quagga + mininet で BGP 検証環境を作る その①

BGP を検証できる環境がほしかったので探したところ、quagga + mininet を使った環境が見つかったので、そちらを利用させてもらうことにしました。

BGP Path Hijacking Attack Demo · mininet/mininet Wiki · GitHub

mininet が namespace を使うことで routing table が個別に扱えるようになります。その上で quagga を動作させて、BGP peer をはれる NW 環境が構成できるとのことです。

環境

  • OS: Ubuntu 16.04.3 LTS
  • Memory: 4GB
  • Quagga: version 1.2.1

Installation

1. Git インストール
$ sudo apt install git
2. Mininet インストール
$ git clone git://github.com/mininet/mininet
$ cd mininet
$ git tag
$ git checkout -b 2.2.1 2.2.1
$ cd ..
$ mininet/util/install.sh -nfv

-nfv オプションで mininet とあわせて Open vSwitch もインストールします

3. Quagga インストール
$ sudo apt install libreadline-dev libc-ares-dev
$ wget http://download.savannah.gnu.org/releases/quagga/quagga-1.2.1.tar.gz
$ tar xvzf quagga-1.2.1.tar.gz
$ cd quagga-1.2.1
$ ./configure --enable-multipath=0
$ make
$ sudo make install

ECMP も動作確認したかったので、--enable-multipathのオプションもつけました。引数が0だと、ECMP の数を上限なしに設定できます。
quagga ユーザを作っておいて、ldconfiglibzebra.so.1を読み込んでおきます。

$ sudo adduser --system --no-create-home --group quagga
$ sudo ldconfig
$ ldconfig -p | grep -i zebra
4. BGP サンプル環境をインストール
$ git clone https://bitbucket.org/jvimal/bgp.git
$ sudo bash -c "curl -kL https://bootstrap.pypa.io/get-pip.py | python"
$ sudo pip install termcolor

これで、bgp/bgp.py を起動すれば、quagga が各 Switch で動作した mininet が起動するのですが、zebra/bgpd のパスが違っていたりするので修正しておきます。
(追記) 加えて、zebra/bgpd が使う Zserv API のソケットのパス(-z オプションで指定)を追加しておきます。

--- a/bgp.py
+++ b/bgp.py
@@ -140,9 +140,9 @@
-        router.cmd("/usr/lib/quagga/zebra -f conf/zebra-%s.conf -d -i /tmp/zebra-%s.pid  > logs/%s-zebra-stdout 2>&1" % (router.name, router.name, router.name))
+        router.cmd("/usr/local/sbin/zebra -f conf/zebra-%s.conf -d -i /tmp/zebra-%s.pid -z /tmp/zebra-%s.sock > logs/%s-zebra-stdout 2>&1" % (router.name, router.name, router.name, router.name))
         router.waitOutput()
-        router.cmd("/usr/lib/quagga/bgpd -f conf/bgpd-%s.conf -d -i /tmp/bgp-%s.pid > logs/%s-bgpd-stdout 2>&1" % (router.name, router.name, router.name), shell=True)
+        router.cmd("/usr/local/sbin/bgpd -f conf/bgpd-%s.conf -d -i /tmp/bgp-%s.pid -z /tmp/zebra-%s.sock > logs/%s-bgpd-stdout 2>&1" % (router.name, router.name, router.name, router.name), shell=True)
         router.waitOutput()


修正後に quagga + mininet を起動します。

$ cd bgp
$ sudo ./bgp.py

BGP ルータに接続

./connect.sh <Router名> で接続します。ですが、ps コマンドからノード名を取得するための正規表現が合っていなかったので、スクリプトを少し書き換えます。

--- a/run.py
+++ b/run.py
@@ -16,7 +16,7 @@
-node_pat = re.compile(r'.*bash ... mininet:(.*)')
+node_pat = re.compile(r'.*bash --norc -is mininet:(.*)')

その後に、./connect.sh <Router名> で接続します。telnet login/enable の password は、いずれも en です。

$ ./connect.sh R2
Connecting to R2 shell
Trying ::1...

Connected to localhost.
Escape character is '^]'.

Hello, this is Quagga (version 1.2.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.


User Access Verification

Password: 
bgpd-R2> en
Password: 
bgpd-R2# 


(追記) zebra に接続する際は、connect.sh の telnet localhost bgpdtelnet localhost zebra に書き換えて接続します。また、quagga から設定変更やログの書き込みができるように、設定/ログ用のディレクトリとファイルのパーミッションを変更しておく必要があります。

$ chown :quagga conf
$ chown :quagga conf/*
$ chown :quagga logs

トポロジを変更する

デフォルトのトポロジは、とてもシンプル(R1---R2---R3)なので、topology.py の中身を変更してトポロジを好きなように変更します。トポロジを変更してノード名を変えた場合は、conf/配下にノードに対応する設定ファイルを作る必要があります。特に zebra に対応する設定では loopback の設定を残しておかないと connect.sh で接続ができなくなるので注意が必要です。

Spotify + Mopidy でカラオケしてみた

以前に手元の Lubuntu で Spotify を再生できるように、Mopidy をインストールしてみました。

tawaku.hatenablog.com

設定いじって色々できないか探してみたところ、GStreamer というマルチメディアのフレームワークの設定を変えて、簡単なカラオケができそうです。

GStreamer pipeline

Mopidy では、GStreamer を使って音を再生しています。
Mopidy のチュートリアルにもあるのですが、まずは GStreamer で音が再生できるか確認してみます。Mopidy で音楽が聞けている場合は、音がなるはずです。

$ gst-launch-1.0 audiotestsrc ! audioresample ! autoaudiosink


Mopidy のデフォルトでは、音の再生にautoaudiosinkが使われています。それで音をいじれないか探してみたところ、audiokaraokeというものを見つけました。


audiokaraoke: GStreamer Good Plugins 1.0 Plugins Reference Manual

センタチャネルをフィルタして、音楽から音声を取り除けるそうです。センタチャネルがなにか分かってないですが、効果は楽しそうです。

まずは、サンプルでaudiokaraokeが再生可能か確認してみます。

$ gst-inspect-1.0 | grep -i "karaoke"
audiofx:  audiokaraoke: AudioKaraoke

$ gst-launch-1.0 audiotestsrc ! audioresample ! audiokaraoke ! autoaudiosink


再生できたら、Mopidy に設定してみます。

Mopidy に audiokaraoke を設定する

[audio] セクションのoutputに、GStreamer のパイプラインを設定できます。

$ vim /usr/share/mopidy/conf.d/mopidy.conf

[audio]
output = audiokaraoke ! autoaudiosink


Mopidy を再起動して、音楽を再生してみます。サンプルが載せられないですが、ボーカルがコーラスみたいになってカラオケっぽくなっています。

課題

以下の2点が不満で、暇があれば改善したいです。

  • カラオケなので歌詞が欲しかったですが、適当な Extension が見つからなかった
  • カラオケを止める時は一々設定を書き換えて、Mopidy を再起動しないといけない

Mopidy で Spotify を聴いてみた

Lubuntu で音楽聴きたいので、探してみたらこんなのありました。

github.com

インストール環境

Mopidy とは

Python ベースの Music Server とのことで、ローカルの音楽ファイルを再生できるし、Extension を使うことで Spotify とかクラウド上の音楽サービスを再生できるとのこと。

Mopidy に加えて、Mopidy Spotify という Extension を入れて Spotify を聴けるようにします。

github.com

なお、Mopidy SpotifySpotify プレミアムアカウントでないと正しく動かないみたいです。

Mopidy インストール

まずはリポジトリを登録します。

$ wget -q -O - https://apt.mopidy.com/mopidy.gpg | sudo apt-key add -
$ sudo wget -q -O /etc/apt/sources.list.d/mopidy.list https://apt.mopidy.com/jessie.list

$ sudo apt update


次にパッケージをインストールします。

$ sudo apt install mopidy
$ sudo apt install mopidy-spotify


最後に関連するライブラリをインストールしておきます。

$ sudo pip install spotipy

Mopidy の設定

Client ID と Client Secret を手に入れる

Mopidy から Spotify にアクセスするため、Spotify から Client ID と Client Secret を発行してもらう必要があります。

developer.spotify.com

上のページにログインしたら、"My Apps"に進みます。

f:id:tawaku:20170907232413p:plain


“My Applications"を選択して、 Mopidy を登録します。

f:id:tawaku:20170907235023p:plain


アプリケーション名は適当に入れて、"CREATE"をクリックします。

f:id:tawaku:20170907232947p:plain


Client ID と Client Secret が表示される画面に移動するので、文字列を控えておきます。

f:id:tawaku:20170907235050p:plain


mopidy.conf の編集

mopidy.conf の [spotify] のセクションを設定します。

$ cp ~/.config/mopidy/mopidy.conf /usr/share/mopidy/conf.d/mopidy.conf
$ vim /usr/share/mopidy/conf.d/mopidy.conf

[spotify]
enabled = true
username = <username>
password = <password>
client_id = <client_id>
client_secret = <client_secret>

Mopidy 起動

PC 立ち上げ時に mopidy が起動するように設定しておき、サービスを開始します。

$ sudo systemctl enable mopidy
$ sudo systemctl start mopidy


これで、TCP port 6600 と 6680 で接続待ち受けが始まります。6600 は MPD Client 用の接続で、6680 は Web Client 用の接続です。

Mopidy-Iris でアクセス

ブラウザからアクセスしたかったので、Web Client をインストールします。 Web Client はいくつかあるようです( Web extensions — Mopidy 2.1.0-10-gd4d7680 documentation )。見た目が気に入った Mopidy-Iris をインストールしてみました。

$ sudo pip install Mopidy-Iris
$ sudo systemctl restart mopidy


その後、ブラウザからhttp://127.0.0.1:6680/にアクセスします。"Web Clients"にirisが表示されているので、クリックします。

Mopidy-Iris の画面が表示されます。音楽再生前にいくつか設定を入れておきます。サイドのナビゲーションから、"Settings"を選択します。

f:id:tawaku:20170910000111p:plain


Localization 設定に以下を設定します。

f:id:tawaku:20170910000120p:plain


“Log in"を押して、Mopidy-Iris でのログインを実行します。

f:id:tawaku:20170910000126p:plain


これで音楽の再生ができるようになりました。

f:id:tawaku:20170910000131p:plain

おわりに

Spotify 聞くだけであれば手元のスマホだけで済む気もしますが、Extension で拡張していければスマホとの違いも出せそうです。暇なときに他の Extension も調べてみようかと思います。

python スクリプトの行頭に書く "#!"

pyenv の環境でスクリプトの行頭の#!に何を書けばよいかと言う話。
#!/usr/bin/env pythonが適当みたい。

$ pyenv version
2.7.13 (set by /home/***/.pyenv/version)
$ /usr/bin/env python -V
Python 2.7.13

$ cd test
test$ pyenv version
3.6.2 (set by /home/***/test/.python-version)
test$ /usr/bin/env python -V
Python 3.6.2


#!/usr/bin/pythonだとダメそう。

test$ pyenv version
3.6.2 (set by /home/***/test/.python-version)
test$ /usr/bin/python -V
Python 2.7.12