Atom Login Admin

Above the clouds

Ryu コントローラでDiffServ #2 DSCP Marking & Queuing

written on Sunday,January 12,2014

今回は実際にDSCP MarkingとDSCP値に基づいた入力Queueへのマッピングを行い、動作確認を行う。
前回Meter Tableを用いたDSCP値のリマーキングの動作を確認していみたが、今回は実際にQueueingし、パケットを送出して検証してみた。
コントローラはRyuで、OpenFlow Switchはofsoftswitch13、ネットワークシュミレータにはMininet 2.0を使用している。
また、コントローラの実装は、CloudySwitchを使用。
経路制御はMPLSで行っている。

ネットワーク構成について

以下の構成で実験を行った。

[Host1] - [OFS1] - [OFS2] - [Host2]

リンクスピードは6Mbpsとなるようにofsoftswitch13の
lib/netdev.cのnetdev->speedを変更した。
ofsoftswitch13はqueueing 規則にHTBを用いている。
HTBについては、HTB Homepageを参照してほしい。
また、前回mininetのトポロジを作成するスクリプトのqueue-modの3つ目の引数について説明していなかったが、ここで設定する値は、使用可能帯域幅に対する10倍したパーセンテージを指定する。

dpctl unix:/tmp/s1 queue-mod 1 1 100
queue id 1に割り当てる帯域幅は、6Mbpsの10% = 600kbps
【追記】下記の割り当だとQueueに割り当てた帯域幅の合計が100%にならないため、Priorizing bandwidth shareが行われる。優先順位は指定していないので、割当帯域幅を公平に超過している。

from mininet.net import Mininet
from mininet.cli import CLI
from mininet.node import UserSwitch as Switch
from mininet.node import RemoteController

from sample_topology import MyTopo 

def run(net):
    s1 = net.getNodeByName('s1')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 1 1 100')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 1 2 200')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 1 3 300')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 2 1 100')
    s2 = net.getNodeByName('s2')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 1 1 100')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 2 1 100')

def genericTest(topo):
    net = Mininet(topo=topo, switch=Switch, controller=RemoteController)
    net.start()
    run(net)
    CLI(net)
    net.stop()

def main():
    topo = MyTopo()
    genericTest(topo)

コントローラ側の処理について

まず、MPLSで経路制御しているので、DSCP値をEXPビットへコピーした後に選択経路で使用するラベルを設定した後にEXPビットの値に基づいたキューイングをしなくてはならない。

パイプライン流れは以下の通り

[Table 0]
マッチング条件に基づいてDSCP値をマーキング
[Table 1]
DSCP値に基づいて次のTable idへと振分ける。
(今回はDSCP値が0,8,16はTable id 2へ、24,32,40はTable id 3へ、
40,48,56はTable id 4へ)
この時点で、Push MPLS ActionをApplyする。
(これはPrerequisiteがあるため)
[Table 2,3,4]
Table 2,3,4 それぞれEXPビットを1,2,3と設定するActionをApplyし次のTable 5へ
[Table 5]
MPLSラベルを設定して、
EXPビットに基づいたQueueをセットし、Output

以下は、DSCP値のマッピングとEXPからQueueへの設定の部分のコード

    def dscp_to_exp_mapping(self, dp):
        parser = dp.ofproto_parser
        eth_MPLS = ether.ETH_TYPE_MPLS
        dscp_to_table_values = {0:2, 8:2, 16:2, 24:3, 32:3, 40:3, 48:4, 56:4}
        tc = 1
        for table_id in set(dscp_to_table_values.values()):
            match = parser.OFPMatch(eth_type=eth_MPLS)
            actions = [parser.OFPActionSetField(mpls_tc=tc)]
            insts = [dp.ofproto_parser.OFPInstructionActions(
                     dp.ofproto.OFPIT_APPLY_ACTIONS, actions),
                     dp.ofproto_parser.OFPInstructionGotoTable(5)]
            flow_mod = self.create_flow_mod(dp, 100, table_id, match, insts)
            dp.send_msg(flow_mod)
            tc += 1

        eth_IP = ether.ETH_TYPE_IP
        for dscp, table in dscp_to_table_values.items():
            match = parser.OFPMatch(eth_type=eth_IP, ip_dscp=dscp)
            actions = [parser.OFPActionPushMpls(eth_MPLS)]
            insts = [dp.ofproto_parser.OFPInstructionActions(
                     dp.ofproto.OFPIT_APPLY_ACTIONS, actions),
                     dp.ofproto_parser.OFPInstructionGotoTable(table)]
            flow_mod = self.create_flow_mod(dp, 50, 1, match, insts)
            dp.send_msg(flow_mod)

    def create_exp_queue_mapping(self, dp, label, port_no, dst_port):
        dscp_values = {1:1, 2:2, 3:3}
        parser = dp.ofproto_parser
        ofproto = dp.ofproto
        eth_MPLS = ether.ETH_TYPE_MPLS
        for dscp, queue in dscp_values.items():
            match = parser.OFPMatch(eth_type=eth_MPLS, mpls_tc=dscp,
                                    eth_dst=dst_port[2])
            actions = [parser.OFPActionSetField(mpls_label=label),
                       parser.OFPActionSetQueue(queue),
                       parser.OFPActionOutput(port_no)]
            insts = [parser.OFPInstructionActions(
                    ofproto.OFPIT_APPLY_ACTIONS, actions)]
            flow_mod = self.create_flow_mod(dp, 100, 5, match, insts)
            dp.send_msg(flow_mod)

実行

今回は以下のようなマッチング条件でマーキングを行った。

s1 dpctl unix:/tmp/s1 flow-mod cmd=add,table=0 eth_type=0x800,ip_proto=6,tcp_dst=5001 apply:set_field=ip_dscp:56 goto:1

s1 dpctl unix:/tmp/s1 flow-mod cmd=add,table=0 eth_type=0x800,ip_proto=6,tcp_dst=5002 apply:set_field=ip_dscp:24 goto:1

Port 5001宛はDSCP 56で、Port 5002宛はDSCP 24、Port 5003宛はBest Effort

結果

以下の通り、概ね期待通りとなった。
QoS Test

今回もofsoftswitch13のバグにより手こずってしまった。
前回Pull Requestしたパッチは取り込まれたようで、今回もDSCP値の変更でチェックサムの再計算が
おかしくなっていた箇所と、Packetをパースする箇所にバグがあり、DSCP値でマッチングできない問題の
パッチを送る予定。。
またQoS関連で実験してみる。

Comments

Add Comment

Login
This entry was tagged #Ryu #QoS #OpenFlow