大家好,又见面了,我是你们的朋友全栈君。
前面已经知道了Floodlight Controller是通过从SW发送LLDP帧来获得链路信息的,链路层发现协议(L2)是通过在本地网络中广播LLDP报文来通告自己的设备信息,从而服务于拓扑计算,(wikipedia:LLDP information is sent by devices from each of their interfaces at a fixed interval, in the form of an Ethernet frame. Each frame contains one LLDP Data Unit (LLDPDU). Each LLDPDU is a sequence of type-length-value (TLV) structures.)报文格式如下:
type-length-value 的设计很常见(比如netlink中attribute也是这种格式),这里的TLV结构是:
此时再看代码就很容易理解:
public class LLDPTLV {
protected byte type ;
protected short length ;
protected byte [] value ;
public byte getType() {
return type ;
}
public LLDPTLV setType( byte type) {
this . type = type;
return this ;
}
public short getLength() {
return length ;
}
public LLDPTLV setLength( short length) {
this . length = length;
return this ;
}
public byte [] getValue() {
return value ;
}
public LLDPTLV setValue( byte [] value) {
this . value = value;
return this ;
}
// serialization – Turn data into a stream of bytes
public byte [] serialize() {
// type = 7 bits
// info string length 9 bits, each value == byte
// info string
short scratch = ( short ) (((0x7f & this . type ) << 9) | (0x1ff & this . length ));
// 7 9 = 2B
byte [] data = new byte [2 this . length ];
ByteBuffer bb = ByteBuffer. wrap(data);
bb.putShort(scratch);
if ( this . value != null )
bb.put( this . value );
return data;
}
// deserialization – Turn a stream of bytes back into a copy of the original
// object.
public LLDPTLV deserialize(ByteBuffer bb) {
short sscratch;
sscratch = bb.getShort();
this . type = ( byte ) ((sscratch >> 9) & 0x7f);
this . length = ( short ) (sscratch & 0x1ff);
if ( this . length > 0) {
this . value = new byte [ this . length ];
// if there is an underrun just toss the TLV
if (bb.remaining() < this . length )
return null ;
bb.get( this . value );
}
return this ;
}
}
public class LLDP extends BasePacket {
protected LLDPTLV chassisId ;
protected LLDPTLV portId ;
protected LLDPTLV ttl ;
protected List<LLDPTLV> optionalTLVList ;
protected short ethType ;
//上述几个字段都是LLDP协议规定的
public LLDP() {
this . optionalTLVList = new ArrayList<LLDPTLV>();
this . ethType = Ethernet. TYPE_LLDP ; // 0x88cc
}
public LLDPTLV getChassisId() {
return chassisId ;
}
public LLDP setChassisId(LLDPTLV chassisId) {
this . chassisId = chassisId;
return this ;
}
public LLDPTLV getPortId() {
return portId ;
}
public LLDP setPortId(LLDPTLV portId) {
this . portId = portId;
return this ;
}
public LLDPTLV getTtl() {
return ttl ;
}
public LLDP setTtl(LLDPTLV ttl) {
this . ttl = ttl;
return this ;
}
public List<LLDPTLV> getOptionalTLVList() {
return optionalTLVList ;
}
public LLDP setOptionalTLVList(List<LLDPTLV> optionalTLVList) {
this . optionalTLVList = optionalTLVList;
return this ;
}
@Override
public byte [] serialize() {
int length = 2 this . chassisId .getLength() 2
this . portId .getLength() 2 this . ttl .getLength() 2;
for (LLDPTLV tlv : this . optionalTLVList ) {
length = 2 tlv.getLength();
}
byte [] data = new byte [length];
ByteBuffer bb = ByteBuffer. wrap(data);
bb.put( this . chassisId .serialize());
bb.put( this . portId .serialize());
bb.put( this . ttl .serialize());
for (LLDPTLV tlv : this . optionalTLVList ) {
bb.put(tlv.serialize());
}
bb.putShort(( short ) 0); // End of LLDPDU
if ( this . parent != null && this . parent instanceof Ethernet)
((Ethernet) this . parent ).setEtherType( ethType );
return data;
}
@Override
public IPacket deserialize( byte [] data, int offset, int length) {
ByteBuffer bb = ByteBuffer. wrap(data, offset, length);
LLDPTLV tlv;
do {
tlv = new LLDPTLV().deserialize(bb);
// if there was a failure to deserialize stop processing TLVs
if (tlv == null )
break ;
switch (tlv.getType()) {
case 0x0:
// can throw this one away, its just an end delimiter
break ;
case 0x1:
this . chassisId = tlv;
break ;
case 0x2:
this . portId = tlv;
break ;
case 0x3:
this . ttl = tlv;
break ;
default :
this . optionalTLVList .add(tlv);
break ;
}
} while (tlv.getType() != 0 && bb.hasRemaining());
return this ;
}
}
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/140278.html原文链接:https://javaforall.cn