SDN時代のインフラ構築には、APIベースの設定作業が標準になりつつあります。
通常、仮想VMであれば、OpenStackなどが活用されるところでしょう。
SDNインフラ環境でも既存ネットワークとの相互運用は必須になりますが、NW機器での諸設定が従来通りの手作業によるコンフィグ設定が行なわれている事例がまだ多いと思います。
昨今のSDN技術の台頭により、作業効率の向上、および、オペミス防止の観点から、従来のNW機器もSDNオーケストレーション的なアプローチでAPIベースで制御してしまおうという風潮が高まりつつあります。
そこで、 NETCONFというプロトコルが注目されるわけですね。
◼️ NETCONF確認用のSRXトポロジ環境
今回は、NETCONFを活用したSRX実機でのBGP設定にチャレンジしたいと思います。
なお、BGP構成は、以前の記事と全く同じ構成にします。
なお、NETCONFサーバ動作環境の構築方法は、以前のブログ記事「vSRXを活用した、JUNOSのお勉強まとめ【JUNOS初期設定 + BGP基本編】」と同じです。
SRX実機も、vSRXも同じJUNOSなので、環境構築上の違いはないです。詳しくは、こちらの参照ください。
ttsubo.hatenablog.com
今回は、さらに、NETCONF動作環境を追加しているイメージです。
+----------+ | -MacOS X-| | NETCONF | | (Client) | +----------+ + | | 192.168.100.0/24 | + .101 +----------+ +----------+ .1 | -SRX100- | .1 i-BGP .2 | -BHR4GRV-| .1 ... -------------+ | NETCONF | +----------------------+ | OpenWRT | +------------- ... 172.16.0.0/24 | (Server) | 192.168.0.0/30 | (Quaaga) | 172.16.1.0/24 +----------+ +----------+ < AS65000 > < AS65000 >
SRXトポロジj構成として、SRX実機に加えて、対向BGPルータを用意する必要があります。
ただ、環境構築になるべくお金を掛けたくなかったので、対向BGPには、Buffalo"BHR-4GRV"に、OpenWRT環境をセットアップした上で、Quaggaをインストールして代用しました。
ttsubo.hatenablog.com
◼️ NETCONF環境設定
1. NETCONFクライアント側の環境設定
SDNオーケストレーションなどの自動制御を担う動作環境で、NETCONFを動作させるには、
オープンソースの"ncclient: Python library for NETCONF clients"が活用されることが多いようです。
github.com
ncclientは、次のような多種多様なNETCONF装置に対応しているようです。
Supported device handlers
(1) 事前準備
まず、ncclientをインストールします。
$ pip install ncclient
(2) BGP設定サンプルアプリ[create-bgp.py]の配置
NETCONFを活用して、BGPコンフィグ設定を行うサンプルアプリを配置します。
from ncclient import manager from ncclient.xml_ import * import time def connect(host, port, user, password, config): conn = manager.connect(host=host, port=port, username=user, password=password, timeout=30, device_params = {'name':'junos'}, hostkey_verify=False) print "------------" print "1. conn.lock" print "------------" try: lock = conn.lock() print lock.tostring except Exception as e: print ("Error in 'conn.lock': type=[%s], message=[%s]"%(type(e), e.message)) raise print "--------------------------" print "2. conn.load_configuration" print "--------------------------" try: load_conf = conn.load_configuration(target="candidate", config=config[routing_options], format='xml') print load_conf.tostring load_conf = conn.load_configuration(target="candidate", config=config[protocols], format='xml') print load_conf.tostring except Exception as e: print ("Error in 'conn.load_configuration': type=[%s], message=[%s]"%(type(e), e.message)) raise print "----------------" print "3. conn.validate" print "----------------" try: validate = conn.validate() print validate.tostring except Exception as e: print ("Error in 'conn.validate': type=[%s], message=[%s]"%(type(e), e.message)) raise print "-----------------------------" print "4. conn.compare_configuration" print "-----------------------------" try: compare = conn.compare_configuration() print compare.tostring except Exception as e: print ("Error in 'conn.compare_configuration': type=[%s], message=[%s]"%(type(e), e.message)) raise print "---------------" print "5. conn.commit" print "---------------" try: commit = conn.commit() print commit.tostring except Exception as e: print ("Error in 'conn.commit': type=[%s], message=[%s]"%(type(e), e.message)) raise print "---------------" print "6. conn.unlock" print "---------------" try: unlock = conn.unlock() print unlock.tostring except Exception as e: print ("Error in 'conn.unlock': type=[%s], message=[%s]"%(type(e), e.message)) raise if __name__ == '__main__': protocols = new_ele('protocols') bgp = sub_ele(protocols, 'bgp') group = sub_ele(bgp, 'group') group_name = sub_ele(group, 'name').text = 'INTERNAL' sub_ele(group, 'type').text = 'internal' sub_ele(group, 'export').text = 'export-bgp' sub_ele(group, 'neighbor').text = '192.168.0.2' routing_options = new_ele('routing-options') sub_ele(routing_options, 'router-id').text = '10.0.0.1' sub_ele(routing_options, 'autonomous-system').text = '65000' config = {} config[routing_options] = routing_options config[protocols] = protocols connect('192.168.100.101', 830, 'tsubo', 'xxxxxxx', config)
(3) BGP確認サンプルアプリ[show-bgp.py]の配置
NETCONFを活用して、BGP動作確認を行うサンプルアプリを配置します。
from ncclient import manager from ncclient.xml_ import * import time def connect(host, port, user, password): conn = manager.connect(host=host, port=port, username=user, password=password, timeout=30, device_params = {'name':'junos'}, hostkey_verify=False) print "-------------------------------------" print "1. conn.get_configuration 'protocols'" print "-------------------------------------" config_filter = new_ele('configuration') sub_ele(config_filter, 'routing-options') sub_ele(config_filter, 'protocols') get_conf = conn.get_configuration(format='text', filter=config_filter) print get_conf.tostring print "----------------------------------" print "2. conn.command 'show bgp summary'" print "----------------------------------" time.sleep(10) print "root@SRX> show bgp summary" result = conn.command(command='show bgp summary', format='text') print result.xpath('output')[0].text print "-------------------------------------------------------------" print "3. conn.command 'show route receive-protocol bgp 192.168.0.2'" print "-------------------------------------------------------------" print "root@SRX> show route receive-protocol bgp 192.168.0.2" result = conn.command(command='show route receive-protocol bgp 192.168.0.2', format='text') print result.xpath('output')[0].text if __name__ == '__main__': connect('192.168.100.101', 830, 'tsubo', 'xxxxxxx')
2. NETCONFサーバ側の環境設定
NETCONFサーバ環境として、JUNOS搭載のNW機器が活用されることが多いと思います、
そこで、今回は、JUNOS搭載のNETCONFサーバ環境として、SRX実機を採用しました。
(1) 事前準備
NETCONFクライアント環境からの制御を受信できるように準備しておきます。
具体的には、NETCONFプロトコル(830ポート)を有効にしておきます。
root@SRX> configure Entering configuration mode [edit] root@SRX# set system services netconf ssh port 830
(2) その他、事前に行っておくコンフィグ設定
今回のNETCONF動作として、"protocols"と"routing-options "を設定することにします。
従って、それ以外の各種コンフィグ設定は、事前に設定しておきます。
root@SRX> show configuration |display set set version 12.1X44-D35.5 set system host-name SRX set system time-zone Asia/Tokyo set system root-authentication encrypted-password "$1$kAd32lTR$F7o4dwAbW9vY1CIV.a9kt." set system login user tsubo uid 2000 set system login user tsubo class super-user set system login user tsubo authentication encrypted-password "$1$eT7nqVkt$uCwT9W8WuBhrEhBcyKoQ5/" set system services ssh root-login allow set system services netconf ssh port 830 set system syslog archive size 100k set system syslog archive files 3 set system syslog user * any emergency set system syslog file messages any any set system syslog file messages authorization info set system syslog file interactive-commands interactive-commands any set system max-configurations-on-flash 5 set system max-configuration-rollbacks 5 set system license autoupdate url https://ae1.juniper.net/junos/key_retrieval set system ntp set interfaces fe-0/0/0 unit 0 family inet address 192.168.100.101/24 set interfaces fe-0/0/1 unit 0 family inet address 192.168.0.1/24 set interfaces fe-0/0/2 unit 0 family inet address 172.16.0.1/24 set interfaces lo0 unit 0 family inet address 10.0.0.1/32 set policy-options policy-statement export-bgp term 1 from route-filter 172.16.0.0/24 exact set policy-options policy-statement export-bgp term 1 then accept set security forwarding-options family inet6 mode packet-based set security forwarding-options family mpls mode packet-based
◼️ いよいよ、NETCONF動作を試してみる
1. BGP設定を行う
まずは、NETCONFを活用して、"routing-options"と"protocols"のコンフィグ設定を行います。
$ python create-bgp.py ------------ 1. conn.lock ------------ <rpc-reply message-id="urn:uuid:06ced48c-03d4-11e6-81aa-a45e60ba8c55"> <ok/> </rpc-reply> -------------------------- 2. conn.load_configuration -------------------------- <rpc-reply message-id="urn:uuid:06e4c133-03d4-11e6-ab26-a45e60ba8c55"> <load-configuration-results> <ok/> </load-configuration-results> </rpc-reply> <rpc-reply message-id="urn:uuid:06f798fd-03d4-11e6-afa3-a45e60ba8c55"> <load-configuration-results> <ok/> </load-configuration-results> </rpc-reply> ---------------- 3. conn.validate ---------------- <rpc-reply message-id="urn:uuid:070b022b-03d4-11e6-bca1-a45e60ba8c55"> <commit-results> </commit-results> <ok/> </rpc-reply> ----------------------------- 4. conn.compare_configuration ----------------------------- <rpc-reply message-id="urn:uuid:0a753c47-03d4-11e6-8b4f-a45e60ba8c55"> <configuration-information> <configuration-output> [edit] + routing-options { + router-id 10.0.0.1; + autonomous-system 65000; + } + protocols { + bgp { + group INTERNAL { + type internal; + export export-bgp; + neighbor 192.168.0.2; + } + } + } </configuration-output> </configuration-information> </rpc-reply> --------------- 5. conn.commit --------------- <rpc-reply message-id="urn:uuid:0b0273cc-03d4-11e6-a844-a45e60ba8c55"> <ok/> </rpc-reply> --------------- 6. conn.unlock --------------- <rpc-reply message-id="urn:uuid:1663174f-03d4-11e6-bf75-a45e60ba8c55"> <ok/> </rpc-reply>
特に、エラーも発生せずに、BGP設定を行うことができたようです。
2. BGP動作を確認してみる
それでは、NETCONFを活用して、"routing-options"と"protocols"のコンフィグ設定が正しく行われたことを確認してみます。
$ python show-bgp.py ------------------------------------- 1. conn.get_configuration 'protocols' ------------------------------------- <rpc-reply message-id="urn:uuid:2119510a-03d4-11e6-9a47-a45e60ba8c55"> <configuration-text> ## Last changed: 2016-04-16 22:06:42 JST routing-options { router-id 10.0.0.1; autonomous-system 65000; } ## Last changed: 2016-04-16 22:06:42 JST protocols { bgp { group INTERNAL { type internal; export export-bgp; neighbor 192.168.0.2; } } } </configuration-text> </rpc-reply> ---------------------------------- 2. conn.command 'show bgp summary' ---------------------------------- root@SRX> show bgp summary Groups: 1 Peers: 1 Down peers: 0 Table Tot Paths Act Paths Suppressed History Damp State Pending inet.0 1 1 0 0 0 0 Peer AS InPkt OutPkt OutQ Flaps Last Up/Dwn State|#Active/Received/Accepted/Damped... 192.168.0.2 65000 3 4 0 0 18 1/1/1/0 0/0/0/0 ------------------------------------------------------------- 3. conn.command 'show route receive-protocol bgp 192.168.0.2' ------------------------------------------------------------- root@SRX> show route receive-protocol bgp 192.168.0.2 inet.0: 8 destinations, 8 routes (8 active, 0 holddown, 0 hidden) Prefix Nexthop MED Lclpref AS path * 172.16.1.0/24 192.168.0.2 0 100 I
さらに、対向BGPルータにて、SRXから配布されたBGP経路が受信できたことを確認してみます。
Quagga-3# show ip bgp BGP table version is 0, local router ID is 10.0.1.3 Status codes: s suppressed, d damped, h history, * valid, > best, i - internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *>i172.16.0.0/24 192.168.0.1 100 0 i *> 172.16.1.0/24 0.0.0.0 0 32768 i Total number of prefixes 2
以上より、NETCONFを活用することにより、NW機器への各種コンフィグ設定/確認が自動的に実施できるよう、Pythonスクリプト化することができました。
◼️ 最後に、
SDNインフラと相互接続しているNW機器を、SDNオーケストレーション層から順序制御できる仕組みとして、NETCONFの活用は、とても有効であると思います。
今後も、クラウド基盤として、OpenStackが活用される事例は、ますます増えていくと思います。OpenStackとNETCONFの動作連携を担う仕組みとして、heat プロジェクトの役割りの重要性が、どんどん増していくのでしょう。