Atom Login Admin

Above the clouds

Ryu コントローラでDiffServ #3 MeterTableを使ってPolicing

written on Sunday,January 26,2014

今回はMeter Tableを使ってPolicingということで、より実践的にDoS/Worm Mitigationをやってみた。
port 5003宛で500kbpsを超えるトラッフィクは異常と見なし、DSCP値を24から8(CS 1:Scavenger)へとMarkdownし、DSCP:24の帯域を確保するシナリオとした。(実践的では無いかもしれないが。。)
コントローラはRyuを使い、OpenFlow Switchはofsoftswitch13、ネットワークシュミレータにはMininet2.0を使用している。
コントローラの実装はCloudy Switchを使用。

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

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

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

リンクスピードは6Mbpsとなるようにofsoftswitch13の
lib/netdev.cのnetdev->speedを変更している。

Mininetのスクリプトは以下のとおり

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 300')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 1 3 600')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 1 1 100')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 1 2 300')
    s1.cmdPrint('dpctl unix:/tmp/s1 queue-mod 1 3 600')
    s2 = net.getNodeByName('s2')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 1 1 100')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 1 2 300')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 1 3 600')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 2 1 100')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 2 2 300')
    s2.cmdPrint('dpctl unix:/tmp/s2 queue-mod 2 3 600')

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)

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

まず、Meter Tableのエントリーは以下のとおり

    def send_meter_entry(self, datapath):
        parser = datapath.ofproto_parser
        ofproto = datapath.ofproto
        band = parser.OFPMeterBandDscpRemark(rate=500, burst_size=5, prec_level=2)
        req = parser.OFPMeterMod(datapath, ofproto.OFPMC_ADD,
                                 ofproto.OFPMF_KBPS, 1, [band])
        datapath.send_msg(req)
        eth_IP = ether.ETH_TYPE_IP
        match = parser.OFPMatch(eth_type=eth_IP, ip_dscp=24)
        instructions = [parser.OFPInstructionMeter(1),
                        parser.OFPInstructionGotoTable(2)]
        flow_mod = self.create_flow_mod(datapath, 0, 1,
                                        match, instructions)
        datapath.send_msg(flow_mod)
        # Policing for Scavenger class
        band = parser.OFPMeterBandDrop(rate=100,
                                       burst_size=5)
        req = parser.OFPMeterMod(datapath, ofproto.OFPMC_ADD,
                                 ofproto.OFPMF_KBPS, 2, [band])
        datapath.send_msg(req)

    def process_end_hw_addr_flows(self, port):
        """ Default flow entry for end switch"""
        eth_IP = ether.ETH_TYPE_IP
        target_switch = self.switches[port[0]]
        datapath = target_switch.switch.dp
        dscp_to_queue_values = {0:1, 8:1, 16:1, 24:2, 32:2, 40:2, 48:3, 56:3}
        SCAVENGER = 8
        for dscp, queue in dscp_to_queue_values.items():
            hw_addr = port[2]
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
            actions = [parser.OFPActionSetQueue(queue),
                       parser.OFPActionOutput(port[1])]
            match = datapath.ofproto_parser.OFPMatch(eth_type=eth_IP,
                                                     ip_dscp=dscp,
                                                     eth_dst=hw_addr)
            inst = [parser.OFPInstructionActions(
                    ofproto.OFPIT_APPLY_ACTIONS, actions)]
            if dscp == SCAVENGER:
                inst.insert(0, parser.OFPInstructionMeter(2))
            flow_mod = self.create_flow_mod(datapath, 100, 7, match, inst)
            datapath.send_msg(flow_mod)

ここでポイントなのが、
[Host1] - [OFS1] - [OFS2] - [Host2]
上記構成で、OFS1でMeter Table(Meter id:1)を用いてMarkdownしているが、更に全てのOFSの入力ポートでMeter Table(Meter id:2)でScavenger Class(DSCP:8)のトラフィックに対して、100kbps以上の流量があるとパケットをドロップするMeter Entryを登録している。
これによってScavenger ClassのトラフィックでBest Effortトラフィックの帯域を確保することにしている。
また、DSCP:56、48はQueue 3(3.6Mbps)へ、DSCP:40、32、24はQueue 2(1.8Mbps)、DSCP:16、8、0はQueue 1(0.6Mbps)へQueingされるようにFlow Entryは登録されている。

実行

今回は以下のようなマッチング条件でマーキングを行った。
Table 1はMeter Flow用のTableとしている。

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:2
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:2
s1 dpctl unix:/tmp/s1 flow-mod cmd=add,table=0 eth_type=0x800,ip_proto=6,tcp_dst=5003 apply:set_field=ip_dscp:24 goto:1

Port 5001宛はDSCP 56、Port 5002宛はDSCP 24、Port 5003宛はMeter対象でDSCP 24、Port 5004宛はBest Effort

結果

以下の通り、概ね期待通りとなったのだが、
Port 5003宛のトラフィックがBest Effortと同じ位の流量になってしまっている。これは、Markdownされるまでの流量とMarkdownされた後の流量(100kbpsまで)が混じることによって、BestEffortトラフィックと同じくらいになってしまったからであろう。

QoS DiffServ #3

Meter Tableの統計は以下の通り

s1 dpctl unix:/tmp/s1 stats-meter

SENDING:
stat_req{type="mstats", flags="0x0"{meter_id= ffffffff"}

RECEIVED:
stat_repl{type="mstats", flags="0x0", stats=[{meter= 1"", flow_cnt="1", pkt_in_cnt="6250", byte_in_cnt="3684544", duration_sec="141", duration_nsec="19000", bands=[{pkt_band_cnt="542", byte_band_cnt="319780"}]}, {meter= 2"", flow_cnt="1", pkt_in_cnt="0", byte_in_cnt="0", duration_sec="141", duration_nsec="19000", bands=[{pkt_band_cnt="0", byte_band_cnt="0"}]}]}

s2 dpctl unix:/tmp/s2 stats-meter

SENDING:
stat_req{type="mstats", flags="0x0"{meter_id= ffffffff"}

RECEIVED:
stat_repl{type="mstats", flags="0x0", stats=[{meter= 1"", flow_cnt="1", pkt_in_cnt="0", byte_in_cnt="0", duration_sec="115", duration_nsec="100000", bands=[{pkt_band_cnt="0", byte_band_cnt="0"}]}, {meter= 2"", flow_cnt="1", pkt_in_cnt="539", byte_in_cnt="318010", duration_sec="115", duration_nsec="100000", bands=[{pkt_band_cnt="202", byte_band_cnt="119180"}]}]}

今回はMeter TableでQoSを実践してみたが、DoS/Worm Mitigation StrategyとしてはMeter Tableは有効な方法だと思った。
更にOpenFlowでQoSを実施する方法について考えていきたいと思う。
もっとQoSの理解も深めていきたいところだ。(^^;

Comments

Add Comment

Login
This entry was tagged #Ryu #OpenFlow #QoS