基于OpenFlow的SDN网络中,控制器可以通过OpenFlow的消息”OFPT_PACKET_OUT”,直接发送任意报文到网络的数据通路中。本文介绍了在ODL环境下如何直接通过控制器发送任意报文的两种方法。第一种使用控制器的RESTCONF接口packet-processing(2013-07-09),采用HTTP协议和JSON格式直接发送任意的报文到网络中;第二种方法编写内嵌于ODL的APP应用,采用PacketProcessingService服务接口发送任意报文。两种方法在ODL的版本Boron(硼)和Beryllium(铍)均测试通过。
OpenDaylight作为一款开源SDN网络控制器,依托于强大的社区支持以及功能特性,成为了目前主流的SDN网络控制器开发平台。不仅为开发者提供了大量的网络管理功能,而且藉由AD-SAL(API驱动的服务层)和MD-SAL(模型驱动的服务层), 给独立的网络应用提供了完善的二次开发接口。尤其是其提供的REST API接口, 基于HTTP协议及JSON/XML格式进行接口的调用和数据的获取,独立于具体的开发语言,其使用非常的方便。
1.1 YANG模型和NETCONF协议
YANG模型是一种数据建模语言,用来建模由NETCONF协议定义的配置数据和状态数据、远端过程调用(RPCs)、和NETCONF通知(notification), 具有良好的可读性和可扩展性。设备端和客户端都可以使用YANG进行数据的建模, 设备侧提供了YANG数据模型后,客户端可依据工具自动生成对应的访问模型代码,大大的节省开发工作量。其具体的定义可以参看RFC 6020: “YANG - A Data Modeling Language for the Network Configuration Protocol (NETCONF)” 。
NETCONF(Network Configuration Protocol,网络配置协议)是一种基于XML的网络管理协议,它提供了一种可编程的、对网络设备进行配置和管理的方法。用户可以通过该协议设置参数、获取参数值、获取统计信息等。NETCONF报文使用XML格式,具有强大的过滤能力,而且每一个数据项都有一个固定的元素名称和位置,这使得同一厂商的不同设备具有相同的访问方式和结果呈现方式,不同厂商之间的设备也可以经过映射XML得到相同的效果,这使得它在第三方软件的开发上非常便利,很容易开发出在混合不同厂商、不同设备的环境下的通用的管理软件。在管理软件的协助下,使用NETCONF功能会使网络设备的配置管理工作,变得更简单更高效。
NETCONF协议采用了分层结构,分成四层:内容层、操作层、RPC(Remote Procedure Call,远程调用)层和通信协议层。
其具体定义可看RFC 6241:” Network Configuration Protocol (NETCONF)”。
最初的网络管理协议SNMP也有对应的建模语言SMI。而操作ODL的应用采用的RPC接口、HTTP协议和XML格式数据,就构成了SOAP协议内容。
在ODL中,通过YANG模型来建模应用的配置数据和状态数据,以及RPC和Notification.
NETCONF/SNMP/YANG/SOAD/REST其对比关系如下图:
图 11 SNMP/NETCONF/SOAD/REST对比
1.2 报文发送接口packet-processing
在ODL中,安装了bundle” odl-restconf”和” odl-netconf-connector-all”后,打开浏览器的地址:
http://:8181/ apidoc/explorer/index.html
(以ODL版本Boron-SR1为例),就能看到相应的REST 公开的接口,其中RPC调用接口” packet-processing”提供了发送任意报文的功能, 此功能由openflowplugin提供, 如下图:
该接口的yang文件定义在ODL的bundle“openflowplugin”里面:openflowplugin/model/model-flow-service/src/main/yang/packet-processing.yang
此接口的yang RPC定义内容如下:
description "Sending packet out through openflow device.";
input {
uses inv:node-context-ref;
leaf connection-cookie {
type connection-cookie;
leaf egress {
type inv:node-connector-ref;
leaf buffer-id {
type uint32;
uses raw-packet;
uses action-type:action-list;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rpc
transmit
-
packet
{
description
"Sending packet out through openflow device."
;
input
{
uses
inv
:
node
-
context
-
ref
;
leaf
connection
-
cookie
{
type
connection
-
cookie
;
}
leaf
egress
{
type
inv
:
node
-
connector
-
ref
;
}
leaf
buffer
-
id
{
type
uint32
;
}
uses
raw
-
packet
;
uses
action
-
type
:
action
-
list
;
}
}
使用此接口时,需要构造:
raw-packet: 整个原始报文。报文内容包含数据链路层。Yang的定义为binary类型,采用HTTP协议发送时,此二进制内容以Base64编码为ASCII字符后发送
egress: 报文出口,这里指的是网络中交换机的端口,此端口格式为ODL中的node-connector-ref
node: 发送此报文的交换机,为ODL中的node-ref
action-list: 可选功能。如果提供action, 那么action-list的最后一个动作是output-action来发送报文,否则报文不能从交换机发送出去
Url: 发送的url为 http://:8181/restconf/operations/packet-processing:transmit-packet
1.3 PacketProcessingService服务
此服务由openflowplugin的模块model-flow-service提供。只有一个接口transmitPacket。定义如下:
2.2 REST接口之packet-processing
根据yang定义文件构造相应的请求报文即可。其中的payload原始数据为二进制数据,需要采用Base64编码为ASCII字符串序列。
构造JSON请求报文的java代码如下(采用Nayuki’s library for JSON):
public String buildInput_transmit_packet(){
byte[] rawPacket=getRawByte(xxx);
String nodeid="openflow:11";
String egress="openflow:11:2";
Map<String,Object> input = new TreeMap<String,Object>();
input.put("connection-cookie", 123456);
String strNode = "/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='"+nodeid+"']";
input.put("node",strNode);
input.put("egress",strNode + "/opendaylight-inventory:node-connector[opendaylight-inventory:id='"+ egress+"']");
//payload
input.put("payload", Base64Util.encode(rawPacket));
Map<String,Object> packet = new TreeMap<String,Object>();
packet.put("input", (Object)input);
return Json.serialize(packet);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public
String
buildInput_transmit_packet
(
)
{
byte
[
]
rawPacket
=
getRawByte
(
xxx
)
;
String
nodeid
=
"openflow:11"
;
String
egress
=
"openflow:11:2"
;
Map
<
String
,
Object
>
input
=
new
TreeMap
<
String
,
Object
>
(
)
;
input
.
put
(
"connection-cookie"
,
123456
)
;
String
strNode
=
"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='"
+
nodeid
+
"']"
;
input
.
put
(
"node"
,
strNode
)
;
input
.
put
(
"egress"
,
strNode
+
"/opendaylight-inventory:node-connector[opendaylight-inventory:id='"
+
egress
+
"']"
)
;
//payload
input
.
put
(
"payload"
,
Base64Util
.
encode
(
rawPacket
)
)
;
Map
<
String
,
Object
>
packet
=
new
TreeMap
<
String
,
Object
>
(
)
;
packet
.
put
(
"input"
,
(
Object
)
input
)
;
return
Json
.
serialize
(
packet
)
;
}
public void doTransmitPacket() throws Exception{
String strUrl = "http://<IP>:8181/restconf/operations/packet-processing:transmit-packet";
HttpUtil http = new HttpUtil(strUrl);
http.addBasicAuth("admin","admin");
http.addHeaderField("Accept","application/json");
http.addHeaderField("Content-type","application/json");
String strEntity = buildInput_transmit_packet();
System.out.println(strEntity);
http.addEntity(strEntity);
http.sendRequest(HttpUtil.Method.POST);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public
void
doTransmitPacket
(
)
throws
Exception
{
String
strUrl
=
"http://<IP>:8181/restconf/operations/packet-processing:transmit-packet"
;
HttpUtil
http
=
new
HttpUtil
(
strUrl
)
;
http
.
addBasicAuth
(
"admin"
,
"admin"
)
;
http
.
addHeaderField
(
"Accept"
,
"application/json"
)
;
http
.
addHeaderField
(
"Content-type"
,
"application/json"
)
;
String
strEntity
=
buildInput_transmit_packet
(
)
;
System
.
out
.
println
(
strEntity
)
;
http
.
addEntity
(
strEntity
)
;
http
.
sendRequest
(
HttpUtil
.
Method
.
POST
)
;
}
mvn archetype:generate -DarchetypeGroupId=org.opendaylight.controller \
-DarchetypeArtifactId=opendaylight-startup-archetype\
-DarchetypeVersion=1.2.1-Boron-SR1 \
-DarchetypeRepository=https://nexus.opendaylight.org/content/repositories/public/\
-DarchetypeCatalog=https://nexus.opendaylight.org/content/repositories/public/archetype-catalog.xml
mvn
archetype
:
generate
-
DarchetypeGroupId
=
org
.
opendaylight
.
controller
\
-
DarchetypeArtifactId
=
opendaylight
-
startup
-
archetype
\
-
DarchetypeVersion
=
1.2.1
-
Boron
-
SR1
\
-
DarchetypeRepository
=
https
:
//nexus.opendaylight.org/content/repositories/public/\
-
DarchetypeCatalog
=
https
:
//nexus.opendaylight.org/content/repositories/public/archetype-catalog.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
rpc
send
-
packet
{
input
{
leaf
rawpacket
{
type
binary
;
}
leaf
egress
{
type
inv
:
node
-
connector
-
ref
;
}
leaf
node
{
type
inv
:
node
-
ref
;
}
}
output
{
leaf
result
{
type
string
;
}
}
}
private void packetOut(NodeRef egressNodeRef, NodeConnectorRef egressNodeConnectorRef, byte[] payload) {
// Construct input for RPC call to packet processing service
TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(payload).setNode(egressNodeRef)
.setEgress(egressNodeConnectorRef).build();
packetProcessingService.transmitPacket(input);
private
void
packetOut
(
NodeRef
egressNodeRef
,
NodeConnectorRef
egressNodeConnectorRef
,
byte
[
]
payload
)
{
// Construct input for RPC call to packet processing service
TransmitPacketInput
input
=
new
TransmitPacketInputBuilder
(
)
.
setPayload
(
payload
)
.
setNode
(
egressNodeRef
)
.
setEgress
(
egressNodeConnectorRef
)
.
build
(
)
;
packetProcessingService
.
transmitPacket
(
input
)
;
}
@Override
public Future<RpcResult<SendPacketOutput>> sendPacket(SendPacketInput input) {
SendPacketOutputBuilder packetBuilder = new SendPacketOutputBuilder();
NodeConnectorRef egress = input.getEgress();
NodeRef node = input.getNode();
byte[] payload = input.getRawpacket();
packetOut(node,egress, payload); //send packet!!
packetBuilder.setResult("OK");
return RpcResultBuilder.success(packetBuilder.build()).buildFuture();
1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public
Future
<
RpcResult
<SendPacketOutput>
>
sendPacket
(
SendPacketInput
input
)
{
SendPacketOutputBuilder
packetBuilder
=
new
SendPacketOutputBuilder
(
)
;
NodeConnectorRef
egress
=
input
.
getEgress
(
)
;
NodeRef
node
=
input
.
getNode
(
)
;
byte
[
]
payload
=
input
.
getRawpacket
(
)
;
packetOut
(
node
,
egress
,
payload
)
;
//send packet!!
packetBuilder
.
setResult
(
"OK"
)
;
return
RpcResultBuilder
.
success
(
packetBuilder
.
build
(
)
)
.
buildFuture
(
)
;
}
4) 添加相应的依赖, 并编译运行
在api/pom.xml文件中添加依赖:model-inventory
在impl/pom.xml文件中添加依赖:openflowplugin-model的model-flow-service依赖
在feature/pom.xml添加上述2个依赖,
在feature/ src/main/features/features.xml文件中分别添加如下的内容:
<repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/${openflowplugin.version}/xml/features</repository>
<feature version='${openflowplugin.version}'>odl-openflowplugin-southbound</feature>
5) 运行测试
浏览器打开"
http://:8181/apidoc/explorer/index.html
"
找到” mypacket(2015-01-05)”,其中mypacket为第一步定义的项目名。
构造如下的JSON输入串,然后点击”try it out!”. 可以在Test-PC上运行wireshark看到我们发送的自定义报文。
{"input": {"egress": "/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:10']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:10:2']", "node": "/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:10']", "rawpacket": "QAwpyJZqAAwp06cxCABFAAA8fR0AAEABaCjAqAoVwKgKFggATJcCAP7EYWJjZGVmZ2hpamtsbW5vcHFyc3R1dndhYmNkZWZnaGk="}}
{
"input"
:
{
"egress"
:
"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:10']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:10:2']"
,
"node"
:
"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:10']"
,
"rawpacket"
:
"QAwpyJZqAAwp06cxCABFAAA8fR0AAEABaCjAqAoVwKgKFggATJcCAP7EYWJjZGVmZ2hpamtsbW5vcHFyc3R1dndhYmNkZWZnaGk="
}
}
发送报文是网络设备的最基本功能。本文我们介绍了ODL环境中的两种直接发送任意原始报文的方法。并且在ODL的版本Boron(硼)和Beryllium(铍)都测试通过。需要注意的是:通过HTTP构造请求时,二进制类型的原始报文需要编码为Base64类型,ODL系统会自动进行解码。
本文完整的代码:
https://github.com/siwind/mypacket
作者简介:
王寅庆, 目前在北京邮电大学网络技术研究院学习。 曾经供职于行业内某通信技术公司, 做过软件研发, 带领过项目团队。 关注于网络、SDN、大数据和信息安全等方面研究。
本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。
本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
本文链接
:
https://www.sdnlab.com/18092.html
Viagra 5 mg funziona https://chanchuoi.com/community/profile/canadianpharmacy/
Whoa plenty of beneficial advice!
(2023/05/21 04:25)
canadian pharmacies https://chanchuoi.com/community/profile/canadianpharmacy/
Perfectly expressed indeed. !
(2023/05/21 03:40)
canadian pharmaceuticals online https://www.careerstek.com/forum/profile/canadianpharmacy/
Awesome facts. Thanks a lot!
(2023/05/20 20:29)
详解:VirtIO Networking 虚…
VirtIO 由 Rusty Russell 开发,最初是为…
超文本传输协议(HTTP)全称Hyper Text Tr…
2011 年 8 月,主要由 VMware 与 Cisco 公…
互联网协议以TCP/IP最为人们所熟知,大多…
软硬件解耦的概念已提出多年,但如今的大…
fnedu_42c48d04fb
请问为什么这些交换机都没说支持 802.1 Qcr 呢?我觉得ATS是最容易实现的啊