📜  SDN控制器(Ryu和ODL)(1)

📅  最后修改于: 2023-12-03 14:47:21.119000             🧑  作者: Mango

SDN控制器

SDN(Software-Defined Networking,软件定义网络)是将网络控制平面(control plane)与数据平面(data plane)分离的一种网络架构,其中控制平面由计算机程序控制,而数据平面是随时转发网络数据包的硬件部分。

SDN控制器是SDN架构中的核心组件,负责控制网络中各个设备的行为,如路由、转发、QoS(Quality of Service,服务质量)等。本文将介绍两个常用的SDN控制器:Ryu和OpenDaylight。

Ryu

Ryu是一个日本制作的开源SDN控制器,由Python编写,采用BSD协议。Ryu提供了丰富的API,使得程序员可以方便地使用Python编写SDN程序。Ryu的特点包括:

  • 轻量级,易于安装和使用;
  • 提供了快速开发SDN应用程序的框架,包括交换机、控制器以及北向接口;
  • 支持OpenFlow 1.0-1.5协议版本。

以下是使用Ryu Python API实现一个简单交换机的示例代码:

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


class SimpleSwitch(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

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

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

        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                          ofproto.OFPCML_NO_BUFFER)]
        self.add_flow(datapath, 0, match, actions)

    def add_flow(self, datapath, priority, match, actions):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

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

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

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

        dst = eth.dst
        src = eth.src

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

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

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

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

        actions = [parser.OFPActionOutput(out_port)]

        # install a flow to avoid packet_in next time
        if out_port != ofproto.OFPP_FLOOD:
            match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
            self.add_flow(datapath, 1, match, actions)

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

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

    @set_ev_cls(ofp_event.EventOFPStateChange,
                [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def state_change_handler(self, ev):
        datapath = ev.datapath
        if ev.state == MAIN_DISPATCHER:
            if not datapath.id in self.mac_to_port:
                self.mac_to_port[datapath.id] = {}
            self.logger.info('switch joined: %s', datapath.id)
        elif ev.state == DEAD_DISPATCHER:
            self.logger.info('switch left: %s', datapath.id)
            if datapath.id in self.mac_to_port:
                del self.mac_to_port[datapath.id]
OpenDaylight

OpenDaylight(ODL)是一个由Linux基金会支持的、以Java编写的、开源的SDN控制器。ODL提供了一种通用的框架,使得用户可以创建、管理和调度SDN网络。ODL的特点包括:

  • 提供了基于组件、可扩展的架构;
  • 支持多种南向接口,如OpenFlow、NETCONF、OVSDB等;
  • 提供了丰富的REST API,便于用户进行编程。

以下是使用ODL REST API查询网络拓扑的示例代码:

import requests
import json

def get_topology():
    url = 'http://127.0.0.1:8181/restconf/operational/network-topology:network-topology'

    headers = {
        'Authorization': 'Basic YWRtaW46YWRtaW4=',
        'Content-type': 'application/json'
    }

    response = requests.get(url, headers=headers)
    data = json.loads(response.text)

    topology = data['network-topology']['topology'][0]['node']

    for node in topology:
        print('Node:', node['node-id'])
        for link in node['termination-point']:
            print('  Link:', link['tp-id'], 'to', link['remote-system']['system-id'] + '/' + link['remote-system']['node-id'] + '/' + link['remote-tp'])
结语

通过使用SDN控制器,程序员可以实现更加灵活、高效的网络编程,为网络运营和管理带来了巨大的变革。以上是介绍两个常用的SDN控制器,有助于程序员们更好地了解和使用SDN技术。