首页 文章

OpenFlow - 如何处理ICMP消息

提问于
浏览
0

我正在运行一个Ryu控制器和一个带有2个主机和1个开关的Mininet实例,如下所示 .

H1 ---小号--- H2

Ryu控制器中的代码

from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types


class SimpleSwitch13(app_manager.RyuApp):

OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

def __init__(self, *args, **kwargs):
    super(SimpleSwitch13, self).__init__(*args, **kwargs)
    self.mac_to_port = {}

@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
    datapath = ev.msg.datapath
    ofproto = datapath.ofproto
    parser = datapath.ofproto_parser

基本上 the switch flow table is empty . 在这种情况下,当我从我的mininet控制台运行 h1 ping h2 并记录数据包交换时,这就是我从主机h1到wireshark的内容 .

enter image description here

mininet实例中没有路由器 . 我如何从发起ping的同一主机收到ICMP主机目标无法到达消息?

2 回答

  • 1

    您发布的应用代码是 not complete .

    对于完整的simple_switch_13.py,您可以从osrg github获取它 .

    看一下,就像这样:

    class SimpleSwitch13(app_manager.RyuApp):
        OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    
        def __init__(self, *args, **kwargs):
            super(SimpleSwitch13, self).__init__(*args, **kwargs)
            self.mac_to_port = {}
    
        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_features_handler(self, ev):
            datapath = ev.msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
    
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                              ofproto.OFPCML_NO_BUFFER)]
            self.add_flow(datapath, 0, match, actions)
    
        def add_flow(self, datapath, priority, match, actions, buffer_id=None):
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
    
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                                 actions)]
            if buffer_id:
                mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                        priority=priority, match=match,
                                        instructions=inst)
            else:
                mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                        match=match, instructions=inst)
            datapath.send_msg(mod)
    
        @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
    
            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)]
    
            # 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)
    

    这个simple_switch_13.py应用程序只处理第2层转发,这是你的情况 .

    如您所见,在 Build 连接后, switch_features_handler 将侦听此事件并在交换机上添加 send all flow to controller 流 . ( table-miss flow)

    对于正常状态,当控制器收到PACKET_IN时,它将检查dst_MAC是否在 mac_to_port 中 . 如果是,则输出到端口,同时插入流(其匹配字段为inport和dst_MAC); else(不在数组中),通过分配 outport=FLOOD 将操作设置为FLOOD .

    在第2层交换中就是这种情况 .

    对于第3层交换中的ICMP消息处理,您需要读取 rest_router.py 代码,这要复杂得多 .

  • 0

    您的ICMP主机目标无法访问,因为h2永远不会回答ARP请求 .

    由于h1没有ARP回复,因此ICMP错误消息来自其自己的IP堆栈 .

相关问题