OFMessage类是openflow 协议消息的基础类,该类包含了所有openflow消息都要使用到的ofp_header。
特定openflow 消息对OFMessage类进行继承和扩展,两者之间的关系如下图:
可见OFMessage基础类的重要性。
以下为带注解的源码:
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
* 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.
**/
package org.openflow.protocol; //源码包位置
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.packet.Ethernet;
import org.jboss.netty.buffer.ChannelBuffer;
import org.openflow.util.HexString;
import org.openflow.util.U16;
import org.openflow.util.U32;
import org.openflow.util.U8;
/**
* The base class for all OpenFlow protocol messages. This class contains the
* equivalent of the ofp_header which is present in all OpenFlow messages.
*
* @author David Erickson ([email protected]) - Feb 3, 2010
* @author Rob Sherwood ([email protected]) - Feb 3, 2010
*/
public class OFMessage {
public static byte OFP_VERSION = 0x01; //openflow协议版本 0x01表示 openflow spec 1.0
public static int MINIMUM_LENGTH = 8; //openflow最小消息长度,8字节,等于消息头大小
protected byte version; //openflow协议版本
protected OFType type; //openflow消息类型
protected short length; //openflow消息长度 包括ofp_header
protected int xid; //openflow消息传输id
/*
创建ConcurrentHashMap对象,ConcurrentHashMap是一个线程安全的Hash Table,
它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法
*/
private ConcurrentHashMap storage;
/*构造函数,storage初始化为null,版本号为1.0*/
public OFMessage() {
storage = null;
this.version = OFP_VERSION;
}
/*实例化ConcurrentHashMap对象*/
protected synchronized ConcurrentHashMap getMessageStore() {
if (storage == null) {
storage = new ConcurrentHashMap();;
}
return storage;
}
/**
* 获取openflow消息长度(short类型)
*/
public short getLength() {
return length;
}
/**
* 获取openflow消息长度 (unsigned short类型)
*/
public int getLengthU() {
return U16.f(length);
}
/**
* 设置消息长度(short类型)
*/
public OFMessage setLength(short length) {
this.length = length;
return this;
}
/**
* 设置消息长度(unsigned short类型)
*/
public OFMessage setLengthU(int length) {
this.length = U16.t(length);
return this;
}
/**
* 获取openflow消息类型
*/
public OFType getType() {
return type;
}
/**
* 设置openflow消息类型
*/
public void setType(OFType type) {
this.type = type;
}
/**
* 获取openflow消息版本号
*/
public byte getVersion() {
return version;
}
/**
* 设置openflow消息版本号
*/
public void setVersion(byte version) {
this.version = version;
}
/**
* 获取openflow消息传输id
*/
public int getXid() {
return xid;
}
/**
* 设置openflow消息传输id
*/
public void setXid(int xid) {
this.xid = xid;
}
/**
*从ChannelBuffer缓冲区读取消息
* ChannelBuffer是Netty中比较常用的一个类,其功能类似于字符数组,可以对其进行读写操作
*/
public void readFrom(ChannelBuffer data) {
this.version = data.readByte();
this.type = OFType.valueOf(data.readByte());
this.length = data.readShort();
this.xid = data.readInt();
}
/**
*将消息写入ChannelBuffer缓冲区
* @param data
*/
public void writeTo(ChannelBuffer data) {
data.writeByte(version);
data.writeByte(type.getTypeValue());
data.writeShort(length);
data.writeInt(xid);
}
/**
* 将openflow消息头部转换为字符串
*格式为:"ofmsg:v=$version;t=$type:l=$len:xid=$xid"
*/
public String toString() {
return "ofmsg" +
":v=" + U8.f(this.getVersion()) +
";t=" + this.getType() +
";l=" + this.getLengthU() +
";x=" + U32.f(this.getXid());
}
@Override
/*
*将openflow消息头部信息生成哈希码
*/
public int hashCode() {
final int prime = 97;
int result = 1;
result = prime * result + length;
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + version;
result = prime * result + xid;
return result;
}
/*
*判断两个openflow消息内容是否一样
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof OFMessage)) {
return false;
}
OFMessage other = (OFMessage) obj;
if (length != other.length) {
return false;
}
if (type == null) {
if (other.type != null) {
return false;
}
} else if (!type.equals(other.type)) {
return false;
}
if (version != other.version) {
return false;
}
if (xid != other.xid) {
return false;
}
return true;
}
/*
*将PACKET_IN, PACKET_OUT,FLOW_MOD消息中的关键信息及eth内容转换为字符串,并添加日期,标识等信息
*
*/
public static String getDataAsString(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
Ethernet eth;
StringBuffer sb = new StringBuffer("");
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
Date date = new Date();
sb.append(dateFormat.format(date));
sb.append(" ");
switch (msg.getType()) {
case PACKET_IN:
OFPacketIn pktIn = (OFPacketIn) msg;
sb.append("packet_in [ ");
sb.append(sw.getStringId()); //DPID
sb.append(" -> Controller");
sb.append(" ]");
sb.append("\ntotal length: ");
sb.append(pktIn.getTotalLength()); //消息总长度
sb.append("\nin_port: ");
sb.append(pktIn.getInPort()); //输入端口号
sb.append("\ndata_length: ");
sb.append(pktIn.getTotalLength() - OFPacketIn.MINIMUM_LENGTH); //除去消息头的数据的长度
sb.append("\nbuffer: ");
sb.append(pktIn.getBufferId()); //buffer id
// If the conext is not set by floodlight, then ignore.
if (cntx != null) {
// packet type icmp, arp, etc.
eth = IFloodlightProviderService.bcStore.get(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
if (eth != null)
sb.append(eth.toString());
}
break;
case PACKET_OUT:
OFPacketOut pktOut = (OFPacketOut) msg;
sb.append("packet_out [ ");
sb.append("Controller -> ");
sb.append(HexString.toHexString(sw.getId())); //DPID
sb.append(" ]");
sb.append("\nin_port: ");
sb.append(pktOut.getInPort()); //输入端口号
sb.append("\nactions_len: ");
sb.append(pktOut.getActionsLength()); //获取Actions长度
if (pktOut.getActions() != null) {
sb.append("\nactions: ");
sb.append(pktOut.getActions().toString()); //获取Actions内容
}
break;
case FLOW_MOD:
OFFlowMod fm = (OFFlowMod) msg;
sb.append("flow_mod [ ");
sb.append("Controller -> ");
sb.append(HexString.toHexString(sw.getId())); //DPID
sb.append(" ]");
// If the conext is not set by floodlight, then ignore.
if (cntx != null) {
eth = IFloodlightProviderService.bcStore.get(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
if (eth != null)
sb.append(eth.toString());
}
sb.append("\nADD: cookie: ");
sb.append(fm.getCookie()); //获取cookie 不太明白这是什么
sb.append(" idle: ");
sb.append(fm.getIdleTimeout()); //获取idle time
sb.append(" hard: ");
sb.append(fm.getHardTimeout()); //获取hard time
sb.append(" pri: ");
sb.append(fm.getPriority()); //获取优先级
sb.append(" buf: ");
sb.append(fm.getBufferId()); //获取buffer id
sb.append(" flg: ");
sb.append(fm.getFlags());
if (fm.getActions() != null) {
sb.append("\nactions: ");
sb.append(fm.getActions().toString()); //获取Actions内容
}
break;
default:
sb.append("[Unknown Packet]"); //未知消息
}
sb.append("\n\n");
return sb.toString();
}
public static byte[] getData(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
return OFMessage.getDataAsString(sw, msg, cntx).getBytes();
}
}
public boolean equals(Object obj)方法流控图
getDataAsString 方法流控图