/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford 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 net.floodlightcontroller.packet;
import java.nio.ByteBuffer;
/**
* This class is a Rapid Spanning Tree Protocol
* Bridge Protocol Data Unit
* @author alexreimers
*/
public class BPDU extends BasePacket {
public enum BPDUType {
CONFIG,
TOPOLOGY_CHANGE;
}
private final long destMac = 0x0180c2000000L; // 01-80-c2-00-00-00
// TODO - check this for RSTP
private LLC llcHeader;
private short protocolId = 0;
private byte version = 0;
private byte type;
private byte flags;
private byte[] rootBridgeId;
private int rootPathCost;
private byte[] senderBridgeId; // switch cluster MAC
private short portId; // port it was transmitted from
private short messageAge; // 256ths of a second
private short maxAge; // 256ths of a second
private short helloTime; // 256ths of a second
private short forwardDelay; // 256ths of a second
public BPDU(BPDUType type) {
rootBridgeId = new byte[8];
senderBridgeId = new byte[8];
llcHeader = new LLC();
llcHeader.setDsap((byte) 0x42);
llcHeader.setSsap((byte) 0x42);
llcHeader.setCtrl((byte) 0x03);
switch(type) {
case CONFIG:
this.type = 0x0;
break;
case TOPOLOGY_CHANGE:
this.type = (byte) 0x80; // 1000 0000
break;
default:
this.type = 0;
break;
}
}
@Override
public byte[] serialize() {
byte[] data;
// TODO check these
if (type == 0x0) {
// config
data = new byte[38];
} else {
// topology change
data = new byte[7]; // LLC + TC notification
}
ByteBuffer bb = ByteBuffer.wrap(data);
// Serialize the LLC header
byte[] llc = llcHeader.serialize();
bb.put(llc, 0, llc.length);
bb.putShort(protocolId);
bb.put(version);
bb.put(type);
if (type == 0x0) {
bb.put(flags);
bb.put(rootBridgeId, 0, rootBridgeId.length);
bb.putInt(rootPathCost);
bb.put(senderBridgeId, 0, senderBridgeId.length);
bb.putShort(portId);
bb.putShort(messageAge);
bb.putShort(maxAge);
bb.putShort(helloTime);
bb.putShort(forwardDelay);
}
return data;
}
@Override
public IPacket deserialize(byte[] data, int offset, int length) {
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
// LLC header
llcHeader.deserialize(data, offset, 3);
this.protocolId = bb.getShort();
this.version = bb.get();
this.type = bb.get();
// These fields only exist if it's a configuration BPDU
if (this.type == 0x0) {
this.flags = bb.get();
bb.get(rootBridgeId, 0, 6);
this.rootPathCost = bb.getInt();
bb.get(this.senderBridgeId, 0, 6);
this.portId = bb.getShort();
this.messageAge = bb.getShort();
this.maxAge = bb.getShort();
this.helloTime = bb.getShort();
this.forwardDelay = bb.getShort();
}
// TODO should we set other fields to 0?
return this;
}
public long getDestMac() {
return destMac;
}
}