zoukankan      html  css  js  c++  java
  • RyuBook1.0案例一:Switching Hub项目源码分析

    开发目标

    实现一个带MAC地址学习功能的二层交换机

    Openflow交换机与Openflow控制器安全通道建立步骤

    • switch and controller建立未加密TCP连接或者加密的TLS连接
    • 确定连接通道的Openflow版本
    • 握手
    • 其他操作

    建立连接通道后,二者发生Hello包,进行协商Openflow版本号

    完成交换Hello消息之后建立安全通道,执行握手。Controller发生Features请求,并处理Features响应

    接收到Features响应,控制器可以向交换机发送SET_CONFIG或者GET_CONFIG请求消息,进行设置交换机默认配置或者查询交换机配置。

    之后,可以进行OpenFlow的其他操作

    Flow-Mod消息

    Flow-Mod(Modify Flow Entry Message)由控制器向交换机下发的设置流表项的信息

    其中 ofp_match结构体为数据包匹配部分。

    程序分析

    设置想要向交换机协商的OpenFlow版本号

    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    

    下发Table-miss流表项

    设置完成该项参数配置,控制器自动执行第一步操作,即交换Hello包,协商版本号。协商完成之后,自动执行交换Features包,进行握手。

    握手完成后,使用set_ev_cls函数处理Features响应包

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    

    第二项参数详情如下:

    Defination Explanation
    HANDSHAKE_DISPATCHER 交换HELLO消息
    CONFIG_DISPATCHER 等待接收SwitchFeatures消息
    MAIN_DISPATCHER 正常状态
    DEAD_DISPATCHER 连接断开

    定义处理函数,并解析返回包的字段

    def switch_features_handler(self, ev):
        datapath = ev.msg.data
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
    

    安装table-miss entry

    match = parser.OFPMatch()
    

    table-miss:

    OpenFlow1.3版本为处理table miss事件专门引入的条目。并规定每一个flow table必须要支持table-miss flow entry去处理table miss情况。table-miss flow entry具备最低的优先级(0);必须至少能够支持使用CONTROLLER保留端口发送包,使用Clear-Actions指令丢包;table-miss flow entry和其他flow entry具有相同的特性:默认不存在,控制器可以随时添加或丢弃该条目,也可以到期;如果使用CONTROLLER保留端口发生数据包,Packet-In发送原因必须标明table-miss。

    actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                      ofproto.OFPCML_NO_BUFFER)]
    

    OFPActionOutput() :使用一个packet_out 消息去指定你想从交换机的哪个端口发送出数据包。在该应用中,按照标准指定通过CONTROLLER保留端口发生,所以选择了OFPP_CONTROLLER端口。第二个参数OFPCML_NO_BUFFER,指明:消息中必须包含完整的包,而不会被缓冲。

    指定完成actions,使用类的add_flow向控制器添加流表项

    self.add_flow(self, datapath, 0, match, actions)
    

    接下来分析add_flow的具体实现过程:

    构建OpenFlow流表消息

    inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
    mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    match=match, instructions=inst)
    

    OpenFlow目前主流版本为Openflow1.0,1.1,1.3。相比1.0版本,1.3版本流表项结构变化很大,在这里我们用到的Instruction可以说是1.0版本中Actions的拓展。Instruction主要负责将流表转发到其他Table,流水线,或者进行其他转发操作。

    • OFPIT_APPLY_ACTIONS: 立即应用actions操作到交换机

    函数OFPFlowMod()负责构建Flow-Mod消息

    使用send()函数发送flow-mod消息

    datapath.send(mod)
    

    以上步骤完成下发配置table-miss流表项

    MAC地址学习功能实现

    MAC地址学习功能,主要要处理接收到的Packet-In数据包,所以重写set_cls_ev函数

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    
    • ofp_event.EventOFPPacketIn: 指处理PacketIn消息
    • MAIN_DISPATCHER: ???

    解析数据包

    def _package_in_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
    
    

    获取datapath.id

    dpid = datapath.id
    

    datapath是交换机的唯一标识,即dpid

    添加dpid: {}到mac地址、port字典中

    self.mac_to_port.setdefault(dpid, {})
    

    从datapath中解析dst,src

    pkt = packet.Packet(msg.data)
    eth_pkt = pkt.get_protocol(ethernet.ethernet)
    dst = eth_pkt.dst
    src = eth_pkt.src
    

    从datapath中匹配出in_port

    in_port = msg.match['in_port']
    

    存储in_port和mac

    self.mac_to_port[dpid][src] = in_port
    

    检查,如果已经存储过port和mac,如果存在,则配置out_port为指定端口;如果不存在,则使用OFPP_FLOOD端口,向全部端口进行泛洪。

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

    构建Actions

    actions = [parser.OFPActionOutput(out_port)]
    

    如果out_port非Flood端口,则下发流表到交换机

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

    构建Packet_Out消息,并发送到交换机

    out = parser.OFPPacketOut(datapath=datapath,
                              buffer_id=ofproto.OFP_NO_BUFFER,
                              in_port=in_port, actions=actions,
                              data=msg.data)
    datapath.send_msg(out)
    
  • 相关阅读:
    计算机组成原理小结
    selenium基本操作
    selenium实现网易邮箱的登录注册
    如何安装selenium框架
    2020年目标
    个人对软件测试的认识
    java b2b2c电商系统javashop7.2发布
    基于脚本引擎的运费架构分享
    模拟支付宝微信回调
    Javashop电商系统7.2发布
  • 原文地址:https://www.cnblogs.com/NinWoo/p/9357135.html
Copyright © 2011-2022 走看看