基礎的SDNに処理を加える
こちらは #インフラ勉強会 Advent Calendar 2018 18日目の記事です。今18日の29時前なので滑り込みセーフですね
先日の記事はkusuwadaさんでした。
kusuwada.hatenablog.com
加藤(suminofu_3)と申します、研究室でSDN(Software Defined Networking)の研究をしている学生です。
自分の整理も兼ねて、RyuとOVSを使って環境構築した後、比較的簡単に遊べることについて説明したいと思います。最近資格試験にも出題されることが増えてきており、とりあえず組んだ上でちょっといじりたい〜という方には参考になるかなと思っています。
用意したもの
・(Guest)OS : Ubuntu 14.04 or 16.04
・Rapberry Pi 3B × 複数台
SDNを試すならMininetで仮想的に構築するのが経済的な感じがありますが、物理的に組んだ方がやれることも増えるのでラズパイがあればぜひ。
構成
コントローラーのRyu、そしてRasberry Piに仮想スイッチ「Open vSwitch」をインストールしたものを利用します。
OVS間では接続が2本入っております。本来ならループまったなしなのですが、持ち前のフロー制御によってあらかじめ防いでおくことができます。フラッディングをドロップさせるフローを優先度を下げて敷いておけばとりあえずは事故りません。
ここからの方針をいくつか紹介します。
パケット統計取得機能
Ryuは大変ありがたいことにサンプルコードをいくつか配布し、なおかつ日本語のリファレンスも存在しています。OpenFlowコントローラーの中でも入門にオススメされることが多い理由ですね。
その中で、パケットの統計情報を定期的にOVSから取ってくることができる機能があります。
simple_monitor_13.py(一部抜粋)
def _port_stats_reply_handler(self, ev): body = ev.msg.body self.logger.info('datapath port ' 'rx-pkts rx-bytes rx-error ' 'tx-pkts tx-bytes tx-error') self.logger.info('---------------- -------- ' '-------- -------- -------- ' '-------- -------- --------') for stat in sorted(body, key=attrgetter('port_no')): self.logger.info('6x %8x � � � � � �', ev.msg.datapath.id, stat.port_no, stat.rx_packets, stat.rx_bytes, stat.rx_errors, stat.tx_packets, stat.tx_bytes, stat.tx_errors)
OVSごとに通過しているパケットの統計情報がわかるようになります。
下記は少し改変したもので、同じような結果が出力されます。
例
datapath in-port eth-dst out-port packets ------------------ -------- ----------------- ---------- -------- 0000000000000001 1 aa:aa:aa:aa:aa:aa 3 439 0000000000000001 2 bb:bb:bb:bb:bb:bb 1 574 0000000000000001 3 cc:cc:cc:cc:cc:cc 2 1134
プロトコルごとの処理
TCP・UDPなどのプロトコルや、ポート番号を判別するためのコーディングです。
APIを参考に組んでみました。
Ryu API Reference — Ryu 4.30 documentation
例
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def _packet_in_handler(self, ev): if ev.msg.msg_len < ev.msg.total_len: self.logger.debug("packet truncated: only %s of %s bytes", ev.msg.msg_len, ev.msg.total_len) msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser in_port = msg.match['in_port'] pkt = packet.Packet(msg.data) ip4 = pkt.get_protocol(ipv4.ipv4) tcpheader = pkt.get_protocol(tcp.tcp) udpheader = pkt.get_protocol(udp.udp) dst = ip4.dst src = ip4.src if tcpheader: dstport = tcpheader.dst_port srcport = tcpheader.src_port elif udpheader: dstport = udpheader.dst_port srcport = udpheader.src_port
こちらはPacketInイベントの際にTCP・UDPのパケットを判別できるようにしたものです。
上記二つを組み合わせればプロトコルやポート番号によってOVS間の通過するルートを変更させるネットワークの構築が可能です!
よければ実践してみてください〜。
お次(本日...)はAnorlondo448さんです!