| /** |
| * 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; |
| } |
| } |