一、基础要求
1)/home/用户名/学号/lab3/目录下的拓扑文件
#!/usr/bin/env python
from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSController
from mininet.node import CPULimitedHost, Host, Node
from mininet.node import OVSKernelSwitch, UserSwitch
from mininet.node import IVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.link import TCLink, Intf
from subprocess import call
def myNetwork():
net = Mininet( topo=None,
build=False,
ipBase='10.0.0.0/8')
info( '*** Adding controller\n' )
c0=net.addController(name='c0',
controller=Controller,
protocol='tcp',
port=6633)
info( '*** Add switches\n')
s1 = net.addSwitch('s1', cls=OVSKernelSwitch)
s2 = net.addSwitch('s2', cls=OVSKernelSwitch)
info( '*** Add hosts\n')
h1 = net.addHost('h1', cls=Host, ip='192.168.0.101/24', defaultRoute=None)
h2 = net.addHost('h2', cls=Host, ip='192.168.0.102/24', defaultRoute=None)
h3 = net.addHost('h3', cls=Host, ip='192.168.0.103/24', defaultRoute=None)
h4 = net.addHost('h4', cls=Host, ip='192.168.0.104/24', defaultRoute=None)
info( '*** Add links\n')
net.addLink(h1, s1)
net.addLink(h3, s1)
net.addLink(s1, s2)
net.addLink(s2, h2)
net.addLink(s2, h4)
info( '*** Starting network\n')
net.build()
info( '*** Starting controllers\n')
for controller in net.controllers:
controller.start()
info( '*** Starting switches\n')
net.get('s1').start([c0])
net.get('s2').start([c0])
info( '*** Post configure switches and hosts\n')
CLI(net)
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
myNetwork()
2)wireshark抓包的结果截图和对应的文字说明
Hello
控制器6633端口(我最高能支持OpenFlow 1.0) ---> 交换机57176端口
交换机57176端口(我最高能支持OpenFlow 1.3) ---> 控制器6633端口
于是双方建立连接,并使用OpenFlow 1.0
Features Request
控制器6633端口(我需要你的特征信息) ---> 交换机57176端口
Set Conig
控制器6633端口(请按照我给你的flag和max bytes of packet进行配置) ---> 交换机57176端口
Port Status
当交换机端口发生变化时,告知控制器相应的端口状态。
Features Reply
交换机57176端口(这是我的特征信息,请查收) ---> 控制器6633端口
Packet in
有两种情况会触发交换机向控制器发送 Packet-in 消息:
1、交换机查找流表,发现没有匹配条目时
2、 有匹配条目但是对应的action是OUTPUT=CONTROLLER时
交换机57178端口(有数据包进来,请指示)--- 控制器6633端口
Flow mod
控制器通过6633端口向交换机35334端口、交换机57176端口下发流表项,指导数据的转发处理
Packet out
控制器6633端口(请按照我给你的action进行处理) ---> 交换机57176端口
3)OpenFlow协议中交换机与控制器的消息交互过程,画出相关交互图或流程图
4)交换机与控制器建立通信时是使用TCP协议还是UDP协议?
使用的是TCP协议
二、进阶要求
Hello
/* Header on all OpenFlow packets. */
struct ofp_header {
uint8_t version; //版本号 /* OFP_VERSION. */
uint8_t type; //消息类型 /* One of the OFPT_ constants. */
uint16_t length; //长度 /* Length including this ofp_header. */
uint32_t xid; //id /* Transaction id associated with this packet.
Replies use the same id as was in the request
to facilitate pairing. */
};
Features Request
struct ofp_header {
uint8_t version; /* OFP_VERSION. */
uint8_t type; /* One of the OFPT_ constants. */
uint16_t length; /* Length including this ofp_header. */
uint32_t xid; /* Transaction id associated with this packet.
Replies use the same id as was in the request
to facilitate pairing. */
};
Set Config
/* Switch configuration. */
struct ofp_switch_config {
struct ofp_header header;
uint16_t flags; /* 指示交换机如何处理 IP 分片数据包OFPC_* flags. */
uint16_t miss_send_len; /* 发送数据包最多字节数 Max bytes of new flow that datapath should
send to the controller. */
};
Port Status
/* A physical port has changed in the datapath */
struct ofp_port_status {
struct ofp_header header;
uint8_t reason; /* One of OFPPR_*. */
uint8_t pad[7]; /* 对齐至64位Align to 64-bits. */
struct ofp_phy_port desc;
};
Features Reply
/* Switch features. */
struct ofp_switch_features {
struct ofp_header header;
uint64_t datapath_id; //唯一标识ID号/* Datapath unique ID. The lower 48-bits are for
a MAC address, while the upper 16-bits are
implementer-defined. */
uint32_t n_buffers; //缓冲区可缓存的最大数据包个数 /* Max packets buffered at once. */
uint8_t n_tables; //流表数量/* Number of tables supported by datapath. */
uint8_t pad[3]; /* Align to 64-bits. */
/* Features. */
uint32_t capabilities; //支持的特殊功能 /* Bitmap of support "ofp_capabilities". */
uint32_t actions; //支持的动作 /* Bitmap of supported "ofp_action_type"s. */
/* Port info.*/
struct ofp_phy_port ports[0]; //物理端口描述列表 /* Port definitions. The number of ports
is inferred from the length field in
the header. */
};
OFP_ASSERT(sizeof(struct ofp_switch_features) == 32);
Packet-in
/* Why is this packet being sent to the controller? */
enum ofp_packet_in_reason {
OFPR_NO_MATCH, /* No matching flow. */ //交换机查找流表,发现没有匹配条目时
OFPR_ACTION /* Action explicitly output to controller. */ //有匹配条目但是对应的action是OUTPUT=CONTROLLER时
};
/* Packet received on port (datapath -> controller). */
struct ofp_packet_in {
struct ofp_header header;
uint32_t buffer_id; //Packet-in消息所携带的数据包在交换机缓存区中的ID /* ID assigned by datapath. */
uint16_t total_len; //data字段的长度 /* Full length of frame. */
uint16_t in_port; //数据包进入交换机时的端口号 /* Port on which frame was received. */
uint8_t reason; //发送Packet-in消息的原因 /* Reason packet is being sent (one of OFPR_*) */
uint8_t pad;
uint8_t data[0]; //携带的数据包 /* Ethernet frame, halfway through 32-bit word,
so the IP header is 32-bit aligned. The
amount of data is inferred from the length
field in the header. Because of padding,
offsetof(struct ofp_packet_in, data) ==
sizeof(struct ofp_packet_in) - 2. */
};
OFP_ASSERT(sizeof(struct ofp_packet_in) == 20);
Flow-Mod
/* Flow setup and teardown (controller -> datapath). */
struct ofp_flow_mod {
struct ofp_header header;
struct ofp_match match; //流表的匹配域 /* Fields to match */
uint64_t cookie; // 流表项标识符 /* Opaque controller-issued identifier. */
/* Flow actions. */
uint16_t command; //可以是ADD,DELETE,DELETE-STRICT,MODIFY,MODIFY-STRICT /* One of OFPFC_*. */
uint16_t idle_timeout; //空闲超时时间 /* Idle time before discarding (seconds). */
uint16_t hard_timeout; //最大生存时间 /* Max time before discarding (seconds). */
uint16_t priority; //优先级,优先级高的流表项优先匹配 /* Priority level of flow entry. */
uint32_t buffer_id; //缓存区ID ,用于指定缓存区中的一个数据包按这个消息的action列表处理 /* Buffered packet to apply to (or -1).
Not meaningful for OFPFC_DELETE*. */
uint16_t out_port; //如果这条消息是用于删除流表则需要提供额外的匹配参数 /* For OFPFC_DELETE* commands, require
matching entries to include this as an
output port. A value of OFPP_NONE
indicates no restriction. */
uint16_t flags; //标志位,可以用来指示流表删除后是否发送flow‐removed消息,添加流表时是否检查流表重复项,添加的流表项是否为应急流表项。 /* One of OFPFF_*. */
struct ofp_action_header actions[0]; //action列表/* The action length is inferred
from the length field in the
header. */
};
OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72);
Packet-out
/* Send packet (controller -> datapath). */
struct ofp_packet_out {
struct ofp_header header;
uint32_t buffer_id; //交换机缓存区id,如果为-1则指定的为packet-out消息携带的data字段 /* ID assigned by datapath (-1 if none). */
uint16_t in_port; //如果buffer_id为‐1,并且action列表中指定了Output=TABLE的动作,in_port将作为data段数据包的额外匹配信息进行流表查询
/* Packet's input port (OFPP_NONE if none). */
uint16_t actions_len; //action列表的长度,可以用来区分actions和data段 /* Size of action array in bytes. */
struct ofp_action_header actions[0]; //动作列表 /* Actions. */
/* uint8_t data[0]; */ // 数据缓存区,可以存储一个以太网帧,可选 /* Packet data. The length is inferred
from the length field in the header.
(Only meaningful if buffer_id == -1.) */
};
OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
三、实验总结
这次实验主要是抓包软件获取控制器与交换机之间的通信数据,分析OpenFlow协议中交换机与控制器的消息交互过程。
搭建拓扑前就要把wireshark打开,才能抓到完整的包。通过分析openflow/include/openflow当中的openflow.h头文件,以及网上查找的资料,了解了控制器和交换机之间的通信。