+++ /dev/null
-/**
-* 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.factory;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionType;
-import org.openflow.protocol.action.OFActionVendor;
-import org.openflow.protocol.statistics.OFStatistics;
-import org.openflow.protocol.statistics.OFStatisticsType;
-import org.openflow.protocol.statistics.OFVendorStatistics;
-import org.openflow.protocol.vendor.OFByteArrayVendorData;
-import org.openflow.protocol.vendor.OFVendorData;
-import org.openflow.protocol.vendor.OFVendorDataType;
-import org.openflow.protocol.vendor.OFVendorId;
-
-
-/**
- * A basic OpenFlow factory that supports naive creation of both Messages and
- * Actions.
- *
- * @author David Erickson (daviderickson@cs.stanford.edu)
- * @author Rob Sherwood (rob.sherwood@stanford.edu)
- *
- */
-public class BasicFactory implements OFMessageFactory, OFActionFactory,
- OFStatisticsFactory, OFVendorDataFactory {
-
- private final OFVendorActionRegistry vendorActionRegistry;
-
- public BasicFactory() {
- vendorActionRegistry = OFVendorActionRegistry.getInstance();
- }
-
- /**
- * create and return a new instance of a message for OFType t. Also injects
- * factories for those message types that implement the *FactoryAware
- * interfaces.
- *
- * @return a newly created instance that may be modified / used freely by
- * the caller
- */
- @Override
- public OFMessage getMessage(OFType t) {
- OFMessage message = t.newInstance();
- injectFactories(message);
- return message;
- }
-
- @Override
- public List<OFMessage> parseMessage(ChannelBuffer data) throws MessageParseException {
- List<OFMessage> msglist = new ArrayList<OFMessage>();
- OFMessage msg = null;
-
- while (data.readableBytes() >= OFMessage.MINIMUM_LENGTH) {
- data.markReaderIndex();
- msg = this.parseMessageOne(data);
- if (msg == null) {
- data.resetReaderIndex();
- break;
- }
- else {
- msglist.add(msg);
- }
- }
-
- if (msglist.size() == 0) {
- return null;
- }
- return msglist;
-
- }
-
- public OFMessage parseMessageOne(ChannelBuffer data) throws MessageParseException {
- try {
- OFMessage demux = new OFMessage();
- OFMessage ofm = null;
-
- if (data.readableBytes() < OFMessage.MINIMUM_LENGTH)
- return ofm;
-
- data.markReaderIndex();
- demux.readFrom(data);
- data.resetReaderIndex();
-
- if (demux.getLengthU() > data.readableBytes())
- return ofm;
-
- ofm = getMessage(demux.getType());
- if (ofm == null)
- return null;
-
- injectFactories(ofm);
- ofm.readFrom(data);
- if (OFMessage.class.equals(ofm.getClass())) {
- // advance the position for un-implemented messages
- data.readerIndex(data.readerIndex()+(ofm.getLengthU() -
- OFMessage.MINIMUM_LENGTH));
- }
-
- return ofm;
- } catch (Exception e) {
- /* Write the offending data along with the error message */
- data.resetReaderIndex();
- String msg =
- "Message Parse Error for packet:" + dumpBuffer(data) +
- "\nException: " + e.toString();
- data.resetReaderIndex();
-
- throw new MessageParseException(msg, e);
- }
- }
-
-
-
-
- private void injectFactories(OFMessage ofm) {
- if (ofm instanceof OFActionFactoryAware) {
- ((OFActionFactoryAware)ofm).setActionFactory(this);
- }
- if (ofm instanceof OFMessageFactoryAware) {
- ((OFMessageFactoryAware)ofm).setMessageFactory(this);
- }
- if (ofm instanceof OFStatisticsFactoryAware) {
- ((OFStatisticsFactoryAware)ofm).setStatisticsFactory(this);
- }
- if (ofm instanceof OFVendorDataFactoryAware) {
- ((OFVendorDataFactoryAware)ofm).setVendorDataFactory(this);
- }
- }
-
- @Override
- public OFAction getAction(OFActionType t) {
- return t.newInstance();
- }
-
- @Override
- public List<OFAction> parseActions(ChannelBuffer data, int length) {
- return parseActions(data, length, 0);
- }
-
- @Override
- public List<OFAction> parseActions(ChannelBuffer data, int length, int limit) {
- List<OFAction> results = new ArrayList<OFAction>();
- OFAction demux = new OFAction();
- OFAction ofa;
- int end = data.readerIndex() + length;
-
- while (limit == 0 || results.size() <= limit) {
- if ((data.readableBytes() < OFAction.MINIMUM_LENGTH ||
- (data.readerIndex() + OFAction.MINIMUM_LENGTH) > end))
- return results;
-
- data.markReaderIndex();
- demux.readFrom(data);
- data.resetReaderIndex();
-
- if ((demux.getLengthU() > data.readableBytes() ||
- (data.readerIndex() + demux.getLengthU()) > end))
- return results;
-
- ofa = parseActionOne(demux.getType(), data);
- results.add(ofa);
- }
-
- return results;
- }
-
- private OFAction parseActionOne(OFActionType type, ChannelBuffer data) {
- OFAction ofa;
- data.markReaderIndex();
- ofa = getAction(type);
- ofa.readFrom(data);
-
- if(type == OFActionType.VENDOR) {
- OFActionVendor vendorAction = (OFActionVendor) ofa;
-
- OFVendorActionFactory vendorActionFactory = vendorActionRegistry.get(vendorAction.getVendor());
-
- if(vendorActionFactory != null) {
- // if we have a specific vendorActionFactory for this vendor id,
- // delegate to it for vendor-specific reparsing of the message
- data.resetReaderIndex();
- OFActionVendor newAction = vendorActionFactory.readFrom(data);
- if(newAction != null)
- ofa = newAction;
- }
- }
-
- if (OFAction.class.equals(ofa.getClass())) {
- // advance the position for un-implemented messages
- data.readerIndex(data.readerIndex()+(ofa.getLengthU() -
- OFAction.MINIMUM_LENGTH));
- }
- return ofa;
- }
-
- @Override
- public OFActionFactory getActionFactory() {
- return this;
- }
-
- @Override
- public OFStatistics getStatistics(OFType t, OFStatisticsType st) {
- return st.newInstance(t);
- }
-
- @Override
- public List<OFStatistics> parseStatistics(OFType t, OFStatisticsType st,
- ChannelBuffer data, int length) {
- return parseStatistics(t, st, data, length, 0);
- }
-
- /**
- * @param t
- * OFMessage type: should be one of stats_request or stats_reply
- * @param st
- * statistics type of this message, e.g., DESC, TABLE
- * @param data
- * buffer to read from
- * @param length
- * length of statistics
- * @param limit
- * number of statistics to grab; 0 == all
- *
- * @return list of statistics
- */
-
- @Override
- public List<OFStatistics> parseStatistics(OFType t, OFStatisticsType st,
- ChannelBuffer data, int length, int limit) {
- List<OFStatistics> results = new ArrayList<OFStatistics>();
- OFStatistics statistics = getStatistics(t, st);
-
- int start = data.readerIndex();
- int count = 0;
-
- while (limit == 0 || results.size() <= limit) {
- // TODO Create a separate MUX/DEMUX path for vendor stats
- if (statistics instanceof OFVendorStatistics)
- ((OFVendorStatistics)statistics).setLength(length);
-
- /**
- * can't use data.remaining() here, b/c there could be other data
- * buffered past this message
- */
- if ((length - count) >= statistics.getLength()) {
- if (statistics instanceof OFActionFactoryAware)
- ((OFActionFactoryAware)statistics).setActionFactory(this);
- statistics.readFrom(data);
- results.add(statistics);
- count += statistics.getLength();
- statistics = getStatistics(t, st);
- } else {
- if (count < length) {
- /**
- * Nasty case: partial/incomplete statistic found even
- * though we have a full message. Found when NOX sent
- * agg_stats request with wrong agg statistics length (52
- * instead of 56)
- *
- * just throw the rest away, or we will break framing
- */
- data.readerIndex(start + length);
- }
- return results;
- }
- }
- return results; // empty; no statistics at all
- }
-
-
- @Override
- public OFVendorData getVendorData(OFVendorId vendorId,
- OFVendorDataType vendorDataType) {
- if (vendorDataType == null)
- return null;
-
- return vendorDataType.newInstance();
- }
-
- /**
- * Attempts to parse and return the OFVendorData contained in the given
- * ChannelBuffer, beginning right after the vendor id.
- * @param vendor the vendor id that was parsed from the OFVendor message.
- * @param data the ChannelBuffer from which to parse the vendor data
- * @param length the length to the end of the enclosing message.
- * @return an OFVendorData instance
- */
- @Override
- public OFVendorData parseVendorData(int vendor, ChannelBuffer data,
- int length) {
- OFVendorDataType vendorDataType = null;
- OFVendorId vendorId = OFVendorId.lookupVendorId(vendor);
- if (vendorId != null) {
- data.markReaderIndex();
- vendorDataType = vendorId.parseVendorDataType(data, length);
- data.resetReaderIndex();
- }
-
- OFVendorData vendorData = getVendorData(vendorId, vendorDataType);
- if (vendorData == null)
- vendorData = new OFByteArrayVendorData();
-
- vendorData.readFrom(data, length);
-
- return vendorData;
- }
-
- public static String dumpBuffer(ChannelBuffer data) {
- // NOTE: Reads all the bytes in buffer from current read offset.
- // Set/Reset ReaderIndex if you want to read from a different location
- int len = data.readableBytes();
- StringBuffer sb = new StringBuffer();
- for (int i=0 ; i<len; i++) {
- if (i%32 == 0) sb.append("\n");
- if (i%4 == 0) sb.append(" ");
- sb.append(String.format("%02x", data.getUnsignedByte(i)));
- }
- return sb.toString();
- }
-
-}