Ryu控制器官方应用simple_switch_13.py解读2

简单介绍

上一篇文章Ryu控制器官方应用simple_switch_13.py解读提到我的两个疑问 :
 - 为什么要有3次Packet-in事件?
 - 为什么有两个匹配项:in_porteth_dst
下面就做下实验来尝试解决这两个疑问。

实验1

  实验1来验证我的第一个想法,实现1次Packet-in就可以实现主机互通。

代码修改

  只修改Packet-in事件处理函数,这时候匹配项只有eth_dst。要不然意思就是:“把从1端口来的且目的地址是1端口主机MAC地址的数据包output到1端口”,显然有问题。

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):
        # If you hit this you might want to increase
        # the "miss_send_length" of your switch
        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)
        eth = pkt.get_protocols(ethernet.ethernet)[0]

        if eth.ethertype == ether_types.ETH_TYPE_LLDP:
            # ignore lldp packet
            return
        dst = eth.dst
        src = eth.src

        dpid = datapath.id
        self.mac_to_port.setdefault(dpid, {})

        self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)

        # learn a mac address to avoid FLOOD next time.
        self.mac_to_port[dpid][src] = in_port

        # *************修改内容*************
        actions = [parser.OFPActionOutput(in_port)]
        match = parser.OFPMatch(eth_dst=src)
        if msg.buffer_id != ofproto.OFP_NO_BUFFER:
            self.add_flow(datapath, 1, match, actions, msg.buffer_id)
            return
        else:
            self.add_flow(datapath, 1, match, actions)
        if dst == 'ff:ff:ff:ff:ff:ff':
            # 当数据包是广播包时
            # 用于Packet-out中的action,洪泛广播包
            actions = [parser.OFPActionOutput(ofproto.OFPP_FLOOD)]
        # *************修改结束*************

        # if dst in self.mac_to_port[dpid]:
        #     out_port = self.mac_to_port[dpid][dst]
        # else:
        #     out_port = ofproto.OFPP_FLOOD
        #
        # # install a flow to avoid packet_in next time
        # if out_port != ofproto.OFPP_FLOOD:
        #     match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
        #     # verify if we have a valid buffer_id, if yes avoid to send both
        #     # flow_mod & packet_out
        #     if msg.buffer_id != ofproto.OFP_NO_BUFFER:
        #         self.add_flow(datapath, 1, match, actions, msg.buffer_id)
        #         return
        #     else:
        #         self.add_flow(datapath, 1, match, actions)
        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data

        out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                                  in_port=in_port, actions=actions, data=data)
        datapath.send_msg(out)

【注】主要是修改了“下发流表操作”的相关代码部分。

实验结果

实验结果完全没按照套路出牌,首先是ping不通
这里写图片描述
流表项只添加了一条
这里写图片描述
Packet-in/Packet-out事件不停止,流表重复添加
这里写图片描述
【注】flow_add中内容是一样的。
  第一次Packet-in/Packet-out事件是因为ARP Request,后面的Packet-in/Packet-out事件是因为ICMP Request。流表项添加的内容都是一样的,如下:
cookie=0x0, duration=351.158s, table=0, n_packets=1, n_bytes=42, priority=1,
  dl_dst=00:00:00:00:00:01 actions=output:1

主机h2(h2)正常回复ARP Request:
这里写图片描述

错误原因分析

   ARP Request引发的第一次Packet-in属于正常,然后添加了匹配发往该request主机数据包的流表项;
cookie=0x0, duration=351.158s, table=0, n_packets=1, n_bytes=42, priority=1,
   dl_dst=00:00:00:00:00:01 actions=output:1
  ARP Request被洪泛至除源端口外的所有端口,然后主机h2回复了ARP Reply。因为流表项的存在,ARP Reply被上面的流表项匹配处理,ARP Reply没有引起Packet-in,而是直接根据流表项的动作被发往物理端口1。然后主机h1获取到ARP Reply,得到主机h2的IP与MAC对应关系,所以发送ICMP Request包,但是交换机并没有流表项来处理ICMP Request包,所以引发Packet-in事件。但是代码中处理这个Packet-in事件是根据包的来源信息来添加到这个来源的流表项;因为都是主机h1发的数据包,所以这时新添加的流表项与之前的流表项内容一样,并没有什么卵用。所以ICMP Request包得不到处理,就会一直引起Packet-in。
  主机h2回复的ARP Reply数据包没有被Controller捕获呢,没有添加到主机h2的流表项,ICMP Request数据包可不知道发往哪里啊,就只有送Controller了。

结论

  Too yong too simple。考虑太少,没有认真分析数据包的处理流程,没有考虑到流表项的修改引起的一些列变化。

实验2

  实验2来验证我的第一个想法,实现只需要 eth_dst这一个匹配项。

代码修改

  修改非常少,去掉in_port匹配项就行

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        in_port = msg.match['in_port']

        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocols(ethernet.ethernet)[0]

        dst = eth.dst
        src = eth.src

        dpid = datapath.id
        self.mac_to_port.setdefault(dpid, {})

        self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)

        self.mac_to_port[dpid][src] = in_port

        if dst in self.mac_to_port[dpid]:
            out_port = self.mac_to_port[dpid][dst]
        else:
            out_port = ofproto.OFPP_FLOOD

        actions = [parser.OFPActionOutput(out_port)]

        if out_port != ofproto.OFPP_FLOOD:
            #修改处
            # match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
            match = parser.OFPMatch(eth_dst=dst)
            self.add_flow(datapath, 1, match, actions)

        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data

        out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                                  in_port=in_port, actions=actions, data=data)
        datapath.send_msg(out)

实验结果

  实验结果非常有戏剧性,会根据主机h3的参与情况发生变化。

实验操作1

  1. h1 ping -c1 h2(h1可与h2调换位置)
  2. h3 ping -c1 h1(第2步可以与第3步调换顺序)
  3. h3 ping -c1 h2(第3步可以与第2步调换顺序)
  4. pingall

全部能ping通
这里写图片描述
流表内容也没有问题
这里写图片描述

下面来看抓包数据
这里写图片描述
这里写图片描述
这里写图片描述
  h1 ping h2时的过程与修改前的并没有什么区别,同样是3次Packet-in事件,添加了两条流表项
cookie=0x0, duration=36.552s, table=0, n_packets=3, n_bytes=182, priority=1,
  dl_dst=00:00:00:00:00:02 actions=output:2
cookie=0x0, duration=36.554s, table=0, n_packets=4, n_bytes=280, priority=1,
  dl_dst=00:00:00:00:00:01 actions=output:1
  h3 ping h1时的添加的流表项
cookie=0x0, duration=28.181s, table=0, n_packets=5, n_bytes=322, priority=1,
  dl_dst=00:00:00:00:00:03 actions=output:3

实验操作2

  1. h1 ping -c1 h2(h1可与h2调换位置)
  2. h1 ping -c1 h3(第2步可以与第3步调换顺序)
  3. h2 ping -c1 h3(第3步可以与第2步调换顺序)
  4. pingall

也能全部ping通
这里写图片描述
但是流表内容就不一样了
这里写图片描述
相比操作1的流表少了一条流表项,少的是处理到h3(00:00:00:00:00:03)数据包的流表项

下面来看看抓包截图
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
对于上面的抓包图,可以总结一点:
  由于没有处理到h3(00:00:00:00:00:03)数据包的流表项,所以导致发往h3的数据包全部引起Packet-in事件交给Controller处理,而Controller的处理是洪泛至所有端口。
  通过对每个主机网卡监听可以证明,下图是主机h1的网卡监听,可以看到h1竟然收到h2发往h3的数据包。
这里写图片描述

为什么操作1正常,而操作2就有问题呢?留给读者思考。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值