今回は実際に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
結果
以下の通り、概ね期待通りとなった。
今回もofsoftswitch13のバグにより手こずってしまった。
前回Pull Requestしたパッチは取り込まれたようで、今回もDSCP値の変更でチェックサムの再計算が
おかしくなっていた箇所と、Packetをパースする箇所にバグがあり、DSCP値でマッチングできない問題の
パッチを送る予定。。
またQoS関連で実験してみる。
Comments
Add Comment