首页 > 代码库 > LLDP报文格式

LLDP报文格式



     前面已经知道了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结构是:
技术分享
技术分享

此时再看代码就非常easy理解:
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 =http://www.mamicode.com/= byte
           // info string
           short scratch = (short) (((0x7f & this. type) << 9) | (0x1ff & this .length ));
           // 7+9 = 2B
           byte[] data =http://www.mamicode.com/ 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 =http://www.mamicode.com/ 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 ;
     }
}



LLDP报文格式