生动的SDN基础内容介绍(五)--SDN北向协议/接口和意图驱动

  • 背景
  • 北向协议
  • REST API
  • REST API在Ryu中的实现
  • 意图驱动
  • 总结

背景

经过前几章的讲解,现在回过头来再看看SDN的架构

自底向上看一遍:
1、网络设备就是交换机,也就是上一章提到的OVS。

2、南向协议就是OpenFlow协议。

3、SDN控制器有很多种,我们之前关注的是Ryu。

现在就剩北向协议和应用平面了。

这章会关注北向协议和意图驱动,下章会以网络测量为例子说一下应用平面。

北向协议

北向协议/接口的定义:

SDN北向接口是通过控制器向上层业务应用开放的接口,其目标是使得业务应用能够便利地调用底层的网络资源和能力。
通过北向接口,网络业务的开发者能以软件编程的形式调用各种网络资源;同时上层的网络资源管理系统可以通过控制器的北向接口全局把控整个网网络的资源状态,并对资源进行统一调度。
因为北向接口是直接为业务应用服务的,因此其设计需要密切联系业务应用需求,具有多样化的特征。
同时,北向接口的设计是否合理、便捷,以便能被业务应用广泛调用,会直接影响到SDN控制器厂商的市场前景。

来源:
https://zhuanlan.zhihu.com/p/74465580

打住!说了这么多其实可以总结为一句话:

北向协议就是用户与控制器沟通的渠道。

那怎么理解呢:

用户说我现在想删除一个交换机里面的一个流表项,具体的删除逻辑是控制器干的事情,用户只需要告诉控制器他想删掉交换机1的匹配域为“目的ip:10.0.0.1”的那个流表项。

好,用户只表达了三个需求:
1、交换机1
2、匹配域为“目的ip:10.0.0.1”
3、删除这个流表项

具体怎么干用户才懒得去弄,直接让控制器去决定怎么删除,具体的删除逻辑是什么样子的。

按前几章的比喻其实就是,甲方给领导提了三个要求,领导想怎么干就怎么干,只要最后完成了这三个要求就可以。

也就是说北向协议将底层的具体实现抽象化了。

北向协议有很多,也没有规定说是一定要用哪个,因为Ryu用的是REST API,而且REST API在当今的软件开发中也是一种很主流的风格,因此这里我只介绍一下REST API。

REST API

REST API不是一个什么新的技术,它只是一种风格,把之前章节的部分内容搬过来。

REST (Representational State Transfer) API,这是Roy Fielding在2000年提出的一种架构风格或设计原则。REST的原则是将系统中的所有事物抽象为URL表示的资源。客户端可以通过 HTTP 请求(如 GET、POST、PUT、DELETE等)来操作资源。服务器收到请求后会根据不同的方法采取不同的响应,最终将数据以XML、JSON等格式返回给客户端。

说白了就是用URL表示资源然后用GET/POST等常见的动作来对资源进行操作。

一些更详细的讨论可以看
https://www.zhihu.com/question/28557115

我认为REST API为什么被大家喜爱主要有两个优点:
1、简单:
这种设计风格十分简洁易懂,因为大家都接触过HTTP协议,对URL请求也不陌生,以上一章用过的http://127.0.0.1:8080/stats/flow/1为例,很容易就能理解这是对flow流表的查询,最后的1就表示是对交换机1的查询,结合起来就是对交换机1的流表进行查询,是不是很容易理解。

还有就是使用上的简单,大家已经习惯了client-server形式的资源请求,在使用相似的REST API的时候就很容易了。

2、通用性:
由于互联网的快速发展,各种客户端应用和服务器应用层出不穷,REST API可以通过一套一致的接口为各种应用提供服务。换到SDN这里来说就是不管上层应用是啥,只要你们按着我提供好的接口给我发http请求,我就帮你干活。

尽管在SDN里没有明确的client-server结构,但是也可以这么抽象地理解:

用户,也就是应用平面,是client
控制器,也就是帮用户干活的,是server

然后REST API就可以完美地契合进去:

REST API在Ryu中的实现

ofctl_rest.py实现了很多REST API,上一章已经介绍过了,详情见
https://www.freesion.com/article/8090870623/

但是这些都是Ryu预定义好了的,我们如果想自己定义新的该怎么办?
比如说我的毕设需要我自己实现一些REST API来完成应用层与控制层的通信。

让我们看一下Ryu控制器给我们写好了的示例:simple_switch_rest_13.py
详情见
https://osrg.github.io/ryu-book/en/html/rest_api.html

# Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.import jsonfrom ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import route
from ryu.app.wsgi import WSGIApplication
from ryu.lib import dpid as dpid_libsimple_switch_instance_name = 'simple_switch_api_app'
url = '/simpleswitch/mactable/{dpid}'class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):_CONTEXTS = {'wsgi': WSGIApplication}def __init__(self, *args, **kwargs):super(SimpleSwitchRest13, self).__init__(*args, **kwargs)self.switches = {}wsgi = kwargs['wsgi']wsgi.register(SimpleSwitchController,{simple_switch_instance_name: self})@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)def switch_features_handler(self, ev):super(SimpleSwitchRest13, self).switch_features_handler(ev)datapath = ev.msg.datapathself.switches[datapath.id] = datapathself.mac_to_port.setdefault(datapath.id, {})def set_mac_to_port(self, dpid, entry):mac_table = self.mac_to_port.setdefault(dpid, {})datapath = self.switches.get(dpid)entry_port = entry['port']entry_mac = entry['mac']if datapath is not None:parser = datapath.ofproto_parserif entry_port not in mac_table.values():for mac, port in mac_table.items():# from known device to new deviceactions = [parser.OFPActionOutput(entry_port)]match = parser.OFPMatch(in_port=port, eth_dst=entry_mac)self.add_flow(datapath, 1, match, actions)# from new device to known deviceactions = [parser.OFPActionOutput(port)]match = parser.OFPMatch(in_port=entry_port, eth_dst=mac)self.add_flow(datapath, 1, match, actions)mac_table.update({entry_mac: entry_port})return mac_tableclass SimpleSwitchController(ControllerBase):def __init__(self, req, link, data, **config):super(SimpleSwitchController, self).__init__(req, link, data, **config)self.simple_switch_app = data[simple_switch_instance_name]@route('simpleswitch', url, methods=['GET'],requirements={'dpid': dpid_lib.DPID_PATTERN})def list_mac_table(self, req, **kwargs):simple_switch = self.simple_switch_appdpid = kwargs['dpid']if dpid not in simple_switch.mac_to_port:return Response(status=404)mac_table = simple_switch.mac_to_port.get(dpid, {})body = json.dumps(mac_table)return Response(content_type='application/json', text=body)@route('simpleswitch', url, methods=['PUT'],requirements={'dpid': dpid_lib.DPID_PATTERN})def put_mac_table(self, req, **kwargs):simple_switch = self.simple_switch_appdpid = kwargs['dpid']try:new_entry = req.json if req.body else {}except ValueError:raise Response(status=400)if dpid not in simple_switch.mac_to_port:return Response(status=404)try:mac_table = simple_switch.set_mac_to_port(dpid, new_entry)body = json.dumps(mac_table)return Response(content_type='application/json', text=body)except Exception as e:return Response(status=500)

让我们看看它干了哪几件事:

1、WSGI:
想实现一个简单的REST接口,只需让程序代码满足Python的WSGI标准即可。
WSGI又是啥?
https://zhuanlan.zhihu.com/p/95942024
WSGI,Web Server Gateway Interface,是一套接口标准协议/规范,让Web服务器和Python Web应用程序之间可以正常的通信。

那么为啥要有WSGI呢?因为Web框架和Web服务器都有很多种,如果不定义一套接口的话会导致各说各的,没办法有效地通信。

Ryu中已经为我们实现了WSGI,在app的目录下有个文件叫wsgi.py。
在实现REST API的时候需要引入以下几个类:

from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import route
from ryu.app.wsgi import WSGIApplication

然后还需要进行WSGI的注册:

class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):_CONTEXTS = {'wsgi': WSGIApplication}def __init__(self, *args, **kwargs):super(SimpleSwitchRest13, self).__init__(*args, **kwargs)self.switches = {}wsgi = kwargs['wsgi']wsgi.register(SimpleSwitchController,{simple_switch_instance_name: self})

SimpleSwitchController是用来接收HTTP请求,处理路由的类。
这部分代码将SimpleSwitchController注册到WSGIApplication的一个实例里,同时需要传入参数{simple_switch_instance_name: self}让SimpleSwitchController与SimpleSwitchRest13连接上。

连接上之后可以在SimpleSwitchController中对SimpleSwitchRest13进行一系列的操作。

2、定义全局变量:
需要定义两个全局变量

simple_switch_instance_name = 'simple_switch_api_app'
url = '/simpleswitch/mactable/{dpid}'

第一个是为了帮助SimpleSwitchController对SimpleSwitchRest13进行操作。
第二个是定义需要处理的url,其中{dpid}是变量。
如果我们请求http://127.0.0.1:8080/simpleswitch/mactable/1,那么dpid就为1。

3、SimpleSwitchController类
SimpleSwitchController类是对路由和HTTP请求进行处理

class SimpleSwitchController(ControllerBase):def __init__(self, req, link, data, **config):super(SimpleSwitchController, self).__init__(req, link, data, **config)self.simple_switch_app = data[simple_switch_instance_name]

simple_switch_app让SimpleSwitchController可以对SimpleSwitchRest13进行操作。

  @route('simpleswitch', url, methods=['GET'],requirements={'dpid': dpid_lib.DPID_PATTERN})def list_mac_table(self, req, **kwargs):

这里定义了路由,
也就是说只要我们发送请求形如“http://127.0.0.1/simpleswitch/mactable/数字”的GET请求就会调用list_mac_table()函数:

simple_switch = self.simple_switch_app
dpid = kwargs['dpid']

这两行表明SimpleSwitchController可以对SimpleSwitchRest13进行操作,并且dpid是用户通过url传入的参数。

如果我们想定义新的路由及处理方式的话只需要编写2、3步的代码即可。
如想添加查询当前存在的任务的功能:
定义全局变量

urlQuery='/measurement/query/tasks'

在SimpleSwitchController中增加路由

@route('measurement', urlQuery, methods=['GET'])#下发查询任务的指令def setQuery(self, req, **kwargs):simple_switch = self.simple_switch_apptasks_info=simple_switch.queryTasks()return Response(content_type='application/json', text=tasks_info)

意图驱动

实现了北向协议后,用户可以向控制器发出一个个指令了,但是人们还不满足于此。

就像那个经典的段子描述的一样:
人类因为太懒了,所以才会创造一个个工具帮助人类干活。

没错,用户觉得光这样还是太麻烦、太累了。

用户想,我这发一个指令就得发一次HTTP请求,那如果我要打一套组合拳发一系列的指令,那我岂不是得手动发好多条指令。不行,这样太麻烦,那怎么办呢?

用户想,那我就找个方法,只要把我想干的事描述一下,应用就发送用于完成这件事的一系列指令。用户拍了拍应用的脑袋,说:你已经是一个成熟的应用了,该学会自己下发指令了。

没错,这种思想就是意图驱动的核心,就是为了让人们可以更方便地管理网络。

用户在应用层编排网络管理任务的时候,仍需要了解底层的相关实现细节,起码得知道每条指令是干啥的,需要用什么指令才能完成想干的事情。但是用意图驱动之后,应用会将用户的意图映射为一条条指令,然后将这些指令从应用平面下发到控制平面。

也就是说意图是将北向协议再次抽象化了。

这样还有一个好处,就是可以让非专业人士对网络进行有效的管理。
如果没有意图驱动,那么只有网络工程师可以编排任务,但是现在只要说一句“我想看看谁在用校园网看b站”,那么应用会自动将这个意图拆分成多个指令:
1、应用先查询b站的ip。
2、让控制平面下发流表项,匹配域为“源ip为b站服务器,或者目的ip为b站服务器”。
3、控制平面在一定时间内查询,然后把ip与同学相对应。
4、控制平面汇报给应用。

这样很复杂的事情一句话就解决了,当然,这是因为我们已经在应用平面实现了意图的映射,这些都是我们制定好的规则。

目前业内对意图驱动网络,也就是基于意图的网络intent-based networking(IBN)还没有一套标准。也是近几年网络方向的一个研究热点。

我推荐把东北大学李福亮老师的《基于意图的网络研究综述》来作为IBN的入门。

IBN不是一个新的技术,而是一种新的理念,将已有的技术结合起来对网络进行更方便的管理。下图是李福亮老师这篇论文给出的IBN体系结构:

可以看到的是IBN的结构和SDN很像,因此可以在SDN的基础上实现IBN。

IBN的实施步骤可分为意图表达、意图转化、策略验证、意图发布与执行、网络信息的实时反馈。(更详细的内容请看李福亮老师的这篇论文)

1、意图表达:
表达意图的方法有很多,最流行的是用自然语言书写意图。对于自然语言输入,大多数研究使用语义的形式来获取意图。

2、意图转化:
意图的转化是IBN的核心任务,实现了从用户意图到网络策略的转化。
目前,意图的转化主要采用自然语言处理NLP的方法,通过关键词抽取、词法分析、意图语义挖掘,生成相应的网络策略(原语)。

3、策略验证:
为了保证IBN的鲁棒性,通过意图转换得到的网络策略不能直接下发,需要在发布前进行策略的验证。目前,策略的验证主要考虑资源的可用性、策略的冲突和策略的正确性。
检查资源的可用性是指根据系统中现有的资源决定是否可以发布该策略。对于策略冲突的验证,需要确定要发布的策略与系统中当前策略之间是否存在冲突,如果存在,则需要消除检测到的冲突。
对策略正确性的验证是指该策略是否可以按预期在网络中实现。

4、意图发布与执行:
在验证网络策略后,IBN自动将策略发送到网络基础设施并配置相应的转发规则。由于IBN需要将集中的意图转换为分布式的全局网络配置,整个策略下发的过程可以由SDN实现。

5、网络信息的实时反馈:
策略下发到网络后,需要实时监控网络的状态信息,保证网络的转发行为符合意图。此外,由于网络的状态也在不断变化,IBN需要根据当前网络状态自动优化和调整策略,保证网络始终满足任务需求。

总结

我毕设的时候实现了一套意图驱动的分布式SDN协同网络测量系统。
只不过因为时间比较紧,最后只基于策略库实现了意图的映射,以后如果有机会的话可以尝试用NLP来映射。

下一章会以网络测量为例,说一下应用平面以及SDN在网络测量方向的应用。
https://blog.csdn.net/weixin_44480014/article/details/123285199

生动的SDN基础内容介绍(五)--SDN北向协议/接口和意图驱动相关推荐

  1. 生动的SDN基础内容介绍(二)--OpenFlow协议

    生动的SDN基础内容介绍(二)--OpenFlow协议 背景 OpenFlow OpenFlow的基础概念 流表项 流表 漏表 流表项的下发 流表项的删除 计量表 组表 控制器与交换机的通信 总结 背 ...

  2. 生动的SDN基础内容介绍(六)--SDN应用平面和网络测量

    生动的SDN基础内容介绍(六)--SDN应用平面和网络测量 背景 网络测量 网络测量的定义 网络测量的对象 网络状态参数 网络性能参数 网络流量参数 Heavy Hitter和Hierarchical ...

  3. 生动的SDN基础内容介绍(三)--Ryu控制器

    生动的SDN基础内容介绍(三)--Ryu控制器 控制器 Ryu的目录 Ryu的学习 simple_switch_13.py simple_switch_rest_13.py 交换机信息及流表项的查询 ...

  4. folium基础内容介绍

    folium基础内容介绍 1. 简介 ​ folium是js上著名的地理信息可视化库leafet.js为Python提供的接口,通过它,我们可以通过在Python端编写代码操纵数据,来调用leafle ...

  5. 题库搜题内容内含五千万条数据api接口

    题库搜题内容内含五千万条数据api接口 本接口题库范围 大学生网课答案.公务员考试答案,外语类考试答案,财会类考试答案,建筑类考试答案,职业资格考试答案,学历考试考试答案,医药类考试答案,外贸类考试答 ...

  6. 工业控制计算机硬件基础知识,第五章 工业控制计算机及其接口技术知识 机电一体化课件.ppt...

    第五章 工业控制计算机及其接口技术知识 机电一体化课件.ppt (3) 编程方法举例 1. A/D编程 下面C语言例程为软件触发A/D和软件查询方式完成A/D转换功能,模拟输入范围为±5V增益为1. ...

  7. 图像标注的基础内容介绍

    点击上方"AI公园",关注公众号,选择加"星标"或"置顶" 作者:Surya Remanan 编译:ronghuaiyang 导读 给大家介 ...

  8. 收藏 | 图像标注的基础内容介绍

    作者:Surya Remanan,来源:AI公园 介绍 "如果没有数据分析,公司就会变得既盲又聋,就像高速公路上的鹿一样在网络上游荡." - Geoffrey Moore 每个数据 ...

  9. 工赋开发者社区 | 当PLC与见“IT”:MES/MOM标准之ISA-95基础内容介绍

    ISA-95 简称S95,也有称作SP95.ISA-95 是企业系统与控制系统集成国际标准,由国际自动化学会(ISA,International Society of Automation) 在199 ...

最新文章

  1. iphone8p百度云认证_探秘百度数据工厂Pingo的多存储后端数据联合查询技术
  2. 20W奖金+实习机会:阿里巴巴达摩院最新时间序列赛事来了!
  3. SQL Server 索引结构及其使用(二)(转)
  4. 大数据、云计算构筑百姓安全防护网
  5. [Linux]core文件调试方法
  6. Docker:You cannot remove a running container
  7. si24r1程序_简要分析SI24R1替代兼容NRF24L01P
  8. python asyncio和celery对比_如何将Celery与asyncio结合? - python
  9. rnn中文语音识别java_语音识别算法阅读之RNN-T-2018
  10. linux分区label,label英文什么意思单词讲解(Linux中为一个分区设定label)
  11. 计算机科学家图灵,伟大的计算机科学家图灵
  12. centos 定时任务
  13. 电视盒子做文件共享服务器,【当贝市场】智能电视盒子和PC电脑文件共享教程...
  14. 深度学习CV(基础理论知识)
  15. 版本号命名规则 软件版本说明
  16. python疲劳检测代码_【君奉天|开发日记】疲劳驾驶检测
  17. 联想笔记本ideapad 320C 15IKB笔记本电脑改装总结
  18. 伺服电机步进电机区别
  19. split命令切割文件
  20. 2015年10月管理计算机,全国2015年10月高等教育自学考试管理系统中计算机应用考前密卷和答案...

热门文章

  1. 数字转化为十六进制 按位操作(详解)
  2. 安全面试、笔试、学习知识点大杂烩2
  3. Java版星球大战游戏(横向射击)
  4. uni H5微信内自定义分享朋友圈/好友带图片 标题
  5. MobPush智能精准推送,运营效果加倍
  6. Invoke 最简单用法
  7. 容智信息喜获36氪“中国企服软件金榜”与“数字化创新标杆奖”双重殊荣
  8. python 群和群之间的自动转发功能
  9. 各种测试的定义、负载测试和压力测试的区别
  10. tomcat9 java版本_Tomcat与JDK版本对应关系,Tomcat各版本特性