Software Defined Network week 3(三)

在这里插入图片描述
在这里插入图片描述
Here’s an overview of the Ryu architecture. At the very bottom of the picture, you can see a bunch of libraries that we’ll talk about. We also have a Ryu controller interface with switches via various south-bound interfaces. We have an OpenFlow controller, a Ryu manager, and an app manager that sit on top of that. And on top of that we have applications and other north-bound APIs such as rest and open step neutron. Ryu can also speak to switches natively via the OpenFlow controller.

北向接口和南向接口
A northbound interface is an interface that conceptualizes lower level details. It interfaces to higher level layers and is normally drawn at the top of an architectural overview.
A southbound interface decomposes concepts in the technical details, mostly specific to a single component of the architecture. Southbound interfaces are drawn at the bottom of an architectural overview.
Northbound interfaces normally talk to southbound interfaces of higher level components and vice versa.

从英文定义可以看出来:

1.北向接口是某个模块的顶层抽象接口;

2.南向接口是某个模块之内部子模块的接口;

3.北向接口因处于架构图的顶部而得名,南向接口则因处于架构图的底部而得名,所谓上北下南;

4.另外,北向和南向也是相对的,相对于更顶级的模块,某个模块的北向接口就相对来说是南向接口了。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
The Ryu libraries support multiple southbound protocols, including OF-CONFIG, OVSDB, NETCONF, XFLOW, and an open vSwitch Python Binding.
There’s also support for various parsing, and constructing packet parsers that conform to various protocol definitions.
Ryu supports OpenFlow up to version 1.4, and handles a variety of controller to switch messages. Including handshake, switch-config, flow-table config, ability to read and modify state, queue configs and barrier commands.

在这里插入图片描述

The controller also handles various asynchronous messages such as packet-in, flow-removed, and port-status. The Ryu manager, which we’ll look at in a minute, is the main executable. It listens to port 6633 by default, and any OpenFlow switch can connect to the manager, whether it’s software or hardware.

在这里插入图片描述
All control applications inherit from the RyuApp class. The Ryu north-bound API provides support for Openstack Neutron, as well as GRE-based overlays, VLANs. It also provides a generic REST interface for performing OpenFlow Operations and makes it easy to introduce new REST APIs.

REST和REST API
REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口)
REST不是"rest"这个单词,而是几个单词缩写 – REpresentational State Transfer 直接翻译:表现层状态转移,但这个翻译正常人根本看不懂,找到的一种最好理解的说法是,URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。
REST成熟度的四个层次
第一个层次(Level0)的Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形 式。SOAP和 XML-RPC都属于此类。

第二个层次(Level1)的Web 服务引入了资源的概念。每个资源有对应的标识符和表达。

第三个层次(Level2)的Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用HTTP 状态码来表示不同的结果。如 HTTPGET 方法来获取资源,HTTPDELETE 方法来删除资源。

第四个层次(Level3)的Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。
总结,看一个标准的restful api要可以做到

看Url就知道要操作的资源是什么,是操作车辆还是围栏
看Http Method就知道操作动作是什么,是添加(post)还是删除(delete)
看Http Status Code就知道操作结果如何,是成功(200)还是内部错误(500)

在这里插入图片描述

Ryu ships with many applications including a simple switch, which we’ll look at, a router, a firewall, and many others. The application has a FIFO event queue, and event processing as blocking, meaning that when a controller is processing an event, all other tasks, such as processing incoming packets, are blocked.
在这里插入图片描述
Here’s some code showing a simple switch overview, which we will look at in detail in just a minute. As you can see, the Ryu control application is a simple Python program. The layer to switch class inherits from the RyuApp, and the main function of interest is the packet-in handler.
装饰器set_ev_cls意味着,当这个function被调用时(当有包进来的时候就被调用),packet_handler 向所有端口发包

SDNhub上的教程

此代码从Nick Feamster的GitHub上撸下来的  simple_hub.py
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0

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

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

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        actions = [datapath.ofproto_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]
# 事件发生的时候,解析message,Datapath,Openflow协议版本以及actions set
# 之后产生一个新的包从switch送出去
        out = datapath.ofproto_parser.OFPPacketOut(
            datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.in_port,
            actions=actions, data=None)
        datapath.send_msg(out)

在这里插入图片描述

# simple_switch 
import logging
import struct

from ryu.base import app_manager
from ryu.controller import mac_to_port
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0
from ryu.lib.mac import haddr_to_bin
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet


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

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

    def add_flow(self, datapath, in_port, dst, actions):
        ofproto = datapath.ofproto

        match = datapath.ofproto_parser.OFPMatch(
            in_port=in_port, dl_dst=haddr_to_bin(dst))

        mod = datapath.ofproto_parser.OFPFlowMod(
            datapath=datapath, match=match, cookie=0,
            command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0,
            priority=ofproto.OFP_DEFAULT_PRIORITY,
            flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
        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

        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocol(ethernet.ethernet)

        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, msg.in_port)

        # learn a mac address to avoid FLOOD next time.
        self.mac_to_port[dpid][src] = msg.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 = [datapath.ofproto_parser.OFPActionOutput(out_port)]

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

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

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

    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def _port_status_handler(self, ev):
        msg = ev.msg
        reason = msg.reason
        port_no = msg.desc.port_no

        ofproto = msg.datapath.ofproto
        if reason == ofproto.OFPPR_ADD:
            self.logger.info("port added %s", port_no)
        elif reason == ofproto.OFPPR_DELETE:
            self.logger.info("port deleted %s", port_no)
        elif reason == ofproto.OFPPR_MODIFY:
            self.logger.info("port modified %s", port_no)
        else:
            self.logger.info("Illeagal port state %s %s", port_no, reason)

在这里插入图片描述

在这里插入图片描述
Here’s an overview of the code structure of the Ryu code base. When you look at the Ryu code base, you’ll see many different sub-directories. App contains the set of applications that run on top of the controller. Base contains the base class for Ryu applications. In particular, it contains the RyuApp class which is inherited. We’re creating a new application.
Controller contains the required set of files to handle OpenFlow functions, such as packets from switches, network events, and so forth.

Lib contains a set of packet libraries to parse different protocol headers and a library for OFConfig, as well as libraries for parcing netflow and esflow. OF proto contains the overflow protocol specification in related parsers. Topology contains coded forms of policy discovery related to OpenFlow switches.
在这里插入图片描述
In conclusion, Ryu is a Python-based SDN controller that supplies rich support for a wide variety of north-bound applications and south-bound control protocols. It’s easy to program and provides OpenFlow support up to OpenFlow 1.4. You can read more about Ryu in the url provided here and we also provided some examples such as the ones we offered in this lecture in the course virtual machine.

大家都说建议先用Ryu上手,不如我先把SDNhub tutorial上的都过一遍

RYU Code Structure

The main controller code is organized under the /ryu/ folder (In our VM – /home/ubuntu/ryu/ryu/). Here we discuss the functionalities of the key components. It is important to become familiar with them.

  • app/ – Contains set of applications that run on-top of the controller.
  • base/ – Contains the base class for RYU applications. The RyuApp class in the app_manager.py file is inherited when creating a new application.
  • controller/ – Contains the required set of files to handle OpenFlow functions (e.g., packets from switches, generating flows, handling network events, gathering statistics etc).
  • lib/ – Contains set of packet libraries to parse different protocol headers and a library for OFConfig. In addition, it includes parsers for Netflow and sFlow too.
  • ofproto/ – Contains the OpenFlow protocol specific information and related parsers to support different versions of OF protocol (1.0, 1.2, 1.3, 1.4)
    • topology/: Contains code that performs topology discovery related to OpenFlow switches and handles associated information (e.g., ports, links etc). Internally uses LLDP protocol.
      l链路层发现协议讲解
      LLDP(Link Layer Discovery Protocol,链路层发现协议)就是用于这个目的的协议。LLDP定义在802.1ab中,它是一个二层协议,它提供了一种标准的链路层发现方式。LLDP协议使得接入网络的一台设备可以将其主要的能力,管理地址,设备标识,接口标识等信息发送给接入同一个局域网络的其它设备。当一个设备从网络中接收到其它设备的这些信息时,它就将这些信息以MIB的形式存储起来。
      这些MIB信息可用于发现设备的物理拓扑结构以及管理配置信息。需要注意的是LLDP仅仅被设计用于进行信息通告,它被用于通告一个设备的信息并可以获得其它设备的信息,进而得到相关的MIB信息。它不是一个配置、控制协议,无法通过该协议对远端设备进行配置,它只是提供了关于网络拓扑以及管理配置的信息,这些信息可以被用于管理、配置的目的,如何用取决于信息的使用者。

Ryu Controller Code Essentials

大多数控制器的native features?:

  • 监听异步事件(如PACKET_IN,FLOW_REMOVED),用ryu.controller.handler.set_ev_cls decorator去视察事件
  • 解析来的包(如ARP,ICMP,TCP),构造包送至网络
  • 创建并发送OpenFlow/SDN 信息到可编程的转发平面(如PACKET_OUT,FLOW_MOD,STATS_REQUEST)

通过唤醒一些列应用来处理网络时间,解析任何交换机请求,并对网络变化做出响应,如添加新流。
创建一个新的应用需要穿件RyuAPP的子类,并且构建逻辑来监听网络事件

from ryu.base import app_manager 

class L2Forwarding(app_manager.RyuApp):
    def __init__(self, *args, **kwargs):
        super(L2Forwarding, self).__init__(*args, **kwargs)

上述代码代表了一个合法的Ryu应用
为了能够让应用接收从交换机发送至控制器的包,类中需要实现由EventOFPPacketIn装饰器装饰的方法

 @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def packet_in_handler(self, ev):

第一个参数在每收到一个packet_in的信息的时候调用函数,第二个参数意味着交换机与其支持的协议信息可以按照如下解析:

    msg = ev.msg               # Object representing a packet_in data structure.
    datapath = msg.datapath    # Switch Datapath ID
    ofproto = datapath.ofproto # OpenFlow Protocol version the entities negotiated. In our case OF1.3

一旦包被接收,可以引用/ryu/lib下的库来解析包

  from ryu.lib.packet import packet
  from ryu.lib.packet import ethernet

我们可以检查这几种包的包头: ARP, Ethernet, ICMP, IPv4, IPv6, MPLS, OSPF, LLDP, TCP, UDP

 pkt = packet.Packet(msg.data)
 eth = pkt.get_protocol(ethernet.ethernet)

通过这两个命令来提取Ether header details

 dst = eth.dst
 src = eth.src

类似地,能用OFPPacketOut类来构建packet_out信息,需要提供DataPath ID,相关actions等

   out = ofp_parser.OFPPacketOut(datapath=dp,in_port=msg.in_port,actions=actions)#Generate the message
   dp.send_msg(out) #Send the message to the switch

除了PACKET_OUt,我们也可以将FLOW_MOD插入一个交换机。为此,我们要构建Match,action,instructions并生成需要的流。下面是一个如何从PACKET_IN中提取in_port和eth_dst,创建一个匹配的match header的

 msg = ev.msg
    in_port = msg.match['in_port']
    # Get the destination ethernet address
    pkt = packet.Packet(msg.data)
    eth = pkt.get_protocol(ethernet.ethernet)
    dst = eth.dst
    match = parser.OFPMatch(in_port=in_port, eth_dst=dst)

There are several other fields you can match, which are defined in line 1130. The supported set of actions is defined in line 230 and the instructions are defined in line 195.
可以匹配其他的fields。下面是一个创建actions的例子

 actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)] # Build the required action

match rule和action list形成后,指令如下创建:

   inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]

结合上述代码,流并生成并增加到特定的交换机

    mod = parser.OFPFlowMod(datapath=datapath, priority=0, match=match, instructions=inst)
    datapath.send_msg(mod)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值