Ejemplo n.º 1
0
class DomainController(app_manager.RyuApp):

    _CONTEXTS = {"wsgi": WSGIApplication, "switches": switches.Switches, "arp": IcmpResponder}

    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION, ofproto_v1_3.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        super(DomainController, self).__init__(*args, **kwargs)

        self.domainId = self.CONF.domain_id
        self.name = "domain_controller"
        self.domainWsgiIp = self.CONF.domain_wsgi_ip
        self.domainWsgiPort = self.CONF.domain_port
        self.topo = DomainTopo(name="Domain " + str(self.domainId))
        self.dps = {}
        self.switches = []
        self.sleep = 10

        self.TASK_LIST = {}
        self.LabelsPool = MplsLabelsPool()
        self.LabelsPool.initPool()
        self.deviceInfo = {}
        self.num = 0
        ############################################
        self.edgePort = []
        self.borderPeer = []
        self.outDomainSwitch = {}
        self.shortestPath = {}
        # self.shortestPath = {(513,518):[513,515,518],(518,513):[518,515,513]}
        #####################################################

        self.QoS_dict = {}
        self.superExist = self.CONF.super_exist
        if self.superExist:
            self.superWsgiIp = self.CONF.super_wsgi_ip
            self.superWsgiPort = self.CONF.super_wsgi_port

        self.superLastEcho = time.time()

        self.monitorThreadFlag = self.CONF.monitor_thread_flag
        # if self.monitorThreadFlag:
        # self.monitorThread = hub.spawn(self._monitor)
        self.lastCollect = {}

        self.keepAliveThread = hub.spawn(self._keepAlive)

        wsgi = kwargs["wsgi"]
        data = {}
        data[DOMAINCONTROLLER] = self
        data[DomainReplyController] = DomainReplyController()
        wsgi.register(DomainWsgiController, data)

    def _get_QueueQos(self, dpid):
        assert dpid in self.QoS_dict
        return self.QoS_dict[dpid]

    def _get_datapath(self, dpid):
        assert dpid in self.dps
        return self.dps[dpid]

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        self.logger.debug("switch features ev %s", msg)

        dpid = datapath.id

        switch = self.deviceInfo.setdefault(dpid, SwitchFeatures(dpid))

        switch.initFieds(msg.version, msg.capabilities, msg.n_buffers, msg.n_tables, msg.auxiliary_id)

        if dpid not in self.QoS_dict:
            queueQoSInstance = QueueQos(datapath, self.CONF)
            self.QoS_dict[dpid] = queueQoSInstance
            ip = datapath.address[0]
            ovs_addr = "tcp:" + ip + ":" + DEFAULTOVSDBADDR
            queueQoSInstance.set_ovsdb_addr(dpid, ovs_addr)
            self.logger.info("QueueQoS Entering. dpid: %016x, addr: %s" % (dpid, ovs_addr))

    # msg:  {'body': [OFPPort(port_no=9,hw_addr='48:6e:73:02:03:08',
    # name='ge-1/1/9',config=0,state=1,curr=10240

    @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, CONFIG_DISPATCHER)
    def multipart_reply_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        dpid = datapath.id
        switch = self.deviceInfo.setdefault(dpid, SwitchFeatures(dpid))

        # self.num = self.num+1
        # print self.num
        # ports = switch.getPorts()
        # print 'msg: ', msg.__dict__
        for portdesc in msg.body:
            # print 'portdesc: ', portdesc

            portNo = portdesc.port_no
            if portNo > 10000:
                # print 11111111111111111111111111
                name = portdesc.name
                switch.setName(name)
            else:
                port = PortFeatures(portNo)
                port.initFields(portdesc)
                # print 'port: ',port.__dict__
                switch.ports[portNo] = port
                self.QoS_dict[dpid].queueInfo[portNo] = QueuePort(portNo, dpid)

        if self.superExist:
            self._send_switch_features_message(dpid)

    def _send_switch_features_message(self, dpid):

        send_message = self._make_switch_features_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_switch_features_message(self, dpid):
        assert dpid in self.deviceInfo
        switchFeaturs = self.deviceInfo[dpid]
        info = switchFeaturs.makeFeaturesMessage()
        to_send = {}
        to_send[TYPE] = "switchFeature"
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[SWITCHFEATURE] = info

        send_message = json.dumps(to_send)
        return send_message

    def remove_flow(self, datapath, match):

        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
            mod = parser.OFPFlowMod(
                datapath=datapath, command=ofproto.OFPFC_DELETE, out_port=ofproto.OFPP_ANY, match=match
            )
        elif ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            mod = parser.OFPFlowMod(
                datapath=datapath,
                command=ofproto.OFPFC_DELETE,
                out_group=ofproto.OFPG_ANY,
                out_port=ofproto.OFPP_ANY,
                match=match,
            )

        datapath.send_msg(mod)

    def _get_ofproto_info(self, dpid):
        assert dpid in self.dps
        dp = self.dps[dpid]
        parser = dp.ofproto_parser
        ofproto = dp.ofproto
        return dp, parser, ofproto

    def _get_flow_mod(self, dpid, match, actions, priority=None, buffer_id=None):

        dp, parser, ofproto = self._get_ofproto_info(dpid)

        if not priority:
            priority = ofproto.OFP_DEFAULT_PRIORITY

        if ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
            mod = parser.OFPFlowMod(datapath=dp, priority=priority, match=match, instructions=inst)
        else:
            raise ValueError("We only support OpenFlow 1.3 now")
        return mod

    def _send_flow(self, datapath, mod):
        datapath.send_msg(mod)

    def pushMplsFlow(self, dpid, pushLabel, srcIp, dstIp, outPortNo, queueId, pathType):
        assert dpid in self.dps

        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        # print 'srcIp,dstIp: ',srcIp,dstIp
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)
        # match = parser.OFPMatch(eth_type=eth_IP,ipv4_src=('10.108.92.0','255.255.255.0'),
        #                        ipv4_dst=('10.108.93.0','255.255.255.0'))
        actions = []
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions)
        if pathType == "main":
            self._send_flow(dp, mod)
        elif pathType == "backup":
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod

    def popMplsFlow(self, dpid, popLabel, outPort, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod

    def swapMplsFlow(self, dpid, pushLabel, popLabel, outPortNo, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod

    def noMplsFlow(self, dpid, srcIp, dstIp, outPortNo, queueId, pathType):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        # eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)

        actions = []
        actions.append(parser.OFPActionOutput(outPortNo))
        actions.append(parser.OFPActionSetQueue(queueId))

        mod = self._get_flow_mod(dpid, match, actions)

        if pathType == "main":
            self._send_flow(dp, mod)
        elif pathType == "backup":
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod

    def popMplsMacFlow(self, dpid, popLabel, outPortNo, local_mac, next_mac, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))
        # print 'local_mac,next_mac: ',local_mac,next_mac
        actions.append(parser.OFPActionSetField(eth_src=local_mac))  ##
        actions.append(parser.OFPActionSetField(eth_dst=next_mac))

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod  ####

    def noMplsMacFlow(self, dpid, srcIp, dstIp, outPortNo, local_mac, next_mac, queueId, pathType):

        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        # eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)

        actions = []
        actions.append(parser.OFPActionOutput(outPortNo))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionSetField(eth_src=local_mac))  ##
        actions.append(parser.OFPActionSetField(eth_dst=next_mac))

        mod = self._get_flow_mod(dpid, match, actions)

        if pathType == "main":
            self._send_flow(dp, mod)
        elif pathType == "backup":
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod

    @set_ev_cls(event.EventSwitchEnter, [MAIN_DISPATCHER, CONFIG_DISPATCHER])
    def switchEnterHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id
        if dpid not in self.switches:
            self.switches.append(dpid)

        if dpid not in self.dps:
            self.dps[dpid] = dp

        assert len(self.switches) == len(self.dps)

        self.topo.addNode(dpid)
        self.logger.info("Switch %016x enter in local topo", dpid)

        if self.superExist:
            self._send_switch_enter_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %016x", dpid)

    def _send_switch_enter_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[TYPE] = "switchEnter"
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventSwitchLeave, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def switchLeaveHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id

        if dpid in self.switches:
            self.switches.remove(dpid)
        if dpid in self.dps:
            del self.dps[dpid]

        if dpid not in self.topo.nodes():
            self.logger.warning("Switch %016x not in local topo", dpid)
        else:
            self.topo.removeNode(dpid)
            self.logger.info("Switch %016x leave the local topo", dpid)

        if self.superExist:
            self._send_switch_leave_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %016x", dpid)

    def _send_switch_leave_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = "switchLeave"
        to_send[DPID] = dpid
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkAdd, [CONFIG_DISPATCHER, MAIN_DISPATCHER])
    def linkAddHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no
        # print 'src_switch: ',src_switch,type(src_switch)
        edge = (src_switch, dst_switch)

        ########################################################################
        if src_switch in self.dps:
            if edge not in self.topo.edges():
                self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
                self.logger.info(
                    "Link add: src %016x port_no %8d-> dst %016x %8d" % (src_switch, src_port, dst_switch, dst_port)
                )

        else:
            assert src_switch not in self.dps
            # self.outDomainSwitch[(dst_switch, dst_port)] = (src_switch, src_port)
            if src_switch not in self.outDomainSwitch.values():
                self.outDomainSwitch[dst_switch] = src_switch
                self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
                self.reportPath()
                dst_switch = str(dst_switch)

        #####################################################################################

        if self.superExist:
            self._send_link_add_msg(src_switch, src_port, dst_switch, dst_port)
            dst_switch = int(dst_switch)
            self.logger.info(
                "TO Super controller.Link add: src %016x port_no %8d-> dst %016x %8d"
                % (src_switch, src_port, dst_switch, dst_port)
            )

    def _send_link_add_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = "linkAdd"
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkDelete, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def linkDelHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if edge in self.topo.edges():
            self.topo.removeEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info(
                "Link delete: src %016x port_no %8d-> dst %016x port_no %8d"
                % (src_switch, src_port, dst_switch, dst_port)
            )

        if self.superExist:
            self._send_link_delete_msg(src_switch, src_port, dst_switch, dst_port)
            self.logger.info(
                "TO Super controller.Link Delete: src %016x port_no %8d-> dst %016x %8d"
                % (src_switch, src_port, dst_switch, dst_port)
            )

    def _send_link_delete_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = "linkDelete"
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _monitor(self):
        hub.sleep(5)
        while True:

            for k in self.dps.keys():
                # self._request_stats(dp)
                self._request_stats(self.dps[k])
            hub.sleep(self.sleep)

    def _request_stats(self, datapath):
        self.logger.info("send stats request: %016x", datapath.id)
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        req = parser.OFPFlowStatsRequest(datapath)
        datapath.send_msg(req)
        req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
        datapath.send_msg(req)

    def _keepAlive(self):
        while True:
            if self.superExist:
                self._send_keep_alive_message()
                self.logger.info("send keep alive")
            hub.sleep(5)

    def _send_keep_alive_message(self):
        to_send = {}
        to_send[TYPE] = "keepAlive"
        to_send[DOMAINID] = self.domainId
        to_send[DOMAINWSGIIP] = self.domainWsgiIp
        to_send[DOMAINWSGIPORT] = self.domainWsgiPort

        send_message = json.dumps(to_send)
        # print send_message
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body
        self.logger.info("datapath         in_port  eth_dst  out_port packets  bytes    ")
        self.logger.info("---------------- -------- -------- -------- -------- -------- ")
        for stat in sorted(
            [flow for flow in body if flow.priority == 1],
            key=lambda flow: (flow.match["in_port"], flow.match["eth_dst"]),
        ):
            self.logger.info(
                "%016x %8x %17s %8x %8d %8d",
                ev.msg.datapath.id,
                stat.match["in_port"],
                stat.match["eth_dst"],
                stat.instructions[0].actions[0].port,
                stat.packet_count,
                stat.byte_count,
            )

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        msg = ev.msg
        body = msg.body
        dpid = msg.datapath.id
        switchCollect = self.lastCollect.setdefault(dpid, SwitchStats(dpid))
        ports = switchCollect.getPotrs()

        self.logger.info(
            "datapath            port     " "rx-pkts   rx-bytes   rx-error" "tx-pkts   tx-bytes   tx-error"
        )
        self.logger.info(
            "-----------    --------------" "-------   --------   --------" "-------   --------   --------"
        )
        for stat in sorted(body, key=attrgetter("port_no")):
            self.logger.info(
                "%016x %8x %8d %8d %8d %8d %8d %8d ",
                ev.msg.datapath.id,
                stat.port_no,
                stat.rx_packets,
                stat.rx_bytes,
                stat.rx_errors,
                stat.tx_packets,
                stat.tx_bytes,
                stat.tx_errors,
            )

        for stat in sorted(body, key=attrgetter("port_no")):
            portNo = stat.port_no
            if portNo < 10000:
                port = ports.setdefault(portNo, Portstats(portNo))
                port.setFieds(stat, time.time())

        if self.superExist:
            pass
            # self._send_port_stats(dpid)

    def _send_port_stats(self, dpid):

        send_message = self._make_port_stats_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_port_stats_message(self, dpid):
        assert dpid in self.lastCollect
        switchCollect = self.lastCollect[dpid]
        portsMsg = switchCollect.getPortMessageByRx_bytes()
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = "portStats"
        to_send[DPID] = dpid
        to_send[PORTSTATS] = portsMsg
        send_message = json.dumps(to_send)

        # print send_message
        return send_message

    def sendTaskAssignReply(self, taskId, pathType):
        self.logger.info("send Task Assign Reply")
        send_message = self._make_task_assign_reply(taskId, pathType)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_assign_reply(self, taskId, pathType):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = "taskAssignReply"
        to_send[TASK_ID] = taskId
        to_send[PATHTYPE] = pathType

        send_message = json.dumps(to_send)
        return send_message

    def sendTaskDeleteReply(self, taskId):
        self.logger.info("send Task Delete Reply")
        send_message = self._make_task_delete_reply(taskId)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_delete_reply(self, taskId):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = "taskDeleteReply"
        to_send[TASK_ID] = taskId

        send_message = json.dumps(to_send)
        return send_message

    def _to_commad(self, send_message, returnType=False):

        command = "curl -X "
        if returnType:
            command += "GET -d '"
        else:
            command += "PUT -d '"
        command += send_message
        command += "' http://"
        command += self.superWsgiIp
        command += ":"
        command += str(self.superWsgiPort)
        command += super_url_no_reutrn
        command += " 2> /dev/null"
        return command

    # @staticmethod
    def send_no_return_command(self, command):
        print "command: ", command
        os.popen2(command)
        # print "to_print:", to_print

    @set_ev_cls(arpevent, dispatchers=None)
    def arp_handler(self, ev):

        ev_dict = self.object2dict(ev)

        self.borderPeer.extend(ev.dpid_table)
        self.borderPeer = list(set(self.borderPeer))
        self.reportPath()

        ev_dict[TYPE] = "ArpMessage"
        # print ev_dict
        send_msg = json.dumps(ev_dict)
        command = self._to_commad(send_msg)
        self.send_no_return_command(command)
        # print 12333333333333333333

    @set_ev_cls(mactoportEvent, dispatchers=None)
    def mac_to_port_handler(self, ev):
        ev_dict = self.object2dict(ev)
        ev_dict[TYPE] = "mactoportmessage"
        send_msg = json.dumps(ev_dict)
        command = self._to_commad(send_msg)
        self.send_no_return_command(command)

    def object2dict(self, obj):
        d = {}
        d["__class__"] = obj.__class__.__name__
        d["__module__"] = obj.__module__
        d.update(obj.__dict__)
        return d

    def reportPath(self):
        self.edgePort = list(set(self.borderPeer) | set(self.outDomainSwitch.keys()))
        tmpPathList = self.pathAnalysisByShortest(self.edgePort)
        self._send_path_report_msg(tmpPathList)
        print "self.edgePort:", self.edgePort
        print "tmpPathList:", tmpPathList
        # print 'tmpPathList: ',tmpPathList

    ###############################################

    def pathAnalysisByShortest(self, edgePort):
        pathList = []
        if edgePort is None:
            LOG.info("This Domain have no edgePort!")
            return None
        # if len(edgePort) == 0 or len(edgePort) == 1:
        #     return

        for i in edgePort:
            for m in edgePort:
                if i == m:
                    continue
                tmppath = self.topo.getShortestPath(i, m)
                pathList.append([i, m, len(tmppath) - 1])
                self.shortestPath[(i, m)] = tmppath

        self.logger.info("in_switch          out_switch        length    ")
        self.logger.info("----------------  ----------------  -------- ")

        for stat in pathList:
            if len(stat) > 2:
                print ("%016x %016x %8d" % (stat[0], stat[1], stat[2]))
        self.logger.info("pathList end")
        print "self.edgePort", self.edgePort
        print "self.borderPeer", self.borderPeer
        print "self.outDomainSwitch", self.outDomainSwitch
        print "self.topoe.dges:", self.topo.edges()
        print "self.topo.nodes:", self.topo.nodes()

        # print 'self.shortestPath: ', self.shortestPath
        return pathList

    def _send_path_report_msg(self, pathList):
        self.logger.info("send Path Report Msg")
        send_message = self._make_path_report_msg(pathList)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_path_report_msg(self, pathList):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = "pathReport"
        to_send[PATHLIST] = pathList
        send_message = json.dumps(to_send)
        return send_message
Ejemplo n.º 2
0
class DomainController(app_manager.RyuApp):

    _CONTEXTS = {'wsgi': WSGIApplication,
                 'switches': switches.Switches,
                 'arp': IcmpResponder}

    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION, ofproto_v1_3.OFP_VERSION]


    def __init__(self, *args, **kwargs):
        super(DomainController, self).__init__(*args, **kwargs)

        self.domainId = self.CONF.domain_id
        self.name = 'domain_controller'
        self.domainWsgiIp = self.CONF.domain_wsgi_ip
        self.domainWsgiPort = self.CONF.domain_port
        self.topo = DomainTopo(name='Domain '+str(self.domainId))
        self.dps = {}
        self.switches = []
        self.sleep = 10
        self.local_mac = ['10.108.93.100', '10.108.90.201']
        self.TASK_LIST = {}
        self.LabelsPool = MplsLabelsPool()
        self.LabelsPool.initPool()
        self.deviceInfo = {}
        self.num = 0
        self.taskId_match = {}
        self.border_table = []
        self.arp_table = {}
        self.port_to_localmac = {}
        self.timesOfQos = 0
        self.qosSwitch = []
        self.completeTopo = None
    ############################################
        self.edgePort = []
        self.borderPeer = []
        self.outDomainSwitch = {}
        self.shortestPath = {}
        # self.shortestPath = {(513,518):[513,515,518],(518,513):[518,515,513]}
    #####################################################

        self.QoS_dict = {}
        self.superExist = self.CONF.super_exist
        if self.superExist:
            self.superWsgiIp = self.CONF.super_wsgi_ip
            self.superWsgiPort = self.CONF.super_wsgi_port

        self.superLastEcho = time.time()

        self.monitorThreadFlag = self.CONF.monitor_thread_flag
        # if self.monitorThreadFlag:
        #     self.monitorThread = hub.spawn(self._monitor)
        self.lastCollect = {}

        self.keepAliveThread = hub.spawn(self._keepAlive)

        wsgi = kwargs['wsgi']
        data = {}
        data[DOMAINCONTROLLER] = self
        data[DomainReplyController] = DomainReplyController()
        wsgi.register(DomainWsgiController, data)

    def _get_QueueQos(self, dpid):
        assert dpid in self.QoS_dict
        return self.QoS_dict[dpid]

    def _get_datapath(self, dpid):
        assert dpid in self.dps
        return self.dps[dpid]

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        self.logger.debug('switch features ev %s', msg)

        dpid = datapath.id

        switch = self.deviceInfo.setdefault(dpid, SwitchFeatures(dpid))

        switch.initFieds(msg.version, msg.capabilities, msg.n_buffers, msg.n_tables, msg.auxiliary_id)

        if dpid not in self.QoS_dict:
            queueQoSInstance = QueueQos(datapath, self.CONF)
            self.QoS_dict[dpid] = queueQoSInstance
            ip = datapath.address[0]
            ovs_addr = 'tcp:' + ip + ':' + DEFAULTOVSDBADDR
            queueQoSInstance.set_ovsdb_addr(dpid, ovs_addr)
            self.logger.info("QueueQoS Entering. dpid: %016x, addr: %s" % (dpid, ovs_addr))

#msg:  {'body': [OFPPort(port_no=9,hw_addr='48:6e:73:02:03:08',
# name='ge-1/1/9',config=0,state=1,curr=10240

    @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, CONFIG_DISPATCHER)
    def multipart_reply_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        dpid = datapath.id
        switch = self.deviceInfo.setdefault(dpid, SwitchFeatures(dpid))

        # self.num = self.num+1
        # print self.num
        #ports = switch.getPorts()
        #print 'msg: ', msg.__dict__
        for portdesc in msg.body:
            #print 'portdesc: ', portdesc

            portNo = portdesc.port_no
            if portNo > 10000:
               # print 11111111111111111111111111
                name = portdesc.name
                switch.setName(name)
            else:
                port = PortFeatures(portNo)
                port.initFields(portdesc)
                #print 'port: ',port.__dict__
                switch.ports[portNo] = port
                self.QoS_dict[dpid].queueInfo[portNo] = QueuePort(portNo, dpid)


        if self.superExist:
            self._send_switch_features_message(dpid)

    def _send_switch_features_message(self, dpid):

        send_message = self._make_switch_features_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_switch_features_message(self, dpid):
        assert dpid in self.deviceInfo
        switchFeaturs = self.deviceInfo[dpid]
        info = switchFeaturs.makeFeaturesMessage()
        to_send = {}
        to_send[TYPE] = 'switchFeature'
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[SWITCHFEATURE] = info

        send_message = json.dumps(to_send)
        return send_message


    def remove_flow(self, datapath, match):

        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
                                    out_port=ofproto.OFPP_ANY, match=match)
        elif ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
                                    out_group=ofproto.OFPG_ANY,out_port=ofproto.OFPP_ANY,
                                    match=match)

        datapath.send_msg(mod)

    def _get_ofproto_info(self, dpid):
        if dpid in self.dps:
            dp = self.dps[dpid]
            parser = dp.ofproto_parser
            ofproto = dp.ofproto
            return dp, parser, ofproto

    def _get_flow_mod(self, dpid, match, actions, priority=None, instruction=None):

        dp, parser, ofproto = self._get_ofproto_info(dpid)

        if not priority:
            priority = ofproto.OFP_DEFAULT_PRIORITY

        if ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
            mod = parser.OFPFlowMod(datapath=dp, priority=priority, match=match, instructions=inst)
        else:
            raise ValueError('We only support OpenFlow 1.3 now')
        return mod

    def _send_flow(self, datapath, mod):
        datapath.send_msg(mod)

    def pushMplsFlow(self, dpid, pushLabel, srcIp, dstIp, outPortNo, queueId, pathType, src_mac,dst_mac,priority):
        assert dpid in self.dps

        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        #print 'srcIp,dstIp: ',srcIp,dstIp
        match = parser.OFPMatch(eth_type=eth_IP,ipv4_src=srcIp,ipv4_dst=dstIp)
        #match = parser.OFPMatch(eth_type=eth_IP,ipv4_src=('10.108.92.0','255.255.255.0'),
        #                        ipv4_dst=('10.108.93.0','255.255.255.0'))
        actions = []
        actions.append(parser.OFPActionSetField(eth_src=src_mac))
        actions.append(parser.OFPActionSetField(eth_dst=dst_mac))
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions, priority)
        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod

    def popMplsFlow(self, dpid, popLabel, outPort, queueId, priority):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions =[]
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))

        mod = self._get_flow_mod(dpid, match, actions, priority)

        self._send_flow(dp, mod)
        return match, mod

    def swapMplsFlow(self, dpid, pushLabel, popLabel, outPortNo, queueId, priority):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions, priority)

        self._send_flow(dp, mod)
        return match, mod

    def noMplsFlow(self, dpid, srcIp, dstIp, outPortNo, queueId, pathType, priority):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        #eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)

        actions = []

        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions, priority)

        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod


    def popMplsMacFlow(self, dpid, popLabel, outPortNo, local_mac, next_mac, queueId, priority):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions =[]
        #actions_inst = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        #local_mac = self.port_to_localmac[outPortNo]
        #print 'local_mac,next_mac: ',local_mac,next_mac
        #actions.append(parser.OFPActionSetField(eth_src=local_mac))  ##
        #actions.append(parser.OFPActionSetField(eth_dst=next_mac))

        actions.append(parser.OFPActionOutput(outPortNo))
        #inst = parser.OFPInstructionGotoTable(2)
        #actions_inst.append(inst)
        mod = self._get_flow_mod(dpid, match, actions, priority)
        #print 'mod: ', mod.__dict__
        self._send_flow(dp, mod)
        return match, mod  ####

    def noMplsMacFlow(self, dpid, srcIp, dstIp, outPortNo, local_mac, next_mac, queueId, pathType, priority):

        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        #eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)

        actions = []
        #actions_inst = []

        #local_mac = self.port_to_localmac[outPortNo]
        actions.append(parser.OFPActionSetField(eth_src=local_mac))  ##
        actions.append(parser.OFPActionSetField(eth_dst=next_mac))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))
        #inst = (parser.OFPInstructionGotoTable(2))
        mod = self._get_flow_mod(dpid, match, actions, priority)

        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod


    @set_ev_cls(event.EventSwitchEnter, [MAIN_DISPATCHER, CONFIG_DISPATCHER])
    def switchEnterHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id
        if dpid not in self.switches:
            self.switches.append(dpid)

        if dpid not in self.dps:
            self.dps[dpid] = dp

        assert len(self.switches) == len(self.dps)

        self.topo.addNode(dpid)
        self.logger.info("Switch %d enter in local topo", dpid)

        if self.superExist:
            self._send_switch_enter_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %d", dpid)

    def _send_switch_enter_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[TYPE] = 'switchEnter'
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)


    @set_ev_cls(event.EventSwitchLeave, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def switchLeaveHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id

        if dpid in self.switches:
            self.switches.remove(dpid)
        if dpid in self.dps:
            del self.dps[dpid]

        if dpid not in self.topo.nodes():
            self.logger.warning("Switch %d not in local topo", dpid)
        else:
            self.topo.removeNode(dpid)
            self.logger.info("Switch %d leave the local topo", dpid)

        if self.superExist:
            self._send_switch_leave_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %d", dpid)

    def _send_switch_leave_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'switchLeave'
        to_send[DPID] = dpid
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def changeToBackPath(self, dpid, nextdpid):
        # topo1 = copy.deepcopy(self.topo)
        # topo1.remove_edge(dpid, nextdpid)
        self.completeTopo = copy.deepcopy(self.topo)
        self.topo.topo.remove_edge(dpid, nextdpid)
        self.pathAnalysisByShortest(self.edgePort)


    @set_ev_cls(event.EventLinkAdd, [CONFIG_DISPATCHER, MAIN_DISPATCHER])
    def linkAddHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no
        #print 'src_switch: ',src_switch,type(src_switch)
        edge = (src_switch, dst_switch)

    ########################################################################
        if src_switch in self.dps:
            if edge not in self.topo.edges():
                self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
                self.logger.info("Link add: src %d port_no %8d-> dst %d %8d" % (src_switch, src_port,
                                                                                      dst_switch, dst_port))

        else:
            assert src_switch not in self.dps
            print "src_switch:",src_switch
            print "outdomian:",self.outDomainSwitch
            #self.outDomainSwitch[(dst_switch, dst_port)] = (src_switch, src_port)
            if src_switch not in self.outDomainSwitch.values():
                self.outDomainSwitch[dst_switch] = src_switch
                self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
                self.reportPath()
                dst_switch = str(dst_switch)

    #####################################################################################

        if self.superExist:
                self._send_link_add_msg(src_switch, src_port, dst_switch, dst_port)
                dst_switch = int(dst_switch)
                self.logger.info("TO Super controller.Link add: src %d port_no %8d-> dst %d %8d" %
                             (src_switch, src_port, dst_switch, dst_port))

    def _send_link_add_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkAdd'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkDelete, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def linkDelHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if edge in self.topo.edges():
            self.topo.removeEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("Link delete: src %d port_no %8d-> dst %d port_no %8d" % (src_switch, src_port,
                                                                                           dst_switch, dst_port))

        if self.superExist:
            self._send_link_delete_msg(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("TO Super controller.Link Delete: src %d port_no %8d-> dst %016x %8d" %
                             (src_switch, src_port, dst_switch, dst_port))

    def _send_link_delete_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkDelete'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _monitor(self):
        hub.sleep(5)
        while True:

            for k in self.dps.keys():
                # self._request_stats(dp)
                self._request_stats(self.dps[k])
            hub.sleep(self.sleep)

    def _request_stats(self, datapath):
        self.logger.info('send stats request: %d', datapath.id)
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        #req = parser.OFPFlowStatsRequest(datapath)
        #datapath.send_msg(req)
        req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
        datapath.send_msg(req)

    def _keepAlive(self):
        while True:
            if self.superExist:
                self._send_keep_alive_message()
                self.logger.info("send keep alive")
            hub.sleep(5)


    def _send_keep_alive_message(self):
        to_send = {}
        to_send[TYPE] = 'keepAlive'
        to_send[DOMAINID] = self.domainId
        to_send[DOMAINWSGIIP] =self.domainWsgiIp
        to_send[DOMAINWSGIPORT] = self.domainWsgiPort

        send_message = json.dumps(to_send)
        #print send_message
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body
        self.logger.info('datapath                '
                         'in_port   eth_dst       '
                         'out_port  packets  bytes')
        self.logger.info('---------------- '
                         '--------  -------- '
                         '--------  -------- -------- ')
        for stat in sorted([flow for flow in body if flow.priority == 1],
                           key=lambda flow: (flow.match['in_port'],
                                             flow.match['ipv4_dst'])):
            self.logger.info('%016x %8x %17s %8x %8d %8d',
                             ev.msg.datapath.id,
                             stat.match['in_port'], stat.match['ipv4_dst'],
                             stat.instructions[0].actions[0].port,
                             stat.packet_count, stat.byte_count)

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        msg = ev.msg
        body = msg.body
        dpid = msg.datapath.id
        switchCollect = self.lastCollect.setdefault(dpid, SwitchStats(dpid))
        ports = switchCollect.getPotrs()

        self.logger.info('datapath             port  '
                         'rx-pkts   rx-bytes   rx-error '
                         'tx-pkts tx-bytes  tx-error')
        self.logger.info('-----------         ------  '
                         '-------   --------   -----   '
                         '------  -------   --------')
        for stat in sorted(body, key=attrgetter('port_no')):
            if stat.port_no > 10000:
                continue
            self.logger.info('%016x %8d %8d %8d %8d %8d %8d %8d ',
                             ev.msg.datapath.id, stat.port_no,
                             stat.rx_packets, stat.rx_bytes, stat.rx_errors,
                             stat.tx_packets, stat.tx_bytes, stat.tx_errors)

        for stat in sorted(body, key=attrgetter('port_no')):
            portNo = stat.port_no
            if portNo < 10000:
                port = ports.setdefault(portNo, Portstats(portNo))
                port.setFieds(stat, time.time())

        if self.superExist:
            self._send_port_stats(dpid)

    def _send_port_stats(self, dpid):

        send_message = self._make_port_stats_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_port_stats_message(self, dpid):
        assert dpid in self.lastCollect
        switchCollect = self.lastCollect[dpid]
        portsMsg = switchCollect.getPortMessageByRx_bytes()
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'portStats'
        to_send[DPID] = dpid
        to_send[PORTSTATS] = portsMsg
        send_message = json.dumps(to_send)

        return send_message

    def sendPathChangeReply(self, src, dst):
        to_send = {}
        to_send['src'] = src
        to_send['dst'] = dst
        to_send['domainId'] = self.domainId
        to_send['type'] = 'pathChangeReply'
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def sendTaskAssignReply(self, taskId, pathType, src, dst):
        self.logger.info("send Task Assign Reply")
        send_message = self._make_task_assign_reply(taskId, pathType, src, dst)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_assign_reply(self, taskId, pathType, src, dst):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskAssignReply'
        to_send[TASK_ID] = taskId
        to_send[PATHTYPE] = pathType
        to_send['src'] = src
        to_send['dst'] = dst
        send_message = json.dumps(to_send)
        return send_message

    def sendTaskDeleteReply(self, taskId, src, dst):
        self.logger.info("send Task Delete Reply")
        send_message = self._make_task_delete_reply(taskId, src, dst)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_delete_reply(self, taskId, src, dst):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskDeleteReply'
        to_send[TASK_ID] = taskId
        to_send['src'] = src
        to_send['dst'] = dst

        send_message = json.dumps(to_send)
        return send_message

    def _to_commad(self, send_message, returnType=False):

        command = 'curl -X '
        if returnType:
            command += 'GET -d \''
        else:
            command += 'PUT -d \''
        command += send_message
        command += '\' http://'
        command += self.superWsgiIp
        command += ':'
        command += str(self.superWsgiPort)
        command += super_url_no_return
        command += ' 2> /dev/null'
        return command

    # @staticmethod
    def send_no_return_command(self, command):
        print 'command: ',command
        os.popen2(command)
        # print "to_print:", to_print


    @set_ev_cls(arpevent, dispatchers=None)
    def arp_handler(self, ev):

        ev_dict = self.object2dict(ev)

        self.borderPeer.extend(ev.dpid_table)
        self.borderPeer = list(set(self.borderPeer))
        self.reportPath()

        self.port_to_localmac = ev_dict['port_to_localmac']
        self.arp_table.update(ev_dict['ip_to_mac'])
        ev_dict[TYPE] = 'ArpMessage'
        #print ev_dict
        send_msg = json.dumps(ev_dict)
        command = self._to_commad(send_msg)
        self.send_no_return_command(command)
        #print 12333333333333333333

    @set_ev_cls(mactoportEvent, dispatchers=None)
    def mac_to_port_handler(self,ev):
        ev_dict = self.object2dict(ev)
        ev_dict[TYPE] = 'mactoportmessage'
        send_msg = json.dumps(ev_dict)
        command = self._to_commad(send_msg)
        self.send_no_return_command(command)



    def object2dict(self,obj):
        d={}
        d['__class__'] = obj.__class__.__name__
        d['__module__'] = obj.__module__
        d.update(obj.__dict__)
        return d


    def reportPath(self):
        self.edgePort = list(set(self.borderPeer) | set(self.outDomainSwitch.keys()))
        tmpPathList = self.pathAnalysisByShortest(self.edgePort)
        self._send_path_report_msg(tmpPathList)
        #print "self.edgePort:" , self.edgePort
        #print "tmpPathList:" , tmpPathList
        #print 'tmpPathList: ',tmpPathList
    ###############################################


    def pathAnalysisByShortest(self, edgePort):
        pathList=[]
        if edgePort is None:
            LOG.info("This Domain have no edgePort!")
            return None
        # if len(edgePort) == 0 or len(edgePort) == 1:
        #     return
        print edgePort
        for i in edgePort:
            for m in edgePort:
                if i == m:
                    continue
                tmppath = self.topo.getShortestPath(i, m)
                pathList.append([i, m, len(tmppath)-1])
                self.shortestPath[(i, m)] = tmppath

        self.logger.info('in_switch          out_switch        length    ')
        self.logger.info('----------------  ----------------  -------- ')

        for stat in pathList:
            if len(stat) > 2:
                pass
                #print ('%016x %016x %8d'%(stat[0], stat[1], stat[2]))
        self.logger.info("pathList end")
        # print "self.edgePort", self.edgePort
        # print "self.borderPeer", self.borderPeer
        # print "self.outDomainSwitch",self.outDomainSwitch
        # print "self.topoe.dges:",self.topo.edges()
        # print "self.topo.nodes:",self.topo.nodes()
        
        #print 'self.shortestPath: ', self.shortestPath
        return pathList

    def _send_path_report_msg(self, pathList):
        #self.logger.info("send Path Report Msg")
        send_message = self._make_path_report_msg(pathList)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_path_report_msg(self, pathList):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'pathReport'
        to_send[PATHLIST] = pathList
        send_message = json.dumps(to_send)
        return send_message
Ejemplo n.º 3
0
class DomainController(app_manager.RyuApp):

    _CONTEXTS = {
        'wsgi': WSGIApplication,
        'switches': switches.Switches,
        'simple_switch_13': SimpleSwitch13
    }

    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION, ofproto_v1_3.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        super(DomainController, self).__init__(*args, **kwargs)

        self.domainId = self.CONF.domain_id
        self.name = 'domain_controller'
        self.domainWsgiIp = self.CONF.domain_wsgi_ip
        self.domainWsgiPort = self.CONF.domain_port
        self.topo = DomainTopo(name='Domain ' + str(self.domainId))
        self.dps = {}
        self.switches = []
        self.sleep = 2

        self.TASK_LIST = {}
        self.LabelsPool = MplsLabelsPool()
        self.LabelsPool.initPool()
        self.deviceInfo = {}
        self.edgePort = []
        self.borderPeer = []
        self.outDomainSwitch = {}
        self.shortestPath = {}
        #self.shortestPath = {(773,769):[773,770,769],(769,773):[769,770,773]}

        self.QoS_dict = {}
        self.superExist = self.CONF.super_exist
        if self.superExist:
            self.superWsgiIp = self.CONF.super_wsgi_ip
            self.superWsgiPort = self.CONF.super_wsgi_port

        self.superLastEcho = time.time()

        self.monitorThreadFlag = self.CONF.monitor_thread_flag
        if self.monitorThreadFlag:
            self.monitorThread = hub.spawn(self._monitor)
            self.lastCollect = {}

        self.keepAliveThread = hub.spawn(self._keepAlive)

        wsgi = kwargs['wsgi']
        data = {}
        data[DOMAINCONTROLLER] = self
        data[DomainReplyController] = DomainReplyController()
        wsgi.register(DomainWsgiController, data)

    def _get_QueueQos(self, dpid):
        assert dpid in self.QoS_dict
        return self.QoS_dict[dpid]

    def _get_datapath(self, dpid):
        assert dpid in self.dps
        return self.dps[dpid]

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        self.logger.debug('switch features ev %s', msg)

        dpid = datapath.id

        switch = self.deviceInfo.setdefault(dpid, SwtichFeatures(dpid))

        switch.initFieds(msg.version, msg.capabilities, msg.n_buffers,
                         msg.n_tables, msg.auxiliary_id)

        if dpid not in self.QoS_dict:
            queueQoSInstance = QueueQos(datapath, self.CONF)
            self.QoS_dict[dpid] = queueQoSInstance
            ip = datapath.address[0]
            ovs_addr = 'tcp:' + ip + ':' + DEFAULTOVSDBADDR
            queueQoSInstance.set_ovsdb_addr(dpid, ovs_addr)
            self.logger.info("QueueQoS Entering. dpid: %016x, addr: %s" %
                             (dpid, ovs_addr))

    @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, CONFIG_DISPATCHER)
    def multipart_reply_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        dpid = datapath.id
        switch = self.deviceInfo.setdefault(dpid, SwtichFeatures(dpid))

        #ports = switch.getPorts()

        for portdesc in msg.body:
            #print 'portdesc: ',portdesc
            portNo = portdesc.port_no
            if portNo > 10000:
                name = portdesc.name
                switch.setName(name)
            else:
                port = PortFeatures(portNo)
                port.initFields(portdesc)
                switch.ports[portNo] = port
                self.QoS_dict[dpid].queueInfo[portNo] = QueuePort(portNo, dpid)

        if self.superExist:
            self._send_switch_features_message(dpid)

    def _send_switch_features_message(self, dpid):

        send_message = self._make_switch_features_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_switch_features_message(self, dpid):
        assert dpid in self.deviceInfo
        switchFeaturs = self.deviceInfo[dpid]
        info = switchFeaturs.makeFeaturesMessage()
        to_send = {}
        to_send[TYPE] = 'switchFeature'
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[SWITCHFEATURE] = info

        send_message = json.dumps(to_send)
        return send_message

    def remove_flow(self, datapath, match):

        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath,
                                    command=ofproto.OFPFC_DELETE,
                                    out_port=ofproto.OFPP_ANY,
                                    match=match)
        elif ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath,
                                    command=ofproto.OFPFC_DELETE,
                                    out_group=ofproto.OFPG_ANY,
                                    out_port=ofproto.OFPP_ANY,
                                    match=match)

        datapath.send_msg(mod)

    def _get_ofproto_info(self, dpid):
        assert dpid in self.dps
        dp = self.dps[dpid]
        parser = dp.ofproto_parser
        ofproto = dp.ofproto
        return dp, parser, ofproto

    def _get_flow_mod(self,
                      dpid,
                      match,
                      actions,
                      priority=None,
                      buffer_id=None):

        dp, parser, ofproto = self._get_ofproto_info(dpid)

        if not priority:
            priority = ofproto.OFP_DEFAULT_PRIORITY

        if ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            inst = [
                parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)
            ]
            mod = parser.OFPFlowMod(datapath=dp,
                                    priority=priority,
                                    match=match,
                                    instructions=inst)
        else:
            raise ValueError('We only support OpenFlow 1.3 now')
        return mod

    def _send_flow(self, datapath, mod):
        datapath.send_msg(mod)

    def pushMplsFlow(self, dpid, pushLabel, srcMac, dstMac, outPortNo, queueId,
                     pathType):
        assert dpid in self.dps

        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_IP,
                                eth_src=srcMac,
                                eth_dst=dstMac)

        actions = []
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions)
        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info(
                "Backup path's First switch should not install flow now!")

        return match, mod

    def popMplsFlow(self, dpid, popLabel, outPortNo, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod

    def swapMplsFlow(self, dpid, pushLabel, popLabel, outPort, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod

    # def popMplsMacFlow(self, dpid, popLabel, outPort, queueId,local_mac,next_mac):
    #     dp, parser, ofproto = self._get_ofproto_info(dpid)
    #     eth_IP = ether.ETH_TYPE_IP
    #     eth_MPLS = ether.ETH_TYPE_MPLS
    #     match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)
    #
    #     actions =[]
    #     actions.append(parser.OFPActionPopMpls(eth_IP))
    #     actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
    #     actions.append(parser.OFPActionOutput(outPort))
    #     actions.append(parser.OFPActionSetField(eth_src=local_mac, eth_dst=next_mac))  ##
    #
    #     mod = self._get_flow_mod(dpid, match, actions)
    #
    #     self._send_flow(dp, mod)
    #     return match, mod  ####

    def noMplsFlow(self, dpid, srcMac, dstMac, outPortNo, queueId, pathType):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        #eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_IP,
                                eth_src=srcMac,
                                eth_dst=dstMac)

        actions = []
        actions.append(parser.OFPActionOutput(outPortNo))
        actions.append(parser.OFPActionSetQueue(queueId))

        mod = self._get_flow_mod(dpid, match, actions)

        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info(
                "Backup path's First switch should not install flow now!")

        return match, mod

    # def noMplsMacFlow(self, dpid, srcMac, dstMac, outPortNo,queueId, pathType):
    #     dp, parser, ofproto = self._get_ofproto_info(dpid)
    #     eth_IP = ether.ETH_TYPE_IP
    #     #eth_MPLS = ether.ETH_TYPE_MPLS
    #     match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcMac, ipv4_dst=dstMac)
    #
    #     actions = []
    #     actions.append(parser.OFPActionOutput(outPortNo))
    #     actions.append(parser.OFPActionSetQueue(queueId))
    #
    #     mod = self._get_flow_mod(dpid, match, actions)
    #
    #     if pathType == 'main':
    #         self._send_flow(dp, mod)
    #     elif pathType == 'backup':
    #         self.logger.info("Backup path's First switch should not install flow now!")
    #
    #     return match, mod

    def reportPath(self):
        self.edgePort = list(
            set(self.borderPeer) | set(self.outDomainSwitch.keys()))
        tempPathList = self.BoardShortestPath(self.edgePort)
        print 'self.edgePort: ', self.edgePort

        self._send_path_report_msg(tempPathList)

    def BoardShortestPath(self, edgeSwitch):
        pathList = []
        if edgeSwitch is None:
            LOG.info("This Domain have no edgePort!")
            return None
        # if len(edgeSwitch) == 1 or len(edgeSwitch) == 0:
        #     return

        for i in edgeSwitch:
            for m in edgeSwitch:
                if i == m:
                    continue
                temppath = self.topo.getShortestPath(i, m)
                #print 'temppath: ',temppath
                pathList.append([i, m, len(temppath) - 1])
                self.shortestPath[(i, m)] = temppath

        self.logger.info('in_switch          out_switch        length    ')
        self.logger.info('----------------  ----------------  -------- ')
        # for stat in pathList:
        #     self.logger.info('%016x %016x %8d' % stat[0], stat[1], stat[2])

        return pathList

    #Send pathList which created by the function named athAnalysisByShortest to SuperController
    def _send_path_report_msg(self, pathList):
        self.logger.info("send Path Report Msg")
        send_message = self._make_path_report_msg(pathList)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    # Implement the message for SuperController path
    # At last, if SuperController exists,this function transmit the pathlist to SuperController.

    def _make_path_report_msg(self, pathList):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'pathReport'
        to_send[PATHLIST] = pathList
        send_message = json.dumps(to_send)
        return send_message

    @set_ev_cls(event.EventSwitchEnter, [MAIN_DISPATCHER, CONFIG_DISPATCHER])
    def switchEnterHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id
        if dpid not in self.switches:
            self.switches.append(dpid)

        if dpid not in self.dps:
            self.dps[dpid] = dp

        assert len(self.switches) == len(self.dps)

        self.topo.addNode(dpid)
        self.logger.info("Switch %016x enter in local topo", dpid)

        if self.superExist:
            self._send_switch_enter_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %016x",
                             dpid)

    def _send_switch_enter_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[TYPE] = 'switchEnter'
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventSwitchLeave, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def switchLeaveHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id

        if dpid in self.switches:
            self.switches.remove(dpid)
        if dpid in self.dps:
            del self.dps[dpid]

        if dpid not in self.topo.nodes():
            self.logger.warning("Switch %016x not in local topo", dpid)
        else:
            self.topo.removeNode(dpid)
            self.logger.info("Switch %016x leave the local topo", dpid)

        if self.superExist:
            self._send_switch_leave_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %016x",
                             dpid)

    def _send_switch_leave_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'switchLeave'
        to_send[DPID] = dpid
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkAdd, [CONFIG_DISPATCHER, MAIN_DISPATCHER])
    def linkAddHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if src_switch in self.dps:
            if edge not in self.topo.edges():
                self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
                self.logger.info(
                    "Link add: src %016x port_no %8d-> dst %016x %8d" %
                    (src_switch, src_port, dst_switch, dst_port))
        else:
            assert src_switch not in self.dps
            #self.outDomainSwitch[(dst_switch,dst_port)] = (src_switch, src_port)
            self.outDomainSwitch[dst_switch] = src_switch
            self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info(
                "Link add: src %016x port_no %8d-> dst %016x %8d" %
                (src_switch, src_port, dst_switch, dst_port))
            self.reportPath()
            dst_switch = str(dst_switch)
        if self.superExist:
            self._send_link_add_msg(src_switch, src_port, dst_switch, dst_port)
            dst_switch = int(dst_switch)
            self.logger.info(
                "TO Super controller.Link add: src %016x port_no %8d-> dst %016x %8d"
                % (src_switch, src_port, dst_switch, dst_port))

    def _send_link_add_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkAdd'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        print send_message
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkDelete, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def linkDelHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if edge in self.topo.edges():
            self.topo.removeEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info(
                "Link delete: src %016x port_no %8d-> dst %016x port_no %8d" %
                (src_switch, src_port, dst_switch, dst_port))

        if self.superExist:
            self._send_link_delete_msg(src_switch, src_port, dst_switch,
                                       dst_port)
            self.logger.info(
                "TO Super controller.Link Delete: src %016x port_no %8d-> dst %016x %8d"
                % (src_switch, src_port, dst_switch, dst_port))

    def _send_link_delete_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkDelete'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _monitor(self):
        hub.sleep(5)
        while True:

            for k in self.dps.keys():
                # self._request_stats(dp)
                self._request_stats(self.dps[k])
            hub.sleep(self.sleep)

    def _request_stats(self, datapath):
        # self.logger.info('send stats request: %016x', datapath.id)
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        # req = parser.OFPFlowStatsRequest(datapath)
        # datapath.send_msg(req)
        req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
        datapath.send_msg(req)

    def _keepAlive(self):
        while True:
            if self.superExist:
                self._send_keep_alive_message()
                self.logger.info("send keep alive")
            hub.sleep(5)

    def _send_keep_alive_message(self):
        to_send = {}
        to_send[TYPE] = 'keepAlive'
        to_send[DOMAINID] = self.domainId
        to_send[DOMAINWSGIIP] = self.domainWsgiIp
        to_send[DOMAINWSGIPORT] = self.domainWsgiPort

        send_message = json.dumps(to_send)
        print send_message
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body
        self.logger.info(
            'datapath         in_port  eth_dst  out_port packets  bytes    ')
        self.logger.info(
            '---------------- -------- -------- -------- -------- -------- ')
        for stat in sorted([flow for flow in body if flow.priority == 1],
                           key=lambda flow:
                           (flow.match['in_port'], flow.match['eth_dst'])):
            self.logger.info('%016x %8x %17s %8x %8d %8d', ev.msg.datapath.id,
                             stat.match['in_port'], stat.match['eth_dst'],
                             stat.instructions[0].actions[0].port,
                             stat.packet_count, stat.byte_count)

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        msg = ev.msg
        body = msg.body
        dpid = msg.datapath.id
        switchCollect = self.lastCollect.setdefault(dpid, SwitchStats(dpid))
        ports = switchCollect.getPorts()

        for stat in sorted(body, key=attrgetter('port_no')):
            portNo = stat.port_no
            if portNo < 10000:
                port = ports.setdefault(portNo, Portstats(portNo))
                port.setFieds(stat, time.time())

        if self.superExist:
            pass
            # self._send_port_stats(dpid)

    def _send_port_stats(self, dpid):

        send_message = self._make_port_stats_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_port_stats_message(self, dpid):
        assert dpid in self.lastCollect
        switchCollect = self.lastCollect[dpid]
        portsMsg = switchCollect.getPortMessageByRx_bytes()
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'portStats'
        to_send[DPID] = dpid
        to_send[PORTSTATS] = portsMsg
        send_message = json.dumps(to_send)

        # print send_message
        return send_message

    def sendTaskAssignReply(self, taskId, pathType):
        self.logger.info("send Task Assign Reply")
        send_message = self._make_task_assign_reply(taskId, pathType)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_assign_reply(self, taskId, pathType):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskAssignReply'
        to_send[TASK_ID] = taskId
        to_send[PATHTYPE] = pathType

        send_message = json.dumps(to_send)
        return send_message

    def sendTaskDeleteReply(self, taskId):
        self.logger.info("send Task Delete Reply")
        send_message = self._make_task_delete_reply(taskId)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_delete_reply(self, taskId):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskDeleteReply'
        to_send[TASK_ID] = taskId

        send_message = json.dumps(to_send)
        return send_message

    def _to_commad(self, send_message, returnType=False):

        command = 'curl -X '
        if returnType:
            command += 'GET -d \''
        else:
            command += 'PUT -d \''
        command += send_message
        command += '\' http://'
        command += self.superWsgiIp
        command += ':'
        command += str(self.superWsgiPort)
        command += super_url_no_reutrn
        command += ' 2> /dev/null'

        return command

    # @staticmethod
    def send_no_return_command(self, command):
        print 'command: ', command
        os.popen2(command)
        # try:
        #     os.popen2(command)
        # except:
        #     self.logger.debug('command exceute fail.Fail Command: %s' % command)
        #     return
        # print "to_print:", to_print

    ##

    # @set_ev_cls(arpevent, MAIN_DISPATCHER)
    # def arp_handler(self, ev):
    #     ev_dict = self.object2dict(ev)
    #     send_msg = json.dumps(ev_dict)
    #     send_msg['TYPE'] = 'ArpMessage'
    #     command = self._to_commad(send_msg)
    #     self.send_no_return_command(command)

    @set_ev_cls(mactoportEvent, dispatchers=None)
    def mac_to_port_handler(self, ev):
        ev_dict = self.object2dict(ev)

        for dpid in ev_dict['mac_to_port'].keys():
            self.borderPeer.append(dpid)
        self.borderPeer = list(set(self.borderPeer))
        self.reportPath()
        ev_dict[TYPE] = 'mactoportmessage'
        send_msg = json.dumps(ev_dict)
        command = self._to_commad(send_msg)
        self.send_no_return_command(command)

    def object2dict(self, obj):
        d = {}
        d['__class__'] = obj.__class__.__name__
        d['__module__'] = obj.__module__
        d.update(obj.__dict__)
        return d
Ejemplo n.º 4
0
class DomainController(app_manager.RyuApp):

    _CONTEXTS = {'wsgi': WSGIApplication,
                 'switches': switches.Switches}

    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION, ofproto_v1_3.OFP_VERSION]


    def __init__(self, *args, **kwargs):
        super(DomainController, self).__init__(*args, **kwargs)

        self.domainId = self.CONF.domain_id

        self.domainWsgiIp = self.CONF.domain_wsgi_ip
        self.domainWsgiPort = self.CONF.wsapi_port
        self.topo = DomainTopo(name='Domain '+str(self.domainId))
        self.dps = {}
        self.switches = []
        self.sleep = 2

        self.TASK_LIST = {}

        self.deviceInfo = {}

        self.QoS_dict = {}
        self.superExist = self.CONF.super_exist
        if self.superExist:
            self.superWsgiIp = self.CONF.super_wsgi_ip
            self.superWsgiPort = self.CONF.super_wsgi_port

        self.superLastEcho = time.time()

        self.monitorThreadFlag = self.CONF.monitor_thread_flag
        if self.monitorThreadFlag:
            self.monitorThread = hub.spawn(self._monitor)
            self.lastCollect = {}

        self.keepAliveThread = hub.spawn(self._keepAlive)

        wsgi = kwargs['wsgi']
        data = {}
        data[DOMAINCONTROLLER] = self
        data[DomainReplyController] = DomainReplyController()
        wsgi.register(DomainWsgiController, data)

    def _get_QueueQos(self, dpid):
        assert dpid in self.QoS_dict
        return self.QoS_dict[dpid]

    def _get_datapath(self, dpid):
        assert dpid in self.dps
        return self.dps[dpid]

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        self.logger.debug('switch features ev %s', msg)

        dpid = datapath.id

        switch = self.deviceInfo.setdefault(dpid, SwtichFeatures(dpid))

        switch.initFieds(msg.version, msg.capabilities, msg.n_buffers, msg.n_tables, msg.auxiliary_id)

        if dpid not in self.QoS_dict:
            queueQoSInstance = QueueQos(datapath, self.CONF)
            self.QoS_dict[dpid] = queueQoSInstance
            ip = datapath.address[0]
            ovs_addr = 'tcp:' + ip + ':' + DEFAULTOVSDBADDR
            queueQoSInstance.set_ovsdb_addr(dpid, ovs_addr)
            self.logger.info("QueueQoS Entering. dpid: %0x16, addr: %s" % (dpid, ovs_addr))



    @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, CONFIG_DISPATCHER)
    def multipart_reply_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        dpid = datapath.id
        switch = self.deviceInfo.setdefault(dpid, SwtichFeatures(dpid))

        ports = switch.getPorts()

        for portdesc in msg.body:
            portNo = portdesc.port_no
            if portNo > 10000:
                name = portdesc.name
                switch.setName(name)
            port = PortFeatures(portNo)
            port.initFields(portdesc)
            ports[portNo] = port

        if self.superExist:
            self._send_switch_features_message(dpid)

    def _send_switch_features_message(self, dpid):

        send_message = self._make_switch_features_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_switch_features_message(self, dpid):
        assert dpid in self.deviceInfo
        switchFeaturs = self.deviceInfo[dpid]
        info = switchFeaturs.makeFeaturesMessage()
        to_send = {}
        to_send[TYPE] = 'switchFeature'
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[SWITCHFEATURE] = info

        send_message = json.dumps(to_send)
        return send_message


    def remove_flow(self, datapath, match):

        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
                                    out_port=ofproto.OFPP_ANY, match=match)
        elif ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
                                    out_group=ofproto.OFPG_ANY,out_port=ofproto.OFPP_ANY,
                                    match=match)

        datapath.send_msg(mod)

    def _get_ofproto_info(self, dpid):
        assert dpid in self.dps
        dp = self.dps[dpid]
        parser = dp.ofproto_parser
        ofproto = dp.ofproto
        return dp, parser, ofproto

    def _get_flow_mod(self, dpid, match, actions, priority=None, buffer_id=None):

        dp, parser, ofproto = self._get_ofproto_info(dpid)

        if not priority:
            priority = ofproto.OFP_DEFAULT_PRIORITY

        if ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
            mod = parser.OFPFlowMod(datapath=dp, priority=priority, match=match, instructions=inst)
        else:
            raise ValueError('We only support OpenFlow 1.3 now')
        return mod

    def _send_flow(self, datapath, mod):
        datapath.send_msg(mod)

    def pushMplsFlow(self, dpid, pushLabel, srcIp, dstIp, outPort, queueId, pathType):
        assert dpid in self.dps

        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS

        #match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp,nw_src_mask=24, nw_dst_mask=24)

        actions = []
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))

        mod = self._get_flow_mod(dpid, match, actions)
        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod

    def popMplsFlow(self, dpid, popLabel, outPort, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS,mpls_label=popLabel)

        actions =[]
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod

    def swapMplsFlow(self, dpid, pushLabel, popLabel, outPort, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod

    def noMplsFlow(self, dpid, srcIp, dstIp, outPort, queueId, pathType):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        #match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp,nw_src_mask=24, nw_dst_mask=24)
        actions = []
        actions.append(parser.OFPActionOutput(outPort))
        actions.append(parser.OFPActionSetQueue(queueId))

        mod = self._get_flow_mod(dpid, match, actions)

        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod


    def popMplsMacFlow(self, dpid, popLabel, outPort, next_mac, local_mac, queueId):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions =[]
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))
        actions.append(parser.OFPActionSetField(eth_src=local_mac, eth_dst=next_mac))  ##

        mod = self._get_flow_mod(dpid, match, actions)

        self._send_flow(dp, mod)
        return match, mod  ####

    def noMplsMacFlow(self, dpid, srcIp, dstIp, outPort, next_mac, local_mac, queueId, pathType):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS

        #match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp)
        match = parser.OFPMatch(eth_type=eth_IP, ipv4_src=srcIp, ipv4_dst=dstIp,nw_src_mask=24, nw_dst_mask=24)

        actions = []
        actions.append(parser.OFPActionOutput(outPort))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionSetField(eth_src=local_mac, eth_dst=next_mac))  ##


        mod = self._get_flow_mod(dpid, match, actions)

        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod


    @set_ev_cls(event.EventSwitchEnter, [MAIN_DISPATCHER, CONFIG_DISPATCHER])
    def switchEnterHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id
        if dpid not in self.switches:
            self.switches.append(dpid)

        if dpid not in self.dps:
            self.dps[dpid] = dp

        assert len(self.switches) == len(self.dps)

        self.topo.addNode(dpid)
        self.logger.info("Switch %d enter in local topo", dpid)

        if self.superExist:
            self._send_switch_enter_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %d", dpid)


    def _send_switch_enter_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[TYPE] = 'switchEnter'
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)


    @set_ev_cls(event.EventSwitchLeave, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def switchLeaveHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id

        if dpid in self.switches:
            self.switches.remove(dpid)
        if dpid in self.dps:
            del self.dps[dpid]

        if dpid not in self.topo.nodes():
            self.logger.warning("Swtich %d not in local topo", dpid)
        else:
            self.topo.removeNode(dpid)
            self.logger.info("Swtich %d leave the local topo", dpid)

        if self.superExist:
            self._send_switch_leave_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %d", dpid)

    def _send_switch_leave_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'switchLeave'
        to_send[DPID] = dpid
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkAdd, [CONFIG_DISPATCHER, MAIN_DISPATCHER])
    def linkAddHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if edge not in self.topo.edges():
            self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("Link add: src %d port_no %8x-> dst %d %8x" % (src_switch, src_port,
                                                                                dst_switch, dst_port))

        if self.superExist:
            self._send_link_add_msg(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("TO Super controller.Link add: src %d port_no %8d-> dst %d %8d" %
                             (src_switch, src_port, dst_switch, dst_port))

    def _send_link_add_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkAdd'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkDelete, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def linkDelHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if edge in self.topo.edges():
            self.topo.removeEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("Link delete: src %d port_no %8d-> dst %d port_no %8d" % (src_switch, src_port,
                                                                                           dst_switch, dst_port))

        if self.superExist:
            self._send_link_delete_msg(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("TO Super controller.Link Delete: src %d port_no %8d-> dst %d %8d" %
                             (src_switch, src_port, dst_switch, dst_port))

    def _send_link_delete_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkDelete'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _monitor(self):
        hub.sleep(5)
        while True:

            for k in self.dps.keys():
                # self._request_stats(dp)
                self._request_stats(self.dps[k])
            hub.sleep(self.sleep)

    def _request_stats(self, datapath):
        # self.logger.info('send stats request: %016x', datapath.id)
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        # req = parser.OFPFlowStatsRequest(datapath)
        # datapath.send_msg(req)
        req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
        datapath.send_msg(req)

    def _keepAlive(self):
        while True:
            if self.superExist:
                self._send_keep_alive_message()
                self.logger.info("send keep alive")
            hub.sleep(5)


    def _send_keep_alive_message(self):
        to_send = {}
        to_send[TYPE] = 'keepAlive'
        to_send[DOMAINID] = self.domainId
        to_send[DOMAINWSGIIP] =self.domainWsgiIp
        to_send[DOMAINWSGIPORT] = self.domainWsgiPort

        send_message = json.dumps(to_send)
        # print send_message
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body
        self.logger.info('datapath         in_port  eth_dst  out_port packets  bytes    ')
        self.logger.info('---------------- -------- -------- -------- -------- -------- ')
        for stat in sorted([flow for flow in body if flow.priority == 1],
                           key=lambda flow: (flow.match['in_port'],
                                             flow.match['eth_dst'])):
            self.logger.info('%016x %8x %17s %8x %8d %8d',
                             ev.msg.datapath.id, stat.match['in_port'],
                             stat.match['eth_dst'], stat.instructions[0].actions[0].port,
                             stat.packet_count, stat.byte_count)

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        msg = ev.msg
        body = msg.body
        dpid = msg.datapath.id
        switchCollect = self.lastCollect.setdefault(dpid, SwitchStats(dpid))
        ports = switchCollect.getPotrs()

        for stat in sorted(body, key=attrgetter('port_no')):
            portNo = stat.port_no
            if portNo < 10000:
                port = ports.setdefault(portNo, Portstats(portNo))
                port.setFieds(stat, time.time())

        if self.superExist:
            pass
            # self._send_port_stats(dpid)

    def _send_port_stats(self, dpid):

        send_message = self._make_port_stats_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)



    def _make_port_stats_message(self, dpid):
        assert dpid in self.lastCollect
        switchCollect = self.lastCollect[dpid]
        portsMsg = switchCollect.getPortMessageByRx_bytes()
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'portStats'
        to_send[DPID] = dpid
        to_send[PORTSTATS] = portsMsg
        send_message = json.dumps(to_send)

        # print send_message
        return send_message


    def sendTaskAssignReply(self, taskId, pathType):
        self.logger.info("send Task Assign Reply")
        send_message = self._make_task_assign_reply(taskId, pathType)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_assign_reply(self, taskId, pathType):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskAssignReply'
        to_send[TASK_ID] = taskId
        to_send[PATHTYPE] = pathType

        send_message = json.dumps(to_send)
        return send_message

    def sendTaskDeleteReply(self, taskId):
        self.logger.info("send Task Delete Reply")
        send_message = self._make_task_delete_reply(taskId)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_delete_reply(self, taskId):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskDeleteReply'
        to_send[TASK_ID] = taskId

        send_message = json.dumps(to_send)
        return send_message

    def _to_commad(self, send_message, returnType=False):

        command = 'curl -X '
        if returnType:
            command += 'GET -d \''
        else:
            command += 'PUT -d \''
        command += send_message
        command += '\' http://'
        command += self.superWsgiIp
        command += ':'
        command += str(self.superWsgiPort)
        command += super_url_no_reutrn
        command += ' 2> /dev/null'


        return command

    # @staticmethod
    def send_no_return_command(self, command):
        # print command
        os.popen2(command)
        # print "to_print:", to_print

    from ryu.app.arp import arpevent
    @set_ev_cls(arpevent, MAIN_DISPATCHER)
    def arp_handler(self, ev):
        ev_dict = self.object2dict(ev)
        send_msg = json.dumps(ev_dict)
        send_msg['TYPE'] = 'ArpMessage'
        command = self._to_commad(send_msg)
        self.send_no_return_command(command)

    def object2dict(self,obj):
        d={}
        d['__class__'] = obj.__class__.__name__
        d['__module__'] = obj.__module__
        d.update(obj.__dict__)
        return d
Ejemplo n.º 5
0
class DomainController(app_manager.RyuApp):

    _CONTEXTS = {'wsgi': WSGIApplication,
                 'switches': switches.Switches}

    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION, ofproto_v1_3.OFP_VERSION]


    def __init__(self, *args, **kwargs):
        super(DomainController, self).__init__(*args, **kwargs)
        self.domainId = self.CONF.domain_id
        self.name = 'domain_controller'
        self.domainWsgiIp = self.CONF.domain_wsgi_ip
        self.domainWsgiPort = self.CONF.domain_port
        self.topo = DomainTopo(name='Domain '+str(self.domainId))
        self.dps = {}
        self.switches = []
        self.sleep = 2

        self.TASK_LIST = {}
        self.LabelsPool = MplsLabelsPool()
        self.LabelsPool.initPool()
        self.deviceInfo = {}
        self.edgePort = []
        self.borderPeer = []
        self.timeOfQos = 0
        self.qosSwitch = []
        self.outDomainSwitch = {}
        self.shortestPath = {}
        self.taskId_match = {}
        self.QoS_dict = {}
        self.completeTopo = None
        self.superExist = self.CONF.super_exist
        if self.superExist:
            self.superWsgiIp = self.CONF.super_wsgi_ip
            self.superWsgiPort = self.CONF.super_wsgi_port

        self.superLastEcho = time.time()

        self.monitorThreadFlag = self.CONF.monitor_thread_flag
        if self.monitorThreadFlag:
            #self.monitorThread = hub.spawn(self._monitor)
            self.lastCollect = {}

        self.keepAliveThread = hub.spawn(self._keepAlive)

        wsgi = kwargs['wsgi']
        data = {}
        data[DOMAINCONTROLLER] = self
        data[DomainReplyController] = DomainReplyController()
        wsgi.register(DomainWsgiController, data)

    def _keepAlive(self):
        while True:
            if self.superExist:
                self._send_keep_alive_message()
                self.logger.info("send keep alive")
            hub.sleep(5)

    def _send_keep_alive_message(self):
        to_send = {}
        to_send[TYPE] = 'keepAlive'
        to_send[DOMAINID] = self.domainId
        to_send[DOMAINWSGIIP] =self.domainWsgiIp
        to_send[DOMAINWSGIPORT] = self.domainWsgiPort

        send_message = json.dumps(to_send)
        print send_message
        command = self._to_commad(send_message)
        self.send_no_return_command(command)


    def _monitor(self):
        hub.sleep(5)
        while True:
            for k in self.dps.keys():
                self._request_stats(self.dps[k])
            hub.sleep(self.sleep)

    def _request_stats(self, datapath):
        self.logger.info('send stats request: %016x', datapath.id)
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
        datapath.send_msg(req)

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body
        self.logger.info('datapath         in_port  eth_dst  out_port packets  bytes    ')
        self.logger.info('---------------- -------- -------- -------- -------- -------- ')
        for stat in sorted([flow for flow in body if flow.priority == 1],
                           key=lambda flow: (flow.match['in_port'],
                                             flow.match['eth_dst'])):
            self.logger.info('%016x %8x %17s %8x %8d %8d',
                             ev.msg.datapath.id, stat.match['in_port'],
                             stat.match['eth_dst'], stat.instructions[0].actions[0].port,
                             stat.packet_count, stat.byte_count)

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        msg = ev.msg
        body = msg.body
        dpid = msg.datapath.id
        switchCollect = self.lastCollect.setdefault(dpid, SwitchStats(dpid))
        ports = switchCollect.getPorts()

        self.logger.info('datapath            port  '
                         'rx-pkts   rx-bytes   rx-error '
                         'tx-pkts tx-bytes tx-error')
        self.logger.info('-----------        ------  '
                         '-------   -------   -----   '
                         '------  -------  --------')
        for stat in sorted(body, key=attrgetter('port_no')):
            if stat.port_no > 10000:
                continue
            self.logger.info('%016x %8d %8d %8d %8d %8d %8d %8d ',
                             ev.msg.datapath.id, stat.port_no,
                             stat.rx_packets, stat.rx_bytes, stat.rx_errors,
                             stat.tx_packets, stat.tx_bytes, stat.tx_errors)

        for stat in sorted(body, key=attrgetter('port_no')):
            portNo = stat.port_no
            if portNo < 10000:
                port = ports.setdefault(portNo, Portstats(portNo))
                port.setFieds(stat, time.time())

        if self.superExist:
            self._send_port_stats(dpid)

    def _send_port_stats(self, dpid):

        send_message = self._make_port_stats_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_port_stats_message(self, dpid):
        assert dpid in self.lastCollect
        switchCollect = self.lastCollect[dpid]
        portsMsg = switchCollect.getPortMessageByRx_bytes()
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'portStats'
        to_send[DPID] = dpid
        to_send[PORTSTATS] = portsMsg
        send_message = json.dumps(to_send)
        return send_message

    def _get_QueueQos(self, dpid):
        assert dpid in self.QoS_dict
        return self.QoS_dict[dpid]

    def _get_datapath(self, dpid):
        assert dpid in self.dps
        return self.dps[dpid]

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        self.logger.debug('switch features ev %s', msg)

        dpid = datapath.id
        #print 'dpid in domain: ', dpid
        switch = self.deviceInfo.setdefault(dpid, SwtichFeatures(dpid))

        switch.initFieds(msg.version, msg.capabilities, msg.n_buffers, msg.n_tables, msg.auxiliary_id)

        if dpid not in self.QoS_dict:
            queueQoSInstance = QueueQos(datapath, self.CONF)
            self.QoS_dict[dpid] = queueQoSInstance
            ip = datapath.address[0]
            ovs_addr = 'tcp:' + ip + ':' + DEFAULTOVSDBADDR
            queueQoSInstance.set_ovsdb_addr(dpid, ovs_addr)
            self.logger.info("QueueQoS Entering. dpid: %016x, addr: %s" % (dpid, ovs_addr))


    @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, CONFIG_DISPATCHER)
    def multipart_reply_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        dpid = datapath.id
        switch = self.deviceInfo.setdefault(dpid, SwtichFeatures(dpid))

        for portdesc in msg.body:
            #print 'portdesc: ',portdesc
            portNo = portdesc.port_no
            if portNo > 10000:
                name = portdesc.name
                switch.setName(name)
            else:
                port = PortFeatures(portNo)
                port.initFields(portdesc)
                switch.ports[portNo] = port
                self.QoS_dict[dpid].queueInfo[portNo] = QueuePort(portNo,dpid)

        if self.superExist:
            self._send_switch_features_message(dpid)

    def _send_switch_features_message(self, dpid):

        send_message = self._make_switch_features_message(dpid)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_switch_features_message(self, dpid):
        assert dpid in self.deviceInfo
        switchFeaturs = self.deviceInfo[dpid]
        info = switchFeaturs.makeFeaturesMessage()
        to_send = {}
        to_send[TYPE] = 'switchFeature'
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[SWITCHFEATURE] = info

        send_message = json.dumps(to_send)
        return send_message

    @set_ev_cls(event.EventSwitchEnter, [MAIN_DISPATCHER, CONFIG_DISPATCHER])
    def switchEnterHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id
        if dpid not in self.switches:
            self.switches.append(dpid)

        if dpid not in self.dps:
            self.dps[dpid] = dp

        assert len(self.switches) == len(self.dps)

        self.topo.addNode(dpid)
        self.logger.info("Switch %016x enter in local topo", dpid)

        if self.superExist:
            self._send_switch_enter_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %016x", dpid)

    def _send_switch_enter_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[DPID] = dpid
        to_send[TYPE] = 'switchEnter'
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)


    @set_ev_cls(event.EventLinkAdd, [CONFIG_DISPATCHER, MAIN_DISPATCHER])
    def linkAddHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if src_switch in self.dps:
            if edge not in self.topo.edges():
                self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
                #print 'self.linkWithPort: ', self.topo.linkWithPort
                self.logger.info("Link add: src %016x port_no %8d-> dst %016x %8d" % (src_switch, src_port,
                                                                                      dst_switch, dst_port))
        else:
            assert src_switch not in self.dps
            #self.outDomainSwitch[(dst_switch,dst_port)] = (src_switch, src_port)
            self.outDomainSwitch[dst_switch] = src_switch
            self.topo.addEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("Link add: src %016x port_no %8d-> dst %016x %8d" % (src_switch, src_port,
                                                                                  dst_switch, dst_port))
            self.reportPath()
            dst_switch = str(dst_switch)
        if self.superExist:
            self._send_link_add_msg(src_switch, src_port, dst_switch, dst_port)
            dst_switch = int(dst_switch)
            self.logger.info("TO Super controller.Link add: src %016x port_no %8d-> dst %016x %8d" %
                             (src_switch, src_port, dst_switch, dst_port))

    def _send_link_add_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkAdd'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        print send_message
        command = self._to_commad(send_message)
        self.send_no_return_command(command)


    @set_ev_cls(event.EventSwitchLeave, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def switchLeaveHandler(self, ev):
        switch = ev.switch
        dp = switch.dp
        dpid = dp.id

        if dpid in self.switches:
            self.switches.remove(dpid)
        if dpid in self.dps:
            del self.dps[dpid]

        if dpid not in self.topo.nodes():
            self.logger.warning("Switch %016x not in local topo", dpid)
        else:
            self.topo.removeNode(dpid)
            self.logger.info("Switch %016x leave the local topo", dpid)

        if self.superExist:
            self._send_switch_leave_msg(dpid)
            self.logger.info("To super controller: Switch Enter->dpid %016x", dpid)

    def _send_switch_leave_msg(self, dpid):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'switchLeave'
        to_send[DPID] = dpid
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    @set_ev_cls(event.EventLinkDelete, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def linkDelHandler(self, ev):
        link = ev.link
        src = link.src
        dst = link.dst
        src_switch = src.dpid
        dst_switch = dst.dpid
        src_port = src.port_no
        dst_port = dst.port_no

        edge = (src_switch, dst_switch)
        if edge in self.topo.edges():
            self.topo.removeEdge(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("Link delete: src %016x port_no %8d-> dst %016x port_no %8d" % (src_switch, src_port,
                                                                                           dst_switch, dst_port))

        if self.superExist:
            self._send_link_delete_msg(src_switch, src_port, dst_switch, dst_port)
            self.logger.info("TO Super controller.Link Delete: src %016x port_no %8d-> dst %016x %8d" %
                             (src_switch, src_port, dst_switch, dst_port))

    def _send_link_delete_msg(self, ss, sp, ds, dp):

        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'linkDelete'
        to_send[SRC_SWITCH] = ss
        to_send[SRC_PORT] = sp
        to_send[DST_SWITCH] = ds
        to_send[DST_PORT] = dp

        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _get_ofproto_info(self, dpid):
        assert dpid in self.dps
        dp = self.dps[dpid]
        parser = dp.ofproto_parser
        ofproto = dp.ofproto
        return dp, parser, ofproto

    def _get_flow_mod(self, dpid, match, actions, priority=None, buffer_id=None):

        dp, parser, ofproto = self._get_ofproto_info(dpid)

        if not priority:
            priority = ofproto.OFP_DEFAULT_PRIORITY

        if ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
            mod = parser.OFPFlowMod(datapath=dp, priority=priority, match=match, instructions=inst)
        else:
            raise ValueError('We only support OpenFlow 1.3 now')
        return mod

    def _send_flow(self, datapath, mod):
        datapath.send_msg(mod)

    def pushMplsFlow(self, dpid, pushLabel, srcMac, dstMac, outPortNo, queueId, pathType, priority):
        assert dpid in self.dps

        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_IP, eth_src=srcMac, eth_dst=dstMac)

        actions = []
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions, priority)
        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod

    def popMplsFlow(self, dpid, popLabel, outPortNo,queueId,local_mac, priority):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions =[]
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(dp.ofproto_parser.OFPActionSetQueue(queueId))
        #actions.append(parser.OFPActionSetField(eth_src=local_mac))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions, priority)

        self._send_flow(dp, mod)
        return match, mod

    def swapMplsFlow(self, dpid, pushLabel, popLabel, outPort, queueId, priority):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        eth_MPLS = ether.ETH_TYPE_MPLS
        match = parser.OFPMatch(eth_type=eth_MPLS, mpls_label=popLabel)

        actions = []
        actions.append(parser.OFPActionPopMpls(eth_IP))
        actions.append(parser.OFPActionPushMpls(eth_MPLS))
        f = parser.OFPMatchField.make(ofproto.OXM_OF_MPLS_LABEL, pushLabel)
        actions.append(parser.OFPActionSetField(f))
        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPort))

        mod = self._get_flow_mod(dpid, match, actions, priority)

        self._send_flow(dp, mod)
        return match, mod

    def noMplsFlow(self, dpid, srcMac, dstMac, outPortNo, queueId, pathType, priority):
        dp, parser, ofproto = self._get_ofproto_info(dpid)
        eth_IP = ether.ETH_TYPE_IP
        match = parser.OFPMatch(eth_type=eth_IP, eth_src=srcMac, eth_dst=dstMac)

        actions = []

        actions.append(parser.OFPActionSetQueue(queueId))
        actions.append(parser.OFPActionOutput(outPortNo))

        mod = self._get_flow_mod(dpid, match, actions, priority)

        if pathType == 'main':
            self._send_flow(dp, mod)
        elif pathType == 'backup':
            self.logger.info("Backup path's First switch should not install flow now!")

        return match, mod

    def changeToBackPath(self, dpid, nextdpid):
        #topo1 = copy.deepcopy(self.topo)
        self.completeTopo = copy.deepcopy(self.topo)
        self.topo.topo.remove_edge(dpid, nextdpid)
        self.BoardShortestPath(self.edgePort)


    @set_ev_cls(mactoportEvent, dispatchers=None)
    def mac_to_port_handler(self, ev):
        ev_dict = self.object2dict(ev)
        for dpid in ev_dict['mac_to_port'].keys():
            self.borderPeer.append(dpid)
        self.borderPeer = list(set(self.borderPeer))
        self.reportPath()
        ev_dict[TYPE] = 'mactoportmessage'
        send_msg = json.dumps(ev_dict)
        command = self._to_commad(send_msg)
        self.send_no_return_command(command)
        print "mac to port:", ev_dict

    def object2dict(self,obj):
        d={}
        d['__class__'] = obj.__class__.__name__
        d['__module__'] = obj.__module__
        d.update(obj.__dict__)
        return d

    def reportPath(self):
        self.edgePort = list(set(self.borderPeer) | set(self.outDomainSwitch.keys()))
        tempPathList = self.BoardShortestPath(self.edgePort)
        print 'self.edgePort: ', self.edgePort
        self._send_path_report_msg(tempPathList)

    def BoardShortestPath(self, edgeSwitch):
        pathList=[]
        if edgeSwitch is None:
            LOG.info("This Domain have no edgePort!")
            return None

        for i in edgeSwitch:
            for m in edgeSwitch:
                if i == m:
                    continue
                temppath = self.topo.getShortestPath(i, m)
                #print 'temppath: ',temppath
                pathList.append([i, m, len(temppath)-1])
                self.shortestPath[(i, m)] = temppath

        self.logger.info('in_switch          out_switch        length    ')
        self.logger.info('----------------  ----------------  -------- ')
        # for stat in pathList:
        #     self.logger.info('%016x %016x %8d' % stat[0], stat[1], stat[2])
        print self.shortestPath
        return pathList

    #Send pathList which created by the function named athAnalysisByShortest to SuperController
    def _send_path_report_msg(self, pathList):
        self.logger.info("send Path Report Msg")
        send_message = self._make_path_report_msg(pathList)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    # Implement the message for SuperController path
    # At last, if SuperController exists,this function transmit the pathlist to SuperController.

    def _make_path_report_msg(self, pathList):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'pathReport'
        to_send[PATHLIST] = pathList
        send_message = json.dumps(to_send)
        print "local_topo:", self.topo.edges()
        return send_message



    def sendPathChangeReply(self, src, dst):
        to_send = {}
        to_send['src'] = src
        to_send['dst'] = dst
        to_send['domainId'] = self.domainId
        to_send['type'] = 'pathChangeReply'
        send_message = json.dumps(to_send)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)


    def sendTaskAssignReply(self, taskId, pathType, src, dst):
        self.logger.info("send Task Assign Reply")
        send_message = self._make_task_assign_reply(taskId, pathType, src, dst)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_assign_reply(self, taskId, pathType, src, dst):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskAssignReply'
        to_send[TASK_ID] = taskId
        to_send[PATHTYPE] = pathType
        to_send['src'] = src
        to_send['dst'] = dst

        send_message = json.dumps(to_send)
        return send_message

    def sendTaskDeleteReply(self, taskId, src, dst):
        self.logger.info("send Task Delete Reply")
        send_message = self._make_task_delete_reply(taskId, src, dst)
        command = self._to_commad(send_message)
        self.send_no_return_command(command)

    def _make_task_delete_reply(self, taskId, src, dst):
        to_send = {}
        to_send[DOMAINID] = self.domainId
        to_send[TYPE] = 'taskDeleteReply'
        to_send[TASK_ID] = taskId
        to_send['src'] = src
        to_send['dst'] = dst

        send_message = json.dumps(to_send)
        return send_message

    def remove_flow(self, datapath, match):

        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
                                    out_port=ofproto.OFPP_ANY, match=match)
        elif ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
            mod = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
                                    out_group=ofproto.OFPG_ANY, out_port=ofproto.OFPP_ANY,
                                    match=match)
        datapath.send_msg(mod)

    def _to_commad(self, send_message, returnType=False):

        command = 'curl -X '
        if returnType:
            command += 'GET -d \''
        else:
            command += 'PUT -d \''
        command += send_message
        command += '\' http://'
        command += self.superWsgiIp
        command += ':'
        command += str(self.superWsgiPort)
        command += super_url_no_reutrn
        command += ' 2> /dev/null'
        return command

    def send_no_return_command(self, command):
        print 'command: ', command
        os.popen2(command)