pusuke0418’s diary

異常にマルチタスクな社内SEのブログ

Linux Network Namespaceで使う/etc以下のファイル

Linux Network Namespaceは、基本的に「ネットワーク」の名前空間。仮想的な。最初は簡単に何でもかんでも独立させられるのかと思って勘違いしていたけど。

ip netns execコマンドでネームスペース上で何かコマンドを実行できる。manコマンドでip netnsを見てみると、"applications that are aware of network namespaces, the convention is to look for global network configuration files first in /etc/netns/NAME/ then in /etc/."とまず記載がある。

ネットワークに関わるものは、どのコマンド or applicationまでなのかは正確にわからなくて調べているけれども、/etc/netns/[name]/以下に設定ファイルを置けば優先して読み込むようだ。ちょっと少しhostsファイルをいじってためしてみる。環境はUbuntu14.04にて、カーネルは3.13.0-45。

まず、ネームスペースの準備。alphaとbetaというものを作る。

$ sudo ip netns add alpha
$ sudo ip netns add beta

作っただけではネットワークインタフェースはダウンしているので、上げておく。因みに作った段階ではループバックしか存在しませんものね。今回は気にしない。

$ sudo ip netns exec alpha ip link set lo up
$ sudo ip netns exec beta ip link set lo up

そして、それぞれのネームスペースが使うetc以下を作成。その下に/etc/hostsをコピーしておく。

$ sudo mkdir -p /etc/netns/alpha
$ sudo mkdir /etc/netns/beta
$ sudo cp /etc/hosts /etc/netns/alpha/
$ sudo cp /etc/hosts /etc/netns/beta/

下記のような形でそれぞれのhostsファイルを編集。それぞれのネームスペースでは自分の名前のみループバックに投げるようにすることが目的。

[/etc/netns/alpha/hosts]
127.0.0.1       localhost
127.0.1.1       alpha

[/etc/netns/beta/hosts]
127.0.0.1       localhost
127.0.1.1       beta

この状態で各々ping打ってみる。ネームスペースalphaではalphaは解決できるが、betaは解決できないことが、ネームスペースbetaではbetaは解決できるが~、と各々のhostsを読んでいることがわかる。

[alpha]
$ sudo ip netns exec alpha ping alpha
PING alpha (127.0.1.1) 56(84) bytes of data.
64 bytes from alpha (127.0.1.1): icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from alpha (127.0.1.1): icmp_seq=2 ttl=64 time=0.037 ms
64 bytes from alpha (127.0.1.1): icmp_seq=3 ttl=64 time=0.035 ms
64 bytes from alpha (127.0.1.1): icmp_seq=4 ttl=64 time=0.039 ms
^C
 --- alpha ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2997ms
rtt min/avg/max/mdev = 0.035/0.038/0.041/0.002 ms
$
$ sudo ip netns exec alpha ping beta
ping: unknown host beta

[beta]
$ sudo ip netns exec beta ping beta
PING beta (127.0.1.1) 56(84) bytes of data.
64 bytes from beta (127.0.1.1): icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from beta (127.0.1.1): icmp_seq=2 ttl=64 time=0.036 ms
64 bytes from beta (127.0.1.1): icmp_seq=3 ttl=64 time=0.037 ms
64 bytes from beta (127.0.1.1): icmp_seq=4 ttl=64 time=0.040 ms
^C
 --- beta ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2997ms
rtt min/avg/max/mdev = 0.036/0.043/0.060/0.010 ms
$ 
$ sudo ip netns exec beta ping alpha
ping: unknown host alpha

Open FlowのReserved Portと設計のなぞ

Open Flowは、コントローラへの通信は、その空っぽのスイッチはどうやってやるんだろうとふと疑問に思った。実は実装を知っているような機器もあるのだけれども、なんとなく単純にOpen FlowのSpecificationをかいつまんで読んでみた。

たとえばv1.3.4を読むと、p.13 にReserved Portなるものがあった。1.3.4を読んでみたのは、実装されているもので新しいものは1.3.xが多いのかなという思い込みと、その系で新しそうだったから。

引用すると

"They specify generic forwarding actions such as sending to the controller, flooding, or forwarding using non-OpenFlow methods, such as “normal” switch processing.A switch is not required to support all reserved"

いわゆる普通のスイッチングのようにOpen Flowではない方法を使うものっぽい。その中に、CONTROLLERという種類のものがある。

"Represents the control channel with the OpenFlow controllers. Can be used as an ingress port or as an output port. When used as an output port, encapsulate the packet in a packet-in message and send it using the OpenFlow switch protocol (see 7.4.1). When used as an ingress port, this identifies a packet originating from the controller."

私にはポエムのようにしか見えないのだけれども、コントローラとの通信に使われるようだ。ingressまたはoutputのポートとして使われるとか、ingressとして使われる場合は、というような部分がよくわからないんだけれども(別にポートが2つ要るとかじゃないよね)。

さしあたって、「ふつうの通信」するポートでコントローラと通信しているのかな。それなら、フロー情報無くてもコントローラと通信できるということは理解できる。

ただし、その場合、Open Flowで形成されるネットワークとは別に、コントローラ接続用のネットワークの系が必要になることになるということか。線新しく引いたりする必要が出てきたりするのかな。その場合、そこも冗長取りたくなるわけで、そうしたら、その部分ではメーカーの実装に依ったりして、冗長プロトコルを動かせるのだろうか。華々しい?Open Flowの実際の全体の設計イメージとして、特に使うこともなさそうな寂しい私ですが、なんとなくもやもやしてます。

 

Arubaの無線コントローラのconfigファイルを見やすく。。

Aruba Networks社の無線コントローラのconfigファイルは見辛い。なぜ見辛いかというと、設定は多段の階層構造になっているけどconfig中の記載順序はその階層構造とは逆で(configファイルをコントローラが読み込む順なのだろうか)、さらにデフォルトのconfigも大量に入っているから。テキストエディタの検索とかでも辛い。

直接コントローラにアクセスできれば、実はWeb管理画面にアクセスするのが、configファイルに映らないデフォルト設定値も確認できるし、ap-groupあたりからたどれば階層的に確認していけるから便利だと思う。

でも、それができない場合も多く、それがベストでない場合もあって、結局テキストのconfigを読まなければいけないときが多く、イライラを減らすためにCode Academyで学びたてのpythonスクリプト書いてみました。

目的は、見たいところが確認できること。使い方は、

  • 下記のpythonスクリプトとconfigファイルを同じ場所において、対話的にできるようにスクリプト実行する
  • そして、confsplit("<configファイル名>")とすると、configが"!"でばらばらにされて、aaaの設定、とかスクリプト中指定してあるパーツごとにわけられる(ディクショナリに入れてる)

ここまで準備。そして、

  • そこから、list(aaa)とかlist(role)と打つと、aaa profileやuser-roleのconfigにあるプロファイル名が出る
  • profs()を使って、profs(aaa)とか、profs(role)とか打つと、aaa profileやuser-roleの設定してあるconfigがだらだらと出る
  • prof_part()を使って、prof_part(aaa, "<プロファイル名>")とすると、aaaのプロファイル名で指定したものだけが確認できる。

今回利用できるのは、Aruba上のap-group, virtual-ap, ssid-profile, aaa-profile, user-role, ip access-list session, server-group, authentication-serverで、スクリプト上で指定するときはそれぞれapgroup, vap, ssid, aaa, role, acl, servergroup, authserverとしています(紛らわしいけど)

やりたかったことは、profs(apgroup)からじゅんぐりに使われている設定を見ていく感じ

import os, re

apgroup = {}
ssid = {}
vap = {}
aaa = {}
role = {}
acl = {}
servergroup = {}
authserver = {}

def confsplit(config):
    f = open(config, "r")
    spltd = (f.read()).split("!\n")
    f.close()

    for j in spltd:
        j = j.replace("\"", "")
        if "ip access-list session" in j:
            matched = re.search(r"session\s(.*)\n", j)
            acl[matched.group(1)] = j
            
        elif "user-role" in j:
            matched = re.search(r"user-role\s(.*)\n", j)
            role[matched.group(1)] = j
            
        elif "aaa profile" in j:
            matched = re.search(r"aaa\sprofile\s(.*)\n", j)
            aaa[matched.group(1)] = j
            
        elif "wlan ssid-profile" in j:
            matched = re.search(r"wlan\sssid-profile\s(.*)\n", j)
            ssid[matched.group(1)] = j
            
        elif "wlan virtual-ap" in j:
            matched = re.search(r"wlan\svirtual-ap\s(.*)\n", j)
            vap[matched.group(1)] = j
            
        elif "ap-group" in j:
            matched = re.search(r"ap-group\s(.*)\n", j)
            apgroup[matched.group(1)] = j

        elif "aaa server-group" in j:
            matched = re.search(r"server-group\s(.*)\n", j)
            servergroup[matched.group(1)] = j

        elif "authentication-server radius" in j:
            matched = re.search(r"radius\s(.*)\n", j)
            authserver[matched.group(1)] = j

def profs(part):
    for i in part:
        print part[i]

def prof_part(prof,obj):
    print prof[obj]