Performacne improvements via adding a netty-based openflowj and openflow plugin;... 09/809/3
authorColin Dixon <ckd@us.ibm.com>
Tue, 6 Aug 2013 15:30:53 +0000 (10:30 -0500)
committerColin Dixon <ckd@us.ibm.com>
Wed, 7 Aug 2013 22:04:04 +0000 (17:04 -0500)
This code builds, runs and switches can connect, but there are still a few bugs to work out. I'm quoting Anil Vishnoi below:

===

Now controller starts up fine, and also shows the switches on dashboard when i connect mininet to the controller. But I see following error and exception when i try pingall from mininet.

1)
2013-08-08 00:12:07.625 IST [New I/O server worker #1-2] INFO  o.o.c.p.o.i.OFStatisticsManager - Added Switch 00:00:00:00:00:00:00:01 to target pool
2013-08-08 00:12:09.695 IST [New I/O server worker #1-2] WARN  o.o.c.p.o.c.i.EnhancedSwitchHandler - Timeout while waiting for FLOW_MOD reply
2013-08-08 00:12:09.696 IST [New I/O server worker #1-2] WARN  o.o.c.f.i.ForwardingRulesManager - SDN Plugin failed to program the flow: FlowEntry[flowName = cbenchflow, groupName = cbenchpolicy, node = OF|00:00:00:00:00:00:00:01, flow = Flow[match = Match[[DL_SRC(16:2d:e9:46:41:90,null)]], actions = [DROP], priority = 111, id = 0, idleTimeout = 5, hardTimeout = 0]]. The failure is: Failed to add the flow: Request Timed Out
2013-08-08 00:12:09.696 IST [New I/O server worker #1-2] WARN  o.o.c.f.i.ForwardingRulesManager - Failed to install the entry: [Install = FlowEntry[flowName = cbenchflow, groupName = cbenchpolicy, node = OF|00:00:00:00:00:00:00:01, flow = Flow[match = Match[[DL_SRC(16:2d:e9:46:41:90,null)]], actions = [DROP], priority = 111, id = 0, idleTimeout = 5, hardTimeout = 0]] Original = FlowEntry[flowName = cbenchflow, groupName = cbenchpolicy, node = OF|00:00:00:00:00:00:00:01, flow = Flow[match = Match[[DL_SRC(16:2d:e9:46:41:90,null)]], actions = [DROP], priority = 111, id = 0, idleTimeout = 5, hardTimeout = 0]] cFlow = null rid = 0]. The failure is: Failed to add the flow: Request Timed Out
2013-08-08 00:12:09.697 IST [New I/O server worker #1-2] ERROR o.o.c.s.r.i.ReactiveForwardingService - Error in installing flow entry to node : OF|00:00:00:00:00:00:00:01

2)
2013-08-08 00:12:27.748 IST [Statistics Collector] WARN  o.o.c.p.o.c.i.EnhancedSwitchHandler - Timeout while waiting for STATS_REQUEST replies
2013-08-08 00:12:27.748 IST [Statistics Collector] WARN  o.o.c.p.o.i.OFStatisticsManager - Request Timed Out for (TABLE) from switch 00:00:00:00:00:00:00:01
2013-08-08 00:12:29.749 IST [Statistics Collector] WARN  o.o.c.p.o.c.i.EnhancedSwitchHandler - Timeout while waiting for STATS_REQUEST replies
2013-08-08 00:12:29.749 IST [Statistics Collector] WARN  o.o.c.p.o.i.OFStatisticsManager - Request Timed Out for (PORT) from switch 00:00:00:00:00:00:00:01
2013-08-08 00:12:31.750 IST [Statistics Collector] WARN  o.o.c.p.o.c.i.EnhancedSwitchHandler - Timeout while waiting for STATS_REQUEST replies
2013-08-08 00:12:31.750 IST [Statistics Collector] WARN  o.o.c.p.o.i.OFStatisticsManager - Request Timed Out for (FLOW) from switch 00:00:00:00:00:00:00:01
2013-08-08 00:12:33.751 IST [Statistics Collector] WARN  o.o.c.p.o.c.i.EnhancedSwitchHandler - Timeout while waiting for STATS_REQUEST replies

3)
2013-08-08 00:13:17.565 IST [New I/O server worker #1-2] ERROR o.o.c.s.i.internal.DataPacketService -
org.opendaylight.controller.sal.packet.PacketException: Illegal arguement/out of bound exception - data.length = 22 startOffset = 144 numBits 48
at org.opendaylight.controller.sal.packet.Packet.serialize(Packet.java:187) ~[na:na]
at org.opendaylight.controller.sal.packet.Packet.serialize(Packet.java:163) ~[na:na]
at org.opendaylight.controller.sal.implementation.internal.DataPacketService.encodeDataPacket(DataPacketService.java:505) ~[na:na]
at org.opendaylight.controller.arphandler.internal.ArpHandler.sendBcastARPRequest(ArpHandler.java:354) ~[na:na]
at org.opendaylight.controller.arphandler.internal.ArpHandler.handleARPPacket(ArpHandler.java:282) ~[na:na]
at org.opendaylight.controller.arphandler.internal.ArpHandler.receiveDataPacket(ArpHandler.java:548) ~[na:na]
at org.opendaylight.controller.sal.implementation.internal.DataPacketService.dispatchPacket(DataPacketService.java:159) ~[na:na]
at org.opendaylight.controller.sal.implementation.internal.DataPacketService.receiveDataPacket(DataPacketService.java:455) ~[na:na]
at org.opendaylight.controller.protocol_plugin.openflow.internal.DataPacketMuxDemux.receive(DataPacketMuxDemux.java:195) ~[na:na]
at org.opendaylight.controller.protocol_plugin.openflow.core.internal.EnhancedController.switchMessage(EnhancedController.java:598) ~[na:na]

Change-Id: I101a0b2a9993b0d9301ae4210da0be002d322e7f
Signed-off-by: Colin Dixon <ckd@us.ibm.com>
210 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/distribution/opendaylight/pom.xml
opendaylight/protocol_plugins/openflow/pom.xml
opendaylight/protocol_plugins/openflow_netty/pom.xml [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IDataPacketListen.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IDataPacketMux.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IInventoryShimExternalListener.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IInventoryShimInternalListener.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IRefreshInternalProvider.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IStatisticsListener.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IStatisticsServiceShimListener.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/ITopologyServiceShimListener.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IController.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageListener.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageReadWrite.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitch.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitchStateListener.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/EnhancedController.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/EnhancedSwitchHandler.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFChannelState.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFMessageDecoder.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFMessageEncoder.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OpenflowPipelineFactory.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/PriorityMessage.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/StatisticsCollector.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchEvent.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SynchronousMessage.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/TrafficStatisticsHandler.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DataPacketMuxDemux.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DataPacketServices.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DescStatisticsConverter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowStatisticsConverter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryService.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceHelper.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortConverter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortStatisticsConverter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServices.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Utils.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Error.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6StatsReply.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6StatsRequest.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerServiceTest.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow_netty/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java [new file with mode: 0644]
opendaylight/samples/northbound/loadbalancer/pom.xml
opendaylight/samples/reactiveforwarding/pom.xml [new file with mode: 0644]
opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/LBConst.java [new file with mode: 0644]
opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/LBUtil.java [new file with mode: 0644]
opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/entities/Client.java [new file with mode: 0644]
opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/entities/VIP.java [new file with mode: 0644]
opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/internal/Activator.java [new file with mode: 0644]
opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/internal/ReactiveForwardingService.java [new file with mode: 0644]
third-party/openflowj_netty/LICENSE [new file with mode: 0644]
third-party/openflowj_netty/Makefile [new file with mode: 0644]
third-party/openflowj_netty/README [new file with mode: 0644]
third-party/openflowj_netty/eclipse_codestyle.xml [new file with mode: 0644]
third-party/openflowj_netty/lib/commons-cli-1.2.jar [new file with mode: 0644]
third-party/openflowj_netty/lib/junit-4.8.1.jar [new file with mode: 0644]
third-party/openflowj_netty/pom.xml [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/Instantiable.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFBarrierReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFBarrierRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFEchoReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFEchoRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFError.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFeaturesReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFeaturesRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFlowMod.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFlowRemoved.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFGetConfigReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFGetConfigRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFHello.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatch.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatchBeanInfo.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMessage.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMessageContextStore.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketIn.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketOut.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketQueue.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPhysicalPort.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPort.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPortMod.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPortStatus.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueProp.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFSetConfig.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFSwitchConfig.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFType.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFVendor.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/Wildcards.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFAction.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayer.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayerDestination.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayerSource.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionEnqueue.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerAddress.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerDestination.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerSource.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkTypeOfService.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionOutput.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionStripVirtualLan.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayer.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayerDestination.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayerSource.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionType.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVendor.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVirtualLanIdentifier.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVirtualLanPriorityCodePoint.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/BasicFactory.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/MessageParseException.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFActionFactory.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFActionFactoryAware.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFMessageFactory.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFMessageFactoryAware.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFStatisticsFactory.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFStatisticsFactoryAware.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsReply.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsRequest.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFStatistics.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFStatisticsType.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFTableStatistics.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFVendorStatistics.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorId.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/HexString.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/IProducer.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/LRULinkedHashMap.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/ProducerConsumer.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/StringByteSerializer.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/U16.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/U32.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/U64.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/U8.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/util/Unsigned.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/BasicFactoryTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFActionTypeTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFErrorTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFMatchTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPacketOutTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPortConfigTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPortStatusTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFSetConfigTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFTypeTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFVendorTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/WildcardsTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/MockVendorAction.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/util/HexStringTest.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/util/OFTestCase.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/util/U16Test.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/util/U32Test.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/util/U64Test.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/util/U8Test.java [new file with mode: 0644]
third-party/openflowj_netty/src/test/java/org/openflow/util/UnsignedTest.java [new file with mode: 0644]

index f5fcdbd3d5c33dc56c4dfa13fc7dc4f851fbb985..0aa28cefc6852d55672f564c5e95e512f9da546f 100644 (file)
@@ -39,6 +39,7 @@
     <jersey.version>1.17</jersey.version>
     <virgo.version>3.6.0.RELEASE</virgo.version>
     <geminiweb.version>2.2.0.RELEASE</geminiweb.version>
+    <netty.version>3.2.6.Final</netty.version>
     <checkstyle.version>2.10</checkstyle.version>
     <testvm.argLine>-Xmx1024m -XX:MaxPermSize=256m</testvm.argLine>
   </properties>
       <artifactId>jersey-json</artifactId>
       <version>${jersey.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.jboss.netty</groupId>
+      <artifactId>netty</artifactId>
+      <version>${netty.version}</version>
+    </dependency>
   </dependencies>
 </project>
index 1833b4ae592fa5867ccb58730dd8a7bb4feccf21..63278f719d750a55a576ee4ccf43ce87d3a778ad 100644 (file)
@@ -65,6 +65,7 @@
     <module>../../security</module>
 
     <module>../../../third-party/openflowj</module>
+    <module>../../../third-party/openflowj_netty</module>
     <module>../../../third-party/net.sf.jung2</module>
     <module>../../../third-party/jersey-servlet</module>
 
 
     <!-- Southbound bundles -->
     <module>../../protocol_plugins/openflow</module>
+    <module>../../protocol_plugins/openflow_netty</module>
     <module>../../protocol_plugins/stub</module>
 
     <!-- Samples -->
     <module>../../samples/simpleforwarding</module>
     <module>../../samples/loadbalancer</module>
     <module>../../samples/northbound/loadbalancer</module>
+    <module>../../samples/reactiveforwarding</module>
     <module>../../commons/concepts</module>
     <module>../../commons/integrationtest</module>
     <module>../../commons/checkstyle</module>
index 373d67dab15976a117d15a989d716948cf42621b..569c38e7681d92ce73bf18fe4c4c46c0749dd716 100644 (file)
             <Embed-Transitive>
               false
             </Embed-Transitive>
+<!-- uncomment to switch back to non-netty
             <Bundle-Activator>
               org.opendaylight.controller.protocol_plugin.openflow.internal.Activator
             </Bundle-Activator>
+-->
           </instructions>
           <manifestLocation>${project.basedir}/META-INF</manifestLocation>
         </configuration>
diff --git a/opendaylight/protocol_plugins/openflow_netty/pom.xml b/opendaylight/protocol_plugins/openflow_netty/pom.xml
new file mode 100644 (file)
index 0000000..25849ad
--- /dev/null
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+  <artifactId>protocol_plugins.openflow_netty</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <profiles>
+    <profile>
+      <id>jenkins</id>
+      <activation>
+        <property>
+          <name>env.BUILD_NUMBER</name>
+        </property>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>cobertura-maven-plugin</artifactId>
+            <version>2.5.1</version>
+            <configuration>
+              <formats>
+                <format>xml</format>
+              </formats>
+            </configuration>
+            <executions>
+              <execution>
+                <phase>package</phase>
+                <goals>
+                  <goal>cobertura</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              org.opendaylight.controller.sal.packet,
+              org.opendaylight.controller.sal.action,
+              org.opendaylight.controller.sal.discovery,
+              org.opendaylight.controller.sal.topology,
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.sal.flowprogrammer,
+              org.opendaylight.controller.sal.reader,
+              org.opendaylight.controller.sal.inventory,
+              org.opendaylight.controller.sal.match,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.protocol_plugin.openflow.core,
+              org.apache.commons.lang3.builder,
+              org.apache.commons.lang3.tuple,
+              org.apache.felix.dm,
+              org.slf4j,
+              org.eclipse.osgi.framework.console,
+              org.osgi.framework,
+              javax.net.ssl,
+              org.jboss.netty.*
+            </Import-Package>
+            <Export-Package>
+              org.opendaylight.controller.protocol_plugin.openflow.core.internal,
+              org.opendaylight.controller.protocol_plugin.openflow.core
+            </Export-Package>
+            <Embed-Dependency>
+              org.openflow.openflowj_netty,org.jboss.netty;type=!pom;inline=false
+            </Embed-Dependency>
+            <Embed-Transitive>
+              false
+            </Embed-Transitive>
+            <Bundle-Activator>
+              <!--  TODO : UNCOMMENT THIS TO START NETTY-PLUGIN DURING RUNTIME  -->
+              org.opendaylight.controller.protocol_plugin.openflow.internal.Activator
+            </Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.thirdparty</groupId>
+      <artifactId>org.openflow.openflowj_netty</artifactId>
+      <version>1.0.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.netty</groupId>
+      <artifactId>netty</artifactId>
+      <version>3.2.6.Final</version>
+    </dependency>
+
+  </dependencies>
+</project>
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IDataPacketListen.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IDataPacketListen.java
new file mode 100644 (file)
index 0000000..300967e
--- /dev/null
@@ -0,0 +1,39 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ * @file   IDataPacketListen.java
+ *
+ * @brief  Interface to dispatch locally in the protocol plugin the
+ * data packets, intended especially for Discovery, main difference
+ * here with the analogous of SAL is that this is Global
+ * inherently
+ *
+ */
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.packet.PacketResult;
+
+/**
+ * Interface to dispatch locally in the protocol plugin the
+ * data packets, intended especially for Discovery, main difference
+ * here with the analogous of SAL is that this is Global
+ * inherently.
+ */
+public interface IDataPacketListen {
+    /**
+     * Dispatch received data packet
+     *
+     * @param inPkt
+     *            The incoming raw packet
+     * @return Possible results for Data packet processing handler
+     */
+    public PacketResult receiveDataPacket(RawPacket inPkt);
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IDataPacketMux.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IDataPacketMux.java
new file mode 100644 (file)
index 0000000..747a8fb
--- /dev/null
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+/**
+ * @file   IDataPacketMux.java
+ *
+ * @brief  Simple wrapped interface for the IPluginInDataPacketService
+ * which will be only exported by DataPacketServices mux/demux
+ * component and will be only accessible by the openflow protocol
+ * plugin
+ */
+
+import org.opendaylight.controller.sal.packet.IPluginInDataPacketService;
+
+/**
+ * Simple wrapped interface for the IPluginInDataPacketService
+ * which will be only exported by DataPacketServices mux/demux
+ * component and will be only accessible by the openflow protocol
+ * plugin
+ */
+public interface IDataPacketMux extends IPluginInDataPacketService {
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java
new file mode 100644 (file)
index 0000000..3071765
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
+
+/**
+ * Interface which defines the methods exposed by the Flow Programmer Notifier.
+ * Their implementation relays the asynchronous messages received from the
+ * network nodes to the the SAL Flow Programmer Notifier Service on the proper
+ * container.
+ */
+public interface IFlowProgrammerNotifier extends
+        IPluginOutFlowProgrammerService {
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IInventoryShimExternalListener.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IInventoryShimExternalListener.java
new file mode 100644 (file)
index 0000000..df03a04
--- /dev/null
@@ -0,0 +1,18 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+/**
+ * Wrapper of Interface that provides inventory updates locally in the protocol
+ * plugin.
+ */
+public interface IInventoryShimExternalListener extends
+        IInventoryShimInternalListener {
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IInventoryShimInternalListener.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IInventoryShimInternalListener.java
new file mode 100644 (file)
index 0000000..cabc36b
--- /dev/null
@@ -0,0 +1,47 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+
+/**
+ * The Interface provides inventory updates to inventory listeners within the
+ * protocol plugin
+ */
+public interface IInventoryShimInternalListener {
+    /**
+     * Updates node and its properties
+     *
+     * @param node             {@link org.opendaylight.controller.sal.core.Node} being updated
+     * @param type           {@link org.opendaylight.controller.sal.core.UpdateType}
+     * @param props           set of {@link org.opendaylight.controller.sal.core.Property} such as
+     *                         {@link org.opendaylight.controller.sal.core.Description} and/or
+     *                         {@link org.opendaylight.controller.sal.core.Tier} etc.
+     */
+    public void updateNode(Node node, UpdateType type, Set<Property> props);
+
+    /**
+     * Updates node connector and its properties
+     *
+     * @param nodeConnector    {@link org.opendaylight.controller.sal.core.NodeConnector} being updated
+     * @param type           {@link org.opendaylight.controller.sal.core.UpdateType}
+     * @param props           set of {@link org.opendaylight.controller.sal.core.Property} such as
+     *                         {@link org.opendaylight.controller.sal.core.Description} and/or
+     *                         {@link org.opendaylight.controller.sal.core.State} etc.
+     */
+    public void updateNodeConnector(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props);
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IOFStatisticsManager.java
new file mode 100644 (file)
index 0000000..6638fcf
--- /dev/null
@@ -0,0 +1,108 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import java.util.List;
+
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+
+/**
+ * Interface to expose the openflow statistics collected on the switches
+ */
+public interface IOFStatisticsManager {
+    /**
+     * Return all the statistics for all the flows present on the specified switch
+     *
+     * @param switchId the openflow datapath id
+     * @return    the list of openflow statistics
+     */
+    List<OFStatistics> getOFFlowStatistics(Long switchId);
+
+    /**
+     * Return all the statistics for all the flows present on the specified switch
+     *
+     * @param switchId the openflow datapath id
+     * @param ofMatch the openflow match to query. If null, the query is intended for all the flows
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> getOFFlowStatistics(Long switchId, OFMatch ofMatch);
+
+    /**
+     * Return the description statistics for the specified switch.
+     *
+     * @param switchId the openflow datapath id
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> getOFDescStatistics(Long switchId);
+
+    /**
+     * Return the flow table statistics for the specified switch.
+     *
+     * @param switchId the openflow datapath id
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> getOFTableStatistics(Long switchId);
+
+    /**
+     * Returns the statistics for all the ports on the specified switch
+     *
+     * @param switchId the openflow datapath id
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> getOFPortStatistics(Long switchId);
+
+    /**
+     * Returns the statistics for the specified switch port
+     *
+     * @param switchId the openflow datapath id
+     * @param portId the openflow switch port id
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> getOFPortStatistics(Long switchId, short portId);
+
+    /**
+     * Returns the number of flows installed on the switch
+     *
+     * @param switchId the openflow datapath id
+     * @return the number of flows installed on the switch
+     */
+    int getFlowsNumber(long switchId);
+
+    /**
+     * Send a statistics request message to the specified switch and returns
+     * the switch response. It blocks the caller until the response has arrived
+     * from the switch or the request has timed out
+     *
+     * @param switchId the openflow datapath id of the target switch
+     * @param statType the openflow statistics type
+     * @param target the target object. For flow statistics it is the OFMatch.
+     *                  For port statistics, it is the port id. If null the query
+     *                  will be performed for all the targets for the specified
+     *                  statistics type.
+     *
+     * @param timeout the timeout in milliseconds the system will wait for a response
+     *           from the switch, before declaring failure
+     * @return the list of openflow statistics
+     */
+    List<OFStatistics> queryStatistics(Long switchId,
+            OFStatisticsType statType, Object target);
+
+    /**
+     * Returns the averaged transmit rate for the passed switch port
+     *
+     * @param switchId the openflow datapath id of the target switch
+     * @param portId the openflow switch port id
+     * @return the median transmit rate in bits per second
+     */
+    long getTransmitRate(Long switchId, Short port);
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IPluginReadServiceFilter.java
new file mode 100644 (file)
index 0000000..a000024
--- /dev/null
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
+
+/**
+ * Interface to serve the hardware information requests coming from SAL
+ * It is implemented by the respective OF1.0 plugin component
+ *
+ */
+public interface IPluginReadServiceFilter {
+    /**
+     * Returns the hardware image for the specified flow
+     * on the specified network node for the passed container
+     *
+     * @param container
+     * @param node
+     * @param flow
+     * @param cached
+     * @return
+     */
+    public FlowOnNode readFlow(String container, Node node, Flow flow,
+            boolean cached);
+
+    /**
+     * Returns the hardware view of all the flow installed
+     * on the specified network node for the passed container
+     *
+     * @param container
+     * @param node
+     * @param cached
+     * @return
+     */
+    public List<FlowOnNode> readAllFlow(String container, Node node,
+            boolean cached);
+
+    /**
+     * Returns the description of the network node as provided by the node itself
+     *
+     * @param node
+     * @param cached
+     * @return
+     */
+    public NodeDescription readDescription(Node node, boolean cached);
+
+    /**
+     * Returns the hardware view of the specified network node connector
+     * for the given container
+     * @param node
+     * @return
+     */
+    public NodeConnectorStatistics readNodeConnector(String container,
+            NodeConnector nodeConnector, boolean cached);
+
+    /**
+     * Returns the hardware info for all the node connectors on the
+     * specified network node for the given container
+     *
+     * @param node
+     * @return
+     */
+    public List<NodeConnectorStatistics> readAllNodeConnector(String container,
+            Node node, boolean cached);
+
+    /**
+     * Returns the average transmit rate for the specified node conenctor on
+     * the given container. If the node connector does not belong to the passed
+     * container a zero value is returned
+     *
+     * @param container
+     * @param nodeConnector
+     * @return tx rate [bps]
+     */
+    public long getTransmitRate(String container, NodeConnector nodeConnector);
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IRefreshInternalProvider.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IRefreshInternalProvider.java
new file mode 100644 (file)
index 0000000..21efae3
--- /dev/null
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+/**
+ * @file       IRefreshInternalProvider.java
+ *
+ * @brief      Topology refresh notifications requested by application
+ *             to be fetched from the plugin
+ *
+ * For example, an application that has been started late, will want to
+ * be up to date with the latest topology.  Hence, it requests for a
+ * topology refresh from the plugin.
+ */
+
+/**
+ * Topology refresh requested by the application from the plugin
+ *
+ */
+
+public interface IRefreshInternalProvider {
+
+    /**
+     * @param containerName
+     */
+    public void requestRefresh(String containerName);
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IStatisticsListener.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IStatisticsListener.java
new file mode 100644 (file)
index 0000000..b93d8d5
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+
+/**
+ * Interface which defines the api which gets called when the information
+ * contained in the OF description statistics reply message from a network
+ * is updated with new one.
+ */
+public interface IStatisticsListener {
+    public void descriptionRefreshed(Long switchId,
+                    OFDescriptionStatistics description);
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IStatisticsServiceShimListener.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IStatisticsServiceShimListener.java
new file mode 100644 (file)
index 0000000..1105239
--- /dev/null
@@ -0,0 +1,43 @@
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import java.util.List;
+
+import org.openflow.protocol.statistics.OFStatistics;
+
+/**
+ * @file   IStatisticsShimListener.java
+ *
+ * @brief  Statistics notifications provided by SAL toward the application
+ *
+ * For example an application that wants to keep up to date with the
+ * updates coming from SAL it will register in the OSGi service
+ * registry this interface (on a per-container base) and SAL will call it
+ * providing the update
+ */
+
+/**
+ * Statistics notifications provided by SAL toward the application
+ *
+ */
+public interface IStatisticsServiceShimListener {
+
+    /**
+     * Called to update statistics
+     *
+     * @param
+     * @param
+     * @param
+     */
+    public void flowStatisticsUpdate(Long switchId,
+                        List<OFStatistics> value, String containerName);
+
+    public void descStatisticsUpdate(Long switchId,
+                        List<OFStatistics> value, String containerName);
+
+    public void portStatisticsUpdate(Long switchId,
+                        List<OFStatistics> value, String containerName);
+
+    public void flowTableStatisticsUpdate(Long switchId,
+                        List<OFStatistics> value, String containerName);
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/ITopologyServiceShimListener.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/ITopologyServiceShimListener.java
new file mode 100644 (file)
index 0000000..eaff585
--- /dev/null
@@ -0,0 +1,47 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.Edge;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+
+/**
+ * The Interface provides Edge updates to the topology listeners
+ */
+public interface ITopologyServiceShimListener {
+    /**
+     * Called to update on Edge in the topology graph
+     *
+     * @param edge             {@link org.opendaylight.controller.sal.core.Edge} being updated
+     * @param type           {@link org.opendaylight.controller.sal.core.UpdateType}
+     * @param props           set of {@link org.opendaylight.controller.sal.core.Property} like
+     *                         {@link org.opendaylight.controller.sal.core.Bandwidth} and/or
+     *                         {@link org.opendaylight.controller.sal.core.Latency} etc.
+     */
+    public void edgeUpdate(Edge edge, UpdateType type, Set<Property> props);
+
+    /**
+     * Called when an Edge utilization is above the safe threshold configured
+     * on the controller
+     * @param {@link org.opendaylight.controller.sal.core.Edge}
+     */
+    public void edgeOverUtilized(Edge edge);
+
+    /**
+     * Called when the Edge utilization is back to normal, below the safety
+     * threshold level configured on the controller
+     *
+     * @param {@link org.opendaylight.controller.sal.core.Edge}
+     */
+    public void edgeUtilBackToNormal(Edge edge);
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IController.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IController.java
new file mode 100644 (file)
index 0000000..4920bb4
--- /dev/null
@@ -0,0 +1,66 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core;
+
+import java.net.InetAddress;
+import java.util.Map;
+
+import org.openflow.protocol.OFType;
+
+/**
+ * This interface defines an abstraction of the Open Flow Controller that allows applications to control and manage the Open Flow switches.
+ *
+ */
+public interface IController {
+
+    /**
+     * Allows application to start receiving OF messages received from switches.
+     * @param type the type of OF message that applications want to receive
+      * @param listener: Object that implements the IMessageListener
+     */
+    public void addMessageListener(OFType type, IMessageListener listener);
+
+    /**
+     * Allows application to stop receiving OF message received from switches.
+     * @param type The type of OF message that applications want to stop receiving
+     * @param listener The object that implements the IMessageListener
+     */
+    public void removeMessageListener(OFType type, IMessageListener listener);
+
+    /**
+     * Allows application to start receiving switch state change events.
+     * @param listener The object that implements the ISwitchStateListener
+     */
+    public void addSwitchStateListener(ISwitchStateListener listener);
+
+    /**
+     * Allows application to stop receiving switch state change events.
+     * @param listener The object that implements the ISwitchStateListener
+     */
+    public void removeSwitchStateListener(ISwitchStateListener listener);
+
+    /**
+     * Returns a map containing all the OF switches that are currently connected to the Controller.
+     * @return Map of ISwitch
+     */
+    public Map<Long, ISwitch> getSwitches();
+
+    /**
+     * Returns the ISwitch of the given switchId.
+     *
+     * @param switchId The switch ID
+     * @return ISwitch if present, null otherwise
+     */
+    public ISwitch getSwitch(Long switchId);
+
+    public InetAddress getControllerIdForSwitch(Long id);
+
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageListener.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageListener.java
new file mode 100644 (file)
index 0000000..aed19db
--- /dev/null
@@ -0,0 +1,26 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core;
+
+import org.openflow.protocol.OFMessage;
+
+/**
+ * Interface to be implemented by applications that want to receive OF messages.
+ *
+ */
+public interface IMessageListener {
+    /**
+     * This method is called by the Controller when a message is received from a switch.
+     * Application who is interested in receiving OF Messages needs to implement this method.
+     * @param sw The ISwitch which sent the OF message
+     * @param msg The OF message
+     */
+    public void receive(ISwitch sw, OFMessage msg);
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageReadWrite.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageReadWrite.java
new file mode 100644 (file)
index 0000000..8cfad48
--- /dev/null
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core;
+
+import java.util.List;
+
+import org.openflow.protocol.OFMessage;
+
+/**
+ * This interface defines low level routines to read/write messages on an open
+ * socket channel. If secure communication is desired, these methods also perform
+ * encryption and decryption of the network data.
+ */
+public interface IMessageReadWrite {
+    /**
+     * Sends the OF message out over the socket channel. For secure
+     * communication, the data will be encrypted.
+     *
+     * @param msg OF message to be sent
+     * @throws Exception
+     */
+    public void asyncSend(OFMessage msg) throws Exception;
+
+    /**
+     * Resumes sending the remaining messages in the outgoing buffer
+     * @throws Exception
+     */
+    public void resumeSend() throws Exception;
+
+    /**
+     * Reads the incoming network data from the socket and retrieves the OF
+     * messages. For secure communication, the data will be decrypted first.
+     *
+     * @return list of OF messages
+     * @throws Exception
+     */
+    public List<OFMessage> readMessages() throws Exception;
+
+    /**
+     * Proper clean up when the switch connection is closed
+     *
+     * @return
+     * @throws Exception
+     */
+    public void stop() throws Exception;
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitch.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitch.java
new file mode 100644 (file)
index 0000000..5f804ec
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core;
+
+import java.net.SocketAddress;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFStatisticsRequest;
+
+/**
+ * This interface defines an abstraction of an Open Flow Switch.
+ *
+ */
+public interface ISwitch {
+    /**
+     * Gets a unique XID.
+     *
+     * @return XID
+     */
+    public int getNextXid();
+
+    /**
+     * Returns the Switch's ID.
+     *
+     * @return the Switch's ID
+     */
+    public Long getId();
+
+    /**
+     * Returns the Switch's table numbers supported by datapath
+     *
+     * @return the tables
+     */
+    public Byte getTables();
+
+    /**
+     * Returns the Switch's bitmap of supported ofp_action_type
+     *
+     * @return the actions
+     */
+    public Integer getActions();
+
+    /**
+     * Returns the Switch's bitmap of supported ofp_capabilities
+     *
+     * @return the capabilities
+     */
+    public Integer getCapabilities();
+
+    /**
+     * Returns the Switch's buffering capacity in Number of Pkts
+     *
+     * @return the buffers
+     */
+    public Integer getBuffers();
+
+    /**
+     * Returns the Date when the switch was connected.
+     *
+     * @return Date The date when the switch was connected
+     */
+    public Date getConnectedDate();
+
+    /**
+     * This method puts the message in an outgoing priority queue with normal
+     * priority. It will be served after high priority messages. The method
+     * should be used for non-critical messages such as statistics request,
+     * discovery packets, etc. An unique XID is generated automatically and
+     * inserted into the message.
+     *
+     * @param msg
+     *            The OF message to be sent
+     * @return The XID used
+     */
+    public Integer asyncSend(OFMessage msg);
+
+    /**
+     * This method puts the message in an outgoing priority queue with normal
+     * priority. It will be served after high priority messages. The method
+     * should be used for non-critical messages such as statistics request,
+     * discovery packets, etc. The specified XID is inserted into the message.
+     *
+     * @param msg
+     *            The OF message to be Sent
+     * @param xid
+     *            The XID to be used in the message
+     * @return The XID used
+     */
+    public Integer asyncSend(OFMessage msg, int xid);
+
+    /**
+     * This method puts the message in an outgoing priority queue with high
+     * priority. It will be served first before normal priority messages. The
+     * method should be used for critical messages such as hello, echo reply
+     * etc. An unique XID is generated automatically and inserted into the
+     * message.
+     *
+     * @param msg
+     *            The OF message to be sent
+     * @return The XID used
+     */
+    public Integer asyncFastSend(OFMessage msg);
+
+    /**
+     * This method puts the message in an outgoing priority queue with high
+     * priority. It will be served first before normal priority messages. The
+     * method should be used for critical messages such as hello, echo reply
+     * etc. The specified XID is inserted into the message.
+     *
+     * @param msg
+     *            The OF message to be sent
+     * @return The XID used
+     */
+    public Integer asyncFastSend(OFMessage msg, int xid);
+
+    /**
+     * Sends the OF message followed by a Barrier Request with a unique XID
+     * which is automatically generated, and waits for a result from the switch.
+     *
+     * @param msg
+     *            The message to be sent
+     * @return An Object which has one of the followings instances/values:
+     *         Boolean with value true to indicate the message has been
+     *         successfully processed and acknowledged by the switch; Boolean
+     *         with value false to indicate the message has failed to be
+     *         processed by the switch within a period of time or OFError to
+     *         indicate that the message has been denied by the switch which
+     *         responded with OFError.
+     */
+    public Object syncSend(OFMessage msg);
+
+    /**
+     * Returns a map containing all OFPhysicalPorts of this switch.
+     *
+     * @return The Map of OFPhysicalPort
+     */
+    public Map<Short, OFPhysicalPort> getPhysicalPorts();
+
+    /**
+     * Returns a Set containing all port IDs of this switch.
+     *
+     * @return The Set of port ID
+     */
+    public Set<Short> getPorts();
+
+    /**
+     * Returns OFPhysicalPort of the specified portNumber of this switch.
+     *
+     * @param portNumber
+     *            The port ID
+     * @return OFPhysicalPort for the specified PortNumber
+     */
+    public OFPhysicalPort getPhysicalPort(Short portNumber);
+
+    /**
+     * Returns the bandwidth of the specified portNumber of this switch.
+     *
+     * @param portNumber
+     *            the port ID
+     * @return bandwidth
+     */
+    public Integer getPortBandwidth(Short portNumber);
+
+    /**
+     * Returns True if the port is enabled,
+     *
+     * @param portNumber
+     * @return True if the port is enabled
+     */
+    public boolean isPortEnabled(short portNumber);
+
+    /**
+     * Returns True if the port is enabled.
+     *
+     * @param port
+     * @return True if the port is enabled
+     */
+    public boolean isPortEnabled(OFPhysicalPort port);
+
+    /**
+     * Returns a list containing all enabled ports of this switch.
+     *
+     * @return: List containing all enabled ports of this switch
+     */
+    public List<OFPhysicalPort> getEnabledPorts();
+
+    /**
+     * Sends OFStatisticsRequest with a unique XID generated automatically and
+     * waits for a result from the switch.
+     *
+     * @param req
+     *            the OF Statistic Request to be sent
+     * @return Object has one of the following instances/values::
+     *         List<OFStatistics>, a list of statistics records received from
+     *         the switch as response from the request; OFError if the switch
+     *         failed handle the request or NULL if timeout has occurred while
+     *         waiting for the response.
+     */
+    public Object getStatistics(OFStatisticsRequest req);
+
+    /**
+     * Returns true if the switch has reached the operational state (has sent
+     * FEATURE_REPLY to the controller).
+     *
+     * @return true if the switch is operational
+     */
+    public boolean isOperational();
+
+    /**
+     * Send Barrier message synchronously. The caller will be blocked until the
+     * Barrier reply arrives.
+     */
+    Object syncSendBarrierMessage();
+
+    /**
+     * Send Barrier message asynchronously. The caller is not blocked. The
+     * Barrier message will be sent in a transmit thread which will be blocked
+     * until the Barrier reply arrives.
+     */
+    Object asyncSendBarrierMessage();
+
+
+    public void startHandler();
+
+    public void shutDownHandler();
+
+    public void handleMessage(OFMessage ofMessage);
+
+    public void flushBufferedMessages();
+
+    public SocketAddress getRemoteAddress();
+
+    public SocketAddress getLocalAddress();
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitchStateListener.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitchStateListener.java
new file mode 100644 (file)
index 0000000..608b6f5
--- /dev/null
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core;
+
+/**
+ * Interface to be implemented by applications that want to receive switch state event changes.
+ *
+ */
+public interface ISwitchStateListener {
+    /**
+     * This method is invoked by Controller when a switch has been connected to the Controller.
+     * Application who wants to receive this event needs to implement this method.
+     * @param sw The switch that has just connected.
+     */
+    public void switchAdded(ISwitch sw);
+
+    /**
+     * This method is invoked by Controller when a switch has been disconnected from the Controller.
+     * Application who wants to receive this event needs to implement this method.
+     * @param sw The switch that has just disconnected.
+     */
+    public void switchDeleted(ISwitch sw);
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/EnhancedController.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/EnhancedController.java
new file mode 100644 (file)
index 0000000..eb49768
--- /dev/null
@@ -0,0 +1,659 @@
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.RejectedExecutionException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SocketChannel;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.AdaptiveReceiveBufferSizePredictorFactory;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.channel.group.ChannelGroup;
+import org.jboss.netty.channel.group.DefaultChannelGroup;
+import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.jboss.netty.handler.execution.ExecutionHandler;
+import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
+import org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler;
+import org.jboss.netty.handler.timeout.IdleStateEvent;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.ObjectSizeEstimator;
+import org.jboss.netty.handler.timeout.ReadTimeoutException;
+
+
+
+
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.MessageParseException;
+
+
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitchStateListener;
+//import org.opendaylight.controller.protocol_plugin.openflow.core.internal.OFChannelState.HandshakeState;
+//import org.openflow.protocol.OFType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+
+
+public class EnhancedController implements IController {
+
+
+    protected BasicFactory factory;
+
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(EnhancedController.class);
+
+
+    // Track connected switches via SwitchID
+    private ConcurrentHashMap<Long, ISwitch> connectedSwitches;
+
+    // Track connected switches via ChannelID. Whenever the message
+    private ConcurrentHashMap<Integer, ISwitch> channelIDToSwitchMap;
+
+    // only 1 message listener per OFType
+    private ConcurrentMap<OFType, IMessageListener> messageListeners;
+
+    // only 1 switch state listener
+    private ISwitchStateListener switchStateListener;
+    private AtomicInteger switchInstanceNumber;
+
+
+    private OFChannelHandler ofChannelHandler = null;
+    private ControllerServerBootstrap bootstrap = null;
+
+    private ThreadPoolExecutor execHandler = null;
+
+    private static final int SEND_BUFFER_SIZE = 1 * 1024 * 1024;
+    private static final int RECEIVE_BUFFER_SIZE = 1 * 1024 * 1024;
+    private static final int WRITE_BUFFER_LOW_WATERMARK = 32 * 1024;
+    private static final int WRITE_BUFFER_HIGH_WATERMARK = 64 * 1024;
+    private static final String CONTROLLER_HOST = null;
+    private static final int CONTROLLER_PORT = 6633;
+
+    private static final int OMATPE_CORE_POOL_SIZE = 200;
+    private static final int OMATPE_PER_CHANNEL_SIZE = 2 * 1048576;
+    private static final int OMATPE_POOL_WIDE_SIZE = 0; //1073741824;
+    private static final int OMATPE_THREAD_KEEP_ALIVE_IN_MILLISECONDS = 100;
+    private static final int EXPERIMENTAL_OMATPE_OBJECT_SIZE = 1000; // bytes
+
+    private HashedWheelTimer hashedWheelTimer = null;
+
+    // This executor would be used by individual switches to handle
+    // cases like Stats Request/Response or Sync* methods which sends request and
+    // waits via Future for responses. Please note that threads in this
+    // pool are shared across multiple threads. So, if all threads are busy,
+    // Socket IO thread would get blocked creating sharp decline in performance
+    // If possible TOTALLY avoid any thread usage which does network level
+    // request / response by making a thread in this pool wait for response
+    // Consider storing the Future reference against the "sent" request and
+    // fire-event to wake-up the same when response is received rather than making the
+    // sender thread getting into a "wait" mode. That would never scale
+    private ExecutorService executorService = null;
+
+    // IMPORTANT: DO NOT REDUCE THIS THREAD COUNT TO 0
+    // THIS THREAD COUNT WOULD BE USED FOR SOCKET-IO + FOLLOWING EXECUTION CHAIN
+    // Plugin + SAL + North-to-SAL + Egress (flow_provisioning)
+    private static final int WORKER_THREAD_COUNT = 4;
+
+    // This is a handy thread-pool if WORKER_THREAD_COUNT is not able to cope with
+    // Socket IO + Execution of the following handling chain
+    // Plugin + SAL + North-to-SAL + Egress (flow_provisioning)
+    private static final int EXECUTION_HANDLER_THREAD_POOL_SIZE = 0;
+
+    // This is the thread-pool which can be optionally used for
+    // building synchronous semantics for flow_mod and stats handling cycle
+    // Flow_Mod in synchronous model could involve FLOW_MOD + BARRIER_MSG
+    // sending and receiving with wait timeout for reply
+    // Stats handling in synchronous model could involve STATS_REQUEST + STATS_REPLY
+    // sending and receiving with wait timeout for reply
+    private static final int THREAD_POOL_SIZE_FOR_EGRESS_SYNC_MSGS = 30;
+
+    private TrafficStatisticsHandler statsHandler = null;
+
+    // Lock for locking messagelisteners list while escalating the switch
+    // messages
+    private ReentrantLock lock = new ReentrantLock();
+
+    private static final int FLUSH_BATCH_SIZE = 100;
+
+    //****************** IController Interafce Methods Begin ******************
+
+    @Override
+    public void addMessageListener(OFType type, IMessageListener listener) {
+        IMessageListener currentListener = this.messageListeners.get(type);
+        if (currentListener != null) {
+            logger.warn("{} is already listened by {}", type.toString(),
+                    currentListener.toString());
+        }
+        this.messageListeners.put(type, listener);
+        logger.debug("{} is now listened by {}", type.toString(),
+                listener.toString());
+
+    }
+
+    @Override
+    public void removeMessageListener(OFType type, IMessageListener listener) {
+        IMessageListener currentListener = this.messageListeners.get(type);
+        if ((currentListener != null) && (currentListener == listener)) {
+            logger.debug("{} listener {} is Removed", type.toString(),
+                    listener.toString());
+            this.messageListeners.remove(type);
+        }
+
+    }
+
+    @Override
+    public void addSwitchStateListener(ISwitchStateListener listener) {
+        if (this.switchStateListener != null) {
+            logger.warn("Switch events are already listened by {}",
+                    this.switchStateListener.toString());
+        }
+        this.switchStateListener = listener;
+        logger.debug("Switch events are now listened by {}",
+                listener.toString());
+
+    }
+
+    @Override
+    public void removeSwitchStateListener(ISwitchStateListener listener) {
+        if ((this.switchStateListener != null)
+                && (this.switchStateListener == listener)) {
+            logger.debug("SwitchStateListener {} is Removed",
+                    listener.toString());
+            this.switchStateListener = null;
+        }
+
+    }
+
+    @Override
+    public Map<Long, ISwitch> getSwitches() {
+        return this.connectedSwitches;
+    }
+
+    @Override
+    public ISwitch getSwitch(Long switchId) {
+        return this.connectedSwitches.get(switchId);
+    }
+
+    //****************** IController Interafce Methods End ******************
+
+
+
+    //****************** Dependency-manager callbacks Begin ******************
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    public void init() {
+        logger.debug("Initializing!");
+        this.connectedSwitches = new ConcurrentHashMap<Long, ISwitch>();
+        this.channelIDToSwitchMap = new ConcurrentHashMap<Integer, ISwitch>();
+        this.messageListeners = new ConcurrentHashMap<OFType, IMessageListener>();
+        this.switchStateListener = null;
+        this.hashedWheelTimer = new HashedWheelTimer();
+        this.statsHandler = new TrafficStatisticsHandler(hashedWheelTimer);
+        this.switchInstanceNumber = new AtomicInteger(0);
+        this.factory = new BasicFactory();
+        this.bootstrap = new ControllerServerBootstrap(this);
+        this.executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE_FOR_EGRESS_SYNC_MSGS);
+
+
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    public void start() {
+        this.statsHandler.init();
+        logger.debug("Starting!");
+        bootstrap.startServer(WORKER_THREAD_COUNT,
+                CONTROLLER_HOST,
+                CONTROLLER_PORT,
+                ofChannelHandler);
+
+
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    public void stop() {
+        for (Iterator<Entry<Integer, ISwitch>> it = channelIDToSwitchMap.entrySet().iterator(); it
+                .hasNext();) {
+            Entry<Integer, ISwitch> entry = it.next();
+            ((EnhancedSwitchHandler) entry.getValue()).stop();
+        }
+
+        hashedWheelTimer.stop();
+
+        executorService.shutdown();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    public void destroy() {
+    }
+    //****************** Dependency-manager callbacks End ******************
+
+
+
+    public OFChannelHandler getChannelHandler(){
+        return new OFChannelHandler(this);
+    }
+
+
+    protected class OFChannelHandler extends IdleStateAwareChannelUpstreamHandler{
+
+
+        protected EnhancedController controller = null;
+        protected Channel channel = null;
+
+
+        public OFChannelHandler(EnhancedController controller){
+            this.controller = controller;
+        }
+
+
+        @Override
+        public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
+                throws Exception {
+            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+            msglist.add(factory.getMessage(OFType.ECHO_REQUEST));
+            e.getChannel().write(msglist);
+            statsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.ECHO_REQUEST_SENT);
+        }
+
+        @Override
+        public void channelConnected(ChannelHandlerContext ctx,
+                ChannelStateEvent e) throws Exception {
+            channel = e.getChannel();
+            logger.info("New switch connection from {}",
+                     channel.getRemoteAddress());
+
+            Integer channelID = e.getChannel().getId();
+
+            ISwitch switchHandler = new EnhancedSwitchHandler(controller,
+                    channelID, channel, hashedWheelTimer, executorService, statsHandler);
+            switchHandler.startHandler();
+            channelIDToSwitchMap.put(channelID, switchHandler);
+            statsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.CONNECTED_SWITCHES);
+
+          }
+
+        @Override
+        public void channelDisconnected(ChannelHandlerContext ctx,
+                ChannelStateEvent e) throws Exception {
+            // when SwitchHandler.shutDownHandler is called, Controller would
+            // get the feedback via switchDeleted method. So that both SwitchHandler and
+            // controller both release resources of the switch concerned
+
+            Integer channelID = e.getChannel().getId();
+            ISwitch switchHandler = channelIDToSwitchMap.get(channelID);
+            if (switchHandler != null){
+                switchHandler.shutDownHandler();
+            }
+            statsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.DISCONNECTED_SWITCHES);
+
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
+                throws Exception {
+
+            EnhancedSwitchHandler sw = null;
+
+            if (e.getCause() instanceof ReadTimeoutException) {
+                // switch timeout
+                logger.error("Disconnecting switch {} due to read timeout",
+                        e.getChannel().getId(), e.getCause().getMessage());
+                ctx.getChannel().close();
+                sw = (EnhancedSwitchHandler)channelIDToSwitchMap.get(e.getChannel().getId());
+                sw.stop();
+            /*
+            } else if (e.getCause() instanceof HandshakeTimeoutException) {
+                logger.error("Disconnecting switch {}: failed to complete handshake",
+                        e.getChannel().getId());
+                ctx.getChannel().close();
+                channelIDToSwitchMap.remove(e.getChannel().getId());
+                */
+            } else if (e.getCause() instanceof ClosedChannelException) {
+                logger.warn("Channel for sw {} already closed Error : {}",
+                        e.getChannel().getId(), e.getCause().getMessage());
+                ctx.getChannel().close();
+                sw = (EnhancedSwitchHandler)channelIDToSwitchMap.get(e.getChannel().getId());
+                sw.stop();
+            } else if (e.getCause() instanceof IOException) {
+                logger.error("Disconnecting switch {} due to IO Error: {}",
+                        e.getChannel().getId(), e.getCause().getMessage());
+                ctx.getChannel().close();
+                sw = (EnhancedSwitchHandler)channelIDToSwitchMap.get(e.getChannel().getId());
+                sw.stop();
+            /*
+            } else if (e.getCause() instanceof SwitchStateException) {
+                logger.error("Disconnecting switch {} due to switch state error: {}",
+                        e.getChannel().getId(), e.getCause().getMessage());
+                ctx.getChannel().close();
+                channelIDToSwitchMap.remove(e.getChannel().getId());
+
+            } else if (e.getCause() instanceof MessageParseException) {
+                logger.error("Disconnecting switch {} due to message parse error Error : {}",
+                        e.getChannel().getId(), e.getCause().getMessage());
+                ctx.getChannel().close();
+                sw = (EnhancedSwitchHandler)channelIDToSwitchMap.get(e.getChannel().getId());
+                sw.stop(); */
+            } else if (e.getCause() instanceof RejectedExecutionException) {
+                logger.warn("Could not process message: queue full");
+                ctx.getChannel().close();
+                sw = (EnhancedSwitchHandler)channelIDToSwitchMap.get(e.getChannel().getId());
+                sw.stop();
+            } else {
+                logger.error("Error while processing message from switch {} Error : {}",
+                        e.getChannel().getId(), e.getCause().getMessage());
+                e.getCause().printStackTrace();
+                ctx.getChannel().close();
+                sw = (EnhancedSwitchHandler)channelIDToSwitchMap.get(e.getChannel().getId());
+                sw.stop();
+            }
+
+            statsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.EXCEPTION_CAUGHT);
+        }
+
+        @Override
+        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
+                throws Exception {
+            Integer messageChannelId = e.getChannel().getId();
+            ISwitch swHan = (EnhancedSwitchHandler)channelIDToSwitchMap.get(messageChannelId);
+
+            if (e.getMessage() instanceof List) {
+                //@SuppressWarnings("unchecked")
+                List<OFMessage> msglist = (List<OFMessage>)e.getMessage();
+                if (msglist != null){ // this check actually brought down rate to some extent - weird !!!
+                    for (OFMessage ofm : msglist) {
+                        try {
+
+                            // Do the actual packet processing
+                            processOFMessage(ofm, messageChannelId);
+                        }
+                        catch (Exception ex) {
+                            // We are the last handler in the stream, so run the
+                            // exception through the channel again by passing in
+                            // ctx.getChannel().
+                            Channels.fireExceptionCaught(ctx.getChannel(), ex);
+                        }
+                    }
+                }
+            }
+
+            // Flush all flow-mods/packet-out/stats generated from this "train"
+            swHan.flushBufferedMessages();
+
+            statsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.MESSAGE_RECEIVED);
+
+
+        }
+
+
+        public void processOFMessage(OFMessage ofm, Integer channelID){
+            ISwitch switchHandler = channelIDToSwitchMap.get(channelID);
+            statsHandler.countForEntitySimpleMeasurement(channelID, TrafficStatisticsHandler.ENTITY_COUNTER_RCV_MSG);
+            if (switchHandler != null){
+                switchHandler.handleMessage(ofm);
+            }
+        }
+
+
+    }
+
+
+    protected class ControllerServerBootstrap{
+
+        private int workerThreads = 0;
+        private EnhancedController controller = null;
+
+        public ControllerServerBootstrap(EnhancedController controller){
+            this.controller = controller;
+        }
+
+
+        public void startServer(int numWorkerThreads, String openFlowHost, int openFlowPort, OFChannelHandler ofchan){
+            this.workerThreads = numWorkerThreads;
+            try {
+                final ServerBootstrap bootstrap = createServerBootStrap();
+
+                 bootstrap.setOption("reuseAddr", true);
+                 bootstrap.setOption("child.keepAlive", true);
+                 bootstrap.setOption("child.tcpNoDelay", true);
+                 bootstrap.setOption("child.receiveBufferSize", EnhancedController.RECEIVE_BUFFER_SIZE);
+                 bootstrap.setOption("child.sendBufferSize", EnhancedController.SEND_BUFFER_SIZE);
+
+                 // better to have an receive buffer predictor
+                 //bootstrap.setOption("receiveBufferSizePredictorFactory",
+                 //      new AdaptiveReceiveBufferSizePredictorFactory());
+                 //if the server is sending 1000 messages per sec, optimum write buffer water marks will
+                 //prevent unnecessary throttling, Check NioSocketChannelConfig doc
+                 //bootstrap.setOption("writeBufferLowWaterMark", WRITE_BUFFER_LOW_WATERMARK);
+                 //bootstrap.setOption("writeBufferHighWaterMark", WRITE_BUFFER_HIGH_WATERMARK);
+
+                 // TODO: IMPORTANT: If the threadpool is supplied as null, ExecutionHandler would
+                 // not be present in pipeline. If the load increases and ordering is required ,
+                 // use OrderedMemoryAwareThreadPoolExecutor as argument instead of null
+
+                 /*
+                 execHandler = new OrderedMemoryAwareThreadPoolExecutor(
+                                 OMATPE_CORE_POOL_SIZE,
+                                 OMATPE_PER_CHANNEL_SIZE,
+                                 OMATPE_POOL_WIDE_SIZE,
+                                 OMATPE_THREAD_KEEP_ALIVE_IN_MILLISECONDS,
+                                 TimeUnit.MILLISECONDS,
+                                 new ObjectSizeEstimator() {
+
+                                    @Override
+                                    public int estimateSize(Object o) {
+                                        return 30000;
+                                    }
+                                },
+                                Executors.defaultThreadFactory());     */
+
+                 execHandler = new OrderedMemoryAwareThreadPoolExecutor(
+                         OMATPE_CORE_POOL_SIZE,
+                         OMATPE_PER_CHANNEL_SIZE,
+                         OMATPE_POOL_WIDE_SIZE,
+                         OMATPE_THREAD_KEEP_ALIVE_IN_MILLISECONDS,
+                         TimeUnit.MILLISECONDS);
+
+
+
+                 ChannelPipelineFactory pfact =
+                         new OpenflowPipelineFactory(controller, execHandler);
+                 bootstrap.setPipelineFactory(pfact);
+                 InetSocketAddress sa =
+                         (openFlowHost == null)
+                         ? new InetSocketAddress(openFlowPort)
+                         : new InetSocketAddress(openFlowHost, openFlowPort);
+                 final ChannelGroup cg = new DefaultChannelGroup();
+                 cg.add(bootstrap.bind(sa));
+
+
+             } catch (Exception e) {
+                 throw new RuntimeException(e);
+             }
+
+        }
+
+        private ServerBootstrap createServerBootStrap() {
+            if (workerThreads == 0) {
+                return new ServerBootstrap(
+                        new NioServerSocketChannelFactory(
+                                Executors.newCachedThreadPool(),
+                                Executors.newCachedThreadPool()));
+            } else {
+                return new ServerBootstrap(
+                        new NioServerSocketChannelFactory(
+                                Executors.newCachedThreadPool(),
+                                Executors.newCachedThreadPool(), workerThreads));
+            }
+        }
+
+
+
+    }
+
+
+    /**
+     * Method called by SwitchHandler once the handshake state is completed
+     *
+     * @param sw
+     */
+    public void switchAdded(SwitchEvent switchEv, Integer switchChannelID){
+
+        ISwitch sw = switchEv.getSwitch();
+        Long switchId = sw.getId();
+
+        connectedSwitches.put(switchId, sw);
+        statsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.CONNECTED_SWITCHES);
+
+        logger.info("Switch with DPID : {} connected ", switchId);
+
+        notifySwitchAdded(sw);
+    }
+
+
+    /**
+     * Method called by SwitchHandler switch is disconnected
+     *
+     * @param sw
+     */
+
+    public void switchDeleted(SwitchEvent switchEv, Integer switchChannelID){
+        ISwitch sw = switchEv.getSwitch();
+        disconnectSwitch(sw, switchChannelID);
+    }
+
+
+    /**
+     * Method called by SwitchHandler when it encounters any errors
+     *
+     *
+     * @param sw
+     */
+
+    public void switchError(SwitchEvent switchEv, Integer switchChannelID){
+
+    }
+
+
+    public void switchMessage(SwitchEvent switchEv, Integer switchChannelID){
+        long startTime = 0L;
+        long endTime = 0L;
+
+
+        OFMessage msg = switchEv.getMsg();
+        ISwitch sw = switchEv.getSwitch();
+        if (msg != null) {
+            //try{
+            //    lock.lock();
+                IMessageListener listener = messageListeners
+                        .get(msg.getType());
+                if (listener != null) {
+                    //logger.debug("delegating to msg-receiver");
+                    //startTime = System.nanoTime();
+                    listener.receive(sw, msg);
+                    //endTime = System.nanoTime();
+                    //this.statsHandler.reportPacketInProcessingTime(endTime - startTime);
+                }
+            //}
+            //finally{
+            //    lock.unlock();
+            //}
+        }
+    }
+
+    public void disconnectSwitch(ISwitch sw, Integer switchChannelID){
+        Long sid = null;
+        if (((EnhancedSwitchHandler) sw).isOperational()) {
+            sid = sw.getId();
+
+            this.connectedSwitches.remove(sid);
+            this.channelIDToSwitchMap.remove(switchChannelID);
+            notifySwitchDeleted(sw);
+        }
+        //((EnhancedSwitchHandler) sw).stop();
+        logger.info("Switch with DPID {} disconnected", sid);
+        sw = null;
+    }
+
+
+    private void notifySwitchAdded(ISwitch sw) {
+        if (switchStateListener != null) {
+            switchStateListener.switchAdded(sw);
+        }
+    }
+
+    private void notifySwitchDeleted(ISwitch sw) {
+        if (switchStateListener != null) {
+            switchStateListener.switchDeleted(sw);
+        }
+    }
+
+    @Override
+    public InetAddress getControllerIdForSwitch(Long id) {
+        //Added to enable Cluster handling.
+
+        if(id==null)
+        {
+            logger.debug("id is null");
+            return null;
+        }
+
+        ISwitch sw = (ISwitch) connectedSwitches.get(id);
+
+        SocketAddress sockAddr = sw.getLocalAddress();
+
+        if( sockAddr != null && InetSocketAddress.class.isAssignableFrom(sockAddr.getClass())) {
+            InetAddress localAddress = ((InetSocketAddress) sockAddr).getAddress();
+            this.logger.debug("socketchannel local address is " + localAddress);
+            return localAddress;
+        }
+
+        return null;
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/EnhancedSwitchHandler.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/EnhancedSwitchHandler.java
new file mode 100644 (file)
index 0000000..b84b3ac
--- /dev/null
@@ -0,0 +1,819 @@
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedSelectorException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.opendaylight.controller.protocol_plugin.openflow.core.internal.SwitchEvent.SwitchEventType;
+import org.openflow.protocol.OFBarrierReply;
+import org.openflow.protocol.OFBarrierRequest;
+import org.openflow.protocol.OFEchoReply;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFGetConfigReply;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFPortStatus;
+import org.openflow.protocol.OFSetConfig;
+import org.openflow.protocol.OFStatisticsReply;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
+import org.openflow.protocol.OFPhysicalPort.OFPortFeatures;
+import org.openflow.protocol.OFPhysicalPort.OFPortState;
+import org.openflow.protocol.OFPortStatus.OFPortReason;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.MessageParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EnhancedSwitchHandler implements ISwitch {
+
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(EnhancedSwitchHandler.class);
+    private static final int switchLivenessTimeout = getSwitchLivenessTimeout();
+    private int MESSAGE_RESPONSE_TIMER = 2000;
+
+    private EnhancedController controller = null;
+    private Integer switchChannelID = null;
+    private Channel channel;
+    private long lastMsgReceivedTimeStamp = 0;
+    private SwitchState state = null;
+    private BasicFactory factory = null;
+    private HashedWheelTimer timer = null;
+    private SwitchLivelinessTimerTask switchLivelinessTask = null;
+    private Timeout switchLivelinessTaskHandle = null;
+    private long sid;
+    private AtomicInteger xid;
+    private int buffers;
+    private int capabilities;
+    private byte tables;
+    private int actions;
+    private Map<Short, OFPhysicalPort> physicalPorts;
+    private Map<Short, Integer> portBandwidth;
+    private Date connectedDate;
+    private ExecutorService executor = null;
+    private ConcurrentHashMap<Integer, Callable<Object>> messageWaitingDone;
+    private Integer responseTimerValue;
+    private TrafficStatisticsHandler trafficStatsHandler = null;
+    private static final boolean START_LIVELINESS_TIMER = false;
+
+    private static final int BATCH_COUNT_FOR_FLUSHING = 3;
+    private int flushBatchTrack = 0;
+
+    /*
+    private List<OFMessage> msgBuffer = new ArrayList<OFMessage>();
+    private int bufferTrack = 0;
+    private static final int BATCH_BUFFER_THRESHOLD = 100;
+    */
+
+
+    // PLEASE .. IF THERE IS SOMETHING CALLED GOD, HELP ME GET THE THROUGHPUT WITH THIS !!
+    private List<OFMessage> flushableMsgBuffer = new ArrayList<OFMessage>();
+
+
+    public enum SwitchState {
+        NON_OPERATIONAL(0),
+        WAIT_FEATURES_REPLY(1),
+        WAIT_CONFIG_REPLY(2),
+        OPERATIONAL(3);
+
+        private int value;
+
+        private SwitchState(int value) {
+            this.value = value;
+        }
+
+        @SuppressWarnings("unused")
+        public int value() {
+            return this.value;
+        }
+    }
+
+
+    public EnhancedSwitchHandler(EnhancedController controller,
+            Integer switchConnectionChannelID,
+            Channel channel,
+            HashedWheelTimer timer,
+            ExecutorService executor,
+            TrafficStatisticsHandler tHandler){
+
+        this.controller = controller;
+        this.physicalPorts = new HashMap<Short, OFPhysicalPort>();
+        this.portBandwidth = new HashMap<Short, Integer>();
+        this.switchChannelID = switchConnectionChannelID;
+        this.timer = timer;
+        this.sid = (long) 0;
+        this.tables = (byte) 0;
+        this.actions = (int) 0;
+        this.capabilities = (int) 0;
+        this.buffers = (int) 0;
+        this.connectedDate = new Date();
+        this.state = SwitchState.NON_OPERATIONAL;
+        this.executor = executor;
+        this.messageWaitingDone = new ConcurrentHashMap<Integer, Callable<Object>>();
+        this.responseTimerValue = MESSAGE_RESPONSE_TIMER;
+        this.channel = channel;
+        this.xid = new AtomicInteger(this.channel.hashCode());
+        this.trafficStatsHandler = tHandler;
+
+    }
+
+
+    public void startHandler(){
+        this.factory = new BasicFactory();
+        start();
+
+    }
+
+
+    public void shutDownHandler(){
+        stop();
+
+    }
+
+
+    public void handleChannelIdle(){
+        // TODO: this is already handled by OFChannelHandler
+        // so DON'T care
+
+
+    }
+
+
+    public void start() {
+        sendFirstHello();
+    }
+
+    public void stop() {
+        cancelSwitchTimer();
+        SwitchEvent ev = new SwitchEvent(SwitchEventType.SWITCH_DELETE, this, null);
+        controller.switchDeleted(ev, switchChannelID);
+    }
+
+    private void cancelSwitchTimer() {
+        if (switchLivelinessTaskHandle != null){
+            this.switchLivelinessTaskHandle.cancel();
+        }
+    }
+
+
+    public void handleCaughtException(){
+
+
+
+    }
+
+
+
+
+    @Override
+    public int getNextXid() {
+        return this.xid.incrementAndGet();
+    }
+
+    @Override
+    public Long getId() {
+        return this.sid;
+    }
+
+    @Override
+    public Byte getTables() {
+        return this.tables;
+    }
+
+    @Override
+    public Integer getActions() {
+        return this.actions;
+    }
+
+    @Override
+    public Integer getCapabilities() {
+        return this.capabilities;
+    }
+
+    @Override
+    public Integer getBuffers() {
+        return this.buffers;
+    }
+
+    @Override
+    public Date getConnectedDate() {
+        return this.connectedDate;
+    }
+
+    @Override
+    public Integer asyncSend(OFMessage msg) {
+        return asyncSend(msg, getNextXid());
+    }
+
+
+    @Override
+    public Integer asyncSend(OFMessage msg, int xid) {
+        // TODO:
+        // BATCHING IMPLEMENTATION. Please think hard before enablng this !!
+        // Some messages could be latency-sensitive and some could be batched
+        // for better throughput. So, below decision may not bring better
+        // throughput for latency-sensitive cases like FLOW-MODs or
+        // PACKET-OUTs
+
+        /*
+        if (bufferTrack == BUFFER_THRESHOLD){
+            this.channel.write(msgBuffer);
+            msgBuffer.clear();
+            bufferTrack = 0;
+
+        }
+        msg.setXid(xid);
+        msgBuffer.add(msg);
+        bufferTrack++;
+        */
+
+
+
+        //List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msg.setXid(xid);
+        synchronized( flushableMsgBuffer ) {
+            flushableMsgBuffer.add(msg);
+        }
+
+        trafficStatsHandler.countForEntitySimpleMeasurement(switchChannelID,
+                TrafficStatisticsHandler.ENTITY_COUNTER_SND_MSG);
+
+        //this.channel.write(msglist);
+
+        /*
+        if (msg.getType() == OFType.FLOW_MOD){
+            this.trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.FLOW_MOD_SENT);
+            this.trafficStatsHandler.countForRateMeasurement(TrafficStatisticsHandler.FLOW_MOD_SENT);
+        }
+        */
+
+
+        return xid;
+    }
+
+
+    @Override
+    public Integer asyncFastSend(OFMessage msg) {
+        return asyncFastSend(msg, getNextXid());
+    }
+
+    @Override
+    public Integer asyncFastSend(OFMessage msg, int xid) {
+        msg.setXid(xid);
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(msg);
+        this.channel.write(msglist);
+        trafficStatsHandler.countForEntitySimpleMeasurement(switchChannelID,
+                TrafficStatisticsHandler.ENTITY_COUNTER_SND_MSG);
+        return xid;
+    }
+
+    @Override
+    public Object syncSend(OFMessage msg) {
+        int xid = getNextXid();
+        return syncSend(msg, xid);
+    }
+
+    private Object syncSend(OFMessage msg, int xid) {
+        return syncMessageInternal(msg, xid, true);
+    }
+
+    @Override
+    public Map<Short, OFPhysicalPort> getPhysicalPorts() {
+        return this.physicalPorts;
+    }
+
+    @Override
+    public Set<Short> getPorts() {
+        return this.physicalPorts.keySet();
+    }
+
+    @Override
+    public OFPhysicalPort getPhysicalPort(Short portNumber) {
+        return this.physicalPorts.get(portNumber);
+    }
+
+    @Override
+    public Integer getPortBandwidth(Short portNumber) {
+        return this.portBandwidth.get(portNumber);
+    }
+
+    @Override
+    public boolean isPortEnabled(short portNumber) {
+        return isPortEnabled(physicalPorts.get(portNumber));
+    }
+
+    @Override
+    public boolean isPortEnabled(OFPhysicalPort port) {
+        if (port == null) {
+            return false;
+        }
+        int portConfig = port.getConfig();
+        int portState = port.getState();
+        if ((portConfig & OFPortConfig.OFPPC_PORT_DOWN.getValue()) > 0) {
+            return false;
+        }
+        if ((portState & OFPortState.OFPPS_LINK_DOWN.getValue()) > 0) {
+            return false;
+        }
+        if ((portState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK
+                .getValue()) {
+            return false;
+        }
+        return true;
+
+    }
+
+    @Override
+    public List<OFPhysicalPort> getEnabledPorts() {
+        List<OFPhysicalPort> result = new ArrayList<OFPhysicalPort>();
+        synchronized (this.physicalPorts) {
+            for (OFPhysicalPort port : physicalPorts.values()) {
+                if (isPortEnabled(port)) {
+                    result.add(port);
+                }
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * WARNING: CALLER WOULD BE BLOCKED
+     *
+     */
+    @Override
+    public Object getStatistics(OFStatisticsRequest req) {
+        int xid = getNextXid();
+        StatisticsCollector worker = new StatisticsCollector(this, xid, req);
+        messageWaitingDone.put(xid, worker);
+        Future<Object> submit = executor.submit(worker);
+        Object result = null;
+        try {
+            result = submit.get(responseTimerValue, TimeUnit.MILLISECONDS);
+            return result;
+        } catch (Exception e) {
+            logger.warn("Timeout while waiting for {} replies", req.getType());
+            result = null; // to indicate timeout has occurred
+            return result;
+        }
+    }
+
+    @Override
+    public boolean isOperational() {
+        return ((this.state == SwitchState.WAIT_CONFIG_REPLY) || (this.state == SwitchState.OPERATIONAL));
+    }
+
+    @Override
+    public Object syncSendBarrierMessage() {
+        OFBarrierRequest barrierMsg = new OFBarrierRequest();
+        return syncSend(barrierMsg);
+    }
+
+    @Override
+    public Object asyncSendBarrierMessage() {
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        OFBarrierRequest barrierMsg = new OFBarrierRequest();
+        int xid = getNextXid();
+
+        barrierMsg.setXid(xid);
+        msglist.add(barrierMsg);
+
+        this.channel.write(msglist);
+        trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.BARRIER_REQUEST_SENT);
+        return Boolean.TRUE;
+    }
+
+
+    @Override
+    public void handleMessage(OFMessage ofMessage) {
+
+
+        logger.debug("Message received: {}", ofMessage.toString());
+        this.lastMsgReceivedTimeStamp = System.currentTimeMillis();
+        OFType type = ofMessage.getType();
+        switch (type) {
+        case HELLO:
+            logger.debug("<<<< HELLO");
+            // send feature request
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.HELLO_RECEIVED);
+            OFMessage featureRequest = factory
+                    .getMessage(OFType.FEATURES_REQUEST);
+            asyncFastSend(featureRequest);
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.FEATURES_REQUEST_SENT);
+            // delete all pre-existing flows
+            OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
+            OFFlowMod flowMod = (OFFlowMod) factory
+                    .getMessage(OFType.FLOW_MOD);
+            flowMod.setMatch(match).setCommand(OFFlowMod.OFPFC_DELETE)
+                    .setOutPort(OFPort.OFPP_NONE)
+                    .setLength((short) OFFlowMod.MINIMUM_LENGTH);
+            asyncFastSend(flowMod);
+            this.state = SwitchState.WAIT_FEATURES_REPLY;
+            if (START_LIVELINESS_TIMER){
+                startSwitchTimer();
+            }
+            break;
+        case ECHO_REQUEST:
+            logger.debug("<<<< ECHO REQUEST");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.ECHO_REQUEST_RECEIVED);
+            OFEchoReply echoReply = (OFEchoReply) factory
+                    .getMessage(OFType.ECHO_REPLY);
+            asyncFastSend(echoReply);
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.ECHO_REPLY_SENT);
+
+            break;
+        case ECHO_REPLY:
+            logger.debug("<<<< ECHO REPLY");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.ECHO_REPLY_RECEIVED);
+            //this.probeSent = false;
+            break;
+        case FEATURES_REPLY:
+            logger.debug("<<<< FEATURES REPLY");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.FEATURES_REPLY_RECEIVED);
+            processFeaturesReply((OFFeaturesReply) ofMessage);
+            break;
+        case GET_CONFIG_REPLY:
+            logger.debug("<<<< CONFIG REPLY");
+            // make sure that the switch can send the whole packet to the
+            // controller
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.CONFIG_REPLY_RECEIVED);
+            if (((OFGetConfigReply) ofMessage).getMissSendLength() == (short) 0xffff) {
+                this.state = SwitchState.OPERATIONAL;
+            }
+            break;
+        case BARRIER_REPLY:
+            logger.debug("<<<< BARRIER REPLY");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.BARRIER_REPLY_RECEIVED);
+            processBarrierReply((OFBarrierReply) ofMessage);
+            break;
+        case ERROR:
+            logger.debug("<<<< ERROR");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.ERROR_MSG_RECEIVED);
+            processErrorReply((OFError) ofMessage);
+            break;
+        case PORT_STATUS:
+            logger.debug("<<<< PORT STATUS");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.PORT_STATUS_RECEIVED);
+            processPortStatusMsg((OFPortStatus) ofMessage);
+            break;
+        case STATS_REPLY:
+            logger.debug("<<<< STATS REPLY");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.STATS_RESPONSE_RECEIVED);
+            processStatsReply((OFStatisticsReply) ofMessage);
+            break;
+        case PACKET_IN:
+            logger.debug("<<<< PACKET_IN");
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.PACKET_IN_RECEIVED);
+            trafficStatsHandler.countForRateMeasurement(TrafficStatisticsHandler.PACKET_IN_RECEIVED);
+            break;
+        default:
+            break;
+        } // end of switch
+        if (isOperational()) {
+            logger.debug("SWITCH IS OPERATIONAL ... forwarding");
+            SwitchEvent ev = new SwitchEvent(
+                    SwitchEvent.SwitchEventType.SWITCH_MESSAGE, this, ofMessage);
+            controller.switchMessage(ev, switchChannelID);
+        }
+    }
+
+
+    private void startSwitchTimer(){
+        if (this.timer != null){
+            if (switchLivelinessTask == null){
+                switchLivelinessTask = new SwitchLivelinessTimerTask();
+            }
+            switchLivelinessTaskHandle = timer.newTimeout(switchLivelinessTask,
+                    switchLivenessTimeout, TimeUnit.SECONDS);
+        }
+    }
+
+
+
+    /**
+     * This method returns the switch liveness timeout value. If controller did
+     * not receive any message from the switch for such a long period,
+     * controller will tear down the connection to the switch.
+     *
+     * @return The timeout value
+     */
+    private static int getSwitchLivenessTimeout() {
+        String timeout = System.getProperty("of.switchLivenessTimeout");
+        int rv = 60500;
+        try {
+            if (timeout != null) {
+                rv = Integer.parseInt(timeout);
+            }
+        } catch (Exception e) {
+        }
+        return rv;
+    }
+
+
+    private void processFeaturesReply(OFFeaturesReply reply) {
+        if (this.state == SwitchState.WAIT_FEATURES_REPLY) {
+            this.sid = reply.getDatapathId();
+            this.buffers = reply.getBuffers();
+            this.capabilities = reply.getCapabilities();
+            this.tables = reply.getTables();
+            this.actions = reply.getActions();
+            // notify core of this error event
+            for (OFPhysicalPort port : reply.getPorts()) {
+                updatePhysicalPort(port);
+            }
+            // config the switch to send full data packet
+            OFSetConfig config = (OFSetConfig) factory
+                    .getMessage(OFType.SET_CONFIG);
+            config.setMissSendLength((short) 0xffff).setLengthU(
+                    OFSetConfig.MINIMUM_LENGTH);
+            asyncFastSend(config);
+            // send config request to make sure the switch can handle the set
+            // config
+            OFMessage getConfig = factory.getMessage(OFType.GET_CONFIG_REQUEST);
+            asyncFastSend(getConfig);
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.CONFIG_REQUEST_SENT);
+            this.state = SwitchState.WAIT_CONFIG_REPLY;
+            // inform core that a new switch is now operational
+            reportSwitchStateChange(true);
+        }
+    }
+
+
+    private void updatePhysicalPort(OFPhysicalPort port) {
+        Short portNumber = port.getPortNumber();
+        physicalPorts.put(portNumber, port);
+        portBandwidth
+                .put(portNumber,
+                        port.getCurrentFeatures()
+                                & (OFPortFeatures.OFPPF_10MB_FD.getValue()
+                                        | OFPortFeatures.OFPPF_10MB_HD
+                                                .getValue()
+                                        | OFPortFeatures.OFPPF_100MB_FD
+                                                .getValue()
+                                        | OFPortFeatures.OFPPF_100MB_HD
+                                                .getValue()
+                                        | OFPortFeatures.OFPPF_1GB_FD
+                                                .getValue()
+                                        | OFPortFeatures.OFPPF_1GB_HD
+                                                .getValue() | OFPortFeatures.OFPPF_10GB_FD
+                                            .getValue()));
+        trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.UPDATE_PHYSICAL_PORT);
+    }
+
+
+    private void reportSwitchStateChange(boolean added) {
+        SwitchEvent ev = null;
+        if (added) {
+            ev = new SwitchEvent(SwitchEvent.SwitchEventType.SWITCH_ADD, this, null);
+            controller.switchAdded(ev, switchChannelID);
+        } else {
+            ev = new SwitchEvent(SwitchEvent.SwitchEventType.SWITCH_DELETE, this, null);
+            controller.switchDeleted(ev, switchChannelID);
+        }
+    }
+
+
+    protected class SwitchLivelinessTimerTask implements TimerTask {
+
+        @Override
+        public void run(Timeout timeout) throws Exception {
+
+            // set this reference in parent so that cancellation is
+            // possible
+            switchLivelinessTaskHandle = timeout;
+            Long now = System.currentTimeMillis();
+            if ((now - lastMsgReceivedTimeStamp) > switchLivenessTimeout) {
+                if (state == SwitchState.WAIT_FEATURES_REPLY) {
+                    // send another features request
+                    OFMessage request = factory
+                            .getMessage(OFType.FEATURES_REQUEST);
+                    asyncFastSend(request);
+                } else {
+                    if (state == SwitchState.WAIT_CONFIG_REPLY) {
+                        // send another config request
+                        OFSetConfig config = (OFSetConfig) factory
+                                .getMessage(OFType.SET_CONFIG);
+                        config.setMissSendLength((short) 0xffff)
+                        .setLengthU(OFSetConfig.MINIMUM_LENGTH);
+                        asyncFastSend(config);
+                        OFMessage getConfig = factory
+                                .getMessage(OFType.GET_CONFIG_REQUEST);
+                        asyncFastSend(getConfig);
+                    }
+                }
+            }
+            timer.newTimeout(this, switchLivenessTimeout, TimeUnit.SECONDS);
+
+        }
+    }
+
+
+    /*
+     * Either a BarrierReply or a OFError is received. If this is a reply for an
+     * outstanding sync message, wake up associated task so that it can continue
+     */
+    private void processBarrierReply(OFBarrierReply msg) {
+        Integer xid = msg.getXid();
+        SynchronousMessage worker = (SynchronousMessage) messageWaitingDone
+                .remove(xid);
+        if (worker == null) {
+            return;
+        }
+        worker.wakeup();
+    }
+
+    private void processErrorReply(OFError errorMsg) {
+        try{
+            OFMessage offendingMsg = errorMsg.getOffendingMsg();
+            Integer xi = 0;
+            if (offendingMsg != null) {
+                xi = offendingMsg.getXid();
+            } else {
+                xi = errorMsg.getXid();
+            }
+        }
+        catch(MessageParseException mpe){
+            reportError(mpe);
+        }
+    }
+
+    private void processPortStatusMsg(OFPortStatus msg) {
+        OFPhysicalPort port = msg.getDesc();
+        if (msg.getReason() == (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
+            updatePhysicalPort(port);
+        } else if (msg.getReason() == (byte) OFPortReason.OFPPR_ADD.ordinal()) {
+            updatePhysicalPort(port);
+        } else if (msg.getReason() == (byte) OFPortReason.OFPPR_DELETE
+                .ordinal()) {
+            deletePhysicalPort(port);
+        }
+
+    }
+
+    private void deletePhysicalPort(OFPhysicalPort port) {
+        Short portNumber = port.getPortNumber();
+        physicalPorts.remove(portNumber);
+        portBandwidth.remove(portNumber);
+    }
+
+    private void processStatsReply(OFStatisticsReply reply) {
+        Integer xid = reply.getXid();
+        StatisticsCollector worker = (StatisticsCollector) messageWaitingDone
+                .get(xid);
+        if (worker == null) {
+            return;
+        }
+        if (worker.collect(reply)) {
+            // if all the stats records are received (collect() returns true)
+            // then we are done.
+            messageWaitingDone.remove(xid);
+            worker.wakeup();
+        }
+    }
+
+
+    /**
+     * This method performs synchronous operations for a given message. If
+     * syncRequest is set to true, the message will be sent out followed by a
+     * Barrier request message. Then it's blocked until the Barrier rely arrives
+     * or timeout. If syncRequest is false, it simply skips the message send and
+     * just waits for the response back.
+     *
+     * @param msg
+     *            Message to be sent
+     * @param xid
+     *            Message XID
+     * @param request
+     *            If set to true, the message the message will be sent out
+     *            followed by a Barrier request message. If set to false, it
+     *            simply skips the sending and just waits for the Barrier reply.
+     * @return the result
+     */
+    private Object syncMessageInternal(OFMessage msg, int xid, boolean syncRequest) {
+        Object result = null;
+
+        SynchronousMessage worker = new SynchronousMessage(this, xid, msg, syncRequest);
+        messageWaitingDone.put(xid, worker);
+
+        Boolean status = false;
+        Future<Object> submit = executor.submit(worker);
+        try {
+            result = submit.get(responseTimerValue, TimeUnit.MILLISECONDS);
+            messageWaitingDone.remove(xid);
+            if (result == null) {
+                // if result is null, then it means the switch can handle this
+                // message successfully
+                // convert the result into a Boolean with value true
+                status = true;
+                // logger.debug("Successfully send " +
+                // msg.getType().toString());
+                result = status;
+            } else {
+                // if result is not null, this means the switch can't handle
+                // this message
+                // the result if OFError already
+                logger.debug("Send {} failed --> {}", msg.getType().toString(),
+                        ((OFError) result).toString());
+            }
+            return result;
+        } catch (Exception e) {
+            logger.warn("Timeout while waiting for {} reply", msg.getType()
+                    .toString());
+            // convert the result into a Boolean with value false
+            status = false;
+            result = status;
+            return result;
+        }
+
+
+    }
+
+
+    private void sendFirstHello() {
+        try {
+            OFMessage msg = factory.getMessage(OFType.HELLO);
+            asyncFastSend(msg);
+            trafficStatsHandler.countForSimpleMeasurement(TrafficStatisticsHandler.HELLO_SENT);
+            trafficStatsHandler.addEntityForCounter(switchChannelID, TrafficStatisticsHandler.ENTITY_COUNTER_RCV_MSG);
+            trafficStatsHandler.addEntityForCounter(switchChannelID, TrafficStatisticsHandler.ENTITY_COUNTER_SND_MSG);
+        } catch (Exception e) {
+            reportError(e);
+        }
+    }
+
+
+    private void reportError(Exception e) {
+        if (e instanceof AsynchronousCloseException
+                || e instanceof InterruptedException
+                || e instanceof SocketException || e instanceof IOException
+                || e instanceof ClosedSelectorException) {
+            logger.error("Caught exception {}", e.getMessage());
+        } else {
+            logger.error("Caught exception ", e);
+        }
+        // notify core of this error event and disconnect the switch
+
+        // TODO: We do not need this because except-hanling is done by
+        // Controller's OFChannelHandler
+
+        /*
+        SwitchEvent ev = new SwitchEvent(
+                SwitchEvent.SwitchEventType.SWITCH_ERROR, this, null);
+
+        controller.switchError(ev, switchChannelID);
+        */
+    }
+
+
+    @Override
+    public void flushBufferedMessages() {
+        //flushBatchTrack++;
+        //if (flushBatchTrack > BATCH_COUNT_FOR_FLUSHING){
+        synchronized (flushableMsgBuffer) {
+            if (flushableMsgBuffer.size() > 0){
+                channel.write(flushableMsgBuffer);
+                flushableMsgBuffer.clear();
+            }
+        }
+        //    flushBatchTrack = 0;
+        //}
+
+    }
+
+    @Override
+    public SocketAddress getRemoteAddress() {
+        return (channel != null) ? channel.getRemoteAddress() : null;
+    }
+
+    @Override
+    public SocketAddress getLocalAddress() {
+        return (channel != null) ? channel.getLocalAddress() : null;
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFChannelState.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFChannelState.java
new file mode 100644 (file)
index 0000000..b66ce97
--- /dev/null
@@ -0,0 +1,51 @@
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+
+/**
+ * Wrapper class to hold state for the OpenFlow switch connection
+ * @author readams
+ */
+class OFChannelState {
+
+    /**
+     * State for handling the switch handshake
+     */
+    protected enum HandshakeState {
+        /**
+         * Beginning state
+         */
+        START,
+
+        /**
+         * Received HELLO from switch
+         */
+        HELLO,
+
+        /**
+         * We've received the features reply
+         * Waiting for Config and Description reply
+         */
+        FEATURES_REPLY,
+
+        /**
+         * Switch is ready for processing messages
+         */
+        READY
+
+    }
+
+    protected volatile HandshakeState hsState = HandshakeState.START;
+    protected boolean hasGetConfigReply = false;
+    protected boolean hasDescription = false;
+    protected boolean switchBindingDone = false;
+
+    protected OFFeaturesReply featuresReply = null;
+    protected OFDescriptionStatistics description = null;
+    protected List<OFMessage> queuedOFMessages = new ArrayList<OFMessage>();
+}
\ No newline at end of file
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFMessageDecoder.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFMessageDecoder.java
new file mode 100644 (file)
index 0000000..46472e6
--- /dev/null
@@ -0,0 +1,43 @@
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+
+/**
+ * Decode an openflow message from a Channel, for use in a netty
+ * pipeline
+ * @author readams
+ */
+public class OFMessageDecoder extends FrameDecoder {
+
+    OFMessageFactory factory = new BasicFactory();
+
+    @Override
+    protected Object decode(ChannelHandlerContext ctx, Channel channel,
+                            ChannelBuffer buffer) throws Exception {
+        if (!channel.isConnected()) {
+            // In testing, I see decode being called AFTER decode last.
+            // This check avoids that from reading curroupted frames
+            return null;
+        }
+
+        List<OFMessage> message = factory.parseMessage(buffer);
+        return message;
+    }
+
+    @Override
+    protected Object decodeLast(ChannelHandlerContext ctx, Channel channel,
+                            ChannelBuffer buffer) throws Exception {
+        // This is not strictly needed atthis time. It is used to detect
+        // connection reset detection from netty (for debug)
+        return null;
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFMessageEncoder.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OFMessageEncoder.java
new file mode 100644 (file)
index 0000000..12775c6
--- /dev/null
@@ -0,0 +1,39 @@
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
+import org.openflow.protocol.OFMessage;
+
+/**
+ * Encode an openflow message for output into a ChannelBuffer, for use in a
+ * netty pipeline
+ * @author readams
+ */
+public class OFMessageEncoder extends OneToOneEncoder {
+
+    @Override
+    protected Object encode(ChannelHandlerContext ctx, Channel channel,
+                            Object msg) throws Exception {
+        if (!(  msg instanceof List))
+            return msg;
+
+        @SuppressWarnings("unchecked")
+        List<OFMessage> msglist = (List<OFMessage>)msg;
+        int size = 0;
+        for (OFMessage ofm :  msglist) {
+                size += ofm.getLengthU();
+        }
+
+        ChannelBuffer buf = ChannelBuffers.buffer(size);;
+        for (OFMessage ofm :  msglist) {
+            ofm.writeTo(buf);
+        }
+        return buf;
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OpenflowPipelineFactory.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/OpenflowPipelineFactory.java
new file mode 100644 (file)
index 0000000..3414632
--- /dev/null
@@ -0,0 +1,66 @@
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.handler.execution.ExecutionHandler;
+import org.jboss.netty.handler.timeout.IdleStateHandler;
+import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+
+/**
+ * Creates a ChannelPipeline for a server-side openflow channel
+ * @author readams
+ */
+public class OpenflowPipelineFactory implements ChannelPipelineFactory {
+
+    private static final int READ_TIMEOUT = 30;
+    private static final int READER_IDLE_TIMEOUT = 20;
+    private static final int WRITER_IDLE_TIMEOUT = 25;
+    private static final int ALL_IDLE_TIMEOUT = 0;
+
+    protected EnhancedController controller;
+    protected ThreadPoolExecutor pipelineExecutor;
+    protected Timer timer;
+    protected IdleStateHandler idleHandler;
+    protected ReadTimeoutHandler readTimeoutHandler;
+
+    public OpenflowPipelineFactory(EnhancedController controller,
+                                   ThreadPoolExecutor pipelineExecutor) {
+        super();
+        this.controller = controller;
+        this.pipelineExecutor = pipelineExecutor;
+        this.timer = new HashedWheelTimer();
+        this.idleHandler = new IdleStateHandler(timer, READER_IDLE_TIMEOUT, WRITER_IDLE_TIMEOUT, ALL_IDLE_TIMEOUT);
+        this.readTimeoutHandler = new ReadTimeoutHandler(timer, READ_TIMEOUT);
+    }
+
+    @Override
+    public ChannelPipeline getPipeline() throws Exception {
+        //OFChannelState state = new OFChannelState();
+
+
+        ChannelPipeline pipeline = Channels.pipeline();
+
+        /*
+        if (pipelineExecutor != null)
+            pipeline.addLast("pipelineExecutor",
+                             new ExecutionHandler(pipelineExecutor));*/
+        pipeline.addLast("ofmessagedecoder", new OFMessageDecoder());
+        pipeline.addLast("ofmessageencoder", new OFMessageEncoder());
+        pipeline.addLast("idle", idleHandler);
+        //pipeline.addLast("timeout", readTimeoutHandler);
+        //pipeline.addLast("handshaketimeout",
+        //                 new HandshakeTimeoutHandler(state, timer, 15));
+
+        /*
+        if (pipelineExecutor != null)
+            pipeline.addLast("pipelineExecutor",
+                             new ExecutionHandler(pipelineExecutor));*/
+        pipeline.addLast("handler", controller.getChannelHandler());
+        return pipeline;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/PriorityMessage.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/PriorityMessage.java
new file mode 100644 (file)
index 0000000..c9d1724
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openflow.protocol.OFMessage;
+
+/**
+ * This class describes an OpenFlow message with priority
+ */
+class PriorityMessage {
+    OFMessage msg;
+    int priority;
+    final static AtomicLong seq = new AtomicLong();
+    final long seqNum;
+    boolean syncReply; // set to true if we want to be blocked until the response arrives
+
+    public PriorityMessage(OFMessage msg, int priority) {
+        this.msg = msg;
+        this.priority = priority;
+        this.seqNum = seq.getAndIncrement();
+        this.syncReply = false;
+    }
+
+    public PriorityMessage(OFMessage msg, int priority, boolean syncReply) {
+        this(msg, priority);
+        this.syncReply = syncReply;
+    }
+
+    public OFMessage getMsg() {
+        return msg;
+    }
+
+    public void setMsg(OFMessage msg) {
+        this.msg = msg;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+
+    public void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+    @Override
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
+    @Override
+    public String toString() {
+        return "PriorityMessage[" + ReflectionToStringBuilder.toString(this)
+                + "]";
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/StatisticsCollector.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/StatisticsCollector.java
new file mode 100644 (file)
index 0000000..98fb803
--- /dev/null
@@ -0,0 +1,81 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFStatisticsReply;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.statistics.OFStatistics;
+
+public class StatisticsCollector implements Callable<Object> {
+
+    private ISwitch sw;
+    private Integer xid;
+    private OFStatisticsRequest request;
+    private CountDownLatch latch;
+    private Object result;
+    private List<OFStatistics> stats;
+
+    public StatisticsCollector(ISwitch sw, int xid, OFStatisticsRequest request) {
+        this.sw = sw;
+        this.xid = xid;
+        this.request = request;
+        latch = new CountDownLatch(1);
+        result = new Object();
+        stats = new CopyOnWriteArrayList<OFStatistics>();
+    }
+
+    /*
+     * accumulate the stats records in result
+     * Returns: true: if this is the last record
+     *                 false: more to come
+     */
+    public boolean collect(OFStatisticsReply reply) {
+        synchronized (result) {
+            stats.addAll(reply.getStatistics());
+            if ((reply.getFlags() & 0x01) == 0) {
+                // all stats are collected, done
+                result = stats;
+                return true;
+            } else {
+                // still waiting for more to come
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public Object call() throws Exception {
+        sw.asyncSend(request, xid);
+        // free up the request as it is no longer needed
+        request = null;
+        // wait until all stats replies are received or timeout
+        latch.await();
+        return result;
+    }
+
+    public Integer getXid() {
+        return this.xid;
+    }
+
+    public void wakeup() {
+        this.latch.countDown();
+    }
+
+    public void wakeup(OFError errorMsg) {
+
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchEvent.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchEvent.java
new file mode 100644 (file)
index 0000000..87e30d7
--- /dev/null
@@ -0,0 +1,64 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.openflow.protocol.OFMessage;
+
+public class SwitchEvent {
+
+    public static enum SwitchEventType {
+        SWITCH_ADD, SWITCH_DELETE, SWITCH_ERROR, SWITCH_MESSAGE,
+    }
+
+    private SwitchEventType eventType;
+    private ISwitch sw;
+    private OFMessage msg;
+
+    public SwitchEvent(SwitchEventType type, ISwitch sw, OFMessage msg) {
+        this.eventType = type;
+        this.sw = sw;
+        this.msg = msg;
+    }
+
+    public SwitchEventType getEventType() {
+        return this.eventType;
+    }
+
+    public ISwitch getSwitch() {
+        return this.sw;
+    }
+
+    public OFMessage getMsg() {
+        return this.msg;
+    }
+
+    @Override
+    public String toString() {
+        String s;
+        switch (this.eventType) {
+        case SWITCH_ADD:
+            s = "SWITCH_ADD";
+            break;
+        case SWITCH_DELETE:
+            s = "SWITCH_DELETE";
+            break;
+        case SWITCH_ERROR:
+            s = "SWITCH_ERROR";
+            break;
+        case SWITCH_MESSAGE:
+            s = "SWITCH_MESSAGE";
+            break;
+        default:
+            s = "?" + this.eventType.ordinal() + "?";
+        }
+        return "Switch Event: " + s;
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SynchronousMessage.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SynchronousMessage.java
new file mode 100644 (file)
index 0000000..04c8dd4
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.openflow.protocol.OFBarrierRequest;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFMessage;
+
+/**
+ * This class implements synchronous operations on message send to a switch. If
+ * syncRequest is set to true, it sends the requested message to the switch
+ * followed by a Barrier request message. It returns the result once it gets the
+ * reply from the switch or after a timeout. If the protocol does not dictate
+ * the switch to reply the processing status for a particular message, the
+ * Barrier request forces the switch to reply saying whether or not the message
+ * processing was successful for messages sent to the switch up to this point.
+ * If syncRequest is false, it simply skips the message send and just waits for
+ * the response back.
+ */
+public class SynchronousMessage implements Callable<Object> {
+
+
+
+
+    private ISwitch sw;
+    private Integer xid;
+    private OFMessage syncMsg;
+    protected CountDownLatch latch;
+    private Object result;
+    private boolean syncRequest;
+
+    public SynchronousMessage(ISwitch sw, Integer xid, OFMessage msg,
+            boolean syncRequest) {
+        this.sw = sw;
+        this.xid = xid;
+        syncMsg = msg;
+        latch = new CountDownLatch(1);
+        result = null;
+        this.syncRequest = syncRequest;
+    }
+
+    @Override
+    public Object call() throws Exception {
+        /*
+         * Send out message only if syncRequest is set to true. Otherwise, just
+         * wait for the Barrier response back.
+         */
+
+        if (syncRequest) {
+            sw.asyncSend(syncMsg, xid);
+            if (!(syncMsg instanceof OFBarrierRequest)) {
+                OFBarrierRequest barrierMsg = new OFBarrierRequest();
+                sw.asyncSend(barrierMsg, xid);
+            }
+        }
+        latch.await();
+        return result;
+    }
+
+    public Integer getXid() {
+        return this.xid;
+    }
+
+    public void wakeup() {
+        this.latch.countDown();
+    }
+
+    public void wakeup(OFError e) {
+        result = e;
+        wakeup();
+    }
+
+
+}
\ No newline at end of file
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/TrafficStatisticsHandler.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/TrafficStatisticsHandler.java
new file mode 100644 (file)
index 0000000..540ec39
--- /dev/null
@@ -0,0 +1,336 @@
+package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+
+public class TrafficStatisticsHandler {
+
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(EnhancedController.class);
+
+    private Timeout statsTaskHandle = null;
+
+    private Map<String, AtomicLong> currentCounterMap = new ConcurrentHashMap<String, AtomicLong>();
+    private Map<String, AtomicLong> lastCounterMap = new ConcurrentHashMap<String, AtomicLong>();
+    private Map<String, Long> lastMeasurementTStamp = new ConcurrentHashMap<String, Long>();
+    private List<String> rawRateMeasurementData = new ArrayList<String>();
+
+    private ConcurrentHashMap<Integer, AtomicLong> msgRcvEntityCounter =
+            new ConcurrentHashMap<Integer, AtomicLong>();
+    private ConcurrentHashMap<Integer, AtomicLong> msgSndEntityCounter =
+            new ConcurrentHashMap<Integer, AtomicLong>();
+
+
+
+    private static final long STATISTICS_RATE_INTERVAL = 25000;
+    private static final int STATISTICS_PRINT_INTREVAL = 180;
+    private static List<Long> packetInProcessingTimeList = new ArrayList<Long>();
+    private static List<Integer> pendingTaskCountList = new ArrayList<Integer>();
+
+
+    public static final String ENTITY_COUNTER_RCV_MSG = "SWITCHWISE_RCV_MSG_COUNT";
+    public static final String ENTITY_COUNTER_SND_MSG = "SWITCHWISE_SND_MSG_COUNT";
+
+    private HashedWheelTimer hashedWheelTimer = null;
+
+    public static final String ADDED_SWITCHES = "ADDED_SWITCHES";
+    public static final String CONNECTED_SWITCHES = "CONNECTED_SWITCHES";
+    public static final String DELETED_SWITCHES = "DELETED_SWITCHES";
+    public static final String DISCONNECTED_SWITCHES = "DISCONNECTED_SWITCHES";
+    public static final String SWITCH_ERROR = "SWITCH_ERROR";
+
+
+
+    public static final String EXCEPTION_CAUGHT = "EXCEPTION_CAUGHT";
+    public static final String MESSAGE_RECEIVED = "MESSAGE_RECEIVED";  // DO RATE-MEASUREMENTS
+
+    public static final String MSG_LISTENER_INVOCATION = "MSG_LISTENER_INVOCATION";
+    public static final String HELLO_RECEIVED = "HELLO_RECEIVED";
+    public static final String HELLO_SENT = "HELLO_SENT";
+    public static final String ECHO_REQUEST_SENT = "ECHO_REQUEST_SENT";
+    public static final String ECHO_REQUEST_RECEIVED = "ECHO_REQUEST_RECEIVED";
+    public static final String ECHO_REPLY_SENT = "ECHO_REPLY_SENT";
+    public static final String ECHO_REPLY_RECEIVED = "ECHO_REPLY_RECEIVED";
+    public static final String FEATURES_REQUEST_SENT = "FEATURES_REQUEST_SENT";
+    public static final String FEATURES_REQUEST_RECEIVED = "FEATURES_REQUEST_RECEIVED";
+    public static final String FEATURES_REPLY_SENT = "FEATURES_REPLY_SENT";
+    public static final String FEATURES_REPLY_RECEIVED = "FEATURES_REPLY_RECEIVED";
+    public static final String CONFIG_REQUEST_SENT = "CONFIG_REQUEST_SENT";
+    public static final String CONFIG_REQUEST_RECEIVED = "CONFIG_REQUEST_RECEIVED";
+    public static final String CONFIG_REPLY_SENT = "CONFIG_REPLY_SENT";
+    public static final String CONFIG_REPLY_RECEIVED = "CONFIG_REPLY_RECEIVED";
+    public static final String BARRIER_REQUEST_SENT = "BARRIER_REQUEST_SENT";
+    public static final String BARRIER_REPLY_RECEIVED = "BARRIER_REPLY_RECEIVED";
+    public static final String ERROR_MSG_RECEIVED = "ERROR_MSG_RECEIVED";
+    public static final String PORT_STATUS_RECEIVED = "PORT_STATUS";
+    public static final String PACKET_IN_RECEIVED = "PACKET_IN";        // DO RATE-MEASUREMENTS
+    public static final String FLOW_MOD_SENT = "FLOW_MOD_SENT";            // DO RATE-MEASUREMENTS ==> To be determined as to where to collect this data from
+    public static final String STATS_REQUEST_SENT = "STATS_REQUEST_SENT";     // DO RATE-MEASUREMENTS ==> To be determined as to where to collect this data from
+    public static final String STATS_RESPONSE_RECEIVED = "STATS_RESPONSE_RECEIVED";
+
+    public static final String UPDATE_PHYSICAL_PORT = "UPDATE_PHYSICAL_PORT";
+
+    private static final int TASK_SCHEDULE_INITIAL_DELAY_IN_SECONDS = 10;
+
+    private int trackPktInProcessing = 0;
+    private static final int PKT_IN_PROCESSING_DURATION_SAMPLING_COUNT = 100000;
+
+
+    public TrafficStatisticsHandler(HashedWheelTimer timer){
+        this.hashedWheelTimer = timer;
+    }
+
+
+    public void init(){
+
+        currentCounterMap.put(MSG_LISTENER_INVOCATION, new AtomicLong(0));
+        currentCounterMap.put(ADDED_SWITCHES, new AtomicLong(0));
+        currentCounterMap.put(DELETED_SWITCHES, new AtomicLong(0));
+        currentCounterMap.put(CONNECTED_SWITCHES, new AtomicLong(0));
+        currentCounterMap.put(DISCONNECTED_SWITCHES, new AtomicLong(0));
+        currentCounterMap.put(SWITCH_ERROR, new AtomicLong(0));
+        currentCounterMap.put(HELLO_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(HELLO_SENT, new AtomicLong(0));
+        currentCounterMap.put(ECHO_REQUEST_SENT, new AtomicLong(0));
+        currentCounterMap.put(ECHO_REQUEST_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(ECHO_REPLY_SENT, new AtomicLong(0));
+        currentCounterMap.put(ECHO_REPLY_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(EXCEPTION_CAUGHT, new AtomicLong(0));
+        currentCounterMap.put(MESSAGE_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(FEATURES_REQUEST_SENT, new AtomicLong(0));
+        currentCounterMap.put(FEATURES_REQUEST_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(FEATURES_REPLY_SENT, new AtomicLong(0));
+        currentCounterMap.put(FEATURES_REPLY_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(CONFIG_REQUEST_SENT, new AtomicLong(0));
+        currentCounterMap.put(CONFIG_REQUEST_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(CONFIG_REPLY_SENT, new AtomicLong(0));
+        currentCounterMap.put(CONFIG_REPLY_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(BARRIER_REQUEST_SENT, new AtomicLong(0));
+        currentCounterMap.put(BARRIER_REPLY_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(ERROR_MSG_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(PORT_STATUS_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(PACKET_IN_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(FLOW_MOD_SENT, new AtomicLong(0));
+        currentCounterMap.put(STATS_REQUEST_SENT, new AtomicLong(0));
+        currentCounterMap.put(STATS_RESPONSE_RECEIVED, new AtomicLong(0));
+        currentCounterMap.put(UPDATE_PHYSICAL_PORT, new AtomicLong(0));
+
+        lastCounterMap.put(MSG_LISTENER_INVOCATION, new AtomicLong(0));
+        lastCounterMap.put(ADDED_SWITCHES, new AtomicLong(0));
+        lastCounterMap.put(DELETED_SWITCHES, new AtomicLong(0));
+        lastCounterMap.put(CONNECTED_SWITCHES, new AtomicLong(0));
+        lastCounterMap.put(DISCONNECTED_SWITCHES, new AtomicLong(0));
+        lastCounterMap.put(SWITCH_ERROR, new AtomicLong(0));
+        lastCounterMap.put(HELLO_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(HELLO_SENT, new AtomicLong(0));
+        lastCounterMap.put(FEATURES_REQUEST_SENT, new AtomicLong(0));
+        lastCounterMap.put(FEATURES_REQUEST_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(ECHO_REQUEST_SENT, new AtomicLong(0));
+        lastCounterMap.put(ECHO_REQUEST_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(ECHO_REPLY_SENT, new AtomicLong(0));
+        lastCounterMap.put(ECHO_REPLY_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(EXCEPTION_CAUGHT, new AtomicLong(0));
+        lastCounterMap.put(MESSAGE_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(FEATURES_REPLY_SENT, new AtomicLong(0));
+        lastCounterMap.put(FEATURES_REPLY_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(CONFIG_REQUEST_SENT, new AtomicLong(0));
+        lastCounterMap.put(CONFIG_REQUEST_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(CONFIG_REPLY_SENT, new AtomicLong(0));
+        lastCounterMap.put(CONFIG_REPLY_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(BARRIER_REQUEST_SENT, new AtomicLong(0));
+        lastCounterMap.put(BARRIER_REPLY_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(ERROR_MSG_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(PORT_STATUS_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(PACKET_IN_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(FLOW_MOD_SENT, new AtomicLong(0));
+        lastCounterMap.put(STATS_REQUEST_SENT, new AtomicLong(0));
+        lastCounterMap.put(STATS_RESPONSE_RECEIVED, new AtomicLong(0));
+        lastCounterMap.put(UPDATE_PHYSICAL_PORT, new AtomicLong(0));
+
+        lastMeasurementTStamp.put(MSG_LISTENER_INVOCATION, new Long(0));
+        lastMeasurementTStamp.put(ADDED_SWITCHES, new Long(0));
+        lastMeasurementTStamp.put(DELETED_SWITCHES, new Long(0));
+        lastMeasurementTStamp.put(CONNECTED_SWITCHES, new Long(0));
+        lastMeasurementTStamp.put(DISCONNECTED_SWITCHES, new Long(0));
+        lastMeasurementTStamp.put(SWITCH_ERROR, new Long(0));
+        lastMeasurementTStamp.put(HELLO_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(HELLO_SENT, new Long(0));
+        lastMeasurementTStamp.put(ECHO_REQUEST_SENT, new Long(0));
+        lastMeasurementTStamp.put(ECHO_REQUEST_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(ECHO_REPLY_SENT, new Long(0));
+        lastMeasurementTStamp.put(ECHO_REPLY_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(EXCEPTION_CAUGHT, new Long(0));
+        lastMeasurementTStamp.put(MESSAGE_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(FEATURES_REQUEST_SENT, new Long(0));
+        lastMeasurementTStamp.put(FEATURES_REQUEST_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(FEATURES_REPLY_SENT, new Long(0));
+        lastMeasurementTStamp.put(FEATURES_REPLY_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(CONFIG_REQUEST_SENT, new Long(0));
+        lastMeasurementTStamp.put(CONFIG_REQUEST_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(CONFIG_REPLY_SENT, new Long(0));
+        lastMeasurementTStamp.put(CONFIG_REPLY_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(BARRIER_REQUEST_SENT, new Long(0));
+        lastMeasurementTStamp.put(BARRIER_REPLY_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(ERROR_MSG_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(PORT_STATUS_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(PACKET_IN_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(FLOW_MOD_SENT, new Long(0));
+        lastMeasurementTStamp.put(STATS_REQUEST_SENT, new Long(0));
+        lastMeasurementTStamp.put(STATS_RESPONSE_RECEIVED, new Long(0));
+        lastMeasurementTStamp.put(UPDATE_PHYSICAL_PORT, new Long(0));
+
+        /*
+        rateMap.put(HELLO_SENT, new Double(0.00000000));
+        rateMap.put(FEATURES_REQUEST, new Double(0.00000000));
+        rateMap.put(FEATURES_REPLY, new Double(0.00000000));
+        rateMap.put(CONFIG_REQUEST, new Double(0.00000000));
+        rateMap.put(CONFIG_REPLY, new Double(0.00000000));
+        rateMap.put(PORT_STATUS, new Double(0.00000000));
+        rateMap.put(PACKET_IN, new Double(0.00000000));
+        rateMap.put(FLOW_MOD_SENT, new Double(0.00000000));
+
+
+        history.put(HELLO_SENT, new ArrayList());
+        history.put(FEATURES_REQUEST, new ArrayList());
+        history.put(FEATURES_REPLY, new ArrayList());
+        history.put(CONFIG_REQUEST, new ArrayList());
+        history.put(CONFIG_REPLY, new ArrayList());
+        history.put(PORT_STATUS, new ArrayList());
+        history.put(PACKET_IN, new ArrayList());
+        history.put(FLOW_MOD_SENT, new ArrayList());
+        */
+
+        statsTaskHandle = this.hashedWheelTimer.newTimeout(new StatsOutTask(),
+                TASK_SCHEDULE_INITIAL_DELAY_IN_SECONDS, TimeUnit.SECONDS);
+
+    }
+
+    public void stopStatsHandler(){
+        if (statsTaskHandle != null){
+            statsTaskHandle.cancel();
+        }
+    }
+
+    public void reportPacketInProcessingTime(long duration){
+        trackPktInProcessing++;
+        if (trackPktInProcessing > PKT_IN_PROCESSING_DURATION_SAMPLING_COUNT){
+            packetInProcessingTimeList.add(new Long(duration));
+            trackPktInProcessing = 0;
+        }
+    }
+
+    public void addEntityForCounter(Integer entityID, String counterType){
+        if (counterType.equalsIgnoreCase(ENTITY_COUNTER_RCV_MSG)){
+            msgRcvEntityCounter.put(entityID, new AtomicLong(0));
+        }
+        else{
+            msgSndEntityCounter.put(entityID, new AtomicLong(0));
+        }
+    }
+
+    public void countForEntitySimpleMeasurement(Integer entityID, String counterType){
+        if (counterType.equalsIgnoreCase(ENTITY_COUNTER_RCV_MSG)){
+            //msgRcvEntityCounter.get(entityID).incrementAndGet();
+        }
+        else{
+            //msgSndEntityCounter.get(entityID).incrementAndGet();
+        }
+    }
+
+
+    public void countForSimpleMeasurement(String counterName){
+        currentCounterMap.get(counterName).incrementAndGet();
+    }
+
+    public void countForRateMeasurement(String counterName){
+
+        long currCntr = currentCounterMap.get(counterName).incrementAndGet();
+        if (lastMeasurementTStamp.get(counterName) == 0){
+            lastMeasurementTStamp.put(counterName, System.currentTimeMillis());
+        }
+
+        Long currentCount = new Long(currCntr);
+        Long lastCount = lastCounterMap.get(counterName).get();
+
+        //Double rate = 0.00000000000;
+        if ((currentCount - lastCount) == STATISTICS_RATE_INTERVAL){
+            Long currentTime = System.currentTimeMillis();
+            Long lastTime = lastMeasurementTStamp.get(counterName);
+            //rate = new Double((STATISTICS_RATE_INTERVAL/(currentTime-lastTime))*1000); //convert to count/sec
+            rawRateMeasurementData.add("CN:" + counterName +
+                    ",CC:" + currentCount +
+                    ",LC:" + lastCount +
+                    ",CT:" + currentTime +
+                    ",LT:" + lastTime +
+                    ",CV:" + ((STATISTICS_RATE_INTERVAL/(currentTime-lastTime))*1000));
+            lastCounterMap.put(counterName, new AtomicLong(currentCount));
+            lastMeasurementTStamp.put(counterName, currentTime);
+            //history.get(counterName).add(String.valueOf(rate.doubleValue()));
+            //rateMap.put(counterName, rate);
+        }
+
+    }
+
+
+    private class StatsOutTask implements TimerTask {
+
+        @Override
+        public void run(Timeout timeout) throws Exception {
+
+            statsTaskHandle = timeout;
+            logger.warn(">>>>>>Raw Counter values at controller BEGIN<<<<<<<<");
+
+            for (Entry<String, AtomicLong> entry : currentCounterMap.entrySet()){
+                logger.warn("{} {}", entry.getKey(), entry.getValue());
+            }
+            logger.warn(">>>>>>Counter values at controller END  <<<<<<<<");
+
+            logger.warn(">>>>>>Entity Counter values at controller BEGIN<<<<<<<<");
+
+            for (Entry<Integer, AtomicLong> entry : msgRcvEntityCounter.entrySet()){
+                logger.warn("SwitchID {} : Rcv Msg Count {}", entry.getKey(), entry.getValue());
+            }
+            logger.warn(">>>>>>Entity Counter values at controller END  <<<<<<<<");
+
+            logger.warn(">>>>>>Raw data rate values at controller BEGIN<<<<<<<<");
+
+            for (String str : rawRateMeasurementData ){
+                logger.warn("{}", str);
+            }
+            logger.warn(">>>>>>Raw data rate values at controller END  <<<<<<<<");
+
+
+            if (packetInProcessingTimeList.size() > 0){
+                logger.warn("================ MAX PACKET_IN PROC TIME in microseconds : {}",
+                        Collections.max(packetInProcessingTimeList)/1000);
+                logger.warn("================ MIN PACKET_IN PROC TIME in microseconds : {}",
+                        Collections.min(packetInProcessingTimeList)/1000);
+                long v = 0L;
+                int track = 0;
+                for (Long val : packetInProcessingTimeList){
+                    v = v + val.longValue();
+                    track++;
+                }
+                logger.warn("================ AVG PACKET_IN PROC TIME in microseconds : {}",
+                        ((double)(v/track))/1000);
+            }
+            hashedWheelTimer.newTimeout(this, STATISTICS_PRINT_INTREVAL, TimeUnit.SECONDS);
+        }
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java
new file mode 100644 (file)
index 0000000..0f6c630
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketListen;
+import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux;
+import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
+import org.opendaylight.controller.protocol_plugin.openflow.IPluginReadServiceFilter;
+import org.opendaylight.controller.protocol_plugin.openflow.IRefreshInternalProvider;
+import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsServiceShimListener;
+import org.opendaylight.controller.protocol_plugin.openflow.ITopologyServiceShimListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.internal.EnhancedController;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.discovery.IDiscoveryService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
+import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.controller.sal.packet.IPluginInDataPacketService;
+import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService;
+import org.opendaylight.controller.sal.reader.IPluginInReadService;
+import org.opendaylight.controller.sal.topology.IPluginInTopologyService;
+import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Openflow protocol plugin Activator
+ *
+ *
+ */
+public class Activator extends ComponentActivatorAbstractBase {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(Activator.class);
+
+    /**
+     * Function called when the activator starts just after some initializations
+     * are done by the ComponentActivatorAbstractBase.
+     *
+     */
+    public void init() {
+    }
+
+    /**
+     * Function called when the activator stops just before the cleanup done by
+     * ComponentActivatorAbstractBase
+     *
+     */
+    public void destroy() {
+    }
+
+    /**
+     * Function that is used to communicate to dependency manager the list of
+     * known implementations for services inside a container
+     *
+     *
+     * @return An array containing all the CLASS objects that will be
+     *         instantiated in order to get an fully working implementation
+     *         Object
+     */
+    public Object[] getImplementations() {
+        Object[] res = { TopologyServices.class, DataPacketServices.class,
+                InventoryService.class, ReadService.class,
+                FlowProgrammerNotifier.class };
+        return res;
+    }
+
+    /**
+     * Function that is called when configuration of the dependencies is
+     * required.
+     *
+     * @param c
+     *            dependency manager Component object, used for configuring the
+     *            dependencies exported and imported
+     * @param imp
+     *            Implementation class that is being configured, needed as long
+     *            as the same routine can configure multiple implementations
+     * @param containerName
+     *            The containerName being configured, this allow also optional
+     *            per-container different behavior if needed, usually should not
+     *            be the case though.
+     */
+    public void configureInstance(Component c, Object imp, String containerName) {
+        if (imp.equals(TopologyServices.class)) {
+            // export the service to be used by SAL
+            c.setInterface(
+                    new String[] { IPluginInTopologyService.class.getName(),
+                            ITopologyServiceShimListener.class.getName() },
+                    null);
+            // Hook the services coming in from SAL, as optional in
+            // case SAL is not yet there, could happen
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutTopologyService.class)
+                    .setCallbacks("setPluginOutTopologyService",
+                            "unsetPluginOutTopologyService").setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(IRefreshInternalProvider.class)
+                    .setCallbacks("setRefreshInternalProvider",
+                            "unsetRefreshInternalProvider").setRequired(false));
+        }
+
+        if (imp.equals(InventoryService.class)) {
+            // export the service
+            c.setInterface(
+                    new String[] { IPluginInInventoryService.class.getName(),
+                            IStatisticsListener.class.getName(),
+                            IInventoryShimInternalListener.class.getName() },
+                    null);
+
+            // Now lets add a service dependency to make sure the
+            // provider of service exists
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutInventoryService.class)
+                    .setCallbacks("setPluginOutInventoryServices",
+                            "unsetPluginOutInventoryServices")
+                    .setRequired(false));
+        }
+
+        if (imp.equals(DataPacketServices.class)) {
+            // export the service to be used by SAL
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            // Set the protocolPluginType property which will be used
+            // by SAL
+            props.put("protocolPluginType", Node.NodeIDType.OPENFLOW);
+            c.setInterface(IPluginInDataPacketService.class.getName(), props);
+            // Hook the services coming in from SAL, as optional in
+            // case SAL is not yet there, could happen
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            // This is required for the transmission to happen properly
+            c.add(createServiceDependency().setService(IDataPacketMux.class)
+                    .setCallbacks("setIDataPacketMux", "unsetIDataPacketMux")
+                    .setRequired(true));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutDataPacketService.class)
+                    .setCallbacks("setPluginOutDataPacketService",
+                            "unsetPluginOutDataPacketService")
+                    .setRequired(false));
+        }
+
+        if (imp.equals(ReadService.class)) {
+            // export the service to be used by SAL
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            // Set the protocolPluginType property which will be used
+            // by SAL
+            props.put("protocolPluginType", Node.NodeIDType.OPENFLOW);
+            c.setInterface(IPluginInReadService.class.getName(), props);
+            c.add(createServiceDependency()
+                    .setService(IPluginReadServiceFilter.class)
+                    .setCallbacks("setService", "unsetService")
+                    .setRequired(true));
+        }
+
+        if (imp.equals(FlowProgrammerNotifier.class)) {
+            // export the service to be used by SAL
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            // Set the protocolPluginType property which will be used
+            // by SAL
+            props.put("protocolPluginType", Node.NodeIDType.OPENFLOW);
+            c.setInterface(IFlowProgrammerNotifier.class.getName(), props);
+
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutFlowProgrammerService.class)
+                    .setCallbacks("setPluginOutFlowProgrammerService",
+                            "unsetPluginOutFlowProgrammerService")
+                    .setRequired(true));
+        }
+    }
+
+    /**
+     * Function that is used to communicate to dependency manager the list of
+     * known implementations for services that are container independent.
+     *
+     *
+     * @return An array containing all the CLASS objects that will be
+     *         instantiated in order to get an fully working implementation
+     *         Object
+     */
+    public Object[] getGlobalImplementations() {
+        Object[] res = { EnhancedController.class, OFStatisticsManager.class,
+                FlowProgrammerService.class, ReadServiceFilter.class,
+                DiscoveryService.class, DataPacketMuxDemux.class,
+                InventoryServiceShim.class, TopologyServiceShim.class };
+        return res;
+    }
+
+    /**
+     * Function that is called when configuration of the dependencies is
+     * required.
+     *
+     * @param c
+     *            dependency manager Component object, used for configuring the
+     *            dependencies exported and imported
+     * @param imp
+     *            Implementation class that is being configured, needed as long
+     *            as the same routine can configure multiple implementations
+     */
+    public void configureGlobalInstance(Component c, Object imp) {
+
+        if (imp.equals(EnhancedController.class)) {
+            logger.debug("Activator configureGlobalInstance( ) is called");
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            props.put("name", "Controller");
+            c.setInterface(IController.class.getName(), props);
+        }
+
+        if (imp.equals(FlowProgrammerService.class)) {
+            // export the service to be used by SAL
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            // Set the protocolPluginType property which will be used
+            // by SAL
+            props.put("protocolPluginType", Node.NodeIDType.OPENFLOW);
+            c.setInterface(
+                    new String[] {
+                            IPluginInFlowProgrammerService.class.getName(),
+                            IMessageListener.class.getName(),
+                            IContainerListener.class.getName(),
+                            IInventoryShimExternalListener.class.getName() },
+                    props);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+
+            c.add(createServiceDependency()
+                    .setService(IFlowProgrammerNotifier.class)
+                    .setCallbacks("setFlowProgrammerNotifier",
+                            "unsetsetFlowProgrammerNotifier")
+                    .setRequired(false));
+
+        }
+
+        if (imp.equals(ReadServiceFilter.class)) {
+
+            c.setInterface(
+                    new String[] { IPluginReadServiceFilter.class.getName(),
+                            IContainerListener.class.getName() }, null);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IOFStatisticsManager.class)
+                    .setCallbacks("setService", "unsetService")
+                    .setRequired(true));
+        }
+
+        if (imp.equals(OFStatisticsManager.class)) {
+
+            c.setInterface(new String[] { IOFStatisticsManager.class.getName(),
+                    IInventoryShimExternalListener.class.getName() }, null);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IStatisticsListener.class)
+                    .setCallbacks("setStatisticsListener",
+                            "unsetStatisticsListener").setRequired(false));
+        }
+
+        if (imp.equals(DiscoveryService.class)) {
+            // export the service
+            c.setInterface(
+                    new String[] {
+                            IInventoryShimExternalListener.class.getName(),
+                            IDataPacketListen.class.getName(),
+                            IContainerListener.class.getName() }, null);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createContainerServiceDependency(
+                    GlobalConstants.DEFAULT.toString())
+                    .setService(IPluginInInventoryService.class)
+                    .setCallbacks("setPluginInInventoryService",
+                            "unsetPluginInInventoryService").setRequired(true));
+            c.add(createServiceDependency().setService(IDataPacketMux.class)
+                    .setCallbacks("setIDataPacketMux", "unsetIDataPacketMux")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IDiscoveryService.class)
+                    .setCallbacks("setDiscoveryService",
+                            "unsetDiscoveryService").setRequired(true));
+        }
+
+        // DataPacket mux/demux services, which is teh actual engine
+        // doing the packet switching
+        if (imp.equals(DataPacketMuxDemux.class)) {
+            c.setInterface(new String[] { IDataPacketMux.class.getName(),
+                    IContainerListener.class.getName(),
+                    IInventoryShimExternalListener.class.getName() }, null);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IPluginOutDataPacketService.class)
+                    .setCallbacks("setPluginOutDataPacketService",
+                            "unsetPluginOutDataPacketService")
+                    .setRequired(false));
+            // See if there is any local packet dispatcher
+            c.add(createServiceDependency()
+                    .setService(IDataPacketListen.class)
+                    .setCallbacks("setIDataPacketListen",
+                            "unsetIDataPacketListen").setRequired(false));
+        }
+
+        if (imp.equals(InventoryServiceShim.class)) {
+            c.setInterface(new String[] { IContainerListener.class.getName() },
+                    null);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IInventoryShimInternalListener.class)
+                    .setCallbacks("setInventoryShimInternalListener",
+                            "unsetInventoryShimInternalListener")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IInventoryShimExternalListener.class)
+                    .setCallbacks("setInventoryShimExternalListener",
+                            "unsetInventoryShimExternalListener")
+                    .setRequired(false));
+        }
+
+        if (imp.equals(TopologyServiceShim.class)) {
+            c.setInterface(new String[] { IDiscoveryService.class.getName(),
+                    IContainerListener.class.getName(),
+                    IRefreshInternalProvider.class.getName(),
+                    IInventoryShimExternalListener.class.getName() }, null);
+          c.add(createServiceDependency()
+                    .setService(ITopologyServiceShimListener.class)
+                    .setCallbacks("setTopologyServiceShimListener",
+                            "unsetTopologyServiceShimListener")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IOFStatisticsManager.class)
+                    .setCallbacks("setStatisticsManager",
+                            "unsetStatisticsManager").setRequired(false));
+        }
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DataPacketMuxDemux.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DataPacketMuxDemux.java
new file mode 100644 (file)
index 0000000..280e925
--- /dev/null
@@ -0,0 +1,410 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketListen;
+import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService;
+import org.opendaylight.controller.sal.packet.PacketResult;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+
+public class DataPacketMuxDemux implements IContainerListener,
+        IMessageListener, IDataPacketMux, IInventoryShimExternalListener {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(DataPacketMuxDemux.class);
+    private IController controller = null;
+    private ConcurrentMap<Long, ISwitch> swID2ISwitch = new ConcurrentHashMap<Long, ISwitch>();
+    // Gives a map between a Container and all the DataPacket listeners on SAL
+    private ConcurrentMap<String, IPluginOutDataPacketService> pluginOutDataPacketServices = new ConcurrentHashMap<String, IPluginOutDataPacketService>();
+    // Gives a map between a NodeConnector and the containers to which it belongs
+    private ConcurrentMap<NodeConnector, List<String>> nc2Container = new ConcurrentHashMap<NodeConnector, List<String>>();
+    // Gives a map between a Container and the FlowSpecs on it
+    private ConcurrentMap<String, List<ContainerFlow>> container2FlowSpecs = new ConcurrentHashMap<String, List<ContainerFlow>>();
+    // Track local data packet listener
+    private List<IDataPacketListen> iDataPacketListen = new CopyOnWriteArrayList<IDataPacketListen>();
+
+    void setIDataPacketListen(IDataPacketListen s) {
+        if (this.iDataPacketListen != null) {
+            if (!this.iDataPacketListen.contains(s)) {
+                logger.debug("Added new IDataPacketListen");
+                this.iDataPacketListen.add(s);
+            }
+        }
+    }
+
+    void unsetIDataPacketListen(IDataPacketListen s) {
+        if (this.iDataPacketListen != null) {
+            if (this.iDataPacketListen.contains(s)) {
+                logger.debug("Removed IDataPacketListen");
+                this.iDataPacketListen.remove(s);
+            }
+        }
+    }
+
+    void setPluginOutDataPacketService(Map<String, Object> props,
+            IPluginOutDataPacketService s) {
+        if (props == null) {
+            logger.error("Didn't receive the service properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            logger.error("containerName not supplied");
+            return;
+        }
+        if (this.pluginOutDataPacketServices != null) {
+            // It's expected only one SAL per container as long as the
+            // replication is done in the SAL implementation toward
+            // the different APPS
+            this.pluginOutDataPacketServices.put(containerName, s);
+            logger.debug("New outService for container: {}", containerName);
+        }
+    }
+
+    void unsetPluginOutDataPacketService(Map<String, Object> props,
+            IPluginOutDataPacketService s) {
+        if (props == null) {
+            logger.error("Didn't receive the service properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            logger.error("containerName not supplied");
+            return;
+        }
+        if (this.pluginOutDataPacketServices != null) {
+            this.pluginOutDataPacketServices.remove(containerName);
+            logger.debug("Removed outService for container: {}", containerName);
+        }
+    }
+
+    void setController(IController s) {
+        logger.debug("Controller provider set in DATAPACKET SERVICES");
+        this.controller = s;
+    }
+
+    void unsetController(IController s) {
+        if (this.controller == s) {
+            logger.debug("Controller provider UNset in DATAPACKET SERVICES");
+            this.controller = null;
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        this.controller.addMessageListener(OFType.PACKET_IN, this);
+    }
+
+    /**
+     * Function called by the dependency manager when at least one
+     * dependency become unsatisfied or when the component is shutting
+     * down because for example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        this.controller.removeMessageListener(OFType.PACKET_IN, this);
+
+        // Clear state that may need to be reused on component restart
+        this.pluginOutDataPacketServices.clear();
+        this.nc2Container.clear();
+        this.container2FlowSpecs.clear();
+        this.controller = null;
+        this.swID2ISwitch.clear();
+    }
+
+    @Override
+    public void receive(ISwitch sw, OFMessage msg) {
+        if (sw == null || msg == null
+                || this.pluginOutDataPacketServices == null) {
+            // Something fishy, we cannot do anything
+            logger.debug("sw: {} and/or msg: {} and/or pluginOutDataPacketServices: {} is null!",
+                        new Object[]{sw, msg, this.pluginOutDataPacketServices});
+            return;
+        }
+        if (msg instanceof OFPacketIn) {
+            OFPacketIn ofPacket = (OFPacketIn) msg;
+            Long ofSwitchID = Long.valueOf(sw.getId());
+            Short ofPortID = Short.valueOf(ofPacket.getInPort());
+
+            try {
+                Node n = new Node(Node.NodeIDType.OPENFLOW, ofSwitchID);
+                NodeConnector p = PortConverter.toNodeConnector(ofPortID, n);
+                RawPacket dataPacket = new RawPacket(ofPacket.getPacketData());
+                dataPacket.setIncomingNodeConnector(p);
+
+                // Try to dispatch the packet locally, in here we will
+                // pass the parsed packet simply because once the
+                // packet infra is settled all the packets will passed
+                // around as parsed and read-only
+                for (int i = 0; i < this.iDataPacketListen.size(); i++) {
+                    IDataPacketListen s = this.iDataPacketListen.get(i);
+                    if (s.receiveDataPacket(dataPacket).equals(
+                            PacketResult.CONSUME)) {
+                        logger.trace("Consumed locally data packet");
+                        return;
+                    }
+                }
+
+                // Now dispatch the packet toward SAL at least for
+                // default container, we need to revisit this in a general
+                // slicing architecture refresh
+                IPluginOutDataPacketService defaultOutService = this.pluginOutDataPacketServices
+                        .get(GlobalConstants.DEFAULT.toString());
+                if (defaultOutService != null) {
+                    defaultOutService.receiveDataPacket(dataPacket);
+                    logger.trace("Dispatched to apps a frame of size: {} on container: {}",
+                            ofPacket.getPacketData().length, GlobalConstants.DEFAULT.toString());
+                }
+                // Now check the mapping between nodeConnector and
+                // Container and later on optinally filter based on
+                // flowSpec
+                /*
+                List<String> containersRX = this.nc2Container.get(p);
+                if (containersRX != null) {
+                    for (int i = 0; i < containersRX.size(); i++) {
+                        String container = containersRX.get(i);
+                        IPluginOutDataPacketService s = this.pluginOutDataPacketServices
+                                .get(container);
+                        if (s != null) {
+                            // TODO add filtering on a per-flowSpec base
+                            s.receiveDataPacket(dataPacket);
+                            logger.trace("Dispatched to apps a frame of size: {} on container: {}",
+                                    ofPacket.getPacketData().length, GlobalConstants.DEFAULT.toString());
+
+                        }
+                    }
+                }
+                */
+
+                // This is supposed to be the catch all for all the
+                // DataPacket hence we will assume it has been handled
+                return;
+            } catch (ConstructionException cex) {
+            }
+
+            // If we reach this point something went wrong.
+            return;
+        } else {
+            // We don't care about non-data packets
+            return;
+        }
+    }
+
+    @Override
+    public void transmitDataPacket(RawPacket outPkt) {
+        // Sanity check area
+        if (outPkt == null) {
+            logger.debug("outPkt is null!");
+            return;
+        }
+
+        NodeConnector outPort = outPkt.getOutgoingNodeConnector();
+        if (outPort == null) {
+            logger.debug("outPort is null! outPkt: {}", outPkt);
+            return;
+        }
+
+        if (!outPort.getType().equals(
+                NodeConnector.NodeConnectorIDType.OPENFLOW)) {
+            // The output Port is not of type OpenFlow
+            logger.debug("outPort is not OF Type! outPort: {}", outPort);
+            return;
+        }
+
+        Short port = (Short) outPort.getID();
+        Long swID = (Long) outPort.getNode().getID();
+        ISwitch sw = this.swID2ISwitch.get(swID);
+
+        if (sw == null) {
+            // If we cannot get the controller descriptor we cannot even
+            // send out the frame
+            logger.debug("swID: {} - sw is null!", swID);
+            return;
+        }
+
+        byte[] data = outPkt.getPacketData();
+        // build action
+        OFActionOutput action = new OFActionOutput().setPort(port);
+        // build packet out
+        OFPacketOut po = new OFPacketOut().setBufferId(
+                OFPacketOut.BUFFER_ID_NONE).setInPort(OFPort.OFPP_NONE)
+                .setActions(Collections.singletonList((OFAction) action))
+                .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
+
+        po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength()
+                + data.length);
+        po.setPacketData(data);
+
+        sw.asyncSend(po);
+        logger.trace("Transmitted a frame of size: {}", data.length);
+    }
+
+    public void addNode(Node node, Set<Property> props) {
+        if (node == null) {
+            logger.debug("node is null!");
+            return;
+        }
+
+        long sid = (Long) node.getID();
+        ISwitch sw = controller.getSwitches().get(sid);
+        if (sw == null) {
+            logger.debug("sid: {} - sw is null!", sid);
+            return;
+        }
+        this.swID2ISwitch.put(sw.getId(), sw);
+    }
+
+    public void removeNode(Node node) {
+        if (node == null) {
+            logger.debug("node is null!");
+            return;
+        }
+
+        long sid = (Long) node.getID();
+        ISwitch sw = controller.getSwitches().get(sid);
+        if (sw == null) {
+            logger.debug("sid: {} - sw is null!", sid);
+            return;
+        }
+        this.swID2ISwitch.remove(sw.getId());
+    }
+
+    @Override
+    public void tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+        // Do nothing
+    }
+
+    @Override
+    public void containerFlowUpdated(String containerName,
+            ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
+        if (this.container2FlowSpecs == null) {
+            logger.error("container2FlowSpecs is NULL");
+            return;
+        }
+        List<ContainerFlow> fSpecs = this.container2FlowSpecs
+                .get(containerName);
+        if (fSpecs == null) {
+            fSpecs = new CopyOnWriteArrayList<ContainerFlow>();
+        }
+        switch (t) {
+        case ADDED:
+            if (!fSpecs.contains(previousFlow)) {
+                fSpecs.add(previousFlow);
+            }
+            break;
+        case REMOVED:
+            if (fSpecs.contains(previousFlow)) {
+                fSpecs.remove(previousFlow);
+            }
+            break;
+        case CHANGED:
+            break;
+        }
+    }
+
+    @Override
+    public void nodeConnectorUpdated(String containerName, NodeConnector p,
+            UpdateType t) {
+        if (this.nc2Container == null) {
+            logger.error("nc2Container is NULL");
+            return;
+        }
+        List<String> containers = this.nc2Container.get(p);
+        if (containers == null) {
+            containers = new CopyOnWriteArrayList<String>();
+        }
+        boolean updateMap = false;
+        switch (t) {
+        case ADDED:
+            if (!containers.contains(containerName)) {
+                containers.add(containerName);
+                updateMap = true;
+            }
+            break;
+        case REMOVED:
+            if (containers.contains(containerName)) {
+                containers.remove(containerName);
+                updateMap = true;
+            }
+            break;
+        case CHANGED:
+            break;
+        }
+        if (updateMap) {
+            if (containers.isEmpty()) {
+                // Do cleanup to reduce memory footprint if no
+                // elements to be tracked
+                this.nc2Container.remove(p);
+            } else {
+                this.nc2Container.put(p, containers);
+            }
+        }
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+        // do nothing
+    }
+
+    @Override
+    public void updateNode(Node node, UpdateType type, Set<Property> props) {
+        switch (type) {
+        case ADDED:
+            addNode(node, props);
+            break;
+        case REMOVED:
+            removeNode(node);
+            break;
+        default:
+            break;
+        }
+    }
+
+    @Override
+    public void updateNodeConnector(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props) {
+        // do nothing
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DataPacketServices.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DataPacketServices.java
new file mode 100644 (file)
index 0000000..adb9d20
--- /dev/null
@@ -0,0 +1,37 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.sal.packet.IPluginInDataPacketService;
+import org.opendaylight.controller.sal.packet.RawPacket;
+
+public class DataPacketServices implements IPluginInDataPacketService {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(DataPacketServices.class);
+    private IDataPacketMux iDataPacketMux = null;
+
+    void setIDataPacketMux(IDataPacketMux s) {
+        this.iDataPacketMux = s;
+    }
+
+    void unsetIDataPacketMux(IDataPacketMux s) {
+        if (this.iDataPacketMux == s) {
+            this.iDataPacketMux = null;
+        }
+    }
+
+    @Override
+    public void transmitDataPacket(RawPacket outPkt) {
+        this.iDataPacketMux.transmitDataPacket(outPkt);
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DescStatisticsConverter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DescStatisticsConverter.java
new file mode 100644 (file)
index 0000000..01221e1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for converting openflow description statistics into SAL
+ * NodeDescription object
+ *
+ *
+ *
+ */
+public class DescStatisticsConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(DescStatisticsConverter.class);
+    NodeDescription hwDesc;
+    OFDescriptionStatistics ofDesc;
+
+    public DescStatisticsConverter(List<OFStatistics> statsList) {
+        this.hwDesc = null;
+        if( statsList != null && !statsList.isEmpty() ) {
+            this.ofDesc = (OFDescriptionStatistics) statsList.get(0);
+        }
+    }
+
+    public NodeDescription getHwDescription() {
+        if (hwDesc == null && ofDesc != null) {
+            hwDesc = new NodeDescription();
+            hwDesc.setManufacturer(ofDesc.getManufacturerDescription());
+            hwDesc.setHardware(ofDesc.getHardwareDescription());
+            hwDesc.setSoftware(ofDesc.getSoftwareDescription());
+            hwDesc.setDescription(ofDesc.getDatapathDescription());
+            hwDesc.setSerialNumber(ofDesc.getSerialNumber());
+        }
+        log.trace("OFDescriptionStatistics: {}", ofDesc);
+        log.trace("NodeDescription: {}", hwDesc);
+        return hwDesc;
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
new file mode 100644 (file)
index 0000000..972d1c0
--- /dev/null
@@ -0,0 +1,1518 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketListen;
+import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.openflow.protocol.OFPhysicalPort;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.core.Config;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Edge;
+import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.State;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.discovery.IDiscoveryService;
+import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.LLDP;
+import org.opendaylight.controller.sal.packet.LLDPTLV;
+import org.opendaylight.controller.sal.packet.LinkEncap;
+import org.opendaylight.controller.sal.packet.PacketResult;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+
+/**
+ * The class describes neighbor discovery service for an OpenFlow network.
+ */
+public class DiscoveryService implements IInventoryShimExternalListener,
+        IDataPacketListen, IContainerListener, CommandProvider {
+    private static Logger logger = LoggerFactory
+            .getLogger(DiscoveryService.class);
+    private IController controller = null;
+    private IDiscoveryService discoveryService = null;
+    private IPluginInInventoryService pluginInInventoryService = null;
+    private IDataPacketMux iDataPacketMux = null;
+
+    private List<NodeConnector> readyListHi = null; // newly added ports go into this list and will be served first
+    private List<NodeConnector> readyListLo = null; // come here after served at least once
+    private List<NodeConnector> waitingList = null; // staging area during quiet period
+    private ConcurrentMap<NodeConnector, Integer> pendingMap = null;// wait for response back
+    private ConcurrentMap<NodeConnector, Edge> edgeMap = null; // openflow edges keyed by head connector
+    private ConcurrentMap<NodeConnector, Integer> agingMap = null; // aging entries keyed by edge port
+    private ConcurrentMap<NodeConnector, Edge> prodMap = null; // production edges keyed by edge port
+
+    private Timer discoveryTimer; // discovery timer
+    private DiscoveryTimerTask discoveryTimerTask; // timer task
+    private long discoveryTimerTick = 1L * 1000; // per tick in msec
+    private int discoveryTimerTickCount = 0; // main tick counter
+    private int discoveryBatchMaxPorts = 500; // max # of ports handled in one batch
+    private int discoveryBatchRestartTicks = getDiscoveryInterval(); // periodically restart batching process
+    private int discoveryBatchPausePeriod = 5; // pause for few secs
+    private int discoveryBatchPauseTicks = discoveryBatchRestartTicks - discoveryBatchPausePeriod; // pause after this point
+    private int discoveryRetry = 2; // number of retry after initial timeout
+    private int discoveryTimeoutTicks = getDiscoveryTimeout(); // timeout in sec
+    private int discoveryAgeoutTicks = 120; // age out 2 min
+    private int discoveryConsistencyCheckMultiple = 2; // multiple of discoveryBatchRestartTicks
+    private int discoveryConsistencyCheckTickCount = discoveryBatchPauseTicks; // CC tick counter
+    private int discoveryConsistencyCheckCallingTimes = 0; // # of times CC gets called
+    private int discoveryConsistencyCheckCorrected = 0; // # of cases CC corrected
+    private boolean discoveryConsistencyCheckEnabled = true;// enable or disable CC
+    private boolean discoveryAgingEnabled = true; // enable or disable aging
+    private boolean discoverySpoofingEnabled = true; // enable or disable spoofing neighbor of a production network
+
+    private BlockingQueue<NodeConnector> transmitQ;
+    private Thread transmitThread;
+    private Boolean throttling = false; // if true, no more batching.
+    private volatile Boolean shuttingDown = false;
+
+    private LLDPTLV chassisIdTlv, portIdTlv, ttlTlv, customTlv;
+
+    class DiscoveryTransmit implements Runnable {
+        private final BlockingQueue<NodeConnector> transmitQ;
+
+        DiscoveryTransmit(BlockingQueue<NodeConnector> transmitQ) {
+            this.transmitQ = transmitQ;
+        }
+
+        public void run() {
+            while (true) {
+                try {
+                    NodeConnector nodeConnector = transmitQ.take();
+                    RawPacket outPkt = createDiscoveryPacket(nodeConnector);
+                    sendDiscoveryPacket(nodeConnector, outPkt);
+                    nodeConnector = null;
+                } catch (InterruptedException e1) {
+                    logger
+                            .warn("DiscoveryTransmit interupted", e1
+                                    .getMessage());
+                    if (shuttingDown)
+                        return;
+                } catch (Exception e2) {
+                    logger.error("",e2);
+                }
+            }
+        }
+    }
+
+    class DiscoveryTimerTask extends TimerTask {
+        public void run() {
+            checkTimeout();
+            checkAging();
+            doConsistencyCheck();
+            doDiscovery();
+        }
+    }
+
+    private RawPacket createDiscoveryPacket(NodeConnector nodeConnector) {
+        String nodeId = HexEncode.longToHexString((Long) nodeConnector
+                .getNode().getID());
+
+        // Create LLDP ChassisID TLV
+        byte[] cidValue = LLDPTLV.createChassisIDTLVValue(nodeId);
+        chassisIdTlv.setType((byte) LLDPTLV.TLVType.ChassisID.getValue())
+                .setLength((short) cidValue.length).setValue(cidValue);
+
+        // Create LLDP PortID TLV
+        String portId = nodeConnector.getNodeConnectorIDString();
+        byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId);
+        portIdTlv.setType((byte) LLDPTLV.TLVType.PortID.getValue())
+                .setLength((short) pidValue.length).setValue(pidValue);
+
+        // Create LLDP Custom TLV
+        byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnector.toString());
+        customTlv.setType((byte) LLDPTLV.TLVType.Custom.getValue())
+                .setLength((short) customValue.length).setValue(customValue);
+
+        // Create LLDP Custom Option list
+        List<LLDPTLV> customList = new ArrayList<LLDPTLV>();
+        customList.add(customTlv);
+
+        // Create discovery pkt
+        LLDP discoveryPkt = new LLDP();
+        discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(
+                ttlTlv).setOptionalTLVList(customList);
+
+        RawPacket rawPkt = null;
+        try {
+            // Create ethernet pkt
+            byte[] sourceMac = getSouceMACFromNodeID(nodeId);
+            Ethernet ethPkt = new Ethernet();
+            ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(
+                    LLDP.LLDPMulticastMac).setEtherType(
+                    EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt);
+
+            byte[] data = ethPkt.serialize();
+            rawPkt = new RawPacket(data);
+            rawPkt.setOutgoingNodeConnector(nodeConnector);
+        } catch (ConstructionException cex) {
+            logger.warn("RawPacket creation caught exception {}", cex
+                    .getMessage());
+        } catch (Exception e) {
+            logger.error("Failed to serialize the LLDP packet: " + e);
+        }
+
+        return rawPkt;
+    }
+
+    private void sendDiscoveryPacket(NodeConnector nodeConnector,
+            RawPacket outPkt) {
+        if (nodeConnector == null) {
+            logger.debug("Can not send discovery packet out since nodeConnector is null");
+            return;
+        }
+
+        if (outPkt == null) {
+            logger.debug("Can not send discovery packet out since outPkt is null");
+            return;
+        }
+
+        long sid = (Long) nodeConnector.getNode().getID();
+        ISwitch sw = controller.getSwitches().get(sid);
+
+        if (sw == null) {
+            logger.debug("Can not send discovery packet out since switch {} is null", sid);
+            return;
+        }
+
+        if (!sw.isOperational()) {
+            logger.debug("Can not send discovery packet out since switch {} is not operational", sw);
+            return;
+        }
+
+        if (this.iDataPacketMux == null) {
+            logger.debug("Can not send discovery packet out since DataPacket service is not available");
+            return;
+        }
+
+        logger.trace("Sending topology discovery pkt thru {}", nodeConnector);
+        this.iDataPacketMux.transmitDataPacket(outPkt);
+    }
+
+    @Override
+    public PacketResult receiveDataPacket(RawPacket inPkt) {
+        if (inPkt == null) {
+            logger.debug("Ignoring null packet");
+            return PacketResult.IGNORED;
+        }
+
+        byte[] data = inPkt.getPacketData();
+        if (data.length <= 0) {
+            logger.trace("Ignoring zero length packet");
+            return PacketResult.IGNORED;
+        }
+
+        if (!inPkt.getEncap().equals(LinkEncap.ETHERNET)) {
+            logger.trace("Ignoring non ethernet packet");
+            return PacketResult.IGNORED;
+        }
+
+        if (((Short) inPkt.getIncomingNodeConnector().getID())
+                .equals(NodeConnector.SPECIALNODECONNECTORID)) {
+            logger.trace("Ignoring ethernet packet received on special port: "
+                    + inPkt.getIncomingNodeConnector().toString());
+            return PacketResult.IGNORED;
+        }
+
+        Ethernet ethPkt = new Ethernet();
+        try {
+            ethPkt.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+        } catch (Exception e) {
+            logger.warn("Failed to decode LLDP packet from {}: {}",
+                    inPkt.getIncomingNodeConnector(), e);
+            return PacketResult.IGNORED;
+        }
+        if (ethPkt.getPayload() instanceof LLDP) {
+            NodeConnector dst = inPkt.getIncomingNodeConnector();
+            if (!processDiscoveryPacket(dst, ethPkt)) {
+                /* Spoof the discovery pkt if not generated from us */
+                spoofDiscoveryPacket(dst, ethPkt);
+            }
+            return PacketResult.CONSUME;
+        }
+        return PacketResult.IGNORED;
+    }
+
+    /*
+     * Spoof incoming discovery frames generated by the production network neighbor switch
+     */
+    private void spoofDiscoveryPacket(NodeConnector dstNodeConnector,
+            Ethernet ethPkt) {
+        if (!this.discoverySpoofingEnabled) {
+            return;
+        }
+
+        if ((dstNodeConnector == null) || (ethPkt == null)) {
+            logger.trace("Quit spoofing discovery packet: Null node connector or packet");
+            return;
+        }
+
+        LLDP lldp = (LLDP) ethPkt.getPayload();
+
+        try {
+            String nodeId = LLDPTLV.getHexStringValue(lldp.getChassisId().getValue(), lldp.getChassisId().getLength());
+            String portId = LLDPTLV.getStringValue(lldp.getPortId().getValue(), lldp.getPortId().getLength());
+            byte[] systemNameBytes = null;
+            // get system name if present in the LLDP pkt
+            for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
+                if (lldptlv.getType() == LLDPTLV.TLVType.SystemName.getValue()) {
+                    systemNameBytes = lldptlv.getValue();
+                    break;
+                }
+            }
+            String nodeName = (systemNameBytes == null) ? nodeId : new String(systemNameBytes);
+            Node srcNode = new Node(Node.NodeIDType.PRODUCTION, nodeName);
+            NodeConnector srcNodeConnector = NodeConnectorCreator
+                    .createNodeConnector(NodeConnector.NodeConnectorIDType.PRODUCTION,
+                            portId, srcNode);
+
+            Edge edge = null;
+            Set<Property> props = null;
+            edge = new Edge(srcNodeConnector, dstNodeConnector);
+            props = getProps(dstNodeConnector);
+
+            updateProdEdge(edge, props);
+        } catch (Exception e) {
+            logger.warn("Caught exception ", e);
+        }
+    }
+
+    /*
+     * Handle discovery frames generated by our controller
+     * @return true if it's a success
+     */
+    private boolean processDiscoveryPacket(NodeConnector dstNodeConnector,
+            Ethernet ethPkt) {
+        if ((dstNodeConnector == null) || (ethPkt == null)) {
+            logger
+                    .trace("Ignoring processing of discovery packet: Null node connector or packet");
+            return false;
+        }
+
+        logger.trace("Handle discovery packet {} from {}", ethPkt,
+                dstNodeConnector);
+
+        LLDP lldp = (LLDP) ethPkt.getPayload();
+
+        List<LLDPTLV> optionalTLVList = lldp.getOptionalTLVList();
+        if (optionalTLVList == null) {
+            logger.info("The discovery packet with null custom option from {}",
+                    dstNodeConnector);
+            return false;
+        }
+
+        Node srcNode = null;
+        NodeConnector srcNodeConnector = null;
+        for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
+            if (lldptlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
+                String ncString = LLDPTLV.getCustomString(lldptlv.getValue(), lldptlv.getLength());
+                srcNodeConnector = NodeConnector.fromString(ncString);
+                if (srcNodeConnector != null) {
+                    srcNode = srcNodeConnector.getNode();
+                    /* Check if it's expected */
+                    if (isTracked(srcNodeConnector)) {
+                        break;
+                    } else {
+                        srcNode = null;
+                        srcNodeConnector = null;
+                    }
+                }
+            }
+        }
+
+        if ((srcNode == null) || (srcNodeConnector == null)) {
+            logger
+                    .trace(
+                            "Received non-controller generated discovery packet from {}",
+                            dstNodeConnector);
+            return false;
+        }
+
+        // push it out to Topology
+        Edge edge = null;
+        Set<Property> props = null;
+        try {
+            edge = new Edge(srcNodeConnector, dstNodeConnector);
+            props = getProps(dstNodeConnector);
+        } catch (ConstructionException e) {
+            logger.error("Caught exception ", e);
+        }
+        addEdge(edge, props);
+
+        logger.trace("Received discovery packet for Edge {}", edge);
+
+        return true;
+    }
+
+    public Map<String, Property> getPropMap(NodeConnector nodeConnector) {
+        if (nodeConnector == null) {
+            return null;
+        }
+
+        if (pluginInInventoryService == null) {
+            return null;
+        }
+
+        Map<NodeConnector, Map<String, Property>> props = pluginInInventoryService
+                .getNodeConnectorProps(false);
+        if (props == null) {
+            return null;
+        }
+
+        return props.get(nodeConnector);
+    }
+
+    public Property getProp(NodeConnector nodeConnector, String propName) {
+        Map<String, Property> propMap = getPropMap(nodeConnector);
+        if (propMap == null) {
+            return null;
+        }
+
+        Property prop = (Property) propMap.get(propName);
+        return prop;
+    }
+
+    public Set<Property> getProps(NodeConnector nodeConnector) {
+        Map<String, Property> propMap = getPropMap(nodeConnector);
+        if (propMap == null) {
+            return null;
+        }
+
+        Set<Property> props = new HashSet<Property>(propMap.values());
+        return props;
+    }
+
+    private boolean isEnabled(NodeConnector nodeConnector) {
+        if (nodeConnector == null) {
+            return false;
+        }
+
+        Config config = (Config) getProp(nodeConnector, Config.ConfigPropName);
+        State state = (State) getProp(nodeConnector, State.StatePropName);
+        return ((config != null) && (config.getValue() == Config.ADMIN_UP)
+                && (state != null) && (state.getValue() == State.EDGE_UP));
+    }
+
+    private boolean isTracked(NodeConnector nodeConnector) {
+        if (readyListHi.contains(nodeConnector)) {
+            return true;
+        }
+
+        if (readyListLo.contains(nodeConnector)) {
+            return true;
+        }
+
+        if (pendingMap.keySet().contains(nodeConnector)) {
+            return true;
+        }
+
+        if (waitingList.contains(nodeConnector)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private Set<NodeConnector> getWorkingSet() {
+        Set<NodeConnector> workingSet = new HashSet<NodeConnector>();
+        Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
+
+        for (NodeConnector nodeConnector : readyListHi) {
+            if (isOverLimit(workingSet.size())) {
+                break;
+            }
+
+            workingSet.add(nodeConnector);
+            removeSet.add(nodeConnector);
+        }
+        readyListHi.removeAll(removeSet);
+
+        removeSet.clear();
+        for (NodeConnector nodeConnector : readyListLo) {
+            if (isOverLimit(workingSet.size())) {
+                break;
+            }
+
+            workingSet.add(nodeConnector);
+            removeSet.add(nodeConnector);
+        }
+        readyListLo.removeAll(removeSet);
+
+        return workingSet;
+    }
+
+    private Boolean isOverLimit(int size) {
+        return ((size >= discoveryBatchMaxPorts) && !throttling);
+    }
+
+    private void addDiscovery() {
+        Map<Long, ISwitch> switches = controller.getSwitches();
+        Set<Long> sidSet = switches.keySet();
+        if (sidSet == null) {
+            return;
+        }
+        for (Long sid : sidSet) {
+            Node node = NodeCreator.createOFNode(sid);
+            addDiscovery(node);
+        }
+    }
+
+    private void addDiscovery(Node node) {
+        Map<Long, ISwitch> switches = controller.getSwitches();
+        ISwitch sw = switches.get((Long) node.getID());
+        List<OFPhysicalPort> ports = sw.getEnabledPorts();
+        if (ports == null) {
+            return;
+        }
+        for (OFPhysicalPort port : ports) {
+            NodeConnector nodeConnector = NodeConnectorCreator
+                    .createOFNodeConnector(port.getPortNumber(), node);
+            if (!readyListHi.contains(nodeConnector)) {
+                readyListHi.add(nodeConnector);
+            }
+        }
+    }
+
+    private void addDiscovery(NodeConnector nodeConnector) {
+        if (isTracked(nodeConnector)) {
+            return;
+        }
+
+        readyListHi.add(nodeConnector);
+    }
+
+    private Set<NodeConnector> getRemoveSet(Collection<NodeConnector> c,
+            Node node) {
+        Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
+        if (c == null) {
+            return removeSet;
+        }
+        for (NodeConnector nodeConnector : c) {
+            if (node.equals(nodeConnector.getNode())) {
+                removeSet.add(nodeConnector);
+            }
+        }
+        return removeSet;
+    }
+
+    private void removeDiscovery(Node node) {
+        Set<NodeConnector> removeSet;
+
+        removeSet = getRemoveSet(readyListHi, node);
+        readyListHi.removeAll(removeSet);
+
+        removeSet = getRemoveSet(readyListLo, node);
+        readyListLo.removeAll(removeSet);
+
+        removeSet = getRemoveSet(waitingList, node);
+        waitingList.removeAll(removeSet);
+
+        removeSet = getRemoveSet(pendingMap.keySet(), node);
+        for (NodeConnector nodeConnector : removeSet) {
+            pendingMap.remove(nodeConnector);
+        }
+
+        removeSet = getRemoveSet(edgeMap.keySet(), node);
+        for (NodeConnector nodeConnector : removeSet) {
+            removeEdge(nodeConnector, false);
+        }
+
+        removeSet = getRemoveSet(prodMap.keySet(), node);
+        for (NodeConnector nodeConnector : removeSet) {
+            removeProdEdge(nodeConnector);
+        }
+    }
+
+    private void removeDiscovery(NodeConnector nodeConnector) {
+        readyListHi.remove(nodeConnector);
+        readyListLo.remove(nodeConnector);
+        waitingList.remove(nodeConnector);
+        pendingMap.remove(nodeConnector);
+        removeEdge(nodeConnector, false);
+        removeProdEdge(nodeConnector);
+    }
+
+    private void checkTimeout() {
+        Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
+        Set<NodeConnector> retrySet = new HashSet<NodeConnector>();
+        int sentCount;
+
+        Set<NodeConnector> pendingSet = pendingMap.keySet();
+        if (pendingSet != null) {
+            for (NodeConnector nodeConnector : pendingSet) {
+                sentCount = pendingMap.get(nodeConnector);
+                pendingMap.put(nodeConnector, ++sentCount);
+                if (sentCount > getDiscoveryFinalTimeoutInterval()) {
+                    // timeout the edge
+                    removeSet.add(nodeConnector);
+                    logger.trace("Discovery timeout {}", nodeConnector);
+                } else if (sentCount % discoveryTimeoutTicks == 0) {
+                    retrySet.add(nodeConnector);
+                }
+            }
+        }
+
+        for (NodeConnector nodeConnector : removeSet) {
+            removeEdge(nodeConnector);
+        }
+
+        for (NodeConnector nodeConnector : retrySet) {
+            transmitQ.add(nodeConnector);
+        }
+    }
+
+    private void checkAging() {
+        if (!discoveryAgingEnabled) {
+            return;
+        }
+
+        Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
+        int sentCount;
+
+        Set<NodeConnector> agingSet = agingMap.keySet();
+        if (agingSet != null) {
+            for (NodeConnector nodeConnector : agingSet) {
+                sentCount = agingMap.get(nodeConnector);
+                agingMap.put(nodeConnector, ++sentCount);
+                if (sentCount > discoveryAgeoutTicks) {
+                    // age out the edge
+                    removeSet.add(nodeConnector);
+                    logger.trace("Discovery age out {}", nodeConnector);
+                }
+            }
+        }
+
+        for (NodeConnector nodeConnector : removeSet) {
+            removeProdEdge(nodeConnector);
+        }
+    }
+
+    private void doDiscovery() {
+        if (++discoveryTimerTickCount <= discoveryBatchPauseTicks) {
+            for (NodeConnector nodeConnector : getWorkingSet()) {
+                pendingMap.put(nodeConnector, 0);
+                transmitQ.add(nodeConnector);
+            }
+        } else if (discoveryTimerTickCount >= discoveryBatchRestartTicks) {
+            discoveryTimerTickCount = 0;
+            for (NodeConnector nodeConnector : waitingList) {
+                if (!readyListLo.contains(nodeConnector))
+                    readyListLo.add(nodeConnector);
+            }
+            waitingList.removeAll(readyListLo);
+        }
+    }
+
+    private void doConsistencyCheck() {
+        if (!discoveryConsistencyCheckEnabled) {
+            return;
+        }
+
+        if (++discoveryConsistencyCheckTickCount
+                % getDiscoveryConsistencyCheckInterval() != 0) {
+            return;
+        }
+
+        discoveryConsistencyCheckCallingTimes++;
+
+        Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
+        Set<NodeConnector> ncSet = edgeMap.keySet();
+        if (ncSet == null) {
+            return;
+        }
+        for (NodeConnector nodeConnector : ncSet) {
+            if (!isEnabled(nodeConnector)) {
+                removeSet.add(nodeConnector);
+                discoveryConsistencyCheckCorrected++;
+                logger.debug("ConsistencyChecker: remove disabled {}",
+                        nodeConnector);
+                continue;
+            }
+
+            if (!isTracked(nodeConnector)) {
+                waitingList.add(nodeConnector);
+                discoveryConsistencyCheckCorrected++;
+                logger.debug("ConsistencyChecker: add back untracked {}",
+                        nodeConnector);
+                continue;
+            }
+        }
+
+        for (NodeConnector nodeConnector : removeSet) {
+            removeEdge(nodeConnector, false);
+        }
+
+        // remove stale entries
+        removeSet.clear();
+        for (NodeConnector nodeConnector : waitingList) {
+            if (!isEnabled(nodeConnector)) {
+                removeSet.add(nodeConnector);
+                discoveryConsistencyCheckCorrected++;
+                logger.debug("ConsistencyChecker: remove disabled {}",
+                        nodeConnector);
+            }
+        }
+        waitingList.removeAll(removeSet);
+
+        // Get a snapshot of all the existing switches
+        Map<Long, ISwitch> switches = this.controller.getSwitches();
+        for (ISwitch sw : switches.values()) {
+            for (OFPhysicalPort port : sw.getEnabledPorts()) {
+                Node node = NodeCreator.createOFNode(sw.getId());
+                NodeConnector nodeConnector = NodeConnectorCreator
+                        .createOFNodeConnector(port.getPortNumber(), node);
+                if (!isTracked(nodeConnector)) {
+                    waitingList.add(nodeConnector);
+                    discoveryConsistencyCheckCorrected++;
+                    logger.debug("ConsistencyChecker: add back untracked {}",
+                            nodeConnector);
+                }
+            }
+        }
+    }
+
+    private void addEdge(Edge edge, Set<Property> props) {
+        if (edge == null) {
+            return;
+        }
+
+        NodeConnector src = edge.getTailNodeConnector();
+        if (!src.getType().equals(
+                NodeConnector.NodeConnectorIDType.PRODUCTION)) {
+            pendingMap.remove(src);
+            if (!waitingList.contains(src)) {
+                waitingList.add(src);
+            }
+        } else {
+            NodeConnector dst = edge.getHeadNodeConnector();
+            agingMap.put(dst, 0);
+        }
+
+        // notify routeEngine
+        updateEdge(edge, UpdateType.ADDED, props);
+        logger.trace("Add edge {}", edge);
+    }
+
+
+    /**
+     * Update Production Edge
+     *
+     * @param edge The Production Edge
+     * @param props Properties associated with the edge
+     */
+    private void updateProdEdge(Edge edge, Set<Property> props) {
+        NodeConnector edgePort = edge.getHeadNodeConnector();
+
+        /* Do not update in case there is an existing OpenFlow link */
+        if (edgeMap.get(edgePort) != null) {
+            logger.trace("Discarded edge {} since there is an existing OF link {}",
+                    edge, edgeMap.get(edgePort));
+            return;
+        }
+
+        /* Look for any existing Production Edge */
+        Edge oldEdge = prodMap.get(edgePort);
+        if (oldEdge == null) {
+            /* Let's add a new one */
+            addEdge(edge, props);
+        } else if (!edge.equals(oldEdge)) {
+            /* Remove the old one first */
+            removeProdEdge(oldEdge.getHeadNodeConnector());
+            /* Then add the new one */
+            addEdge(edge, props);
+        } else {
+            /* o/w, just reset the aging timer */
+            NodeConnector dst = edge.getHeadNodeConnector();
+            agingMap.put(dst, 0);
+        }
+    }
+
+    /**
+     * Remove Production Edge for a given edge port
+     *
+     * @param edgePort The OF edge port
+     */
+    private void removeProdEdge(NodeConnector edgePort) {
+        agingMap.remove(edgePort);
+
+        Edge edge = null;
+        Set<NodeConnector> prodKeySet = prodMap.keySet();
+        if ((prodKeySet != null) && (prodKeySet.contains(edgePort))) {
+            edge = prodMap.get(edgePort);
+            prodMap.remove(edgePort);
+        }
+
+        // notify Topology
+        if (this.discoveryService != null) {
+            this.discoveryService.notifyEdge(edge, UpdateType.REMOVED, null);
+        }
+        logger.trace("Remove edge {}", edge);
+    }
+
+    /*
+     * Remove OpenFlow edge
+     */
+    private void removeEdge(NodeConnector nodeConnector, boolean stillEnabled) {
+        pendingMap.remove(nodeConnector);
+        readyListLo.remove(nodeConnector);
+        readyListHi.remove(nodeConnector);
+
+        if (stillEnabled) {
+            // keep discovering
+            if (!waitingList.contains(nodeConnector)) {
+                waitingList.add(nodeConnector);
+            }
+        } else {
+            // stop it
+            waitingList.remove(nodeConnector);
+        }
+
+        Edge edge = null;
+        Set<NodeConnector> edgeKeySet = edgeMap.keySet();
+        if ((edgeKeySet != null) && (edgeKeySet.contains(nodeConnector))) {
+            edge = edgeMap.get(nodeConnector);
+            edgeMap.remove(nodeConnector);
+        }
+
+        // notify Topology
+        if (this.discoveryService != null) {
+            this.discoveryService.notifyEdge(edge, UpdateType.REMOVED, null);
+        }
+        logger.trace("Remove {}", nodeConnector);
+    }
+
+    private void removeEdge(NodeConnector nodeConnector) {
+        removeEdge(nodeConnector, isEnabled(nodeConnector));
+    }
+
+    private void updateEdge(Edge edge, UpdateType type, Set<Property> props) {
+        if (discoveryService == null) {
+            return;
+        }
+
+        this.discoveryService.notifyEdge(edge, type, props);
+
+        NodeConnector src = edge.getTailNodeConnector(), dst = edge
+                .getHeadNodeConnector();
+        if (!src.getType().equals(
+                NodeConnector.NodeConnectorIDType.PRODUCTION)) {
+            if (type == UpdateType.ADDED) {
+                edgeMap.put(src, edge);
+            } else {
+                edgeMap.remove(src);
+            }
+        } else {
+            /*
+             * Save Production edge into different DB keyed by the Edge port
+             */
+            if (type == UpdateType.ADDED) {
+                prodMap.put(dst, edge);
+            } else {
+                prodMap.remove(dst);
+            }
+        }
+    }
+
+    private void moreToReadyListHi(NodeConnector nodeConnector) {
+        if (readyListLo.contains(nodeConnector)) {
+            readyListLo.remove(nodeConnector);
+            readyListHi.add(nodeConnector);
+        } else if (waitingList.contains(nodeConnector)) {
+            waitingList.remove(nodeConnector);
+            readyListHi.add(nodeConnector);
+        }
+    }
+
+    private void registerWithOSGIConsole() {
+        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+        bundleContext.registerService(CommandProvider.class.getName(), this,
+                null);
+    }
+
+    private int getDiscoveryConsistencyCheckInterval() {
+        return discoveryConsistencyCheckMultiple * discoveryBatchRestartTicks;
+    }
+
+    private int getDiscoveryFinalTimeoutInterval() {
+        return (discoveryRetry + 1) * discoveryTimeoutTicks;
+    }
+
+    @Override
+    public String getHelp() {
+        StringBuffer help = new StringBuffer();
+        help.append("---Topology Discovery---\n");
+        help.append("\t prlh                   - Print readyListHi entries\n");
+        help.append("\t prll                   - Print readyListLo entries\n");
+        help.append("\t pwl                    - Print waitingList entries\n");
+        help.append("\t ppl                    - Print pendingList entries\n");
+        help.append("\t ptick                  - Print tick time in msec\n");
+        help.append("\t pcc                    - Print CC info\n");
+        help.append("\t psize                  - Print sizes of all the lists\n");
+        help.append("\t ptm                    - Print timeout info\n");
+        help.append("\t ecc                     - Enable CC\n");
+        help.append("\t dcc                     - Disable CC\n");
+        help.append("\t scc [multiple]         - Set/show CC multiple and interval\n");
+        help.append("\t sports [ports]            - Set/show max ports per batch\n");
+        help.append("\t spause [ticks]         - Set/show pause period\n");
+        help.append("\t sdi [ticks]              - Set/show discovery interval in ticks\n");
+        help.append("\t stm [ticks]            - Set/show per timeout ticks\n");
+        help.append("\t sretry [count]            - Set/show num of retries\n");
+        help.append("\t addsw <swid>            - Add a switch\n");
+        help.append("\t remsw <swid>            - Remove a switch\n");
+        help.append("\t page                   - Print aging info\n");
+        help.append("\t sage                   - Set/Show aging time limit\n");
+        help.append("\t eage                     - Enable aging\n");
+        help.append("\t dage                     - Disable aging\n");
+        help.append("\t pthrot                 - Print throttling\n");
+        help.append("\t ethrot                 - Enable throttling\n");
+        help.append("\t dthrot                 - Disable throttling\n");
+        return help.toString();
+    }
+
+    public void _prlh(CommandInterpreter ci) {
+        ci.println("ReadyListHi\n");
+        for (NodeConnector nodeConnector : readyListHi) {
+            if (nodeConnector == null) {
+                continue;
+            }
+            ci.println(nodeConnector);
+        }
+    }
+
+    public void _prll(CommandInterpreter ci) {
+        ci.println("ReadyListLo\n");
+        for (NodeConnector nodeConnector : readyListLo) {
+            if (nodeConnector == null) {
+                continue;
+            }
+            ci.println(nodeConnector);
+        }
+    }
+
+    public void _pwl(CommandInterpreter ci) {
+        ci.println("WaitingList\n");
+        for (NodeConnector nodeConnector : waitingList) {
+            if (nodeConnector == null) {
+                continue;
+            }
+            ci.println(nodeConnector);
+        }
+    }
+
+    public void _ppl(CommandInterpreter ci) {
+        ci.println("PendingList\n");
+        for (NodeConnector nodeConnector : pendingMap.keySet()) {
+            if (nodeConnector == null) {
+                continue;
+            }
+            ci.println(nodeConnector);
+        }
+    }
+
+    public void _ptick(CommandInterpreter ci) {
+        ci.println("Current timer is " + discoveryTimerTick + " msec per tick");
+    }
+
+    public void _pcc(CommandInterpreter ci) {
+        if (discoveryConsistencyCheckEnabled) {
+            ci.println("ConsistencyChecker is currently enabled");
+        } else {
+            ci.println("ConsistencyChecker is currently disabled");
+        }
+        ci.println("Interval " + getDiscoveryConsistencyCheckInterval());
+        ci.println("Multiple " + discoveryConsistencyCheckMultiple);
+        ci.println("Number of times called "
+                + discoveryConsistencyCheckCallingTimes);
+        ci.println("Corrected count " + discoveryConsistencyCheckCorrected);
+    }
+
+    public void _ptm(CommandInterpreter ci) {
+        ci.println("Final timeout ticks " + getDiscoveryFinalTimeoutInterval());
+        ci.println("Per timeout ticks " + discoveryTimeoutTicks);
+        ci.println("Retry after initial timeout " + discoveryRetry);
+    }
+
+    public void _psize(CommandInterpreter ci) {
+        ci.println("readyListLo size " + readyListLo.size() + "\n"
+                + "readyListHi size " + readyListHi.size() + "\n"
+                + "waitingList size " + waitingList.size() + "\n"
+                + "pendingMap size " + pendingMap.size() + "\n"
+                + "edgeMap size " + edgeMap.size() + "\n" + "prodMap size "
+                + prodMap.size() + "\n" + "agingMap size " + agingMap.size());
+    }
+
+    public void _page(CommandInterpreter ci) {
+        if (this.discoveryAgingEnabled) {
+            ci.println("Aging is enabled");
+        } else {
+            ci.println("Aging is disabled");
+        }
+        ci.println("Current aging time limit " + this.discoveryAgeoutTicks);
+        ci.println("\n");
+        ci.println("                           Edge                                 Aging ");
+        Collection<Edge> prodSet = prodMap.values();
+        if (prodSet == null) {
+            return;
+        }
+        for (Edge edge : prodSet) {
+            Integer aging = agingMap.get(edge.getHeadNodeConnector());
+            if (aging != null) {
+                ci.println(edge + "      " + aging);
+            }
+        }
+        ci.println("\n");
+        ci.println("              NodeConnector                                 Edge ");
+        Set<NodeConnector> keySet = prodMap.keySet();
+        if (keySet == null) {
+            return;
+        }
+        for (NodeConnector nc : keySet) {
+            ci.println(nc + "      " + prodMap.get(nc));
+        }
+        return;
+    }
+
+    public void _sage(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        if (val == null) {
+            ci.println("Please enter aging time limit. Current value "
+                    + this.discoveryAgeoutTicks);
+            return;
+        }
+        try {
+            this.discoveryAgeoutTicks = Integer.parseInt(val);
+        } catch (Exception e) {
+            ci.println("Please enter a valid number");
+        }
+        return;
+    }
+
+    public void _eage(CommandInterpreter ci) {
+        this.discoveryAgingEnabled = true;
+        ci.println("Aging is enabled");
+        return;
+    }
+
+    public void _dage(CommandInterpreter ci) {
+        this.discoveryAgingEnabled = false;
+        ci.println("Aging is disabled");
+        return;
+    }
+
+    public void _scc(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        if (val == null) {
+            ci.println("Please enter CC multiple. Current multiple "
+                    + discoveryConsistencyCheckMultiple + " (interval "
+                    + getDiscoveryConsistencyCheckInterval()
+                    + ") calling times "
+                    + discoveryConsistencyCheckCallingTimes);
+            return;
+        }
+        try {
+            discoveryConsistencyCheckMultiple = Integer.parseInt(val);
+        } catch (Exception e) {
+            ci.println("Please enter a valid number");
+        }
+        return;
+    }
+
+    public void _ecc(CommandInterpreter ci) {
+        this.discoveryConsistencyCheckEnabled = true;
+        ci.println("ConsistencyChecker is enabled");
+        return;
+    }
+
+    public void _dcc(CommandInterpreter ci) {
+        this.discoveryConsistencyCheckEnabled = false;
+        ci.println("ConsistencyChecker is disabled");
+        return;
+    }
+
+    public void _pspf(CommandInterpreter ci) {
+        if (this.discoverySpoofingEnabled) {
+            ci.println("Discovery spoofing is enabled");
+        } else {
+            ci.println("Discovery spoofing is disabled");
+        }
+        return;
+    }
+
+    public void _espf(CommandInterpreter ci) {
+        this.discoverySpoofingEnabled = true;
+        ci.println("Discovery spoofing is enabled");
+        return;
+    }
+
+    public void _dspf(CommandInterpreter ci) {
+        this.discoverySpoofingEnabled = false;
+        ci.println("Discovery spoofing is disabled");
+        return;
+    }
+
+    public void _spause(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        String out = "Please enter pause period less than "
+                + discoveryBatchRestartTicks + ". Current pause period is "
+                + discoveryBatchPausePeriod + " pause tick is "
+                + discoveryBatchPauseTicks + ".";
+
+        if (val != null) {
+            try {
+                int pause = Integer.parseInt(val);
+                if (pause < discoveryBatchRestartTicks) {
+                    discoveryBatchPausePeriod = pause;
+                    discoveryBatchPauseTicks = discoveryBatchRestartTicks - discoveryBatchPausePeriod;
+                    return;
+                }
+            } catch (Exception e) {
+            }
+        }
+
+        ci.println(out);
+    }
+
+    public void _sdi(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        String out = "Please enter discovery interval greater than "
+                + discoveryBatchPausePeriod + ". Current value is "
+                + discoveryBatchRestartTicks + ".";
+
+        if (val != null) {
+            try {
+                int restart = Integer.parseInt(val);
+                if (restart > discoveryBatchPausePeriod) {
+                    discoveryBatchRestartTicks = restart;
+                    discoveryBatchPauseTicks = discoveryBatchRestartTicks - discoveryBatchPausePeriod;
+                    return;
+                }
+            } catch (Exception e) {
+            }
+        }
+        ci.println(out);
+    }
+
+    public void _sports(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        if (val == null) {
+            ci.println("Please enter max ports per batch. Current value is "
+                    + discoveryBatchMaxPorts);
+            return;
+        }
+        try {
+            discoveryBatchMaxPorts = Integer.parseInt(val);
+        } catch (Exception e) {
+            ci.println("Please enter a valid number");
+        }
+        return;
+    }
+
+    public void _sretry(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        if (val == null) {
+            ci.println("Please enter number of retries. Current value is "
+                    + discoveryRetry);
+            return;
+        }
+        try {
+            discoveryRetry = Integer.parseInt(val);
+        } catch (Exception e) {
+            ci.println("Please enter a valid number");
+        }
+        return;
+    }
+
+    public void _stm(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        String out = "Please enter timeout tick value less than "
+                + discoveryBatchRestartTicks + ". Current value is "
+                + discoveryTimeoutTicks;
+        if (val != null) {
+            try {
+                int timeout = Integer.parseInt(val);
+                if (timeout < discoveryBatchRestartTicks) {
+                    discoveryTimeoutTicks = timeout;
+                    return;
+                }
+            } catch (Exception e) {
+            }
+        }
+
+        ci.println(out);
+    }
+
+    public void _addsw(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        Long sid;
+        try {
+            sid = Long.parseLong(val);
+            Node node = NodeCreator.createOFNode(sid);
+            addDiscovery(node);
+        } catch (Exception e) {
+            ci.println("Please enter a valid number");
+        }
+        return;
+    }
+
+    public void _remsw(CommandInterpreter ci) {
+        String val = ci.nextArgument();
+        Long sid;
+        try {
+            sid = Long.parseLong(val);
+            Node node = NodeCreator.createOFNode(sid);
+            removeDiscovery(node);
+        } catch (Exception e) {
+            ci.println("Please enter a valid number");
+        }
+        return;
+    }
+
+    public void _pthrot(CommandInterpreter ci) {
+        if (this.throttling) {
+            ci.println("Throttling is enabled");
+        } else {
+            ci.println("Throttling is disabled");
+        }
+    }
+
+    public void _ethrot(CommandInterpreter ci) {
+        this.throttling = true;
+        ci.println("Throttling is enabled");
+        return;
+    }
+
+    public void _dthrot(CommandInterpreter ci) {
+        this.throttling = false;
+        ci.println("Throttling is disabled");
+        return;
+    }
+
+    @Override
+    public void updateNode(Node node, UpdateType type, Set<Property> props) {
+        switch (type) {
+        case ADDED:
+            addNode(node, props);
+            break;
+        case REMOVED:
+            removeNode(node);
+            break;
+        default:
+            break;
+        }
+    }
+
+    @Override
+    public void updateNodeConnector(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props) {
+        Config config = null;
+        State state = null;
+        boolean enabled = false;
+
+        for (Property prop : props) {
+            if (prop.getName().equals(Config.ConfigPropName)) {
+                config = (Config) prop;
+            } else if (prop.getName().equals(State.StatePropName)) {
+                state = (State) prop;
+            }
+        }
+        enabled = ((config != null) && (config.getValue() == Config.ADMIN_UP)
+                && (state != null) && (state.getValue() == State.EDGE_UP));
+
+        switch (type) {
+        case ADDED:
+            if (enabled) {
+                addDiscovery(nodeConnector);
+                logger.trace("ADDED enabled {}", nodeConnector);
+            } else {
+                logger.trace("ADDED disabled {}", nodeConnector);
+            }
+            break;
+        case CHANGED:
+            if (enabled) {
+                addDiscovery(nodeConnector);
+                logger.trace("CHANGED enabled {}", nodeConnector);
+            } else {
+                removeDiscovery(nodeConnector);
+                logger.trace("CHANGED disabled {}", nodeConnector);
+            }
+            break;
+        case REMOVED:
+            removeDiscovery(nodeConnector);
+            logger.trace("REMOVED enabled {}", nodeConnector);
+            break;
+        default:
+            return;
+        }
+    }
+
+    public void addNode(Node node, Set<Property> props) {
+        if (node == null)
+            return;
+
+        addDiscovery(node);
+    }
+
+    public void removeNode(Node node) {
+        if (node == null)
+            return;
+
+        removeDiscovery(node);
+    }
+
+    public void updateNode(Node node, Set<Property> props) {
+    }
+
+    void setController(IController s) {
+        this.controller = s;
+    }
+
+    void unsetController(IController s) {
+        if (this.controller == s) {
+            this.controller = null;
+        }
+    }
+
+    public void setPluginInInventoryService(IPluginInInventoryService service) {
+        this.pluginInInventoryService = service;
+    }
+
+    public void unsetPluginInInventoryService(IPluginInInventoryService service) {
+        this.pluginInInventoryService = null;
+    }
+
+    public void setIDataPacketMux(IDataPacketMux service) {
+        this.iDataPacketMux = service;
+    }
+
+    public void unsetIDataPacketMux(IDataPacketMux service) {
+        if (this.iDataPacketMux == service) {
+            this.iDataPacketMux = null;
+        }
+    }
+
+    void setDiscoveryService(IDiscoveryService s) {
+        this.discoveryService = s;
+    }
+
+    void unsetDiscoveryService(IDiscoveryService s) {
+        if (this.discoveryService == s) {
+            this.discoveryService = null;
+        }
+    }
+
+    private void initDiscoveryPacket() {
+        // Create LLDP ChassisID TLV
+        chassisIdTlv = new LLDPTLV();
+        chassisIdTlv.setType((byte) LLDPTLV.TLVType.ChassisID.getValue());
+
+        // Create LLDP PortID TLV
+        portIdTlv = new LLDPTLV();
+        portIdTlv.setType((byte) LLDPTLV.TLVType.PortID.getValue());
+
+        // Create LLDP TTL TLV
+        byte[] ttl = new byte[] {(byte) 0, (byte) 120 };
+        ttlTlv = new LLDPTLV();
+        ttlTlv.setType((byte) LLDPTLV.TLVType.TTL.getValue()).setLength(
+                (short) ttl.length).setValue(ttl);
+
+        customTlv = new LLDPTLV();
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        logger.trace("Init called");
+
+        transmitQ = new LinkedBlockingQueue<NodeConnector>();
+
+        readyListHi = new CopyOnWriteArrayList<NodeConnector>();
+        readyListLo = new CopyOnWriteArrayList<NodeConnector>();
+        waitingList = new CopyOnWriteArrayList<NodeConnector>();
+        pendingMap = new ConcurrentHashMap<NodeConnector, Integer>();
+        edgeMap = new ConcurrentHashMap<NodeConnector, Edge>();
+        agingMap = new ConcurrentHashMap<NodeConnector, Integer>();
+        prodMap = new ConcurrentHashMap<NodeConnector, Edge>();
+
+        discoveryTimer = new Timer("DiscoveryService");
+        discoveryTimerTask = new DiscoveryTimerTask();
+
+        transmitThread = new Thread(new DiscoveryTransmit(transmitQ));
+
+        initDiscoveryPacket();
+
+        registerWithOSGIConsole();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        transmitQ = null;
+        readyListHi = null;
+        readyListLo = null;
+        waitingList = null;
+        pendingMap = null;
+        edgeMap = null;
+        agingMap = null;
+        prodMap = null;
+        discoveryTimer = null;
+        discoveryTimerTask = null;
+        transmitThread = null;
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    void start() {
+        discoveryTimer.schedule(discoveryTimerTask, discoveryTimerTick,
+                discoveryTimerTick);
+        transmitThread.start();
+    }
+
+    /**
+     * Function called after registering the
+     * service in OSGi service registry.
+     */
+    void started() {
+        /* get a snapshot of all the existing switches */
+        addDiscovery();
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    void stop() {
+        shuttingDown = true;
+        discoveryTimer.cancel();
+        transmitThread.interrupt();
+    }
+
+    @Override
+    public void tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+    }
+
+    @Override
+    public void containerFlowUpdated(String containerName,
+            ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
+    }
+
+    @Override
+    public void nodeConnectorUpdated(String containerName, NodeConnector p,
+            UpdateType t) {
+        switch (t) {
+        case ADDED:
+            moreToReadyListHi(p);
+            break;
+        default:
+            break;
+        }
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+        // do nothing
+    }
+
+    private byte[] getSouceMACFromNodeID(String nodeId) {
+        byte[] cid = HexEncode.bytesFromHexString(nodeId);
+        byte[] sourceMac = new byte[6];
+        int pos = cid.length - sourceMac.length;
+
+        if (pos >= 0) {
+            System.arraycopy(cid, pos, sourceMac, 0, sourceMac.length);
+        }
+
+        return sourceMac;
+    }
+
+    /**
+     * This method returns the interval which determines how often the discovery
+     * packets will be sent. Default is 300 seconds.
+     *
+     * @return The discovery interval in second
+     */
+    private static int getDiscoveryInterval() {
+        String elapsedTime = System.getProperty("of.discoveryInterval");
+        int rv = 300;
+
+        try {
+            if (elapsedTime != null) {
+                rv = Integer.parseInt(elapsedTime);
+            }
+        } catch (Exception e) {
+        }
+
+        return rv;
+    }
+
+    /**
+     * This method returns the timeout value in waiting for response of a
+     * discovery query. Default is 60 seconds.
+     *
+     * @return The discovery timeout in second
+     */
+    private static int getDiscoveryTimeout() {
+        String elapsedTime = System.getProperty("of.discoveryTimeout");
+        int rv = 60;
+
+        try {
+            if (elapsedTime != null) {
+                rv = Integer.parseInt(elapsedTime);
+            }
+        } catch (Exception e) {
+        }
+
+        return rv;
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java
new file mode 100644 (file)
index 0000000..7af9ff3
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6FlowMod;
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.ActionType;
+import org.opendaylight.controller.sal.action.Controller;
+import org.opendaylight.controller.sal.action.Drop;
+import org.opendaylight.controller.sal.action.Flood;
+import org.opendaylight.controller.sal.action.FloodAll;
+import org.opendaylight.controller.sal.action.HwPath;
+import org.opendaylight.controller.sal.action.Loopback;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.action.PopVlan;
+import org.opendaylight.controller.sal.action.SetDlDst;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+import org.opendaylight.controller.sal.action.SetNwDst;
+import org.opendaylight.controller.sal.action.SetNwSrc;
+import org.opendaylight.controller.sal.action.SetNwTos;
+import org.opendaylight.controller.sal.action.SetTpDst;
+import org.opendaylight.controller.sal.action.SetTpSrc;
+import org.opendaylight.controller.sal.action.SetVlanId;
+import org.opendaylight.controller.sal.action.SetVlanPcp;
+import org.opendaylight.controller.sal.action.SwPath;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchField;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFVendor;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionDataLayerDestination;
+import org.openflow.protocol.action.OFActionDataLayerSource;
+import org.openflow.protocol.action.OFActionNetworkLayerAddress;
+import org.openflow.protocol.action.OFActionNetworkLayerDestination;
+import org.openflow.protocol.action.OFActionNetworkLayerSource;
+import org.openflow.protocol.action.OFActionNetworkTypeOfService;
+import org.openflow.protocol.action.OFActionOutput;
+import org.openflow.protocol.action.OFActionStripVirtualLan;
+import org.openflow.protocol.action.OFActionTransportLayer;
+import org.openflow.protocol.action.OFActionTransportLayerDestination;
+import org.openflow.protocol.action.OFActionTransportLayerSource;
+import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
+import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
+import org.openflow.util.U16;
+import org.openflow.util.U32;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for converting a SAL Flow into the OF flow and vice-versa
+ */
+public class FlowConverter {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(FlowConverter.class);
+    private Flow flow; // SAL Flow
+    private OFMatch ofMatch; // OF 1.0 match or OF 1.0 + IPv6 extension match
+    private List<OFAction> actionsList; // OF 1.0 actions
+    private int actionsLength;
+    private boolean isIPv6;
+
+    public FlowConverter(OFMatch ofMatch, List<OFAction> actionsList) {
+        this.ofMatch = ofMatch;
+        this.actionsList = actionsList;
+        this.actionsLength = 0;
+        this.flow = null;
+        this.isIPv6 = ofMatch instanceof V6Match;
+    }
+
+    public FlowConverter(Flow flow) {
+        this.ofMatch = null;
+        this.actionsList = null;
+        this.actionsLength = 0;
+        this.flow = flow;
+        this.isIPv6 = flow.isIPv6();
+    }
+
+    /**
+     * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions
+     * form (V6Match)
+     *
+     * @return
+     */
+    public OFMatch getOFMatch() {
+        if (ofMatch == null) {
+            Match match = flow.getMatch();
+            ofMatch = (isIPv6) ? new V6Match() : new OFMatch();
+
+            int wildcards = OFMatch.OFPFW_ALL;
+            if (match.isPresent(MatchType.IN_PORT)) {
+                short port = (Short) ((NodeConnector) match.getField(
+                        MatchType.IN_PORT).getValue()).getID();
+                if (!isIPv6) {
+                    ofMatch.setInputPort(port);
+                    wildcards &= ~OFMatch.OFPFW_IN_PORT;
+                } else {
+                    ((V6Match) ofMatch).setInputPort(port, (short) 0);
+                }
+            }
+            if (match.isPresent(MatchType.DL_SRC)) {
+                byte[] srcMac = (byte[]) match.getField(MatchType.DL_SRC)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setDataLayerSource(srcMac.clone());
+                    wildcards &= ~OFMatch.OFPFW_DL_SRC;
+                } else {
+                    ((V6Match) ofMatch).setDataLayerSource(srcMac, null);
+                }
+            }
+            if (match.isPresent(MatchType.DL_DST)) {
+                byte[] dstMac = (byte[]) match.getField(MatchType.DL_DST)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setDataLayerDestination(dstMac.clone());
+                    wildcards &= ~OFMatch.OFPFW_DL_DST;
+                } else {
+                    ((V6Match) ofMatch).setDataLayerDestination(dstMac, null);
+                }
+            }
+            if (match.isPresent(MatchType.DL_VLAN)) {
+                short vlan = (Short) match.getField(MatchType.DL_VLAN)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setDataLayerVirtualLan(vlan);
+                    wildcards &= ~OFMatch.OFPFW_DL_VLAN;
+                } else {
+                    ((V6Match) ofMatch).setDataLayerVirtualLan(vlan, (short) 0);
+                }
+            }
+            if (match.isPresent(MatchType.DL_VLAN_PR)) {
+                byte vlanPr = (Byte) match.getField(MatchType.DL_VLAN_PR)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setDataLayerVirtualLanPriorityCodePoint(vlanPr);
+                    wildcards &= ~OFMatch.OFPFW_DL_VLAN_PCP;
+                } else {
+                    ((V6Match) ofMatch)
+                            .setDataLayerVirtualLanPriorityCodePoint(vlanPr,
+                                    (byte) 0);
+                }
+            }
+            if (match.isPresent(MatchType.DL_TYPE)) {
+                short ethType = (Short) match.getField(MatchType.DL_TYPE)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setDataLayerType(ethType);
+                    wildcards &= ~OFMatch.OFPFW_DL_TYPE;
+                } else {
+                    ((V6Match) ofMatch).setDataLayerType(ethType, (short) 0);
+                }
+            }
+            if (match.isPresent(MatchType.NW_TOS)) {
+                /*
+                 * OF 1.0 switch expects the TOS as the 6 msb in the byte. it is
+                 * actually the DSCP field followed by a zero ECN
+                 */
+                byte tos = (Byte) match.getField(MatchType.NW_TOS).getValue();
+                byte dscp = (byte) ((int) tos << 2);
+                if (!isIPv6) {
+                    ofMatch.setNetworkTypeOfService(dscp);
+                    wildcards &= ~OFMatch.OFPFW_NW_TOS;
+                } else {
+                    ((V6Match) ofMatch).setNetworkTypeOfService(dscp, (byte) 0);
+                }
+            }
+            if (match.isPresent(MatchType.NW_PROTO)) {
+                byte proto = (Byte) match.getField(MatchType.NW_PROTO)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setNetworkProtocol(proto);
+                    wildcards &= ~OFMatch.OFPFW_NW_PROTO;
+                } else {
+                    ((V6Match) ofMatch).setNetworkProtocol(proto, (byte) 0);
+                }
+            }
+            if (match.isPresent(MatchType.NW_SRC)) {
+                InetAddress address = (InetAddress) match.getField(
+                        MatchType.NW_SRC).getValue();
+                InetAddress mask = (InetAddress) match.getField(
+                        MatchType.NW_SRC).getMask();
+                if (!isIPv6) {
+                    ofMatch.setNetworkSource(NetUtils.byteArray4ToInt(address
+                            .getAddress()));
+                    int maskLength = NetUtils
+                            .getSubnetMaskLength((mask == null) ? null : mask
+                                    .getAddress());
+                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_SRC_MASK)
+                            | (maskLength << OFMatch.OFPFW_NW_SRC_SHIFT);
+                } else {
+                    ((V6Match) ofMatch).setNetworkSource(address, mask);
+                }
+            }
+            if (match.isPresent(MatchType.NW_DST)) {
+                InetAddress address = (InetAddress) match.getField(
+                        MatchType.NW_DST).getValue();
+                InetAddress mask = (InetAddress) match.getField(
+                        MatchType.NW_DST).getMask();
+                if (!isIPv6) {
+                    ofMatch.setNetworkDestination(NetUtils
+                            .byteArray4ToInt(address.getAddress()));
+                    int maskLength = NetUtils
+                            .getSubnetMaskLength((mask == null) ? null : mask
+                                    .getAddress());
+                    wildcards = (wildcards & ~OFMatch.OFPFW_NW_DST_MASK)
+                            | (maskLength << OFMatch.OFPFW_NW_DST_SHIFT);
+                } else {
+                    ((V6Match) ofMatch).setNetworkDestination(address, mask);
+                }
+            }
+            if (match.isPresent(MatchType.TP_SRC)) {
+                short port = (Short) match.getField(MatchType.TP_SRC)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setTransportSource(port);
+                    wildcards &= ~OFMatch.OFPFW_TP_SRC;
+                } else {
+                    ((V6Match) ofMatch).setTransportSource(port, (short) 0);
+                }
+            }
+            if (match.isPresent(MatchType.TP_DST)) {
+                short port = (Short) match.getField(MatchType.TP_DST)
+                        .getValue();
+                if (!isIPv6) {
+                    ofMatch.setTransportDestination(port);
+                    wildcards &= ~OFMatch.OFPFW_TP_DST;
+                } else {
+                    ((V6Match) ofMatch)
+                            .setTransportDestination(port, (short) 0);
+                }
+            }
+
+            if (!isIPv6) {
+                ofMatch.setWildcards(U32.t(Long.valueOf(wildcards)));
+            }
+        }
+        logger.trace("SAL Match: {} Openflow Match: {}", flow.getMatch(),
+                ofMatch);
+        return ofMatch;
+    }
+
+    /**
+     * Returns the list of actions in OF 1.0 form
+     *
+     * @return
+     */
+    public List<OFAction> getOFActions() {
+        if (this.actionsList == null) {
+            actionsList = new ArrayList<OFAction>();
+            for (Action action : flow.getActions()) {
+                if (action.getType() == ActionType.OUTPUT) {
+                    Output a = (Output) action;
+                    OFActionOutput ofAction = new OFActionOutput();
+                    ofAction.setMaxLength((short) 0xffff);
+                    ofAction.setPort(PortConverter.toOFPort(a.getPort()));
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionOutput.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.DROP) {
+                    continue;
+                }
+                if (action.getType() == ActionType.LOOPBACK) {
+                    OFActionOutput ofAction = new OFActionOutput();
+                    ofAction.setPort(OFPort.OFPP_IN_PORT.getValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionOutput.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.FLOOD) {
+                    OFActionOutput ofAction = new OFActionOutput();
+                    ofAction.setPort(OFPort.OFPP_FLOOD.getValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionOutput.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.FLOOD_ALL) {
+                    OFActionOutput ofAction = new OFActionOutput();
+                    ofAction.setPort(OFPort.OFPP_ALL.getValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionOutput.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.CONTROLLER) {
+                    OFActionOutput ofAction = new OFActionOutput();
+                    ofAction.setPort(OFPort.OFPP_CONTROLLER.getValue());
+                    // We want the whole frame hitting the match be sent to the
+                    // controller
+                    ofAction.setMaxLength((short) 0xffff);
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionOutput.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SW_PATH) {
+                    OFActionOutput ofAction = new OFActionOutput();
+                    ofAction.setPort(OFPort.OFPP_LOCAL.getValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionOutput.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.HW_PATH) {
+                    OFActionOutput ofAction = new OFActionOutput();
+                    ofAction.setPort(OFPort.OFPP_NORMAL.getValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionOutput.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_VLAN_ID) {
+                    SetVlanId a = (SetVlanId) action;
+                    OFActionVirtualLanIdentifier ofAction = new OFActionVirtualLanIdentifier();
+                    ofAction.setVirtualLanIdentifier((short) a.getVlanId());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionVirtualLanIdentifier.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_VLAN_PCP) {
+                    SetVlanPcp a = (SetVlanPcp) action;
+                    OFActionVirtualLanPriorityCodePoint ofAction = new OFActionVirtualLanPriorityCodePoint();
+                    ofAction.setVirtualLanPriorityCodePoint(Integer.valueOf(
+                            a.getPcp()).byteValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.POP_VLAN) {
+                    OFActionStripVirtualLan ofAction = new OFActionStripVirtualLan();
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionStripVirtualLan.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_DL_SRC) {
+                    SetDlSrc a = (SetDlSrc) action;
+                    OFActionDataLayerSource ofAction = new OFActionDataLayerSource();
+                    ofAction.setDataLayerAddress(a.getDlAddress());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionDataLayerSource.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_DL_DST) {
+                    SetDlDst a = (SetDlDst) action;
+                    OFActionDataLayerDestination ofAction = new OFActionDataLayerDestination();
+                    ofAction.setDataLayerAddress(a.getDlAddress());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionDataLayerDestination.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_NW_SRC) {
+                    SetNwSrc a = (SetNwSrc) action;
+                    OFActionNetworkLayerSource ofAction = new OFActionNetworkLayerSource();
+                    ofAction.setNetworkAddress(NetUtils.byteArray4ToInt(a
+                            .getAddress().getAddress()));
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionNetworkLayerAddress.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_NW_DST) {
+                    SetNwDst a = (SetNwDst) action;
+                    OFActionNetworkLayerDestination ofAction = new OFActionNetworkLayerDestination();
+                    ofAction.setNetworkAddress(NetUtils.byteArray4ToInt(a
+                            .getAddress().getAddress()));
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionNetworkLayerAddress.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_NW_TOS) {
+                    SetNwTos a = (SetNwTos) action;
+                    OFActionNetworkTypeOfService ofAction = new OFActionNetworkTypeOfService();
+                    ofAction.setNetworkTypeOfService(Integer.valueOf(
+                            a.getNwTos()).byteValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionNetworkTypeOfService.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_TP_SRC) {
+                    SetTpSrc a = (SetTpSrc) action;
+                    OFActionTransportLayerSource ofAction = new OFActionTransportLayerSource();
+                    ofAction.setTransportPort(Integer.valueOf(a.getPort())
+                            .shortValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionTransportLayer.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_TP_DST) {
+                    SetTpDst a = (SetTpDst) action;
+                    OFActionTransportLayerDestination ofAction = new OFActionTransportLayerDestination();
+                    ofAction.setTransportPort(Integer.valueOf(a.getPort())
+                            .shortValue());
+                    actionsList.add(ofAction);
+                    actionsLength += OFActionTransportLayer.MINIMUM_LENGTH;
+                    continue;
+                }
+                if (action.getType() == ActionType.SET_NEXT_HOP) {
+                    // TODO
+                    continue;
+                }
+            }
+        }
+        logger.trace("SAL Actions: {} Openflow Actions: {}", flow.getActions(),
+                actionsList);
+        return actionsList;
+    }
+
+    /**
+     * Utility to convert a SAL flow to an OF 1.0 (OFFlowMod) or to an OF 1.0 +
+     * IPv6 extension (V6FlowMod) Flow modifier Message
+     *
+     * @param sw
+     * @param command
+     * @param port
+     * @return
+     */
+    public OFMessage getOFFlowMod(short command, OFPort port) {
+        OFMessage fm = (isIPv6) ? new V6FlowMod() : new OFFlowMod();
+        if (this.ofMatch == null) {
+            getOFMatch();
+        }
+        if (this.actionsList == null) {
+            getOFActions();
+        }
+        if (!isIPv6) {
+            ((OFFlowMod) fm).setMatch(this.ofMatch);
+            ((OFFlowMod) fm).setActions(this.actionsList);
+            ((OFFlowMod) fm).setPriority(flow.getPriority());
+            ((OFFlowMod) fm).setCookie(flow.getId());
+            ((OFFlowMod) fm).setBufferId(OFPacketOut.BUFFER_ID_NONE);
+            ((OFFlowMod) fm).setLength(U16.t(OFFlowMod.MINIMUM_LENGTH
+                    + actionsLength));
+            ((OFFlowMod) fm).setIdleTimeout(flow.getIdleTimeout());
+            ((OFFlowMod) fm).setHardTimeout(flow.getHardTimeout());
+            ((OFFlowMod) fm).setCommand(command);
+            if (port != null) {
+                ((OFFlowMod) fm).setOutPort(port);
+            }
+            if (command == OFFlowMod.OFPFC_ADD
+                    || command == OFFlowMod.OFPFC_MODIFY
+                    || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
+                if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) {
+                    // Instruct switch to let controller know when flow expires
+                    ((OFFlowMod) fm).setFlags((short) 1);
+                }
+            }
+        } else {
+            ((V6FlowMod) fm).setVendor();
+            ((V6FlowMod) fm).setMatch((V6Match) ofMatch);
+            ((V6FlowMod) fm).setActions(this.actionsList);
+            ((V6FlowMod) fm).setPriority(flow.getPriority());
+            ((V6FlowMod) fm).setCookie(flow.getId());
+            ((V6FlowMod) fm).setLength(U16.t(OFVendor.MINIMUM_LENGTH
+                    + ((V6Match) ofMatch).getIPv6ExtMinHdrLen()
+                    + ((V6Match) ofMatch).getIPv6MatchLen()
+                    + ((V6Match) ofMatch).getPadSize() + actionsLength));
+            ((V6FlowMod) fm).setIdleTimeout(flow.getIdleTimeout());
+            ((V6FlowMod) fm).setHardTimeout(flow.getHardTimeout());
+            ((V6FlowMod) fm).setCommand(command);
+            if (port != null) {
+                ((V6FlowMod) fm).setOutPort(port);
+            }
+            if (command == OFFlowMod.OFPFC_ADD
+                    || command == OFFlowMod.OFPFC_MODIFY
+                    || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
+                if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) {
+                    // Instruct switch to let controller know when flow expires
+                    ((V6FlowMod) fm).setFlags((short) 1);
+                }
+            }
+        }
+        logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch,
+                actionsList);
+        logger.trace("Openflow Mod Message: {}", fm);
+        return fm;
+    }
+
+    public Flow getFlow(Node node) {
+        if (this.flow == null) {
+            Match salMatch = new Match();
+
+            /*
+             * Installed flow may not have a Match defined like in case of a
+             * drop all flow
+             */
+            if (ofMatch != null) {
+                if (!isIPv6) {
+                    // Compute OF1.0 Match
+                    if (ofMatch.getInputPort() != 0) {
+                        salMatch.setField(new MatchField(MatchType.IN_PORT,
+                                NodeConnectorCreator.createNodeConnector(
+                                        (Short) ofMatch.getInputPort(), node)));
+                    }
+                    if (ofMatch.getDataLayerSource() != null
+                            && !NetUtils
+                                    .isZeroMAC(ofMatch.getDataLayerSource())) {
+                        byte srcMac[] = ofMatch.getDataLayerSource();
+                        salMatch.setField(new MatchField(MatchType.DL_SRC,
+                                srcMac.clone()));
+                    }
+                    if (ofMatch.getDataLayerDestination() != null
+                            && !NetUtils.isZeroMAC(ofMatch
+                                    .getDataLayerDestination())) {
+                        byte dstMac[] = ofMatch.getDataLayerDestination();
+                        salMatch.setField(new MatchField(MatchType.DL_DST,
+                                dstMac.clone()));
+                    }
+                    if (ofMatch.getDataLayerType() != 0) {
+                        salMatch.setField(new MatchField(MatchType.DL_TYPE,
+                                ofMatch.getDataLayerType()));
+                    }
+                    if (ofMatch.getDataLayerVirtualLan() != 0) {
+                        salMatch.setField(new MatchField(MatchType.DL_VLAN,
+                                ofMatch.getDataLayerVirtualLan()));
+                    }
+                    if (ofMatch.getDataLayerVirtualLanPriorityCodePoint() != 0) {
+                        salMatch.setField(MatchType.DL_VLAN_PR, ofMatch
+                                .getDataLayerVirtualLanPriorityCodePoint());
+                    }
+                    if (ofMatch.getNetworkSource() != 0) {
+                        salMatch.setField(MatchType.NW_SRC, NetUtils
+                                .getInetAddress(ofMatch.getNetworkSource()),
+                                NetUtils.getInetNetworkMask(
+                                        ofMatch.getNetworkSourceMaskLen(),
+                                        false));
+                    }
+                    if (ofMatch.getNetworkDestination() != 0) {
+                        salMatch.setField(MatchType.NW_DST,
+                                NetUtils.getInetAddress(ofMatch
+                                        .getNetworkDestination()),
+                                NetUtils.getInetNetworkMask(
+                                        ofMatch.getNetworkDestinationMaskLen(),
+                                        false));
+                    }
+                    if (ofMatch.getNetworkTypeOfService() != 0) {
+                        int dscp = NetUtils.getUnsignedByte(ofMatch
+                                .getNetworkTypeOfService());
+                        byte tos = (byte) (dscp >> 2);
+                        salMatch.setField(MatchType.NW_TOS, tos);
+                    }
+                    if (ofMatch.getNetworkProtocol() != 0) {
+                        salMatch.setField(MatchType.NW_PROTO,
+                                ofMatch.getNetworkProtocol());
+                    }
+                    if (ofMatch.getTransportSource() != 0) {
+                        salMatch.setField(MatchType.TP_SRC,
+                                ((Short) ofMatch.getTransportSource()));
+                    }
+                    if (ofMatch.getTransportDestination() != 0) {
+                        salMatch.setField(MatchType.TP_DST,
+                                ((Short) ofMatch.getTransportDestination()));
+                    }
+                } else {
+                    // Compute OF1.0 + IPv6 extensions Match
+                    V6Match v6Match = (V6Match) ofMatch;
+                    if (v6Match.getInputPort() != 0) {
+                        // Mask on input port is not defined
+                        salMatch.setField(new MatchField(MatchType.IN_PORT,
+                                NodeConnectorCreator.createOFNodeConnector(
+                                        (Short) v6Match.getInputPort(), node)));
+                    }
+                    if (v6Match.getDataLayerSource() != null
+                            && !NetUtils
+                                    .isZeroMAC(ofMatch.getDataLayerSource())) {
+                        byte srcMac[] = v6Match.getDataLayerSource();
+                        salMatch.setField(new MatchField(MatchType.DL_SRC,
+                                srcMac.clone()));
+                    }
+                    if (v6Match.getDataLayerDestination() != null
+                            && !NetUtils.isZeroMAC(ofMatch
+                                    .getDataLayerDestination())) {
+                        byte dstMac[] = v6Match.getDataLayerDestination();
+                        salMatch.setField(new MatchField(MatchType.DL_DST,
+                                dstMac.clone()));
+                    }
+                    if (v6Match.getDataLayerType() != 0) {
+                        salMatch.setField(new MatchField(MatchType.DL_TYPE,
+                                v6Match.getDataLayerType()));
+                    }
+                    if (v6Match.getDataLayerVirtualLan() != 0) {
+                        salMatch.setField(new MatchField(MatchType.DL_VLAN,
+                                v6Match.getDataLayerVirtualLan()));
+                    }
+                    if (v6Match.getDataLayerVirtualLanPriorityCodePoint() != 0) {
+                        salMatch.setField(MatchType.DL_VLAN_PR, v6Match
+                                .getDataLayerVirtualLanPriorityCodePoint());
+                    }
+                    if (v6Match.getNetworkSrc() != null) {
+                        salMatch.setField(MatchType.NW_SRC,
+                                v6Match.getNetworkSrc(),
+                                v6Match.getNetworkSourceMask());
+                    }
+                    if (v6Match.getNetworkDest() != null) {
+                        salMatch.setField(MatchType.NW_DST,
+                                v6Match.getNetworkDest(),
+                                v6Match.getNetworkDestinationMask());
+                    }
+                    if (v6Match.getNetworkTypeOfService() != 0) {
+                        int dscp = NetUtils.getUnsignedByte(v6Match
+                                .getNetworkTypeOfService());
+                        byte tos = (byte) (dscp >> 2);
+                        salMatch.setField(MatchType.NW_TOS, tos);
+                    }
+                    if (v6Match.getNetworkProtocol() != 0) {
+                        salMatch.setField(MatchType.NW_PROTO,
+                                v6Match.getNetworkProtocol());
+                    }
+                    if (v6Match.getTransportSource() != 0) {
+                        salMatch.setField(MatchType.TP_SRC,
+                                ((Short) v6Match.getTransportSource()));
+                    }
+                    if (v6Match.getTransportDestination() != 0) {
+                        salMatch.setField(MatchType.TP_DST,
+                                ((Short) v6Match.getTransportDestination()));
+                    }
+                }
+            }
+
+            // Convert actions
+            Action salAction = null;
+            List<Action> salActionList = new ArrayList<Action>();
+            if (actionsList == null) {
+                salActionList.add(new Drop());
+            } else {
+                for (OFAction ofAction : actionsList) {
+                    if (ofAction instanceof OFActionOutput) {
+                        short ofPort = ((OFActionOutput) ofAction).getPort();
+                        if (ofPort == OFPort.OFPP_CONTROLLER.getValue()) {
+                            salAction = new Controller();
+                        } else if (ofPort == OFPort.OFPP_NONE.getValue()) {
+                            salAction = new Drop();
+                        } else if (ofPort == OFPort.OFPP_IN_PORT.getValue()) {
+                            salAction = new Loopback();
+                        } else if (ofPort == OFPort.OFPP_FLOOD.getValue()) {
+                            salAction = new Flood();
+                        } else if (ofPort == OFPort.OFPP_ALL.getValue()) {
+                            salAction = new FloodAll();
+                        } else if (ofPort == OFPort.OFPP_LOCAL.getValue()) {
+                            salAction = new SwPath();
+                        } else if (ofPort == OFPort.OFPP_NORMAL.getValue()) {
+                            salAction = new HwPath();
+                        } else if (ofPort == OFPort.OFPP_TABLE.getValue()) {
+                            salAction = new HwPath(); // TODO: we do not handle
+                                                      // table in sal for now
+                        } else {
+                            salAction = new Output(
+                                    NodeConnectorCreator.createOFNodeConnector(
+                                            ofPort, node));
+                        }
+                    } else if (ofAction instanceof OFActionVirtualLanIdentifier) {
+                        salAction = new SetVlanId(
+                                ((OFActionVirtualLanIdentifier) ofAction)
+                                        .getVirtualLanIdentifier());
+                    } else if (ofAction instanceof OFActionStripVirtualLan) {
+                        salAction = new PopVlan();
+                    } else if (ofAction instanceof OFActionVirtualLanPriorityCodePoint) {
+                        salAction = new SetVlanPcp(
+                                ((OFActionVirtualLanPriorityCodePoint) ofAction)
+                                        .getVirtualLanPriorityCodePoint());
+                    } else if (ofAction instanceof OFActionDataLayerSource) {
+                        salAction = new SetDlSrc(
+                                ((OFActionDataLayerSource) ofAction)
+                                        .getDataLayerAddress().clone());
+                    } else if (ofAction instanceof OFActionDataLayerDestination) {
+                        salAction = new SetDlDst(
+                                ((OFActionDataLayerDestination) ofAction)
+                                        .getDataLayerAddress().clone());
+                    } else if (ofAction instanceof OFActionNetworkLayerSource) {
+                        byte addr[] = BigInteger.valueOf(
+                                ((OFActionNetworkLayerSource) ofAction)
+                                        .getNetworkAddress()).toByteArray();
+                        InetAddress ip = null;
+                        try {
+                            ip = InetAddress.getByAddress(addr);
+                        } catch (UnknownHostException e) {
+                            logger.error("", e);
+                        }
+                        salAction = new SetNwSrc(ip);
+                    } else if (ofAction instanceof OFActionNetworkLayerDestination) {
+                        byte addr[] = BigInteger.valueOf(
+                                ((OFActionNetworkLayerDestination) ofAction)
+                                        .getNetworkAddress()).toByteArray();
+                        InetAddress ip = null;
+                        try {
+                            ip = InetAddress.getByAddress(addr);
+                        } catch (UnknownHostException e) {
+                            logger.error("", e);
+                        }
+                        salAction = new SetNwDst(ip);
+                    } else if (ofAction instanceof OFActionNetworkTypeOfService) {
+                        salAction = new SetNwTos(
+                                ((OFActionNetworkTypeOfService) ofAction)
+                                        .getNetworkTypeOfService());
+                    } else if (ofAction instanceof OFActionTransportLayerSource) {
+                        Short port = ((OFActionTransportLayerSource) ofAction)
+                                .getTransportPort();
+                        int intPort = NetUtils.getUnsignedShort(port);
+                        salAction = new SetTpSrc(intPort);
+                    } else if (ofAction instanceof OFActionTransportLayerDestination) {
+                        Short port = ((OFActionTransportLayerDestination) ofAction)
+                                .getTransportPort();
+                        int intPort = NetUtils.getUnsignedShort(port);
+                        salAction = new SetTpDst(intPort);
+                    }
+                    salActionList.add(salAction);
+                }
+            }
+            // Create Flow
+            flow = new Flow(salMatch, salActionList);
+        }
+        logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch,
+                actionsList);
+        logger.trace("SAL Flow: {}", flow);
+        return flow;
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java
new file mode 100644 (file)
index 0000000..2a62d6c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Flow Programmer Notifier class for relaying asynchronous messages received
+ * from the network node to the listeners on the proper container
+ */
+public class FlowProgrammerNotifier implements IFlowProgrammerNotifier {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(FlowProgrammerNotifier.class);
+    private IPluginOutFlowProgrammerService salNotifier;
+
+    public FlowProgrammerNotifier() {
+        salNotifier = null;
+    }
+
+    void init(Component c) {
+        logger.debug("INIT called!");
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        logger.debug("DESTROY called!");
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    void start() {
+        logger.debug("START called!");
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    void stop() {
+        logger.debug("STOP called!");
+    }
+
+    public void setPluginOutFlowProgrammerService(
+            IPluginOutFlowProgrammerService s) {
+        this.salNotifier = s;
+    }
+
+    public void unsetPluginOutFlowProgrammerService(
+            IPluginOutFlowProgrammerService s) {
+        if (this.salNotifier == s) {
+            this.salNotifier = null;
+        }
+    }
+
+    @Override
+    public void flowRemoved(Node node, Flow flow) {
+        if (salNotifier != null) {
+            salNotifier.flowRemoved(node, flow);
+        } else {
+            logger.warn("Unable to relay switch message to upper layer");
+        }
+    }
+
+    @Override
+    public void flowErrorReported(Node node, long rid, Object err) {
+        if (salNotifier != null) {
+            salNotifier.flowErrorReported(node, rid, err);
+        } else {
+            logger.warn("Unable to relay switch error message to upper layer");
+        }
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java
new file mode 100644 (file)
index 0000000..7f90c88
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFFlowRemoved;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.MessageParseException;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents the openflow plugin component in charge of programming the flows
+ * the flow programming and relay them to functional modules above SAL.
+ */
+public class FlowProgrammerService implements IPluginInFlowProgrammerService,
+        IMessageListener, IContainerListener, IInventoryShimExternalListener,
+        CommandProvider {
+    private static final Logger log = LoggerFactory
+            .getLogger(FlowProgrammerService.class);
+    private IController controller;
+    private ConcurrentMap<String, IFlowProgrammerNotifier> flowProgrammerNotifiers;
+    private Map<String, Set<NodeConnector>> containerToNc;
+    private ConcurrentMap<Long, Map<Integer, Long>> xid2rid;
+    private int barrierMessagePriorCount = getBarrierMessagePriorCount();
+
+    public FlowProgrammerService() {
+        controller = null;
+        flowProgrammerNotifiers = new ConcurrentHashMap<String, IFlowProgrammerNotifier>();
+        containerToNc = new HashMap<String, Set<NodeConnector>>();
+        xid2rid = new ConcurrentHashMap<Long, Map<Integer, Long>>();
+    }
+
+    public void setController(IController core) {
+        this.controller = core;
+    }
+
+    public void unsetController(IController core) {
+        if (this.controller == core) {
+            this.controller = null;
+        }
+    }
+
+    public void setFlowProgrammerNotifier(Map<String, ?> props,
+            IFlowProgrammerNotifier s) {
+        if (props == null || props.get("containerName") == null) {
+            log.error("Didn't receive the service correct properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        this.flowProgrammerNotifiers.put(containerName, s);
+    }
+
+    public void unsetFlowProgrammerNotifier(Map<String, ?> props,
+            IFlowProgrammerNotifier s) {
+        if (props == null || props.get("containerName") == null) {
+            log.error("Didn't receive the service correct properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (this.flowProgrammerNotifiers != null
+                && this.flowProgrammerNotifiers.containsKey(containerName)
+                && this.flowProgrammerNotifiers.get(containerName) == s) {
+            this.flowProgrammerNotifiers.remove(containerName);
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        this.controller.addMessageListener(OFType.FLOW_REMOVED, this);
+        this.controller.addMessageListener(OFType.ERROR, this);
+        registerWithOSGIConsole();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    void stop() {
+    }
+
+    @Override
+    public Status addFlow(Node node, Flow flow) {
+        return addFlowInternal(node, flow, 0);
+    }
+
+    @Override
+    public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
+        return modifyFlowInternal(node, oldFlow, newFlow, 0);
+    }
+
+    @Override
+    public Status removeFlow(Node node, Flow flow) {
+        return removeFlowInternal(node, flow, 0);
+    }
+
+    @Override
+    public Status addFlowAsync(Node node, Flow flow, long rid) {
+        return addFlowInternal(node, flow, rid);
+    }
+
+    @Override
+    public Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow,
+            long rid) {
+        return modifyFlowInternal(node, oldFlow, newFlow, rid);
+    }
+
+    @Override
+    public Status removeFlowAsync(Node node, Flow flow, long rid) {
+        return removeFlowInternal(node, flow, rid);
+    }
+
+    private Status addFlowInternal(Node node, Flow flow, long rid) {
+        String action = "add";
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
+                    action, "Invalid node type"));
+        }
+
+        if (controller != null) {
+            ISwitch sw = controller.getSwitch((Long) node.getID());
+            if (sw != null) {
+                FlowConverter x = new FlowConverter(flow);
+                OFMessage msg = x.getOFFlowMod(OFFlowMod.OFPFC_ADD, null);
+
+                Object result;
+                if (rid == 0) {
+                    /*
+                     * Synchronous message send. Each message is followed by a
+                     * Barrier message.
+                     */
+                    result = sw.syncSend(msg);
+                } else {
+                    log.debug("Sending flow asynchronously");
+                    /*
+                     * Message will be sent asynchronously. A Barrier message
+                     * will be inserted automatically to synchronize the
+                     * progression.
+                     */
+                    result = asyncMsgSend(node, sw, msg, rid);
+                }
+                return getStatusInternal(result, action, rid);
+            } else {
+                return new Status(StatusCode.GONE, errorString("send", action,
+                        "Switch is not available"));
+            }
+        }
+        return new Status(StatusCode.INTERNALERROR, errorString("send", action,
+                "Internal plugin error"));
+    }
+
+    private Status modifyFlowInternal(Node node, Flow oldFlow, Flow newFlow, long rid) {
+        String action = "modify";
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
+                    action, "Invalid node type"));
+        }
+        if (controller != null) {
+            ISwitch sw = controller.getSwitch((Long) node.getID());
+            if (sw != null) {
+                OFMessage msg1 = null, msg2 = null;
+
+                // If priority and match portion are the same, send a
+                // modification message
+                if (oldFlow.getPriority() != newFlow.getPriority()
+                        || !oldFlow.getMatch().equals(newFlow.getMatch())) {
+                    msg1 = new FlowConverter(oldFlow).getOFFlowMod(
+                            OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
+                    msg2 = new FlowConverter(newFlow).getOFFlowMod(
+                            OFFlowMod.OFPFC_ADD, null);
+                } else {
+                    msg1 = new FlowConverter(newFlow).getOFFlowMod(
+                            OFFlowMod.OFPFC_MODIFY_STRICT, null);
+                }
+                /*
+                 * Synchronous message send
+                 */
+                action = (msg2 == null) ? "modify" : "delete";
+                Object result;
+                if (rid == 0) {
+                    /*
+                     * Synchronous message send. Each message is followed by a
+                     * Barrier message.
+                     */
+                    result = sw.syncSend(msg1);
+                } else {
+                    /*
+                     * Message will be sent asynchronously. A Barrier message
+                     * will be inserted automatically to synchronize the
+                     * progression.
+                     */
+                    result = asyncMsgSend(node, sw, msg1, rid);
+                }
+
+                Status rv = getStatusInternal(result, action, rid);
+                if ((msg2 == null) || !rv.isSuccess()) {
+                    return rv;
+                }
+
+                action = "add";
+                if (rid == 0) {
+                    /*
+                     * Synchronous message send. Each message is followed by a
+                     * Barrier message.
+                     */
+                    result = sw.syncSend(msg2);
+                } else {
+                    /*
+                     * Message will be sent asynchronously. A Barrier message
+                     * will be inserted automatically to synchronize the
+                     * progression.
+                     */
+                    result = asyncMsgSend(node, sw, msg2, rid);
+                }
+                return getStatusInternal(result, action, rid);
+            } else {
+                return new Status(StatusCode.GONE, errorString("send", action,
+                        "Switch is not available"));
+            }
+        }
+        return new Status(StatusCode.INTERNALERROR, errorString("send", action,
+                "Internal plugin error"));
+    }
+
+    private Status removeFlowInternal(Node node, Flow flow, long rid) {
+        String action = "remove";
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
+                    action, "Invalid node type"));
+        }
+        if (controller != null) {
+            ISwitch sw = controller.getSwitch((Long) node.getID());
+            if (sw != null) {
+                OFMessage msg = new FlowConverter(flow).getOFFlowMod(
+                        OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
+                Object result;
+                if (rid == 0) {
+                    /*
+                     * Synchronous message send. Each message is followed by a
+                     * Barrier message.
+                     */
+                    result = sw.syncSend(msg);
+                } else {
+                    /*
+                     * Message will be sent asynchronously. A Barrier message
+                     * will be inserted automatically to synchronize the
+                     * progression.
+                     */
+                    result = asyncMsgSend(node, sw, msg, rid);
+                }
+                return getStatusInternal(result, action, rid);
+            } else {
+                return new Status(StatusCode.GONE, errorString("send", action,
+                        "Switch is not available"));
+            }
+        }
+        return new Status(StatusCode.INTERNALERROR, errorString("send", action,
+                "Internal plugin error"));
+    }
+
+    @Override
+    public Status removeAllFlows(Node node) {
+        return new Status(StatusCode.SUCCESS);
+    }
+
+    private String errorString(String phase, String action, String cause) {
+        return "Failed to "
+                + ((phase != null) ? phase + " the " + action
+                        + " flow message: " : action + " the flow: ") + cause;
+    }
+
+    @Override
+    public void receive(ISwitch sw, OFMessage msg) {
+        if (msg instanceof OFFlowRemoved) {
+            handleFlowRemovedMessage(sw, (OFFlowRemoved) msg);
+        } else if (msg instanceof OFError) {
+            handleErrorMessage(sw, (OFError) msg);
+        }
+    }
+
+    private void handleFlowRemovedMessage(ISwitch sw, OFFlowRemoved msg) {
+        Node node = NodeCreator.createOFNode(sw.getId());
+        Flow flow = new FlowConverter(msg.getMatch(),
+                new ArrayList<OFAction>(0)).getFlow(node);
+        flow.setPriority(msg.getPriority());
+        flow.setIdleTimeout(msg.getIdleTimeout());
+        flow.setId(msg.getCookie());
+
+        Match match = flow.getMatch();
+        NodeConnector inPort = match.isPresent(MatchType.IN_PORT) ? (NodeConnector) match
+                .getField(MatchType.IN_PORT).getValue() : null;
+
+        for (Map.Entry<String, IFlowProgrammerNotifier> containerNotifier : flowProgrammerNotifiers
+                .entrySet()) {
+            String container = containerNotifier.getKey();
+            IFlowProgrammerNotifier notifier = containerNotifier.getValue();
+            /*
+             * Switch only provide us with the match information. For now let's
+             * try to identify the container membership only from the input port
+             * match field. In any case, upper layer consumers can derive
+             * whether the notification was not for them. More sophisticated
+             * filtering can be added later on.
+             */
+            if (inPort == null
+                    || container.equals(GlobalConstants.DEFAULT.toString())
+                    || this.containerToNc.get(container).contains(inPort)) {
+                notifier.flowRemoved(node, flow);
+            }
+        }
+    }
+
+    private void handleErrorMessage(ISwitch sw, OFError errorMsg) {
+        Node node = NodeCreator.createOFNode(sw.getId());
+        OFMessage offendingMsg = null;
+        try {
+            offendingMsg = errorMsg.getOffendingMsg();
+        } catch (MessageParseException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        Integer xid;
+        if (offendingMsg != null) {
+            xid = offendingMsg.getXid();
+        } else {
+            xid = errorMsg.getXid();
+        }
+
+        Long rid = getMessageRid(sw.getId(), xid);
+        /*
+         * Null or zero requestId indicates that the error message is meant for
+         * a sync message. It will be handled by the sync message worker thread.
+         * Hence we are done here.
+         */
+        if ((rid == null) || (rid == 0)) {
+            return;
+        }
+
+        /*
+         * Notifies the caller that error has been reported for a previous flow
+         * programming request
+         */
+        for (Map.Entry<String, IFlowProgrammerNotifier> containerNotifier : flowProgrammerNotifiers
+                .entrySet()) {
+            IFlowProgrammerNotifier notifier = containerNotifier.getValue();
+            notifier.flowErrorReported(node, rid, errorMsg);
+        }
+    }
+
+    @Override
+    public void tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+
+    }
+
+    @Override
+    public void containerFlowUpdated(String containerName,
+            ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
+    }
+
+    @Override
+    public void nodeConnectorUpdated(String containerName, NodeConnector p,
+            UpdateType type) {
+        Set<NodeConnector> target = null;
+
+        switch (type) {
+        case ADDED:
+            if (!containerToNc.containsKey(containerName)) {
+                containerToNc.put(containerName, new HashSet<NodeConnector>());
+            }
+            containerToNc.get(containerName).add(p);
+            break;
+        case CHANGED:
+            break;
+        case REMOVED:
+            target = containerToNc.get(containerName);
+            if (target != null) {
+                target.remove(p);
+            }
+            break;
+        default:
+        }
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+
+    }
+
+    @Override
+    public Status syncSendBarrierMessage(Node node) {
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            return new Status(StatusCode.NOTACCEPTABLE,
+                    "The node does not support Barrier message.");
+        }
+
+        if (controller != null) {
+            long swid = (Long) node.getID();
+            ISwitch sw = controller.getSwitch(swid);
+            if (sw != null) {
+                sw.syncSendBarrierMessage();
+                clearXid2Rid(swid);
+                return (new Status(StatusCode.SUCCESS));
+            } else {
+                return new Status(StatusCode.GONE,
+                        "The node does not have a valid Switch reference.");
+            }
+        }
+        return new Status(StatusCode.INTERNALERROR,
+                "Failed to send Barrier message.");
+    }
+
+    @Override
+    public Status asyncSendBarrierMessage(Node node) {
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            return new Status(StatusCode.NOTACCEPTABLE,
+                    "The node does not support Barrier message.");
+        }
+
+        if (controller != null) {
+            long swid = (Long) node.getID();
+            ISwitch sw = controller.getSwitch(swid);
+            if (sw != null) {
+                sw.asyncSendBarrierMessage();
+                clearXid2Rid(swid);
+                return (new Status(StatusCode.SUCCESS));
+            } else {
+                return new Status(StatusCode.GONE,
+                        "The node does not have a valid Switch reference.");
+            }
+        }
+        return new Status(StatusCode.INTERNALERROR,
+                "Failed to send Barrier message.");
+    }
+
+    /**
+     * This method sends the message asynchronously until the number of messages
+     * sent reaches a threshold. Then a Barrier message is sent automatically
+     * for sync purpose. An unique Request ID associated with the message is
+     * passed down by the caller. The Request ID will be returned to the caller
+     * when an error message is received from the switch.
+     *
+     * @param node
+     *            The node
+     * @param msg
+     *            The switch
+     * @param msg
+     *            The OF message to be sent
+     * @param rid
+     *            The Request Id
+     * @return result
+     */
+    private Object asyncMsgSend(Node node, ISwitch sw, OFMessage msg, long rid) {
+        Object result = Boolean.TRUE;
+        long swid = (Long) node.getID();
+        int xid;
+
+        xid = sw.asyncSend(msg);
+        addXid2Rid(swid, xid, rid);
+
+        Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
+        if (swxid2rid == null) {
+            return result;
+        }
+
+        int size = swxid2rid.size();
+        if (size % barrierMessagePriorCount == 0) {
+            result = asyncSendBarrierMessage(node);
+        }
+
+        return result;
+    }
+
+    /**
+     * A number of async messages are sent followed by a synchronous Barrier
+     * message. This method returns the maximum async messages that can be sent
+     * before the Barrier message.
+     *
+     * @return The max count of async messages sent prior to Barrier message
+     */
+    private int getBarrierMessagePriorCount() {
+        String count = System.getProperty("of.barrierMessagePriorCount");
+        int rv = 100;
+
+        if (count != null) {
+            try {
+                rv = Integer.parseInt(count);
+            } catch (Exception e) {
+            }
+        }
+
+        return rv;
+    }
+
+    /**
+     * This method returns the message Request ID previously assigned by the
+     * caller for a given OF message xid
+     *
+     * @param swid
+     *            The switch id
+     * @param xid
+     *            The OF message xid
+     * @return The Request ID
+     */
+    private Long getMessageRid(long swid, Integer xid) {
+        Long rid = null;
+
+        if (xid == null) {
+            return rid;
+        }
+
+        Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
+        if (swxid2rid != null) {
+            rid = swxid2rid.get(xid);
+        }
+        return rid;
+    }
+
+    /**
+     * This method returns a copy of outstanding xid to rid mappings.for a given
+     * switch
+     *
+     * @param swid
+     *            The switch id
+     * @return a copy of xid2rid mappings
+     */
+    public Map<Integer, Long> getSwXid2Rid(long swid) {
+        Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
+
+        if (swxid2rid != null) {
+            return new HashMap<Integer, Long>(swxid2rid);
+        } else {
+            return new HashMap<Integer, Long>();
+        }
+    }
+
+    /**
+     * Adds xid to rid mapping to the local DB
+     *
+     * @param swid
+     *            The switch id
+     * @param xid
+     *            The OF message xid
+     * @param rid
+     *            The message Request ID
+     */
+    private void addXid2Rid(long swid, int xid, long rid) {
+        Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
+        if (swxid2rid != null) {
+            swxid2rid.put(xid, rid);
+        }
+    }
+
+    /**
+     * When an Error message is received, this method will be invoked to remove
+     * the offending xid from the local DB.
+     *
+     * @param swid
+     *            The switch id
+     * @param xid
+     *            The OF message xid
+     */
+    private void removeXid2Rid(long swid, int xid) {
+        Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
+        if (swxid2rid != null) {
+            swxid2rid.remove(xid);
+        }
+    }
+
+    /**
+     * Convert various result into Status
+     *
+     * @param result
+     *            The returned result from previous action
+     * @param action
+     *            add/modify/delete flow action
+     * @param rid
+     *            The Request ID associated with the flow message
+     * @return Status
+     */
+    private Status getStatusInternal(Object result, String action, long rid) {
+        if (result instanceof Boolean) {
+            return ((Boolean) result == Boolean.TRUE) ? new Status(
+                    StatusCode.SUCCESS, rid) : new Status(
+                    StatusCode.TIMEOUT, errorString(null, action,
+                            "Request Timed Out"));
+        } else if (result instanceof Status) {
+            return (Status) result;
+        } else if (result instanceof OFError) {
+            OFError res = (OFError) result;
+            return new Status(StatusCode.INTERNALERROR, errorString(
+                    "program", action, Utils.getOFErrorString(res)));
+        } else {
+            return new Status(StatusCode.INTERNALERROR, errorString(
+                    "send", action, "Internal Error"));
+        }
+    }
+
+    /**
+     * When a Barrier reply is received, this method will be invoked to clear
+     * the local DB
+     *
+     * @param swid
+     *            The switch id
+     */
+    private void clearXid2Rid(long swid) {
+        Map<Integer, Long> swxid2rid = this.xid2rid.get(swid);
+        if (swxid2rid != null) {
+            swxid2rid.clear();
+        }
+    }
+
+    @Override
+    public void updateNode(Node node, UpdateType type, Set<Property> props) {
+        long swid = (Long)node.getID();
+
+        switch (type) {
+        case ADDED:
+            Map<Integer, Long> swxid2rid = new HashMap<Integer, Long>();
+            this.xid2rid.put(swid, swxid2rid);
+            break;
+        case CHANGED:
+            break;
+        case REMOVED:
+            this.xid2rid.remove(swid);
+            break;
+        default:
+        }
+    }
+
+    @Override
+    public void updateNodeConnector(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props) {
+    }
+
+    private void registerWithOSGIConsole() {
+        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+        bundleContext.registerService(CommandProvider.class.getName(), this,
+                null);
+    }
+
+    @Override
+    public String getHelp() {
+        StringBuffer help = new StringBuffer();
+        help.append("-- Flow Programmer Service --\n");
+        help.append("\t px2r <node id>          - Print outstanding xid2rid mappings for a given node id\n");
+        help.append("\t px2rc                   - Print max num of async msgs prior to the Barrier\n");
+        return help.toString();
+    }
+
+    public void _px2r(CommandInterpreter ci) {
+        String st = ci.nextArgument();
+        if (st == null) {
+            ci.println("Please enter a valid node id");
+            return;
+        }
+
+        long sid;
+        try {
+            sid = HexEncode.stringToLong(st);
+        } catch (NumberFormatException e) {
+            ci.println("Please enter a valid node id");
+            return;
+        }
+
+        Map<Integer, Long> swxid2rid = this.xid2rid.get(sid);
+        if (swxid2rid == null) {
+            ci.println("The node id entered does not exist");
+            return;
+        }
+
+        ci.println("xid             rid");
+
+        Set<Integer> xidSet = swxid2rid.keySet();
+        if (xidSet == null) {
+            return;
+        }
+
+        for (Integer xid : xidSet) {
+            ci.println(xid + "       " + swxid2rid.get(xid));
+        }
+    }
+
+    public void _px2rc(CommandInterpreter ci) {
+        ci.println("Max num of async messages sent prior to the Barrier message is "
+                + barrierMessagePriorCount);
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowStatisticsConverter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowStatisticsConverter.java
new file mode 100644 (file)
index 0000000..82dbf67
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6StatsReply;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.openflow.protocol.statistics.OFFlowStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Converts an openflow list of flow statistics in a SAL list of FlowOnNode
+ * objects
+ *
+ *
+ *
+ */
+public class FlowStatisticsConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(FlowStatisticsConverter.class);
+    private List<OFStatistics> ofStatsList;
+    private List<FlowOnNode> flowOnNodeList;
+
+    public FlowStatisticsConverter(List<OFStatistics> statsList) {
+        if (statsList == null) {// || statsList.isEmpty()) {
+            this.ofStatsList = new ArrayList<OFStatistics>(1); // dummy list
+        } else {
+            this.ofStatsList = statsList; // new
+                                          // ArrayList<OFStatistics>(statsList);
+        }
+        this.flowOnNodeList = null;
+    }
+
+    public List<FlowOnNode> getFlowOnNodeList(Node node) {
+        if (ofStatsList != null && flowOnNodeList == null) {
+            flowOnNodeList = new ArrayList<FlowOnNode>();
+            FlowConverter flowConverter = null;
+            OFFlowStatisticsReply ofFlowStat;
+            V6StatsReply v6StatsReply;
+            for (OFStatistics ofStat : ofStatsList) {
+                FlowOnNode flowOnNode = null;
+                if (ofStat instanceof OFFlowStatisticsReply) {
+                    ofFlowStat = (OFFlowStatisticsReply) ofStat;
+                    flowConverter = new FlowConverter(ofFlowStat.getMatch(),
+                            ofFlowStat.getActions());
+                    Flow flow = flowConverter.getFlow(node);
+                    flow.setPriority(ofFlowStat.getPriority());
+                    flow.setIdleTimeout(ofFlowStat.getIdleTimeout());
+                    flow.setHardTimeout(ofFlowStat.getHardTimeout());
+                    flowOnNode = new FlowOnNode(flow);
+                    flowOnNode.setByteCount(ofFlowStat.getByteCount());
+                    flowOnNode.setPacketCount(ofFlowStat.getPacketCount());
+                    flowOnNode.setDurationSeconds(ofFlowStat
+                            .getDurationSeconds());
+                    flowOnNode.setDurationNanoseconds(ofFlowStat
+                            .getDurationNanoseconds());
+                } else if (ofStat instanceof V6StatsReply) {
+                    v6StatsReply = (V6StatsReply) ofStat;
+                    flowConverter = new FlowConverter(v6StatsReply.getMatch(),
+                            v6StatsReply.getActions());
+                    Flow flow = flowConverter.getFlow(node);
+                    flow.setPriority(v6StatsReply.getPriority());
+                    flow.setIdleTimeout(v6StatsReply.getIdleTimeout());
+                    flow.setHardTimeout(v6StatsReply.getHardTimeout());
+                    flowOnNode = new FlowOnNode(flow);
+                    flowOnNode.setByteCount(v6StatsReply.getByteCount());
+                    flowOnNode.setPacketCount(v6StatsReply.getPacketCount());
+                    flowOnNode.setDurationSeconds(v6StatsReply
+                            .getDurationSeconds());
+                    flowOnNode.setDurationNanoseconds(v6StatsReply
+                            .getDurationNanoseconds());
+                } else {
+                    continue;
+                }
+                flowOnNodeList.add(flowOnNode);
+            }
+        }
+        log.trace("OFStatistics: {} FlowOnNode: {}", ofStatsList,
+                flowOnNodeList);
+        return flowOnNodeList;
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryService.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryService.java
new file mode 100644 (file)
index 0000000..60fbd70
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.opendaylight.controller.sal.core.Actions;
+import org.opendaylight.controller.sal.core.Buffers;
+import org.opendaylight.controller.sal.core.Capabilities;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Description;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.Tables;
+import org.opendaylight.controller.sal.core.TimeStamp;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The class describes inventory service protocol plugin. One instance per
+ * container of the network. Each instance gets container specific inventory
+ * events from InventoryServiceShim. It interacts with SAL to pass inventory
+ * data to the upper application.
+ *
+ *
+ */
+public class InventoryService implements IInventoryShimInternalListener,
+        IPluginInInventoryService, IStatisticsListener {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(InventoryService.class);
+    private Set<IPluginOutInventoryService> pluginOutInventoryServices = Collections
+            .synchronizedSet(new HashSet<IPluginOutInventoryService>());
+    private IController controller = null;
+    private ConcurrentMap<Node, Map<String, Property>> nodeProps; // properties are maintained in global container only
+    private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps; // properties are maintained in global container only
+    private boolean isDefaultContainer = false;
+
+    void setController(IController s) {
+        this.controller = s;
+    }
+
+    void unsetController(IController s) {
+        if (this.controller == s) {
+            this.controller = null;
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    @SuppressWarnings("rawtypes")
+    void init(Component c) {
+        logger.trace("INIT called!");
+
+        Dictionary props = c.getServiceProperties();
+        if (props != null) {
+            String containerName = (String) props.get("containerName");
+            isDefaultContainer = containerName.equals(GlobalConstants.DEFAULT
+                    .toString());
+        }
+
+        nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
+        nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        logger.trace("DESTROY called!");
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    void start() {
+        logger.trace("START called!");
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    void stop() {
+        logger.trace("STOP called!");
+    }
+
+    public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
+        logger.trace("Got a service set request {}", service);
+        if (this.pluginOutInventoryServices != null) {
+            this.pluginOutInventoryServices.add(service);
+        }
+    }
+
+    public void unsetPluginOutInventoryServices(
+            IPluginOutInventoryService service) {
+        logger.trace("Got a service UNset request");
+        if (this.pluginOutInventoryServices != null) {
+            this.pluginOutInventoryServices.remove(service);
+        }
+    }
+
+    protected Node OFSwitchToNode(ISwitch sw) {
+        Node node = null;
+        Object id = sw.getId();
+
+        try {
+            node = new Node(NodeIDType.OPENFLOW, id);
+        } catch (ConstructionException e) {
+            logger.error("",e);
+        }
+
+        return node;
+    }
+
+    /**
+     * Retrieve nodes from openflow
+     */
+    @Override
+    public ConcurrentMap<Node, Map<String, Property>> getNodeProps() {
+        if (nodeProps == null)
+            return null;
+        Map<Long, ISwitch> switches = controller.getSwitches();
+        for (Map.Entry<Long, ISwitch> entry : switches.entrySet()) {
+            ISwitch sw = entry.getValue();
+            Node node = OFSwitchToNode(sw);
+            Map<String, Property> propMap = null;
+            if (isDefaultContainer) {
+                propMap = new HashMap<String, Property>();
+                byte tables = sw.getTables();
+                Tables t = new Tables(tables);
+                if (t != null) {
+                    propMap.put(Tables.TablesPropName, t);
+                }
+                int cap = sw.getCapabilities();
+                Capabilities c = new Capabilities(cap);
+                if (c != null) {
+                    propMap.put(Capabilities.CapabilitiesPropName, c);
+                }
+                int act = sw.getActions();
+                Actions a = new Actions(act);
+                if (a != null) {
+                    propMap.put(Actions.ActionsPropName, a);
+                }
+                int buffers = sw.getBuffers();
+                Buffers b = new Buffers(buffers);
+                if (b != null) {
+                    propMap.put(Buffers.BuffersPropName, b);
+                }
+                Date connectedSince = sw.getConnectedDate();
+                Long connectedSinceTime = (connectedSince == null) ? 0
+                        : connectedSince.getTime();
+                TimeStamp timeStamp = new TimeStamp(connectedSinceTime,
+                        "connectedSince");
+                propMap.put(TimeStamp.TimeStampPropName, timeStamp);
+                nodeProps.put(node, propMap);
+            }
+        }
+        return nodeProps;
+    }
+
+    @Override
+    public ConcurrentMap<NodeConnector, Map<String, Property>> getNodeConnectorProps(
+            Boolean refresh) {
+        if (nodeConnectorProps == null)
+            return null;
+
+        if (isDefaultContainer && refresh) {
+            Map<Long, ISwitch> switches = controller.getSwitches();
+            for (ISwitch sw : switches.values()) {
+                Map<NodeConnector, Set<Property>> ncProps = InventoryServiceHelper
+                        .OFSwitchToProps(sw);
+                for (Map.Entry<NodeConnector, Set<Property>> entry : ncProps
+                        .entrySet()) {
+                    updateNodeConnector(entry.getKey(), UpdateType.ADDED,
+                            entry.getValue());
+                }
+            }
+        }
+
+        return nodeConnectorProps;
+    }
+
+    @Override
+    public void updateNodeConnector(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props) {
+        logger.trace("updateNodeConnector {} type {}", nodeConnector,
+                type.getName());
+        if (nodeConnectorProps == null) {
+            logger.trace("nodeConnectorProps is null");
+            return;
+        }
+
+        Map<String, Property> propMap = nodeConnectorProps.get(nodeConnector);
+        switch (type) {
+        case ADDED:
+        case CHANGED:
+            if (propMap == null)
+                propMap = new HashMap<String, Property>();
+
+            if (props != null) {
+                for (Property prop : props) {
+                    propMap.put(prop.getName(), prop);
+                }
+            }
+            nodeConnectorProps.put(nodeConnector, propMap);
+            break;
+        case REMOVED:
+            nodeConnectorProps.remove(nodeConnector);
+            break;
+        default:
+            return;
+        }
+
+        // update sal and discovery
+        synchronized (pluginOutInventoryServices) {
+            for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+                service.updateNodeConnector(nodeConnector, type, props);
+            }
+        }
+    }
+
+    private void addNode(Node node, Set<Property> props) {
+        logger.trace("{} added", node);
+        if (nodeProps == null)
+            return;
+
+        // update local cache
+        Map<String, Property> propMap = new HashMap<String, Property>();
+        for (Property prop : props) {
+            propMap.put(prop.getName(), prop);
+        }
+        nodeProps.put(node, propMap);
+
+        // update sal
+        synchronized (pluginOutInventoryServices) {
+            for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+                service.updateNode(node, UpdateType.ADDED, props);
+            }
+        }
+    }
+
+    private void removeNode(Node node) {
+        logger.trace("{} removed", node);
+        if (nodeProps == null)
+            return;
+
+        // update local cache
+        nodeProps.remove(node);
+
+        Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
+        for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
+            if (nodeConnector.getNode().equals(node)) {
+                removeSet.add(nodeConnector);
+            }
+        }
+        for (NodeConnector nodeConnector : removeSet) {
+            nodeConnectorProps.remove(nodeConnector);
+        }
+
+        // update sal
+        synchronized (pluginOutInventoryServices) {
+            for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+                service.updateNode(node, UpdateType.REMOVED, null);
+            }
+        }
+    }
+
+    private void updateSwitchProperty(Long switchId, Set<Property> propSet) {
+        // update local cache
+        Node node = OFSwitchToNode(controller.getSwitch(switchId));
+        Map<String, Property> propMap = nodeProps.get(node);
+        if (propMap == null) {
+            propMap = new HashMap<String, Property>();
+        }
+
+        boolean change = false;
+        for (Property prop : propSet) {
+            String propertyName = prop.getName();
+            Property currentProp = propMap.get(propertyName);
+            if (!prop.equals(currentProp)) {
+                change = true;
+                propMap.put(propertyName, prop);
+            }
+        }
+        nodeProps.put(node, propMap);
+
+        // Update sal if any of the properties has changed
+        if (change) {
+            synchronized (pluginOutInventoryServices) {
+                for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+                    service.updateNode(node, UpdateType.CHANGED, propSet);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void updateNode(Node node, UpdateType type, Set<Property> props) {
+        switch (type) {
+        case ADDED:
+            addNode(node, props);
+            break;
+        case REMOVED:
+            removeNode(node);
+            break;
+        default:
+            break;
+        }
+    }
+
+    @Override
+    public void descriptionRefreshed(Long switchId,
+            OFDescriptionStatistics descriptionStats) {
+
+        Set<Property> propSet = new HashSet<Property>(1);
+        Description desc = new Description(
+                descriptionStats.getDatapathDescription());
+        propSet.add(desc);
+        this.updateSwitchProperty(switchId, propSet);
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceHelper.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceHelper.java
new file mode 100644 (file)
index 0000000..79973ee
--- /dev/null
@@ -0,0 +1,167 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.Bandwidth;
+import org.opendaylight.controller.sal.core.AdvertisedBandwidth;
+import org.opendaylight.controller.sal.core.SupportedBandwidth;
+import org.opendaylight.controller.sal.core.PeerBandwidth;
+import org.opendaylight.controller.sal.core.Config;
+import org.opendaylight.controller.sal.core.Name;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.State;
+
+import org.opendaylight.controller.sal.utils.NodeCreator;
+
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
+import org.openflow.protocol.OFPhysicalPort.OFPortFeatures;
+import org.openflow.protocol.OFPhysicalPort.OFPortState;
+
+/**
+ * The class provides helper functions to retrieve inventory properties from
+ * OpenFlow messages
+ */
+public class InventoryServiceHelper {
+    /*
+     * Returns BandWidth property from OpenFlow OFPhysicalPort features
+     */
+    public static Bandwidth OFPortToBandWidth(int portFeatures) {
+        Bandwidth bw = null;
+        int value = portFeatures
+                & (OFPortFeatures.OFPPF_10MB_FD.getValue()
+                        | OFPortFeatures.OFPPF_10MB_HD.getValue()
+                        | OFPortFeatures.OFPPF_100MB_FD.getValue()
+                        | OFPortFeatures.OFPPF_100MB_HD.getValue()
+                        | OFPortFeatures.OFPPF_1GB_FD.getValue()
+                        | OFPortFeatures.OFPPF_1GB_HD.getValue() | OFPortFeatures.OFPPF_10GB_FD
+                        .getValue());
+
+        switch (value) {
+        case 1:
+        case 2:
+            bw = new Bandwidth(Bandwidth.BW10Mbps);
+            break;
+        case 4:
+        case 8:
+            bw = new Bandwidth(Bandwidth.BW100Mbps);
+            break;
+        case 16:
+        case 32:
+            bw = new Bandwidth(Bandwidth.BW1Gbps);
+            break;
+        case 64:
+            bw = new Bandwidth(Bandwidth.BW10Gbps);
+            break;
+        default:
+            break;
+        }
+        return bw;
+    }
+
+    /*
+     * Returns Config property from OpenFLow OFPhysicalPort config
+     */
+    public static Config OFPortToConfig(int portConfig) {
+        Config config;
+        if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & portConfig) != 0)
+            config = new Config(Config.ADMIN_DOWN);
+        else
+            config = new Config(Config.ADMIN_UP);
+        return config;
+    }
+
+    /*
+     * Returns State property from OpenFLow OFPhysicalPort state
+     */
+    public static State OFPortToState(int portState) {
+        State state;
+        if ((OFPortState.OFPPS_LINK_DOWN.getValue() & portState) != 0)
+            state = new State(State.EDGE_DOWN);
+        else
+            state = new State(State.EDGE_UP);
+        return state;
+    }
+
+    /*
+     * Returns set of properties from OpenFLow OFPhysicalPort
+     */
+    public static Set<Property> OFPortToProps(OFPhysicalPort port) {
+        Set<Property> props = new HashSet<Property>();
+        Bandwidth bw = InventoryServiceHelper.OFPortToBandWidth(port
+                .getCurrentFeatures());
+        if (bw != null) {
+            props.add(bw);
+        }
+
+        Bandwidth abw = InventoryServiceHelper.OFPortToBandWidth(port.getAdvertisedFeatures());
+        if (abw != null) {
+            AdvertisedBandwidth a = new AdvertisedBandwidth(abw.getValue());
+            if (a != null) {
+                props.add(a);
+            }
+        }
+        Bandwidth sbw = InventoryServiceHelper.OFPortToBandWidth(port.getSupportedFeatures());
+        if (sbw != null) {
+            SupportedBandwidth s = new SupportedBandwidth(sbw.getValue());
+            if (s != null) {
+                props.add(s);
+            }
+        }
+        Bandwidth pbw = InventoryServiceHelper.OFPortToBandWidth(port.getPeerFeatures());
+        if (pbw != null) {
+            PeerBandwidth p = new PeerBandwidth(pbw.getValue());
+            if (p != null) {
+                props.add(p);
+            }
+        }
+        props.add(new Name(port.getName()));
+        props.add(InventoryServiceHelper.OFPortToConfig(port.getConfig()));
+        props.add(InventoryServiceHelper.OFPortToState(port.getState()));
+        return props;
+    }
+
+    /*
+     * Returns set of properties for each nodeConnector in an OpenFLow switch
+     */
+    public static Map<NodeConnector, Set<Property>> OFSwitchToProps(ISwitch sw) {
+        Map<NodeConnector, Set<Property>> ncProps = new HashMap<NodeConnector, Set<Property>>();
+
+        if (sw == null) {
+            return ncProps;
+        }
+
+        Node node = NodeCreator.createOFNode(sw.getId());
+        if (node == null) {
+            return ncProps;
+        }
+
+        Set<Property> props;
+        NodeConnector nodeConnector;
+        OFPhysicalPort port;
+        Map<Short, OFPhysicalPort> ports = sw.getPhysicalPorts();
+        for (Map.Entry<Short, OFPhysicalPort> entry : ports.entrySet()) {
+            nodeConnector = PortConverter.toNodeConnector(entry.getKey(), node);
+            port = entry.getValue();
+            props = InventoryServiceHelper.OFPortToProps(port);
+            ncProps.put(nodeConnector, props);
+        }
+
+        return ncProps;
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java
new file mode 100644 (file)
index 0000000..49143c8
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitchStateListener;
+import org.opendaylight.controller.sal.core.Actions;
+import org.opendaylight.controller.sal.core.Buffers;
+import org.opendaylight.controller.sal.core.Capabilities;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.Tables;
+import org.opendaylight.controller.sal.core.TimeStamp;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPortStatus;
+import org.openflow.protocol.OFPortStatus.OFPortReason;
+import org.openflow.protocol.OFType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The class describes a shim layer that bridges inventory events from Openflow
+ * core to various listeners. The notifications are filtered based on container
+ * configurations.
+ *
+ *
+ */
+public class InventoryServiceShim implements IContainerListener,
+        IMessageListener, ISwitchStateListener {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(InventoryServiceShim.class);
+    private IController controller = null;
+    private ConcurrentMap<String, IInventoryShimInternalListener> inventoryShimInternalListeners = new ConcurrentHashMap<String, IInventoryShimInternalListener>();
+    private List<IInventoryShimExternalListener> inventoryShimExternalListeners = new CopyOnWriteArrayList<IInventoryShimExternalListener>();
+    private ConcurrentMap<NodeConnector, List<String>> containerMap = new ConcurrentHashMap<NodeConnector, List<String>>();
+
+    void setController(IController s) {
+        this.controller = s;
+    }
+
+    void unsetController(IController s) {
+        if (this.controller == s) {
+            this.controller = null;
+        }
+    }
+
+    void setInventoryShimInternalListener(Map<?, ?> props,
+            IInventoryShimInternalListener s) {
+        if (props == null) {
+            logger.error("setInventoryShimInternalListener property is null");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            logger.error("setInventoryShimInternalListener containerName not supplied");
+            return;
+        }
+        if ((this.inventoryShimInternalListeners != null)
+                && !this.inventoryShimInternalListeners.containsValue(s)) {
+            this.inventoryShimInternalListeners.put(containerName, s);
+            logger.trace(
+                    "Added inventoryShimInternalListener for container {}",
+                    containerName);
+        }
+    }
+
+    void unsetInventoryShimInternalListener(Map<?, ?> props,
+            IInventoryShimInternalListener s) {
+        if (props == null) {
+            logger.error("unsetInventoryShimInternalListener property is null");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            logger.error("unsetInventoryShimInternalListener containerName not supplied");
+            return;
+        }
+        if ((this.inventoryShimInternalListeners != null)
+                && this.inventoryShimInternalListeners.get(containerName) != null
+                && this.inventoryShimInternalListeners.get(containerName)
+                        .equals(s)) {
+            this.inventoryShimInternalListeners.remove(containerName);
+            logger.trace(
+                    "Removed inventoryShimInternalListener for container {}",
+                    containerName);
+        }
+    }
+
+    void setInventoryShimExternalListener(IInventoryShimExternalListener s) {
+        logger.trace("Set inventoryShimExternalListener");
+        if ((this.inventoryShimExternalListeners != null)
+                && !this.inventoryShimExternalListeners.contains(s)) {
+            this.inventoryShimExternalListeners.add(s);
+        }
+    }
+
+    void unsetInventoryShimExternalListener(IInventoryShimExternalListener s) {
+        if ((this.inventoryShimExternalListeners != null)
+                && this.inventoryShimExternalListeners.contains(s)) {
+            this.inventoryShimExternalListeners.remove(s);
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        this.controller.addMessageListener(OFType.PORT_STATUS, this);
+        this.controller.addSwitchStateListener(this);
+    }
+
+    /**
+     * Function called after registering the service in OSGi service registry.
+     */
+    void started() {
+        /* Start with existing switches */
+        startService();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        this.controller.removeMessageListener(OFType.PACKET_IN, this);
+        this.controller.removeSwitchStateListener(this);
+
+        this.inventoryShimInternalListeners.clear();
+        this.containerMap.clear();
+        this.controller = null;
+    }
+
+    @Override
+    public void receive(ISwitch sw, OFMessage msg) {
+        try {
+            if (msg instanceof OFPortStatus) {
+                handlePortStatusMessage(sw, (OFPortStatus) msg);
+            }
+        } catch (ConstructionException e) {
+            logger.error("",e);
+        }
+        return;
+    }
+
+    protected void handlePortStatusMessage(ISwitch sw, OFPortStatus m)
+            throws ConstructionException {
+        Node node = new Node(NodeIDType.OPENFLOW, sw.getId());
+        NodeConnector nodeConnector = PortConverter.toNodeConnector(m.getDesc()
+                .getPortNumber(), node);
+        UpdateType type = null;
+
+        if (m.getReason() == (byte) OFPortReason.OFPPR_ADD.ordinal()) {
+            type = UpdateType.ADDED;
+        } else if (m.getReason() == (byte) OFPortReason.OFPPR_DELETE.ordinal()) {
+            type = UpdateType.REMOVED;
+        } else if (m.getReason() == (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
+            type = UpdateType.CHANGED;
+        }
+
+        logger.trace("handlePortStatusMessage {} type {}", nodeConnector, type);
+
+        if (type != null) {
+            // get node connector properties
+            Set<Property> props = InventoryServiceHelper.OFPortToProps(m
+                    .getDesc());
+            notifyInventoryShimListener(nodeConnector, type, props);
+        }
+    }
+
+    @Override
+    public void switchAdded(ISwitch sw) {
+        if (sw == null)
+            return;
+
+        // Add all the nodeConnectors of this switch
+        Map<NodeConnector, Set<Property>> ncProps = InventoryServiceHelper
+                .OFSwitchToProps(sw);
+        for (Map.Entry<NodeConnector, Set<Property>> entry : ncProps.entrySet()) {
+            notifyInventoryShimListener(entry.getKey(), UpdateType.ADDED,
+                    entry.getValue());
+        }
+
+        // Add this node
+        addNode(sw);
+    }
+
+    @Override
+    public void switchDeleted(ISwitch sw) {
+        if (sw == null)
+            return;
+
+        removeNode(sw);
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+        // do nothing
+    }
+
+    @Override
+    public void tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+    }
+
+    @Override
+    public void containerFlowUpdated(String containerName,
+            ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
+    }
+
+    @Override
+    public void nodeConnectorUpdated(String containerName, NodeConnector p,
+            UpdateType t) {
+        if (this.containerMap == null) {
+            logger.error("containerMap is NULL");
+            return;
+        }
+        List<String> containers = this.containerMap.get(p);
+        if (containers == null) {
+            containers = new CopyOnWriteArrayList<String>();
+        }
+        boolean updateMap = false;
+        switch (t) {
+        case ADDED:
+            if (!containers.contains(containerName)) {
+                containers.add(containerName);
+                updateMap = true;
+            }
+            break;
+        case REMOVED:
+            if (containers.contains(containerName)) {
+                containers.remove(containerName);
+                updateMap = true;
+            }
+            break;
+        case CHANGED:
+            break;
+        }
+        if (updateMap) {
+            if (containers.isEmpty()) {
+                // Do cleanup to reduce memory footprint if no
+                // elements to be tracked
+                this.containerMap.remove(p);
+            } else {
+                this.containerMap.put(p, containers);
+            }
+        }
+
+        // notify InventoryService
+        notifyInventoryShimInternalListener(containerName, p, t, null);
+    }
+
+    private void notifyInventoryShimExternalListener(Node node,
+            UpdateType type, Set<Property> props) {
+        for (IInventoryShimExternalListener s : this.inventoryShimExternalListeners) {
+            s.updateNode(node, type, props);
+        }
+    }
+
+    private void notifyInventoryShimExternalListener(
+            NodeConnector nodeConnector, UpdateType type, Set<Property> props) {
+        for (IInventoryShimExternalListener s : this.inventoryShimExternalListeners) {
+            s.updateNodeConnector(nodeConnector, type, props);
+        }
+    }
+
+    private void notifyInventoryShimInternalListener(String container,
+            NodeConnector nodeConnector, UpdateType type, Set<Property> props) {
+        IInventoryShimInternalListener inventoryShimInternalListener = inventoryShimInternalListeners
+                .get(container);
+        if (inventoryShimInternalListener != null) {
+            inventoryShimInternalListener.updateNodeConnector(nodeConnector,
+                    type, props);
+            logger.trace(
+                    "notifyInventoryShimInternalListener {} type {} for container {}",
+                    nodeConnector, type, container);
+        }
+    }
+
+    /*
+     * Notify all internal and external listeners
+     */
+    private void notifyInventoryShimListener(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props) {
+        // Always notify default InventoryService. Store properties in default
+        // one.
+        notifyInventoryShimInternalListener(GlobalConstants.DEFAULT.toString(),
+                nodeConnector, type, props);
+
+        // Now notify other containers
+        List<String> containers = containerMap.get(nodeConnector);
+        if (containers != null) {
+            for (String container : containers) {
+                // no property stored in container components.
+                notifyInventoryShimInternalListener(container, nodeConnector,
+                        type, null);
+            }
+        }
+
+        // Notify DiscoveryService
+        notifyInventoryShimExternalListener(nodeConnector, type, props);
+    }
+
+    /*
+     * Notify all internal and external listeners
+     */
+    private void notifyInventoryShimListener(Node node, UpdateType type,
+            Set<Property> props) {
+        switch (type) {
+        case ADDED:
+            // Notify only the default Inventory Service
+            IInventoryShimInternalListener inventoryShimDefaultListener = inventoryShimInternalListeners
+                    .get(GlobalConstants.DEFAULT.toString());
+            if (inventoryShimDefaultListener != null) {
+                inventoryShimDefaultListener.updateNode(node, type, props);
+            }
+            break;
+        case REMOVED:
+            // Notify all Inventory Service containers
+            for (IInventoryShimInternalListener inventoryShimInternalListener : inventoryShimInternalListeners
+                    .values()) {
+                inventoryShimInternalListener.updateNode(node, type, null);
+            }
+            break;
+        default:
+            break;
+        }
+
+        // Notify external listener
+        notifyInventoryShimExternalListener(node, type, props);
+    }
+
+    private void addNode(ISwitch sw) {
+        Node node;
+        try {
+            node = new Node(NodeIDType.OPENFLOW, sw.getId());
+        } catch (ConstructionException e) {
+            logger.error("{}", e.getMessage());
+            return;
+        }
+
+        UpdateType type = UpdateType.ADDED;
+
+        Set<Property> props = new HashSet<Property>();
+        Long sid = (Long) node.getID();
+
+        Date connectedSince = controller.getSwitches().get(sid)
+                .getConnectedDate();
+        Long connectedSinceTime = (connectedSince == null) ? 0 : connectedSince
+                .getTime();
+        props.add(new TimeStamp(connectedSinceTime, "connectedSince"));
+
+        byte tables = sw.getTables();
+        Tables t = new Tables(tables);
+        if (t != null) {
+            props.add(t);
+        }
+        int cap = sw.getCapabilities();
+        Capabilities c = new Capabilities(cap);
+        if (c != null) {
+            props.add(c);
+        }
+        int act = sw.getActions();
+        Actions a = new Actions(act);
+        if (a != null) {
+            props.add(a);
+        }
+        int buffers = sw.getBuffers();
+        Buffers b = new Buffers(buffers);
+        if (b != null) {
+            props.add(b);
+        }
+        // Notify all internal and external listeners
+        notifyInventoryShimListener(node, type, props);
+    }
+
+    private void removeNode(ISwitch sw) {
+        Node node;
+        try {
+            node = new Node(NodeIDType.OPENFLOW, sw.getId());
+        } catch (ConstructionException e) {
+            logger.error("{}", e.getMessage());
+            return;
+        }
+
+        UpdateType type = UpdateType.REMOVED;
+
+        // Notify all internal and external listeners
+        notifyInventoryShimListener(node, type, null);
+    }
+
+    private void startService() {
+        // Get a snapshot of all the existing switches
+        Map<Long, ISwitch> switches = this.controller.getSwitches();
+        for (ISwitch sw : switches.values()) {
+            switchAdded(sw);
+        }
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java
new file mode 100644 (file)
index 0000000..cf9a2c5
--- /dev/null
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
+import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsServiceShimListener;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6StatsReply;
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6StatsRequest;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.statistics.OFAggregateStatisticsRequest;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.protocol.statistics.OFFlowStatisticsReply;
+import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
+import org.openflow.protocol.statistics.OFPortStatisticsReply;
+import org.openflow.protocol.statistics.OFPortStatisticsRequest;
+import org.openflow.protocol.statistics.OFQueueStatisticsRequest;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.protocol.statistics.OFVendorStatistics;
+import org.openflow.util.HexString;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * It periodically polls the different OF statistics from the OF switches and
+ * caches them for quick retrieval for the above layers' modules It also
+ * provides an API to directly query the switch about the statistics
+ */
+public class OFStatisticsManager implements IOFStatisticsManager,
+        IInventoryShimExternalListener, CommandProvider {
+    private static final Logger log = LoggerFactory
+            .getLogger(OFStatisticsManager.class);
+    private static final int initialSize = 64;
+    private static final long flowStatsPeriod = 10000;
+    private static final long descriptionStatsPeriod = 60000;
+    private static final long portStatsPeriod = 5000;
+    private static final long flowTableStatsPeriod = 60000;
+    private static final long tickPeriod = 1000;
+    private static short statisticsTickNumber = (short) (flowStatsPeriod / tickPeriod);
+    private static short descriptionTickNumber = (short) (descriptionStatsPeriod / tickPeriod);
+    private static short portTickNumber = (short) (portStatsPeriod / tickPeriod);
+    private static short flowTableTickNumber = (short) (flowTableStatsPeriod / tickPeriod);
+    private static short factoredSamples = (short) 2;
+    private static short counter = 1;
+    private IController controller = null;
+    private ConcurrentMap<Long, List<OFStatistics>> flowStatistics;
+    private ConcurrentMap<Long, List<OFStatistics>> descStatistics;
+    private ConcurrentMap<Long, List<OFStatistics>> portStatistics;
+    private ConcurrentMap<Long, List<OFStatistics>> flowTableStatistics;
+    private List<OFStatistics> dummyList;
+    private ConcurrentMap<Long, StatisticsTicks> statisticsTimerTicks;
+    protected BlockingQueue<StatsRequest> pendingStatsRequests;
+    protected BlockingQueue<Long> switchPortStatsUpdated;
+    private Thread statisticsCollector;
+    private Thread txRatesUpdater;
+    private Timer statisticsTimer;
+    private TimerTask statisticsTimerTask;
+    private ConcurrentMap<Long, Boolean> switchSupportsVendorExtStats;
+    private Map<Long, Map<Short, TxRates>> txRates; // Per port sampled (every
+                                                    // portStatsPeriod) transmit
+                                                    // rate
+    private Set<IStatisticsListener> descriptionListeners;
+    private ConcurrentMap<String, IStatisticsServiceShimListener> statisticsServiceShimListener;
+
+    /**
+     * The object containing the latest factoredSamples tx rate samples for a
+     * given switch port
+     */
+    protected class TxRates {
+        Deque<Long> sampledTxBytes; // contains the latest factoredSamples
+                                    // sampled transmitted bytes
+
+        public TxRates() {
+            sampledTxBytes = new LinkedBlockingDeque<Long>();
+        }
+
+        public void update(Long txBytes) {
+            /*
+             * Based on how many samples our average works on, we might have to
+             * remove the oldest sample
+             */
+            if (sampledTxBytes.size() == factoredSamples) {
+                sampledTxBytes.removeLast();
+            }
+
+            // Add the latest sample to the top of the queue
+            sampledTxBytes.addFirst(txBytes);
+        }
+
+        /**
+         * Returns the average transmit rate in bps
+         *
+         * @return the average transmit rate [bps]
+         */
+        public long getAverageTxRate() {
+            long average = 0;
+            /*
+             * If we cannot provide the value for the time window length set
+             */
+            if (sampledTxBytes.size() < factoredSamples) {
+                return average;
+            }
+            long increment = (long) (sampledTxBytes.getFirst() - sampledTxBytes
+                    .getLast());
+            long timePeriod = (long) (factoredSamples * portStatsPeriod)
+                    / (long) tickPeriod;
+            average = (8L * increment) / timePeriod;
+            return average;
+        }
+    }
+
+    public void setController(IController core) {
+        this.controller = core;
+    }
+
+    public void unsetController(IController core) {
+        if (this.controller == core) {
+            this.controller = null;
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        flowStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
+        descStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
+        portStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
+        flowTableStatistics = new ConcurrentHashMap<Long, List<OFStatistics>>();
+        dummyList = new ArrayList<OFStatistics>(1);
+        statisticsTimerTicks = new ConcurrentHashMap<Long, StatisticsTicks>(
+                initialSize);
+        pendingStatsRequests = new LinkedBlockingQueue<StatsRequest>(
+                initialSize);
+        switchPortStatsUpdated = new LinkedBlockingQueue<Long>(initialSize);
+        switchSupportsVendorExtStats = new ConcurrentHashMap<Long, Boolean>(
+                initialSize);
+        txRates = new HashMap<Long, Map<Short, TxRates>>(initialSize);
+        descriptionListeners = new HashSet<IStatisticsListener>();
+
+        statisticsServiceShimListener =
+                new ConcurrentHashMap<String, IStatisticsServiceShimListener>();
+        configStatsPollIntervals();
+
+        // Initialize managed timers
+        statisticsTimer = new Timer();
+        statisticsTimerTask = new TimerTask() {
+            @Override
+            public void run() {
+                decrementTicks();
+            }
+        };
+
+        // Initialize Statistics collector thread
+        statisticsCollector = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        StatsRequest req = pendingStatsRequests.take();
+                        acquireStatistics(req.switchId, req.type);
+                    } catch (InterruptedException e) {
+                        log.warn("Flow Statistics Collector thread "
+                                + "interrupted", e);
+                    }
+                }
+            }
+        }, "Statistics Collector");
+
+        // Initialize Tx Rate Updater thread
+        txRatesUpdater = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        long switchId = switchPortStatsUpdated.take();
+                        updatePortsTxRate(switchId);
+                    } catch (InterruptedException e) {
+                        log.warn("TX Rate Updater thread interrupted", e);
+                    }
+                }
+            }
+        }, "TX Rate Updater");
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        this.statisticsServiceShimListener = null;
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    void start() {
+        // Start managed timers
+        statisticsTimer.scheduleAtFixedRate(statisticsTimerTask, 0, tickPeriod);
+
+        // Start statistics collector thread
+        statisticsCollector.start();
+
+        // Start bandwidth utilization computer thread
+        txRatesUpdater.start();
+
+        // OSGI console
+        registerWithOSGIConsole();
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    void stop() {
+        // Stop managed timers
+        statisticsTimer.cancel();
+    }
+
+    public void setStatisticsListener(IStatisticsListener s) {
+        this.descriptionListeners.add(s);
+    }
+
+    public void unsetStatisticsListener(IStatisticsListener s) {
+        if (s != null) {
+            this.descriptionListeners.remove(s);
+        }
+    }
+
+    private void registerWithOSGIConsole() {
+        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+        bundleContext.registerService(CommandProvider.class.getName(), this,
+                null);
+    }
+
+    private static class StatsRequest {
+        protected Long switchId;
+        protected OFStatisticsType type;
+
+        public StatsRequest(Long d, OFStatisticsType t) {
+            switchId = d;
+            type = t;
+        }
+
+        public String toString() {
+            return "SReq = {switchId=" + switchId + ", type=" + type + "}";
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result
+                    + ((switchId == null) ? 0 : switchId.hashCode());
+            result = prime * result + ((type == null) ? 0 : type.ordinal());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            StatsRequest other = (StatsRequest) obj;
+            if (switchId == null) {
+                if (other.switchId != null) {
+                    return false;
+                }
+            } else if (!switchId.equals(other.switchId)) {
+                return false;
+            }
+            if (type != other.type) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    public void setStatisticsServiceShimListener(Map<?, ?> props,
+            IStatisticsServiceShimListener s) {
+        if (props == null) {
+            log.error("Didn't receive the service properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            log.error("containerName not supplied");
+            return;
+        }
+        if ((this.statisticsServiceShimListener != null)
+                && !this.statisticsServiceShimListener.containsValue(s)) {
+            this.statisticsServiceShimListener.put(containerName, s);
+            log.trace("Added inventoryShimInternalListener for container:"
+                    + containerName);
+        }
+
+    }
+
+    public void unsetStatisticsServiceShimListener(Map<?, ?> props,
+            IStatisticsServiceShimListener s) {
+        if (props == null) {
+            log.error("Didn't receive the service properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            log.error("containerName not supplied");
+            return;
+        }
+        if ((this.statisticsServiceShimListener != null)
+                && this.statisticsServiceShimListener
+                    .get(containerName) != null
+                && this.statisticsServiceShimListener
+                    .get(containerName).equals(s)) {
+            this.statisticsServiceShimListener.remove(containerName);
+            log.trace("Removed inventoryShimInternalListener for container: "
+                            + containerName);
+        }
+    }
+
+
+    private void addStatisticsTicks(Long switchId) {
+        // Start of Change
+
+        // By default, ODL assumes that switch supports Vendor statistics.
+        // It is designed in such a way that if the switch doesn't support Vendor Stats,
+        // then "Flow Stats" would be acquired.
+
+        // Behavior is overridden NOT to assume default support for Vendor Stats
+
+        //switchSupportsVendorExtStats.put(switchId, Boolean.TRUE); // Assume switch supports Vendor extension stats
+        switchSupportsVendorExtStats.put(switchId, Boolean.FALSE);
+
+        // End of Change
+
+        statisticsTimerTicks.put(switchId, new StatisticsTicks(true));
+        log.info("Added Switch {} to target pool",
+                HexString.toHexString(switchId.longValue()));
+    }
+
+    protected static class StatisticsTicks {
+        private short flowStatisticsTicks;
+        private short descriptionTicks;
+        private short portStatisticsTicks;
+        private short flowTableStatisticsTicks;
+
+        public StatisticsTicks(boolean scattered) {
+            if (scattered) {
+                // scatter bursts by statisticsTickPeriod
+                if (++counter < 0) {
+                    counter = 0;
+                } // being paranoid here
+                flowStatisticsTicks = (short) (1 + counter
+                        % statisticsTickNumber);
+                descriptionTicks = (short) (1 + counter % descriptionTickNumber);
+                portStatisticsTicks = (short) (1 + counter % portTickNumber);
+                flowTableStatisticsTicks = (short) (1 + counter % flowTableTickNumber);
+            } else {
+                flowStatisticsTicks = statisticsTickNumber;
+                descriptionTicks = descriptionTickNumber;
+                portStatisticsTicks = portTickNumber;
+                flowTableStatisticsTicks = flowTableTickNumber;
+            }
+        }
+
+        public boolean decrementFlowTicksIsZero() {
+            // Please ensure no code is inserted between the if check and the
+            // flowStatisticsTicks reset
+            if (--flowStatisticsTicks == 0) {
+                flowStatisticsTicks = statisticsTickNumber;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean decrementDescTicksIsZero() {
+            // Please ensure no code is inserted between the if check and the
+            // descriptionTicks reset
+            if (--descriptionTicks == 0) {
+                descriptionTicks = descriptionTickNumber;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean decrementPortTicksIsZero() {
+            // Please ensure no code is inserted between the if check and the
+            // descriptionTicks reset
+            if (--portStatisticsTicks == 0) {
+                portStatisticsTicks = portTickNumber;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean decrementFlowTableTicksIsZero() {
+            // Please ensure no code is inserted between the if check and the descriptionTicks reset
+            if (--flowTableStatisticsTicks == 0) {
+                flowTableStatisticsTicks = flowTableTickNumber;
+                return true;
+            }
+            return false;
+        }
+
+        public String toString() {
+            return "{fT=" + flowStatisticsTicks + ",dT=" + descriptionTicks
+                    + ",pT=" + portStatisticsTicks + ",tT=" + flowTableStatisticsTicks + "}";
+        }
+    }
+
+    private void printInfoMessage(String type, StatsRequest request) {
+        log.info(
+                "{} stats request not inserted for switch: {}. Queue size: {}. Collector state: {}.",
+                new Object[] { type, HexString.toHexString(request.switchId),
+                        pendingStatsRequests.size(),
+                        statisticsCollector.getState().toString() });
+    }
+
+    protected void decrementTicks() {
+        StatsRequest request = null;
+        for (Map.Entry<Long, StatisticsTicks> entry : statisticsTimerTicks
+                .entrySet()) {
+            StatisticsTicks clock = entry.getValue();
+            Long switchId = entry.getKey();
+            if (clock.decrementFlowTicksIsZero() == true) {
+                request = (switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) ? new StatsRequest(
+                        switchId, OFStatisticsType.VENDOR) : new StatsRequest(
+                        switchId, OFStatisticsType.FLOW);
+                // If a request for this switch is already in the queue, skip to
+                // add this new request
+                if (!pendingStatsRequests.contains(request)
+                        && false == pendingStatsRequests.offer(request)) {
+                    printInfoMessage("Flow", request);
+                }
+            }
+
+            if (clock.decrementDescTicksIsZero() == true) {
+                request = new StatsRequest(switchId, OFStatisticsType.DESC);
+                // If a request for this switch is already in the queue, skip to
+                // add this new request
+                if (!pendingStatsRequests.contains(request)
+                        && false == pendingStatsRequests.offer(request)) {
+                    printInfoMessage("Description", request);
+                }
+            }
+
+            if (clock.decrementPortTicksIsZero() == true) {
+                request = new StatsRequest(switchId, OFStatisticsType.PORT);
+                // If a request for this switch is already in the queue, skip to
+                // add this new request
+                if (!pendingStatsRequests.contains(request)
+                        && false == pendingStatsRequests.offer(request)) {
+                    printInfoMessage("Port", request);
+                }
+            }
+
+            if (clock.decrementFlowTableTicksIsZero() == true) {
+                request = new StatsRequest(switchId, OFStatisticsType.TABLE);
+                // If a request for this switch is already in the queue, skip to add this new request
+                if (!pendingStatsRequests.contains(request)
+                        && false == pendingStatsRequests.offer(request)) {
+                    printInfoMessage("Flow Table", request);
+                }
+            }
+        }
+    }
+
+    private void removeStatsRequestTasks(Long switchId) {
+        log.info("Cleaning Statistics database for switch {}",
+                HexEncode.longToHexString(switchId));
+        // To be safe, let's attempt removal of both VENDOR and FLOW request. It
+        // does not hurt
+        pendingStatsRequests.remove(new StatsRequest(switchId,
+                OFStatisticsType.VENDOR));
+        pendingStatsRequests.remove(new StatsRequest(switchId,
+                OFStatisticsType.FLOW));
+        pendingStatsRequests.remove(new StatsRequest(switchId,
+                OFStatisticsType.DESC));
+        pendingStatsRequests.remove(new StatsRequest(switchId,
+                OFStatisticsType.PORT));
+        pendingStatsRequests.remove(new StatsRequest(switchId,
+                OFStatisticsType.TABLE));
+        // Take care of the TX rate databases
+        switchPortStatsUpdated.remove(switchId);
+        txRates.remove(switchId);
+    }
+
+    private void clearFlowStatsAndTicks(Long switchId) {
+        statisticsTimerTicks.remove(switchId);
+        removeStatsRequestTasks(switchId);
+        flowStatistics.remove(switchId);
+        log.info("Statistics removed for switch {}",
+                HexString.toHexString(switchId));
+    }
+
+    private void acquireStatistics(Long switchId, OFStatisticsType statType) {
+
+        // Query the switch on all matches
+        List<OFStatistics> values = this.acquireStatistics(switchId, statType,
+                null);
+
+        String containerName = GlobalConstants.DEFAULT.toString();
+
+        // Update local caching database if got a valid response
+        if (values != null && !values.isEmpty()) {
+            if ((statType == OFStatisticsType.FLOW)
+                    || (statType == OFStatisticsType.VENDOR)) {
+                flowStatistics.put(switchId, values);
+
+                notifyStatisticsListener(containerName, statType, switchId, values);
+
+            } else if (statType == OFStatisticsType.DESC) {
+                // Notify who may be interested in a description change
+                   notifyDescriptionListeners(switchId, values);
+
+                // Overwrite cache
+                descStatistics.put(switchId, values);
+
+                notifyStatisticsListener(containerName, statType, switchId, values);
+            } else if (statType == OFStatisticsType.PORT) {
+                // Overwrite cache with new port statistics for this switch
+                portStatistics.put(switchId, values);
+
+                // Wake up the thread which maintains the TX byte counters for
+                // each port
+                switchPortStatsUpdated.offer(switchId);
+
+                notifyStatisticsListener(containerName, statType, switchId, values);
+            } else if (statType == OFStatisticsType.TABLE) {
+
+                // Overwrite cache
+                   flowTableStatistics.put(switchId, values);
+
+                notifyStatisticsListener(containerName, statType, switchId, values);
+            }
+        }
+    }
+
+    private void notifyStatisticsListener(String containerName, OFStatisticsType type, Long switchId, List<OFStatistics> values){
+
+        IStatisticsServiceShimListener statisticsServiceShimListener =
+                                            this.statisticsServiceShimListener.get(containerName);
+
+        if (statisticsServiceShimListener != null) {
+
+            switch (type) {
+             case FLOW:
+                 statisticsServiceShimListener.
+                                     flowStatisticsUpdate(switchId, values, containerName);
+                 break;
+             case PORT:
+                 statisticsServiceShimListener.
+                                     portStatisticsUpdate(switchId, values, containerName);
+                 break;
+             case DESC:
+                 statisticsServiceShimListener.
+                                     descStatisticsUpdate(switchId, values, containerName);
+                 break;
+             case TABLE:
+                 statisticsServiceShimListener.
+                                     flowTableStatisticsUpdate(switchId, values, containerName);
+                 break;
+             default:
+                 break;
+            }
+
+            log.trace(type + " " + switchId + " on container "
+                                            + containerName);
+        }
+    }
+
+    private void notifyDescriptionListeners(Long switchId,
+            List<OFStatistics> values) {
+        for (IStatisticsListener l : this.descriptionListeners) {
+            l.descriptionRefreshed(switchId,
+                    ((OFDescriptionStatistics) values.get(0)));
+        }
+    }
+
+    /*
+     * Generic function to get the statistics form a OF switch
+     */
+    @SuppressWarnings("unchecked")
+    private List<OFStatistics> acquireStatistics(Long switchId,
+            OFStatisticsType statsType, Object target) {
+        List<OFStatistics> values = null;
+        String type = null;
+        ISwitch sw = controller.getSwitch(switchId);
+
+        if (sw != null) {
+            OFStatisticsRequest req = new OFStatisticsRequest();
+            req.setStatisticType(statsType);
+            int requestLength = req.getLengthU();
+
+            if (statsType == OFStatisticsType.FLOW) {
+                OFMatch match = null;
+                if (target == null) {
+                    // All flows request
+                    match = new OFMatch();
+                    match.setWildcards(0xffffffff);
+                } else if (!(target instanceof OFMatch)) {
+                    // Malformed request
+                    log.warn("Invalid target type for Flow stats request: {}",
+                            target.getClass());
+                    return null;
+                } else {
+                    // Specific flow request
+                    match = (OFMatch) target;
+                }
+                OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest();
+                specificReq.setMatch(match);
+                specificReq.setOutPort(OFPort.OFPP_NONE.getValue());
+                specificReq.setTableId((byte) 0xff);
+                req.setStatistics(Collections
+                        .singletonList((OFStatistics) specificReq));
+                requestLength += specificReq.getLength();
+                type = "FLOW";
+            } else if (statsType == OFStatisticsType.VENDOR) {
+                V6StatsRequest specificReq = new V6StatsRequest();
+                specificReq.setOutPort(OFPort.OFPP_NONE.getValue());
+                specificReq.setTableId((byte) 0xff);
+                req.setStatistics(Collections
+                        .singletonList((OFStatistics) specificReq));
+                requestLength += specificReq.getLength();
+                type = "VENDOR";
+            } else if (statsType == OFStatisticsType.AGGREGATE) {
+                OFAggregateStatisticsRequest specificReq = new OFAggregateStatisticsRequest();
+                OFMatch match = new OFMatch();
+                match.setWildcards(0xffffffff);
+                specificReq.setMatch(match);
+                specificReq.setOutPort(OFPort.OFPP_NONE.getValue());
+                specificReq.setTableId((byte) 0xff);
+                req.setStatistics(Collections
+                        .singletonList((OFStatistics) specificReq));
+                requestLength += specificReq.getLength();
+                type = "AGGREGATE";
+            } else if (statsType == OFStatisticsType.PORT) {
+                short targetPort;
+                if (target == null) {
+                    // All ports request
+                    targetPort = (short) OFPort.OFPP_NONE.getValue();
+                } else if (!(target instanceof Short)) {
+                    // Malformed request
+                    log.warn("Invalid target type for Port stats request: {}",
+                            target.getClass());
+                    return null;
+                } else {
+                    // Specific port request
+                    targetPort = (Short) target;
+                }
+                OFPortStatisticsRequest specificReq = new OFPortStatisticsRequest();
+                specificReq.setPortNumber(targetPort);
+                req.setStatistics(Collections
+                        .singletonList((OFStatistics) specificReq));
+                requestLength += specificReq.getLength();
+                type = "PORT";
+            } else if (statsType == OFStatisticsType.QUEUE) {
+                OFQueueStatisticsRequest specificReq = new OFQueueStatisticsRequest();
+                specificReq.setPortNumber((short) OFPort.OFPP_ALL.getValue());
+                specificReq.setQueueId(0xffffffff);
+                req.setStatistics(Collections
+                        .singletonList((OFStatistics) specificReq));
+                requestLength += specificReq.getLength();
+                type = "QUEUE";
+            } else if (statsType == OFStatisticsType.DESC) {
+                type = "DESC";
+            } else if (statsType == OFStatisticsType.TABLE) {
+                type = "TABLE";
+            }
+            req.setLengthU(requestLength);
+            Object result = sw.getStatistics(req);
+
+            if (result == null) {
+                log.warn("Request Timed Out for ({}) from switch {}", type,
+                        HexString.toHexString(switchId));
+            } else if (result instanceof OFError) {
+                log.warn("Switch {} failed to handle ({}) stats request: {}",
+                        new Object[] { HexString.toHexString(switchId), type,
+                                Utils.getOFErrorString((OFError) result) });
+                if (this.switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) {
+                    log.warn(
+                            "Switching back to regular Flow stats requests for switch {}",
+                            HexString.toHexString(switchId));
+                    this.switchSupportsVendorExtStats.put(switchId,
+                            Boolean.FALSE);
+                }
+            } else {
+                values = (List<OFStatistics>) result;
+            }
+        }
+        return values;
+    }
+
+    @Override
+    public List<OFStatistics> getOFFlowStatistics(Long switchId) {
+        List<OFStatistics> list = flowStatistics.get(switchId);
+
+        /*
+         * Check on emptiness as interference between add and get is still
+         * possible on the inner list (the concurrentMap entry's value)
+         */
+
+        return list;
+
+        /*
+        return (list == null || list.isEmpty()) ? this.dummyList
+                : (list.get(0) instanceof OFVendorStatistics) ? this
+                        .v6StatsListToOFStatsList(list) : list;
+                        */
+    }
+
+    @Override
+    public List<OFStatistics> getOFFlowStatistics(Long switchId, OFMatch ofMatch) {
+        List<OFStatistics> statsList = flowStatistics.get(switchId);
+
+        /*
+         * Check on emptiness as interference between add and get is still
+         * possible on the inner list (the concurrentMap entry's value)
+         */
+        if (statsList == null || statsList.isEmpty()) {
+            return this.dummyList;
+        }
+
+        if (statsList.get(0) instanceof OFVendorStatistics) {
+            /*
+             * Caller could provide regular OF match when we instead pull the
+             * vendor statistics from this node Caller is not supposed to know
+             * whether this switch supports vendor extensions statistics
+             * requests
+             */
+            /*
+            V6Match targetMatch = (ofMatch instanceof V6Match) ? (V6Match) ofMatch
+                    : new V6Match(ofMatch);
+
+            List<OFStatistics> targetList = v6StatsListToOFStatsList(statsList);
+            for (OFStatistics stats : targetList) {
+                V6StatsReply v6Stats = (V6StatsReply) stats;
+                V6Match v6Match = v6Stats.getMatch();
+                if (v6Match.equals(targetMatch)) {
+                    List<OFStatistics> list = new ArrayList<OFStatistics>();
+                    list.add(stats);
+                    return list;
+                }
+            }
+            */
+        } else {
+            for (OFStatistics stats : statsList) {
+                OFFlowStatisticsReply flowStats = (OFFlowStatisticsReply) stats;
+                if (flowStats.getMatch().equals(ofMatch)) {
+                    List<OFStatistics> list = new ArrayList<OFStatistics>();
+                    list.add(stats);
+                    return list;
+                }
+            }
+        }
+        return this.dummyList;
+    }
+
+    /*
+     * Converts the v6 vendor statistics to the OFStatistics
+     */
+    /*
+    private List<OFStatistics> v6StatsListToOFStatsList(
+            List<OFStatistics> statistics) {
+        List<OFStatistics> v6statistics = new ArrayList<OFStatistics>();
+        if (statistics != null && !statistics.isEmpty()) {
+            for (OFStatistics stats : statistics) {
+                if (stats instanceof OFVendorStatistics) {
+                    List<OFStatistics> r = getV6ReplyStatistics((OFVendorStatistics) stats);
+                    if (r != null) {
+                        v6statistics.addAll(r);
+                    }
+                }
+            }
+        }
+        return v6statistics;
+    }
+    */
+
+    /*
+
+    private static List<OFStatistics> getV6ReplyStatistics(
+            OFVendorStatistics stat) {
+        int length = stat.getLength();
+        List<OFStatistics> results = new ArrayList<OFStatistics>();
+        if (length < 12)
+            return null; // Nicira Hdr is 12 bytes. We need atleast that much
+        ByteBuffer data = ByteBuffer.allocate(length);
+        stat.writeTo(data);
+        data.rewind();
+        log.trace("getV6ReplyStatistics: Buffer BYTES ARE {}",
+                HexString.toHexString(data.array()));
+
+        int vendor = data.getInt(); // first 4 bytes is vendor id.
+        if (vendor != V6StatsRequest.NICIRA_VENDOR_ID) {
+            log.warn("Unexpected vendor id: 0x{}", Integer.toHexString(vendor));
+            return null;
+        } else {
+            // go ahead by 8 bytes which is 8 bytes of 0
+            data.getLong(); // should be all 0's
+            length -= 12; // 4 bytes Nicira Hdr + 8 bytes from above line have
+                          // been consumed
+        }
+
+        V6StatsReply v6statsreply;
+        int min_len;
+        while (length > 0) {
+            v6statsreply = new V6StatsReply();
+            min_len = v6statsreply.getLength();
+            if (length < v6statsreply.getLength())
+                break;
+            v6statsreply.setActionFactory(stat.getActionFactory());
+            v6statsreply.readFrom(data);
+            if (v6statsreply.getLength() < min_len)
+                break;
+            v6statsreply.setVendorId(vendor);
+            log.trace("V6StatsReply: {}", v6statsreply);
+            length -= v6statsreply.getLength();
+            results.add(v6statsreply);
+        }
+        return results;
+    }
+    */
+
+    @Override
+    public List<OFStatistics> queryStatistics(Long switchId,
+            OFStatisticsType statType, Object target) {
+        /*
+         * Caller does not know and it is not supposed to know whether this
+         * switch supports vendor extension. We adjust the target for him
+         */
+        if (statType == OFStatisticsType.FLOW) {
+            if (switchSupportsVendorExtStats.get(switchId) == Boolean.TRUE) {
+                statType = OFStatisticsType.VENDOR;
+            }
+        }
+
+        List<OFStatistics> list = this.acquireStatistics(switchId, statType,
+                target);
+
+        return list;
+
+        /*
+        return (list == null) ? null
+                : (statType == OFStatisticsType.VENDOR) ? v6StatsListToOFStatsList(list)
+                        : list;
+                        */
+    }
+
+    @Override
+    public List<OFStatistics> getOFDescStatistics(Long switchId) {
+        if (!descStatistics.containsKey(switchId))
+            return this.dummyList;
+
+        return descStatistics.get(switchId);
+    }
+
+    @Override
+    public List<OFStatistics> getOFPortStatistics(Long switchId) {
+        if (!portStatistics.containsKey(switchId)) {
+            return this.dummyList;
+        }
+
+        return portStatistics.get(switchId);
+    }
+
+    @Override
+    public List<OFStatistics> getOFPortStatistics(Long switchId, short portId) {
+        if (!portStatistics.containsKey(switchId)) {
+            return this.dummyList;
+        }
+        List<OFStatistics> list = new ArrayList<OFStatistics>(1);
+        for (OFStatistics stats : portStatistics.get(switchId)) {
+            if (((OFPortStatisticsReply) stats).getPortNumber() == portId) {
+                list.add(stats);
+                break;
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public List<OFStatistics> getOFTableStatistics(Long switchId) {
+        if (!flowTableStatistics.containsKey(switchId))
+            return this.dummyList;
+
+        return flowTableStatistics.get(switchId);
+    }
+
+    @Override
+    public int getFlowsNumber(long switchId) {
+        return this.flowStatistics.get(switchId).size();
+    }
+
+    /*
+     * InventoryShim replay for us all the switch addition which happened before
+     * we were brought up
+     */
+    @Override
+    public void updateNode(Node node, UpdateType type, Set<Property> props) {
+        Long switchId = (Long) node.getID();
+        switch (type) {
+        case ADDED:
+            addStatisticsTicks(switchId);
+            break;
+        case REMOVED:
+            clearFlowStatsAndTicks(switchId);
+        default:
+        }
+    }
+
+    @Override
+    public void updateNodeConnector(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props) {
+        // No action
+    }
+
+    /**
+     * Update the cached port rates for this switch with the latest retrieved
+     * port transmit byte count
+     *
+     * @param switchId
+     */
+    private synchronized void updatePortsTxRate(long switchId) {
+        List<OFStatistics> newPortStatistics = this.portStatistics
+                .get(switchId);
+        if (newPortStatistics == null) {
+            return;
+        }
+        Map<Short, TxRates> rates = this.txRates.get(switchId);
+        if (rates == null) {
+            // First time rates for this switch are added
+            rates = new HashMap<Short, TxRates>();
+            txRates.put(switchId, rates);
+        }
+        for (OFStatistics stats : newPortStatistics) {
+            OFPortStatisticsReply newPortStat = (OFPortStatisticsReply) stats;
+            short port = newPortStat.getPortNumber();
+            TxRates portRatesHolder = rates.get(port);
+            if (portRatesHolder == null) {
+                // First time rates for this port are added
+                portRatesHolder = new TxRates();
+                rates.put(port, portRatesHolder);
+            }
+            // Get and store the number of transmitted bytes for this port
+            // And handle the case where agent does not support the counter
+            long transmitBytes = newPortStat.getTransmitBytes();
+            long value = (transmitBytes < 0) ? 0 : transmitBytes;
+            portRatesHolder.update(value);
+        }
+    }
+
+    @Override
+    public synchronized long getTransmitRate(Long switchId, Short port) {
+        long average = 0;
+        if (switchId == null || port == null) {
+            return average;
+        }
+        Map<Short, TxRates> perSwitch = txRates.get(switchId);
+        if (perSwitch == null) {
+            return average;
+        }
+        TxRates portRates = perSwitch.get(port);
+        if (portRates == null) {
+            return average;
+        }
+        return portRates.getAverageTxRate();
+    }
+
+    /*
+     * Manual switch name configuration code
+     */
+    @Override
+    public String getHelp() {
+        StringBuffer help = new StringBuffer();
+        help.append("---OF Statistics Manager utilities---\n");
+        help.append("\t ofdumpstatsmgr         - "
+                + "Print Internal Stats Mgr db\n");
+        help.append("\t ofstatsmgrintervals <fP> <pP> <dP> <tP>(in seconds) - "
+                + "Set/Show flow/port/dedscription/table stats poll intervals\n");
+        return help.toString();
+    }
+
+    private boolean isValidSwitchId(String switchId) {
+        String regexDatapathID = "^([0-9a-fA-F]{1,2}[:-]){7}[0-9a-fA-F]{1,2}$";
+        String regexDatapathIDLong = "^[0-9a-fA-F]{1,16}$";
+
+        return (switchId != null && (switchId.matches(regexDatapathID) || switchId
+                .matches(regexDatapathIDLong)));
+    }
+
+    public long getSwitchIDLong(String switchId) {
+        int radix = 16;
+        String switchString = "0";
+
+        if (isValidSwitchId(switchId)) {
+            if (switchId.contains(":")) {
+                // Handle the 00:00:AA:BB:CC:DD:EE:FF notation
+                switchString = switchId.replace(":", "");
+            } else if (switchId.contains("-")) {
+                // Handle the 00-00-AA-BB-CC-DD-EE-FF notation
+                switchString = switchId.replace("-", "");
+            } else {
+                // Handle the 0123456789ABCDEF notation
+                switchString = switchId;
+            }
+        }
+        return Long.parseLong(switchString, radix);
+    }
+
+    /*
+     * Internal information dump code
+     */
+    private String prettyPrintSwitchMap(ConcurrentMap<Long, StatisticsTicks> map) {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("{");
+        for (Entry<Long, StatisticsTicks> entry : map.entrySet()) {
+            buffer.append(HexString.toHexString(entry.getKey()) + "="
+                    + entry.getValue().toString() + " ");
+        }
+        buffer.append("}");
+        return buffer.toString();
+    }
+
+    public void _ofdumpstatsmgr(CommandInterpreter ci) {
+        ci.println("Global Counter: " + counter);
+        ci.println("Timer Ticks: " + prettyPrintSwitchMap(statisticsTimerTicks));
+        ci.println("PendingStatsQueue: " + pendingStatsRequests);
+        ci.println("PendingStatsQueue size: " + pendingStatsRequests.size());
+        ci.println("Stats Collector alive: " + statisticsCollector.isAlive());
+        ci.println("Stats Collector State: "
+                + statisticsCollector.getState().toString());
+        ci.println("StatsTimer: " + statisticsTimer.toString());
+        ci.println("Flow Stats Period: " + statisticsTickNumber + " s");
+        ci.println("Desc Stats Period: " + descriptionTickNumber + " s");
+        ci.println("Port Stats Period: " + portTickNumber + " s");
+        ci.println("Flow Table Stats Period: " + flowTableTickNumber + " s");
+    }
+
+    public void _resetSwitchCapability(CommandInterpreter ci) {
+        String sidString = ci.nextArgument();
+        Long sid = null;
+        if (sidString == null) {
+            ci.println("Insert the switch id (numeric value)");
+            return;
+        }
+        try {
+            sid = Long.valueOf(sidString);
+            this.switchSupportsVendorExtStats.put(sid, Boolean.TRUE);
+            ci.println("Vendor capability for switch " + sid + " set to "
+                    + this.switchSupportsVendorExtStats.get(sid));
+        } catch (NumberFormatException e) {
+            ci.println("Invalid switch id. Has to be numeric.");
+        }
+
+    }
+
+    public void _ofbw(CommandInterpreter ci) {
+        String sidString = ci.nextArgument();
+        Long sid = null;
+        if (sidString == null) {
+            ci.println("Insert the switch id (numeric value)");
+            return;
+        }
+        try {
+            sid = Long.valueOf(sidString);
+        } catch (NumberFormatException e) {
+            ci.println("Invalid switch id. Has to be numeric.");
+        }
+        if (sid != null) {
+            Map<Short, TxRates> thisSwitchRates = txRates.get(sid);
+            ci.println("Bandwidth utilization (" + factoredSamples
+                    * portTickNumber + " sec average) for switch "
+                    + HexEncode.longToHexString(sid) + ":");
+            if (thisSwitchRates == null) {
+                ci.println("Not available");
+            } else {
+                for (Entry<Short, TxRates> entry : thisSwitchRates.entrySet()) {
+                    ci.println("Port: " + entry.getKey() + ": "
+                            + entry.getValue().getAverageTxRate() + " bps");
+                }
+            }
+        }
+    }
+
+    public void _txratewindow(CommandInterpreter ci) {
+        String averageWindow = ci.nextArgument();
+        short seconds = 0;
+        if (averageWindow == null) {
+            ci.println("Insert the length in seconds of the median "
+                    + "window for tx rate");
+            ci.println("Current: " + factoredSamples * portTickNumber + " secs");
+            return;
+        }
+        try {
+            seconds = Short.valueOf(averageWindow);
+        } catch (NumberFormatException e) {
+            ci.println("Invalid period.");
+        }
+        OFStatisticsManager.factoredSamples = (short) (seconds / portTickNumber);
+        ci.println("New: " + factoredSamples * portTickNumber + " secs");
+    }
+
+    public void _ofstatsmgrintervals(CommandInterpreter ci) {
+        String flowStatsInterv = ci.nextArgument();
+        String portStatsInterv = ci.nextArgument();
+        String descStatsInterv = ci.nextArgument();
+        String flowTableStatsInterv = ci.nextArgument();
+
+        if (flowStatsInterv == null || portStatsInterv == null
+                || descStatsInterv == null || flowTableStatsInterv == null) {
+            ci.println("Usage: ostatsmgrintervals <fP> <pP> <dP> <tP>(in seconds)");
+            ci.println("Current Values: fP=" + statisticsTickNumber + "s pP="
+                    + portTickNumber + "s dP=" + descriptionTickNumber +
+                    "s tP=" + flowTableTickNumber + "s");
+            return;
+        }
+        Short fP, pP, dP, tP;
+        try {
+            fP = Short.parseShort(flowStatsInterv);
+            pP = Short.parseShort(portStatsInterv);
+            dP = Short.parseShort(descStatsInterv);
+            tP = Short.parseShort(flowTableStatsInterv);
+        } catch (Exception e) {
+            ci.println("Invalid format values: " + e.getMessage());
+            return;
+        }
+
+        if (pP <= 1 || fP <= 1 || dP <= 1 || tP <= 1) {
+            ci.println("Invalid values. fP, pP, dP, tP have to be greater than 1.");
+            return;
+        }
+
+        statisticsTickNumber = fP;
+        portTickNumber = pP;
+        descriptionTickNumber = dP;
+        flowTableTickNumber = tP;
+
+
+        ci.println("New Values: fP=" + statisticsTickNumber + "s pP="
+                + portTickNumber + "s dP=" + descriptionTickNumber +
+                "s tP=" + flowTableTickNumber + "s");
+    }
+
+    /**
+     * This method retrieves user configurations from config.ini and updates
+     * statisticsTickNumber/portTickNumber/descriptionTickNumber/flowTableTickNumber accordingly.
+     */
+    private void configStatsPollIntervals() {
+        String fsStr = System.getProperty("of.flowStatsPollInterval");
+        String psStr = System.getProperty("of.portStatsPollInterval");
+        String dsStr = System.getProperty("of.descStatsPollInterval");
+        String tsStr = System.getProperty("of.flowTableStatsPollInterval");
+        Short fs, ps, ds, ts;
+
+        if (fsStr != null) {
+            try {
+                fs = Short.parseShort(fsStr);
+                if (fs > 0) {
+                    statisticsTickNumber = fs;
+                }
+            } catch (Exception e) {
+            }
+        }
+
+        if (psStr != null) {
+            try {
+                ps = Short.parseShort(psStr);
+                if (ps > 0) {
+                    portTickNumber = ps;
+                }
+            } catch (Exception e) {
+            }
+        }
+
+        if (dsStr != null) {
+            try {
+                ds = Short.parseShort(dsStr);
+                if (ds > 0) {
+                    descriptionTickNumber = ds;
+                }
+            } catch (Exception e) {
+            }
+        }
+        if (tsStr != null) {
+            try {
+                ts = Short.parseShort(dsStr);
+                if (ts > 0) {
+                    flowTableTickNumber = ts;
+                }
+            } catch (Exception e) {
+            }
+        }
+
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortConverter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortConverter.java
new file mode 100644 (file)
index 0000000..0b605ab
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.openflow.protocol.OFPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class which provides the utilities for converting the Openflow port
+ * number to the equivalent NodeConnector and vice versa
+ *
+ *
+ *
+ */
+public abstract class PortConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(PortConverter.class);
+    private static final int maxOFPhysicalPort = NetUtils
+            .getUnsignedShort(OFPort.OFPP_MAX.getValue());
+
+    /**
+     * Converts the Openflow port number to the equivalent NodeConnector.
+     */
+    public static NodeConnector toNodeConnector(short ofPort, Node node) {
+        // Restore original OF unsigned 16 bits value for the comparison
+        int unsignedOFPort = NetUtils.getUnsignedShort(ofPort);
+        log.trace("Openflow port number signed: {} unsigned: {}", ofPort,
+                unsignedOFPort);
+        if (unsignedOFPort > maxOFPhysicalPort) {
+            if (ofPort == OFPort.OFPP_LOCAL.getValue()) {
+                return NodeConnectorCreator.createNodeConnector(
+                        NodeConnectorIDType.SWSTACK,
+                        NodeConnector.SPECIALNODECONNECTORID, node);
+            } else if (ofPort == OFPort.OFPP_NORMAL.getValue()) {
+                return NodeConnectorCreator.createNodeConnector(
+                        NodeConnectorIDType.HWPATH,
+                        NodeConnector.SPECIALNODECONNECTORID, node);
+            } else if (ofPort == OFPort.OFPP_CONTROLLER.getValue()) {
+                return NodeConnectorCreator.createNodeConnector(
+                        NodeConnectorIDType.CONTROLLER,
+                        NodeConnector.SPECIALNODECONNECTORID, node);
+            }
+        }
+        return NodeConnectorCreator.createNodeConnector(ofPort, node);
+    }
+
+    /**
+     * Converts the NodeConnector to the equivalent Openflow port number
+     */
+    public static short toOFPort(NodeConnector salPort) {
+        log.trace("SAL Port", salPort);
+        if (salPort.getType().equals(NodeConnectorIDType.SWSTACK)) {
+            return OFPort.OFPP_LOCAL.getValue();
+        } else if (salPort.getType().equals(NodeConnectorIDType.HWPATH)) {
+            return OFPort.OFPP_NORMAL.getValue();
+        } else if (salPort.getType().equals(NodeConnectorIDType.CONTROLLER)) {
+            return OFPort.OFPP_CONTROLLER.getValue();
+        }
+        return (Short) salPort.getID();
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortStatisticsConverter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/PortStatisticsConverter.java
new file mode 100644 (file)
index 0000000..b18eae9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.openflow.protocol.statistics.OFPortStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Converts an openflow list of port statistics in a SAL list of
+ * NodeConnectorStatistics objects
+ *
+ *
+ *
+ */
+public class PortStatisticsConverter {
+    private static final Logger log = LoggerFactory
+            .getLogger(PortStatisticsConverter.class);
+    private long switchId;
+    private List<OFStatistics> ofStatsList;
+    private List<NodeConnectorStatistics> ncStatsList;
+
+    public PortStatisticsConverter(long switchId, List<OFStatistics> statsList) {
+        this.switchId = switchId;
+        if (statsList == null || statsList.isEmpty()) {
+            this.ofStatsList = new ArrayList<OFStatistics>(1); // dummy list
+        } else {
+            this.ofStatsList = new ArrayList<OFStatistics>(statsList);
+        }
+        this.ncStatsList = null;
+    }
+
+    public List<NodeConnectorStatistics> getNodeConnectorStatsList() {
+        if (this.ofStatsList != null && this.ncStatsList == null) {
+            this.ncStatsList = new ArrayList<NodeConnectorStatistics>();
+            OFPortStatisticsReply ofPortStat;
+            Node node = NodeCreator.createOFNode(switchId);
+            for (OFStatistics ofStat : this.ofStatsList) {
+                ofPortStat = (OFPortStatisticsReply) ofStat;
+                NodeConnectorStatistics NCStat = new NodeConnectorStatistics();
+                NCStat.setNodeConnector(PortConverter.toNodeConnector(
+                        ofPortStat.getPortNumber(), node));
+                NCStat.setReceivePacketCount(ofPortStat.getreceivePackets());
+                NCStat.setTransmitPacketCount(ofPortStat.getTransmitPackets());
+                NCStat.setReceiveByteCount(ofPortStat.getReceiveBytes());
+                NCStat.setTransmitByteCount(ofPortStat.getTransmitBytes());
+                NCStat.setReceiveDropCount(ofPortStat.getReceiveDropped());
+                NCStat.setTransmitDropCount(ofPortStat.getTransmitDropped());
+                NCStat.setReceiveErrorCount(ofPortStat.getreceiveErrors());
+                NCStat.setTransmitErrorCount(ofPortStat.getTransmitErrors());
+                NCStat.setReceiveFrameErrorCount(ofPortStat
+                        .getReceiveFrameErrors());
+                NCStat.setReceiveOverRunErrorCount(ofPortStat
+                        .getReceiveOverrunErrors());
+                NCStat.setReceiveCRCErrorCount(ofPortStat.getReceiveCRCErrors());
+                NCStat.setCollisionCount(ofPortStat.getCollisions());
+                this.ncStatsList.add(NCStat);
+            }
+        }
+        log.trace("OFStatistics: {} NodeConnectorStatistics: {}", ofStatsList,
+                ncStatsList);
+        return this.ncStatsList;
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadService.java
new file mode 100644 (file)
index 0000000..9ff3d21
--- /dev/null
@@ -0,0 +1,149 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.protocol_plugin.openflow.IPluginReadServiceFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.reader.IPluginInReadService;
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
+
+/**
+ * Container Instance of IPluginInReadService implementation class
+ *
+ *
+ *
+ */
+public class ReadService implements IPluginInReadService {
+    private static final Logger logger = LoggerFactory
+            .getLogger(ReadService.class);
+    private IPluginReadServiceFilter filter;
+    private String containerName;
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    @SuppressWarnings("unchecked")
+    void init(Component c) {
+        Dictionary<Object, Object> props = c.getServiceProperties();
+        containerName = (props != null) ? (String) props.get("containerName")
+                : null;
+    }
+
+    /**
+     * Function called by the dependency manager when at least one
+     * dependency become unsatisfied or when the component is shutting
+     * down because for example bundle is being stopped.
+     *
+     */
+    void destroy() {
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called
+     * and after the services provided by the class are registered in
+     * the service registry
+     *
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services
+     * exported by the component are unregistered, this will be
+     * followed by a "destroy ()" calls
+     *
+     */
+    void stop() {
+    }
+
+    public void setService(IPluginReadServiceFilter filter) {
+        this.filter = filter;
+    }
+
+    public void unsetService(IPluginReadServiceFilter filter) {
+        this.filter = null;
+    }
+
+    @Override
+    public FlowOnNode readFlow(Node node, Flow flow, boolean cached) {
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return null;
+        }
+
+        return filter.readFlow(containerName, node, flow, cached);
+    }
+
+    @Override
+    public List<FlowOnNode> readAllFlow(Node node, boolean cached) {
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return null;
+        }
+
+        return filter.readAllFlow(containerName, node, cached);
+    }
+
+    @Override
+    public NodeDescription readDescription(Node node, boolean cached) {
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return null;
+        }
+
+        return filter.readDescription(node, cached);
+    }
+
+    @Override
+    public NodeConnectorStatistics readNodeConnector(NodeConnector connector,
+            boolean cached) {
+        if (!connector.getNode().getType()
+            .equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return null;
+        }
+        return filter.readNodeConnector(containerName, connector, cached);
+    }
+
+    @Override
+    public List<NodeConnectorStatistics> readAllNodeConnector(Node node,
+            boolean cached) {
+        if (!node.getType().equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return null;
+        }
+
+        return filter.readAllNodeConnector(containerName, node, cached);
+    }
+
+    @Override
+    public long getTransmitRate(NodeConnector connector) {
+        if (!connector.getNode().getType()
+            .equals(NodeIDType.OPENFLOW)) {
+            logger.error("Invalid node type");
+            return 0;
+        }
+        return filter.getTransmitRate(containerName, connector);
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java
new file mode 100644 (file)
index 0000000..73c703e
--- /dev/null
@@ -0,0 +1,421 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
+import org.opendaylight.controller.protocol_plugin.openflow.IPluginReadServiceFilter;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.statistics.OFPortStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.ActionType;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+
+/**
+ * Read Service shim layer which is in charge of filtering the flow statistics
+ * based on container. It is a Global instance.
+ *
+ *
+ *
+ */
+public class ReadServiceFilter implements IPluginReadServiceFilter,
+        IContainerListener {
+    private static final Logger logger = LoggerFactory
+            .getLogger(ReadServiceFilter.class);
+    private IController controller = null;
+    private IOFStatisticsManager statsMgr = null;
+    private Map<String, Set<NodeConnector>> containerToNc;
+
+    public void setController(IController core) {
+        this.controller = core;
+    }
+
+    public void unsetController(IController core) {
+        if (this.controller == core) {
+            this.controller = null;
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        containerToNc = new HashMap<String, Set<NodeConnector>>();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one
+     * dependency become unsatisfied or when the component is shutting
+     * down because for example bundle is being stopped.
+     *
+     */
+    void destroy() {
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called
+     * and after the services provided by the class are registered in
+     * the service registry
+     *
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services
+     * exported by the component are unregistered, this will be
+     * followed by a "destroy ()" calls
+     *
+     */
+    void stop() {
+    }
+
+    public void setService(IOFStatisticsManager service) {
+        this.statsMgr = service;
+    }
+
+    public void unsetService(IOFStatisticsManager service) {
+        this.statsMgr = null;
+    }
+
+    @Override
+    public FlowOnNode readFlow(String container, Node node, Flow flow,
+            boolean cached) {
+
+        if (controller == null) {
+            // Avoid to provide cached statistics if controller went down.
+            // They are not valid anymore anyway
+            logger.error("Internal plugin error");
+            return null;
+        }
+
+        long sid = (Long) node.getID();
+        OFMatch ofMatch = new FlowConverter(flow).getOFMatch();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFFlowStatistics(sid, ofMatch) : statsMgr.queryStatistics(
+                sid, OFStatisticsType.FLOW, ofMatch);
+
+        /*
+         * Convert and filter the statistics per container
+         */
+        List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
+                .getFlowOnNodeList(node);
+        List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
+                node, flowOnNodeList);
+
+        return (filteredList == null || filteredList.isEmpty()) ? null
+                : filteredList.get(0);
+    }
+
+    @Override
+    public List<FlowOnNode> readAllFlow(String container, Node node,
+            boolean cached) {
+
+        long sid = (Long) node.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid,
+                OFStatisticsType.FLOW, null);
+
+        /*
+         * Convert and filter the statistics per container
+         */
+        List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
+                .getFlowOnNodeList(node);
+        List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
+                node, flowOnNodeList);
+
+        return (filteredList == null) ? null : filteredList;
+
+    }
+
+    @Override
+    public NodeDescription readDescription(Node node, boolean cached) {
+
+        if (controller == null) {
+            logger.error("Internal plugin error");
+            return null;
+        }
+
+        long sid = (Long) node.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
+                OFStatisticsType.DESC, null);
+
+        return new DescStatisticsConverter(ofList).getHwDescription();
+    }
+
+    /**
+     * Filters a list of FlowOnNode elements based on the container
+     *
+     * @param container
+     * @param nodeId
+     * @param list
+     * @return
+     */
+    public List<FlowOnNode> filterFlowListPerContainer(String container,
+            Node nodeId, List<FlowOnNode> list) {
+        if (list == null) {
+            return null;
+        }
+
+        // Create new filtered list of flows
+        List<FlowOnNode> newList = new ArrayList<FlowOnNode>();
+
+        for (FlowOnNode target : list) {
+            // Check whether the described flow (match + actions) belongs to this container
+            if (flowBelongToContainer(container, nodeId, target.getFlow())) {
+                newList.add(target);
+            }
+        }
+
+        return newList;
+    }
+
+    /**
+     * Filters a list of FlowOnNode elements based on the container
+     *
+     * @param container
+     * @param nodeId
+     * @param list
+     * @return
+     */
+    public List<OFStatistics> filterPortListPerContainer(String container,
+            long switchId, List<OFStatistics> list) {
+        if (list == null) {
+            return null;
+        }
+
+        // Create new filtered list of flows
+        List<OFStatistics> newList = new ArrayList<OFStatistics>();
+
+        for (OFStatistics stat : list) {
+            OFPortStatisticsReply target = (OFPortStatisticsReply) stat;
+            NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(
+                    target.getPortNumber(), NodeCreator.createOFNode(switchId));
+            if (containerOwnsNodeConnector(container, nc)) {
+                newList.add(target);
+            }
+        }
+
+        return newList;
+    }
+
+    /**
+     * Returns whether the specified flow (flow match + actions)
+     * belongs to the container
+     *
+     * @param container
+     * @param node
+     * @param flow
+     * @return true if it belongs
+     */
+    public boolean flowBelongToContainer(String container, Node node, Flow flow) {
+        // All flows belong to the default container
+        if (container.equals(GlobalConstants.DEFAULT.toString())) {
+            return true;
+        }
+        return (flowPortsBelongToContainer(container, node, flow)
+                && flowVlanBelongsToContainer(container, node, flow) && flowSpecAllowsFlow(
+                container, flow.getMatch()));
+    }
+
+    /**
+     * Returns whether the passed NodeConnector belongs to the container
+     *
+     * @param container    container name
+     * @param p        node connector to test
+     * @return         true if belongs false otherwise
+     */
+    public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
+        // All node connectors belong to the default container
+        if (container.equals(GlobalConstants.DEFAULT.toString())) {
+            return true;
+        }
+        Set<NodeConnector> portSet = containerToNc.get(container);
+        return (portSet == null) ? false : portSet.contains(p);
+    }
+
+    /**
+     * Returns whether the container flowspec allows the passed flow
+     *
+     * @param container
+     * @param match
+     * @return
+     */
+    private boolean flowSpecAllowsFlow(String container, Match match) {
+        return true; // Always true for now
+    }
+
+    /**
+     * Check whether the vlan field in the flow match is the same
+     * of the static vlan configured for the container
+     *
+     * @param container
+     * @param node
+     * @param flow
+     * @return
+     */
+    private boolean flowVlanBelongsToContainer(String container, Node node,
+            Flow flow) {
+        return true; // Always true for now
+    }
+
+    /**
+     * Check whether the ports in the flow match and flow actions for
+     * the specified node belong to the container
+     *
+     * @param container
+     * @param node
+     * @param flow
+     * @return
+     */
+    private boolean flowPortsBelongToContainer(String container, Node node,
+            Flow flow) {
+        Match m = flow.getMatch();
+        if (m.isPresent(MatchType.IN_PORT)) {
+            NodeConnector inPort = (NodeConnector) m
+                    .getField(MatchType.IN_PORT).getValue();
+
+            // If the incoming port is specified, check if it belongs to
+            if (!containerOwnsNodeConnector(container, inPort)) {
+                return false;
+            }
+        }
+
+        // If an outgoing port is specified, it must belong to this container
+        for (Action action : flow.getActions()) {
+            if (action.getType() == ActionType.OUTPUT) {
+                NodeConnector outPort = (NodeConnector) ((Output) action)
+                        .getPort();
+                if (!containerOwnsNodeConnector(container, outPort)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void containerFlowUpdated(String containerName,
+            ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
+
+    }
+
+    @Override
+    public void nodeConnectorUpdated(String containerName, NodeConnector p,
+            UpdateType type) {
+        Set<NodeConnector> target = null;
+
+        switch (type) {
+        case ADDED:
+            if (!containerToNc.containsKey(containerName)) {
+                containerToNc.put(containerName, new HashSet<NodeConnector>());
+            }
+            containerToNc.get(containerName).add(p);
+            break;
+        case CHANGED:
+            break;
+        case REMOVED:
+            target = containerToNc.get(containerName);
+            if (target != null) {
+                target.remove(p);
+            }
+            break;
+        default:
+        }
+    }
+
+    @Override
+    public void tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+        // Not interested in this event
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+        // do nothing
+    }
+
+    @Override
+    public NodeConnectorStatistics readNodeConnector(String containerName,
+            NodeConnector connector, boolean cached) {
+        if (!containerOwnsNodeConnector(containerName, connector)) {
+            return null;
+        }
+        Node node = connector.getNode();
+        long sid = (Long) node.getID();
+        short portId = (Short) connector.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
+                sid, OFStatisticsType.PORT, portId);
+
+        List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(
+                sid, ofList).getNodeConnectorStatsList();
+        return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics()
+                : ncStatistics.get(0);
+    }
+
+    @Override
+    public List<NodeConnectorStatistics> readAllNodeConnector(
+            String containerName, Node node, boolean cached) {
+
+        long sid = (Long) node.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
+                OFStatisticsType.FLOW, null);
+
+        List<OFStatistics> filteredList = filterPortListPerContainer(
+                containerName, sid, ofList);
+
+        return new PortStatisticsConverter(sid, filteredList)
+                .getNodeConnectorStatsList();
+    }
+
+    @Override
+    public long getTransmitRate(String containerName, NodeConnector connector) {
+        if (!containerOwnsNodeConnector(containerName, connector)) {
+            return 0;
+        }
+
+        long switchId = (Long) connector.getNode().getID();
+        short port = (Short) connector.getID();
+
+        return statsMgr.getTransmitRate(switchId, port);
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java
new file mode 100644 (file)
index 0000000..e80f2ae
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
+import org.opendaylight.controller.protocol_plugin.openflow.IRefreshInternalProvider;
+import org.opendaylight.controller.protocol_plugin.openflow.ITopologyServiceShimListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.core.Bandwidth;
+import org.opendaylight.controller.sal.core.Config;
+import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.Edge;
+import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.State;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.discovery.IDiscoveryService;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+
+/**
+ * The class describes a shim layer that relays the topology events from
+ * OpenFlow core to various listeners. The notifications are filtered based on
+ * container configurations.
+ */
+public class TopologyServiceShim implements IDiscoveryService,
+        IContainerListener, CommandProvider, IRefreshInternalProvider,
+        IInventoryShimExternalListener {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(TopologyServiceShim.class);
+    private ConcurrentMap<String, ITopologyServiceShimListener> topologyServiceShimListeners = new ConcurrentHashMap<String, ITopologyServiceShimListener>();
+    private ConcurrentMap<NodeConnector, List<String>> containerMap = new ConcurrentHashMap<NodeConnector, List<String>>();
+    private ConcurrentMap<String, ConcurrentMap<NodeConnector, Pair<Edge, Set<Property>>>> edgeMap = new ConcurrentHashMap<String, ConcurrentMap<NodeConnector, Pair<Edge, Set<Property>>>>();
+
+    private BlockingQueue<NotifyEntry> notifyQ;
+    private Thread notifyThread;
+    private BlockingQueue<String> bulkNotifyQ;
+    private Thread ofPluginTopoBulkUpdate;
+    private volatile Boolean shuttingDown = false;
+    private IOFStatisticsManager statsMgr;
+    private Timer pollTimer;
+    private TimerTask txRatePoller;
+    private Thread bwUtilNotifyThread;
+    private BlockingQueue<UtilizationUpdate> bwUtilNotifyQ;
+    private List<NodeConnector> connectorsOverUtilized;
+    private float bwThresholdFactor = (float) 0.8; // Threshold = 80% of link
+                                                   // bandwidth
+
+    class NotifyEntry {
+        String container;
+        Pair<Edge, Set<Property>> edgeProps;
+        UpdateType type;
+
+        NotifyEntry(String container, Pair<Edge, Set<Property>> edgeProps,
+                UpdateType type) {
+            this.container = container;
+            this.edgeProps = edgeProps;
+            this.type = type;
+        }
+    }
+
+    class TopologyNotify implements Runnable {
+        private final BlockingQueue<NotifyEntry> notifyQ;
+
+        TopologyNotify(BlockingQueue<NotifyEntry> notifyQ) {
+            this.notifyQ = notifyQ;
+        }
+
+        public void run() {
+            while (true) {
+                try {
+                    NotifyEntry entry = notifyQ.take();
+
+                    ITopologyServiceShimListener topologServiceShimListener = topologyServiceShimListeners
+                            .get(entry.container);
+                    topologServiceShimListener.edgeUpdate(
+                            entry.edgeProps.getLeft(), entry.type,
+                            entry.edgeProps.getRight());
+
+                    entry = null;
+                } catch (InterruptedException e1) {
+                    logger.warn("TopologyNotify interrupted {}", e1.getMessage());
+                    if (shuttingDown) {
+                        return;
+                    }
+                } catch (Exception e2) {
+                    logger.error("",e2);
+                }
+            }
+        }
+    }
+
+    class UtilizationUpdate {
+        NodeConnector connector;
+        UpdateType type;
+
+        UtilizationUpdate(NodeConnector connector, UpdateType type) {
+            this.connector = connector;
+            this.type = type;
+        }
+    }
+
+    class BwUtilizationNotify implements Runnable {
+        private final BlockingQueue<UtilizationUpdate> notifyQ;
+
+        BwUtilizationNotify(BlockingQueue<UtilizationUpdate> notifyQ) {
+            this.notifyQ = notifyQ;
+        }
+
+        public void run() {
+            while (true) {
+                try {
+                    UtilizationUpdate update = notifyQ.take();
+                    NodeConnector connector = update.connector;
+                    Set<String> containerList = edgeMap.keySet();
+                    for (String container : containerList) {
+                        Map<NodeConnector, Pair<Edge, Set<Property>>> edgePropsMap = edgeMap
+                                .get(container);
+                        Edge edge = edgePropsMap.get(connector).getLeft();
+                        if (edge.getTailNodeConnector().equals(connector)) {
+                            ITopologyServiceShimListener topologServiceShimListener = topologyServiceShimListeners
+                                    .get(container);
+                            if (update.type == UpdateType.ADDED) {
+                                topologServiceShimListener
+                                        .edgeOverUtilized(edge);
+                            } else {
+                                topologServiceShimListener
+                                        .edgeUtilBackToNormal(edge);
+                            }
+                        }
+                    }
+                } catch (InterruptedException e1) {
+                    logger.warn(
+                            "Edge Bandwidth Utilization Notify Thread interrupted {}",
+                            e1.getMessage());
+                    if (shuttingDown) {
+                        return;
+                    }
+                } catch (Exception e2) {
+                    logger.error("",e2);
+                }
+            }
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        logger.trace("Init called");
+        connectorsOverUtilized = new ArrayList<NodeConnector>();
+        notifyQ = new LinkedBlockingQueue<NotifyEntry>();
+        notifyThread = new Thread(new TopologyNotify(notifyQ));
+        bwUtilNotifyQ = new LinkedBlockingQueue<UtilizationUpdate>();
+        bwUtilNotifyThread = new Thread(new BwUtilizationNotify(bwUtilNotifyQ));
+        bulkNotifyQ = new LinkedBlockingQueue<String>();
+        ofPluginTopoBulkUpdate = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        String containerName = bulkNotifyQ.take();
+                        logger.debug("Bulk Notify container:{}", containerName);
+                        TopologyBulkUpdate(containerName);
+                    } catch (InterruptedException e) {
+                        logger.warn("Topology Bulk update thread interrupted");
+                        if (shuttingDown) {
+                            return;
+                        }
+                    }
+                }
+            }
+        }, "Topology Bulk Update");
+
+        // Initialize node connector tx bit rate poller timer
+        pollTimer = new Timer();
+        txRatePoller = new TimerTask() {
+            @Override
+            public void run() {
+                pollTxBitRates();
+            }
+        };
+
+        registerWithOSGIConsole();
+    }
+
+    /**
+     * Continuously polls the transmit bit rate for all the node connectors from
+     * statistics manager and trigger the warning notification upward when the
+     * transmit rate is above a threshold which is a percentage of the edge
+     * bandwidth
+     */
+    protected void pollTxBitRates() {
+        Map<NodeConnector, Pair<Edge, Set<Property>>> globalContainerEdges = edgeMap
+                .get(GlobalConstants.DEFAULT.toString());
+        if (globalContainerEdges == null) {
+            return;
+        }
+
+        for (NodeConnector connector : globalContainerEdges.keySet()) {
+            // Skip if node connector belongs to production switch
+            if (connector.getType().equals(
+                    NodeConnector.NodeConnectorIDType.PRODUCTION)) {
+                continue;
+            }
+
+            // Get edge for which this node connector is head
+            Pair<Edge, Set<Property>> props = this.edgeMap.get(
+                    GlobalConstants.DEFAULT.toString()).get(connector);
+            // On switch mgr restart the props get reset
+            if (props == null) {
+                continue;
+            }
+            Set<Property> propSet = props.getRight();
+            if (propSet == null) {
+                continue;
+            }
+
+            float bw = 0;
+            for (Property prop : propSet) {
+                if (prop instanceof Bandwidth) {
+                    bw = ((Bandwidth) prop).getValue();
+                    break;
+                }
+            }
+
+            // Skip if agent did not provide a bandwidth info for the edge
+            if (bw == 0) {
+                continue;
+            }
+
+            // Compare bandwidth usage
+            Long switchId = (Long) connector.getNode().getID();
+            Short port = (Short) connector.getID();
+            float rate = statsMgr.getTransmitRate(switchId, port);
+            if (rate > bwThresholdFactor * bw) {
+                if (!connectorsOverUtilized.contains(connector)) {
+                    connectorsOverUtilized.add(connector);
+                    this.bwUtilNotifyQ.add(new UtilizationUpdate(connector,
+                            UpdateType.ADDED));
+                }
+            } else {
+                if (connectorsOverUtilized.contains(connector)) {
+                    connectorsOverUtilized.remove(connector);
+                    this.bwUtilNotifyQ.add(new UtilizationUpdate(connector,
+                            UpdateType.REMOVED));
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        logger.trace("DESTROY called!");
+        notifyQ = null;
+        notifyThread = null;
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    void start() {
+        logger.trace("START called!");
+        notifyThread.start();
+        bwUtilNotifyThread.start();
+        ofPluginTopoBulkUpdate.start();
+        pollTimer.scheduleAtFixedRate(txRatePoller, 10000, 5000);
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    void stop() {
+        logger.trace("STOP called!");
+        shuttingDown = true;
+        notifyThread.interrupt();
+    }
+
+    void setTopologyServiceShimListener(Map<?, ?> props,
+            ITopologyServiceShimListener s) {
+        if (props == null) {
+            logger.error("Didn't receive the service properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            logger.error("containerName not supplied");
+            return;
+        }
+        if ((this.topologyServiceShimListeners != null)
+                && !this.topologyServiceShimListeners
+                        .containsKey(containerName)) {
+            this.topologyServiceShimListeners.put(containerName, s);
+            logger.trace("Added topologyServiceShimListener for container: {}",
+                    containerName);
+        }
+    }
+
+    void unsetTopologyServiceShimListener(Map<?, ?> props,
+            ITopologyServiceShimListener s) {
+        if (props == null) {
+            logger.error("Didn't receive the service properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (containerName == null) {
+            logger.error("containerName not supplied");
+            return;
+        }
+        if ((this.topologyServiceShimListeners != null)
+                && this.topologyServiceShimListeners.containsKey(containerName)
+                && this.topologyServiceShimListeners.get(containerName).equals(
+                        s)) {
+            this.topologyServiceShimListeners.remove(containerName);
+            logger.trace("Removed topologyServiceShimListener for container: {}",
+                    containerName);
+        }
+    }
+
+    void setStatisticsManager(IOFStatisticsManager s) {
+        this.statsMgr = s;
+    }
+
+    void unsetStatisticsManager(IOFStatisticsManager s) {
+        if (this.statsMgr == s) {
+            this.statsMgr = null;
+        }
+    }
+
+    private void removeNodeConnector(String container,
+            NodeConnector nodeConnector) {
+        Map<NodeConnector, Pair<Edge, Set<Property>>> edgePropsMap = edgeMap
+                .get(container);
+        if (edgePropsMap == null) {
+            return;
+        }
+
+        // Remove edge in one direction
+        Pair<Edge, Set<Property>> edgeProps = edgePropsMap.get(nodeConnector);
+        if (edgeProps == null) {
+            return;
+        }
+        notifyEdge(container, edgeProps.getLeft(), UpdateType.REMOVED, null);
+
+        // Remove edge in another direction
+        edgeProps = edgePropsMap
+                .get(edgeProps.getLeft().getHeadNodeConnector());
+        if (edgeProps == null) {
+            return;
+        }
+        notifyEdge(container, edgeProps.getLeft(), UpdateType.REMOVED, null);
+    }
+
+    private void notifyEdge(String container, Edge edge, UpdateType type,
+            Set<Property> props) {
+        ConcurrentMap<NodeConnector, Pair<Edge, Set<Property>>> edgePropsMap = edgeMap
+                .get(container);
+        NodeConnector src = edge.getTailNodeConnector();
+        Pair<Edge, Set<Property>> edgeProps = new ImmutablePair<Edge, Set<Property>>(
+                edge, props);
+
+        switch (type) {
+        case ADDED:
+        case CHANGED:
+            if (edgePropsMap == null) {
+                edgePropsMap = new ConcurrentHashMap<NodeConnector, Pair<Edge, Set<Property>>>();
+            } else {
+                if (edgePropsMap.containsKey(src)
+                        && edgePropsMap.get(src).equals(edgeProps)) {
+                    // Entry already exists. Return here.
+                    return;
+                }
+            }
+            edgePropsMap.put(src, edgeProps);
+            edgeMap.put(container, edgePropsMap);
+            break;
+        case REMOVED:
+            if (edgePropsMap != null) {
+                edgePropsMap.remove(src);
+                if (edgePropsMap.isEmpty()) {
+                    edgeMap.remove(container);
+                } else {
+                    edgeMap.put(container, edgePropsMap);
+                }
+            }
+            break;
+        default:
+            logger.debug("notifyEdge: invalid {} for Edge {} in container {}",
+                    type, edge, container);
+            return;
+        }
+
+        notifyQ.add(new NotifyEntry(container, edgeProps, type));
+
+        logger.debug("notifyEdge: {} Edge {} in container {}",
+                type, edge, container);
+    }
+
+    @Override
+    public void notifyEdge(Edge edge, UpdateType type, Set<Property> props) {
+        if ((edge == null) || (type == null)) {
+            return;
+        }
+
+        // Notify default container
+        notifyEdge(GlobalConstants.DEFAULT.toString(), edge, type, props);
+
+        // Notify the corresponding containers
+        List<String> containers = getEdgeContainers(edge);
+        if (containers != null) {
+            for (String container : containers) {
+                notifyEdge(container, edge, type, props);
+            }
+        }
+    }
+
+    /*
+     * Return a list of containers the edge associated with
+     */
+    private List<String> getEdgeContainers(Edge edge) {
+        NodeConnector src = edge.getTailNodeConnector(), dst = edge
+                .getHeadNodeConnector();
+
+        if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
+            /* Find the common containers for both ends */
+            List<String> srcContainers = this.containerMap.get(src), dstContainers = this.containerMap
+                    .get(dst), cmnContainers = null;
+            if ((srcContainers != null) && (dstContainers != null)) {
+                cmnContainers = new ArrayList<String>(srcContainers);
+                cmnContainers.retainAll(dstContainers);
+            }
+            return cmnContainers;
+        } else {
+            /*
+             * If the neighbor is part of a monitored production network, get
+             * the containers that the edge port belongs to
+             */
+            return this.containerMap.get(dst);
+        }
+    }
+
+    @Override
+    public void tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+    }
+
+    @Override
+    public void containerFlowUpdated(String containerName,
+            ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
+    }
+
+    @Override
+    public void nodeConnectorUpdated(String containerName, NodeConnector p,
+            UpdateType t) {
+        if (this.containerMap == null) {
+            logger.error("containerMap is NULL");
+            return;
+        }
+        List<String> containers = this.containerMap.get(p);
+        if (containers == null) {
+            containers = new CopyOnWriteArrayList<String>();
+        }
+        boolean updateMap = false;
+        switch (t) {
+        case ADDED:
+            if (!containers.contains(containerName)) {
+                containers.add(containerName);
+                updateMap = true;
+            }
+            break;
+        case REMOVED:
+            if (containers.contains(containerName)) {
+                containers.remove(containerName);
+                updateMap = true;
+                removeNodeConnector(containerName, p);
+            }
+            break;
+        case CHANGED:
+            break;
+        }
+        if (updateMap) {
+            if (containers.isEmpty()) {
+                // Do cleanup to reduce memory footprint if no
+                // elements to be tracked
+                this.containerMap.remove(p);
+            } else {
+                this.containerMap.put(p, containers);
+            }
+        }
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+        // do nothing
+    }
+
+    private void registerWithOSGIConsole() {
+        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
+                .getBundleContext();
+        bundleContext.registerService(CommandProvider.class.getName(), this,
+                null);
+    }
+
+    @Override
+    public String getHelp() {
+        StringBuffer help = new StringBuffer();
+        help.append("---Topology Service Shim---\n");
+        help.append("\t pem [container]               - Print edgeMap entries");
+        help.append(" for a given container\n");
+        return help.toString();
+    }
+
+    public void _pem(CommandInterpreter ci) {
+        String container = ci.nextArgument();
+        if (container == null) {
+            container = GlobalConstants.DEFAULT.toString();
+        }
+
+        ci.println("Container: " + container);
+        ci.println("                             Edge                                          Bandwidth");
+
+        Map<NodeConnector, Pair<Edge, Set<Property>>> edgePropsMap = edgeMap
+                .get(container);
+        if (edgePropsMap == null) {
+            return;
+        }
+        int count = 0;
+        for (Pair<Edge, Set<Property>> edgeProps : edgePropsMap.values()) {
+            if (edgeProps == null) {
+                continue;
+            }
+
+            long bw = 0;
+            for (Property prop : edgeProps.getRight()) {
+                if (prop.getName().equals(Bandwidth.BandwidthPropName)) {
+                    bw = ((Bandwidth) prop).getValue();
+                }
+            }
+            count++;
+            ci.println(edgeProps.getLeft() + "          " + bw);
+        }
+        ci.println("Total number of Edges: " + count);
+    }
+
+    public void _bwfactor(CommandInterpreter ci) {
+        String factorString = ci.nextArgument();
+        if (factorString == null) {
+            ci.println("Bw threshold: " + this.bwThresholdFactor);
+            ci.println("Insert a non null bw threshold");
+            return;
+        }
+        bwThresholdFactor = Float.parseFloat(factorString);
+        ci.println("New Bw threshold: " + this.bwThresholdFactor);
+    }
+
+    /**
+     * This method will trigger topology updates to be sent toward SAL. SAL then
+     * pushes the updates to ALL the applications that have registered as
+     * listeners for this service. SAL has no way of knowing which application
+     * requested for the refresh.
+     *
+     * As an example of this case, is stopping and starting the Topology
+     * Manager. When the topology Manager is stopped, and restarted, it will no
+     * longer have the latest topology. Hence, a request is sent here.
+     *
+     * @param containerName
+     * @return void
+     */
+    @Override
+    public void requestRefresh(String containerName) {
+        // wake up a bulk update thread and exit
+        // the thread will execute the bulkUpdate()
+        bulkNotifyQ.add(containerName);
+    }
+
+    /**
+     * Reading the current topology database, the method will replay all the
+     * edge updates for the ITopologyServiceShimListener instance in the given
+     * container, which will in turn publish them toward SAL.
+     *
+     * @param containerName
+     */
+    private void TopologyBulkUpdate(String containerName) {
+        Map<NodeConnector, Pair<Edge, Set<Property>>> edgePropMap = null;
+
+        logger.debug("Try bulk update for container:{}", containerName);
+        edgePropMap = edgeMap.get(containerName);
+        if (edgePropMap == null) {
+            logger.debug("No edges known for container:{}", containerName);
+            return;
+        }
+        ITopologyServiceShimListener topologServiceShimListener = topologyServiceShimListeners
+                .get(containerName);
+        if (topologServiceShimListener == null) {
+            logger.debug("No topology service shim listener for container:{}",
+                    containerName);
+            return;
+        }
+        int i = 0;
+        for (Pair<Edge, Set<Property>> edgeProps : edgePropMap.values()) {
+            if (edgeProps != null) {
+                i++;
+                logger.trace("Add edge {}", edgeProps.getLeft());
+                topologServiceShimListener.edgeUpdate(edgeProps.getLeft(),
+                        UpdateType.ADDED, edgeProps.getRight());
+            }
+        }
+        logger.debug("Sent {} updates", i);
+    }
+
+    @Override
+    public void updateNode(Node node, UpdateType type, Set<Property> props) {
+    }
+
+    @Override
+    public void updateNodeConnector(NodeConnector nodeConnector,
+            UpdateType type, Set<Property> props) {
+        List<String> containers = new ArrayList<String>();
+        List<String> conList = this.containerMap.get(nodeConnector);
+
+        containers.add(GlobalConstants.DEFAULT.toString());
+        if (conList != null) {
+            containers.addAll(conList);
+        }
+
+        switch (type) {
+        case ADDED:
+            break;
+        case CHANGED:
+            if (props == null) {
+                break;
+            }
+
+            boolean rmEdge = false;
+            for (Property prop : props) {
+                if (((prop instanceof Config) && (((Config) prop).getValue() != Config.ADMIN_UP))
+                        || ((prop instanceof State) && (((State) prop)
+                                .getValue() != State.EDGE_UP))) {
+                    /*
+                     * If port admin down or link down, remove the edges
+                     * associated with the port
+                     */
+                    rmEdge = true;
+                    break;
+                }
+            }
+
+            if (rmEdge) {
+                for (String cName : containers) {
+                    removeNodeConnector(cName, nodeConnector);
+                }
+            }
+            break;
+        case REMOVED:
+            for (String cName : containers) {
+                removeNodeConnector(cName, nodeConnector);
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServices.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServices.java
new file mode 100644 (file)
index 0000000..57b55bf
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.util.Dictionary;
+import java.util.Set;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.protocol_plugin.openflow.IRefreshInternalProvider;
+import org.opendaylight.controller.protocol_plugin.openflow.ITopologyServiceShimListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.core.Edge;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.topology.IPluginInTopologyService;
+import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
+
+public class TopologyServices implements ITopologyServiceShimListener,
+        IPluginInTopologyService {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(TopologyServices.class);
+    private IPluginOutTopologyService salTopoService = null;
+    private IRefreshInternalProvider topoRefreshService = null;
+    private String containerName;
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    @SuppressWarnings("unchecked")
+    void init(Component c) {
+        logger.trace("INIT called!");
+        Dictionary<Object, Object> props = c.getServiceProperties();
+        containerName = (props != null) ? (String) props.get("containerName")
+                : null;
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        logger.trace("DESTROY called!");
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     *
+     */
+    void start() {
+        logger.trace("START called!");
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     *
+     */
+    void stop() {
+        logger.trace("STOP called!");
+    }
+
+    /**
+     * Retrieve SAL service IPluginOutTopologyService
+     *
+     * @param s
+     *            Called by Dependency Manager as soon as the SAL service is
+     *            available
+     */
+    public void setPluginOutTopologyService(IPluginOutTopologyService s) {
+        logger.trace("Setting IPluginOutTopologyService to: {}", s);
+        this.salTopoService = s;
+    }
+
+    /**
+     * called when SAL service IPluginOutTopologyService is no longer available
+     *
+     * @param s
+     *            Called by Dependency Manager as soon as the SAL service is
+     *            unavailable
+     */
+    public void unsetPluginOutTopologyService(IPluginOutTopologyService s) {
+        if (this.salTopoService == s) {
+            logger.trace("UNSetting IPluginOutTopologyService from: {}", s);
+            this.salTopoService = null;
+        }
+    }
+
+    /**
+     * Retrieve OF protocol_plugin service IRefreshInternalProvider
+     *
+     * @param s
+     *            Called by Dependency Manager as soon as the SAL service is
+     *            available
+     */
+    public void setRefreshInternalProvider(IRefreshInternalProvider s) {
+        logger.trace("Setting IRefreshInternalProvider to: {}", s);
+        this.topoRefreshService = s;
+    }
+
+    /**
+     * called when OF protocol_plugin service IRefreshInternalProvider is no
+     * longer available
+     *
+     * @param s
+     *            Called by Dependency Manager as soon as the SAL service is
+     *            unavailable
+     */
+    public void unsetRefreshInternalProvider(IRefreshInternalProvider s) {
+        if (this.topoRefreshService == s) {
+            logger.trace("UNSetting IRefreshInternalProvider from: {}", s);
+            this.topoRefreshService = null;
+        }
+    }
+
+    @Override
+    public void edgeUpdate(Edge edge, UpdateType type, Set<Property> props) {
+        if (this.salTopoService != null) {
+            this.salTopoService.edgeUpdate(edge, type, props);
+        }
+    }
+
+    @Override
+    public void sollicitRefresh() {
+        logger.debug("Got a request to refresh topology");
+        topoRefreshService.requestRefresh(containerName);
+    }
+
+    @Override
+    public void edgeOverUtilized(Edge edge) {
+        if (this.salTopoService != null) {
+            this.salTopoService.edgeOverUtilized(edge);
+        }
+    }
+
+    @Override
+    public void edgeUtilBackToNormal(Edge edge) {
+        if (this.salTopoService != null) {
+            this.salTopoService.edgeUtilBackToNormal(edge);
+        }
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Utils.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Utils.java
new file mode 100644 (file)
index 0000000..52f501c
--- /dev/null
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.nio.ByteBuffer;
+
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFError.OFBadActionCode;
+import org.openflow.protocol.OFError.OFBadRequestCode;
+import org.openflow.protocol.OFError.OFErrorType;
+import org.openflow.protocol.OFError.OFFlowModFailedCode;
+import org.openflow.protocol.OFError.OFHelloFailedCode;
+import org.openflow.protocol.OFError.OFPortModFailedCode;
+import org.openflow.protocol.OFError.OFQueueOpFailedCode;
+
+public abstract class Utils {
+    public static String getOFErrorString(OFError error) {
+        // Handle VENDOR extension errors here
+
+        /*
+        if (error.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
+            V6Error er = new V6Error(error);
+            byte[] b = error.getError();
+            ByteBuffer bb = ByteBuffer.allocate(b.length);
+            bb.put(b);
+            bb.rewind();
+            er.readFrom(bb);
+            return er.toString();
+        }
+        */
+
+        // Handle OF1.0 errors here
+        OFErrorType et = OFErrorType.values()[0xffff & error.getErrorType()];
+        String errorStr = "Error : " + et.toString();
+        switch (et) {
+        case OFPET_HELLO_FAILED:
+            OFHelloFailedCode hfc = OFHelloFailedCode.values()[0xffff & error
+                    .getErrorCode()];
+            errorStr += " " + hfc.toString();
+            break;
+        case OFPET_BAD_REQUEST:
+            OFBadRequestCode brc = OFBadRequestCode.values()[0xffff & error
+                    .getErrorCode()];
+            errorStr += " " + brc.toString();
+            break;
+        case OFPET_BAD_ACTION:
+            OFBadActionCode bac = OFBadActionCode.values()[0xffff & error
+                    .getErrorCode()];
+            errorStr += " " + bac.toString();
+            break;
+        case OFPET_FLOW_MOD_FAILED:
+            OFFlowModFailedCode fmfc = OFFlowModFailedCode.values()[0xffff & error
+                    .getErrorCode()];
+            errorStr += " " + fmfc.toString();
+            break;
+        case OFPET_PORT_MOD_FAILED:
+            OFPortModFailedCode pmfc = OFPortModFailedCode.values()[0xffff & error
+                    .getErrorCode()];
+            errorStr += " " + pmfc.toString();
+            break;
+        case OFPET_QUEUE_OP_FAILED:
+            OFQueueOpFailedCode qofc = OFQueueOpFailedCode.values()[0xffff & error
+                    .getErrorCode()];
+            errorStr += " " + qofc.toString();
+            break;
+        default:
+            break;
+        }
+        return errorStr;
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Error.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Error.java
new file mode 100644 (file)
index 0000000..06be542
--- /dev/null
@@ -0,0 +1,90 @@
+package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension;
+
+import java.nio.ByteBuffer;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openflow.protocol.OFError;
+
+public class V6Error extends OFError {
+
+
+    private static final long serialVersionUID = 1L;
+    public static int MINIMUM_LENGTH = 20;//OfHdr(8) + NXET_VENDOR(2) + NXEC_VENDOR_ERROR(2) + struct nx_vendor_error(8)
+    public static final short NICIRA_VENDOR_ERRORTYPE = (short)0xb0c2;
+    protected int V6VendorId;
+    protected short V6VendorErrorType;
+    protected short V6VendorErrorCode;
+    protected byte[] V6ErrorData;
+
+    public V6Error(OFError e) {
+        this.length = (short)e.getLengthU();
+        this.errorType = e.getErrorType();
+        this.errorCode = e.getErrorCode();
+        this.xid = e.getXid();
+    }
+
+    /*
+    @Override
+    public void readFrom(ByteBuffer data) {
+        this.V6VendorId = data.getInt();
+        this.V6VendorErrorType = data.getShort();
+        this.V6VendorErrorCode = data.getShort();
+        int dataLength = this.getLengthU() - MINIMUM_LENGTH;
+        if (dataLength > 0) {
+            this.V6ErrorData = new byte[dataLength];
+            data.get(this.V6ErrorData);
+        }
+    }
+    */
+
+    /**
+     * @return the V6VendorId
+     */
+    public int getVendorId() {
+        return V6VendorId;
+    }
+
+
+
+    /**
+     * @return the V6VendorErrorType
+     */
+    /*
+    public short getVendorErrorType() {
+        return V6VendorErrorType;
+    }
+    */
+
+    /**
+     * @return the VendorErrorType
+     */
+    public short getVendorErrorCode() {
+        return V6VendorErrorCode;
+    }
+
+    /**
+     * @return the Error Bytes
+     */
+    public byte[] getError() {
+        return V6ErrorData;
+    }
+
+    @Override
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+
+    @Override
+    public String toString() {
+        return "V6Error[" + ReflectionToStringBuilder.toString(this) + "]";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java
new file mode 100644 (file)
index 0000000..513ac5e
--- /dev/null
@@ -0,0 +1,244 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFVendor;
+import org.openflow.protocol.action.OFAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to create IPv6 Vendor Extension messages. Specfically, It
+ * defines the methods used in creation of Vendor specific IPv6 Flow Mod message.
+ *
+ *
+ */
+public class V6FlowMod extends OFVendor implements Cloneable {
+    private static final Logger logger = LoggerFactory
+            .getLogger(V6FlowMod.class);
+    private static final long serialVersionUID = 1L;
+    protected V6Match match;
+    protected long cookie;
+    protected short command;
+    protected short idleTimeout;
+    protected short hardTimeout;
+    protected short priority;
+    protected int bufferId;
+    protected short outPort;
+    protected short flags;
+    protected List<OFAction> actions;
+    short match_len;
+    short actions_len;
+    short pad_size;
+
+    private static int IPV6EXT_ADD_FLOW_MSG_TYPE = 13;
+    private static int IPV6_EXT_MIN_HDR_LEN = 36;
+
+    /**
+     * Constructor for the V6FlowMod class. Initializes OFVendor (parent class)
+     * fields by calling the parent class' constructor.
+     */
+    public V6FlowMod() {
+        super();
+    }
+
+    /**
+     * This method sets the match fields of V6FlowMod object
+     * @param match        V6Match object for this V6FlowMod message
+     */
+    public void setMatch(V6Match match) {
+        this.match = match;
+    }
+
+    /**
+     * Sets the list of actions V6FlowMod message
+     * @param actions     a list of ordered OFAction objects
+     */
+    public void setActions(List<OFAction> actions) {
+        this.actions = actions;
+    }
+
+    /**
+     * Sets the priority field of V6FlowMod message
+     * @param priority     Priority of the message
+     */
+    public void setPriority(short priority) {
+        this.priority = priority;
+    }
+
+    /**
+     * Sets the cookie field of V6FlowMod message
+     * @param cookie     Cookie of the message
+     */
+    public void setCookie(long cookie) {
+        this.cookie = cookie;
+    }
+
+    /**
+     * Sets the command field of V6FlowMod message
+     * @param command     Command type of the message (ADD or DELETE)
+     */
+    public V6FlowMod setCommand(short command) {
+        this.command = command;
+        return this;
+    }
+
+    /**
+     * Sets the outPort field of V6FlowMod message
+     * @param outPort     outPort of the message
+     */
+    public V6FlowMod setOutPort(OFPort port) {
+        this.outPort = port.getValue();
+        return this;
+    }
+
+    /**
+     * Sets the idle_timeout of V6FlowMod message
+     * @param idleTimeout    idle timeout for this message
+     */
+    public void setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    /**
+     * Sets the hardTimeout field of V6FlowMod message
+     * @param hardTimeout     hard timeout of the message
+     */
+    public void setHardTimeout(short hardTimeout) {
+        this.hardTimeout = hardTimeout;
+    }
+
+    /**
+     * Returns the Flow Mod message subtype for V6FlowMod message
+     * @return            message subtype
+     */
+    private int getIPv6ExtensionFlowModAddSubType() {
+        return IPV6EXT_ADD_FLOW_MSG_TYPE;
+    }
+
+    /**
+     * Returns the minimum header size for V6Flow Message type
+     * @return        minimum header size
+     */
+
+    public int getV6FlowModMinHdrSize() {
+        return IPV6_EXT_MIN_HDR_LEN;
+    }
+
+    /**
+     * Sets the Vendor type in OFVendor message
+     */
+
+    public void setVendor() {
+        super.setVendor(V6StatsRequest.NICIRA_VENDOR_ID);
+    }
+
+    /**
+     * Get flags
+     * @return
+     */
+    public short getFlags() {
+        return flags;
+    }
+
+    /**
+     * Set flags
+     * @param flags
+     */
+    public void setFlags(short flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * This method forms the Vendor extension IPv6 Flow Mod message.It uses the
+     * fields in V6FlowMod class, and writes the data according to vendor
+     * extension format. The fields include flow properties (cookie, timeout,
+     * priority, etc), flow match, and action list. It also takes care of
+     * required padding.
+     */
+
+    /*
+    @Override
+    public void writeTo(ByteBuffer data) {
+        super.writeTo(data);
+        data.putInt(getIPv6ExtensionFlowModAddSubType());
+        data.putLong(this.cookie);
+        data.putShort(command); // should be OFPFC_ADD, OFPFC_DELETE_STRICT, etc
+        data.putShort(this.idleTimeout);
+        data.putShort(this.hardTimeout);
+        data.putShort(this.priority);
+        data.putInt(OFPacketOut.BUFFER_ID_NONE);
+        data.putShort(outPort); // output_port
+        data.putShort(flags); // flags
+        match_len = this.match.getIPv6MatchLen();
+        data.putShort(match_len);
+        byte[] pad = new byte[6];
+        data.put(pad);
+        this.match.writeTo(data);
+
+        pad_size = (short) (((match_len + 7) / 8) * 8 - match_len);
+
+        /*
+         * action list should be preceded by a padding of 0 to 7 bytes based upon
+         * above formula.
+         */
+
+    /*
+        byte[] pad2 = new byte[pad_size];
+        data.put(pad2);
+        if (actions != null) {
+            for (OFAction action : actions) {
+                actions_len += action.getLength();
+                action.writeTo(data);
+            }
+        }
+        logger.trace("{}", this.toString());
+    }
+    */
+
+
+    /**
+     * Forms the clone of V6FlowMod Object. If Object is returned
+     * successfully, then returns the cloned object. Throws an
+     * exception if cloning is not supported.
+     */
+    @Override
+    public V6FlowMod clone() {
+        try {
+            V6Match neoMatch = match.clone();
+            V6FlowMod v6flowMod = (V6FlowMod) super.clone();
+            v6flowMod.setMatch(neoMatch);
+            List<OFAction> neoActions = new LinkedList<OFAction>();
+            for (OFAction action : this.actions)
+                neoActions.add((OFAction) action.clone());
+            v6flowMod.setActions(neoActions);
+            return v6flowMod;
+        } catch (CloneNotSupportedException e) {
+            // Won't happen
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Prints the contents of V6FlowMod in a string format.
+     */
+    @Override
+    public String toString() {
+        return "V6FlowMod[" + ReflectionToStringBuilder.toString(this) + "]";
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java
new file mode 100644 (file)
index 0000000..bdad75f
--- /dev/null
@@ -0,0 +1,1355 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension;
+
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openflow.protocol.OFMatch;
+import org.openflow.util.U16;
+import org.openflow.util.U8;
+
+import java.net.Inet6Address;
+import org.opendaylight.controller.sal.utils.HexEncode;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This Class forms the vendor specific IPv6 Flow Match messages as well as
+ * processes the vendor specific IPv6 Stats Reply message.
+ *
+ * For message creation, it parses the user entered IPv6 match fields, creates
+ * a sub-message for each field which are later used to form the complete
+ * message.
+ *
+ * For message processing, it parses the incoming message and reads each field
+ * of the message and stores in appropriate field of V6Match object.
+ *
+ *
+ */
+public class V6Match extends OFMatch implements Cloneable {
+    private static final Logger logger = LoggerFactory.getLogger(V6Match.class);
+    private static final long serialVersionUID = 1L;
+    protected InetAddress nwSrc;
+    protected InetAddress nwDst;
+    protected short inputPortMask;
+    protected byte[] dataLayerSourceMask;
+    protected byte[] dataLayerDestinationMask;
+    protected short dataLayerVirtualLanMask;
+    protected byte dataLayerVirtualLanPriorityCodePointMask;
+    protected short dataLayerTypeMask;
+    protected byte networkTypeOfServiceMask;
+    protected byte networkProtocolMask;
+    protected InetAddress networkSourceMask;
+    protected InetAddress networkDestinationMask;
+    protected short transportSourceMask;
+    protected short transportDestinationMask;
+    protected short srcIPv6SubnetMaskbits;
+    protected short dstIPv6SubnetMaskbits;
+
+    protected MatchFieldState inputPortState;
+    protected MatchFieldState dlSourceState;
+    protected MatchFieldState dlDestState;
+    protected MatchFieldState dlVlanState;
+    protected MatchFieldState ethTypeState;
+    protected MatchFieldState nwTosState;
+    protected MatchFieldState nwProtoState;
+    protected MatchFieldState nwSrcState;
+    protected MatchFieldState nwDstState;
+    protected MatchFieldState tpSrcState;
+    protected MatchFieldState tpDstState;
+    protected short match_len = 0;
+    protected short pad_size = 0;
+
+    private static int IPV6_EXT_MIN_HDR_LEN = 36;
+
+    private enum MatchFieldState {
+        MATCH_ABSENT, MATCH_FIELD_ONLY, MATCH_FIELD_WITH_MASK
+    }
+
+    private enum OF_Match_Types {
+        MATCH_OF_IN_PORT(0), MATCH_OF_ETH_DST(1), MATCH_OF_ETH_SRC(2), MATCH_OF_ETH_TYPE(
+                3), MATCH_OF_VLAN_TCI(4), MATCH_OF_IP_TOS(5), MATCH_OF_IP_PROTO(
+                6), MATCH_OF_IP_SRC(7), MATCH_OF_IP_DST(8), MATCH_OF_TCP_SRC(9), MATCH_OF_TCP_DST(
+                10), MATCH_OF_UDP_SRC(11), MATCH_OF_UDP_DST(12), MATCH_OF_ICMTP_TYPE(
+                13), MATCH_OF_ICMP_CODE(14), MATCH_OF_ARP_OP(15);
+
+        private int value;
+
+        private OF_Match_Types(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return this.value;
+        }
+    }
+
+    private enum IPv6Extension_Match_Types {
+        MATCH_IPV6EXT_TUN_ID(16), MATCH_IPV6EXT_ARP_SHA(17), MATCH_IPV6EXT_ARP_THA(
+                18), MATCH_IPV6EXT_IPV6_SRC(19), MATCH_IPV6EXT_IPV6_DST(20);
+
+        private int value;
+
+        private IPv6Extension_Match_Types(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+    public enum Extension_Types {
+        OF_10(0), IPV6EXT(1);
+
+        protected int value;
+
+        private Extension_Types(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+    public V6Match() {
+        super();
+
+        this.nwSrc = null;
+        this.nwDst = null;
+
+        this.inputPortMask = 0;
+        this.dataLayerSourceMask = null;
+        this.dataLayerDestinationMask = null;
+        this.dataLayerTypeMask = 0;
+        this.dataLayerVirtualLanMask = 0;
+        this.dataLayerVirtualLanPriorityCodePointMask = 0;
+        this.networkDestinationMask = null;
+        this.networkSourceMask = null;
+        this.networkTypeOfServiceMask = 0;
+        this.networkProtocolMask = 0;
+        this.transportSourceMask = 0;
+        this.transportDestinationMask = 0;
+
+        this.inputPortState = MatchFieldState.MATCH_ABSENT;
+        this.dlSourceState = MatchFieldState.MATCH_ABSENT;
+        this.dlDestState = MatchFieldState.MATCH_ABSENT;
+        this.dlVlanState = MatchFieldState.MATCH_ABSENT;
+        this.ethTypeState = MatchFieldState.MATCH_ABSENT;
+        this.nwTosState = MatchFieldState.MATCH_ABSENT;
+        this.nwProtoState = MatchFieldState.MATCH_ABSENT;
+        this.nwSrcState = MatchFieldState.MATCH_ABSENT;
+        this.nwDstState = MatchFieldState.MATCH_ABSENT;
+        this.tpSrcState = MatchFieldState.MATCH_ABSENT;
+        this.tpDstState = MatchFieldState.MATCH_ABSENT;
+
+        this.match_len = 0;
+        this.pad_size = 0;
+    }
+
+    public V6Match(OFMatch match) {
+        super();
+        this.match_len = 0;
+        this.pad_size = 0;
+
+        this.networkSourceMask = null;
+        if (match.getNetworkSource() != 0) {
+            InetAddress address = null;
+            try {
+                address = InetAddress.getByAddress(ByteBuffer.allocate(4)
+                        .putInt(match.getNetworkSource()).array());
+            } catch (UnknownHostException e) {
+                logger.error("",e);
+            }
+            this.setNetworkSource(address, null);
+        } else {
+            this.nwSrc = null;
+            this.nwSrcState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.networkDestinationMask = null;
+        if (match.getNetworkDestination() != 0) {
+            InetAddress address = null;
+            try {
+                address = InetAddress.getByAddress(ByteBuffer.allocate(4)
+                        .putInt(match.getNetworkDestination()).array());
+            } catch (UnknownHostException e) {
+                logger.error("",e);
+            }
+            this.setNetworkDestination(address, null);
+        } else {
+            this.nwDst = null;
+            this.nwDstState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.inputPortMask = 0;
+        if (match.getInputPort() != 0) {
+            this.setInputPort(match.getInputPort(), (short) 0);
+        } else {
+            this.inputPortMask = 0;
+            this.inputPortState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.dataLayerSourceMask = null;
+        if (match.getDataLayerSource() != null) {
+            this.setDataLayerSource(match.getDataLayerSource(), null);
+        } else {
+            this.dataLayerSource = null;
+            this.dlSourceState = MatchFieldState.MATCH_ABSENT;
+        }
+        this.dataLayerDestinationMask = null;
+        if (match.getDataLayerDestination() != null) {
+            this.setDataLayerDestination(match.getDataLayerDestination(), null);
+        } else {
+            this.dataLayerDestination = null;
+            this.dlDestState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.dataLayerTypeMask = 0;
+        if (match.getDataLayerType() != 0) {
+            this.setDataLayerType(match.getDataLayerType(), (short) 0);
+        } else {
+            this.dataLayerType = 0;
+            this.ethTypeState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.dataLayerVirtualLanMask = 0;
+        if (match.getDataLayerVirtualLan() != 0) {
+            this.setDataLayerVirtualLan(match.getDataLayerVirtualLan(),
+                    (short) 0);
+        } else {
+            this.dataLayerVirtualLan = 0;
+            this.dlVlanState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.dataLayerVirtualLanPriorityCodePointMask = 0;
+        if (match.getDataLayerVirtualLanPriorityCodePoint() != 0) {
+            this.setDataLayerVirtualLanPriorityCodePoint(match
+                    .getDataLayerVirtualLanPriorityCodePoint(), (byte) 0);
+        } else {
+            this.dataLayerVirtualLanPriorityCodePoint = 0;
+        }
+
+        this.networkProtocolMask = 0;
+        if (match.getNetworkProtocol() != 0) {
+            this.setNetworkProtocol(this.networkProtocol = match
+                    .getNetworkProtocol(), (byte) 0);
+        } else {
+            this.networkProtocol = 0;
+            this.nwProtoState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.networkTypeOfServiceMask = 0;
+        if (match.getNetworkTypeOfService() != 0) {
+            this.setNetworkTypeOfService(this.networkTypeOfService = match
+                    .getNetworkTypeOfService(), (byte) 0);
+        } else {
+            this.networkTypeOfService = match.getNetworkTypeOfService();
+            this.nwTosState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.transportSourceMask = 0;
+        if (match.getTransportSource() != 0) {
+            this.setTransportSource(match.getTransportSource(), (short) 0);
+        } else {
+            this.transportSource = 0;
+            this.tpSrcState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.transportDestinationMask = 0;
+        if (match.getTransportDestination() != 0) {
+            this.setTransportDestination(match.getTransportDestination(),
+                    (short) 0);
+        } else {
+            this.transportDestination = 0;
+            this.tpDstState = MatchFieldState.MATCH_ABSENT;
+        }
+
+        this.setWildcards(match.getWildcards());
+    }
+
+    private enum IPProtocols {
+        ICMP(1), TCP(6), UDP(17), ICMPV6(58);
+
+        private int protocol;
+
+        private IPProtocols(int value) {
+            this.protocol = value;
+        }
+
+        private byte getValue() {
+            return (byte) this.protocol;
+        }
+    }
+
+    public short getIPv6MatchLen() {
+        return match_len;
+    }
+
+    public int getIPv6ExtMinHdrLen() {
+        return IPV6_EXT_MIN_HDR_LEN;
+    }
+
+    public short getPadSize() {
+        return (short) (((match_len + 7) / 8) * 8 - match_len);
+    }
+
+    private int getIPv6ExtensionMatchHeader(Extension_Types extType, int field,
+            int has_mask, int length) {
+        return (((extType.getValue() & 0x0000ffff) << 16)
+                | ((field & 0x0000007f) << 9) | ((has_mask & 0x00000001) << 8) | (length & 0x000000ff));
+    }
+
+    private byte[] getIPv6ExtensionPortMatchMsg(short port) {
+        ByteBuffer ipv6ext_port_msg = ByteBuffer.allocate(6);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_IN_PORT.getValue(), 0, 2);
+        ipv6ext_port_msg.putInt(nxm_header);
+        ipv6ext_port_msg.putShort(port);
+        return (ipv6ext_port_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionDestMacMatchMsg(byte[] destMac) {
+        ByteBuffer ipv6ext_destmac_msg = ByteBuffer.allocate(10);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_ETH_DST.getValue(), 0, 6);
+        ipv6ext_destmac_msg.putInt(nxm_header);
+        ipv6ext_destmac_msg.put(destMac);
+        return (ipv6ext_destmac_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionSrcMacMatchMsg(byte[] srcMac) {
+        ByteBuffer ipv6ext_srcmac_msg = ByteBuffer.allocate(10);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_ETH_SRC.getValue(), 0, 6);
+        ipv6ext_srcmac_msg.putInt(nxm_header);
+        ipv6ext_srcmac_msg.put(srcMac);
+        return (ipv6ext_srcmac_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionEtherTypeMatchMsg(short EtherType) {
+        ByteBuffer ipv6ext_etype_msg = ByteBuffer.allocate(6);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_ETH_TYPE.getValue(), 0, 2);
+        ipv6ext_etype_msg.putInt(nxm_header);
+        ipv6ext_etype_msg.putShort(EtherType);
+        return (ipv6ext_etype_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionVlanIDMatchMsg(short VLAN) {
+        ByteBuffer ipv6ext_vlanid_msg = ByteBuffer.allocate(6);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_VLAN_TCI.getValue(), 0, 2);
+        ipv6ext_vlanid_msg.putInt(nxm_header);
+        ipv6ext_vlanid_msg.putShort(VLAN);
+        return (ipv6ext_vlanid_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionSrcIPv6MatchMsg(byte[] srcIpv6) {
+        ByteBuffer ipv6ext_ipv6_msg = ByteBuffer.allocate(20);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.IPV6EXT,
+                IPv6Extension_Match_Types.MATCH_IPV6EXT_IPV6_SRC.getValue(), 0,
+                16);
+        ipv6ext_ipv6_msg.putInt(nxm_header);
+        ipv6ext_ipv6_msg.put(srcIpv6);
+        return (ipv6ext_ipv6_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionSrcIPv6MatchwithMaskMsg(byte[] srcIpv6,
+            short masklen) {
+        ByteBuffer ipv6ext_ipv6_msg = ByteBuffer.allocate(36);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.IPV6EXT,
+                IPv6Extension_Match_Types.MATCH_IPV6EXT_IPV6_SRC.getValue(), 1,
+                32);
+        ipv6ext_ipv6_msg.putInt(nxm_header);
+        ipv6ext_ipv6_msg.put(srcIpv6);
+        byte[] ipv6_mask = getIPv6NetworkMaskinBytes(masklen);
+        ipv6ext_ipv6_msg.put(ipv6_mask);
+        return (ipv6ext_ipv6_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionDstIPv6MatchMsg(byte[] dstIpv6) {
+        ByteBuffer ipv6ext_ipv6_msg = ByteBuffer.allocate(20);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.IPV6EXT,
+                IPv6Extension_Match_Types.MATCH_IPV6EXT_IPV6_DST.getValue(), 0,
+                16);
+        ipv6ext_ipv6_msg.putInt(nxm_header);
+        ipv6ext_ipv6_msg.put(dstIpv6);
+        return (ipv6ext_ipv6_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionDstIPv6MatchwithMaskMsg(byte[] dstIpv6,
+            short masklen) {
+        ByteBuffer ipv6ext_ipv6_msg = ByteBuffer.allocate(36);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.IPV6EXT,
+                IPv6Extension_Match_Types.MATCH_IPV6EXT_IPV6_DST.getValue(), 1,
+                32);
+        ipv6ext_ipv6_msg.putInt(nxm_header);
+        ipv6ext_ipv6_msg.put(dstIpv6);
+        byte[] ipv6_mask = getIPv6NetworkMaskinBytes(masklen);
+        ipv6ext_ipv6_msg.put(ipv6_mask);
+        return (ipv6ext_ipv6_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionProtocolMatchMsg(byte protocol) {
+        ByteBuffer ipv6ext_proto_msg = ByteBuffer.allocate(5);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_IP_PROTO.getValue(), 0, 1);
+        if (protocol == 0) {
+            return null;
+        }
+        ipv6ext_proto_msg.putInt(nxm_header);
+        if (protocol == IPProtocols.ICMP.getValue()) {
+            /*
+             * The front end  passes the same protocol type values for IPv4
+             * and IPv6 flows. For the Protocol types we allow in our GUI
+             * (ICMP, TCP, UDP), ICMP is the only one which is different for
+             * IPv6. It is 1 for v4 and 58 for v6 Therefore, we overwrite it
+             * here.
+             */
+            protocol = IPProtocols.ICMPV6.getValue();
+        }
+        ipv6ext_proto_msg.put(protocol);
+        return (ipv6ext_proto_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionTOSMatchMsg(byte tos) {
+        ByteBuffer ipv6ext_tos_msg = ByteBuffer.allocate(5);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_IP_TOS.getValue(), 0, 1);
+        ipv6ext_tos_msg.putInt(nxm_header);
+        ipv6ext_tos_msg.put(tos);
+        return (ipv6ext_tos_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionTCPSrcPortMatchMsg(short src_port) {
+        ByteBuffer ipv6ext_tcp_srcport_msg = ByteBuffer.allocate(6);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_TCP_SRC.getValue(), 0, 2);
+        ipv6ext_tcp_srcport_msg.putInt(nxm_header);
+        ipv6ext_tcp_srcport_msg.putShort(src_port);
+        return (ipv6ext_tcp_srcport_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionTCPDstPortMatchMsg(short dst_port) {
+        ByteBuffer ipv6ext_tcp_dstport_msg = ByteBuffer.allocate(6);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_TCP_DST.getValue(), 0, 2);
+        ipv6ext_tcp_dstport_msg.putInt(nxm_header);
+        ipv6ext_tcp_dstport_msg.putShort(dst_port);
+        return (ipv6ext_tcp_dstport_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionUDPSrcPortMatchMsg(short src_port) {
+        ByteBuffer ipv6ext_udp_srcport_msg = ByteBuffer.allocate(6);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_UDP_SRC.getValue(), 0, 2);
+        ipv6ext_udp_srcport_msg.putInt(nxm_header);
+        ipv6ext_udp_srcport_msg.putShort(src_port);
+        return (ipv6ext_udp_srcport_msg.array());
+    }
+
+    private byte[] getIPv6ExtensionUDPDstPortMatchMsg(short dst_port) {
+        ByteBuffer ipv6ext_udp_dstport_msg = ByteBuffer.allocate(6);
+        int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10,
+                OF_Match_Types.MATCH_OF_UDP_DST.getValue(), 0, 2);
+        ipv6ext_udp_dstport_msg.putInt(nxm_header);
+        ipv6ext_udp_dstport_msg.putShort(dst_port);
+        return (ipv6ext_udp_dstport_msg.array());
+    }
+
+    /**
+     * Sets this (V6Match) object's member variables based on a comma-separated key=value pair similar to OFMatch's fromString.
+     *
+     * @param match a key=value comma separated string.
+     */
+    @Override
+    public void fromString(String match) throws IllegalArgumentException {
+        if (match.equals("") || match.equalsIgnoreCase("any")
+                || match.equalsIgnoreCase("all") || match.equals("[]"))
+            match = "OFMatch[]";
+        String[] tokens = match.split("[\\[,\\]]");
+        String[] values;
+        int initArg = 0;
+        if (tokens[0].equals("OFMatch"))
+            initArg = 1;
+        this.wildcards = OFPFW_ALL;
+        int i;
+        for (i = initArg; i < tokens.length; i++) {
+            values = tokens[i].split("=");
+            if (values.length != 2)
+                throw new IllegalArgumentException("Token " + tokens[i]
+                        + " does not have form 'key=value' parsing " + match);
+            values[0] = values[0].toLowerCase(); // try to make this case insens
+            if (values[0].equals(STR_IN_PORT) || values[0].equals("input_port")) {
+                this.inputPort = U16.t(Integer.valueOf(values[1]));
+                inputPortState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 6;
+            } else if (values[0].equals(STR_DL_DST)
+                    || values[0].equals("eth_dst")) {
+                this.dataLayerDestination = HexEncode
+                        .bytesFromHexString(values[1]);
+                dlDestState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 10;
+            } else if (values[0].equals(STR_DL_SRC)
+                    || values[0].equals("eth_src")) {
+                this.dataLayerSource = HexEncode.bytesFromHexString(values[1]);
+                dlSourceState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 10;
+                this.wildcards &= ~OFPFW_DL_SRC;
+            } else if (values[0].equals(STR_DL_TYPE)
+                    || values[0].equals("eth_type")) {
+                if (values[1].startsWith("0x"))
+                    this.dataLayerType = U16.t(Integer.valueOf(values[1]
+                            .replaceFirst("0x", ""), 16));
+                else
+                    this.dataLayerType = U16.t(Integer.valueOf(values[1]));
+                ethTypeState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 6;
+            } else if (values[0].equals(STR_DL_VLAN)) {
+                this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1]));
+                dlVlanState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 6;
+            } else if (values[0].equals(STR_DL_VLAN_PCP)) {
+                this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short
+                        .valueOf(values[1]));
+                this.wildcards &= ~OFPFW_DL_VLAN_PCP;
+            } else if (values[0].equals(STR_NW_DST)
+                    || values[0].equals("ip_dst")) {
+                try {
+                    if (values[1].contains("/")) {
+                        String ipv6addr_wmask[] = values[1].split("/");
+                        this.nwDst = InetAddress.getByName(ipv6addr_wmask[0]);
+                        this.dstIPv6SubnetMaskbits = Short
+                                .valueOf(ipv6addr_wmask[1]);
+                        nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                        match_len += 36;
+                    } else {
+                        this.nwDst = InetAddress.getByName(values[1]);
+                        nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
+                        match_len += 20;
+                    }
+                } catch (UnknownHostException e) {
+                    logger.error("",e);
+                }
+            } else if (values[0].equals(STR_NW_SRC)
+                    || values[0].equals("ip_src")) {
+                try {
+                    if (values[1].contains("/")) {
+                        String ipv6addr_wmask[] = values[1].split("/");
+                        this.nwSrc = InetAddress.getByName(ipv6addr_wmask[0]);
+                        this.srcIPv6SubnetMaskbits = Short
+                                .valueOf(ipv6addr_wmask[1]);
+                        nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                        match_len += 36;
+                    } else {
+                        this.nwSrc = InetAddress.getByName(values[1]);
+                        nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+                        match_len += 20;
+                    }
+                } catch (UnknownHostException e) {
+                    logger.error("",e);
+                }
+            } else if (values[0].equals(STR_NW_PROTO)) {
+                this.networkProtocol = U8.t(Short.valueOf(values[1]));
+                if (!(this.networkProtocol == 0)) {
+                    /*
+                     * if user selects proto 0, don't use it
+                     */
+                    nwProtoState = MatchFieldState.MATCH_FIELD_ONLY;
+                    match_len += 5;
+                }
+            } else if (values[0].equals(STR_NW_TOS)) {
+                this.networkTypeOfService = U8.t(Short.valueOf(values[1]));
+                nwTosState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 5;
+            } else if (values[0].equals(STR_TP_DST)) {
+                this.transportDestination = U16.t(Integer.valueOf(values[1]));
+                tpDstState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 6;
+            } else if (values[0].equals(STR_TP_SRC)) {
+                this.transportSource = U16.t(Integer.valueOf(values[1]));
+                tpSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+                match_len += 6;
+            } else
+                throw new IllegalArgumentException("unknown token " + tokens[i]
+                        + " parsing " + match);
+        }
+
+        /*
+         * In a V6 extension message action list should be preceded by a padding of 0 to
+         * 7 bytes based upon following formula.
+         */
+
+        pad_size = (short) (((match_len + 7) / 8) * 8 - match_len);
+
+    }
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     *
+     * @param data
+     */
+    /*
+    @Override
+    public void writeTo(ByteBuffer data) {
+        if (inputPortState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_ingress_port_msg = getIPv6ExtensionPortMatchMsg(this.inputPort);
+            data.put(ipv6ext_ingress_port_msg);
+        }
+        if (ethTypeState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_ether_type_msg = getIPv6ExtensionEtherTypeMatchMsg(this.dataLayerType);
+            data.put(ipv6ext_ether_type_msg);
+        }
+        if (dlDestState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_destmac_msg = getIPv6ExtensionDestMacMatchMsg(this.dataLayerDestination);
+            data.put(ipv6ext_destmac_msg);
+        }
+        if (dlSourceState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_srcmac_msg = getIPv6ExtensionSrcMacMatchMsg(this.dataLayerSource);
+            data.put(ipv6ext_srcmac_msg);
+        }
+        if (dlVlanState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_vlan_id_msg = getIPv6ExtensionVlanIDMatchMsg(this.dataLayerVirtualLan);
+            data.put(ipv6ext_vlan_id_msg);
+        }
+        if (nwSrcState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_src_ipv6_msg = getIPv6ExtensionSrcIPv6MatchMsg(this.nwSrc
+                    .getAddress());
+            data.put(ipv6ext_src_ipv6_msg);
+        } else if (nwSrcState == MatchFieldState.MATCH_FIELD_WITH_MASK) {
+            byte[] ipv6ext_src_ipv6_with_mask_msg = getIPv6ExtensionSrcIPv6MatchwithMaskMsg(
+                    this.nwSrc.getAddress(), this.srcIPv6SubnetMaskbits);
+            data.put(ipv6ext_src_ipv6_with_mask_msg);
+        }
+        if (nwDstState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_dst_ipv6_msg = getIPv6ExtensionDstIPv6MatchMsg(this.nwDst
+                    .getAddress());
+            data.put(ipv6ext_dst_ipv6_msg);
+        } else if (nwDstState == MatchFieldState.MATCH_FIELD_WITH_MASK) {
+            byte[] ipv6ext_dst_ipv6_with_mask_msg = getIPv6ExtensionDstIPv6MatchwithMaskMsg(
+                    this.nwDst.getAddress(), this.dstIPv6SubnetMaskbits);
+            data.put(ipv6ext_dst_ipv6_with_mask_msg);
+        }
+        if (nwProtoState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_protocol_msg = getIPv6ExtensionProtocolMatchMsg(this.networkProtocol);
+            if (ipv6ext_protocol_msg != null) {
+                data.put(ipv6ext_protocol_msg);
+            }
+        }
+        if (nwTosState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_tos_msg = getIPv6ExtensionTOSMatchMsg(this.networkTypeOfService);
+            data.put(ipv6ext_tos_msg);
+        }
+        if (tpSrcState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_srcport_msg = null;
+            if (this.networkProtocol == IPProtocols.TCP.getValue()) {
+                ipv6ext_srcport_msg = getIPv6ExtensionTCPSrcPortMatchMsg(this.transportSource);
+            } else if (this.networkProtocol == IPProtocols.UDP.getValue()) {
+                ipv6ext_srcport_msg = getIPv6ExtensionUDPSrcPortMatchMsg(this.transportSource);
+            }
+            if (ipv6ext_srcport_msg != null) {
+                data.put(ipv6ext_srcport_msg);
+            }
+        }
+        if (tpDstState == MatchFieldState.MATCH_FIELD_ONLY) {
+            byte[] ipv6ext_dstport_msg = null;
+            if (this.networkProtocol == IPProtocols.TCP.getValue()) {
+                ipv6ext_dstport_msg = getIPv6ExtensionTCPDstPortMatchMsg(this.transportDestination);
+            } else if (this.networkProtocol == IPProtocols.UDP.getValue()) {
+                ipv6ext_dstport_msg = getIPv6ExtensionUDPDstPortMatchMsg(this.transportDestination);
+            }
+            if (ipv6ext_dstport_msg != null) {
+                data.put(ipv6ext_dstport_msg);
+            }
+        }
+        logger.trace("{}", this.toString());
+    }
+    */
+
+    private void readInPort(ByteBuffer data, int nxmLen, boolean hasMask) {
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+            /*
+             * mask is not allowed for inport port
+             */
+            return;
+        super.setInputPort(data.getShort());
+        this.inputPortState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.wildcards ^= (1 << 0); // Sync with 0F 1.0 Match
+        this.match_len += 6;
+    }
+
+    private void readDataLinkDestination(ByteBuffer data, int nxmLen,
+            boolean hasMask) {
+        if (hasMask) {
+            if ((nxmLen != 2 * 6) || (data.remaining() < 2 * 6))
+                return;
+            else {
+                byte[] bytes = new byte[6];
+                data.get(bytes);
+                super.setDataLayerDestination(bytes);
+                this.dataLayerDestinationMask = new byte[6];
+                data.get(this.dataLayerDestinationMask);
+                this.dlDestState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 16;
+            }
+        } else {
+            if ((nxmLen != 6) || (data.remaining() < 6))
+                return;
+            else {
+                byte[] bytes = new byte[6];
+                data.get(bytes);
+                super.setDataLayerDestination(bytes);
+                this.dlDestState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += 10;
+            }
+        }
+        this.wildcards ^= (1 << 3); // Sync with 0F 1.0 Match
+    }
+
+    private void readDataLinkSource(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in data link source
+         */
+        if ((nxmLen != 6) || (data.remaining() < 6) || (hasMask))
+            return;
+        byte[] bytes = new byte[6];
+        data.get(bytes);
+        super.setDataLayerSource(bytes);
+        this.dlSourceState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 10;
+        this.wildcards ^= (1 << 2); // Sync with 0F 1.0 Match
+    }
+
+    private void readEtherType(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in ethertype
+         */
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+            return;
+        super.setDataLayerType(data.getShort());
+        this.ethTypeState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.wildcards ^= (1 << 4); // Sync with 0F 1.0 Match
+        this.match_len += 6;
+    }
+
+    private void readVlanTci(ByteBuffer data, int nxmLen, boolean hasMask) {
+        short vlan_mask = 0xfff;
+        if (hasMask) {
+            if ((nxmLen != 2 * 2) || (data.remaining() < 2 * 2))
+                return;
+            else {
+                short vlan = data.getShort();
+                vlan &= vlan_mask;
+                super.setDataLayerVirtualLan(vlan);
+                this.dataLayerVirtualLanMask = data.getShort();
+                this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 8;
+                this.wildcards ^= (1 << 20);
+            }
+        } else {
+            if ((nxmLen != 2) || (data.remaining() < 2))
+                return;
+            else {
+                short vlan = data.getShort();
+                vlan &= vlan_mask;
+                super.setDataLayerVirtualLan(vlan);
+                this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += 6;
+            }
+        }
+
+        this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match
+    }
+
+    private void readIpTos(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in IP TOS
+         */
+        if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask))
+            return;
+        super.setNetworkTypeOfService(data.get());
+        this.nwTosState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 5;
+        this.wildcards ^= (1 << 21); // Sync with 0F 1.0 Match
+    }
+
+    private void readIpProto(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in IP protocol
+         */
+        if ((nxmLen != 1) || (data.remaining() < 1) || (hasMask))
+            return;
+        super.setNetworkProtocol(data.get());
+        this.nwProtoState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 5;
+        this.wildcards ^= (1 << 5); // Sync with 0F 1.0 Match
+    }
+
+    private void readIpv4Src(ByteBuffer data, int nxmLen, boolean hasMask) {
+        if (hasMask) {
+            if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4))
+                return;
+            else {
+                byte[] sbytes = new byte[4];
+                data.get(sbytes);
+                try {
+                    this.nwSrc = InetAddress.getByAddress(sbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                byte[] mbytes = new byte[4];
+                data.get(mbytes);
+                try {
+                    this.networkSourceMask = InetAddress.getByAddress(mbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 12;
+                int prefixlen = getNetworkMaskPrefixLength(mbytes);
+                this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 Match
+                this.wildcards |= ((32 - prefixlen) << 8); // Sync with 0F 1.0 Match
+
+            }
+        } else {
+            if ((nxmLen != 4) || (data.remaining() < 4))
+                return;
+            else {
+                byte[] sbytes = new byte[4];
+                data.get(sbytes);
+                try {
+                    this.nwSrc = InetAddress.getByAddress(sbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += 8;
+                this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 Match
+            }
+        }
+    }
+
+    private void readIpv4Dst(ByteBuffer data, int nxmLen, boolean hasMask) {
+        if (hasMask) {
+            if ((nxmLen != 2 * 4) || (data.remaining() < 2 * 4))
+                return;
+            else {
+                byte[] dbytes = new byte[4];
+                data.get(dbytes);
+                try {
+                    this.nwDst = InetAddress.getByAddress(dbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                byte[] mbytes = new byte[4];
+                data.get(mbytes);
+                try {
+                    this.networkDestinationMask = InetAddress
+                            .getByAddress(mbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 12;
+                int prefixlen = getNetworkMaskPrefixLength(mbytes);
+                this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match
+                this.wildcards |= ((32 - prefixlen) << 14); // Sync with 0F 1.0 Match
+            }
+        } else {
+            if ((nxmLen != 4) || (data.remaining() < 4))
+                return;
+            else {
+                byte[] dbytes = new byte[4];
+                data.get(dbytes);
+                try {
+                    this.nwDst = InetAddress.getByAddress(dbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match
+                this.match_len += 8;
+            }
+        }
+    }
+
+    private void readTcpSrc(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in TCP SRC
+         */
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+            return;
+        super.setTransportSource(data.getShort());
+        this.tpSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 6;
+        this.wildcards ^= (1 << 6); // Sync with 0F 1.0 Match
+    }
+
+    private void readTcpDst(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in TCP DST
+         */
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+            return;
+        super.setTransportDestination(data.getShort());
+        this.tpDstState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 6;
+        this.wildcards ^= (1 << 7); // Sync with 0F 1.0 Match
+    }
+
+    private void readUdpSrc(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in UDP SRC
+         */
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+            return;
+        super.setTransportSource(data.getShort());
+        this.tpSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 6;
+        this.wildcards ^= (1 << 6); // Sync with 0F 1.0 Match
+    }
+
+    private void readUdpDst(ByteBuffer data, int nxmLen, boolean hasMask) {
+        /*
+         * mask is not allowed in UDP DST
+         */
+        if ((nxmLen != 2) || (data.remaining() < 2) || (hasMask))
+            return;
+        super.setTransportDestination(data.getShort());
+        this.tpDstState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 6;
+        this.wildcards ^= (1 << 7); // Sync with 0F 1.0 Match
+    }
+
+    private void readIpv6Src(ByteBuffer data, int nxmLen, boolean hasMask) {
+        if (hasMask) {
+            if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16))
+                return;
+            else {
+                byte[] sbytes = new byte[16];
+                data.get(sbytes);
+                try {
+                    this.nwSrc = InetAddress.getByAddress(sbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                byte[] mbytes = new byte[16];
+                data.get(mbytes);
+                try {
+                    this.networkSourceMask = InetAddress.getByAddress(mbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 36;
+            }
+        } else {
+            if ((nxmLen != 16) || (data.remaining() < 16))
+                return;
+            else {
+                byte[] sbytes = new byte[16];
+                data.get(sbytes);
+                try {
+                    this.nwSrc = InetAddress.getByAddress(sbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += 20;
+            }
+        }
+    }
+
+    private void readIpv6Dst(ByteBuffer data, int nxmLen, boolean hasMask) {
+        if (hasMask) {
+            if ((nxmLen != 2 * 16) || (data.remaining() < 2 * 16))
+                return;
+            else {
+                byte[] dbytes = new byte[16];
+                data.get(dbytes);
+                try {
+                    this.nwDst = InetAddress.getByAddress(dbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                byte[] mbytes = new byte[16];
+                data.get(mbytes);
+                try {
+                    this.networkDestinationMask = InetAddress
+                            .getByAddress(mbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+                this.match_len += 36;
+            }
+        } else {
+            if ((nxmLen != 16) || (data.remaining() < 16))
+                return;
+            else {
+                byte[] dbytes = new byte[16];
+                data.get(dbytes);
+                try {
+                    this.nwDst = InetAddress.getByAddress(dbytes);
+                } catch (UnknownHostException e) {
+                    return;
+                }
+                this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
+                this.match_len += 20;
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "V6Match[" + ReflectionToStringBuilder.toString(this) + "]";
+    }
+
+    /**
+     * Read the data corresponding to the match field (received from the wire)
+     * Input: data: match field(s). Since match field is of variable length, the whole data that are passed in
+     * are assumed to fem0tbd.be the match fields.
+     * @param data
+     */
+    /*
+    @Override
+    public void readFrom(ByteBuffer data) {
+        readFromInternal(data);
+        postprocessWildCardInfo();
+    }
+    */
+
+    private void readFromInternal(ByteBuffer data) {
+        this.match_len = 0;
+        while (data.remaining() > 0) {
+            if (data.remaining() < 4) {
+                /*
+                 * at least 4 bytes for each match header
+                 */
+                logger.error("Invalid Vendor Extension Header. Size {}", data
+                        .remaining());
+                return;
+            }
+            /*
+             * read the 4 byte match header
+             */
+            int nxmVendor = data.getShort();
+            int b = data.get();
+            int nxmField = b >> 1;
+            boolean hasMask = ((b & 0x01) == 1) ? true : false;
+            int nxmLen = data.get();
+            if (nxmVendor == Extension_Types.OF_10.getValue()) {
+                if (nxmField == OF_Match_Types.MATCH_OF_IN_PORT.getValue()) {
+                    readInPort(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_ETH_DST
+                        .getValue()) {
+                    readDataLinkDestination(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_ETH_SRC
+                        .getValue()) {
+                    readDataLinkSource(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_ETH_TYPE
+                        .getValue()) {
+                    readEtherType(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_VLAN_TCI
+                        .getValue()) {
+                    readVlanTci(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_IP_TOS
+                        .getValue()) {
+                    readIpTos(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_IP_PROTO
+                        .getValue()) {
+                    readIpProto(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_IP_SRC
+                        .getValue()) {
+                    readIpv4Src(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_IP_DST
+                        .getValue()) {
+                    readIpv4Dst(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_TCP_SRC
+                        .getValue()) {
+                    readTcpSrc(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_TCP_DST
+                        .getValue()) {
+                    readTcpDst(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_UDP_SRC
+                        .getValue()) {
+                    readUdpSrc(data, nxmLen, hasMask);
+                } else if (nxmField == OF_Match_Types.MATCH_OF_UDP_DST
+                        .getValue()) {
+                    readUdpDst(data, nxmLen, hasMask);
+                } else {
+                    // unexpected nxmField
+                    return;
+                }
+            } else if (nxmVendor == Extension_Types.IPV6EXT.getValue()) {
+                if (nxmField == IPv6Extension_Match_Types.MATCH_IPV6EXT_IPV6_SRC
+                        .getValue()) {
+                    readIpv6Src(data, nxmLen, hasMask);
+                } else if (nxmField == IPv6Extension_Match_Types.MATCH_IPV6EXT_IPV6_DST
+                        .getValue()) {
+                    readIpv6Dst(data, nxmLen, hasMask);
+                } else {
+                    // unexpected nxmField
+                    return;
+                }
+            } else {
+                // invalid nxmVendor
+                return;
+            }
+        }
+    }
+
+    private void postprocessWildCardInfo() {
+        // Sync with 0F 1.0 Match
+        if (super.getDataLayerType() == 0x800) {
+            if (((this.wildcards >> 8) & 0x3f) == 0x3f) {
+                //ipv4 src processing
+                this.wildcards ^= (((1 << 5) - 1) << 8);
+            }
+            if (((this.wildcards >> 14) & 0x3f) == 0x3f) {
+                //ipv4 dest processing
+                this.wildcards ^= (((1 << 5) - 1) << 14);
+            }
+        } else {
+            this.wildcards = 0;
+        }
+    }
+
+    @Override
+    public V6Match clone() {
+
+        V6Match ret = (V6Match) super.clone();
+        try {
+            if (this.nwSrc != null) {
+                ret.nwSrc = InetAddress.getByAddress(this.nwSrc.getAddress());
+            }
+            if (this.nwDst != null) {
+                ret.nwDst = InetAddress.getByAddress(this.nwDst.getAddress());
+            }
+            return ret;
+        } catch (UnknownHostException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Get nw_dst
+     *
+     * @return
+     */
+
+    public InetAddress getNetworkDest() {
+        return this.nwDst;
+    }
+
+    /**
+     * Get nw_src
+     *
+     * @return
+     */
+
+    public void setNetworkSrc(InetAddress address) {
+        nwSrc = address;
+    }
+
+    /**
+     * Set nw_dst
+     *
+     * @return
+     */
+
+    public void setNetworkDest(InetAddress address) {
+        nwDst = address;
+    }
+
+    /**
+     * Set nw_src
+     *
+     * @return
+     */
+
+    public InetAddress getNetworkSrc() {
+        return this.nwSrc;
+    }
+
+    private int getNetworkMaskPrefixLength(byte[] netMask) {
+        ByteBuffer nm = ByteBuffer.wrap(netMask);
+        int trailingZeros = Integer.numberOfTrailingZeros(nm.getInt());
+        return 32 - trailingZeros;
+    }
+
+    public short getInputPortMask() {
+        return inputPortMask;
+    }
+
+    public void setInputPort(short port, short mask) {
+        super.inputPort = port;
+        this.inputPortState = MatchFieldState.MATCH_FIELD_ONLY;
+        match_len += 6;
+        // Looks like mask is not allowed for input port. Will discard it
+    }
+
+    public byte[] getDataLayerSourceMask() {
+        return dataLayerSourceMask;
+    }
+
+    public void setDataLayerSource(byte[] mac, byte[] mask) {
+        if (mac != null) {
+            System.arraycopy(mac, 0, super.dataLayerSource, 0, mac.length);
+        }
+        if (mask == null) {
+            this.dlSourceState = MatchFieldState.MATCH_FIELD_ONLY;
+            this.match_len += 10;
+        } else {
+            if (this.dataLayerSourceMask == null) {
+                this.dataLayerSourceMask = new byte[mask.length];
+            }
+            System.arraycopy(mask, 0, this.dataLayerSourceMask, 0, mask.length);
+            this.dlSourceState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+            this.match_len += 16;
+        }
+    }
+
+    public byte[] getDataLayerDestinationMask() {
+        return dataLayerDestinationMask;
+    }
+
+    public void setDataLayerDestination(byte[] mac, byte[] mask) {
+        if (mac != null) {
+            System.arraycopy(mac, 0, super.dataLayerDestination, 0, mac.length);
+        }
+        if (mask == null) {
+            this.dlDestState = MatchFieldState.MATCH_FIELD_ONLY;
+            this.match_len += 10;
+        } else {
+            if (this.dataLayerDestinationMask == null) {
+                this.dataLayerDestinationMask = new byte[mask.length];
+            }
+            System.arraycopy(mask, 0, this.dataLayerDestinationMask, 0,
+                    mask.length);
+            this.dlDestState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+            this.match_len += 16;
+        }
+    }
+
+    public short getDataLayerVirtualLanMask() {
+        return dataLayerVirtualLanMask;
+    }
+
+    public void setDataLayerVirtualLan(short vlan, short mask) {
+        super.dataLayerVirtualLan = vlan;
+        if (mask == 0) {
+            this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY;
+            this.match_len += 6;
+        } else {
+            this.dataLayerVirtualLanMask = mask;
+            this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+            this.match_len += 8;
+        }
+    }
+
+    public void setDataLayerVirtualLanPriorityCodePoint(byte pcp, byte mask) {
+        super.dataLayerVirtualLanPriorityCodePoint = pcp;
+    }
+
+    public void setDataLayerType(short ethType, short mask) {
+        // mask not allowed
+        super.dataLayerType = ethType;
+        this.ethTypeState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 6;
+    }
+
+    public void setNetworkTypeOfService(byte tos, byte mask) {
+        // mask not allowed
+        super.networkTypeOfService = tos;
+        this.nwTosState = MatchFieldState.MATCH_FIELD_ONLY;
+        match_len += 5;
+    }
+
+    public void setNetworkProtocol(byte ipProto, byte mask) {
+        // mask not allowed
+        super.networkProtocol = ipProto;
+        this.nwProtoState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 5;
+    }
+
+    public InetAddress getNetworkSourceMask() {
+        return networkSourceMask;
+    }
+
+    public void setNetworkSource(InetAddress address, InetAddress mask) {
+        this.nwSrc = address;
+        if (mask == null) {
+            this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+            this.match_len += (address instanceof Inet6Address) ? 20 : 8;
+        } else {
+            this.networkSourceMask = mask;
+            this.nwSrcState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+            this.match_len += (address instanceof Inet6Address) ? 36 : 12;
+        }
+    }
+
+    public InetAddress getNetworkDestinationMask() {
+        return networkDestinationMask;
+    }
+
+    public void setNetworkDestination(InetAddress address, InetAddress mask) {
+        this.nwDst = address;
+        if (mask == null) {
+            this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY;
+            this.match_len += (address instanceof Inet6Address) ? 20 : 8;
+        } else {
+            this.networkDestinationMask = mask;
+            this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK;
+            this.match_len += (address instanceof Inet6Address) ? 36 : 12;
+        }
+    }
+
+    public void setTransportSource(short tpSrc, short mask) {
+        // mask not allowed
+        super.transportSource = tpSrc;
+        this.tpSrcState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 6;
+    }
+
+    public short getTransportDestinationMask() {
+        return transportDestinationMask;
+    }
+
+    public void setTransportDestination(short tpDst, short mask) {
+        // mask not allowed
+        super.transportDestination = tpDst;
+        this.tpDstState = MatchFieldState.MATCH_FIELD_ONLY;
+        this.match_len += 6;
+    }
+
+    private byte[] getIPv6NetworkMaskinBytes(short num) {
+        byte[] nbytes = new byte[16];
+        int quot = num / 8;
+        int bits = num % 8;
+        int i;
+
+        for (i = 0; i < quot; i++) {
+            nbytes[i] = (byte) 0xff;
+        }
+
+        if (bits > 0) {
+            nbytes[i] = (byte) 0xff;
+            nbytes[i] <<= 8 - bits;
+        }
+        return nbytes;
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6StatsReply.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6StatsReply.java
new file mode 100644 (file)
index 0000000..00005af
--- /dev/null
@@ -0,0 +1,335 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.statistics.OFVendorStatistics;
+import org.openflow.util.U16;
+
+/**
+ * This Class processes the OpenFlow Vendor Extension Reply message of a Stats
+ * Request. It parses the reply message and initializes fields of  V6StatsReply
+ * object. Multiple instances of this class objects are created and used by
+ * OpenDaylight's Troubleshooting Application.
+ *
+ */
+
+public class V6StatsReply extends OFVendorStatistics {
+    private static final long serialVersionUID = 1L;
+
+    public static int MINIMUM_LENGTH = 48; //48 for nx_flow_stats
+
+    protected short length = (short) MINIMUM_LENGTH;
+    protected byte tableId;
+    protected int durationSeconds;
+    protected int durationNanoseconds;
+    protected short priority;
+    protected short idleTimeout;
+    protected short hardTimeout;
+    protected short match_len;
+    protected short idleAge;
+    protected short hardAge;
+    protected long cookie;
+    protected long packetCount;
+    protected long byteCount;
+    protected V6Match match;
+    protected List<OFAction> actions;
+
+    /**
+     * @return vendor id
+     */
+    public int getVendorId() {
+        return vendor;
+    }
+
+    /**
+     * @param vendor the vendor to set
+     */
+    public void setVendorId(int vendor) {
+        this.vendor = vendor;
+    }
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the durationSeconds
+     */
+    public int getDurationSeconds() {
+        return durationSeconds;
+    }
+
+    /**
+     * @param durationSeconds the durationSeconds to set
+     */
+    public void setDurationSeconds(int durationSeconds) {
+        this.durationSeconds = durationSeconds;
+    }
+
+    /**
+     * @return the durationNanoseconds
+     */
+    public int getDurationNanoseconds() {
+        return durationNanoseconds;
+    }
+
+    /**
+     * @param durationNanoseconds the durationNanoseconds to set
+     */
+    public void setDurationNanoseconds(int durationNanoseconds) {
+        this.durationNanoseconds = durationNanoseconds;
+    }
+
+    /**
+     * @return the priority
+     */
+    public short getPriority() {
+        return priority;
+    }
+
+    /**
+     * @param priority the priority to set
+     */
+    public void setPriority(short priority) {
+        this.priority = priority;
+    }
+
+    /**
+     * @return the idleTimeout
+     */
+    public short getIdleTimeout() {
+        return idleTimeout;
+    }
+
+    /**
+     * @param idleTimeout the idleTimeout to set
+     */
+    public void setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    /**
+     * @return the hardTimeout
+     */
+    public short getHardTimeout() {
+        return hardTimeout;
+    }
+
+    /**
+     * @param hardTimeout the hardTimeout to set
+     */
+    public void setHardTimeout(short hardTimeout) {
+        this.hardTimeout = hardTimeout;
+    }
+
+    /**
+     * @param match_len the match_len to set
+     */
+    public void setMatchLen(short match_len) {
+        this.match_len = match_len;
+    }
+
+    /**
+     * @return the match_len
+     */
+    public short getMatchLen() {
+        return match_len;
+    }
+
+    /**
+     * @return the idleAge
+     */
+    public short getIdleAge() {
+        return idleAge;
+    }
+
+    /**
+     * @param idleAge the idleAge to set
+     */
+    public void setIdleAge(short idleAge) {
+        this.idleAge = idleAge;
+    }
+
+    /**
+     * @return the hardAge
+     */
+    public short getHardAge() {
+        return hardAge;
+    }
+
+    /**
+     * @param hardAge the hardAge to set
+     */
+    public void setHardAge(short hardAge) {
+        this.hardAge = hardAge;
+    }
+
+    /**
+     * @return the cookie
+     */
+    public long getCookie() {
+        return cookie;
+    }
+
+    /**
+     * @param cookie the cookie to set
+     */
+    public void setCookie(long cookie) {
+        this.cookie = cookie;
+    }
+
+    /**
+     * @return the packetCount
+     */
+    public long getPacketCount() {
+        return packetCount;
+    }
+
+    /**
+     * @param packetCount the packetCount to set
+     */
+    public void setPacketCount(long packetCount) {
+        this.packetCount = packetCount;
+    }
+
+    /**
+     * @return the byteCount
+     */
+    public long getByteCount() {
+        return byteCount;
+    }
+
+    /**
+     * @param byteCount the byteCount to set
+     */
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    /**
+     * @param length the length to set
+     */
+    public void setLength(short length) {
+        this.length = length;
+    }
+
+    @Override
+    public int getLength() {
+        return U16.f(length);
+    }
+
+    /**
+     * @return the match
+     */
+    public V6Match getMatch() {
+        return match;
+    }
+
+    /**
+     * @return the actions
+     */
+    public List<OFAction> getActions() {
+        return actions;
+    }
+
+    /**
+     * @param actions the actions to set
+     */
+    public void setActions(List<OFAction> actions) {
+        this.actions = actions;
+    }
+
+    /*
+    @Override
+    public void readFrom(ByteBuffer data) {
+        short i;
+        this.length = data.getShort();
+        if (length < MINIMUM_LENGTH)
+            return; //TBD - Spurious Packet?
+        this.tableId = data.get();
+        data.get(); // pad
+        this.durationSeconds = data.getInt();
+        this.durationNanoseconds = data.getInt();
+        this.priority = data.getShort();
+        this.idleTimeout = data.getShort();
+        this.hardTimeout = data.getShort();
+        this.match_len = data.getShort();
+        this.idleAge = data.getShort();
+        this.hardAge = data.getShort();
+        this.cookie = data.getLong();
+        this.packetCount = data.getLong();
+        this.byteCount = data.getLong();
+        if (this.length == MINIMUM_LENGTH) {
+            return; //TBD - can this happen??
+        }
+        if (this.match == null)
+            this.match = new V6Match();
+        ByteBuffer mbuf = ByteBuffer.allocate(match_len);
+        for (i = 0; i < match_len; i++) {
+            mbuf.put(data.get());
+        }
+        mbuf.rewind();
+        this.match.readFrom(mbuf);
+        if (this.actionFactory == null)
+            throw new RuntimeException("OFActionFactory not set");
+        /*
+         * action list may be preceded by a padding of 0 to 7 bytes based upon this:
+         */
+    /*
+        short pad_size = (short) (((match_len + 7) / 8) * 8 - match_len);
+        for (i = 0; i < pad_size; i++)
+            data.get();
+        int action_len = this.length - MINIMUM_LENGTH - (match_len + pad_size);
+        if (action_len > 0)
+            this.actions = this.actionFactory.parseActions(data, action_len);
+    }
+*/
+
+    /*
+    @Override
+    public void writeTo(ByteBuffer data) {
+        super.writeTo(data);//TBD. This Fn needs work. Should never get called though.
+
+    }
+    */
+
+    @Override
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+
+    @Override
+    public String toString() {
+        return "V6StatsReply[" + ReflectionToStringBuilder.toString(this) + "]";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6StatsRequest.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6StatsRequest.java
new file mode 100644 (file)
index 0000000..97d5550
--- /dev/null
@@ -0,0 +1,158 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openflow.protocol.statistics.OFVendorStatistics;
+import java.nio.ByteBuffer;
+
+
+/**
+ * This Class creates the OpenFlow Vendor Extension IPv6 Flow Stats Request
+ * messages and also reads the Reply of a stats request message.
+ *
+ */
+
+public class V6StatsRequest extends OFVendorStatistics {
+    private static final long serialVersionUID = 1L;
+    protected int msgsubtype;
+    protected short outPort;
+    protected short match_len;
+    protected byte tableId;
+
+    public static final int NICIRA_VENDOR_ID = 0x00002320; //Nicira ID
+    private static final int NXST_FLOW = 0x0; //Nicira Flow Stats Request Id
+
+    public V6StatsRequest() {
+        this.vendor = NICIRA_VENDOR_ID;
+        this.msgsubtype = NXST_FLOW;
+        this.match_len = 0;
+    }
+
+    /**
+     * @param None. Being set with local variable (TBD).
+     */
+    public void setVendorId() {
+        this.vendor = NICIRA_VENDOR_ID;
+    }
+
+    /**
+     * @return vendor id
+     */
+    public int getVendorId() {
+        return vendor;
+    }
+
+    /**
+     * @param None. Being set with local variable (TBD).
+     */
+    public void setMsgtype() {
+        this.msgsubtype = NXST_FLOW;
+    }
+
+    /**
+     * @return vendor_msgtype
+     */
+    public int getMsgtype() {
+        return msgsubtype;
+    }
+
+    /**
+     * @param outPort the outPort to set
+     */
+    public void setOutPort(short outPort) {
+        this.outPort = outPort;
+    }
+
+    /**
+     * @return the outPort
+     */
+    public short getOutPort() {
+        return outPort;
+    }
+
+    /**
+     * @param match_len the match_len to set
+     */
+    public void setMatchLen(short match_len) {
+        this.match_len = match_len;
+    }
+
+    /**
+     * @return the match_len
+     */
+    public short getMatchLen() {
+        return match_len;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    @Override
+    public int getLength() {
+        return 20;// 4(vendor)+4(msgsubtype)+4(pad)+2(outPort)+2(match_len)+1(tableid)+3(pad)
+    }
+
+    /*
+    @Override
+    public void readFrom(ByteBuffer data) {
+        this.vendor = data.getInt();
+        this.msgsubtype = data.getInt();
+        data.getInt();//pad 4 bytes
+        this.outPort = data.getShort();
+        this.match_len = data.getShort();
+        this.tableId = data.get();
+        for (int i = 0; i < 3; i++)
+            data.get();//pad byte
+
+    }
+
+    @Override
+    public void writeTo(ByteBuffer data) {
+        data.putInt(this.vendor);
+        data.putInt(this.msgsubtype);
+        data.putInt((int) 0x0);//pad0
+        data.putShort(this.outPort);
+        data.putShort(this.match_len);
+        data.put(this.tableId);
+        for (int i = 0; i < 3; i++)
+            data.put((byte) 0x0);//pad byte
+    }
+    */
+
+    @Override
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+
+    @Override
+    public String toString() {
+        return "V6StatsRequest[" + ReflectionToStringBuilder.toString(this)
+                + "]";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerServiceTest.java b/opendaylight/protocol_plugins/openflow_netty/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerServiceTest.java
new file mode 100644 (file)
index 0000000..c314439
--- /dev/null
@@ -0,0 +1,363 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.protocol_plugin.openflow.internal.FlowConverter;
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.action.OFAction;
+
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.Flood;
+import org.opendaylight.controller.sal.action.FloodAll;
+import org.opendaylight.controller.sal.action.HwPath;
+import org.opendaylight.controller.sal.action.Loopback;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.action.PopVlan;
+import org.opendaylight.controller.sal.action.SetDlDst;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+import org.opendaylight.controller.sal.action.SetNwDst;
+import org.opendaylight.controller.sal.action.SetNwSrc;
+import org.opendaylight.controller.sal.action.SetNwTos;
+import org.opendaylight.controller.sal.action.SetTpDst;
+import org.opendaylight.controller.sal.action.SetTpSrc;
+import org.opendaylight.controller.sal.action.SetVlanId;
+import org.opendaylight.controller.sal.action.SwPath;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+
+public class FlowProgrammerServiceTest {
+
+    @Test
+    public void testSALtoOFFlowConverter() throws UnknownHostException {
+        Node node = NodeCreator.createOFNode(1000l);
+        NodeConnector port = NodeConnectorCreator.createNodeConnector(
+                (short) 24, node);
+        NodeConnector oport = NodeConnectorCreator.createNodeConnector(
+                (short) 30, node);
+        byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
+                (byte) 0x9a, (byte) 0xbc };
+        byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
+                (byte) 0x5e, (byte) 0x6f };
+        InetAddress srcIP = InetAddress.getByName("172.28.30.50");
+        InetAddress dstIP = InetAddress.getByName("171.71.9.52");
+        InetAddress ipMask = InetAddress.getByName("255.255.255.0");
+        short ethertype = EtherTypes.IPv4.shortValue();
+        short vlan = (short) 27;
+        byte vlanPr = 3;
+        Byte tos = 4;
+        byte proto = IPProtocols.TCP.byteValue();
+        short src = (short) 55000;
+        short dst = 80;
+
+        /*
+         * Create a SAL Flow aFlow
+         */
+        Match match = new Match();
+        match.setField(MatchType.IN_PORT, port);
+        match.setField(MatchType.DL_SRC, srcMac);
+        match.setField(MatchType.DL_DST, dstMac);
+        match.setField(MatchType.DL_TYPE, ethertype);
+        match.setField(MatchType.DL_VLAN, vlan);
+        match.setField(MatchType.DL_VLAN_PR, vlanPr);
+        match.setField(MatchType.NW_SRC, srcIP, ipMask);
+        match.setField(MatchType.NW_DST, dstIP, ipMask);
+        match.setField(MatchType.NW_TOS, tos);
+        match.setField(MatchType.NW_PROTO, proto);
+        match.setField(MatchType.TP_SRC, src);
+        match.setField(MatchType.TP_DST, dst);
+
+        Assert.assertTrue(match.isIPv4());
+
+        List<Action> actions = new ArrayList<Action>();
+        // Setting all the actions supported by of
+        actions.add(new PopVlan());
+        actions.add(new Output(oport));
+        actions.add(new Flood());
+        actions.add(new FloodAll());
+        actions.add(new SwPath());
+        actions.add(new HwPath());
+        actions.add(new Loopback());
+        byte mac[] = { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5 };
+        actions.add(new SetDlSrc(mac));
+        actions.add(new SetDlDst(mac));
+        actions.add(new SetNwSrc(dstIP));
+        actions.add(new SetNwDst(srcIP));
+        actions.add(new SetNwTos(3));
+        actions.add(new SetTpSrc(10));
+        actions.add(new SetTpDst(20));
+        actions.add(new SetVlanId(200));
+
+        Flow aFlow = new Flow(match, actions);
+
+        /*
+         * Convert the SAL aFlow to OF Flow
+         */
+        FlowConverter salToOF = new FlowConverter(aFlow);
+        OFMatch ofMatch = salToOF.getOFMatch();
+        List<OFAction> ofActions = salToOF.getOFActions();
+
+        /*
+         * Convert the OF Flow to SAL Flow bFlow
+         */
+        FlowConverter ofToSal = new FlowConverter(ofMatch, ofActions);
+        Flow bFlow = ofToSal.getFlow(node);
+        Match bMatch = bFlow.getMatch();
+        List<Action> bActions = bFlow.getActions();
+
+        /*
+         * Verify the converted SAL flow bFlow is equivalent to the original SAL Flow
+         */
+        Assert.assertTrue(((NodeConnector) match.getField(MatchType.IN_PORT)
+                .getValue()).equals(((NodeConnector) bMatch.getField(
+                MatchType.IN_PORT).getValue())));
+        Assert.assertTrue(Arrays.equals((byte[]) match.getField(
+                MatchType.DL_SRC).getValue(), (byte[]) bMatch.getField(
+                MatchType.DL_SRC).getValue()));
+        Assert.assertTrue(Arrays.equals((byte[]) match.getField(
+                MatchType.DL_DST).getValue(), (byte[]) bMatch.getField(
+                MatchType.DL_DST).getValue()));
+        Assert
+                .assertTrue(((Short) match.getField(MatchType.DL_TYPE)
+                        .getValue()).equals((Short) bMatch.getField(
+                        MatchType.DL_TYPE).getValue()));
+        Assert
+                .assertTrue(((Short) match.getField(MatchType.DL_VLAN)
+                        .getValue()).equals((Short) bMatch.getField(
+                        MatchType.DL_VLAN).getValue()));
+        Assert.assertTrue(((Byte) match.getField(MatchType.DL_VLAN_PR)
+                .getValue()).equals((Byte) bMatch
+                .getField(MatchType.DL_VLAN_PR).getValue()));
+        Assert.assertTrue(((InetAddress) match.getField(MatchType.NW_SRC)
+                .getValue()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_SRC).getValue()));
+        Assert.assertTrue(((InetAddress) match.getField(MatchType.NW_SRC)
+                .getMask()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_SRC).getMask()));
+        Assert.assertTrue(((InetAddress) match.getField(MatchType.NW_DST)
+                .getValue()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_DST).getValue()));
+        Assert.assertTrue(((InetAddress) match.getField(MatchType.NW_DST)
+                .getMask()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_DST).getMask()));
+        Assert
+                .assertTrue(((Byte) match.getField(MatchType.NW_PROTO)
+                        .getValue()).equals((Byte) bMatch.getField(
+                        MatchType.NW_PROTO).getValue()));
+        Assert.assertTrue(((Byte) match.getField(MatchType.NW_TOS).getValue())
+                .equals((Byte) bMatch.getField(MatchType.NW_TOS).getValue()));
+        Assert.assertTrue(((Short) match.getField(MatchType.TP_SRC).getValue())
+                .equals((Short) bMatch.getField(MatchType.TP_SRC).getValue()));
+        Assert.assertTrue(((Short) match.getField(MatchType.TP_DST).getValue())
+                .equals((Short) bMatch.getField(MatchType.TP_DST).getValue()));
+
+        // FlowConverter parses and sets the actions in the same order for sal match and of match
+        for (short i = 0; i < actions.size(); i++) {
+            Assert.assertTrue(actions.get(i).equals(bActions.get(i)));
+        }
+    }
+
+
+    @Ignore
+    public void testV6toSALFlowConversion() throws Exception {
+        Node node = NodeCreator.createOFNode(12l);
+        NodeConnector port = NodeConnectorCreator.createNodeConnector(
+                (short) 34, node);
+        NodeConnector oport = NodeConnectorCreator.createNodeConnector(
+                (short) 30, node);
+        byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
+                (byte) 0x9a, (byte) 0xbc };
+        byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
+                (byte) 0x5e, (byte) 0x6f };
+        InetAddress srcIP = InetAddress
+                .getByName("2001:420:281:1004:407a:57f4:4d15:c355");
+        InetAddress dstIP = InetAddress
+                .getByName("2001:420:281:1004:e123:e688:d655:a1b0");
+        InetAddress ipMask = InetAddress
+                .getByName("ffff:ffff:ffff:ffff:0:0:0:0");
+        short ethertype = EtherTypes.IPv6.shortValue();
+        short vlan = (short) 27;
+        byte vlanPr = 3;
+        Byte tos = 4;
+        byte proto = IPProtocols.TCP.byteValue();
+        short src = (short) 55000;
+        short dst = 80;
+
+        /*
+         * Create a SAL Flow aFlow
+         */
+        Match aMatch = new Match();
+
+        aMatch.setField(MatchType.IN_PORT, port);
+        aMatch.setField(MatchType.DL_SRC, srcMac);
+        aMatch.setField(MatchType.DL_DST, dstMac);
+        aMatch.setField(MatchType.DL_TYPE, ethertype);
+        aMatch.setField(MatchType.DL_VLAN, vlan);
+        aMatch.setField(MatchType.DL_VLAN_PR, vlanPr);
+        aMatch.setField(MatchType.NW_SRC, srcIP, ipMask);
+        aMatch.setField(MatchType.NW_DST, dstIP, ipMask);
+        aMatch.setField(MatchType.NW_TOS, tos);
+        aMatch.setField(MatchType.NW_PROTO, proto);
+        aMatch.setField(MatchType.TP_SRC, src);
+        aMatch.setField(MatchType.TP_DST, dst);
+
+        Assert.assertTrue(aMatch.isIPv6());
+
+        List<Action> actions = new ArrayList<Action>();
+        // Setting all the actions supported by of for v6
+        actions.add(new PopVlan());
+        actions.add(new Output(oport));
+        actions.add(new Flood());
+        actions.add(new FloodAll());
+        actions.add(new SwPath());
+        actions.add(new HwPath());
+        actions.add(new Loopback());
+        byte mac[] = { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5 };
+        actions.add(new SetDlSrc(mac));
+        actions.add(new SetDlDst(mac));
+        //actions.add(new SetNwSrc(dstIP)); Nicira extensions do not provide IPv6 match addresses change
+        //actions.add(new SetNwDst(srcIP));
+        actions.add(new SetNwTos(3));
+        actions.add(new SetTpSrc(10));
+        actions.add(new SetTpDst(65535));
+        actions.add(new SetVlanId(200));
+
+        Flow aFlow = new Flow(aMatch, actions);
+
+        /*
+         * Convert the SAL aFlow to OF Flow
+         */
+        FlowConverter salToOF = new FlowConverter(aFlow);
+        V6Match v6Match = (V6Match) salToOF.getOFMatch();
+        List<OFAction> ofActions = salToOF.getOFActions();
+
+        /*
+         * Convert the OF Flow to SAL Flow bFlow
+         */
+        FlowConverter ofToSal = new FlowConverter(v6Match, ofActions);
+        Flow bFlow = ofToSal.getFlow(node);
+        Match bMatch = bFlow.getMatch();
+        List<Action> bActions = bFlow.getActions();
+
+        /*
+         * Verify the converted SAL flow bFlow is equivalent to the original SAL Flow
+         */
+        Assert.assertTrue(((NodeConnector) aMatch.getField(MatchType.IN_PORT)
+                .getValue()).equals(((NodeConnector) bMatch.getField(
+                MatchType.IN_PORT).getValue())));
+        Assert.assertTrue(Arrays.equals((byte[]) aMatch.getField(
+                MatchType.DL_SRC).getValue(), (byte[]) bMatch.getField(
+                MatchType.DL_SRC).getValue()));
+        Assert.assertTrue(Arrays.equals((byte[]) aMatch.getField(
+                MatchType.DL_DST).getValue(), (byte[]) bMatch.getField(
+                MatchType.DL_DST).getValue()));
+        Assert.assertTrue(((Short) aMatch.getField(MatchType.DL_TYPE)
+                .getValue()).equals((Short) bMatch.getField(MatchType.DL_TYPE)
+                .getValue()));
+        Assert.assertTrue(((Short) aMatch.getField(MatchType.DL_VLAN)
+                .getValue()).equals((Short) bMatch.getField(MatchType.DL_VLAN)
+                .getValue()));
+        Assert.assertTrue(((Byte) aMatch.getField(MatchType.DL_VLAN_PR)
+                .getValue()).equals((Byte) bMatch
+                .getField(MatchType.DL_VLAN_PR).getValue()));
+        Assert.assertTrue(((InetAddress) aMatch.getField(MatchType.NW_SRC)
+                .getValue()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_SRC).getValue()));
+        Assert.assertTrue(((InetAddress) aMatch.getField(MatchType.NW_SRC)
+                .getMask()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_SRC).getMask()));
+        Assert.assertTrue(((InetAddress) aMatch.getField(MatchType.NW_DST)
+                .getValue()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_DST).getValue()));
+        Assert.assertTrue(((InetAddress) aMatch.getField(MatchType.NW_DST)
+                .getMask()).equals((InetAddress) bMatch.getField(
+                MatchType.NW_DST).getMask()));
+        Assert.assertTrue(((Byte) aMatch.getField(MatchType.NW_PROTO)
+                .getValue()).equals((Byte) bMatch.getField(MatchType.NW_PROTO)
+                .getValue()));
+        Assert.assertTrue(((Byte) aMatch.getField(MatchType.NW_TOS).getValue())
+                .equals((Byte) bMatch.getField(MatchType.NW_TOS).getValue()));
+        Assert
+                .assertTrue(((Short) aMatch.getField(MatchType.TP_SRC)
+                        .getValue()).equals((Short) bMatch.getField(
+                        MatchType.TP_SRC).getValue()));
+        Assert
+                .assertTrue(((Short) aMatch.getField(MatchType.TP_DST)
+                        .getValue()).equals((Short) bMatch.getField(
+                        MatchType.TP_DST).getValue()));
+
+        // FlowConverter parses and sets the actions in the same order for sal match and of match
+        for (short i = 0; i < actions.size(); i++) {
+            Assert.assertTrue(actions.get(i).equals(bActions.get(i)));
+        }
+    }
+
+
+    @Ignore
+    public void testV6MatchToSALMatchToV6MatchConversion()
+            throws UnknownHostException {
+        NodeConnector port = NodeConnectorCreator.createNodeConnector(
+                (short) 24, NodeCreator.createOFNode(6l));
+        byte srcMac[] = { (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78,
+                (byte) 0x9a, (byte) 0xbc };
+        byte dstMac[] = { (byte) 0x1a, (byte) 0x2b, (byte) 0x3c, (byte) 0x4d,
+                (byte) 0x5e, (byte) 0x6f };
+        InetAddress srcIP = InetAddress
+                .getByName("2001:420:281:1004:407a:57f4:4d15:c355");
+        InetAddress dstIP = InetAddress
+                .getByName("2001:420:281:1004:e123:e688:d655:a1b0");
+        InetAddress ipMask = null;//InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0");
+        short ethertype = EtherTypes.IPv6.shortValue();
+        short vlan = (short) 27;
+        byte vlanPr = 3;
+        Byte tos = 4;
+        byte proto = IPProtocols.TCP.byteValue();
+        short src = (short) 55000;
+        short dst = 80;
+
+        /*
+         * Create a SAL Flow aFlow
+         */
+        Match aMatch = new Match();
+
+        aMatch.setField(MatchType.IN_PORT, port);
+        aMatch.setField(MatchType.DL_SRC, srcMac);
+        aMatch.setField(MatchType.DL_DST, dstMac);
+        aMatch.setField(MatchType.DL_TYPE, ethertype);
+        aMatch.setField(MatchType.DL_VLAN, vlan);
+        aMatch.setField(MatchType.DL_VLAN_PR, vlanPr);
+        aMatch.setField(MatchType.NW_SRC, srcIP, ipMask);
+        aMatch.setField(MatchType.NW_DST, dstIP, ipMask);
+        aMatch.setField(MatchType.NW_TOS, tos);
+        aMatch.setField(MatchType.NW_PROTO, proto);
+        aMatch.setField(MatchType.TP_SRC, src);
+        aMatch.setField(MatchType.TP_DST, dst);
+
+        Assert.assertTrue(aMatch.isIPv6());
+
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java b/opendaylight/protocol_plugins/openflow_netty/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java
new file mode 100644 (file)
index 0000000..17e3362
--- /dev/null
@@ -0,0 +1,224 @@
+package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension;
+
+import static org.junit.Assert.fail;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
+import org.openflow.protocol.OFMatch;
+
+public class V6ExtensionTest {
+
+    /*
+    @Test
+    public void testFromString() throws UnknownHostException {
+
+        // This tests creating V6Match using fromString and OFMatch by comparing
+        // the results to each other
+        V6Match match = new V6Match();
+        V6Match match2 = new V6Match();
+
+        OFMatch ofm = new OFMatch();
+        V6Match match4 = new V6Match(ofm);
+
+        match.fromString("");
+        Assert.assertTrue(match.equals(match2));
+        match.fromString("any");
+        Assert.assertTrue(match.equals(match2));
+        Assert.assertTrue(match.equals(match4));
+        try {
+            match.fromString("invalidArgument");
+
+            fail("Did not throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // passed test for throwing exception.
+        }
+        try {
+            match.fromString("invalidParameter=abcdefg");
+            fail("Did not throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // passed test for throwing exception.
+        }
+
+        match.fromString("input_port=1");
+        match.fromString("dl_dst=20:A0:11:10:00:99");
+        match.fromString("dl_src=00:10:08:22:12:75");
+
+        match.fromString("ip_src=10.1.1.1");
+        match.fromString("ip_dst=1.2.3.4");
+        match.fromString("eth_type=0x800");
+        match.fromString("dl_vlan=10");
+        match.fromString("dl_vpcp=1");
+        match.fromString("nw_proto=6");
+        match.fromString("nw_tos=100");
+        match.fromString("tp_dst=8080");
+        match.fromString("tp_src=60");
+
+        Assert.assertTrue(match.getInputPort() == 1);
+        // Assert.assertTrue(match.getIPv6MatchLen()==6);
+
+        ofm.setInputPort((short) 1);
+        // V6Match is meant for IPv6, but if using OFMatch, it will be set to
+        // IPv4 values, as OF1.0 doesn't support IPv6.
+        InetAddress addr = InetAddress.getByName("10.1.1.1");
+        int ipsrc = ByteBuffer.wrap(addr.getAddress()).getInt();
+        ofm.setNetworkSource(ipsrc);
+
+        addr = InetAddress.getByName("1.2.3.4");
+        int ipdst = ByteBuffer.wrap(addr.getAddress()).getInt();
+        ofm.setNetworkDestination(ipdst);
+
+        byte[] macSrc = { 0x00, 0x10, 0x08, 0x22, 0x12, 0x75 };
+        ofm.setDataLayerSource(macSrc);
+        byte[] macDst = { 0x20, (byte) 0xA0, 0x11, 0x10, 0x00, (byte) 0x99 };
+        ofm.setDataLayerDestination(macDst);
+        ofm.setDataLayerType((short) 0x800);
+        ofm.setDataLayerVirtualLan((short) 10);
+        ofm.setDataLayerVirtualLanPriorityCodePoint((byte) 1);
+        ofm.setNetworkProtocol((byte) 6);
+        ofm.setNetworkTypeOfService((byte) 100);
+        ofm.setTransportSource((short) 60);
+        ofm.setTransportDestination((short) 8080);
+
+        V6Match match3 = new V6Match(ofm);
+
+        Assert.assertTrue(match.getInputPort() == match3.getInputPort());
+        Assert.assertTrue(Arrays.equals(match.getDataLayerSource(),
+                match3.getDataLayerSource()));
+        Assert.assertTrue(Arrays.equals(match.getDataLayerDestination(),
+                match3.getDataLayerDestination()));
+        Assert.assertTrue(match.getNetworkSrc().equals(match3.getNetworkSrc()));
+        Assert.assertTrue(match.getNetworkDest()
+                .equals(match3.getNetworkDest()));
+        Assert.assertTrue(match.getDataLayerVirtualLan() == match3
+                .getDataLayerVirtualLan());
+        Assert.assertTrue(match.getDataLayerVirtualLanPriorityCodePoint() == match3
+                .getDataLayerVirtualLanPriorityCodePoint());
+        Assert.assertTrue(match.getNetworkProtocol() == match3
+                .getNetworkProtocol());
+        Assert.assertTrue(match.getNetworkTypeOfService() == match3
+                .getNetworkTypeOfService());
+        Assert.assertTrue(match.getTransportSource() == match3
+                .getTransportSource());
+        Assert.assertTrue(match.getTransportDestination() == match3
+                .getTransportDestination());
+        Assert.assertTrue(match.getWildcards() == match3.getWildcards());
+
+    }
+
+    @Test
+    public void testReadWriteBuffer() {
+        V6Match match = new V6Match();
+        match.fromString("input_port=1");
+        match.fromString("dl_dst=20:A0:11:10:00:99");
+        match.fromString("dl_src=00:10:08:22:12:75");
+        // writeTo(ByteBuffer) will only write IPv6
+        match.fromString("ip_src=2001:ddd:3e1:1234:0000:1111:2222:3333/64");
+        match.fromString("ip_dst=2001:123:222:abc:111:aaa:1111:2222/64");
+        match.fromString("dl_vlan=10");
+        match.fromString("nw_proto=6");
+        match.fromString("nw_tos=100");
+        match.fromString("tp_dst=8080");
+        match.fromString("tp_src=60");
+        match.fromString("dl_type=0x800");
+
+        ByteBuffer data = ByteBuffer.allocateDirect(10000);
+        match.writeTo(data);
+        data.flip();
+        V6Match match2 = new V6Match();
+        match2.readFrom(data);
+        Assert.assertTrue(match.getInputPort() == match2.getInputPort());
+        Assert.assertTrue(Arrays.equals(match.getDataLayerSource(),
+                match2.getDataLayerSource()));
+        Assert.assertTrue(Arrays.equals(match.getDataLayerDestination(),
+                match2.getDataLayerDestination()));
+
+        Assert.assertTrue(match.getNetworkSrc().equals(match2.getNetworkSrc()));
+        Assert.assertTrue(match.getNetworkDest()
+                .equals(match2.getNetworkDest()));
+
+        Assert.assertTrue(match.getDataLayerVirtualLan() == match2
+                .getDataLayerVirtualLan());
+        // vlan pcp isn't part of write/read buffer
+        Assert.assertTrue(match.getNetworkProtocol() == match2
+                .getNetworkProtocol());
+        Assert.assertTrue(match.getNetworkTypeOfService() == match2
+                .getNetworkTypeOfService());
+        Assert.assertTrue(match.getTransportSource() == match2
+                .getTransportSource());
+        Assert.assertTrue(match.getTransportDestination() == match2
+                .getTransportDestination());
+
+    }
+
+    @Test
+    public void testClone() {
+        V6Match match = new V6Match();
+        match.fromString("input_port=1");
+        match.fromString("dl_dst=20:A0:11:10:00:99");
+        match.fromString("dl_src=00:10:08:22:12:75");
+        match.fromString("ip_src=2001:ddd:3e1:1234:0000:1111:2222:3333/64");
+        match.fromString("ip_dst=2001:123:222:abc:111:aaa:1111:2222/64");
+        match.fromString("dl_vlan=10");
+        match.fromString("dl_vpcp=1");
+        match.fromString("nw_proto=6");
+        match.fromString("nw_tos=100");
+        match.fromString("tp_dst=8080");
+        match.fromString("tp_src=60");
+        match.fromString("dl_type=0x800");
+
+        V6Match match2 = match.clone();
+        Assert.assertTrue(match.getInputPort() == match2.getInputPort());
+        Assert.assertTrue(Arrays.equals(match.getDataLayerSource(),
+                match2.getDataLayerSource()));
+        Assert.assertTrue(Arrays.equals(match.getDataLayerDestination(),
+                match2.getDataLayerDestination()));
+        Assert.assertTrue(match.getNetworkSrc().equals(match2.getNetworkSrc()));
+        Assert.assertTrue(match.getNetworkDest()
+                .equals(match2.getNetworkDest()));
+        Assert.assertTrue(match.getDataLayerVirtualLan() == match2
+                .getDataLayerVirtualLan());
+        Assert.assertTrue(match.getDataLayerVirtualLanPriorityCodePoint() == match2
+                .getDataLayerVirtualLanPriorityCodePoint());
+        Assert.assertTrue(match.getNetworkProtocol() == match2
+                .getNetworkProtocol());
+        Assert.assertTrue(match.getNetworkTypeOfService() == match2
+                .getNetworkTypeOfService());
+        Assert.assertTrue(match.getTransportSource() == match2
+                .getTransportSource());
+        Assert.assertTrue(match.getTransportDestination() == match2
+                .getTransportDestination());
+        Assert.assertTrue(match.getWildcards() == match2.getWildcards());
+    }
+
+    @Test
+    public void testPadding() {
+        // testing that matchlen+pad keeps the 8byte alignment
+        V6Match match = new V6Match();
+
+        match.fromString("input_port=1");
+        Assert.assertTrue((match.getPadSize() + match.getIPv6MatchLen()) % 8 == 0);
+        match.fromString("dl_dst=20:A0:11:10:00:99");
+        match.fromString("dl_src=00:10:08:22:12:75");
+        Assert.assertTrue((match.getPadSize() + match.getIPv6MatchLen()) % 8 == 0);
+        match.fromString("ip_src=2001:ddd:3e1:1234:0000:1111:2222:3333");
+        Assert.assertTrue((match.getPadSize() + match.getIPv6MatchLen()) % 8 == 0);
+        match.fromString("ip_dst=2001:123:222:abc:111:aaa:1111:2222");
+        Assert.assertTrue((match.getPadSize() + match.getIPv6MatchLen()) % 8 == 0);
+        match.fromString("dl_vlan=10");
+        match.fromString("dl_vpcp=1");
+        match.fromString("nw_proto=6");
+        Assert.assertTrue((match.getPadSize() + match.getIPv6MatchLen()) % 8 == 0);
+        match.fromString("nw_tos=100");
+        match.fromString("tp_dst=8080");
+        Assert.assertTrue((match.getPadSize() + match.getIPv6MatchLen()) % 8 == 0);
+        match.fromString("tp_src=60");
+        Assert.assertTrue((match.getPadSize() + match.getIPv6MatchLen()) % 8 == 0);
+    }
+    */
+
+}
index dc23940d55ae6cf4ef30a96ac0b35dd2bdab1bb8..38fd72f348c43a3c9551d13518bcb1baa62d0efa 100644 (file)
@@ -43,7 +43,6 @@
               org.opendaylight.controller.containermanager,
               org.opendaylight.controller.switchmanager,
               org.apache.commons.logging,
-              com.sun.jersey.spi.container.servlet,
               org.opendaylight.controller.northbound.commons,
               org.opendaylight.controller.northbound.commons.exception,
               javax.ws.rs,
diff --git a/opendaylight/samples/reactiveforwarding/pom.xml b/opendaylight/samples/reactiveforwarding/pom.xml
new file mode 100644 (file)
index 0000000..28d578b
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+  <groupId>org.opendaylight.controller</groupId>
+  <artifactId>samples.reactiveforwarding</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+            </Export-Package>
+            <Import-Package>
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.sal.action,
+              org.opendaylight.controller.sal.match,
+              org.opendaylight.controller.sal.packet,
+              org.opendaylight.controller.sal.routing,
+              org.opendaylight.controller.sal.flowprogrammer,
+              org.opendaylight.controller.sal.packet.address,
+              org.opendaylight.controller.hosttracker,
+              org.opendaylight.controller.hosttracker.hostAware,
+              org.opendaylight.controller.topologymanager,
+              org.opendaylight.controller.forwardingrulesmanager,
+              org.opendaylight.controller.switchmanager,
+              org.opendaylight.controller.clustering.services,
+              javax.xml.bind.annotation,
+              javax.xml.bind,
+              org.apache.felix.dm,
+              org.apache.commons.lang3,
+              org.apache.commons.lang3.builder,
+              org.osgi.service.component,
+              org.slf4j,
+              org.eclipse.osgi.framework.console,
+              org.osgi.framework
+            </Import-Package>
+            <Bundle-Activator>
+              org.opendaylight.controller.samples.reactiveforwarding.internal.Activator
+            </Bundle-Activator>
+            <Service-Component>
+            </Service-Component>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>topologymanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>switchmanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>forwardingrulesmanager</artifactId>
+          <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>hosttracker</artifactId>
+          <version>0.4.0-SNAPSHOT</version>
+      </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/LBConst.java b/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/LBConst.java
new file mode 100644 (file)
index 0000000..ca88b11
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.reactiveforwarding;
+
+/**
+ * Class defines all the constants used by load balancer service
+ *
+ */
+public class LBConst {
+
+    public static final int FORWARD_DIRECTION_LB_FLOW = 0;
+
+    public static final int REVERSE_DIRECTION_LB_FLOW = 1;
+
+    public static final String ROUND_ROBIN_LB_METHOD = "roundrobin";
+
+    public static final String RANDOM_LB_METHOD = "random";
+
+    public static final String STATUS_ACTIVE="active";
+
+    public static final String STATUS_INACTIVE="inactive";
+
+    public static final String STATUS_PENDING="pending";
+
+    public static final String STATUS_ERROR="error";
+
+}
+
diff --git a/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/LBUtil.java b/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/LBUtil.java
new file mode 100644 (file)
index 0000000..9c45bd8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.reactiveforwarding;
+
+import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.TCP;
+import org.opendaylight.controller.sal.packet.UDP;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.samples.reactiveforwarding.entities.Client;
+import org.opendaylight.controller.samples.reactiveforwarding.entities.VIP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class defines utilty methods that will be used by different components
+ * of the load balancer service
+ *
+ */
+public class LBUtil {
+
+    private static final Logger lbuLogger = LoggerFactory.getLogger(LBUtil.class);
+
+    public LBUtil(){}
+
+    /**
+     * Extract the details of the source machine that sent this packet 'inPkt'
+     * @param inPkt Packet that is received by the controller
+     * @return Details of the source machine in Client object.
+     */
+    public Client getClientFromPacket(IPv4 inPkt){
+        lbuLogger.info("Find client information from packet : {}",inPkt.toString());
+
+        String ip = NetUtils.getInetAddress(inPkt.getSourceAddress()).getHostAddress();
+
+        String protocol = IPProtocols.getProtocolName(inPkt.getProtocol());
+
+        lbuLogger.info("client ip {} and protocl {}",ip,protocol);
+
+        Packet tpFrame= inPkt.getPayload();
+
+        lbuLogger.info("Get protocol layer {}",tpFrame.toString());
+
+        short port = 0;
+
+        if(protocol.equals(IPProtocols.TCP.toString())){
+            TCP tcpFrame = (TCP)tpFrame;
+            port = tcpFrame.getSourcePort();
+        }else{
+            UDP udpFrame = (UDP)tpFrame;
+            port = udpFrame.getSourcePort();
+        }
+
+        lbuLogger.info("Found port {}",port);
+
+        Client source = new Client(ip, protocol,port);
+
+        lbuLogger.info("Client information : {}",source.toString());
+
+        return source;
+    }
+
+    /**
+     * Extract the details of the destination machine where this packet 'inPkt' need
+     * to be delivered
+     * @param inPkt Packet that is received by controller for forwarding
+     * @return Details of the destination machine packet in VIP
+     */
+    public VIP getVIPFromPacket(IPv4 inPkt){
+
+        lbuLogger.info("Find VIP information from packet : {}",inPkt.toString());
+
+        String ip = NetUtils.getInetAddress(inPkt.getDestinationAddress()).getHostAddress();
+
+        String protocol = IPProtocols.getProtocolName(inPkt.getProtocol());
+
+        Packet tpFrame= inPkt.getPayload();
+
+        short port = 0;
+
+        if(protocol.equals(IPProtocols.TCP.toString())){
+            TCP tcpFrame = (TCP)tpFrame;
+            port = tcpFrame.getDestinationPort();
+        }else{
+
+            UDP udpFrame = (UDP)tpFrame;
+            port = udpFrame.getDestinationPort();
+        }
+
+        VIP dest = new VIP(null,ip, protocol,port,null);
+
+        lbuLogger.info("VIP information : {}",dest.toString());
+
+        return dest;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/entities/Client.java b/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/entities/Client.java
new file mode 100644 (file)
index 0000000..55dfb68
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.reactiveforwarding.entities;
+
+/**
+ * This class represents the source host that sends any traffic to any existing virtual IP (VIP).
+ * This source host is referred to as a 'Client'. Clients will be differentiated from each other
+ * based on the following three properties:
+ * 1. IP address of the client.
+ * 2. Protocol of the traffic it is using for sending traffic
+ * 3. Source port from which it is sending traffic.
+ * e.g TCP traffic from two different ports from the same host to a given VIP will be considered
+ * as two different clients by this service. Similarly, traffic using two different protocols
+ * (TCP, UDP) from the same host will be considered as two different clients.
+ *
+ */
+public class Client {
+
+    /*
+     * IP address of the client (source address)
+     */
+    private String ip;
+
+    /*
+     * Network protocol of the traffic sent by client
+     */
+    private String protocol;
+
+    /*
+     * Port used to send network traffic (source port)
+     */
+    private short port;
+
+    public Client(String ip, String protocol, short port){
+        this.ip = ip;
+        this.protocol = protocol;
+        this.port = port;
+    }
+
+    /**
+     * @return the client IP
+     */
+    public String getIp() {
+        return ip;
+    }
+
+    /**
+     * @param ip the IP to set
+     */
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    /**
+     * @return the client network protocol
+     */
+    public String getProtocol() {
+        return protocol;
+    }
+
+    /**
+     * @param protocol the protocol to set
+     */
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    /**
+     * @return the client port
+     */
+    public short getPort() {
+        return port;
+    }
+
+    /**
+     * @param port the port to set
+     */
+    public void setPort(short port) {
+        this.port = port;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+        result = prime * result + port;
+        result = prime * result+ ((protocol == null) ? 0 : protocol.hashCode());
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Client)) {
+            return false;
+        }
+        Client other = (Client) obj;
+        if (ip == null) {
+            if (other.ip != null) {
+                return false;
+            }
+        }else if (!ip.equals(other.ip)) {
+            return false;
+        }
+        if (port != other.port) {
+            return false;
+        }
+        if (protocol == null) {
+            if (other.protocol != null) {
+                return false;
+            }
+        }else if (!protocol.equals(other.protocol)) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "Client [ip=" + ip + ", protocol=" + protocol + ", port=" + port+ "]";
+    }
+}
diff --git a/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/entities/VIP.java b/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/entities/VIP.java
new file mode 100644 (file)
index 0000000..75ed067
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.reactiveforwarding.entities;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * This class represents the Virtual IP  (VIP) address exposed by the load balancer application.
+ * Load balancer service differentiates one VIP from the other, using the following three properties:
+ * 1. IP address of the VIP exposed by the application
+ * 2. Protocol of the network traffic (TCP/UDP)
+ * 3. Port to which incoming traffic is destined
+ *
+ * User is allowed to create mutliple VIPs with the same IP, but all such VIPs (with the same IP)
+ * should differ at least in the protocol or port or both.
+ *
+ * NOTE: Each VIP should have a unique name.
+ */
+@XmlRootElement(name="vip")
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class VIP {
+
+    /*
+     * Unique name of the VIP
+     */
+    @XmlElement
+    private String name;
+
+    /*
+     * Virtual IP address of the VIP
+     */
+    @XmlElement
+    private String ip;
+
+    /*
+     * Network traffic protocol
+     */
+    @XmlElement
+    private String protocol;
+
+    /*
+     * Port where network traffic is destined (destination port)
+     */
+    @XmlElement
+    private short port;
+
+    /*
+     * Name of the pool attached to the VIP for load balancing its traffic
+     */
+    @XmlElement(name="poolname")
+    private String poolName;
+
+    /*
+     * Status (Active/inactive)
+     */
+    @XmlElement
+    private String status;
+
+    /**
+     * Private constructor used for JAXB mapping
+     */
+    @SuppressWarnings("unused")
+    private VIP() {}
+
+    public VIP(String name,
+                String ip,
+                String protocol,
+                short port,
+                String poolName){
+        this.name = name;
+        this.ip=ip;
+        this.protocol=protocol;
+        this.port = port;
+        this.poolName = poolName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public short getPort() {
+        return port;
+    }
+
+    public void setPort(short port) {
+        this.port = port;
+    }
+
+    public String getPoolName() {
+        return poolName;
+    }
+
+    public void setPoolName(String poolName) {
+        this.poolName = poolName;
+    }
+
+    /**
+     * @return the status
+     */
+    public String getStatus() {
+        return status;
+    }
+
+    /**
+     * @param status the status to set
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+        result = prime * result + port;
+        result = prime * result
+                + ((protocol == null) ? 0 : protocol.hashCode());
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof VIP)) {
+            return false;
+        }
+
+        VIP other = (VIP) obj;
+        if (ip == null) {
+            if (other.ip != null) {
+                return false;
+            }
+        }else if (!ip.equals(other.ip)) {
+            return false;
+        }
+        if (port != other.port) {
+            return false;
+        }
+        if (protocol == null) {
+            if (other.protocol != null) {
+                return false;
+            }
+        }else if (!protocol.equalsIgnoreCase(other.protocol)) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "VIP [name=" + name + ", ip=" + ip + ", protocol=" + protocol
+                            + ", port=" + port + ", poolName=" + poolName + ", status="
+                            + status + "]";
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/internal/Activator.java b/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/internal/Activator.java
new file mode 100644 (file)
index 0000000..f96075a
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.reactiveforwarding.internal;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.dm.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
+
+
+/**
+ * Main application activator class for registering the dependencies and
+ * initialising the load balancer application.
+ *
+ */
+
+public class Activator extends ComponentActivatorAbstractBase {
+
+    /*
+     * Logger instance
+     */
+    protected static final Logger logger = LoggerFactory.getLogger(Activator.class);
+
+    /**
+     * Function called when the activator starts just after some
+     * initializations are done by the
+     * ComponentActivatorAbstractBase.
+     *
+     */
+    public void init() {
+    }
+
+    /**
+     * Function called when the activator stops just before the
+     * cleanup done by ComponentActivatorAbstractBase
+     *
+     */
+    public void destroy() {
+    }
+
+    /**
+     * Function that is used to communicate to dependency manager the
+     * list of known implementations for services inside a container
+     *
+     *
+     * @return An array containing all the CLASS objects that will be
+     * instantiated in order to get an fully working implementation
+     * Object
+     */
+    public Object[] getImplementations() {
+        Object[] res = { ReactiveForwardingService.class };
+        return res;
+    }
+
+    /**
+     * Function that is called when configuration of the dependencies
+     * is required.
+     *
+     * @param c dependency manager Component object, used for
+     * configuring the dependencies exported and imported
+     * @param imp Implementation class that is being configured,
+     * needed as long as the same routine can configure multiple
+     * implementations
+     * @param containerName The containerName being configured, this allow
+     * also optional per-container different behavior if needed, usually
+     * should not be the case though.
+     */
+    public void configureInstance(Component c, Object imp, String containerName) {
+        if (imp.equals(ReactiveForwardingService.class)) {
+            // export the service
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "reactiveforwarding");
+
+            c.setInterface(new String[] { IListenDataPacket.class.getName() }, props);
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IDataPacketService.class).setCallbacks(
+                    "setDataPacketService", "unsetDataPacketService")
+                    .setRequired(true));
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IRouting.class).setCallbacks("setRouting", "unsetRouting")
+                    .setRequired(false));
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IfIptoHost.class).setCallbacks("setHostTracker",
+                    "unsetHostTracker").setRequired(true));
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IForwardingRulesManager.class).setCallbacks(
+                    "setForwardingRulesManager", "unsetForwardingRulesManager")
+                    .setRequired(true));
+        }
+    }
+
+    /**
+     * Method which tells how many Global implementations are
+     * supported by the bundle. This way we can tune the number of
+     * components created. This components will be created ONLY at the
+     * time of bundle startup and will be destroyed only at time of
+     * bundle destruction, this is the major difference with the
+     * implementation retrieved via getImplementations where all of
+     * them are assumed to be in a container !
+     *
+     *
+     * @return The list of implementations the bundle will support,
+     * in Global version
+     */
+    protected Object[] getGlobalImplementations() {
+        return null;
+    }
+
+    /**
+     * Configure the dependency for a given instance Global
+     *
+     * @param c Component assigned for this instance, this will be
+     * what will be used for configuration
+     * @param imp implementation to be configured
+     * @param containerName container on which the configuration happens
+     */
+    protected void configureGlobalInstance(Component c, Object imp) {
+    }
+}
diff --git a/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/internal/ReactiveForwardingService.java b/opendaylight/samples/reactiveforwarding/src/main/java/org/opendaylight/controller/samples/reactiveforwarding/internal/ReactiveForwardingService.java
new file mode 100644 (file)
index 0000000..d9c013c
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.samples.reactiveforwarding.internal;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.Drop;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.packet.ARP;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.packet.IPv4;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.PacketResult;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Plain simple reactive forwarding service which received PACKET_IN and
+ * uses Dijkstra's module (IRouting interface) to determine the shortest
+ * path between source and destination and provision the switches
+ *
+ */
+public class ReactiveForwardingService implements IListenDataPacket {
+
+    /*
+     * Logger instance
+     */
+    private static Logger lbsLogger = LoggerFactory.getLogger(ReactiveForwardingService.class);
+
+
+    /*
+     * REQUIRED for decoding the packet
+     */
+    private IDataPacketService dataPacketService = null;
+
+    /*
+     * REQUIRED for host identification from the packet
+     */
+    private IfIptoHost hostTracker;
+
+    /*
+     * REQUIRED for the flow-programming
+     */
+    private IForwardingRulesManager ruleManager;
+
+    /*
+     * REQUIRED for getting the path between source and destination determined from packet
+     */
+    private IRouting routing;
+
+    /*
+     * Load balancer application installs all flows with priority 2.
+     */
+    private static short LB_IPSWITCH_PRIORITY = 2;
+
+    /*
+     * Name of the container where this application will register.
+     */
+    private String containerName = null;
+
+    /*
+     * Set/unset methods for the service instance that load balancer
+     * service requires
+     */
+    public String getContainerName() {
+        if (containerName == null)
+            return GlobalConstants.DEFAULT.toString();
+        return containerName;
+    }
+
+    void setDataPacketService(IDataPacketService s) {
+        this.dataPacketService = s;
+    }
+
+    void unsetDataPacketService(IDataPacketService s) {
+        if (this.dataPacketService == s) {
+            this.dataPacketService = null;
+        }
+    }
+
+    public void setRouting(IRouting routing) {
+        this.routing = routing;
+    }
+
+    public void unsetRouting(IRouting routing) {
+        if (this.routing == routing) {
+            this.routing = null;
+        }
+    }
+
+    public void setHostTracker(IfIptoHost hostTracker) {
+        lbsLogger.debug("Setting HostTracker");
+        this.hostTracker = hostTracker;
+    }
+
+    public void unsetHostTracker(IfIptoHost hostTracker) {
+        if (this.hostTracker == hostTracker) {
+            this.hostTracker = null;
+        }
+    }
+
+    public void setForwardingRulesManager(
+            IForwardingRulesManager forwardingRulesManager) {
+        lbsLogger.debug("Setting ForwardingRulesManager");
+        this.ruleManager = forwardingRulesManager;
+    }
+
+    public void unsetForwardingRulesManager(
+            IForwardingRulesManager forwardingRulesManager) {
+        if (this.ruleManager == forwardingRulesManager) {
+            this.ruleManager = null;
+        }
+    }
+
+    /**
+     * This method receives first packet of flows for which there is no
+     * matching flow rule installed on the switch. IP addresses used for VIPs
+     * are not supposed to be used by any real/virtual host in the network.
+     * Hence, any forwarding/routing service will not install any flows rules matching
+     * these VIPs. This ensures that all the flows destined for VIPs will not find a match
+     * in the switch and will be forwarded to the load balancing service.
+     * Service will decide where to route this traffic based on the load balancing
+     * policy of the VIP's attached pool and will install appropriate flow rules
+     * in a reactive manner.
+     */
+    @Override
+    public PacketResult receiveDataPacket(RawPacket inPkt){
+
+        if (inPkt == null) {
+            return PacketResult.IGNORED;
+        }
+
+        Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
+        Node clientNode = inPkt.getIncomingNodeConnector().getNode();
+
+        if (formattedPak instanceof Ethernet) {
+
+
+            Object ipPkt = formattedPak.getPayload();
+
+            if (ipPkt instanceof ARP){
+            }
+            else{
+
+                lbsLogger.debug("RFWD >> got non-ARP ether packet");
+
+                Ethernet ether = (Ethernet) formattedPak;
+                byte[] destMacAddr = ether.getDestinationMACAddress();
+                byte[] srcMacAddr = ether.getSourceMACAddress();
+
+                //Byte[] dstMacAddr = ArrayUtils.toObject(destMacAddr);
+                //Byte[] srMacAddr = ArrayUtils.toObject(srcMacAddr);
+
+                lbsLogger.debug("RFWD >> Dst Mac Address {}", destMacAddr.toString());
+                lbsLogger.debug("RFWD >> Src Mac Address {}", srcMacAddr.toString());
+
+                //lbsLogger.debug("RFWD >> ip-pkt has dst IP as {}", destIPAddr.getHostAddress());
+                //lbsLogger.debug("RFWD >> ip-pkt has src IP as {}", srcIPAddr.getHostAddress());
+
+                installDummyFlowForCBench(clientNode, null, null, srcMacAddr, destMacAddr);
+
+            }
+
+
+
+            lbsLogger.debug("flow sent to cbench !!");
+
+
+
+            if (ipPkt instanceof IPv4) {
+
+
+
+                IPv4 ipv4Pkt = (IPv4)ipPkt;
+
+                lbsLogger.debug("RFWD >> got IP Packet");
+
+                //InetAddress destIPAddr = InetAddress.getByAddress(NetUtils.intToByteArray4(ipv4Pkt.getDestinationAddress()));
+                //InetAddress srcIPAddr = InetAddress.getByAddress(NetUtils.intToByteArray4(ipv4Pkt.getSourceAddress()));
+
+
+
+
+
+
+                lbsLogger.debug("RFWD >> got IPv4 packet");
+
+            }
+
+        }
+        return PacketResult.IGNORED;
+    }
+
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init(Component c) {
+        Dictionary<?, ?> props = c.getServiceProperties();
+        if (props != null) {
+            this.containerName = (String) props.get("containerName");
+
+            lbsLogger.info("Running container name:" + this.containerName);
+        }else {
+
+            // In the Global instance case the containerName is empty
+            this.containerName = "";
+        }
+        //lbsLogger.info(configManager.toString());
+    }
+
+    /**
+     * Function called by the dependency manager when at least one
+     * dependency become unsatisfied or when the component is shutting
+     * down because for example bundle is being stopped.
+     *
+     */
+    void destroy() {
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called
+     * and after the services provided by the class are registered in
+     * the service registry
+     *
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services
+     * exported by the component are unregistered, this will be
+     * followed by a "destroy ()" calls
+     *
+     */
+    void stop() {
+    }
+
+
+    private boolean installDummyFlowForCBench(Node originatorSwitch, InetAddress srcIp, InetAddress dstIp, byte[] srcMac, byte[] dstMac){
+
+
+
+
+        Match match = new Match();
+        List<Action> actions = new ArrayList<Action>();
+
+        //match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue());
+        //match.setField(MatchType.NW_SRC, srcIp);
+        //match.setField(MatchType.NW_DST, dstIp);
+
+        match.setField(MatchType.DL_SRC, srcMac);
+        //match.setField(MatchType.DL_DST, dstMac);
+
+        actions.add(new Drop());
+
+        Flow flow = new Flow(match, actions);
+        flow.setIdleTimeout((short) 5);
+        flow.setHardTimeout((short) 0);
+        flow.setPriority(LB_IPSWITCH_PRIORITY++);
+
+        String policyName = "cbenchpolicy";
+        String flowName ="cbenchflow";
+
+        FlowEntry fEntry = new FlowEntry(policyName, flowName, flow, originatorSwitch);
+
+        //lbsLogger.debug("Install flow entry {} on node {}",fEntry.toString(),originatorSwitch.toString());
+
+
+
+
+        //if(!this.ruleManager.checkFlowEntryConflict(fEntry)){
+            if(this.ruleManager.installFlowEntry(fEntry).isSuccess()){
+                return true;
+            }else{
+                lbsLogger.error("Error in installing flow entry to node : {}",originatorSwitch);
+            }
+
+        //}else{
+        //    lbsLogger.error("Conflicting flow entry exists : {}",fEntry.toString());
+        //}
+
+        return false;
+
+
+    }
+
+
+}
diff --git a/third-party/openflowj_netty/LICENSE b/third-party/openflowj_netty/LICENSE
new file mode 100644 (file)
index 0000000..ee6da46
--- /dev/null
@@ -0,0 +1,29 @@
+Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+University
+
+We are making the OpenFlow specification and associated documentation
+(Software) available for public use and benefit with the expectation that
+others will use, modify and enhance the Software and contribute those
+enhancements back to the community. However, since we would like to make the
+Software available for broadest use, with as few restrictions as possible
+permission is hereby granted, free of charge, to any person obtaining a copy of
+this Software to deal in the Software under the copyrights without restriction,
+including without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+The name and trademarks of copyright holder(s) may NOT be used in advertising
+or publicity pertaining to the Software or any derivatives without specific,
+written prior permission.
diff --git a/third-party/openflowj_netty/Makefile b/third-party/openflowj_netty/Makefile
new file mode 100644 (file)
index 0000000..b803071
--- /dev/null
@@ -0,0 +1,19 @@
+# Because I am old and crotchety and my fingers can't stop from running 
+#      `make` commands
+all:
+       ant
+
+run:
+       ant run
+
+doc: 
+       ant javadoc
+
+tests:
+       ant tests
+
+count: 
+       @find . -name \*.java | xargs wc -l | sort -n
+
+clean:
+       ant clean
diff --git a/third-party/openflowj_netty/README b/third-party/openflowj_netty/README
new file mode 100644 (file)
index 0000000..6fffebe
--- /dev/null
@@ -0,0 +1,16 @@
+OpenFlow Java - v1.0.0 
+
+A Java implementation of low-level OpenFlow packet marshalling/unmarshalling
+and IO operations. Implements v1.0 of the OpenFlow specification at
+http://www.openflow.org.
+
+    - David Erickson (daviderickson@cs.stanford.edu)
+    - Rob Sherwood (rob.sherwood@stanford.edu)
+
+Building requires Maven 2.x+ (http://maven.apache.org/).
+
+To build:
+    mvn package
+
+To build javadocs:
+    mvn javadoc:javadoc
diff --git a/third-party/openflowj_netty/eclipse_codestyle.xml b/third-party/openflowj_netty/eclipse_codestyle.xml
new file mode 100644 (file)
index 0000000..6b661c6
--- /dev/null
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<profiles version="11">
+<profile kind="CodeFormatterProfile" name="OpenFlowJ" version="11">
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
+<setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
+<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
+</profile>
+</profiles>
diff --git a/third-party/openflowj_netty/lib/commons-cli-1.2.jar b/third-party/openflowj_netty/lib/commons-cli-1.2.jar
new file mode 100644 (file)
index 0000000..ce4b9ff
Binary files /dev/null and b/third-party/openflowj_netty/lib/commons-cli-1.2.jar differ
diff --git a/third-party/openflowj_netty/lib/junit-4.8.1.jar b/third-party/openflowj_netty/lib/junit-4.8.1.jar
new file mode 100644 (file)
index 0000000..524cd65
Binary files /dev/null and b/third-party/openflowj_netty/lib/junit-4.8.1.jar differ
diff --git a/third-party/openflowj_netty/pom.xml b/third-party/openflowj_netty/pom.xml
new file mode 100644 (file)
index 0000000..176b6f8
--- /dev/null
@@ -0,0 +1,149 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.controller.thirdparty</groupId>
+  <artifactId>org.openflow.openflowj_netty</artifactId>
+  <version>1.0.2-SNAPSHOT</version>
+  <name>OpenFlow Java</name>
+  <description>A Java implemention of the OpenFlow v1.0 protocol</description>
+
+  <!-- Get some common settings for the project we are using it in -->
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.thirdparty</artifactId>
+    <version>1.1.0-SNAPSHOT</version>
+    <relativePath>../commons/thirdparty</relativePath>
+  </parent>
+  
+  <developers>
+    <developer>
+      <name>David Erickson</name>
+      <email>daviderickson@cs.stanford.edu</email>
+    </developer>
+    <developer>
+      <name>Rob Sherwood</name>
+      <email>rob.sherwood@stanford.edu</email>
+    </developer>
+  </developers>
+  <packaging>bundle</packaging>
+  <url>http://www.openflow.org</url>
+  <licenses>
+    <license>
+      <name>The OpenFlow License</name>
+      <url>http://www.openflowswitch.org/wp/legal/</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:git://gitosis.stanford.edu:openflowj.git</connection>
+    <url>https://openflow.stanford.edu/fisheye/browse/OpenFlowJ</url>
+  </scm>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+  <!-- For GPG release signing, use mvn release:perform -->
+  <profiles>
+    <profile>
+      <id>release-sign-artifacts</id>
+      <activation>
+        <property>
+          <name>performRelease</name>
+          <value>true</value>
+        </property>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>1.1</version>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <mavenExecutorId>forked-path</mavenExecutorId>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+  <build>
+    <plugins>
+    <plugin>
+       <groupId>org.apache.felix</groupId>
+       <artifactId>maven-bundle-plugin</artifactId>
+       <version>2.3.6</version>
+       <extensions>true</extensions>
+       <configuration>
+         <instructions>
+               <Import-Package>
+                 org.jboss.netty.*
+               </Import-Package>
+           <Export-Package>
+             org.openflow.example;version="1.0.1";
+             uses:="org.openflow.example.cli,
+             org.openflow.protocol,
+             org.openflow.io,
+             org.openflow.protocol.factory",
+             org.openflow.io;version="1.0.1";
+             uses:="org.openflow.protocol,
+             org.openflow.protocol.factory",
+             org.openflow.protocol;version="1.0.1";
+             uses:="org.openflow.protocol.statistics,
+             org.openflow.protocol,
+             org.openflow.protocol.factory",
+             org.openflow.protocol.action;version="1.0.1";
+             uses:="org.openflow.protocol",
+             org.openflow.protocol.factory;version="1.0.1";
+             uses:="org.openflow.protocol.statistics,
+             org.openflow.protocol,
+             org.openflow.protocol.action,
+             org.openflow.protocol.queue",
+             org.openflow.protocol.queue;version="1.0.2";
+             uses:="org.openflow.protocol,
+             org.openflow.protocol.factory",
+             org.openflow.protocol.statistics;version="1.0.1";
+             uses:="org.openflow.protocol,
+             org.openflow.protocol.factory",
+             org.openflow.util;version="1.0.1"
+           </Export-Package>
+        <Embed-Dependency>
+          org.jboss.netty;type=!pom;inline=false
+        </Embed-Dependency>        
+         </instructions>
+       </configuration>
+      </plugin>
+      <plugin>
+       <groupId>org.apache.maven.plugins</groupId>
+       <artifactId>maven-compiler-plugin</artifactId>
+       <version>2.3.2</version>
+       <configuration>
+         <source>1.6</source>
+         <target>1.6</target>
+       </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.8.1</version>
+      <scope>test</scope>
+    </dependency>
+        <dependency>
+      <groupId>org.jboss.netty</groupId>
+      <artifactId>netty</artifactId>
+      <version>3.2.6.Final</version>
+    </dependency>
+    
+  </dependencies>
+</project>
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/Instantiable.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/Instantiable.java
new file mode 100644 (file)
index 0000000..1358ba7
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+*    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;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface Instantiable<E> {
+
+    /**
+     * Create a new instance of a given subclass.
+     * @return the new instance.
+     */
+    public E instantiate();
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFBarrierReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFBarrierReply.java
new file mode 100644 (file)
index 0000000..a79a15f
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an OFPT_BARRIER_REPLY message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFBarrierReply extends OFMessage {
+    public OFBarrierReply() {
+        super();
+        this.type = OFType.BARRIER_REPLY;
+        this.length = U16.t(OFMessage.MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFBarrierRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFBarrierRequest.java
new file mode 100644 (file)
index 0000000..9992186
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an OFPT_BARRIER_REQUEST message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFBarrierRequest extends OFMessage {
+    public OFBarrierRequest() {
+        super();
+        this.type = OFType.BARRIER_REQUEST;
+        this.length = U16.t(OFMessage.MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFEchoReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFEchoReply.java
new file mode 100644 (file)
index 0000000..3e282a7
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_echo_reply message
+ * 
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+
+public class OFEchoReply extends OFEchoRequest {
+    public static int MINIMUM_LENGTH = 8;
+
+    public OFEchoReply() {
+        super();
+        this.type = OFType.ECHO_REPLY;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFEchoRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFEchoRequest.java
new file mode 100644 (file)
index 0000000..295a397
--- /dev/null
@@ -0,0 +1,101 @@
+/**
+*    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;
+
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_echo_request message
+ * 
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+
+public class OFEchoRequest extends OFMessage {
+    public static int MINIMUM_LENGTH = 8;
+    byte[] payload;
+
+    public OFEchoRequest() {
+        super();
+        this.type = OFType.ECHO_REQUEST;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer bb) {
+        super.readFrom(bb);
+        int datalen = this.getLengthU() - MINIMUM_LENGTH;
+        if (datalen > 0) {
+            this.payload = new byte[datalen];
+            bb.readBytes(payload);
+        }
+    }
+
+    /**
+     * @return the payload
+     */
+    public byte[] getPayload() {
+        return payload;
+    }
+
+    /**
+     * @param payload
+     *            the payload to set
+     */
+    public void setPayload(byte[] payload) {
+        this.payload = payload;
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        super.writeTo(bb);
+        if (payload != null)
+            bb.writeBytes(payload);
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(payload);
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        OFEchoRequest other = (OFEchoRequest) obj;
+        if (!Arrays.equals(payload, other.payload))
+            return false;
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFError.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFError.java
new file mode 100644 (file)
index 0000000..df7b236
--- /dev/null
@@ -0,0 +1,325 @@
+/**
+*    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;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.protocol.factory.OFMessageFactoryAware;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_error_msg
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class OFError extends OFMessage implements OFMessageFactoryAware {
+    public static int MINIMUM_LENGTH = 12;
+
+    public enum OFErrorType {
+        // OFPET_VENDOR_ERROR is an extension that was added in Open vSwitch and isn't
+        // in the OF 1.0 spec, but it was easier to add it here instead of adding
+        // generic support for extensible vendor-defined error messages.
+        // It uses the random value 0xb0c2 to avoid conflicts with other possible new
+        // error types. Support for vendor-defined extended errors has been standardized
+        // in the OF 1.2 spec, so this workaround is only needed for 1.0.
+        OFPET_HELLO_FAILED, OFPET_BAD_REQUEST, OFPET_BAD_ACTION, OFPET_FLOW_MOD_FAILED, OFPET_PORT_MOD_FAILED, OFPET_QUEUE_OP_FAILED, OFPET_VENDOR_ERROR((short)0xb0c2);
+
+        protected short value;
+
+        private OFErrorType() {
+            this.value = (short) this.ordinal();
+        }
+
+        private OFErrorType(short value) {
+            this.value = value;
+        }
+
+        public short getValue() {
+            return value;
+        }
+    }
+
+    public enum OFHelloFailedCode {
+        OFPHFC_INCOMPATIBLE, OFPHFC_EPERM
+    }
+
+    public enum OFBadRequestCode {
+        OFPBRC_BAD_VERSION, OFPBRC_BAD_TYPE, OFPBRC_BAD_STAT, OFPBRC_BAD_VENDOR, OFPBRC_BAD_SUBTYPE, OFPBRC_EPERM, OFPBRC_BAD_LEN, OFPBRC_BUFFER_EMPTY, OFPBRC_BUFFER_UNKNOWN
+    }
+
+    public enum OFBadActionCode {
+        OFPBAC_BAD_TYPE, OFPBAC_BAD_LEN, OFPBAC_BAD_VENDOR, OFPBAC_BAD_VENDOR_TYPE, OFPBAC_BAD_OUT_PORT, OFPBAC_BAD_ARGUMENT, OFPBAC_EPERM, OFPBAC_TOO_MANY, OFPBAC_BAD_QUEUE
+    }
+
+    public enum OFFlowModFailedCode {
+        OFPFMFC_ALL_TABLES_FULL, OFPFMFC_OVERLAP, OFPFMFC_EPERM, OFPFMFC_BAD_EMERG_TIMEOUT, OFPFMFC_BAD_COMMAND, OFPFMFC_UNSUPPORTED
+    }
+
+    public enum OFPortModFailedCode {
+        OFPPMFC_BAD_PORT, OFPPMFC_BAD_HW_ADDR
+    }
+
+    public enum OFQueueOpFailedCode {
+        OFPQOFC_BAD_PORT, OFPQOFC_BAD_QUEUE, OFPQOFC_EPERM
+    }
+
+    protected short errorType;
+    protected short errorCode;
+    protected int vendor;
+    protected int vendorErrorType;
+    protected short vendorErrorCode;
+    protected OFMessageFactory factory;
+    protected byte[] error;
+    protected boolean errorIsAscii;
+
+    public OFError() {
+        super();
+        this.type = OFType.ERROR;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /** convenience constructor */
+    public OFError(OFErrorType errorType) {
+        this();
+        setErrorType(errorType);
+    }
+
+    /**
+     * @return the errorType
+     */
+    public short getErrorType() {
+        return errorType;
+    }
+
+    /**
+     * @param errorType
+     *            the errorType to set
+     */
+    public void setErrorType(short errorType) {
+        this.errorType = errorType;
+    }
+
+    public void setErrorType(OFErrorType type) {
+        this.errorType = type.getValue();
+    }
+
+    /**
+     * @return true if the error is an extended vendor error
+     */
+    public boolean isVendorError() {
+        return errorType == OFErrorType.OFPET_VENDOR_ERROR.getValue();
+    }
+
+    /**
+     * @return the errorCode
+     */
+    public short getErrorCode() {
+        return errorCode;
+    }
+
+    /**
+     * @param errorCode
+     *            the errorCode to set
+     */
+    public void setErrorCode(OFHelloFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(short errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public void setErrorCode(OFBadRequestCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFBadActionCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFFlowModFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFPortModFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFQueueOpFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public int getVendorErrorType() {
+        return vendorErrorType;
+    }
+
+    public void setVendorErrorType(int vendorErrorType) {
+        this.vendorErrorType = vendorErrorType;
+    }
+
+    public short getVendorErrorCode() {
+        return vendorErrorCode;
+    }
+
+    public void setVendorErrorCode(short vendorErrorCode) {
+        this.vendorErrorCode = vendorErrorCode;
+    }
+
+    public OFMessage getOffendingMsg() throws MessageParseException {
+        // should only have one message embedded; if more than one, just
+        // grab first
+        if (this.error == null)
+            return null;
+        ChannelBuffer errorMsg = ChannelBuffers.wrappedBuffer(this.error);
+        if (factory == null)
+            throw new RuntimeException("MessageFactory not set");
+
+        List<OFMessage> msglist = this.factory.parseMessage(errorMsg);
+        if (msglist == null)
+                return null;
+        return msglist.get(0);
+    }
+
+    /**
+     * Write this offending message into the payload of the Error message
+     *
+     * @param offendingMsg
+     */
+
+    public void setOffendingMsg(OFMessage offendingMsg) {
+        if (offendingMsg == null) {
+            super.setLengthU(MINIMUM_LENGTH);
+        } else {
+            this.error = new byte[offendingMsg.getLengthU()];
+            ChannelBuffer data = ChannelBuffers.wrappedBuffer(this.error);
+            data.writerIndex(0);
+            offendingMsg.writeTo(data);
+            super.setLengthU(MINIMUM_LENGTH + offendingMsg.getLengthU());
+        }
+    }
+
+    public OFMessageFactory getFactory() {
+        return factory;
+    }
+
+    @Override
+    public void setMessageFactory(OFMessageFactory factory) {
+        this.factory = factory;
+    }
+
+    /**
+     * @return the error
+     */
+    public byte[] getError() {
+        return error;
+    }
+
+    /**
+     * @param error
+     *            the error to set
+     */
+    public void setError(byte[] error) {
+        this.error = error;
+    }
+
+    /**
+     * @return the errorIsAscii
+     */
+    public boolean isErrorIsAscii() {
+        return errorIsAscii;
+    }
+
+    /**
+     * @param errorIsAscii
+     *            the errorIsAscii to set
+     */
+    public void setErrorIsAscii(boolean errorIsAscii) {
+        this.errorIsAscii = errorIsAscii;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.errorType = data.readShort();
+        this.errorCode = data.readShort();
+        int dataLength = this.getLengthU() - MINIMUM_LENGTH;
+        if (dataLength > 0) {
+            this.error = new byte[dataLength];
+            data.readBytes(this.error);
+            if (this.errorType == OFErrorType.OFPET_HELLO_FAILED.getValue())
+                this.errorIsAscii = true;
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(errorType);
+        data.writeShort(errorCode);
+        if (error != null)
+            data.writeBytes(error);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(error);
+        result = prime * result + errorCode;
+        result = prime * result + (errorIsAscii ? 1231 : 1237);
+        result = prime * result + errorType;
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        OFError other = (OFError) obj;
+        if (!Arrays.equals(error, other.error))
+            return false;
+        if (errorCode != other.errorCode)
+            return false;
+        if (errorIsAscii != other.errorIsAscii)
+            return false;
+        if (errorType != other.errorType)
+            return false;
+        return true;
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFeaturesReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFeaturesReply.java
new file mode 100644 (file)
index 0000000..ebd82b5
--- /dev/null
@@ -0,0 +1,257 @@
+/**
+*    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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+
+/**
+ * Represents a features reply message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+
+public class OFFeaturesReply extends OFMessage {
+    public static int MINIMUM_LENGTH = 32;
+
+    /**
+     * Corresponds to bits on the capabilities field
+     */
+    public enum OFCapabilities {
+        OFPC_FLOW_STATS     (1 << 0),
+        OFPC_TABLE_STATS    (1 << 1),
+        OFPC_PORT_STATS     (1 << 2),
+        OFPC_STP            (1 << 3),
+        OFPC_RESERVED       (1 << 4),
+        OFPC_IP_REASM       (1 << 5),
+        OFPC_QUEUE_STATS    (1 << 6),
+        OFPC_ARP_MATCH_IP   (1 << 7);
+
+        protected int value;
+
+        private OFCapabilities(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+    }
+
+    protected long datapathId;
+    protected int buffers;
+    protected byte tables;
+    protected int capabilities;
+    protected int actions;
+    protected List<OFPhysicalPort> ports;
+
+    public OFFeaturesReply() {
+        super();
+        this.type = OFType.FEATURES_REPLY;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the datapathId
+     */
+    public long getDatapathId() {
+        return datapathId;
+    }
+
+    /**
+     * @param datapathId the datapathId to set
+     */
+    public void setDatapathId(long datapathId) {
+        this.datapathId = datapathId;
+    }
+
+    /**
+     * @return the buffers
+     */
+    public int getBuffers() {
+        return buffers;
+    }
+
+    /**
+     * @param buffers the buffers to set
+     */
+    public void setBuffers(int buffers) {
+        this.buffers = buffers;
+    }
+
+    /**
+     * @return the tables
+     */
+    public byte getTables() {
+        return tables;
+    }
+
+    /**
+     * @param tables the tables to set
+     */
+    public void setTables(byte tables) {
+        this.tables = tables;
+    }
+
+    /**
+     * @return the capabilities
+     */
+    public int getCapabilities() {
+        return capabilities;
+    }
+
+    /**
+     * @param capabilities the capabilities to set
+     */
+    public void setCapabilities(int capabilities) {
+        this.capabilities = capabilities;
+    }
+
+    /**
+     * @return the actions
+     */
+    public int getActions() {
+        return actions;
+    }
+
+    /**
+     * @param actions the actions to set
+     */
+    public void setActions(int actions) {
+        this.actions = actions;
+    }
+
+    /**
+     * @return the ports
+     */
+    public List<OFPhysicalPort> getPorts() {
+        return ports;
+    }
+
+    /**
+     * @param ports the ports to set
+     */
+    public void setPorts(List<OFPhysicalPort> ports) {
+        this.ports = ports;
+        if (ports == null) {
+            this.setLengthU(MINIMUM_LENGTH);
+        } else {
+            this.setLengthU(MINIMUM_LENGTH + ports.size()
+                    * OFPhysicalPort.MINIMUM_LENGTH);
+        }
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.datapathId = data.readLong();
+        this.buffers = data.readInt();
+        this.tables = data.readByte();
+        data.readerIndex(data.readerIndex() + 3); // pad
+        this.capabilities = data.readInt();
+        this.actions = data.readInt();
+        if (this.ports == null) {
+            this.ports = new ArrayList<OFPhysicalPort>();
+        } else {
+            this.ports.clear();
+        }
+        int portCount = (super.getLengthU() - 32)
+                / OFPhysicalPort.MINIMUM_LENGTH;
+        OFPhysicalPort port;
+        for (int i = 0; i < portCount; ++i) {
+            port = new OFPhysicalPort();
+            port.readFrom(data);
+            this.ports.add(port);
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeLong(this.datapathId);
+        data.writeInt(this.buffers);
+        data.writeByte(this.tables);
+        data.writeShort((short) 0); // pad
+        data.writeByte((byte) 0); // pad
+        data.writeInt(this.capabilities);
+        data.writeInt(this.actions);
+        if (this.ports != null)
+            for (OFPhysicalPort port : this.ports) {
+                port.writeTo(data);
+            }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 139;
+        int result = super.hashCode();
+        result = prime * result + actions;
+        result = prime * result + buffers;
+        result = prime * result + capabilities;
+        result = prime * result + (int) (datapathId ^ (datapathId >>> 32));
+        result = prime * result + ((ports == null) ? 0 : ports.hashCode());
+        result = prime * result + tables;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFFeaturesReply)) {
+            return false;
+        }
+        OFFeaturesReply other = (OFFeaturesReply) obj;
+        if (actions != other.actions) {
+            return false;
+        }
+        if (buffers != other.buffers) {
+            return false;
+        }
+        if (capabilities != other.capabilities) {
+            return false;
+        }
+        if (datapathId != other.datapathId) {
+            return false;
+        }
+        if (ports == null) {
+            if (other.ports != null) {
+                return false;
+            }
+        } else if (!ports.equals(other.ports)) {
+            return false;
+        }
+        if (tables != other.tables) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFeaturesRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFeaturesRequest.java
new file mode 100644 (file)
index 0000000..0a89e4f
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+
+/**
+ * Represents a features request message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class OFFeaturesRequest extends OFMessage {
+    public static int MINIMUM_LENGTH = 8;
+
+    public OFFeaturesRequest() {
+        super();
+        this.type = OFType.FEATURES_REQUEST;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFlowMod.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFlowMod.java
new file mode 100644 (file)
index 0000000..06ef547
--- /dev/null
@@ -0,0 +1,389 @@
+/**
+*    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;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.OFActionFactory;
+import org.openflow.protocol.factory.OFActionFactoryAware;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_flow_mod message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class OFFlowMod extends OFMessage implements OFActionFactoryAware, Cloneable {
+    public static int MINIMUM_LENGTH = 72;
+
+    public static final short OFPFC_ADD = 0;                /* New flow. */
+    public static final short OFPFC_MODIFY = 1;             /* Modify all matching flows. */
+    public static final short OFPFC_MODIFY_STRICT = 2;      /* Modify entry strictly matching wildcards */
+    public static final short OFPFC_DELETE=3;               /* Delete all matching flows. */
+    public static final short OFPFC_DELETE_STRICT =4;       /* Strictly match wildcards and priority. */
+
+    // Open Flow Flow Mod Flags. Use "or" operation to set multiple flags
+    public static final short OFPFF_SEND_FLOW_REM = 0x1; // 1 << 0
+    public static final short OFPFF_CHECK_OVERLAP = 0x2; // 1 << 1
+    public static final short OFPFF_EMERG         = 0x4; // 1 << 2
+
+    protected OFActionFactory actionFactory;
+    protected OFMatch match;
+    protected long cookie;
+    protected short command;
+    protected short idleTimeout;
+    protected short hardTimeout;
+    protected short priority;
+    protected int bufferId;
+    protected short outPort;
+    protected short flags;
+    protected List<OFAction> actions;
+
+    public OFFlowMod() {
+        super();
+        this.outPort = OFPort.OFPP_NONE.getValue();
+        this.type = OFType.FLOW_MOD;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * Get buffer_id
+     * @return
+     */
+    public int getBufferId() {
+        return this.bufferId;
+    }
+
+    /**
+     * Set buffer_id
+     * @param bufferId
+     */
+    public OFFlowMod setBufferId(int bufferId) {
+        this.bufferId = bufferId;
+        return this;
+    }
+
+    /**
+     * Get cookie
+     * @return
+     */
+    public long getCookie() {
+        return this.cookie;
+    }
+
+    /**
+     * Set cookie
+     * @param cookie
+     */
+    public OFFlowMod setCookie(long cookie) {
+        this.cookie = cookie;
+        return this;
+    }
+
+    /**
+     * Get command
+     * @return
+     */
+    public short getCommand() {
+        return this.command;
+    }
+
+    /**
+     * Set command
+     * @param command
+     */
+    public OFFlowMod setCommand(short command) {
+        this.command = command;
+        return this;
+    }
+
+    /**
+     * Get flags
+     * @return
+     */
+    public short getFlags() {
+        return this.flags;
+    }
+
+    /**
+     * Set flags
+     * @param flags
+     */
+    public OFFlowMod setFlags(short flags) {
+        this.flags = flags;
+        return this;
+    }
+
+    /**
+     * Get hard_timeout
+     * @return
+     */
+    public short getHardTimeout() {
+        return this.hardTimeout;
+    }
+
+    /**
+     * Set hard_timeout
+     * @param hardTimeout
+     */
+    public OFFlowMod setHardTimeout(short hardTimeout) {
+        this.hardTimeout = hardTimeout;
+        return this;
+    }
+
+    /**
+     * Get idle_timeout
+     * @return
+     */
+    public short getIdleTimeout() {
+        return this.idleTimeout;
+    }
+
+    /**
+     * Set idle_timeout
+     * @param idleTimeout
+     */
+    public OFFlowMod setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+        return this;
+    }
+
+    /**
+     * Gets a copy of the OFMatch object for this FlowMod, changes to this
+     * object do not modify the FlowMod
+     * @return
+     */
+    public OFMatch getMatch() {
+        return this.match;
+    }
+
+    /**
+     * Set match
+     * @param match
+     */
+    public OFFlowMod setMatch(OFMatch match) {
+        this.match = match;
+        return this;
+    }
+
+    /**
+     * Get out_port
+     * @return
+     */
+    public short getOutPort() {
+        return this.outPort;
+    }
+
+    /**
+     * Set out_port
+     * @param outPort
+     */
+    public OFFlowMod setOutPort(short outPort) {
+        this.outPort = outPort;
+        return this;
+    }
+
+    /**
+     * Set out_port
+     * @param port
+     */
+    public OFFlowMod setOutPort(OFPort port) {
+        this.outPort = port.getValue();
+        return this;
+    }
+
+    /**
+     * Get priority
+     * @return
+     */
+    public short getPriority() {
+        return this.priority;
+    }
+
+    /**
+     * Set priority
+     * @param priority
+     */
+    public OFFlowMod setPriority(short priority) {
+        this.priority = priority;
+        return this;
+    }
+
+    /**
+     * Returns read-only copies of the actions contained in this Flow Mod
+     * @return a list of ordered OFAction objects
+     */
+    public List<OFAction> getActions() {
+        return this.actions;
+    }
+
+    /**
+     * Sets the list of actions this Flow Mod contains
+     * @param actions a list of ordered OFAction objects
+     */
+    public OFFlowMod setActions(List<OFAction> actions) {
+        this.actions = actions;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.cookie = data.readLong();
+        this.command = data.readShort();
+        this.idleTimeout = data.readShort();
+        this.hardTimeout = data.readShort();
+        this.priority = data.readShort();
+        this.bufferId = data.readInt();
+        this.outPort = data.readShort();
+        this.flags = data.readShort();
+        if (this.actionFactory == null)
+            throw new RuntimeException("OFActionFactory not set");
+        this.actions = this.actionFactory.parseActions(data, getLengthU() -
+                MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        this.match.writeTo(data);
+        data.writeLong(cookie);
+        data.writeShort(command);
+        data.writeShort(idleTimeout);
+        data.writeShort(hardTimeout);
+        data.writeShort(priority);
+        data.writeInt(bufferId);
+        data.writeShort(outPort);
+        data.writeShort(flags);
+        if (actions != null) {
+            for (OFAction action : actions) {
+                action.writeTo(data);
+            }
+        }
+    }
+
+    @Override
+    public void setActionFactory(OFActionFactory actionFactory) {
+        this.actionFactory = actionFactory;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 227;
+        int result = super.hashCode();
+        result = prime * result + ((actions == null) ? 0 : actions.hashCode());
+        result = prime * result + bufferId;
+        result = prime * result + command;
+        result = prime * result + (int) (cookie ^ (cookie >>> 32));
+        result = prime * result + flags;
+        result = prime * result + hardTimeout;
+        result = prime * result + idleTimeout;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + outPort;
+        result = prime * result + priority;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowMod)) {
+            return false;
+        }
+        OFFlowMod other = (OFFlowMod) obj;
+        if (actions == null) {
+            if (other.actions != null) {
+                return false;
+            }
+        } else if (!actions.equals(other.actions)) {
+            return false;
+        }
+        if (bufferId != other.bufferId) {
+            return false;
+        }
+        if (command != other.command) {
+            return false;
+        }
+        if (cookie != other.cookie) {
+            return false;
+        }
+        if (flags != other.flags) {
+            return false;
+        }
+        if (hardTimeout != other.hardTimeout) {
+            return false;
+        }
+        if (idleTimeout != other.idleTimeout) {
+            return false;
+        }
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (outPort != other.outPort) {
+            return false;
+        }
+        if (priority != other.priority) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    public OFFlowMod clone() throws CloneNotSupportedException {
+        OFMatch neoMatch = match.clone();
+        OFFlowMod flowMod= (OFFlowMod) super.clone();
+        flowMod.setMatch(neoMatch);
+        List<OFAction> neoActions = new LinkedList<OFAction>();
+        for(OFAction action: this.actions)
+            neoActions.add((OFAction) action.clone());
+        flowMod.setActions(neoActions);
+        return flowMod;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "OFFlowMod [actionFactory=" + actionFactory + ", actions="
+                + actions + ", bufferId=" + bufferId + ", command=" + command
+                + ", cookie=" + cookie + ", flags=" + flags + ", hardTimeout="
+                + hardTimeout + ", idleTimeout=" + idleTimeout + ", match="
+                + match + ", outPort=" + outPort + ", priority=" + priority
+                + ", length=" + length + ", type=" + type + ", version="
+                + version + ", xid=" + xid + "]";
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFlowRemoved.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFFlowRemoved.java
new file mode 100644 (file)
index 0000000..3357006
--- /dev/null
@@ -0,0 +1,294 @@
+/**
+*    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;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_flow_removed message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class OFFlowRemoved extends OFMessage {
+    public static int MINIMUM_LENGTH = 88;
+
+    public enum OFFlowRemovedReason {
+        OFPRR_IDLE_TIMEOUT,
+        OFPRR_HARD_TIMEOUT,
+        OFPRR_DELETE
+    }
+
+    protected OFMatch match;
+    protected long cookie;
+    protected short priority;
+    protected OFFlowRemovedReason reason;
+    protected int durationSeconds;
+    protected int durationNanoseconds;
+    protected short idleTimeout;
+    protected long packetCount;
+    protected long byteCount;
+    
+    public OFFlowRemoved() {
+        super();
+        this.type = OFType.FLOW_REMOVED;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * Get cookie
+     * @return
+     */
+    public long getCookie() {
+        return this.cookie;
+    }
+
+    /**
+     * Set cookie
+     * @param cookie
+     */
+    public void setCookie(long cookie) {
+        this.cookie = cookie;
+    }
+
+    /**
+     * Get idle_timeout
+     * @return
+     */
+    public short getIdleTimeout() {
+        return this.idleTimeout;
+    }
+
+    /**
+     * Set idle_timeout
+     * @param idleTimeout
+     */
+    public void setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    /**
+     * Gets a copy of the OFMatch object for this FlowMod, changes to this
+     * object do not modify the FlowMod
+     * @return
+     */
+    public OFMatch getMatch() {
+        return this.match;
+    }
+
+    /**
+     * Set match
+     * @param match
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * Get priority
+     * @return
+     */
+    public short getPriority() {
+        return this.priority;
+    }
+
+    /**
+     * Set priority
+     * @param priority
+     */
+    public void setPriority(short priority) {
+        this.priority = priority;
+    }
+
+    /**
+     * @return the reason
+     */
+    public OFFlowRemovedReason getReason() {
+        return reason;
+    }
+
+    /**
+     * @param reason the reason to set
+     */
+    public void setReason(OFFlowRemovedReason reason) {
+        this.reason = reason;
+    }
+
+    /**
+     * @return the durationSeconds
+     */
+    public int getDurationSeconds() {
+        return durationSeconds;
+    }
+
+    /**
+     * @param durationSeconds the durationSeconds to set
+     */
+    public void setDurationSeconds(int durationSeconds) {
+        this.durationSeconds = durationSeconds;
+    }
+
+    /**
+     * @return the durationNanoseconds
+     */
+    public int getDurationNanoseconds() {
+        return durationNanoseconds;
+    }
+
+    /**
+     * @param durationNanoseconds the durationNanoseconds to set
+     */
+    public void setDurationNanoseconds(int durationNanoseconds) {
+        this.durationNanoseconds = durationNanoseconds;
+    }
+
+    /**
+     * @return the packetCount
+     */
+    public long getPacketCount() {
+        return packetCount;
+    }
+
+    /**
+     * @param packetCount the packetCount to set
+     */
+    public void setPacketCount(long packetCount) {
+        this.packetCount = packetCount;
+    }
+
+    /**
+     * @return the byteCount
+     */
+    public long getByteCount() {
+        return byteCount;
+    }
+
+    /**
+     * @param byteCount the byteCount to set
+     */
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.cookie = data.readLong();
+        this.priority = data.readShort();
+        int reasonIndex = (int)(0xff & data.readByte());
+        if (reasonIndex >= OFFlowRemovedReason.values().length) {
+            reasonIndex = OFFlowRemovedReason.values().length - 1;
+        }
+        this.reason = OFFlowRemovedReason.values()[reasonIndex];
+        data.readByte(); // pad
+        this.durationSeconds = data.readInt();
+        this.durationNanoseconds = data.readInt();
+        this.idleTimeout = data.readShort();
+        data.readByte(); // pad
+        data.readByte(); // pad
+        this.packetCount = data.readLong();
+        this.byteCount = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        this.match.writeTo(data);
+        data.writeLong(cookie);
+        data.writeShort(priority);
+        data.writeByte((byte) this.reason.ordinal());
+        data.writeByte((byte) 0);
+        data.writeInt(this.durationSeconds);
+        data.writeInt(this.durationNanoseconds);
+        data.writeShort(idleTimeout);
+        data.writeByte((byte) 0); // pad
+        data.writeByte((byte) 0); // pad
+        data.writeLong(this.packetCount);
+        data.writeLong(this.byteCount);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 271;
+        int result = super.hashCode();
+        result = prime * result + (int) (byteCount ^ (byteCount >>> 32));
+        result = prime * result + (int) (cookie ^ (cookie >>> 32));
+        result = prime * result + durationNanoseconds;
+        result = prime * result + durationSeconds;
+        result = prime * result + idleTimeout;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + (int) (packetCount ^ (packetCount >>> 32));
+        result = prime * result + priority;
+        result = prime * result + ((reason == null) ? 0 : reason.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowRemoved)) {
+            return false;
+        }
+        OFFlowRemoved other = (OFFlowRemoved) obj;
+        if (byteCount != other.byteCount) {
+            return false;
+        }
+        if (cookie != other.cookie) {
+            return false;
+        }
+        if (durationNanoseconds != other.durationNanoseconds) {
+            return false;
+        }
+        if (durationSeconds != other.durationSeconds) {
+            return false;
+        }
+        if (idleTimeout != other.idleTimeout) {
+            return false;
+        }
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (packetCount != other.packetCount) {
+            return false;
+        }
+        if (priority != other.priority) {
+            return false;
+        }
+        if (reason == null) {
+            if (other.reason != null) {
+                return false;
+            }
+        } else if (!reason.equals(other.reason)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFGetConfigReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFGetConfigReply.java
new file mode 100644 (file)
index 0000000..257867a
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+*    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;
+
+/**
+ * Represents an OFPT_GET_CONFIG_REPLY type message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFGetConfigReply extends OFSwitchConfig {
+    public OFGetConfigReply() {
+        super();
+        this.type = OFType.GET_CONFIG_REPLY;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFGetConfigRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFGetConfigRequest.java
new file mode 100644 (file)
index 0000000..85c7499
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an OFPT_GET_CONFIG_REQUEST type message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFGetConfigRequest extends OFMessage {
+    public OFGetConfigRequest() {
+        super();
+        this.type = OFType.GET_CONFIG_REQUEST;
+        this.length = U16.t(OFMessage.MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFHello.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFHello.java
new file mode 100644 (file)
index 0000000..e702ca4
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+
+/**
+ * Represents an ofp_hello message
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 8, 2010
+ */
+public class OFHello extends OFMessage {
+    public static int MINIMUM_LENGTH = 8;
+
+    /**
+     * Construct a ofp_hello message
+     */
+    public OFHello() {
+        super();
+        this.type = OFType.HELLO;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatch.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatch.java
new file mode 100644 (file)
index 0000000..91930f1
--- /dev/null
@@ -0,0 +1,1040 @@
+/**
+ *    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;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+import org.openflow.util.U8;
+
+/**
+ * Represents an ofp_match structure
+ * 
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class OFMatch implements Cloneable, Serializable {
+
+    /**
+     *
+     */
+       
+       public static final short VLAN_UNTAGGED = (short)0xffff;
+       
+    private static final long serialVersionUID = 1L;
+    public static int MINIMUM_LENGTH = 40;
+    final public static int OFPFW_ALL = ((1 << 22) - 1);
+
+    final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */
+    final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */
+    final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */
+    final public static int OFPFW_DL_DST = 1 << 3; /*
+                                                    * Ethernet destination
+                                                    * address.
+                                                    */
+    final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */
+    final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */
+    final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */
+    final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */
+
+    /*
+     * IP source address wildcard bit count. 0 is exact match, 1 ignores the
+     * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
+     * the entire field. This is the *opposite* of the usual convention where
+     * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded.
+     */
+    final public static int OFPFW_NW_SRC_SHIFT = 8;
+    final public static int OFPFW_NW_SRC_BITS = 6;
+    final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT;
+    final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT;
+
+    /* IP destination address wildcard bit count. Same format as source. */
+    final public static int OFPFW_NW_DST_SHIFT = 14;
+    final public static int OFPFW_NW_DST_BITS = 6;
+    final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT;
+    final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT;
+
+    final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */
+    final public static int OFPFW_NW_TOS = 1 << 21; /*
+                                                     * IP ToS (DSCP field, 6
+                                                     * bits).
+                                                     */
+
+    final public static int OFPFW_ALL_SANITIZED = (((1 << 22) - 1)
+                                                   & ~OFPFW_NW_SRC_MASK & ~OFPFW_NW_DST_MASK)
+                                                  | OFPFW_NW_SRC_ALL
+                                                  | OFPFW_NW_DST_ALL;
+
+    /* List of Strings for marshalling and unmarshalling to human readable forms */
+    final public static String STR_IN_PORT = "in_port";
+    final public static String STR_DL_DST = "dl_dst";
+    final public static String STR_DL_SRC = "dl_src";
+    final public static String STR_DL_TYPE = "dl_type";
+    final public static String STR_DL_VLAN = "dl_vlan";
+    final public static String STR_DL_VLAN_PCP = "dl_vlan_pcp";
+    final public static String STR_NW_DST = "nw_dst";
+    final public static String STR_NW_SRC = "nw_src";
+    final public static String STR_NW_PROTO = "nw_proto";
+    final public static String STR_NW_TOS = "nw_tos";
+    final public static String STR_TP_DST = "tp_dst";
+    final public static String STR_TP_SRC = "tp_src";
+
+    protected int wildcards;
+    protected short inputPort;
+    protected byte[] dataLayerSource;
+    protected byte[] dataLayerDestination;
+    protected short dataLayerVirtualLan;
+    protected byte dataLayerVirtualLanPriorityCodePoint;
+    protected short dataLayerType;
+    protected byte networkTypeOfService;
+    protected byte networkProtocol;
+    protected int networkSource;
+    protected int networkDestination;
+    protected short transportSource;
+    protected short transportDestination;
+
+    /**
+     * By default, create a OFMatch that matches everything (mostly because it's
+     * the least amount of work to make a valid OFMatch)
+     */
+    public OFMatch() {
+        this.wildcards = OFPFW_ALL;
+        this.dataLayerDestination = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0,
+                                                0x0 };
+        this.dataLayerSource = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+        this.dataLayerVirtualLan = VLAN_UNTAGGED;
+        this.dataLayerVirtualLanPriorityCodePoint = 0;
+        this.dataLayerType = 0;
+        this.inputPort = 0;
+        this.networkProtocol = 0;
+        this.networkTypeOfService = 0;
+        this.networkSource = 0;
+        this.networkDestination = 0;
+        this.transportDestination = 0;
+        this.transportSource = 0;
+    }
+
+    /**
+     * Get dl_dst
+     * 
+     * @return an arrays of bytes
+     */
+    public byte[] getDataLayerDestination() {
+        return this.dataLayerDestination;
+    }
+
+    /**
+     * Set dl_dst
+     * 
+     * @param dataLayerDestination
+     */
+    public OFMatch setDataLayerDestination(byte[] dataLayerDestination) {
+        this.dataLayerDestination = dataLayerDestination;
+        return this;
+    }
+
+    /**
+     * Set dl_dst, but first translate to byte[] using HexString
+     * 
+     * @param mac
+     *            A colon separated string of 6 pairs of octets, e..g.,
+     *            "00:17:42:EF:CD:8D"
+     */
+    public OFMatch setDataLayerDestination(String mac) {
+        byte bytes[] = HexString.fromHexString(mac);
+        if (bytes.length != 6)
+                              throw new IllegalArgumentException(
+                                                                 "expected string with 6 octets, got '"
+                                                                         + mac
+                                                                         + "'");
+        this.dataLayerDestination = bytes;
+        return this;
+    }
+
+    /**
+     * Get dl_src
+     * 
+     * @return an array of bytes
+     */
+    public byte[] getDataLayerSource() {
+        return this.dataLayerSource;
+    }
+
+    /**
+     * Set dl_src
+     * 
+     * @param dataLayerSource
+     */
+    public OFMatch setDataLayerSource(byte[] dataLayerSource) {
+        this.dataLayerSource = dataLayerSource;
+        return this;
+    }
+
+    /**
+     * Set dl_src, but first translate to byte[] using HexString
+     * 
+     * @param mac
+     *            A colon separated string of 6 pairs of octets, e..g.,
+     *            "00:17:42:EF:CD:8D"
+     */
+    public OFMatch setDataLayerSource(String mac) {
+        byte bytes[] = HexString.fromHexString(mac);
+        if (bytes.length != 6)
+                              throw new IllegalArgumentException(
+                                                                 "expected string with 6 octets, got '"
+                                                                         + mac
+                                                                         + "'");
+        this.dataLayerSource = bytes;
+        return this;
+    }
+
+    /**
+     * Get dl_type
+     * 
+     * @return ether_type
+     */
+    public short getDataLayerType() {
+        return this.dataLayerType;
+    }
+
+    /**
+     * Set dl_type
+     * 
+     * @param dataLayerType
+     */
+    public OFMatch setDataLayerType(short dataLayerType) {
+        this.dataLayerType = dataLayerType;
+        return this;
+    }
+
+    /**
+     * Get dl_vlan
+     * 
+     * @return vlan tag; VLAN_NONE == no tag
+     */
+    public short getDataLayerVirtualLan() {
+        return this.dataLayerVirtualLan;
+    }
+
+    /**
+     * Set dl_vlan
+     * 
+     * @param dataLayerVirtualLan
+     */
+    public OFMatch setDataLayerVirtualLan(short dataLayerVirtualLan) {
+        this.dataLayerVirtualLan = dataLayerVirtualLan;
+        return this;
+    }
+
+    /**
+     * Get dl_vlan_pcp
+     * 
+     * @return
+     */
+    public byte getDataLayerVirtualLanPriorityCodePoint() {
+        return this.dataLayerVirtualLanPriorityCodePoint;
+    }
+
+    /**
+     * Set dl_vlan_pcp
+     * 
+     * @param pcp
+     */
+    public OFMatch setDataLayerVirtualLanPriorityCodePoint(byte pcp) {
+        this.dataLayerVirtualLanPriorityCodePoint = pcp;
+        return this;
+    }
+
+    /**
+     * Get in_port
+     * 
+     * @return
+     */
+    public short getInputPort() {
+        return this.inputPort;
+    }
+
+    /**
+     * Set in_port
+     * 
+     * @param inputPort
+     */
+    public OFMatch setInputPort(short inputPort) {
+        this.inputPort = inputPort;
+        return this;
+    }
+
+    /**
+     * Get nw_dst
+     * 
+     * @return
+     */
+    public int getNetworkDestination() {
+        return this.networkDestination;
+    }
+
+    /**
+     * Set nw_dst
+     * 
+     * @param networkDestination
+     */
+    public OFMatch setNetworkDestination(int networkDestination) {
+        this.networkDestination = networkDestination;
+        return this;
+    }
+
+    /**
+     * Parse this match's wildcard fields and return the number of significant
+     * bits in the IP destination field. NOTE: this returns the number of bits
+     * that are fixed, i.e., like CIDR, not the number of bits that are free
+     * like OpenFlow encodes.
+     * 
+     * @return a number between 0 (matches all IPs) and 63 ( 32>= implies exact
+     *         match)
+     */
+    public int getNetworkDestinationMaskLen() {
+        return Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
+                        0);
+    }
+
+    /**
+     * Parse this match's wildcard fields and return the number of significant
+     * bits in the IP destination field. NOTE: this returns the number of bits
+     * that are fixed, i.e., like CIDR, not the number of bits that are free
+     * like OpenFlow encodes.
+     * 
+     * @return a number between 0 (matches all IPs) and 32 (exact match)
+     */
+    public int getNetworkSourceMaskLen() {
+        return Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
+                        0);
+    }
+
+    /**
+     * Get nw_proto
+     * 
+     * @return
+     */
+    public byte getNetworkProtocol() {
+        return this.networkProtocol;
+    }
+
+    /**
+     * Set nw_proto
+     * 
+     * @param networkProtocol
+     */
+    public OFMatch setNetworkProtocol(byte networkProtocol) {
+        this.networkProtocol = networkProtocol;
+        return this;
+    }
+
+    /**
+     * Get nw_src
+     * 
+     * @return
+     */
+    public int getNetworkSource() {
+        return this.networkSource;
+    }
+
+    /**
+     * Set nw_src
+     * 
+     * @param networkSource
+     */
+    public OFMatch setNetworkSource(int networkSource) {
+        this.networkSource = networkSource;
+        return this;
+    }
+
+    /**
+     * Get nw_tos OFMatch stores the ToS bits as top 6-bits, so right shift by 2
+     * bits before returning the value
+     * 
+     * @return : 6-bit DSCP value (0-63)
+     */
+    public byte getNetworkTypeOfService() {
+        return (byte) ((this.networkTypeOfService >> 2) & 0x3f);
+    }
+
+    /**
+     * Set nw_tos OFMatch stores the ToS bits as top 6-bits, so left shift by 2
+     * bits before storing the value
+     * 
+     * @param networkTypeOfService
+     *            : 6-bit DSCP value (0-63)
+     */
+    public OFMatch setNetworkTypeOfService(byte networkTypeOfService) {
+        this.networkTypeOfService = (byte) (networkTypeOfService << 2);
+        return this;
+    }
+
+    /**
+     * Get tp_dst
+     * 
+     * @return
+     */
+    public short getTransportDestination() {
+        return this.transportDestination;
+    }
+
+    /**
+     * Set tp_dst
+     * 
+     * @param transportDestination
+     */
+    public OFMatch setTransportDestination(short transportDestination) {
+        this.transportDestination = transportDestination;
+        return this;
+    }
+
+    /**
+     * Get tp_src
+     * 
+     * @return
+     */
+    public short getTransportSource() {
+        return this.transportSource;
+    }
+
+    /**
+     * Set tp_src
+     * 
+     * @param transportSource
+     */
+    public OFMatch setTransportSource(short transportSource) {
+        this.transportSource = transportSource;
+        return this;
+    }
+
+    /**
+     * Get wildcards
+     * 
+     * @return
+     */
+    public int getWildcards() {
+        return this.wildcards;
+    }
+
+    /**
+     * Get wildcards
+     * 
+     * @return
+     */
+    public Wildcards getWildcardObj() {
+        return Wildcards.of(wildcards);
+    }
+
+    /**
+     * Set wildcards
+     * 
+     * @param wildcards
+     */
+    public OFMatch setWildcards(int wildcards) {
+        this.wildcards = wildcards;
+        return this;
+    }
+
+    /** set the wildcard using the Wildcards convenience object */
+    public OFMatch setWildcards(Wildcards wildcards) {
+        this.wildcards = wildcards.getInt();
+        return this;
+    }
+
+    /**
+     * Initializes this OFMatch structure with the corresponding data from the
+     * specified packet. Must specify the input port, to ensure that
+     * this.in_port is set correctly. Specify OFPort.NONE or OFPort.ANY if input
+     * port not applicable or available
+     * 
+     * @param packetData
+     *            The packet's data
+     * @param inputPort
+     *            the port the packet arrived on
+     */
+    public OFMatch loadFromPacket(byte[] packetData, short inputPort) {
+        short scratch;
+        int transportOffset = 34;
+        ByteBuffer packetDataBB = ByteBuffer.wrap(packetData);
+        int limit = packetDataBB.limit();
+
+        this.wildcards = 0; // all fields have explicit entries
+
+        this.inputPort = inputPort;
+
+        if (inputPort == OFPort.OFPP_ALL.getValue())
+                                                    this.wildcards |= OFPFW_IN_PORT;
+
+        assert (limit >= 14);
+        // dl dst
+        this.dataLayerDestination = new byte[6];
+        packetDataBB.get(this.dataLayerDestination);
+        // dl src
+        this.dataLayerSource = new byte[6];
+        packetDataBB.get(this.dataLayerSource);
+        // dl type
+        this.dataLayerType = packetDataBB.getShort();
+
+        if (getDataLayerType() != (short) 0x8100) { // need cast to avoid signed
+            // bug
+            setDataLayerVirtualLan((short) 0xffff);
+            setDataLayerVirtualLanPriorityCodePoint((byte) 0);
+        } else {
+            // has vlan tag
+            scratch = packetDataBB.getShort();
+            setDataLayerVirtualLan((short) (0xfff & scratch));
+            setDataLayerVirtualLanPriorityCodePoint((byte) ((0xe000 & scratch) >> 13));
+            this.dataLayerType = packetDataBB.getShort();
+        }
+
+        switch (getDataLayerType()) {
+            case 0x0800:
+                // ipv4
+                // check packet length
+                scratch = packetDataBB.get();
+                scratch = (short) (0xf & scratch);
+                transportOffset = (packetDataBB.position() - 1)
+                                  + (scratch * 4);
+                // nw tos (dscp)
+                scratch = packetDataBB.get();
+                setNetworkTypeOfService((byte) ((0xfc & scratch) >> 2));
+                // nw protocol
+                packetDataBB.position(packetDataBB.position() + 7);
+                this.networkProtocol = packetDataBB.get();
+                // nw src
+                packetDataBB.position(packetDataBB.position() + 2);
+                this.networkSource = packetDataBB.getInt();
+                // nw dst
+                this.networkDestination = packetDataBB.getInt();
+                packetDataBB.position(transportOffset);
+                break;
+            case 0x0806:
+                // arp
+                int arpPos = packetDataBB.position();
+                // opcode
+                scratch = packetDataBB.getShort(arpPos + 6);
+                setNetworkProtocol((byte) (0xff & scratch));
+
+                scratch = packetDataBB.getShort(arpPos + 2);
+                // if ipv4 and addr len is 4
+                if (scratch == 0x800 && packetDataBB.get(arpPos + 5) == 4) {
+                    // nw src
+                    this.networkSource = packetDataBB.getInt(arpPos + 14);
+                    // nw dst
+                    this.networkDestination = packetDataBB.getInt(arpPos + 24);
+                } else {
+                    setNetworkSource(0);
+                    setNetworkDestination(0);
+                }
+                break;
+            default:
+                setNetworkTypeOfService((byte) 0);
+                setNetworkProtocol((byte) 0);
+                setNetworkSource(0);
+                setNetworkDestination(0);
+                break;
+        }
+
+        switch (getNetworkProtocol()) {
+            case 0x01:
+                // icmp
+                // type
+                this.transportSource = U8.f(packetDataBB.get());
+                // code
+                this.transportDestination = U8.f(packetDataBB.get());
+                break;
+            case 0x06:
+                // tcp
+                // tcp src
+                this.transportSource = packetDataBB.getShort();
+                // tcp dest
+                this.transportDestination = packetDataBB.getShort();
+                break;
+            case 0x11:
+                // udp
+                // udp src
+                this.transportSource = packetDataBB.getShort();
+                // udp dest
+                this.transportDestination = packetDataBB.getShort();
+                break;
+            default:
+                setTransportDestination((short) 0);
+                setTransportSource((short) 0);
+                break;
+        }
+        return this;
+    }
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     * 
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data) {
+        this.wildcards = data.readInt();
+        this.inputPort = data.readShort();
+        this.dataLayerSource = new byte[6];
+        data.readBytes(this.dataLayerSource);
+        this.dataLayerDestination = new byte[6];
+        data.readBytes(this.dataLayerDestination);
+        this.dataLayerVirtualLan = data.readShort();
+        this.dataLayerVirtualLanPriorityCodePoint = data.readByte();
+        data.readByte(); // pad
+        this.dataLayerType = data.readShort();
+        this.networkTypeOfService = data.readByte();
+        this.networkProtocol = data.readByte();
+        data.readByte(); // pad
+        data.readByte(); // pad
+        this.networkSource = data.readInt();
+        this.networkDestination = data.readInt();
+        this.transportSource = data.readShort();
+        this.transportDestination = data.readShort();
+    }
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     * 
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(wildcards);
+        data.writeShort(inputPort);
+        data.writeBytes(this.dataLayerSource);
+        data.writeBytes(this.dataLayerDestination);
+        data.writeShort(dataLayerVirtualLan);
+        data.writeByte(dataLayerVirtualLanPriorityCodePoint);
+        data.writeByte((byte) 0x0); // pad
+        data.writeShort(dataLayerType);
+        data.writeByte(networkTypeOfService);
+        data.writeByte(networkProtocol);
+        data.writeByte((byte) 0x0); // pad
+        data.writeByte((byte) 0x0); // pad
+        data.writeInt(networkSource);
+        data.writeInt(networkDestination);
+        data.writeShort(transportSource);
+        data.writeShort(transportDestination);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 131;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(dataLayerDestination);
+        result = prime * result + Arrays.hashCode(dataLayerSource);
+        result = prime * result + dataLayerType;
+        result = prime * result + dataLayerVirtualLan;
+        result = prime * result + dataLayerVirtualLanPriorityCodePoint;
+        result = prime * result + inputPort;
+        result = prime * result + networkDestination;
+        result = prime * result + networkProtocol;
+        result = prime * result + networkSource;
+        result = prime * result + networkTypeOfService;
+        result = prime * result + transportDestination;
+        result = prime * result + transportSource;
+        result = prime * result + wildcards;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFMatch)) {
+            return false;
+        }
+        OFMatch other = (OFMatch) obj;
+        if (!Arrays.equals(dataLayerDestination, other.dataLayerDestination)) {
+            return false;
+        }
+        if (!Arrays.equals(dataLayerSource, other.dataLayerSource)) {
+            return false;
+        }
+        if (dataLayerType != other.dataLayerType) {
+            return false;
+        }
+        if (dataLayerVirtualLan != other.dataLayerVirtualLan) {
+            return false;
+        }
+        if (dataLayerVirtualLanPriorityCodePoint != other.dataLayerVirtualLanPriorityCodePoint) {
+            return false;
+        }
+        if (inputPort != other.inputPort) {
+            return false;
+        }
+        if (networkDestination != other.networkDestination) {
+            return false;
+        }
+        if (networkProtocol != other.networkProtocol) {
+            return false;
+        }
+        if (networkSource != other.networkSource) {
+            return false;
+        }
+        if (networkTypeOfService != other.networkTypeOfService) {
+            return false;
+        }
+        if (transportDestination != other.transportDestination) {
+            return false;
+        }
+        if (transportSource != other.transportSource) {
+            return false;
+        }
+        if ((wildcards & OFMatch.OFPFW_ALL) != (other.wildcards & OFPFW_ALL)) { // only
+            // consider
+            // allocated
+            // part
+            // of
+            // wildcards
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Implement clonable interface
+     */
+    @Override
+    public OFMatch clone() {
+        try {
+            OFMatch ret = (OFMatch) super.clone();
+            ret.dataLayerDestination = this.dataLayerDestination.clone();
+            ret.dataLayerSource = this.dataLayerSource.clone();
+            return ret;
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Output a dpctl-styled string, i.e., only list the elements that are not
+     * wildcarded A match-everything OFMatch outputs "OFMatch[]"
+     * 
+     * @return 
+     *         "OFMatch[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]"
+     */
+    @Override
+    public String toString() {
+        String str = "";
+
+        // l1
+        if ((wildcards & OFPFW_IN_PORT) == 0)
+                                             str += "," + STR_IN_PORT + "="
+                                                    + U16.f(this.inputPort);
+
+        // l2
+        if ((wildcards & OFPFW_DL_DST) == 0)
+                                            str += ","
+                                                   + STR_DL_DST
+                                                   + "="
+                                                   + HexString.toHexString(this.dataLayerDestination);
+        if ((wildcards & OFPFW_DL_SRC) == 0)
+                                            str += ","
+                                                   + STR_DL_SRC
+                                                   + "="
+                                                   + HexString.toHexString(this.dataLayerSource);
+        if ((wildcards & OFPFW_DL_TYPE) == 0)
+                                             str += ","
+                                                    + STR_DL_TYPE
+                                                    + "=0x"
+                                                    + Integer.toHexString(U16.f(this.dataLayerType));
+        if ((wildcards & OFPFW_DL_VLAN) == 0)
+                                             str += ","
+                                                    + STR_DL_VLAN
+                                                    + "=0x"
+                                                    + Integer.toHexString(U16.f(this.dataLayerVirtualLan));
+        if ((wildcards & OFPFW_DL_VLAN_PCP) == 0)
+                                                 str += ","
+                                                        + STR_DL_VLAN_PCP
+                                                        + "="
+                                                        + Integer.toHexString(U8.f(this.dataLayerVirtualLanPriorityCodePoint));
+
+        // l3
+        if (getNetworkDestinationMaskLen() > 0)
+                                               str += ","
+                                                      + STR_NW_DST
+                                                      + "="
+                                                      + cidrToString(networkDestination,
+                                                                     getNetworkDestinationMaskLen());
+        if (getNetworkSourceMaskLen() > 0)
+                                          str += ","
+                                                 + STR_NW_SRC
+                                                 + "="
+                                                 + cidrToString(networkSource,
+                                                                getNetworkSourceMaskLen());
+        if ((wildcards & OFPFW_NW_PROTO) == 0)
+                                              str += "," + STR_NW_PROTO
+                                                     + "="
+                                                     + this.networkProtocol;
+        if ((wildcards & OFPFW_NW_TOS) == 0)
+                                            str += ","
+                                                   + STR_NW_TOS
+                                                   + "="
+                                                   + this.getNetworkTypeOfService();
+
+        // l4
+        if ((wildcards & OFPFW_TP_DST) == 0)
+                                            str += ","
+                                                   + STR_TP_DST
+                                                   + "="
+                                                   + this.transportDestination;
+        if ((wildcards & OFPFW_TP_SRC) == 0)
+                                            str += "," + STR_TP_SRC + "="
+                                                   + this.transportSource;
+        if ((str.length() > 0) && (str.charAt(0) == ','))
+                                                         str = str.substring(1); // trim
+                                                                                 // the
+                                                                                 // leading
+                                                                                 // ","
+        // done
+        return "OFMatch[" + str + "]";
+    }
+
+    /**
+     * debug a set of wildcards
+     */
+    public static String debugWildCards(int wildcards) {
+        String str = "";
+
+        // l1
+        if ((wildcards & OFPFW_IN_PORT) != 0) str += "|" + STR_IN_PORT;
+
+        // l2
+        if ((wildcards & OFPFW_DL_DST) != 0) str += "|" + STR_DL_DST;
+        if ((wildcards & OFPFW_DL_SRC) != 0) str += "|" + STR_DL_SRC;
+        if ((wildcards & OFPFW_DL_TYPE) != 0) str += "|" + STR_DL_TYPE;
+        if ((wildcards & OFPFW_DL_VLAN) != 0) str += "|" + STR_DL_VLAN;
+        if ((wildcards & OFPFW_DL_VLAN_PCP) != 0)
+                                                 str += "|"
+                                                        + STR_DL_VLAN_PCP;
+
+        int nwDstMask = Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
+                                 0);
+        int nwSrcMask = Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
+                                 0);
+
+        // l3
+        if (nwDstMask < 32)
+                           str += "|" + STR_NW_DST + "(/" + nwDstMask + ")";
+
+        if (nwSrcMask < 32)
+                           str += "|" + STR_NW_SRC + "(/" + nwSrcMask + ")";
+
+        if ((wildcards & OFPFW_NW_PROTO) != 0) str += "|" + STR_NW_PROTO;
+        if ((wildcards & OFPFW_NW_TOS) != 0) str += "|" + STR_NW_TOS;
+
+        // l4
+        if ((wildcards & OFPFW_TP_DST) != 0) str += "|" + STR_TP_DST;
+        if ((wildcards & OFPFW_TP_SRC) != 0) str += "|" + STR_TP_SRC;
+        if ((str.length() > 0) && (str.charAt(0) == '|'))
+                                                         str = str.substring(1); // trim
+                                                                                 // the
+                                                                                 // leading
+                                                                                 // ","
+        // done
+        return str;
+    }
+
+    private String cidrToString(int ip, int prefix) {
+        String str;
+        if (prefix >= 32) {
+            str = ipToString(ip);
+        } else {
+            // use the negation of mask to fake endian magic
+            int mask = ~((1 << (32 - prefix)) - 1);
+            str = ipToString(ip & mask) + "/" + prefix;
+        }
+
+        return str;
+    }
+
+    /**
+     * Set this OFMatch's parameters based on a comma-separated key=value pair
+     * dpctl-style string, e.g., from the output of OFMatch.toString() <br>
+     * <p>
+     * Supported keys/values include <br>
+     * <p>
+     * <TABLE border=1>
+     * <TR>
+     * <TD>KEY(s)
+     * <TD>VALUE
+     * </TR>
+     * <TR>
+     * <TD>"in_port","input_port"
+     * <TD>integer
+     * </TR>
+     * <TR>
+     * <TD>"dl_src","eth_src", "dl_dst","eth_dst"
+     * <TD>hex-string
+     * </TR>
+     * <TR>
+     * <TD>"dl_type", "dl_vlan", "dl_vlan_pcp"
+     * <TD>integer
+     * </TR>
+     * <TR>
+     * <TD>"nw_src", "nw_dst", "ip_src", "ip_dst"
+     * <TD>CIDR-style netmask
+     * </TR>
+     * <TR>
+     * <TD>"tp_src","tp_dst"
+     * <TD>integer (max 64k)
+     * </TR>
+     * </TABLE>
+     * <p>
+     * The CIDR-style netmasks assume 32 netmask if none given, so:
+     * "128.8.128.118/32" is the same as "128.8.128.118"
+     * 
+     * @param match
+     *            a key=value comma separated string, e.g.
+     *            "in_port=5,ip_dst=192.168.0.0/16,tp_src=80"
+     * @throws IllegalArgumentException
+     *             on unexpected key or value
+     */
+
+    public void fromString(String match) throws IllegalArgumentException {
+        if (match.equals("") || match.equalsIgnoreCase("any")
+            || match.equalsIgnoreCase("all") || match.equals("[]"))
+                                                                   match = "OFMatch[]";
+        String[] tokens = match.split("[\\[,\\]]");
+        String[] values;
+        int initArg = 0;
+        if (tokens[0].equals("OFMatch")) initArg = 1;
+        this.wildcards = OFPFW_ALL;
+        int i;
+        for (i = initArg; i < tokens.length; i++) {
+            values = tokens[i].split("=");
+            if (values.length != 2)
+                                   throw new IllegalArgumentException(
+                                                                      "Token "
+                                                                              + tokens[i]
+                                                                              + " does not have form 'key=value' parsing "
+                                                                              + match);
+            values[0] = values[0].toLowerCase(); // try to make this case insens
+            if (values[0].equals(STR_IN_PORT)
+                || values[0].equals("input_port")) {
+                this.inputPort = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_IN_PORT;
+            } else if (values[0].equals(STR_DL_DST)
+                       || values[0].equals("eth_dst")) {
+                this.dataLayerDestination = HexString.fromHexString(values[1]);
+                this.wildcards &= ~OFPFW_DL_DST;
+            } else if (values[0].equals(STR_DL_SRC)
+                       || values[0].equals("eth_src")) {
+                this.dataLayerSource = HexString.fromHexString(values[1]);
+                this.wildcards &= ~OFPFW_DL_SRC;
+            } else if (values[0].equals(STR_DL_TYPE)
+                       || values[0].equals("eth_type")) {
+                if (values[1].startsWith("0x"))
+                    this.dataLayerType = U16.t(Integer.valueOf(values[1].replaceFirst("0x",
+                                                                                      ""),
+                                                               16));
+                else
+                    this.dataLayerType = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_DL_TYPE;
+            } else if (values[0].equals(STR_DL_VLAN)) {
+                if (values[1].startsWith("0x"))
+                    this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1].replaceFirst("0x",
+                                                                                            ""),
+                                                                     16));
+                else
+                    this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_DL_VLAN;
+            } else if (values[0].equals(STR_DL_VLAN_PCP)) {
+                this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_DL_VLAN_PCP;
+            } else if (values[0].equals(STR_NW_DST)
+                       || values[0].equals("ip_dst")) {
+                setFromCIDR(values[1], STR_NW_DST);
+            } else if (values[0].equals(STR_NW_SRC)
+                       || values[0].equals("ip_src")) {
+                setFromCIDR(values[1], STR_NW_SRC);
+            } else if (values[0].equals(STR_NW_PROTO)) {
+                if (values[1].startsWith("0x"))
+                    this.networkProtocol = U8.t(Short.valueOf(values[1].replaceFirst("0x",""),16));
+                else
+                    this.networkProtocol = U8.t(Short.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_NW_PROTO;
+            } else if (values[0].equals(STR_NW_TOS)) {
+                this.setNetworkTypeOfService(U8.t(Short.valueOf(values[1])));
+                this.wildcards &= ~OFPFW_NW_TOS;
+            } else if (values[0].equals(STR_TP_DST)) {
+                this.transportDestination = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_TP_DST;
+            } else if (values[0].equals(STR_TP_SRC)) {
+                this.transportSource = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_TP_SRC;
+            } else {
+                throw new IllegalArgumentException("unknown token "
+                                                   + tokens[i] + " parsing "
+                                                   + match);
+            }
+        }
+    }
+
+    /**
+     * Set the networkSource or networkDestionation address and their wildcards
+     * from the CIDR string
+     * 
+     * @param cidr
+     *            "192.168.0.0/16" or "172.16.1.5"
+     * @param which
+     *            one of STR_NW_DST or STR_NW_SRC
+     * @throws IllegalArgumentException
+     */
+    private
+            void
+            setFromCIDR(String cidr, String which)
+                                                  throws IllegalArgumentException {
+        String values[] = cidr.split("/");
+        String[] ip_str = values[0].split("\\.");
+        int ip = 0;
+        ip += Integer.valueOf(ip_str[0]) << 24;
+        ip += Integer.valueOf(ip_str[1]) << 16;
+        ip += Integer.valueOf(ip_str[2]) << 8;
+        ip += Integer.valueOf(ip_str[3]);
+        int prefix = 32; // all bits are fixed, by default
+
+        if (values.length >= 2) prefix = Integer.valueOf(values[1]);
+        int mask = 32 - prefix;
+        if (which.equals(STR_NW_DST)) {
+            this.networkDestination = ip;
+            this.wildcards = (wildcards & ~OFPFW_NW_DST_MASK)
+                             | (mask << OFPFW_NW_DST_SHIFT);
+        } else if (which.equals(STR_NW_SRC)) {
+            this.networkSource = ip;
+            this.wildcards = (wildcards & ~OFPFW_NW_SRC_MASK)
+                             | (mask << OFPFW_NW_SRC_SHIFT);
+        }
+    }
+
+    protected static String ipToString(int ip) {
+        return Integer.toString(U8.f((byte) ((ip & 0xff000000) >> 24)))
+               + "." + Integer.toString((ip & 0x00ff0000) >> 16) + "."
+               + Integer.toString((ip & 0x0000ff00) >> 8) + "."
+               + Integer.toString(ip & 0x000000ff);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatchBeanInfo.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatchBeanInfo.java
new file mode 100644 (file)
index 0000000..16a813f
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+*    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;
+
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import java.beans.SimpleBeanInfo;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Extra info for how to treat OFMatch as a JavaBean
+ * 
+ * For some (inane!) reason, using chained setters in OFMatch breaks a lot of the JavaBean defaults.
+ * 
+ * We don't really use OFMatch as a java bean, but there are a lot of nice XML utils that work for
+ * free if OFMatch follows the java bean paradigm.
+ * 
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ *
+ */
+
+public class OFMatchBeanInfo extends SimpleBeanInfo {
+
+    @Override
+    public PropertyDescriptor[] getPropertyDescriptors() {
+        List<PropertyDescriptor> descs = new LinkedList<PropertyDescriptor>();
+        Field[] fields = OFMatch.class.getDeclaredFields();
+        String name;
+        for (int i=0; i< fields.length; i++) {
+            int mod = fields[i].getModifiers();
+            if(Modifier.isFinal(mod) ||     // don't expose static or final fields 
+                    Modifier.isStatic(mod))
+                continue;
+            
+            name = fields[i].getName();
+            Class<?> type = fields[i].getType();
+            
+            try {
+                descs.add(new PropertyDescriptor(name, 
+                        name2getter(OFMatch.class, name), 
+                        name2setter(OFMatch.class, name, type)));
+            } catch (IntrospectionException e) {
+                e.printStackTrace();
+                throw new RuntimeException(e);
+            }
+        }
+        
+        return descs.toArray(new PropertyDescriptor[0]);
+    }
+
+
+    private Method name2setter(Class<OFMatch> c, String name, Class<?> type) {
+        String mName = "set" + toLeadingCaps(name);
+        Method m = null;
+        try {
+            m = c.getMethod(mName, new Class[]{ type});
+        } catch (SecurityException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+        return m;
+    }
+
+    private Method name2getter(Class<OFMatch> c, String name) {
+        String mName= "get" + toLeadingCaps(name);
+        Method m = null;
+        try {
+            m = c.getMethod(mName, new Class[]{});
+        } catch (SecurityException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+        return m;
+    }
+    
+    private String toLeadingCaps(String s) {
+        char[] array = s.toCharArray();
+        array[0] = Character.toUpperCase(array[0]);
+        return String.valueOf(array, 0, array.length);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java
new file mode 100644 (file)
index 0000000..0caf9ff
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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;
+
+import org.openflow.util.HexString;
+
+public class OFMatchWithSwDpid {
+    protected OFMatch ofMatch;
+    protected long  switchDataPathId;
+
+    public OFMatchWithSwDpid() {
+       this.ofMatch = new OFMatch();
+       this.switchDataPathId = 0;
+    }
+    
+    public OFMatchWithSwDpid(OFMatch ofm, long swDpid) {
+       this.ofMatch = ofm.clone();
+       this.switchDataPathId = swDpid;
+    }
+    public OFMatch getOfMatch() {
+               return ofMatch;
+       }
+
+       public void setOfMatch(OFMatch ofMatch) {
+               this.ofMatch = ofMatch.clone();
+       }
+
+       public long getSwitchDataPathId() {
+        return this.switchDataPathId;
+    }
+
+    public OFMatchWithSwDpid setSwitchDataPathId(long dpid) {
+        this.switchDataPathId = dpid;
+        return this;
+    }
+    
+    @Override
+    public String toString() {
+        return "OFMatchWithSwDpid [" + HexString.toHexString(switchDataPathId) + ofMatch + "]";
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMessage.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMessage.java
new file mode 100644 (file)
index 0000000..767b7d1
--- /dev/null
@@ -0,0 +1,324 @@
+/**
+*    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;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+import org.openflow.util.U32;
+import org.openflow.util.U8;
+
+/**
+ * The base class for all OpenFlow protocol messages. This class contains the
+ * equivalent of the ofp_header which is present in all OpenFlow messages.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 3, 2010
+ * @author Rob Sherwood (rob.sherwood@stanford.edu) - Feb 3, 2010
+ */
+public class OFMessage {
+    public static final int MAXIMUM_LENGTH = (1 << 16) - 1;
+    public static byte OFP_VERSION = 0x01;
+    public static int MINIMUM_LENGTH = 8;
+
+    protected byte version;
+    protected OFType type;
+    protected short length;
+    protected int xid;
+
+    private ConcurrentHashMap<String, Object> storage;
+
+    public OFMessage() {
+        storage = null;
+        this.version = OFP_VERSION;
+    }
+
+    protected synchronized ConcurrentHashMap<String, Object> getMessageStore() {
+        if (storage == null) {
+            storage = new ConcurrentHashMap<String, Object>();;
+        }
+        return storage;
+    }
+
+    /**
+     * Get the length of this message
+     *
+     * @return
+     */
+    public short getLength() {
+        return length;
+    }
+
+    /**
+     * Get the length of this message, unsigned
+     *
+     * @return
+     */
+    public int getLengthU() {
+        return U16.f(length);
+    }
+
+    /**
+     * Set the length of this message
+     *
+     * @param length
+     */
+    public OFMessage setLength(short length) {
+        this.length = length;
+        return this;
+    }
+
+    /**
+     * Set the length of this message, unsigned
+     *
+     * @param length
+     */
+    public OFMessage setLengthU(int length) {
+        this.length = U16.t(length);
+        return this;
+    }
+
+    /**
+     * Get the type of this message
+     *
+     * @return
+     */
+    public OFType getType() {
+        return type;
+    }
+
+    /**
+     * Set the type of this message
+     *
+     * @param type
+     */
+    public void setType(OFType type) {
+        this.type = type;
+    }
+
+    /**
+     * Get the OpenFlow version of this message
+     *
+     * @return
+     */
+    public byte getVersion() {
+        return version;
+    }
+
+    /**
+     * Set the OpenFlow version of this message
+     *
+     * @param version
+     */
+    public void setVersion(byte version) {
+        this.version = version;
+    }
+
+    /**
+     * Get the transaction id of this message
+     *
+     * @return
+     */
+    public int getXid() {
+        return xid;
+    }
+
+    /**
+     * Set the transaction id of this message
+     *
+     * @param xid
+     */
+    public void setXid(int xid) {
+        this.xid = xid;
+    }
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data) {
+        this.version = data.readByte();
+        this.type = OFType.valueOf(data.readByte());
+        this.length = data.readShort();
+        this.xid = data.readInt();
+    }
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data) {
+        data.writeByte(version);
+        data.writeByte(type.getTypeValue());
+        data.writeShort(length);
+        data.writeInt(xid);
+    }
+
+    /**
+     * Returns a summary of the message
+     * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid"
+     */
+    @Override
+    public String toString() {
+        return "ofmsg" +
+            ":v=" + U8.f(this.getVersion()) +
+            ";t=" + this.getType() +
+            ";l=" + this.getLengthU() +
+            ";x=" + U32.f(this.getXid());
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 97;
+        int result = 1;
+        result = prime * result + length;
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        result = prime * result + version;
+        result = prime * result + xid;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFMessage)) {
+            return false;
+        }
+        OFMessage other = (OFMessage) obj;
+        if (length != other.length) {
+            return false;
+        }
+        if (type == null) {
+            if (other.type != null) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
+            return false;
+        }
+        if (version != other.version) {
+            return false;
+        }
+        if (xid != other.xid) {
+            return false;
+        }
+        return true;
+    }
+
+    /*
+    public static String getDataAsString(IOFSwitch sw, OFMessage msg) {
+
+        
+       Ethernet eth;
+        StringBuffer sb =  new StringBuffer("");
+
+        DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
+        Date date = new Date();
+
+        sb.append(dateFormat.format(date));
+        sb.append("      ");
+
+        switch (msg.getType()) {
+            case PACKET_IN:
+                OFPacketIn pktIn = (OFPacketIn) msg;
+                sb.append("packet_in          [ ");
+                sb.append(sw.getStringId());
+                sb.append(" -> Controller");
+                sb.append(" ]");
+
+                sb.append("\ntotal length: ");
+                sb.append(pktIn.getTotalLength());
+                sb.append("\nin_port: ");
+                sb.append(pktIn.getInPort());
+                sb.append("\ndata_length: ");
+                sb.append(pktIn.getTotalLength() - OFPacketIn.MINIMUM_LENGTH);
+                sb.append("\nbuffer: ");
+                sb.append(pktIn.getBufferId());
+
+                break;
+
+            case PACKET_OUT:
+                OFPacketOut pktOut = (OFPacketOut) msg;
+                sb.append("packet_out         [ ");
+                sb.append("Controller -> ");
+                sb.append(HexString.toHexString(sw.getId()));
+                sb.append(" ]");
+
+                sb.append("\nin_port: ");
+                sb.append(pktOut.getInPort());
+                sb.append("\nactions_len: ");
+                sb.append(pktOut.getActionsLength());
+                if (pktOut.getActions() != null) {
+                    sb.append("\nactions: ");
+                    sb.append(pktOut.getActions().toString());
+                }
+                break;
+
+            case FLOW_MOD:
+                OFFlowMod fm = (OFFlowMod) msg;
+                sb.append("flow_mod           [ ");
+                sb.append("Controller -> ");
+                sb.append(HexString.toHexString(sw.getId()));
+                sb.append(" ]");
+
+
+                sb.append("\nADD: cookie: ");
+                sb.append(fm.getCookie());
+                sb.append(" idle: ");
+                sb.append(fm.getIdleTimeout());
+                sb.append(" hard: ");
+                sb.append(fm.getHardTimeout());
+                sb.append(" pri: ");
+                sb.append(fm.getPriority());
+                sb.append(" buf: ");
+                sb.append(fm.getBufferId());
+                sb.append(" flg: ");
+                sb.append(fm.getFlags());
+                if (fm.getActions() != null) {
+                    sb.append("\nactions: ");
+                    sb.append(fm.getActions().toString());
+                }
+                break;
+
+            default:
+                sb.append("[Unknown Packet]");
+        }
+
+        sb.append("\n\n");
+        return sb.toString();
+
+    }
+    */
+
+    
+    // Check if this is really required
+    /*
+    public static byte[] getData(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+        return OFMessage.getDataAsString(sw, msg, cntx).getBytes();
+    }
+    */
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMessageContextStore.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFMessageContextStore.java
new file mode 100644 (file)
index 0000000..b60aa1c
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+*    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;
+
+import org.openflow.protocol.OFMessage;
+
+public class OFMessageContextStore<V> {
+    protected OFMessage msg;
+    String namespace;
+    
+    public OFMessageContextStore(OFMessage msg, String namespace) {
+        this.msg = msg;
+        this.namespace = namespace;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public V get(String key) {
+        return (V)msg.getMessageStore().get(namespace + "|" + key);
+    }
+    
+    public void put(String key, V value) {
+        msg.getMessageStore().put(namespace + "|" + key, value);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketIn.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketIn.java
new file mode 100644 (file)
index 0000000..c37c918
--- /dev/null
@@ -0,0 +1,211 @@
+/**
+*    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;
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+import org.openflow.util.U32;
+import org.openflow.util.U8;
+
+/**
+ * Represents an ofp_packet_in
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 8, 2010
+ */
+public class OFPacketIn extends OFMessage {
+    public static short MINIMUM_LENGTH = 18;
+
+    public enum OFPacketInReason {
+        NO_MATCH, ACTION
+    }
+
+    protected int bufferId;
+    protected short totalLength;
+    protected short inPort;
+    protected OFPacketInReason reason;
+    protected byte[] packetData;
+
+    public OFPacketIn() {
+        super();
+        this.type = OFType.PACKET_IN;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * Get buffer_id
+     * @return
+     */
+    public int getBufferId() {
+        return this.bufferId;
+    }
+
+    /**
+     * Set buffer_id
+     * @param bufferId
+     */
+    public OFPacketIn setBufferId(int bufferId) {
+        this.bufferId = bufferId;
+        return this;
+    }
+
+    /**
+     * Returns the packet data
+     * @return
+     */
+    public byte[] getPacketData() {
+        return this.packetData;
+    }
+
+    /**
+     * Sets the packet data, and updates the length of this message
+     * @param packetData
+     */
+    public OFPacketIn setPacketData(byte[] packetData) {
+        this.packetData = packetData;
+        this.length = U16.t(OFPacketIn.MINIMUM_LENGTH + packetData.length);
+        return this;
+    }
+
+    /**
+     * Get in_port
+     * @return
+     */
+    public short getInPort() {
+        return this.inPort;
+    }
+
+    /**
+     * Set in_port
+     * @param inPort
+     */
+    public OFPacketIn setInPort(short inPort) {
+        this.inPort = inPort;
+        return this;
+    }
+
+    /**
+     * Get reason
+     * @return
+     */
+    public OFPacketInReason getReason() {
+        return this.reason;
+    }
+
+    /**
+     * Set reason
+     * @param reason
+     */
+    public OFPacketIn setReason(OFPacketInReason reason) {
+        this.reason = reason;
+        return this;
+    }
+
+    /**
+     * Get total_len
+     * @return
+     */
+    public short getTotalLength() {
+        return this.totalLength;
+    }
+
+    /**
+     * Set total_len
+     * @param totalLength
+     */
+    public OFPacketIn setTotalLength(short totalLength) {
+        this.totalLength = totalLength;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.bufferId = data.readInt();
+        this.totalLength = data.readShort();
+        this.inPort = data.readShort();
+        this.reason = OFPacketInReason.values()[U8.f(data.readByte())];
+        data.readByte(); // pad
+        this.packetData = new byte[getLengthU() - MINIMUM_LENGTH];
+        data.readBytes(this.packetData);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(bufferId);
+        data.writeShort(totalLength);
+        data.writeShort(inPort);
+        data.writeByte((byte) reason.ordinal());
+        data.writeByte((byte) 0x0); // pad
+        data.writeBytes(this.packetData);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 283;
+        int result = super.hashCode();
+        result = prime * result + bufferId;
+        result = prime * result + inPort;
+        result = prime * result + Arrays.hashCode(packetData);
+        result = prime * result + ((reason == null) ? 0 : reason.hashCode());
+        result = prime * result + totalLength;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPacketIn)) {
+            return false;
+        }
+        OFPacketIn other = (OFPacketIn) obj;
+        if (bufferId != other.bufferId) {
+            return false;
+        }
+        if (inPort != other.inPort) {
+            return false;
+        }
+        if (!Arrays.equals(packetData, other.packetData)) {
+            return false;
+        }
+        if (reason == null) {
+            if (other.reason != null) {
+                return false;
+            }
+        } else if (!reason.equals(other.reason)) {
+            return false;
+        }
+        if (totalLength != other.totalLength) {
+            return false;
+        }
+        return true;
+    }
+
+    public String toString() {
+        String myStr = super.toString();
+        return "packetIn" +
+            ":bufferId=" + U32.f(this.bufferId) + myStr;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketOut.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketOut.java
new file mode 100644 (file)
index 0000000..ef4aa61
--- /dev/null
@@ -0,0 +1,260 @@
+/**
+*    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;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.OFActionFactory;
+import org.openflow.protocol.factory.OFActionFactoryAware;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_packet_out message
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 12, 2010
+ */
+public class OFPacketOut extends OFMessage implements OFActionFactoryAware {
+    public static int MINIMUM_LENGTH = 16;
+    public static int BUFFER_ID_NONE = 0xffffffff;
+
+    protected OFActionFactory actionFactory;
+    protected int bufferId;
+    protected short inPort;
+    protected short actionsLength;
+    protected List<OFAction> actions;
+    protected byte[] packetData;
+
+    public OFPacketOut() {
+        super();
+        this.type = OFType.PACKET_OUT;
+        this.length = U16.t(MINIMUM_LENGTH);
+        this.bufferId = BUFFER_ID_NONE;
+    }
+
+    /**
+     * Get buffer_id
+     * @return
+     */
+    public int getBufferId() {
+        return this.bufferId;
+    }
+
+    /**
+     * Set buffer_id
+     * @param bufferId
+     */
+    public OFPacketOut setBufferId(int bufferId) {
+        if (packetData != null && packetData.length > 0 && bufferId != BUFFER_ID_NONE) {
+            throw new IllegalArgumentException(
+                    "PacketOut should not have both bufferId and packetData set");
+        }
+        this.bufferId = bufferId;
+        return this;
+    }
+
+    /**
+     * Returns the packet data
+     * @return
+     */
+    public byte[] getPacketData() {
+        return this.packetData;
+    }
+
+    /**
+     * Sets the packet data
+     * @param packetData
+     */
+    public OFPacketOut setPacketData(byte[] packetData) {
+        if (packetData != null && packetData.length > 0 && bufferId != BUFFER_ID_NONE) {
+            throw new IllegalArgumentException(
+                    "PacketOut should not have both bufferId and packetData set");
+        }
+        this.packetData = packetData;
+        return this;
+    }
+
+    /**
+     * Get in_port
+     * @return
+     */
+    public short getInPort() {
+        return this.inPort;
+    }
+
+    /**
+     * Set in_port
+     * @param inPort
+     */
+    public OFPacketOut setInPort(short inPort) {
+        this.inPort = inPort;
+        return this;
+    }
+
+    /**
+     * Set in_port. Convenience method using OFPort enum.
+     * @param inPort
+     */
+    public OFPacketOut setInPort(OFPort inPort) {
+        this.inPort = inPort.getValue();
+        return this;
+    }
+
+    /**
+     * Get actions_len
+     * @return
+     */
+    public short getActionsLength() {
+        return this.actionsLength;
+    }
+
+    /**
+     * Get actions_len, unsigned
+     * @return
+     */
+    public int getActionsLengthU() {
+        return U16.f(this.actionsLength);
+    }
+
+    /**
+     * Set actions_len
+     * @param actionsLength
+     */
+    public OFPacketOut setActionsLength(short actionsLength) {
+        this.actionsLength = actionsLength;
+        return this;
+    }
+
+    /**
+     * Returns the actions contained in this message
+     * @return a list of ordered OFAction objects
+     */
+    public List<OFAction> getActions() {
+        return this.actions;
+    }
+
+    /**
+     * Sets the list of actions on this message
+     * @param actions a list of ordered OFAction objects
+     */
+    public OFPacketOut setActions(List<OFAction> actions) {
+        this.actions = actions;
+        return this;
+    }
+
+    @Override
+    public void setActionFactory(OFActionFactory actionFactory) {
+        this.actionFactory = actionFactory;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.bufferId = data.readInt();
+        this.inPort = data.readShort();
+        this.actionsLength = data.readShort();
+        if ( this.actionFactory == null)
+            throw new RuntimeException("ActionFactory not set");
+        this.actions = this.actionFactory.parseActions(data, getActionsLengthU());
+        this.packetData = new byte[getLengthU() - MINIMUM_LENGTH - getActionsLengthU()];
+        data.readBytes(this.packetData);
+        validate();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        validate();
+        super.writeTo(data);
+        data.writeInt(bufferId);
+        data.writeShort(inPort);
+        data.writeShort(actionsLength);
+        for (OFAction action : actions) {
+            action.writeTo(data);
+        }
+        if (this.packetData != null)
+            data.writeBytes(this.packetData);
+    }
+
+    /** validate the invariants of this OFMessage hold */
+    public void validate() {
+        if (!((bufferId != BUFFER_ID_NONE) ^ (packetData != null && packetData.length > 0))) {
+            throw new IllegalStateException(
+                    "OFPacketOut must have exactly one of (bufferId, packetData) set (not one, not both)");
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 293;
+        int result = super.hashCode();
+        result = prime * result + ((actions == null) ? 0 : actions.hashCode());
+        result = prime * result + actionsLength;
+        result = prime * result + bufferId;
+        result = prime * result + inPort;
+        result = prime * result + Arrays.hashCode(packetData);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPacketOut)) {
+            return false;
+        }
+        OFPacketOut other = (OFPacketOut) obj;
+        if (actions == null) {
+            if (other.actions != null) {
+                return false;
+            }
+        } else if (!actions.equals(other.actions)) {
+            return false;
+        }
+        if (actionsLength != other.actionsLength) {
+            return false;
+        }
+        if (bufferId != other.bufferId) {
+            return false;
+        }
+        if (inPort != other.inPort) {
+            return false;
+        }
+        if (!Arrays.equals(packetData, other.packetData)) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "OFPacketOut [actionFactory=" + actionFactory + ", actions="
+                + actions + ", actionsLength=" + actionsLength + ", bufferId=0x"
+                + Integer.toHexString(bufferId) + ", inPort=" + inPort + ", packetData="
+                + HexString.toHexString(packetData) + "]";
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketQueue.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPacketQueue.java
new file mode 100644 (file)
index 0000000..e8de1af
--- /dev/null
@@ -0,0 +1,142 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents ofp_packet_queue
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFPacketQueue {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected int queueId;
+    protected short length;
+    protected List<OFQueueProp> properties = new ArrayList<OFQueueProp>();
+
+    public OFPacketQueue() {
+        this.queueId = -1;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    public OFPacketQueue(int queueId) {
+        this.queueId = queueId;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the queueId
+     */
+    public long getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    /**
+     * @return the queue's properties
+     */
+    public List<OFQueueProp> getProperties() {
+        return properties;
+    }
+
+    /**
+     * @param properties the properties to set
+     */
+    public void setProperties(List<OFQueueProp> properties) {
+        this.properties = properties;
+
+        this.length = U16.t(MINIMUM_LENGTH);
+        for (OFQueueProp prop : properties) {
+            this.length += prop.getLength();
+        }
+    }
+
+    /**
+     * @return the length
+     */
+    public short getLength() {
+        return length;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.queueId = data.readInt();
+        this.length = data.readShort();
+        data.readShort(); // pad
+
+        int availLength = (this.length - MINIMUM_LENGTH);
+        this.properties.clear();
+
+        while (availLength > 0) {
+            OFQueueProp prop = new OFQueueProp();
+            prop.readFrom(data);
+            properties.add(prop);
+            availLength -= prop.getLength();
+        }
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(queueId);
+        data.writeShort(length);
+        data.writeShort(0); // pad
+
+        for (OFQueueProp prop : properties) {
+            prop.writeTo(data);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 359;
+        int result = super.hashCode();
+        result = prime * result + queueId;
+        result = prime * result + length;
+        result = prime * result + properties.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPacketQueue)) {
+            return false;
+        }
+        OFPacketQueue other = (OFPacketQueue) obj;
+        if (queueId != other.queueId) {
+            return false;
+        }
+        if (! properties.equals(other.properties)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPhysicalPort.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPhysicalPort.java
new file mode 100644 (file)
index 0000000..da0da61
--- /dev/null
@@ -0,0 +1,465 @@
+/**
+*    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;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents ofp_phy_port
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 25, 2010
+ */
+public class OFPhysicalPort {
+    public static int MINIMUM_LENGTH = 48;
+    public static int OFP_ETH_ALEN = 6;
+
+    public enum OFPortConfig {
+        OFPPC_PORT_DOWN    (1 << 0) {
+            public String toString() {
+                return "port-down (0x1)";
+            }
+        },
+        OFPPC_NO_STP       (1 << 1) {
+            public String toString() {
+                return "no-stp (0x2)";
+            }
+        },
+        OFPPC_NO_RECV      (1 << 2) {
+            public String toString() {
+                return "no-recv (0x4)";
+            }
+        },
+        OFPPC_NO_RECV_STP  (1 << 3) {
+            public String toString() {
+                return "no-recv-stp (0x8)";
+            }
+        },
+        OFPPC_NO_FLOOD     (1 << 4) {
+            public String toString() {
+                return "no-flood (0x10)";
+            }
+        },
+        OFPPC_NO_FWD       (1 << 5) {
+            public String toString() {
+                return "no-fwd (0x20)";
+            }
+        },
+        OFPPC_NO_PACKET_IN (1 << 6) {
+            public String toString() {
+                return "no-pkt-in (0x40)";
+            }
+        };
+
+        protected int value;
+
+        private OFPortConfig(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+    }
+
+    public enum OFPortState {
+        OFPPS_LINK_DOWN   (1 << 0) {
+            public String toString() {
+                return "link-down (0x1)";
+            }
+        },
+        OFPPS_STP_LISTEN  (0 << 8) {
+            public String toString() {
+                return "listen (0x0)";
+            }
+        },
+        OFPPS_STP_LEARN   (1 << 8) {
+            public String toString() {
+                return "learn-no-relay (0x100)";
+            }
+        },
+        OFPPS_STP_FORWARD (2 << 8) {
+            public String toString() {
+                return "forward (0x200)";
+            }
+        },
+        OFPPS_STP_BLOCK   (3 << 8) {
+            public String toString() {
+                return "block-broadcast (0x300)";
+            }
+        },
+        OFPPS_STP_MASK    (3 << 8) {
+            public String toString() {
+                return "block-broadcast (0x300)";
+            }
+        };
+
+        protected int value;
+
+        private OFPortState(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+    }
+
+    public enum OFPortFeatures {
+        OFPPF_10MB_HD    (1 << 0) {
+            public String toString() {
+                return "10mb-hd (0x1)";
+            }
+        },
+        OFPPF_10MB_FD    (1 << 1) {
+            public String toString() {
+                return "10mb-fd (0x2)";
+            }
+        },
+        OFPPF_100MB_HD   (1 << 2) {
+            public String toString() {
+                return "100mb-hd (0x4)";
+            }
+        },
+        OFPPF_100MB_FD   (1 << 3) {
+            public String toString() {
+                return "100mb-fd (0x8)";
+            }
+        },
+        OFPPF_1GB_HD     (1 << 4) {
+            public String toString() {
+                return "1gb-hd (0x10)";
+            }
+        },
+        OFPPF_1GB_FD     (1 << 5) {
+            public String toString() {
+                return "1gb-fd (0x20)";
+            }
+        },
+        OFPPF_10GB_FD    (1 << 6) {
+            public String toString() {
+                return "10gb-fd (0x40)";
+            }
+        },
+        OFPPF_COPPER     (1 << 7) {
+            public String toString() {
+                return "copper (0x80)";
+            }
+        },
+        OFPPF_FIBER      (1 << 8) {
+            public String toString() {
+                return "fiber (0x100)";
+            }
+        },
+        OFPPF_AUTONEG    (1 << 9) {
+            public String toString() {
+                return "autoneg (0x200)";
+            }
+        },
+        OFPPF_PAUSE      (1 << 10) {
+            public String toString() {
+                return "pause (0x400)";
+            }
+        },
+        OFPPF_PAUSE_ASYM (1 << 11) {
+            public String toString() {
+                return "pause-asym (0x800)";
+            }
+        };
+
+        protected int value;
+
+        private OFPortFeatures(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+    }
+
+    protected short portNumber;
+    protected byte[] hardwareAddress;
+    protected String name;
+    protected int config;
+    protected int state;
+    protected int currentFeatures;
+    protected int advertisedFeatures;
+    protected int supportedFeatures;
+    protected int peerFeatures;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the hardwareAddress
+     */
+    public byte[] getHardwareAddress() {
+        return hardwareAddress;
+    }
+
+    /**
+     * @param hardwareAddress the hardwareAddress to set
+     */
+    public void setHardwareAddress(byte[] hardwareAddress) {
+        if (hardwareAddress.length != OFP_ETH_ALEN)
+            throw new RuntimeException("Hardware address must have length "
+                    + OFP_ETH_ALEN);
+        this.hardwareAddress = hardwareAddress;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the config
+     */
+    public int getConfig() {
+        return config;
+    }
+
+    /**
+     * @param config the config to set
+     */
+    public void setConfig(int config) {
+        this.config = config;
+    }
+
+    /**
+     * @return the state
+     */
+    public int getState() {
+        return state;
+    }
+
+    /**
+     * @param state the state to set
+     */
+    public void setState(int state) {
+        this.state = state;
+    }
+
+    /**
+     * @return the currentFeatures
+     */
+    public int getCurrentFeatures() {
+        return currentFeatures;
+    }
+
+    /**
+     * @param currentFeatures the currentFeatures to set
+     */
+    public void setCurrentFeatures(int currentFeatures) {
+        this.currentFeatures = currentFeatures;
+    }
+
+    /**
+     * @return the advertisedFeatures
+     */
+    public int getAdvertisedFeatures() {
+        return advertisedFeatures;
+    }
+
+    /**
+     * @param advertisedFeatures the advertisedFeatures to set
+     */
+    public void setAdvertisedFeatures(int advertisedFeatures) {
+        this.advertisedFeatures = advertisedFeatures;
+    }
+
+    /**
+     * @return the supportedFeatures
+     */
+    public int getSupportedFeatures() {
+        return supportedFeatures;
+    }
+
+    /**
+     * @param supportedFeatures the supportedFeatures to set
+     */
+    public void setSupportedFeatures(int supportedFeatures) {
+        this.supportedFeatures = supportedFeatures;
+    }
+
+    /**
+     * @return the peerFeatures
+     */
+    public int getPeerFeatures() {
+        return peerFeatures;
+    }
+
+    /**
+     * @param peerFeatures the peerFeatures to set
+     */
+    public void setPeerFeatures(int peerFeatures) {
+        this.peerFeatures = peerFeatures;
+    }
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        if (this.hardwareAddress == null)
+            this.hardwareAddress = new byte[OFP_ETH_ALEN];
+        data.readBytes(this.hardwareAddress);
+        byte[] name = new byte[16];
+        data.readBytes(name);
+        // find the first index of 0
+        int index = 0;
+        for (byte b : name) {
+            if (0 == b)
+                break;
+            ++index;
+        }
+        this.name = new String(Arrays.copyOf(name, index),
+                Charset.forName("ascii"));
+        this.config = data.readInt();
+        this.state = data.readInt();
+        this.currentFeatures = data.readInt();
+        this.advertisedFeatures = data.readInt();
+        this.supportedFeatures = data.readInt();
+        this.peerFeatures = data.readInt();
+    }
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeBytes(hardwareAddress);
+        try {
+            byte[] name = this.name.getBytes("ASCII");
+            if (name.length < 16) {
+                data.writeBytes(name);
+                for (int i = name.length; i < 16; ++i) {
+                    data.writeByte((byte) 0);
+                }
+            } else {
+                data.writeBytes(name, 0, 15);
+                data.writeByte((byte) 0);
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        data.writeInt(this.config);
+        data.writeInt(this.state);
+        data.writeInt(this.currentFeatures);
+        data.writeInt(this.advertisedFeatures);
+        data.writeInt(this.supportedFeatures);
+        data.writeInt(this.peerFeatures);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 307;
+        int result = 1;
+        result = prime * result + advertisedFeatures;
+        result = prime * result + config;
+        result = prime * result + currentFeatures;
+        result = prime * result + Arrays.hashCode(hardwareAddress);
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + peerFeatures;
+        result = prime * result + portNumber;
+        result = prime * result + state;
+        result = prime * result + supportedFeatures;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFPhysicalPort)) {
+            return false;
+        }
+        OFPhysicalPort other = (OFPhysicalPort) obj;
+        if (advertisedFeatures != other.advertisedFeatures) {
+            return false;
+        }
+        if (config != other.config) {
+            return false;
+        }
+        if (currentFeatures != other.currentFeatures) {
+            return false;
+        }
+        if (!Arrays.equals(hardwareAddress, other.hardwareAddress)) {
+            return false;
+        }
+        if (name == null) {
+            if (other.name != null) {
+                return false;
+            }
+        } else if (!name.equals(other.name)) {
+            return false;
+        }
+        if (peerFeatures != other.peerFeatures) {
+            return false;
+        }
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (state != other.state) {
+            return false;
+        }
+        if (supportedFeatures != other.supportedFeatures) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPort.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPort.java
new file mode 100644 (file)
index 0000000..93301bc
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+*    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;
+
+public enum OFPort {
+    OFPP_MAX                ((short)0xff00),
+    OFPP_IN_PORT            ((short)0xfff8),
+    OFPP_TABLE              ((short)0xfff9),
+    OFPP_NORMAL             ((short)0xfffa),
+    OFPP_FLOOD              ((short)0xfffb),
+    OFPP_ALL                ((short)0xfffc),
+    OFPP_CONTROLLER         ((short)0xfffd),
+    OFPP_LOCAL              ((short)0xfffe),
+    OFPP_NONE               ((short)0xffff);
+
+    protected short value;
+
+    private OFPort(short value) {
+        this.value = value;
+    }
+
+    /**
+     * @return the value
+     */
+    public short getValue() {
+        return value;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPortMod.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPortMod.java
new file mode 100644 (file)
index 0000000..876e856
--- /dev/null
@@ -0,0 +1,182 @@
+/**
+*    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;
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_port_mod message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortMod extends OFMessage {
+    public static int MINIMUM_LENGTH = 32;
+
+    protected short portNumber;
+    protected byte[] hardwareAddress;
+    protected int config;
+    protected int mask;
+    protected int advertise;
+
+    public OFPortMod() {
+        super();
+        this.type = OFType.PORT_MOD;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the hardwareAddress
+     */
+    public byte[] getHardwareAddress() {
+        return hardwareAddress;
+    }
+
+    /**
+     * @param hardwareAddress the hardwareAddress to set
+     */
+    public void setHardwareAddress(byte[] hardwareAddress) {
+        if (hardwareAddress.length != OFPhysicalPort.OFP_ETH_ALEN)
+            throw new RuntimeException("Hardware address must have length "
+                    + OFPhysicalPort.OFP_ETH_ALEN);
+        this.hardwareAddress = hardwareAddress;
+    }
+
+    /**
+     * @return the config
+     */
+    public int getConfig() {
+        return config;
+    }
+
+    /**
+     * @param config the config to set
+     */
+    public void setConfig(int config) {
+        this.config = config;
+    }
+
+    /**
+     * @return the mask
+     */
+    public int getMask() {
+        return mask;
+    }
+
+    /**
+     * @param mask the mask to set
+     */
+    public void setMask(int mask) {
+        this.mask = mask;
+    }
+
+    /**
+     * @return the advertise
+     */
+    public int getAdvertise() {
+        return advertise;
+    }
+
+    /**
+     * @param advertise the advertise to set
+     */
+    public void setAdvertise(int advertise) {
+        this.advertise = advertise;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        if (this.hardwareAddress == null)
+            this.hardwareAddress = new byte[OFPhysicalPort.OFP_ETH_ALEN];
+        data.readBytes(this.hardwareAddress);
+        this.config = data.readInt();
+        this.mask = data.readInt();
+        this.advertise = data.readInt();
+        data.readInt(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeBytes(this.hardwareAddress);
+        data.writeInt(this.config);
+        data.writeInt(this.mask);
+        data.writeInt(this.advertise);
+        data.writeInt(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 311;
+        int result = super.hashCode();
+        result = prime * result + advertise;
+        result = prime * result + config;
+        result = prime * result + Arrays.hashCode(hardwareAddress);
+        result = prime * result + mask;
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPortMod)) {
+            return false;
+        }
+        OFPortMod other = (OFPortMod) obj;
+        if (advertise != other.advertise) {
+            return false;
+        }
+        if (config != other.config) {
+            return false;
+        }
+        if (!Arrays.equals(hardwareAddress, other.hardwareAddress)) {
+            return false;
+        }
+        if (mask != other.mask) {
+            return false;
+        }
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPortStatus.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFPortStatus.java
new file mode 100644 (file)
index 0000000..8bde6e7
--- /dev/null
@@ -0,0 +1,126 @@
+/**
+*    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;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_port_status message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortStatus extends OFMessage {
+    public static int MINIMUM_LENGTH = 64;
+
+    public enum OFPortReason {
+        OFPPR_ADD,
+        OFPPR_DELETE,
+        OFPPR_MODIFY
+    }
+
+    protected byte reason;
+    protected OFPhysicalPort desc;
+
+    /**
+     * @return the reason
+     */
+    public byte getReason() {
+        return reason;
+    }
+
+    /**
+     * @param reason the reason to set
+     */
+    public void setReason(byte reason) {
+        this.reason = reason;
+    }
+
+    /**
+     * @return the desc
+     */
+    public OFPhysicalPort getDesc() {
+        return desc;
+    }
+
+    /**
+     * @param desc the desc to set
+     */
+    public void setDesc(OFPhysicalPort desc) {
+        this.desc = desc;
+    }
+
+    public OFPortStatus() {
+        super();
+        this.type = OFType.PORT_STATUS;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.reason = data.readByte();
+        data.readerIndex(data.readerIndex() + 7); // skip 7 bytes of padding
+        if (this.desc == null)
+            this.desc = new OFPhysicalPort();
+        this.desc.readFrom(data);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeByte(this.reason);
+        for (int i = 0; i < 7; ++i)
+            data.writeByte((byte) 0);
+        this.desc.writeTo(data);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 313;
+        int result = super.hashCode();
+        result = prime * result + ((desc == null) ? 0 : desc.hashCode());
+        result = prime * result + reason;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPortStatus)) {
+            return false;
+        }
+        OFPortStatus other = (OFPortStatus) obj;
+        if (desc == null) {
+            if (other.desc != null) {
+                return false;
+            }
+        } else if (!desc.equals(other.desc)) {
+            return false;
+        }
+        if (reason != other.reason) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java
new file mode 100644 (file)
index 0000000..62be90d
--- /dev/null
@@ -0,0 +1,125 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_queue_get_config_request message
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueGetConfigReply extends OFMessage {
+    public static int MINIMUM_LENGTH = 16;
+
+    protected short portNumber;
+    protected List<OFPacketQueue> queues = new ArrayList<OFPacketQueue>();
+
+    public OFQueueGetConfigReply() {
+        super();
+        this.type = OFType.QUEUE_GET_CONFIG_REPLY;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the port's queues
+     */
+    public List<OFPacketQueue> getQueues() {
+        return queues;
+    }
+
+    /**
+     * @param queues the queues to set
+     */
+    public void setQueues(List<OFPacketQueue> queues) {
+        this.queues.clear();
+        this.queues.addAll(queues);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        data.readInt();   // pad
+        data.readShort(); // pad
+
+        int availLength = (this.length - MINIMUM_LENGTH);
+        this.queues.clear();
+
+        while (availLength > 0) {
+            OFPacketQueue queue = new OFPacketQueue();
+            queue.readFrom(data);
+            queues.add(queue);
+            availLength -= queue.getLength();
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeInt(0);   // pad
+        data.writeShort(0); // pad
+
+        for (OFPacketQueue queue : queues) {
+            queue.writeTo(data);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 349;
+        int result = super.hashCode();
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueGetConfigReply)) {
+            return false;
+        }
+        OFQueueGetConfigReply other = (OFQueueGetConfigReply) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java
new file mode 100644 (file)
index 0000000..cbb4a37
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_queue_get_config_request message
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueGetConfigRequest extends OFMessage {
+    public static int MINIMUM_LENGTH = 12;
+
+    protected short portNumber;
+
+    public OFQueueGetConfigRequest(short portNumber) {
+        super();
+        this.type = OFType.QUEUE_GET_CONFIG_REQUEST;
+        this.length = U16.t(MINIMUM_LENGTH);
+        this.portNumber = portNumber;
+    }
+
+    public OFQueueGetConfigRequest() {
+        this((short) 0);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeShort(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 347;
+        int result = super.hashCode();
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueGetConfigRequest)) {
+            return false;
+        }
+        OFQueueGetConfigRequest other = (OFQueueGetConfigRequest) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueProp.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFQueueProp.java
new file mode 100644 (file)
index 0000000..2e12224
--- /dev/null
@@ -0,0 +1,175 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+public class OFQueueProp {
+    private int NONE_MINIMUM_LENGTH = 8;
+    private int RATE_MINIMUM_LENGTH = 16;
+
+    public enum OFQueuePropType {
+        OFPQT_NONE       (0),
+        OFPQT_MIN_RATE   (1),
+        OFPQT_MAX_RATE   (2);
+
+        protected int value;
+
+        private OFQueuePropType(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+
+        public static OFQueuePropType fromShort(short x) {
+            switch (x) {
+                case 0:
+                    return OFPQT_NONE;
+                case 1:
+                    return OFPQT_MIN_RATE;
+                case 2:
+                    return OFPQT_MAX_RATE;
+            }
+            return null;
+        }
+    }
+
+    protected OFQueuePropType type;
+    protected short length;
+    protected short rate = -1; // not valid if type == OFPQT_NONE
+
+    public OFQueueProp() {
+        this.type = OFQueuePropType.OFPQT_NONE;
+        this.length = U16.t(NONE_MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the type
+     */
+    public OFQueuePropType getType() {
+        return type;
+    }
+
+    /**
+     * @param type the type to set
+     */
+    public void setType(OFQueuePropType type) {
+        this.type = type;
+
+        switch (type) {
+            case OFPQT_NONE:
+                this.length = U16.t(NONE_MINIMUM_LENGTH);
+                break;
+            case OFPQT_MIN_RATE:
+                this.length = U16.t(RATE_MINIMUM_LENGTH);
+                break;
+            case OFPQT_MAX_RATE:
+                this.length = U16.t(RATE_MINIMUM_LENGTH);
+                break;
+        }
+    }
+
+    /**
+     * @return the rate
+     */
+    public short getRate() {
+        return rate;
+    }
+
+    /**
+     * @param rate the rate to set
+     */
+    public void setRate(short rate) {
+        this.rate = rate;
+    }
+
+    /**
+     * @return the length
+     */
+    public short getLength() {
+        return length;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.type = OFQueuePropType.fromShort(data.readShort());
+        this.length = data.readShort();
+        data.readInt(); // pad
+
+        if (this.type == OFQueuePropType.OFPQT_MIN_RATE ||
+            this.type == OFQueuePropType.OFPQT_MAX_RATE) {
+            assert(this.length == RATE_MINIMUM_LENGTH);
+
+            this.rate = data.readShort();
+            data.readInt(); // pad
+            data.readShort(); // pad
+        } else {
+            assert(this.length == NONE_MINIMUM_LENGTH);
+        }
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.type.getValue());
+        data.writeShort(this.length);
+        data.writeInt(0); // pad
+
+        if (this.type == OFQueuePropType.OFPQT_MIN_RATE ||
+            this.type == OFQueuePropType.OFPQT_MAX_RATE) {
+            data.writeShort(this.rate);
+            data.writeInt(0); // pad
+            data.writeShort(0); // pad
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 353;
+        int result = super.hashCode();
+        result = prime * result + type.getValue();
+        result = prime * result + rate;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueProp)) {
+            return false;
+        }
+        OFQueueProp other = (OFQueueProp) obj;
+        if (type != other.type) {
+            return false;
+        }
+        if (type == OFQueuePropType.OFPQT_MIN_RATE ||
+            type == OFQueuePropType.OFPQT_MAX_RATE) {
+            if (rate != other.rate) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFSetConfig.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFSetConfig.java
new file mode 100644 (file)
index 0000000..4b23564
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+*    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;
+
+/**
+ * Represents an OFPT_SET_CONFIG type message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFSetConfig extends OFSwitchConfig {
+    public OFSetConfig() {
+        super();
+        this.type = OFType.SET_CONFIG;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java
new file mode 100644 (file)
index 0000000..e5a9c01
--- /dev/null
@@ -0,0 +1,180 @@
+/**
+*    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;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.factory.OFStatisticsFactory;
+import org.openflow.protocol.factory.OFStatisticsFactoryAware;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+
+
+/**
+ * Base class for statistics requests/replies
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 27, 2010
+ */
+public abstract class OFStatisticsMessageBase extends OFMessage implements
+        OFStatisticsFactoryAware {
+    public static int MINIMUM_LENGTH = 12;
+
+    protected OFStatisticsFactory statisticsFactory;
+    protected OFStatisticsType statisticType;
+    protected short flags;
+
+    // TODO: this should be List<? extends OFStatistics>, to
+    // allow for type safe assignments of lists of specific message
+    protected List<? extends OFStatistics> statistics;
+
+    /**
+     * @return the statisticType
+     */
+    public OFStatisticsType getStatisticType() {
+        return statisticType;
+    }
+
+    /**
+     * @param statisticType the statisticType to set
+     */
+    public void setStatisticType(OFStatisticsType statisticType) {
+        this.statisticType = statisticType;
+    }
+
+    /**
+     * @return the flags
+     */
+    public short getFlags() {
+        return flags;
+    }
+
+    /**
+     * @param flags the flags to set
+     */
+    public void setFlags(short flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * @return the statistics
+     */
+    public List<? extends OFStatistics> getStatistics() {
+        return statistics;
+    }
+
+    /**
+     * return the first statistics request in the list of statistics, for
+     * statistics messages that expect exactly one message in their body (e.g.,
+     * flow stats request, port statsrequest)
+     *
+     * @return the first and only element in the list of statistics
+     * @throw IllegalArgumentException if the list does not contain exactly one
+     *        element
+     */
+    public OFStatistics getFirstStatistics() {
+        if (statistics == null ) {
+            throw new IllegalArgumentException("Invariant violation: statistics message of type "+statisticType+" is null");
+        }
+        if (statistics.size() != 1) {
+            throw new IllegalArgumentException("Invariant violation: statistics message of type "+statisticType+" contains "+statistics.size() +" statreq/reply messages in its body (should be 1)");
+        }
+
+        return statistics.get(0);
+    }
+
+    /**
+     * @param statistics the statistics to set
+     */
+    public void setStatistics(List<? extends OFStatistics> statistics) {
+        this.statistics = statistics;
+    }
+
+    @Override
+    public void setStatisticsFactory(OFStatisticsFactory statisticsFactory) {
+        this.statisticsFactory = statisticsFactory;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.statisticType = OFStatisticsType.valueOf(data.readShort(), this
+                .getType());
+        this.flags = data.readShort();
+        if (this.statisticsFactory == null)
+            throw new RuntimeException("OFStatisticsFactory not set");
+        this.statistics = statisticsFactory.parseStatistics(this.getType(),
+                this.statisticType, data, super.getLengthU() - MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.statisticType.getTypeValue());
+        data.writeShort(this.flags);
+        if (this.statistics != null) {
+            for (OFStatistics statistic : this.statistics) {
+                statistic.writeTo(data);
+            }
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 317;
+        int result = super.hashCode();
+        result = prime * result + flags;
+        result = prime * result
+                + ((statisticType == null) ? 0 : statisticType.hashCode());
+        result = prime * result
+                + ((statistics == null) ? 0 : statistics.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFStatisticsMessageBase)) {
+            return false;
+        }
+        OFStatisticsMessageBase other = (OFStatisticsMessageBase) obj;
+        if (flags != other.flags) {
+            return false;
+        }
+        if (statisticType == null) {
+            if (other.statisticType != null) {
+                return false;
+            }
+        } else if (!statisticType.equals(other.statisticType)) {
+            return false;
+        }
+        if (statistics == null) {
+            if (other.statistics != null) {
+                return false;
+            }
+        } else if (!statistics.equals(other.statistics)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsReply.java
new file mode 100644 (file)
index 0000000..ddc7267
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_stats_reply message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFStatisticsReply extends OFStatisticsMessageBase {
+    public enum OFStatisticsReplyFlags {
+        REPLY_MORE      (1 << 0);
+
+        protected short type;
+
+        OFStatisticsReplyFlags(int type) {
+            this.type = (short) type;
+        }
+
+        public short getTypeValue() {
+            return type;
+        }
+    }
+
+    public OFStatisticsReply() {
+        super();
+        this.type = OFType.STATS_REPLY;
+        this.length = U16.t(OFStatisticsMessageBase.MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFStatisticsRequest.java
new file mode 100644 (file)
index 0000000..d1d8010
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+*    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;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_stats_request message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFStatisticsRequest extends OFStatisticsMessageBase {
+    public OFStatisticsRequest() {
+        super();
+        this.type = OFType.STATS_REQUEST;
+        this.length = U16.t(OFStatisticsMessageBase.MINIMUM_LENGTH);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFSwitchConfig.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFSwitchConfig.java
new file mode 100644 (file)
index 0000000..e04e3fa
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+*    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;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Base class representing ofp_switch_config based messages
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public abstract class OFSwitchConfig extends OFMessage {
+    public static int MINIMUM_LENGTH = 12;
+
+    public enum OFConfigFlags {
+        OFPC_FRAG_NORMAL,
+        OFPC_FRAG_DROP,
+        OFPC_FRAG_REASM,
+        OFPC_FRAG_MASK
+    }
+
+    protected short flags;
+    protected short missSendLength;
+
+    public OFSwitchConfig() {
+        super();
+        super.setLengthU(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the flags
+     */
+    public short getFlags() {
+        return flags;
+    }
+
+    /**
+     * @param flags the flags to set
+     */
+    public OFSwitchConfig setFlags(short flags) {
+        this.flags = flags;
+        return this;
+    }
+
+    /**
+     * @return the missSendLength
+     */
+    public short getMissSendLength() {
+        return missSendLength;
+    }
+
+    /**
+     * @param missSendLength the missSendLength to set
+     */
+    public OFSwitchConfig setMissSendLength(short missSendLength) {
+        this.missSendLength = missSendLength;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.flags = data.readShort();
+        this.missSendLength = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.flags);
+        data.writeShort(this.missSendLength);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 331;
+        int result = super.hashCode();
+        result = prime * result + flags;
+        result = prime * result + missSendLength;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFSwitchConfig)) {
+            return false;
+        }
+        OFSwitchConfig other = (OFSwitchConfig) obj;
+        if (flags != other.flags) {
+            return false;
+        }
+        if (missSendLength != other.missSendLength) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFType.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFType.java
new file mode 100644 (file)
index 0000000..f1c81e2
--- /dev/null
@@ -0,0 +1,249 @@
+/**
+*    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;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * List of OpenFlow types and mappings to wire protocol value and derived
+ * classes
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public enum OFType {
+    HELLO               (0, OFHello.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFHello();
+                            }}),
+    ERROR               (1, OFError.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFError();
+                            }}),
+    ECHO_REQUEST        (2, OFEchoRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFEchoRequest();
+                            }}),
+    ECHO_REPLY          (3, OFEchoReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFEchoReply();
+                            }}),
+    VENDOR              (4, OFVendor.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFVendor();
+                            }}),
+    FEATURES_REQUEST    (5, OFFeaturesRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFeaturesRequest();
+                            }}),
+    FEATURES_REPLY      (6, OFFeaturesReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFeaturesReply();
+                            }}),
+    GET_CONFIG_REQUEST  (7, OFGetConfigRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFGetConfigRequest();
+                            }}),
+    GET_CONFIG_REPLY    (8, OFGetConfigReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFGetConfigReply();
+                            }}),
+    SET_CONFIG          (9, OFSetConfig.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFSetConfig();
+                            }}),
+    PACKET_IN           (10, OFPacketIn.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPacketIn();
+                            }}),
+    FLOW_REMOVED        (11, OFFlowRemoved.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFlowRemoved();
+                            }}),
+    PORT_STATUS         (12, OFPortStatus.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPortStatus();
+                            }}),
+    PACKET_OUT          (13, OFPacketOut.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPacketOut();
+                            }}),
+    FLOW_MOD            (14, OFFlowMod.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFlowMod();
+                            }}),
+    PORT_MOD            (15, OFPortMod.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPortMod();
+                            }}),
+    STATS_REQUEST       (16, OFStatisticsRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFStatisticsRequest();
+                            }}),
+    STATS_REPLY         (17, OFStatisticsReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFStatisticsReply();
+                            }}),
+    BARRIER_REQUEST     (18, OFBarrierRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFBarrierRequest();
+                            }}),
+    BARRIER_REPLY       (19, OFBarrierReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFBarrierReply();
+                            }}),
+    QUEUE_GET_CONFIG_REQUEST    (20, OFQueueGetConfigRequest.class, new Instantiable<OFMessage>() {
+                                    @Override
+                                    public OFMessage instantiate() {
+                                        return new OFQueueGetConfigRequest();
+                                    }}),
+    QUEUE_GET_CONFIG_REPLY      (21, OFQueueGetConfigReply.class, new Instantiable<OFMessage>() {
+                                    @Override
+                                    public OFMessage instantiate() {
+                                        return new OFQueueGetConfigReply();
+                                    }});
+
+    static OFType[] mapping;
+
+    protected Class<? extends OFMessage> clazz;
+    protected Constructor<? extends OFMessage> constructor;
+    protected Instantiable<OFMessage> instantiable;
+    protected byte type;
+
+    /**
+     * Store some information about the OpenFlow type, including wire protocol
+     * type number, length, and derived class
+     *
+     * @param type Wire protocol number associated with this OFType
+     * @param clazz The Java class corresponding to this type of OpenFlow
+     *              message
+     * @param instantiator An Instantiator<OFMessage> implementation that creates an
+     *          instance of the specified OFMessage
+     */
+    OFType(int type, Class<? extends OFMessage> clazz, Instantiable<OFMessage> instantiator) {
+        this.type = (byte) type;
+        this.clazz = clazz;
+        this.instantiable = instantiator;
+        try {
+            this.constructor = clazz.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + clazz, e);
+        }
+        OFType.addMapping(this.type, this);
+    }
+
+    /**
+     * Adds a mapping from type value to OFType enum
+     *
+     * @param i OpenFlow wire protocol type
+     * @param t type
+     */
+    static public void addMapping(byte i, OFType t) {
+        if (mapping == null)
+            mapping = new OFType[32];
+        OFType.mapping[i] = t;
+    }
+
+    /**
+     * Remove a mapping from type value to OFType enum
+     *
+     * @param i OpenFlow wire protocol type
+     */
+    static public void removeMapping(byte i) {
+        OFType.mapping[i] = null;
+    }
+
+    /**
+     * Given a wire protocol OpenFlow type number, return the OFType associated
+     * with it
+     *
+     * @param i wire protocol number
+     * @return OFType enum type
+     */
+
+    static public OFType valueOf(Byte i) {
+        return OFType.mapping[i];
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this OFType
+     */
+    public byte getTypeValue() {
+        return this.type;
+    }
+
+    /**
+     * @return return the OFMessage subclass corresponding to this OFType
+     */
+    public Class<? extends OFMessage> toClass() {
+        return clazz;
+    }
+
+    /**
+     * Returns the no-argument Constructor of the implementation class for
+     * this OFType
+     * @return the constructor
+     */
+    public Constructor<? extends OFMessage> getConstructor() {
+        return constructor;
+    }
+
+    /**
+     * Returns a new instance of the OFMessage represented by this OFType
+     * @return the new object
+     */
+    public OFMessage newInstance() {
+        return instantiable.instantiate();
+    }
+
+    /**
+     * @return the instantiable
+     */
+    public Instantiable<OFMessage> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * @param instantiable the instantiable to set
+     */
+    public void setInstantiable(Instantiable<OFMessage> instantiable) {
+        this.instantiable = instantiable;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFVendor.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/OFVendor.java
new file mode 100644 (file)
index 0000000..8ecb862
--- /dev/null
@@ -0,0 +1,131 @@
+/**
+*    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;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+import org.openflow.protocol.factory.OFVendorDataFactory;
+import org.openflow.protocol.factory.OFVendorDataFactoryAware;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Represents ofp_vendor_header
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFVendor extends OFMessage implements OFVendorDataFactoryAware {
+    public static int MINIMUM_LENGTH = 12;
+
+    protected int vendor;
+    protected OFVendorData vendorData;
+    protected OFVendorDataFactory vendorDataFactory;
+
+    public OFVendor() {
+        super();
+        this.type = OFType.VENDOR;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the vendor
+     */
+    public int getVendor() {
+        return vendor;
+    }
+
+    /**
+     * @param vendor the vendor to set
+     */
+    public void setVendor(int vendor) {
+        this.vendor = vendor;
+    }
+
+    /**
+     * @return the data
+     */
+    public OFVendorData getVendorData() {
+        return vendorData;
+    }
+
+    /**
+     * @param data the data to set
+     */
+    public void setVendorData(OFVendorData vendorData) {
+        this.vendorData = vendorData;
+    }
+
+    @Override
+    public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory) {
+        this.vendorDataFactory = vendorDataFactory;
+    }
+      
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.vendor = data.readInt();
+        if (vendorDataFactory == null)
+            throw new RuntimeException("OFVendorDataFactory not set");
+            
+        this.vendorData = vendorDataFactory.parseVendorData(vendor,
+                data, super.getLengthU() - MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.vendor);
+        if (vendorData != null)
+            vendorData.writeTo(data);
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 337;
+        int result = super.hashCode();
+        result = prime * result + vendor;
+        if (vendorData != null)
+            result = prime * result + vendorData.hashCode();
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        OFVendor other = (OFVendor) obj;
+        if (vendor != other.vendor)
+            return false;
+        if (vendorData == null) {
+            if (other.vendorData != null) {
+                return false;
+            }
+        } else if (!vendorData.equals(other.vendorData)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/Wildcards.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/Wildcards.java
new file mode 100644 (file)
index 0000000..fbda858
--- /dev/null
@@ -0,0 +1,527 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * a more user friendly representation of the wildcards bits in an OpenFlow
+ * match. The Wildcards object is
+ * <ul>
+ * <li>immutable (i.e., threadsafe)</li>
+ * <li>instance managed (don't instantiate it yourself), instead call "of"</li>
+ * <ul>
+ * <p>
+ * You can construct a Wildcard object from either its integer representation
+ * </p>
+ * <code>
+ *    Wildcard.of(0x3820e0);
+ *  </code>
+ * <p>
+ * Or start with either an empty or full wildcard, and select/unselect foo.
+ * </p>
+ * <code>
+ *  Wildcard w = Wildcards.NONE
+ *                .set(Flag.DL_SRC, Flag. DL_DST, Flag.DL_VLAN_PCP)
+ *                .setNwDstMask(8)
+ *                .setNwSrcMask(8);
+ *  </code>
+ * <p>
+ * <b>Remember:</b> Wildcards objects are immutable. set... operations have
+ * <b>NO EFFECT</b> on the current wildcard object. You HAVE to use the returned
+ * changed object.
+ * </p>
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class Wildcards {
+
+    public final static Wildcards FULL = new Wildcards(OFMatch.OFPFW_ALL_SANITIZED);
+    private static final int FULL_INT = FULL.getInt();
+
+    public final static Wildcards EXACT = new Wildcards(0);
+
+    // floodlight common case: matches on inport + l2
+    public final static int INT_INPORT_L2_MATCH = 0x3820e0;
+    public final static Wildcards INPORT_L2_MATCH = new Wildcards(
+            INT_INPORT_L2_MATCH);
+
+    /**
+     * enum type for the binary flags that can be set in the wildcards field of
+     * an OFMatch. Replaces the unwieldy c-ish int constants in OFMatch.
+     */
+    public static enum Flag {
+        IN_PORT(OFMatch.OFPFW_IN_PORT),  /* Switch input port. */
+        DL_VLAN(OFMatch.OFPFW_DL_VLAN), /* VLAN id. */
+        DL_SRC(OFMatch.OFPFW_DL_SRC), /* Ethernet source address. */
+        DL_DST(OFMatch.OFPFW_DL_DST), /* Ethernet destination addr */
+        DL_TYPE(OFMatch.OFPFW_DL_TYPE), /* Ethernet frame type. */
+        NW_PROTO(OFMatch.OFPFW_NW_PROTO), /* IP protocol. */
+        TP_SRC(OFMatch.OFPFW_TP_SRC), /* TCP/UDP source port. */
+        TP_DST(OFMatch.OFPFW_TP_DST), /* TCP/UDP destination port. */
+        DL_VLAN_PCP(OFMatch.OFPFW_DL_VLAN_PCP), /* VLAN priority. */
+        NW_SRC(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFMatch.OFPFW_NW_SRC_MASK) >> OFMatch.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFMatch.OFPFW_NW_SRC_MASK) | (srcMask << OFMatch.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFMatch.OFPFW_NW_SRC_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFMatch.OFPFW_NW_SRC_ALL;
+            }
+
+            @Override
+            boolean isPartiallyOn(int flags) {
+                int intValue = getInt(flags);
+                return intValue > 0 && intValue < 32;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+
+        },
+        NW_DST(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFMatch.OFPFW_NW_DST_MASK) >> OFMatch.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFMatch.OFPFW_NW_DST_MASK) | (srcMask << OFMatch.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFMatch.OFPFW_NW_DST_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFMatch.OFPFW_NW_DST_ALL;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+        },
+        NW_TOS(OFMatch.OFPFW_NW_TOS); /* IP ToS (DSCP field, 6 bits). */
+
+        final int bitPosition;
+
+        Flag(int bitPosition) {
+            this.bitPosition = bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag cleared (match
+         *         on this field)
+         */
+        int matchOn(int flags) {
+            return flags & ~this.bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag set (wildcard
+         *         this field)
+         */
+        int wildcard(int flags) {
+            return flags | this.bitPosition;
+        }
+
+        /**
+         * @return true iff this is a true boolean flag that can either be off
+         *         or on.True in OF-1.0 for all fields except NW_SRC and NW_DST
+         */
+        boolean isBolean() {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field is currently 'partially on'.
+         *         Always false for true Boolean Flags. Can be true in OF-1.0
+         *         for NW_SRC, NW_DST.
+         */
+        boolean isPartiallyOn(int flags) {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field currently fully on (fully
+         *         wildcarded). Equivalent to the boolean flag being set in the
+         *         bitmask for bit flags, and to the wildcarded bit length set
+         *         to >=32 for NW_SRC and NW_DST
+         * @param flags
+         * @return
+         */
+        boolean isFullyOn(int flags) {
+            return (flags & this.bitPosition) != 0;
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int setInt(int flags, int srcMask) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int getInt(int flags) {
+            throw new UnsupportedOperationException();
+        }
+
+
+    }
+
+    private final int flags;
+
+    /** private constructor. use Wildcard.of() instead */
+    private Wildcards(int flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * return a wildcard object matching the given int flags. May reuse / cache
+     * frequently used wildcard instances. Don't rely on it though (use equals
+     * not ==).
+     *
+     * @param flags
+     * @return
+     */
+    public static Wildcards of(int paramFlags) {
+        int flags = sanitizeInt(paramFlags);
+        switch(flags) {
+            case 0x0000:
+                return EXACT;
+            case OFMatch.OFPFW_ALL_SANITIZED:
+                return FULL;
+            case INT_INPORT_L2_MATCH:
+                return INPORT_L2_MATCH;
+            default:
+                return new Wildcards(flags);
+        }
+    }
+
+    /** convience method return a wildcard for exactly one set flag */
+    public static Wildcards of(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.wildcard(0));
+    }
+
+    /** convience method return a wildcard for exactly two set flags */
+    public static Wildcards of(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.wildcard(setFlag2.wildcard(0)));
+    }
+
+    /** convience method return a wildcard for an arbitrary number of set flags */
+    public static Wildcards of(Wildcards.Flag... setFlags) {
+        int flags = 0;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(0);
+        return Wildcards.of(flags);
+    }
+
+    /** convience method return a wildcards for ofmatches that match on one flag */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.matchOn(FULL_INT));
+    }
+
+    /**
+     * convience method return a wildcard for for an ofmatch that match on two
+     * flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.matchOn(setFlag2.matchOn(FULL_INT)));
+    }
+
+    /**
+     * convience method return a wildcard for an ofmatch that amtch on an
+     * arbitrary number of set flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag... setFlags) {
+        int flags = FULL_INT;
+        for (Wildcards.Flag flag : setFlags)
+           flags = flag.matchOn(flags);
+        return Wildcards.of(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag) {
+        int flags = flag.wildcard(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.wildcard(flag2.wildcard(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags wildcarded
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flag
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag) {
+        int flags = flag.matchOn(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.matchOn(flag2.matchOn(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.matchOn(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return the nw src mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwSrcMask() {
+        return Math.max(0, 32 - Flag.NW_SRC.getInt(flags));
+    }
+
+    /**
+     * return the nw dst mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwDstMask() {
+        return Math.max(0, 32 - Flag.NW_DST.getInt(flags));
+    }
+
+    /**
+     * return a Wildcard object that has the given nwSrcCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param srcCidrMask
+     *            source mask to set in <b>normal CIDR notation</b>, i.e., 8
+     *            means x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwSrcMask(int srcCidrMask) {
+        int flags = Flag.NW_SRC.setInt(this.flags, Math.max(0, 32 - srcCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that has the given nwDstCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param dstCidrMask
+     *            dest mask to set in <b>normal CIDR notation</b>, i.e., 8 means
+     *            x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwDstMask(int dstCidrMask) {
+        int flags = Flag.NW_DST.setInt(this.flags, Math.max(0, 32 - dstCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that is inverted to this wildcard object.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     * @return a modified object
+     */
+    public Wildcards inverted() {
+        return Wildcards.of(flags ^ OFMatch.OFPFW_ALL_SANITIZED);
+    }
+
+    public boolean isWildcarded(Flag flag) {
+        return flag.isFullyOn(flags);
+    }
+
+    /**
+     * return all wildcard flags that are fully wildcarded as an EnumSet. Do not
+     * modify. Note: some flags (like NW_SRC and NW_DST) that are partially
+     * wildcarded are not returned in this set.
+     *
+     * @return the EnumSet of wildcards
+     */
+    public EnumSet<Wildcards.Flag> getWildcardedFlags() {
+        EnumSet<Wildcards.Flag> res = EnumSet.noneOf(Wildcards.Flag.class);
+        for (Wildcards.Flag flag : Flag.values()) {
+            if (flag.isFullyOn(flags)) {
+                res.add(flag);
+            }
+        }
+        return res;
+    }
+
+    /** return the OpenFlow 'wire' integer representation of these wildcards */
+    public int getInt() {
+        return flags;
+    }
+
+    /**
+     * return the OpenFlow 'wire' integer representation of these wildcards.
+     * Sanitize nw_src and nw_dst to be max. 32 (values > 32 are technically
+     * possible, but don't make semantic sense)
+     */
+    public static int sanitizeInt(int flags) {
+        if (((flags & OFMatch.OFPFW_NW_SRC_MASK) >> OFMatch.OFPFW_NW_SRC_SHIFT) > 32) {
+            flags = (flags & ~OFMatch.OFPFW_NW_SRC_MASK) | OFMatch.OFPFW_NW_SRC_ALL;
+        }
+        if (((flags & OFMatch.OFPFW_NW_DST_MASK) >> OFMatch.OFPFW_NW_DST_SHIFT) > 32) {
+            flags = (flags & ~OFMatch.OFPFW_NW_DST_MASK) | OFMatch.OFPFW_NW_DST_ALL;
+        }
+        return flags;
+    }
+
+    /**
+     * is this a wildcard set that has all flags set + and full (/0) nw_src and
+     * nw_dst wildcarding ?
+     */
+    public boolean isFull() {
+        return flags == OFMatch.OFPFW_ALL || flags == OFMatch.OFPFW_ALL_SANITIZED;
+    }
+
+    /** is this a wildcard of an exact match */
+    public boolean isExact() {
+        return flags == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + flags;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Wildcards other = (Wildcards) obj;
+        if (flags != other.flags)
+            return false;
+        return true;
+    }
+
+
+
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFAction.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFAction.java
new file mode 100644 (file)
index 0000000..57b5dc1
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+*    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.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * The base class for all OpenFlow Actions.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFAction implements Cloneable {
+    /**
+     * Note the true minimum length for this header is 8 including a pad to 64
+     * bit alignment, however as this base class is used for demuxing an
+     * incoming Action, it is only necessary to read the first 4 bytes.  All
+     * Actions extending this class are responsible for reading/writing the
+     * first 8 bytes, including the pad if necessary.
+     */
+    public static int MINIMUM_LENGTH = 4;
+    public static int OFFSET_LENGTH = 2;
+    public static int OFFSET_TYPE = 0;
+
+    protected OFActionType type;
+    protected short length;
+
+    /**
+     * Get the length of this message
+     *
+     * @return
+     */
+    public short getLength() {
+        return length;
+    }
+
+    /**
+     * Get the length of this message, unsigned
+     *
+     * @return
+     */
+    public int getLengthU() {
+        return U16.f(length);
+    }
+
+    /**
+     * Set the length of this message
+     *
+     * @param length
+     */
+    public OFAction setLength(short length) {
+        this.length = length;
+        return this;
+    }
+
+    /**
+     * Get the type of this message
+     *
+     * @return OFActionType enum
+     */
+    public OFActionType getType() {
+        return this.type;
+    }
+
+    /**
+     * Set the type of this message
+     *
+     * @param type
+     */
+    public void setType(OFActionType type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns a summary of the message
+     * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid"
+     */
+    public String toString() {
+        return "ofaction" +
+            ";t=" + this.getType() +
+            ";l=" + this.getLength();
+    }
+    
+    /**
+     * Given the output from toString(), 
+     * create a new OFAction
+     * @param val
+     * @return
+     */
+    public static OFAction fromString(String val) {
+        String tokens[] = val.split(";");
+        if (!tokens[0].equals("ofaction"))
+            throw new IllegalArgumentException("expected 'ofaction' but got '" + 
+                    tokens[0] + "'");
+        String type_tokens[] = tokens[1].split("="); 
+        String len_tokens[] = tokens[2].split("=");
+        OFAction action = new OFAction();
+        action.setLength(Short.valueOf(len_tokens[1]));
+        action.setType(OFActionType.valueOf(type_tokens[1]));
+        return action;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.type = OFActionType.valueOf(data.readShort());
+        this.length = data.readShort();
+        // Note missing PAD, see MINIMUM_LENGTH comment for details
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(type.getTypeValue());
+        data.writeShort(length);
+        // Note missing PAD, see MINIMUM_LENGTH comment for details
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 347;
+        int result = 1;
+        result = prime * result + length;
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFAction)) {
+            return false;
+        }
+        OFAction other = (OFAction) obj;
+        if (length != other.length) {
+            return false;
+        }
+        if (type == null) {
+            if (other.type != null) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    public OFAction clone() throws CloneNotSupportedException {
+        return (OFAction) super.clone();
+    }
+    
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayer.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayer.java
new file mode 100644 (file)
index 0000000..a6eae63
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+import java.util.Arrays;
+
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFPhysicalPort;
+
+/**
+ * Represents an ofp_action_dl_addr
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public abstract class OFActionDataLayer extends OFAction {
+    public static int MINIMUM_LENGTH = 16;
+
+    protected byte[] dataLayerAddress;
+
+    /**
+     * @return the dataLayerAddress
+     */
+    public byte[] getDataLayerAddress() {
+        return dataLayerAddress;
+    }
+
+    /**
+     * @param dataLayerAddress the dataLayerAddress to set
+     */
+    public void setDataLayerAddress(byte[] dataLayerAddress) {
+        this.dataLayerAddress = dataLayerAddress;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        if (this.dataLayerAddress == null)
+            this.dataLayerAddress = new byte[OFPhysicalPort.OFP_ETH_ALEN];
+        data.readBytes(this.dataLayerAddress);
+        data.readInt();
+        data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeBytes(this.dataLayerAddress);
+        data.writeInt(0);
+        data.writeShort((short) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 347;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(dataLayerAddress);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionDataLayer)) {
+            return false;
+        }
+        OFActionDataLayer other = (OFActionDataLayer) obj;
+        if (!Arrays.equals(dataLayerAddress, other.dataLayerAddress)) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayerDestination.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayerDestination.java
new file mode 100644 (file)
index 0000000..48b8d0f
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+*    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.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionDataLayerDestination extends OFActionDataLayer {
+    public OFActionDataLayerDestination() {
+        super();
+        super.setType(OFActionType.SET_DL_DST);
+        super.setLength((short) OFActionDataLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionDataLayerDestination(byte[] address) {
+        this();
+        this.dataLayerAddress = address;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayerSource.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionDataLayerSource.java
new file mode 100644 (file)
index 0000000..e04561c
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+*    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.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionDataLayerSource extends OFActionDataLayer {
+    public OFActionDataLayerSource() {
+        super();
+        super.setType(OFActionType.SET_DL_SRC);
+        super.setLength((short) OFActionDataLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionDataLayerSource(byte[] address) {
+        this();
+        this.dataLayerAddress = address;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionEnqueue.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionEnqueue.java
new file mode 100644 (file)
index 0000000..0ec2fa3
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_enqueue
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionEnqueue extends OFAction {
+    public static int MINIMUM_LENGTH = 16;
+
+    protected short port;
+    protected int queueId;
+
+    public OFActionEnqueue() {
+        super.setType(OFActionType.OPAQUE_ENQUEUE);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionEnqueue(short port, int queueId) {
+        this();
+        this.port = port;
+        this.queueId = queueId;
+    }
+
+    /**
+     * Get the output port
+     * @return
+     */
+    public short getPort() {
+        return this.port;
+    }
+
+    /**
+     * Set the output port
+     * @param port
+     */
+    public void setPort(short port) {
+        this.port = port;
+    }
+
+    /**
+     * @return the queueId
+     */
+    public int getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.port = data.readShort();
+        data.readShort();
+        data.readInt();
+        this.queueId = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.port);
+        data.writeShort((short) 0);
+        data.writeInt(0);
+        data.writeInt(this.queueId);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 349;
+        int result = super.hashCode();
+        result = prime * result + port;
+        result = prime * result + queueId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionEnqueue)) {
+            return false;
+        }
+        OFActionEnqueue other = (OFActionEnqueue) obj;
+        if (port != other.port) {
+            return false;
+        }
+        if (queueId != other.queueId) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerAddress.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerAddress.java
new file mode 100644 (file)
index 0000000..dc65ae9
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_nw_addr
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public abstract class OFActionNetworkLayerAddress extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected int networkAddress;
+
+    /**
+     * @return the networkAddress
+     */
+    public int getNetworkAddress() {
+        return networkAddress;
+    }
+
+    /**
+     * @param networkAddress the networkAddress to set
+     */
+    public void setNetworkAddress(int networkAddress) {
+        this.networkAddress = networkAddress;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.networkAddress = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.networkAddress);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 353;
+        int result = super.hashCode();
+        result = prime * result + networkAddress;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionNetworkLayerAddress)) {
+            return false;
+        }
+        OFActionNetworkLayerAddress other = (OFActionNetworkLayerAddress) obj;
+        if (networkAddress != other.networkAddress) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerDestination.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerDestination.java
new file mode 100644 (file)
index 0000000..13c14ff
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+*    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.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionNetworkLayerDestination extends OFActionNetworkLayerAddress {
+    public OFActionNetworkLayerDestination() {
+        super();
+        super.setType(OFActionType.SET_NW_DST);
+        super.setLength((short) OFActionNetworkLayerAddress.MINIMUM_LENGTH);
+    }
+    
+    public OFActionNetworkLayerDestination(int ip) {
+        this();
+        this.networkAddress = ip;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerSource.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerSource.java
new file mode 100644 (file)
index 0000000..ef1d005
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+*    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.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionNetworkLayerSource extends OFActionNetworkLayerAddress {
+    public OFActionNetworkLayerSource() {
+        super();
+        super.setType(OFActionType.SET_NW_SRC);
+        super.setLength((short) OFActionNetworkLayerAddress.MINIMUM_LENGTH);
+    }
+    
+    public OFActionNetworkLayerSource(int ip) {
+        this();
+        this.networkAddress = ip;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkTypeOfService.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionNetworkTypeOfService.java
new file mode 100644 (file)
index 0000000..0d38180
--- /dev/null
@@ -0,0 +1,101 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_enqueue
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionNetworkTypeOfService extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected byte networkTypeOfService;
+
+    public OFActionNetworkTypeOfService() {
+        super.setType(OFActionType.SET_NW_TOS);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionNetworkTypeOfService(byte tos) {
+        this();
+        this.networkTypeOfService = tos;
+    }
+    
+
+    /**
+     * @return the networkTypeOfService
+     */
+    public byte getNetworkTypeOfService() {
+        return networkTypeOfService;
+    }
+
+    /**
+     * @param networkTypeOfService the networkTypeOfService to set
+     */
+    public void setNetworkTypeOfService(byte networkTypeOfService) {
+        this.networkTypeOfService = networkTypeOfService;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.networkTypeOfService = data.readByte();
+        data.readShort();
+        data.readByte();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeByte(this.networkTypeOfService);
+        data.writeShort((short) 0);
+        data.writeByte((byte) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 359;
+        int result = super.hashCode();
+        result = prime * result + networkTypeOfService;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionNetworkTypeOfService)) {
+            return false;
+        }
+        OFActionNetworkTypeOfService other = (OFActionNetworkTypeOfService) obj;
+        if (networkTypeOfService != other.networkTypeOfService) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionOutput.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionOutput.java
new file mode 100644 (file)
index 0000000..b9521d0
--- /dev/null
@@ -0,0 +1,158 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class OFActionOutput extends OFAction implements Cloneable {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short port;
+    protected short maxLength;
+
+    public OFActionOutput() {
+        super.setType(OFActionType.OUTPUT);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+
+    /**
+     * Create an Output Action sending packets out the specified
+     * OpenFlow port.
+     *
+     * This is the most common creation pattern for OFActions.
+     *
+     * @param port
+     */
+
+    public OFActionOutput(short port) {
+        this(port, (short) 65535);
+    }
+
+    /**
+     * Create an Output Action specifying both the port AND
+     * the snaplen of the packet to send out that port.
+     * The length field is only meaningful when port == OFPort.OFPP_CONTROLLER
+     * @param port
+     * @param maxLength The maximum number of bytes of the packet to send.
+     * Most hardware only supports this value for OFPP_CONTROLLER
+     */
+
+    public OFActionOutput(short port, short maxLength) {
+        super();
+        super.setType(OFActionType.OUTPUT);
+        super.setLength((short) MINIMUM_LENGTH);
+        this.port = port;
+        this.maxLength = maxLength;
+    }
+
+    /**
+     * Get the output port
+     * @return
+     */
+    public short getPort() {
+        return this.port;
+    }
+
+    /**
+     * Set the output port
+     * @param port
+     */
+    public OFActionOutput setPort(short port) {
+        this.port = port;
+        return this;
+    }
+
+    /**
+     * Get the max length to send to the controller
+     * @return
+     */
+    public short getMaxLength() {
+        return this.maxLength;
+    }
+
+    /**
+     * Set the max length to send to the controller
+     * @param maxLength
+     */
+    public OFActionOutput setMaxLength(short maxLength) {
+        this.maxLength = maxLength;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.port = data.readShort();
+        this.maxLength = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(port);
+        data.writeShort(maxLength);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 367;
+        int result = super.hashCode();
+        result = prime * result + maxLength;
+        result = prime * result + port;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionOutput)) {
+            return false;
+        }
+        OFActionOutput other = (OFActionOutput) obj;
+        if (maxLength != other.maxLength) {
+            return false;
+        }
+        if (port != other.port) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "OFActionOutput [maxLength=" + maxLength + ", port=" + U16.f(port)
+                + ", length=" + length + ", type=" + type + "]";
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionStripVirtualLan.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionStripVirtualLan.java
new file mode 100644 (file)
index 0000000..7d6b849
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+
+/**
+ * Represents an ofp_action_strip_vlan
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionStripVirtualLan extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    public OFActionStripVirtualLan() {
+        super();
+        super.setType(OFActionType.STRIP_VLAN);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        // PAD
+        data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        // PAD
+        data.writeInt(0);
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayer.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayer.java
new file mode 100644 (file)
index 0000000..0bc09c9
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_tp_port
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public abstract class OFActionTransportLayer extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short transportPort;
+
+    /**
+     * @return the transportPort
+     */
+    public short getTransportPort() {
+        return transportPort;
+    }
+
+    /**
+     * @param transportPort the transportPort to set
+     */
+    public void setTransportPort(short transportPort) {
+        this.transportPort = transportPort;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.transportPort = data.readShort();
+        data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.transportPort);
+        data.writeShort((short) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 373;
+        int result = super.hashCode();
+        result = prime * result + transportPort;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionTransportLayer)) {
+            return false;
+        }
+        OFActionTransportLayer other = (OFActionTransportLayer) obj;
+        if (transportPort != other.transportPort) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayerDestination.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayerDestination.java
new file mode 100644 (file)
index 0000000..7e7b0f1
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+*    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.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionTransportLayerDestination extends OFActionTransportLayer {
+    public OFActionTransportLayerDestination() {
+        super();
+        super.setType(OFActionType.SET_TP_DST);
+        super.setLength((short) OFActionTransportLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionTransportLayerDestination(short port) {
+        this();
+        this.transportPort = port;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayerSource.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionTransportLayerSource.java
new file mode 100644 (file)
index 0000000..385aa53
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+*    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.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionTransportLayerSource extends OFActionTransportLayer {
+    public OFActionTransportLayerSource() {
+        super();
+        super.setType(OFActionType.SET_TP_SRC);
+        super.setLength((short) OFActionTransportLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionTransportLayerSource(short port) {
+        this();
+        this.transportPort = port;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionType.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionType.java
new file mode 100644 (file)
index 0000000..1822917
--- /dev/null
@@ -0,0 +1,203 @@
+/**
+*    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.action;
+
+import java.lang.reflect.Constructor;
+
+import org.openflow.protocol.Instantiable;
+
+/**
+ * List of OpenFlow Action types and mappings to wire protocol value and
+ * derived classes
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public enum OFActionType {
+    OUTPUT              (0, OFActionOutput.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionOutput();
+                            }}),
+    SET_VLAN_ID        (1, OFActionVirtualLanIdentifier.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionVirtualLanIdentifier();
+                            }}),
+    SET_VLAN_PCP        (2, OFActionVirtualLanPriorityCodePoint.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionVirtualLanPriorityCodePoint();
+                            }}),
+    STRIP_VLAN          (3, OFActionStripVirtualLan.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionStripVirtualLan();
+                            }}),
+    SET_DL_SRC          (4, OFActionDataLayerSource.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionDataLayerSource();
+                            }}),
+    SET_DL_DST          (5, OFActionDataLayerDestination.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionDataLayerDestination();
+                            }}),
+    SET_NW_SRC          (6, OFActionNetworkLayerSource.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionNetworkLayerSource();
+                            }}),
+    SET_NW_DST          (7, OFActionNetworkLayerDestination.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionNetworkLayerDestination();
+                            }}),
+    SET_NW_TOS          (8, OFActionNetworkTypeOfService.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionNetworkTypeOfService();
+                            }}),
+    SET_TP_SRC          (9, OFActionTransportLayerSource.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionTransportLayerSource();
+                            }}),
+    SET_TP_DST          (10, OFActionTransportLayerDestination.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionTransportLayerDestination();
+                            }}),
+    OPAQUE_ENQUEUE      (11, OFActionEnqueue.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionEnqueue();
+                            }}),
+    VENDOR              (0xffff, OFActionVendor.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionVendorGeneric();
+                            }});
+
+    protected static OFActionType[] mapping;
+
+    protected Class<? extends OFAction> clazz;
+    protected Constructor<? extends OFAction> constructor;
+    protected Instantiable<OFAction> instantiable;
+    protected int minLen;
+    protected short type;
+
+    /**
+     * Store some information about the OpenFlow Action type, including wire
+     * protocol type number, length, and derrived class
+     *
+     * @param type Wire protocol number associated with this OFType
+     * @param clazz The Java class corresponding to this type of OpenFlow Action
+     * @param instantiable the instantiable for the OFAction this type represents
+     */
+    OFActionType(int type, Class<? extends OFAction> clazz, Instantiable<OFAction> instantiable) {
+        this.type = (short) type;
+        this.clazz = clazz;
+        this.instantiable = instantiable;
+        try {
+            this.constructor = clazz.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + clazz, e);
+        }
+        OFActionType.addMapping(this.type, this);
+    }
+
+    /**
+     * Adds a mapping from type value to OFActionType enum
+     *
+     * @param i OpenFlow wire protocol Action type value
+     * @param t type
+     */
+    static public void addMapping(short i, OFActionType t) {
+        if (mapping == null)
+            mapping = new OFActionType[16];
+        // bring higher mappings down to the edge of our array
+        if (i < 0)
+            i = (short) (16 + i);
+        OFActionType.mapping[i] = t;
+    }
+
+    /**
+     * Given a wire protocol OpenFlow type number, return the OFType associated
+     * with it
+     *
+     * @param i wire protocol number
+     * @return OFType enum type
+     */
+
+    static public OFActionType valueOf(short i) {
+        if (i < 0)
+            i = (short) (16+i);
+        return OFActionType.mapping[i];
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this
+     *         OFActionType
+     */
+    public short getTypeValue() {
+        return this.type;
+    }
+
+    /**
+     * @return return the OFAction subclass corresponding to this OFActionType
+     */
+    public Class<? extends OFAction> toClass() {
+        return clazz;
+    }
+
+    /**
+     * Returns the no-argument Constructor of the implementation class for
+     * this OFActionType
+     * @return the constructor
+     */
+    public Constructor<? extends OFAction> getConstructor() {
+        return constructor;
+    }
+
+    /**
+     * Returns a new instance of the OFAction represented by this OFActionType
+     * @return the new object
+     */
+    public OFAction newInstance() {
+        return instantiable.instantiate();
+    }
+
+    /**
+     * @return the instantiable
+     */
+    public Instantiable<OFAction> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * @param instantiable the instantiable to set
+     */
+    public void setInstantiable(Instantiable<OFAction> instantiable) {
+        this.instantiable = instantiable;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVendor.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVendor.java
new file mode 100644 (file)
index 0000000..5860ef1
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+*    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.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public abstract class OFActionVendor extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected int vendor;
+
+    public OFActionVendor() {
+        super();
+        super.setType(OFActionType.VENDOR);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the vendor
+     */
+    public int getVendor() {
+        return vendor;
+    }
+
+    /**
+     * @param vendor the vendor to set
+     */
+    public void setVendor(int vendor) {
+        this.vendor = vendor;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.vendor = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.vendor);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 379;
+        int result = super.hashCode();
+        result = prime * result + vendor;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVendor)) {
+            return false;
+        }
+        OFActionVendor other = (OFActionVendor) obj;
+        if (vendor != other.vendor) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "; vendor=" + vendor;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java
new file mode 100644 (file)
index 0000000..4f7859f
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+*    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.action;
+
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/** A generic / unparsed vendor action. This action is returned by
+ *  BasicFactory.readFromWire if no more specific OFVendorActionFactory
+ *  is registered.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFActionVendorGeneric extends OFActionVendor {
+    public static int MINIMUM_LENGTH = 8;
+
+    private final static byte[] EMPTY_ARRAY = new byte[0];
+
+    protected byte[] vendorData;
+
+    public OFActionVendorGeneric() {
+        super();
+    }
+
+    public byte[] getVendorData() {
+        return vendorData;
+    }
+
+    public void setVendorData(byte[] vendorData) {
+        this.vendorData = vendorData;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+
+        int vendorDataLength = this.getLength() - MINIMUM_LENGTH;
+        if (vendorDataLength > 0) {
+            vendorData = new byte[vendorDataLength];
+            data.readBytes(vendorData);
+        } else {
+            vendorData = EMPTY_ARRAY;
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.vendor);
+        data.writeBytes(vendorData);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 379;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(vendorData);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVendorGeneric)) {
+            return false;
+        }
+        OFActionVendorGeneric other = (OFActionVendorGeneric) obj;
+        if (!Arrays.equals(vendorData, other.vendorData)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVirtualLanIdentifier.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVirtualLanIdentifier.java
new file mode 100644 (file)
index 0000000..5bd0e0b
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_vlan_vid
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionVirtualLanIdentifier extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short virtualLanIdentifier;
+
+    public OFActionVirtualLanIdentifier() {
+        super.setType(OFActionType.SET_VLAN_ID);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionVirtualLanIdentifier(short vlanId) {
+        this();
+        this.virtualLanIdentifier = vlanId;
+    }
+
+    /**
+     * @return the virtualLanIdentifier
+     */
+    public short getVirtualLanIdentifier() {
+        return virtualLanIdentifier;
+    }
+
+    /**
+     * @param virtualLanIdentifier the virtualLanIdentifier to set
+     */
+    public void setVirtualLanIdentifier(short virtualLanIdentifier) {
+        this.virtualLanIdentifier = virtualLanIdentifier;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.virtualLanIdentifier = data.readShort();
+        data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.virtualLanIdentifier);
+        data.writeShort((short) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 383;
+        int result = super.hashCode();
+        result = prime * result + virtualLanIdentifier;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVirtualLanIdentifier)) {
+            return false;
+        }
+        OFActionVirtualLanIdentifier other = (OFActionVirtualLanIdentifier) obj;
+        if (virtualLanIdentifier != other.virtualLanIdentifier) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVirtualLanPriorityCodePoint.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/action/OFActionVirtualLanPriorityCodePoint.java
new file mode 100644 (file)
index 0000000..9202df3
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_vlan_pcp
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionVirtualLanPriorityCodePoint extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected byte virtualLanPriorityCodePoint;
+
+    public OFActionVirtualLanPriorityCodePoint() {
+        super.setType(OFActionType.SET_VLAN_PCP);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionVirtualLanPriorityCodePoint(byte priority) {
+        this();
+        this.virtualLanPriorityCodePoint = priority;
+    }
+
+    /**
+     * @return the virtualLanPriorityCodePoint
+     */
+    public byte getVirtualLanPriorityCodePoint() {
+        return virtualLanPriorityCodePoint;
+    }
+
+    /**
+     * @param virtualLanPriorityCodePoint the virtualLanPriorityCodePoint to set
+     */
+    public void setVirtualLanPriorityCodePoint(byte virtualLanPriorityCodePoint) {
+        this.virtualLanPriorityCodePoint = virtualLanPriorityCodePoint;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.virtualLanPriorityCodePoint = data.readByte();
+        data.readShort(); // pad
+        data.readByte(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeByte(this.virtualLanPriorityCodePoint);
+        data.writeShort((short) 0);
+        data.writeByte((byte) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 389;
+        int result = super.hashCode();
+        result = prime * result + virtualLanPriorityCodePoint;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVirtualLanPriorityCodePoint)) {
+            return false;
+        }
+        OFActionVirtualLanPriorityCodePoint other = (OFActionVirtualLanPriorityCodePoint) obj;
+        if (virtualLanPriorityCodePoint != other.virtualLanPriorityCodePoint) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/BasicFactory.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/BasicFactory.java
new file mode 100644 (file)
index 0000000..b61aa72
--- /dev/null
@@ -0,0 +1,344 @@
+/**
+*    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();
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/MessageParseException.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/MessageParseException.java
new file mode 100644 (file)
index 0000000..20f381e
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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;
+
+/**
+ * Exception thrown when an openflow message fails to parse properly
+ */
+public class MessageParseException extends Exception {
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -75893812926304726L;
+
+    public MessageParseException() {
+        super();
+    }
+
+    public MessageParseException(String message, Throwable cause) {
+        super(message, cause);
+        this.setStackTrace(cause.getStackTrace());
+    }
+
+    public MessageParseException(String message) {
+        super(message);
+    }
+
+    public MessageParseException(Throwable cause) {
+        super(cause);
+        this.setStackTrace(cause.getStackTrace());
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFActionFactory.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFActionFactory.java
new file mode 100644 (file)
index 0000000..c3cd062
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+*    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.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionType;
+
+
+/**
+ * The interface to factories used for retrieving OFAction instances. All
+ * methods are expected to be thread-safe.
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFActionFactory {
+    /**
+     * Retrieves an OFAction instance corresponding to the specified
+     * OFActionType
+     * @param t the type of the OFAction to be retrieved
+     * @return an OFAction instance
+     */
+    public OFAction getAction(OFActionType t);
+
+    /**
+     * Attempts to parse and return all OFActions contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param data the ChannelBuffer to parse for OpenFlow actions
+     * @param length the number of Bytes to examine for OpenFlow actions
+     * @return a list of OFAction instances
+     */
+    public List<OFAction> parseActions(ChannelBuffer data, int length);
+
+    /**
+     * Attempts to parse and return all OFActions contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param data the ChannelBuffer to parse for OpenFlow actions
+     * @param length the number of Bytes to examine for OpenFlow actions
+     * @param limit the maximum number of messages to return, 0 means no limit
+     * @return a list of OFAction instances
+     */
+    public List<OFAction> parseActions(ChannelBuffer data, int length, int limit);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFActionFactoryAware.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFActionFactoryAware.java
new file mode 100644 (file)
index 0000000..a97a95c
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+*    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;
+
+/**
+ * Objects implementing this interface are expected to be instantiated with an
+ * instance of an OFActionFactory
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFActionFactoryAware {
+    /**
+     * Sets the OFActionFactory
+     * @param actionFactory
+     */
+    public void setActionFactory(OFActionFactory actionFactory);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFMessageFactory.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFMessageFactory.java
new file mode 100644 (file)
index 0000000..8bb7045
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+*    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.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+
+
+/**
+ * The interface to factories used for retrieving OFMessage instances. All
+ * methods are expected to be thread-safe.
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFMessageFactory {
+    /**
+     * Retrieves an OFMessage instance corresponding to the specified OFType
+     * @param t the type of the OFMessage to be retrieved
+     * @return an OFMessage instance
+     */
+    public OFMessage getMessage(OFType t);
+
+    /**
+     * Attempts to parse and return a OFMessages contained in the given
+     * ChannelBuffer, beginning at the ChannelBuffer's position, and ending at the
+     * after the first parsed message
+     * @param data the ChannelBuffer to parse for an OpenFlow message
+     * @return a list of OFMessage instances
+     * @throws MessageParseException 
+     */
+    public List<OFMessage> parseMessage(ChannelBuffer data) throws MessageParseException;
+
+    /**
+     * Retrieves an OFActionFactory
+     * @return an OFActionFactory
+     */
+    public OFActionFactory getActionFactory();
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFMessageFactoryAware.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFMessageFactoryAware.java
new file mode 100644 (file)
index 0000000..adb1421
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+*    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;
+
+/**
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ *
+ */
+public interface OFMessageFactoryAware {
+
+       /**
+        * Sets the message factory for this object
+        * 
+        * @param factory
+        */
+       void setMessageFactory(OFMessageFactory factory);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFStatisticsFactory.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFStatisticsFactory.java
new file mode 100644 (file)
index 0000000..32eb3cb
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+*    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.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+
+
+/**
+ * The interface to factories used for retrieving OFStatistics instances. All
+ * methods are expected to be thread-safe.
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFStatisticsFactory {
+    /**
+     * Retrieves an OFStatistics instance corresponding to the specified
+     * OFStatisticsType
+     * @param t the type of the containing OFMessage, only accepts statistics
+     *           request or reply
+     * @param st the type of the OFStatistics to be retrieved
+     * @return an OFStatistics instance
+     */
+    public OFStatistics getStatistics(OFType t, OFStatisticsType st);
+
+    /**
+     * Attempts to parse and return all OFStatistics contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param t the type of the containing OFMessage, only accepts statistics
+     *           request or reply
+     * @param st the type of the OFStatistics to be retrieved
+     * @param data the ChannelBuffer to parse for OpenFlow Statistics
+     * @param length the number of Bytes to examine for OpenFlow Statistics
+     * @return a list of OFStatistics instances
+     */
+    public List<OFStatistics> parseStatistics(OFType t,
+            OFStatisticsType st, ChannelBuffer data, int length);
+
+    /**
+     * Attempts to parse and return all OFStatistics contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param t the type of the containing OFMessage, only accepts statistics
+     *           request or reply
+     * @param st the type of the OFStatistics to be retrieved
+     * @param data the ChannelBuffer to parse for OpenFlow Statistics
+     * @param length the number of Bytes to examine for OpenFlow Statistics
+     * @param limit the maximum number of messages to return, 0 means no limit
+     * @return a list of OFStatistics instances
+     */
+    public List<OFStatistics> parseStatistics(OFType t,
+            OFStatisticsType st, ChannelBuffer data, int length, int limit);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFStatisticsFactoryAware.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFStatisticsFactoryAware.java
new file mode 100644 (file)
index 0000000..52ab09a
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+*    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;
+
+/**
+ * Objects implementing this interface are expected to be instantiated with an
+ * instance of an OFStatisticsFactory
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFStatisticsFactoryAware {
+    /**
+     * Sets the OFStatisticsFactory
+     * @param statisticsFactory
+     */
+    public void setStatisticsFactory(OFStatisticsFactory statisticsFactory);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java
new file mode 100644 (file)
index 0000000..eb89810
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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 org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFActionVendor;
+
+/** Interface contract for an actionfactory that creates vendor-specific actions.
+ *  VendorActionFactories are registered with the BasicFactory for a specific
+ *  vendor id.
+ *  <p>
+ *  <b>Note:</b> Implementations are expected to be thread-safe.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public interface OFVendorActionFactory {
+
+    /** parse the data from the wire, create and return a vendor-specific action.
+     *
+     * @param data contains a serialized vendor action at the current readerPosition.
+     *    The full message is guaranteed to be available in the buffer.
+     *
+     * @return upon success returns a newly allocated vendor-specific
+     *   action instance, and advances the readerPosition in data for the
+     *   entire length. Upon failure, returns null and leaves the readerPosition
+     *   in data unmodified.
+     */
+    OFActionVendor readFrom(ChannelBuffer data);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java
new file mode 100644 (file)
index 0000000..1f55681
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** Singleton registry object that holds a mapping from vendor ids to vendor-specific
+ *  mapping factories. Threadsafe.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFVendorActionRegistry {
+    private static class InstanceHolder {
+        private final static OFVendorActionRegistry instance = new OFVendorActionRegistry();
+    }
+
+    public static OFVendorActionRegistry getInstance() {
+        return InstanceHolder.instance;
+    }
+    private final Map <Integer, OFVendorActionFactory> vendorActionFactories;
+
+    public OFVendorActionRegistry() {
+        vendorActionFactories = new ConcurrentHashMap<Integer, OFVendorActionFactory>();
+    }
+
+    public OFVendorActionFactory register(int vendorId, OFVendorActionFactory factory) {
+        return vendorActionFactories.put(vendorId, factory);
+    }
+
+    public OFVendorActionFactory get(int vendorId) {
+        return vendorActionFactories.get(vendorId);
+    }
+
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java
new file mode 100644 (file)
index 0000000..d754a4a
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.factory;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.vendor.OFVendorData;
+import org.openflow.protocol.vendor.OFVendorDataType;
+import org.openflow.protocol.vendor.OFVendorId;
+
+/**
+ * The interface to factories used for parsing/creating OFVendorData instances.
+ * All methods are expected to be thread-safe.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public interface OFVendorDataFactory {
+    /**
+     * Retrieves an OFVendorData instance corresponding to the specified
+     * OFVendorId and OFVendorDataType. There are 3 possible cases for
+     * how this will be called:
+     * 
+     * 1) If the vendor id in the OFVendor message is an unknown value, 
+     *    then this method is called with both vendorId and vendorDataType
+     *    set to null. In this case typically the factory method should
+     *    return an instance of OFGenericVendorData that just contains
+     *    the raw byte array of the vendor data.
+     *    
+     * 2) If the vendor id is known but no vendor data type has been
+     *    registered for the data in the message, then vendorId is set to
+     *    the appropriate OFVendorId instance and OFVendorDataType is set
+     *    to null. This would typically be handled the same way as #1
+     *    
+     * 3) If both the vendor id and and vendor data type are known, then
+     *    typically you'd just call the method in OFVendorDataType to
+     *    instantiate the appropriate subclass of OFVendorData.
+     *    
+     * @param vendorId the vendorId of the containing OFVendor message
+     * @param vendorDataType the type of the OFVendorData to be retrieved
+     * @return an OFVendorData instance
+     */
+    public OFVendorData getVendorData(OFVendorId vendorId,
+            OFVendorDataType vendorDataType);
+    
+    /**
+     * Attempts to parse and return the OFVendorData contained in the given
+     * ChannelBuffer, beginning right after the vendor id.
+     * @param vendorId 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
+     */
+    public OFVendorData parseVendorData(int vendorId, ChannelBuffer data,
+            int length);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java
new file mode 100644 (file)
index 0000000..23614b0
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.factory;
+
+/**
+ * Classes implementing this interface are expected to be instantiated with an
+ * instance of an OFVendorDataFactory
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public interface OFVendorDataFactoryAware {
+    public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsReply.java
new file mode 100644 (file)
index 0000000..b5a486c
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_aggregate_stats_reply structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFAggregateStatisticsReply implements OFStatistics {
+    protected long packetCount;
+    protected long byteCount;
+    protected int flowCount;
+
+    /**
+     * @return the packetCount
+     */
+    public long getPacketCount() {
+        return packetCount;
+    }
+
+    /**
+     * @param packetCount the packetCount to set
+     */
+    public void setPacketCount(long packetCount) {
+        this.packetCount = packetCount;
+    }
+
+    /**
+     * @return the byteCount
+     */
+    public long getByteCount() {
+        return byteCount;
+    }
+
+    /**
+     * @param byteCount the byteCount to set
+     */
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    /**
+     * @return the flowCount
+     */
+    public int getFlowCount() {
+        return flowCount;
+    }
+
+    /**
+     * @param flowCount the flowCount to set
+     */
+    public void setFlowCount(int flowCount) {
+        this.flowCount = flowCount;
+    }
+
+    @Override
+    public int getLength() {
+        return 24;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.packetCount = data.readLong();
+        this.byteCount = data.readLong();
+        this.flowCount = data.readInt();
+        data.readInt(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeLong(this.packetCount);
+        data.writeLong(this.byteCount);
+        data.writeInt(this.flowCount);
+        data.writeInt(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 397;
+        int result = 1;
+        result = prime * result + (int) (byteCount ^ (byteCount >>> 32));
+        result = prime * result + flowCount;
+        result = prime * result + (int) (packetCount ^ (packetCount >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFAggregateStatisticsReply)) {
+            return false;
+        }
+        OFAggregateStatisticsReply other = (OFAggregateStatisticsReply) obj;
+        if (byteCount != other.byteCount) {
+            return false;
+        }
+        if (flowCount != other.flowCount) {
+            return false;
+        }
+        if (packetCount != other.packetCount) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsRequest.java
new file mode 100644 (file)
index 0000000..f41a4f1
--- /dev/null
@@ -0,0 +1,135 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMatch;
+
+/**
+ * Represents an ofp_aggregate_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFAggregateStatisticsRequest implements OFStatistics {
+    protected OFMatch match;
+    protected byte tableId;
+    protected short outPort;
+
+    /**
+     * @return the match
+     */
+    public OFMatch getMatch() {
+        return match;
+    }
+
+    /**
+     * @param match the match to set
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the outPort
+     */
+    public short getOutPort() {
+        return outPort;
+    }
+
+    /**
+     * @param outPort the outPort to set
+     */
+    public void setOutPort(short outPort) {
+        this.outPort = outPort;
+    }
+
+    @Override
+    public int getLength() {
+        return 44;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        this.outPort = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        this.match.writeTo(data);
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0);
+        data.writeShort(this.outPort);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 401;
+        int result = 1;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + outPort;
+        result = prime * result + tableId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFAggregateStatisticsRequest)) {
+            return false;
+        }
+        OFAggregateStatisticsRequest other = (OFAggregateStatisticsRequest) obj;
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (outPort != other.outPort) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java
new file mode 100644 (file)
index 0000000..86ad782
--- /dev/null
@@ -0,0 +1,225 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.StringByteSerializer;
+
+/**
+ * Represents an ofp_desc_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFDescriptionStatistics implements OFStatistics {
+    public static int DESCRIPTION_STRING_LENGTH = 256;
+    public static int SERIAL_NUMBER_LENGTH = 32;
+
+    protected String manufacturerDescription;
+    protected String hardwareDescription;
+    protected String softwareDescription;
+    protected String serialNumber;
+    protected String datapathDescription;
+
+    /**
+     * @return the manufacturerDescription
+     */
+    public String getManufacturerDescription() {
+        return manufacturerDescription;
+    }
+
+    /**
+     * @param manufacturerDescription the manufacturerDescription to set
+     */
+    public void setManufacturerDescription(String manufacturerDescription) {
+        this.manufacturerDescription = manufacturerDescription;
+    }
+
+    /**
+     * @return the hardwareDescription
+     */
+    public String getHardwareDescription() {
+        return hardwareDescription;
+    }
+
+    /**
+     * @param hardwareDescription the hardwareDescription to set
+     */
+    public void setHardwareDescription(String hardwareDescription) {
+        this.hardwareDescription = hardwareDescription;
+    }
+
+    /**
+     * @return the softwareDescription
+     */
+    public String getSoftwareDescription() {
+        return softwareDescription;
+    }
+
+    /**
+     * @param softwareDescription the softwareDescription to set
+     */
+    public void setSoftwareDescription(String softwareDescription) {
+        this.softwareDescription = softwareDescription;
+    }
+
+    /**
+     * @return the serialNumber
+     */
+    public String getSerialNumber() {
+        return serialNumber;
+    }
+
+    /**
+     * @param serialNumber the serialNumber to set
+     */
+    public void setSerialNumber(String serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    /**
+     * @return the datapathDescription
+     */
+    public String getDatapathDescription() {
+        return datapathDescription;
+    }
+
+    /**
+     * @param datapathDescription the datapathDescription to set
+     */
+    public void setDatapathDescription(String datapathDescription) {
+        this.datapathDescription = datapathDescription;
+    }
+
+    @Override
+    public int getLength() {
+        return 1056;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.manufacturerDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+        this.hardwareDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+        this.softwareDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+        this.serialNumber = StringByteSerializer.readFrom(data,
+                SERIAL_NUMBER_LENGTH);
+        this.datapathDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.manufacturerDescription);
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.hardwareDescription);
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.softwareDescription);
+        StringByteSerializer.writeTo(data, SERIAL_NUMBER_LENGTH,
+                this.serialNumber);
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.datapathDescription);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 409;
+        int result = 1;
+        result = prime
+                * result
+                + ((datapathDescription == null) ? 0 : datapathDescription
+                        .hashCode());
+        result = prime
+                * result
+                + ((hardwareDescription == null) ? 0 : hardwareDescription
+                        .hashCode());
+        result = prime
+                * result
+                + ((manufacturerDescription == null) ? 0
+                        : manufacturerDescription.hashCode());
+        result = prime * result
+                + ((serialNumber == null) ? 0 : serialNumber.hashCode());
+        result = prime
+                * result
+                + ((softwareDescription == null) ? 0 : softwareDescription
+                        .hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFDescriptionStatistics)) {
+            return false;
+        }
+        OFDescriptionStatistics other = (OFDescriptionStatistics) obj;
+        if (datapathDescription == null) {
+            if (other.datapathDescription != null) {
+                return false;
+            }
+        } else if (!datapathDescription.equals(other.datapathDescription)) {
+            return false;
+        }
+        if (hardwareDescription == null) {
+            if (other.hardwareDescription != null) {
+                return false;
+            }
+        } else if (!hardwareDescription.equals(other.hardwareDescription)) {
+            return false;
+        }
+        if (manufacturerDescription == null) {
+            if (other.manufacturerDescription != null) {
+                return false;
+            }
+        } else if (!manufacturerDescription
+                .equals(other.manufacturerDescription)) {
+            return false;
+        }
+        if (serialNumber == null) {
+            if (other.serialNumber != null) {
+                return false;
+            }
+        } else if (!serialNumber.equals(other.serialNumber)) {
+            return false;
+        }
+        if (softwareDescription == null) {
+            if (other.softwareDescription != null) {
+                return false;
+            }
+        } else if (!softwareDescription.equals(other.softwareDescription)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "Switch Desc - Vendor: " +  manufacturerDescription +
+                "  Model: " + hardwareDescription +
+                "  Make: " + datapathDescription +
+                "  Version: " + softwareDescription +
+                "  S/N: " + serialNumber;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java
new file mode 100644 (file)
index 0000000..0570779
--- /dev/null
@@ -0,0 +1,357 @@
+/**
+*    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.statistics;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.OFActionFactory;
+import org.openflow.protocol.factory.OFActionFactoryAware;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_flow_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFFlowStatisticsReply implements OFStatistics, OFActionFactoryAware {
+    public static int MINIMUM_LENGTH = 88;
+
+    protected OFActionFactory actionFactory;
+    protected short length = (short) MINIMUM_LENGTH;
+    protected byte tableId;
+    protected OFMatch match;
+    protected int durationSeconds;
+    protected int durationNanoseconds;
+    protected short priority;
+    protected short idleTimeout;
+    protected short hardTimeout;
+    protected long cookie;
+    protected long packetCount;
+    protected long byteCount;
+    protected List<OFAction> actions;
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the match
+     */
+    public OFMatch getMatch() {
+        return match;
+    }
+
+    /**
+     * @param match the match to set
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * @return the durationSeconds
+     */
+    public int getDurationSeconds() {
+        return durationSeconds;
+    }
+
+    /**
+     * @param durationSeconds the durationSeconds to set
+     */
+    public void setDurationSeconds(int durationSeconds) {
+        this.durationSeconds = durationSeconds;
+    }
+
+    /**
+     * @return the durationNanoseconds
+     */
+    public int getDurationNanoseconds() {
+        return durationNanoseconds;
+    }
+
+    /**
+     * @param durationNanoseconds the durationNanoseconds to set
+     */
+    public void setDurationNanoseconds(int durationNanoseconds) {
+        this.durationNanoseconds = durationNanoseconds;
+    }
+
+    /**
+     * @return the priority
+     */
+    public short getPriority() {
+        return priority;
+    }
+
+    /**
+     * @param priority the priority to set
+     */
+    public void setPriority(short priority) {
+        this.priority = priority;
+    }
+
+    /**
+     * @return the idleTimeout
+     */
+    public short getIdleTimeout() {
+        return idleTimeout;
+    }
+
+    /**
+     * @param idleTimeout the idleTimeout to set
+     */
+    public void setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    /**
+     * @return the hardTimeout
+     */
+    public short getHardTimeout() {
+        return hardTimeout;
+    }
+
+    /**
+     * @param hardTimeout the hardTimeout to set
+     */
+    public void setHardTimeout(short hardTimeout) {
+        this.hardTimeout = hardTimeout;
+    }
+
+    /**
+     * @return the cookie
+     */
+    public long getCookie() {
+        return cookie;
+    }
+
+    /**
+     * @param cookie the cookie to set
+     */
+    public void setCookie(long cookie) {
+        this.cookie = cookie;
+    }
+
+    /**
+     * @return the packetCount
+     */
+    public long getPacketCount() {
+        return packetCount;
+    }
+
+    /**
+     * @param packetCount the packetCount to set
+     */
+    public void setPacketCount(long packetCount) {
+        this.packetCount = packetCount;
+    }
+
+    /**
+     * @return the byteCount
+     */
+    public long getByteCount() {
+        return byteCount;
+    }
+
+    /**
+     * @param byteCount the byteCount to set
+     */
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    /**
+     * @param length the length to set
+     */
+    public void setLength(short length) {
+        this.length = length;
+    }
+
+    @Override
+    public int getLength() {
+        return U16.f(length);
+    }
+
+    /**
+     * @param actionFactory the actionFactory to set
+     */
+    @Override
+    public void setActionFactory(OFActionFactory actionFactory) {
+        this.actionFactory = actionFactory;
+    }
+
+    /**
+     * @return the actions
+     */
+    public List<OFAction> getActions() {
+        return actions;
+    }
+
+    /**
+     * @param actions the actions to set
+     */
+    public void setActions(List<OFAction> actions) {
+        this.actions = actions;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.length = data.readShort();
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.durationSeconds = data.readInt();
+        this.durationNanoseconds = data.readInt();
+        this.priority = data.readShort();
+        this.idleTimeout = data.readShort();
+        this.hardTimeout = data.readShort();
+        data.readInt(); // pad
+        data.readShort(); // pad
+        this.cookie = data.readLong();
+        this.packetCount = data.readLong();
+        this.byteCount = data.readLong();
+        if (this.actionFactory == null)
+            throw new RuntimeException("OFActionFactory not set");
+        this.actions = this.actionFactory.parseActions(data, getLength() -
+                MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.length);
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0);
+        this.match.writeTo(data);
+        data.writeInt(this.durationSeconds);
+        data.writeInt(this.durationNanoseconds);
+        data.writeShort(this.priority);
+        data.writeShort(this.idleTimeout);
+        data.writeShort(this.hardTimeout);
+        data.writeInt(0); // pad
+        data.writeShort((short)0); // pad
+        data.writeLong(this.cookie);
+        data.writeLong(this.packetCount);
+        data.writeLong(this.byteCount);
+        if (actions != null) {
+            for (OFAction action : actions) {
+                action.writeTo(data);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+       String str = "match=" + this.match;
+       str += " tableId=" + this.tableId;
+       str += " durationSeconds=" + this.durationSeconds;
+       str += " durationNanoseconds=" + this.durationNanoseconds;
+       str += " priority=" + this.priority;
+       str += " idleTimeout=" + this.idleTimeout;
+       str += " hardTimeout=" + this.hardTimeout;
+       str += " cookie=" + this.cookie;
+       str += " packetCount=" + this.packetCount;
+       str += " byteCount=" + this.byteCount;
+       str += " action=" + this.actions;
+       
+       return str;
+    }
+    
+    @Override
+    public int hashCode() {
+        final int prime = 419;
+        int result = 1;
+        result = prime * result + (int) (byteCount ^ (byteCount >>> 32));
+        result = prime * result + (int) (cookie ^ (cookie >>> 32));
+        result = prime * result + durationNanoseconds;
+        result = prime * result + durationSeconds;
+        result = prime * result + hardTimeout;
+        result = prime * result + idleTimeout;
+        result = prime * result + length;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + (int) (packetCount ^ (packetCount >>> 32));
+        result = prime * result + priority;
+        result = prime * result + tableId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowStatisticsReply)) {
+            return false;
+        }
+        OFFlowStatisticsReply other = (OFFlowStatisticsReply) obj;
+        if (byteCount != other.byteCount) {
+            return false;
+        }
+        if (cookie != other.cookie) {
+            return false;
+        }
+        if (durationNanoseconds != other.durationNanoseconds) {
+            return false;
+        }
+        if (durationSeconds != other.durationSeconds) {
+            return false;
+        }
+        if (hardTimeout != other.hardTimeout) {
+            return false;
+        }
+        if (idleTimeout != other.idleTimeout) {
+            return false;
+        }
+        if (length != other.length) {
+            return false;
+        }
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (packetCount != other.packetCount) {
+            return false;
+        }
+        if (priority != other.priority) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsRequest.java
new file mode 100644 (file)
index 0000000..b21de0c
--- /dev/null
@@ -0,0 +1,135 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMatch;
+
+/**
+ * Represents an ofp_flow_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFFlowStatisticsRequest implements OFStatistics {
+    protected OFMatch match;
+    protected byte tableId;
+    protected short outPort;
+
+    /**
+     * @return the match
+     */
+    public OFMatch getMatch() {
+        return match;
+    }
+
+    /**
+     * @param match the match to set
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the outPort
+     */
+    public short getOutPort() {
+        return outPort;
+    }
+
+    /**
+     * @param outPort the outPort to set
+     */
+    public void setOutPort(short outPort) {
+        this.outPort = outPort;
+    }
+
+    @Override
+    public int getLength() {
+        return 44;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        this.outPort = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        this.match.writeTo(data);
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0);
+        data.writeShort(this.outPort);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 421;
+        int result = 1;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + outPort;
+        result = prime * result + tableId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowStatisticsRequest)) {
+            return false;
+        }
+        OFFlowStatisticsRequest other = (OFFlowStatisticsRequest) obj;
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (outPort != other.outPort) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsReply.java
new file mode 100644 (file)
index 0000000..02b97b3
--- /dev/null
@@ -0,0 +1,351 @@
+/**
+*    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.statistics;
+
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_port_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortStatisticsReply implements OFStatistics {
+    protected short portNumber;
+    protected long receivePackets;
+    protected long transmitPackets;
+    protected long receiveBytes;
+    protected long transmitBytes;
+    protected long receiveDropped;
+    protected long transmitDropped;
+    protected long receiveErrors;
+    protected long transmitErrors;
+    protected long receiveFrameErrors;
+    protected long receiveOverrunErrors;
+    protected long receiveCRCErrors;
+    protected long collisions;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the receivePackets
+     */
+    public long getreceivePackets() {
+        return receivePackets;
+    }
+
+    /**
+     * @param receivePackets the receivePackets to set
+     */
+    public void setreceivePackets(long receivePackets) {
+        this.receivePackets = receivePackets;
+    }
+
+    /**
+     * @return the transmitPackets
+     */
+    public long getTransmitPackets() {
+        return transmitPackets;
+    }
+
+    /**
+     * @param transmitPackets the transmitPackets to set
+     */
+    public void setTransmitPackets(long transmitPackets) {
+        this.transmitPackets = transmitPackets;
+    }
+
+    /**
+     * @return the receiveBytes
+     */
+    public long getReceiveBytes() {
+        return receiveBytes;
+    }
+
+    /**
+     * @param receiveBytes the receiveBytes to set
+     */
+    public void setReceiveBytes(long receiveBytes) {
+        this.receiveBytes = receiveBytes;
+    }
+
+    /**
+     * @return the transmitBytes
+     */
+    public long getTransmitBytes() {
+        return transmitBytes;
+    }
+
+    /**
+     * @param transmitBytes the transmitBytes to set
+     */
+    public void setTransmitBytes(long transmitBytes) {
+        this.transmitBytes = transmitBytes;
+    }
+
+    /**
+     * @return the receiveDropped
+     */
+    public long getReceiveDropped() {
+        return receiveDropped;
+    }
+
+    /**
+     * @param receiveDropped the receiveDropped to set
+     */
+    public void setReceiveDropped(long receiveDropped) {
+        this.receiveDropped = receiveDropped;
+    }
+
+    /**
+     * @return the transmitDropped
+     */
+    public long getTransmitDropped() {
+        return transmitDropped;
+    }
+
+    /**
+     * @param transmitDropped the transmitDropped to set
+     */
+    public void setTransmitDropped(long transmitDropped) {
+        this.transmitDropped = transmitDropped;
+    }
+
+    /**
+     * @return the receiveErrors
+     */
+    public long getreceiveErrors() {
+        return receiveErrors;
+    }
+
+    /**
+     * @param receiveErrors the receiveErrors to set
+     */
+    public void setreceiveErrors(long receiveErrors) {
+        this.receiveErrors = receiveErrors;
+    }
+
+    /**
+     * @return the transmitErrors
+     */
+    public long getTransmitErrors() {
+        return transmitErrors;
+    }
+
+    /**
+     * @param transmitErrors the transmitErrors to set
+     */
+    public void setTransmitErrors(long transmitErrors) {
+        this.transmitErrors = transmitErrors;
+    }
+
+    /**
+     * @return the receiveFrameErrors
+     */
+    public long getReceiveFrameErrors() {
+        return receiveFrameErrors;
+    }
+
+    /**
+     * @param receiveFrameErrors the receiveFrameErrors to set
+     */
+    public void setReceiveFrameErrors(long receiveFrameErrors) {
+        this.receiveFrameErrors = receiveFrameErrors;
+    }
+
+    /**
+     * @return the receiveOverrunErrors
+     */
+    public long getReceiveOverrunErrors() {
+        return receiveOverrunErrors;
+    }
+
+    /**
+     * @param receiveOverrunErrors the receiveOverrunErrors to set
+     */
+    public void setReceiveOverrunErrors(long receiveOverrunErrors) {
+        this.receiveOverrunErrors = receiveOverrunErrors;
+    }
+
+    /**
+     * @return the receiveCRCErrors
+     */
+    public long getReceiveCRCErrors() {
+        return receiveCRCErrors;
+    }
+
+    /**
+     * @param receiveCRCErrors the receiveCRCErrors to set
+     */
+    public void setReceiveCRCErrors(long receiveCRCErrors) {
+        this.receiveCRCErrors = receiveCRCErrors;
+    }
+
+    /**
+     * @return the collisions
+     */
+    public long getCollisions() {
+        return collisions;
+    }
+
+    /**
+     * @param collisions the collisions to set
+     */
+    public void setCollisions(long collisions) {
+        this.collisions = collisions;
+    }
+
+    @Override
+    public int getLength() {
+        return 104;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        data.readInt(); // pad
+        this.receivePackets = data.readLong();
+        this.transmitPackets = data.readLong();
+        this.receiveBytes = data.readLong();
+        this.transmitBytes = data.readLong();
+        this.receiveDropped = data.readLong();
+        this.transmitDropped = data.readLong();
+        this.receiveErrors = data.readLong();
+        this.transmitErrors = data.readLong();
+        this.receiveFrameErrors = data.readLong();
+        this.receiveOverrunErrors = data.readLong();
+        this.receiveCRCErrors = data.readLong();
+        this.collisions = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(0); // pad
+        data.writeLong(this.receivePackets);
+        data.writeLong(this.transmitPackets);
+        data.writeLong(this.receiveBytes);
+        data.writeLong(this.transmitBytes);
+        data.writeLong(this.receiveDropped);
+        data.writeLong(this.transmitDropped);
+        data.writeLong(this.receiveErrors);
+        data.writeLong(this.transmitErrors);
+        data.writeLong(this.receiveFrameErrors);
+        data.writeLong(this.receiveOverrunErrors);
+        data.writeLong(this.receiveCRCErrors);
+        data.writeLong(this.collisions);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 431;
+        int result = 1;
+        result = prime * result + (int) (collisions ^ (collisions >>> 32));
+        result = prime * result + portNumber;
+        result = prime * result
+                + (int) (receivePackets ^ (receivePackets >>> 32));
+        result = prime * result + (int) (receiveBytes ^ (receiveBytes >>> 32));
+        result = prime * result
+                + (int) (receiveCRCErrors ^ (receiveCRCErrors >>> 32));
+        result = prime * result
+                + (int) (receiveDropped ^ (receiveDropped >>> 32));
+        result = prime * result
+                + (int) (receiveFrameErrors ^ (receiveFrameErrors >>> 32));
+        result = prime * result
+                + (int) (receiveOverrunErrors ^ (receiveOverrunErrors >>> 32));
+        result = prime * result
+                + (int) (receiveErrors ^ (receiveErrors >>> 32));
+        result = prime * result
+                + (int) (transmitBytes ^ (transmitBytes >>> 32));
+        result = prime * result
+                + (int) (transmitDropped ^ (transmitDropped >>> 32));
+        result = prime * result
+                + (int) (transmitErrors ^ (transmitErrors >>> 32));
+        result = prime * result
+                + (int) (transmitPackets ^ (transmitPackets >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFPortStatisticsReply)) {
+            return false;
+        }
+        OFPortStatisticsReply other = (OFPortStatisticsReply) obj;
+        if (collisions != other.collisions) {
+            return false;
+        }
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (receivePackets != other.receivePackets) {
+            return false;
+        }
+        if (receiveBytes != other.receiveBytes) {
+            return false;
+        }
+        if (receiveCRCErrors != other.receiveCRCErrors) {
+            return false;
+        }
+        if (receiveDropped != other.receiveDropped) {
+            return false;
+        }
+        if (receiveFrameErrors != other.receiveFrameErrors) {
+            return false;
+        }
+        if (receiveOverrunErrors != other.receiveOverrunErrors) {
+            return false;
+        }
+        if (receiveErrors != other.receiveErrors) {
+            return false;
+        }
+        if (transmitBytes != other.transmitBytes) {
+            return false;
+        }
+        if (transmitDropped != other.transmitDropped) {
+            return false;
+        }
+        if (transmitErrors != other.transmitErrors) {
+            return false;
+        }
+        if (transmitPackets != other.transmitPackets) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsRequest.java
new file mode 100644 (file)
index 0000000..c07a895
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_port_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortStatisticsRequest implements OFStatistics {
+    protected short portNumber;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    @Override
+    public int getLength() {
+        return 8;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        data.readInt(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 433;
+        int result = 1;
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFPortStatisticsRequest)) {
+            return false;
+        }
+        OFPortStatisticsRequest other = (OFPortStatisticsRequest) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsReply.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsReply.java
new file mode 100644 (file)
index 0000000..7d0238a
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_queue_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFQueueStatisticsReply implements OFStatistics {
+    protected short portNumber;
+    protected int queueId;
+    protected long transmitBytes;
+    protected long transmitPackets;
+    protected long transmitErrors;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the queueId
+     */
+    public int getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    /**
+     * @return the transmitBytes
+     */
+    public long getTransmitBytes() {
+        return transmitBytes;
+    }
+
+    /**
+     * @param transmitBytes the transmitBytes to set
+     */
+    public void setTransmitBytes(long transmitBytes) {
+        this.transmitBytes = transmitBytes;
+    }
+
+    /**
+     * @return the transmitPackets
+     */
+    public long getTransmitPackets() {
+        return transmitPackets;
+    }
+
+    /**
+     * @param transmitPackets the transmitPackets to set
+     */
+    public void setTransmitPackets(long transmitPackets) {
+        this.transmitPackets = transmitPackets;
+    }
+
+    /**
+     * @return the transmitErrors
+     */
+    public long getTransmitErrors() {
+        return transmitErrors;
+    }
+
+    /**
+     * @param transmitErrors the transmitErrors to set
+     */
+    public void setTransmitErrors(long transmitErrors) {
+        this.transmitErrors = transmitErrors;
+    }
+
+    @Override
+    public int getLength() {
+        return 32;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        this.queueId = data.readInt();
+        this.transmitBytes = data.readLong();
+        this.transmitPackets = data.readLong();
+        this.transmitErrors = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(this.queueId);
+        data.writeLong(this.transmitBytes);
+        data.writeLong(this.transmitPackets);
+        data.writeLong(this.transmitErrors);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 439;
+        int result = 1;
+        result = prime * result + portNumber;
+        result = prime * result + queueId;
+        result = prime * result
+                + (int) (transmitBytes ^ (transmitBytes >>> 32));
+        result = prime * result
+                + (int) (transmitErrors ^ (transmitErrors >>> 32));
+        result = prime * result
+                + (int) (transmitPackets ^ (transmitPackets >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueStatisticsReply)) {
+            return false;
+        }
+        OFQueueStatisticsReply other = (OFQueueStatisticsReply) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (queueId != other.queueId) {
+            return false;
+        }
+        if (transmitBytes != other.transmitBytes) {
+            return false;
+        }
+        if (transmitErrors != other.transmitErrors) {
+            return false;
+        }
+        if (transmitPackets != other.transmitPackets) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsRequest.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsRequest.java
new file mode 100644 (file)
index 0000000..3331453
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_queue_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFQueueStatisticsRequest implements OFStatistics {
+    protected short portNumber;
+    protected int queueId;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the queueId
+     */
+    public int getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    @Override
+    public int getLength() {
+        return 8;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        this.queueId = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(this.queueId);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 443;
+        int result = 1;
+        result = prime * result + portNumber;
+        result = prime * result + queueId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueStatisticsRequest)) {
+            return false;
+        }
+        OFQueueStatisticsRequest other = (OFQueueStatisticsRequest) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (queueId != other.queueId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFStatistics.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFStatistics.java
new file mode 100644 (file)
index 0000000..5e8f4dd
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+*    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.statistics;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * The base class for all OpenFlow statistics.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public interface OFStatistics {
+    /**
+     * Returns the wire length of this message in bytes
+     * @return the length
+     */
+    public int getLength();
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data);
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFStatisticsType.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFStatisticsType.java
new file mode 100644 (file)
index 0000000..f2b9e30
--- /dev/null
@@ -0,0 +1,317 @@
+/**
+*    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.statistics;
+
+import java.lang.reflect.Constructor;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.OFType;
+
+public enum OFStatisticsType {
+    DESC        (0, OFDescriptionStatistics.class, OFDescriptionStatistics.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFDescriptionStatistics();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFDescriptionStatistics();
+                        }
+                    }),
+    FLOW       (1, OFFlowStatisticsRequest.class, OFFlowStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFFlowStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFFlowStatisticsReply();
+                        }
+                    }),
+    AGGREGATE  (2, OFAggregateStatisticsRequest.class, OFAggregateStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFAggregateStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFAggregateStatisticsReply();
+                        }
+                    }),
+    TABLE      (3, OFTableStatistics.class, OFTableStatistics.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFTableStatistics();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFTableStatistics();
+                        }
+                    }),
+    PORT       (4, OFPortStatisticsRequest.class, OFPortStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFPortStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFPortStatisticsReply();
+                        }
+                    }),
+    QUEUE      (5, OFQueueStatisticsRequest.class, OFQueueStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFQueueStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFQueueStatisticsReply();
+                        }
+                    }),
+    VENDOR     (0xffff, OFVendorStatistics.class, OFVendorStatistics.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFVendorStatistics();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFVendorStatistics();
+                        }
+                    });
+
+    static OFStatisticsType[] requestMapping;
+    static OFStatisticsType[] replyMapping;
+
+    protected Class<? extends OFStatistics> requestClass;
+    protected Constructor<? extends OFStatistics> requestConstructor;
+    protected Instantiable<OFStatistics> requestInstantiable;
+    protected Class<? extends OFStatistics> replyClass;
+    protected Constructor<? extends OFStatistics> replyConstructor;
+    protected Instantiable<OFStatistics> replyInstantiable;
+    protected short type;
+
+    /**
+     * Store some information about the OpenFlow Statistic type, including wire
+     * protocol type number, and derived class
+     *
+     * @param type Wire protocol number associated with this OFStatisticsType
+     * @param requestClass The Statistics Java class to return when the
+     *                     containing OFType is STATS_REQUEST
+     * @param replyClass   The Statistics Java class to return when the
+     *                     containing OFType is STATS_REPLY
+     */
+    OFStatisticsType(int type, Class<? extends OFStatistics> requestClass,
+            Class<? extends OFStatistics> replyClass,
+            Instantiable<OFStatistics> requestInstantiable,
+            Instantiable<OFStatistics> replyInstantiable) {
+        this.type = (short) type;
+        this.requestClass = requestClass;
+        try {
+            this.requestConstructor = requestClass.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + requestClass, e);
+        }
+
+        this.replyClass = replyClass;
+        try {
+            this.replyConstructor = replyClass.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + replyClass, e);
+        }
+        this.requestInstantiable = requestInstantiable;
+        this.replyInstantiable = replyInstantiable;
+        OFStatisticsType.addMapping(this.type, OFType.STATS_REQUEST, this);
+        OFStatisticsType.addMapping(this.type, OFType.STATS_REPLY, this);
+    }
+
+    /**
+     * Adds a mapping from type value to OFStatisticsType enum
+     *
+     * @param i OpenFlow wire protocol type
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     * @param st type
+     */
+    static public void addMapping(short i, OFType t, OFStatisticsType st) {
+        if (i < 0)
+            i = (short) (16+i);
+        if (t == OFType.STATS_REQUEST) {
+            if (requestMapping == null)
+                requestMapping = new OFStatisticsType[16];
+            OFStatisticsType.requestMapping[i] = st;
+        } else if (t == OFType.STATS_REPLY){
+            if (replyMapping == null)
+                replyMapping = new OFStatisticsType[16];
+            OFStatisticsType.replyMapping[i] = st;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * Remove a mapping from type value to OFStatisticsType enum
+     *
+     * @param i OpenFlow wire protocol type
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     */
+    static public void removeMapping(short i, OFType t) {
+        if (i < 0)
+            i = (short) (16+i);
+        if (t == OFType.STATS_REQUEST) {
+            requestMapping[i] = null;
+        } else if (t == OFType.STATS_REPLY){
+            replyMapping[i] = null;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * Given a wire protocol OpenFlow type number, return the OFStatisticsType
+     * associated with it
+     *
+     * @param i wire protocol number
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     * @return OFStatisticsType enum type
+     */
+    static public OFStatisticsType valueOf(short i, OFType t) {
+        if (i < 0)
+            i = (short) (16+i);
+        if (t == OFType.STATS_REQUEST) {
+            return requestMapping[i];
+        } else if (t == OFType.STATS_REPLY){
+            return replyMapping[i];
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this
+     * OFStatisticsType
+     */
+    public short getTypeValue() {
+        return this.type;
+    }
+
+    /**
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     * @return return the OFMessage subclass corresponding to this
+     *                OFStatisticsType
+     */
+    public Class<? extends OFStatistics> toClass(OFType t) {
+        if (t == OFType.STATS_REQUEST) {
+            return requestClass;
+        } else if (t == OFType.STATS_REPLY){
+            return replyClass;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * Returns the no-argument Constructor of the implementation class for
+     * this OFStatisticsType, either request or reply based on the supplied
+     * OFType
+     *
+     * @param t
+     * @return
+     */
+    public Constructor<? extends OFStatistics> getConstructor(OFType t) {
+        if (t == OFType.STATS_REQUEST) {
+            return requestConstructor;
+        } else if (t == OFType.STATS_REPLY) {
+            return replyConstructor;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * @return the requestInstantiable
+     */
+    public Instantiable<OFStatistics> getRequestInstantiable() {
+        return requestInstantiable;
+    }
+
+    /**
+     * @param requestInstantiable the requestInstantiable to set
+     */
+    public void setRequestInstantiable(
+            Instantiable<OFStatistics> requestInstantiable) {
+        this.requestInstantiable = requestInstantiable;
+    }
+
+    /**
+     * @return the replyInstantiable
+     */
+    public Instantiable<OFStatistics> getReplyInstantiable() {
+        return replyInstantiable;
+    }
+
+    /**
+     * @param replyInstantiable the replyInstantiable to set
+     */
+    public void setReplyInstantiable(Instantiable<OFStatistics> replyInstantiable) {
+        this.replyInstantiable = replyInstantiable;
+    }
+
+    /**
+     * Returns a new instance of the implementation class for
+     * this OFStatisticsType, either request or reply based on the supplied
+     * OFType
+     *
+     * @param t
+     * @return
+     */
+    public OFStatistics newInstance(OFType t) {
+        if (t == OFType.STATS_REQUEST) {
+            return requestInstantiable.instantiate();
+        } else if (t == OFType.STATS_REPLY) {
+            return replyInstantiable.instantiate();
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFTableStatistics.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFTableStatistics.java
new file mode 100644 (file)
index 0000000..9e6d34e
--- /dev/null
@@ -0,0 +1,223 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.StringByteSerializer;
+
+/**
+ * Represents an ofp_table_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFTableStatistics implements OFStatistics {
+    public static int MAX_TABLE_NAME_LEN = 32;
+
+    protected byte tableId;
+    protected String name;
+    protected int wildcards;
+    protected int maximumEntries;
+    protected int activeCount;
+    protected long lookupCount;
+    protected long matchedCount;
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the wildcards
+     */
+    public int getWildcards() {
+        return wildcards;
+    }
+
+    /**
+     * @param wildcards the wildcards to set
+     */
+    public void setWildcards(int wildcards) {
+        this.wildcards = wildcards;
+    }
+
+    /**
+     * @return the maximumEntries
+     */
+    public int getMaximumEntries() {
+        return maximumEntries;
+    }
+
+    /**
+     * @param maximumEntries the maximumEntries to set
+     */
+    public void setMaximumEntries(int maximumEntries) {
+        this.maximumEntries = maximumEntries;
+    }
+
+    /**
+     * @return the activeCount
+     */
+    public int getActiveCount() {
+        return activeCount;
+    }
+
+    /**
+     * @param activeCount the activeCount to set
+     */
+    public void setActiveCount(int activeCount) {
+        this.activeCount = activeCount;
+    }
+
+    /**
+     * @return the lookupCount
+     */
+    public long getLookupCount() {
+        return lookupCount;
+    }
+
+    /**
+     * @param lookupCount the lookupCount to set
+     */
+    public void setLookupCount(long lookupCount) {
+        this.lookupCount = lookupCount;
+    }
+
+    /**
+     * @return the matchedCount
+     */
+    public long getMatchedCount() {
+        return matchedCount;
+    }
+
+    /**
+     * @param matchedCount the matchedCount to set
+     */
+    public void setMatchedCount(long matchedCount) {
+        this.matchedCount = matchedCount;
+    }
+
+    @Override
+    public int getLength() {
+        return 64;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        data.readByte(); // pad
+        data.readByte(); // pad
+        this.name = StringByteSerializer.readFrom(data, MAX_TABLE_NAME_LEN);
+        this.wildcards = data.readInt();
+        this.maximumEntries = data.readInt();
+        this.activeCount = data.readInt();
+        this.lookupCount = data.readLong();
+        this.matchedCount = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0); // pad
+        data.writeByte((byte) 0); // pad
+        data.writeByte((byte) 0); // pad
+        StringByteSerializer.writeTo(data, MAX_TABLE_NAME_LEN, this.name);
+        data.writeInt(this.wildcards);
+        data.writeInt(this.maximumEntries);
+        data.writeInt(this.activeCount);
+        data.writeLong(this.lookupCount);
+        data.writeLong(this.matchedCount);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 449;
+        int result = 1;
+        result = prime * result + activeCount;
+        result = prime * result + (int) (lookupCount ^ (lookupCount >>> 32));
+        result = prime * result + (int) (matchedCount ^ (matchedCount >>> 32));
+        result = prime * result + maximumEntries;
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + tableId;
+        result = prime * result + wildcards;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFTableStatistics)) {
+            return false;
+        }
+        OFTableStatistics other = (OFTableStatistics) obj;
+        if (activeCount != other.activeCount) {
+            return false;
+        }
+        if (lookupCount != other.lookupCount) {
+            return false;
+        }
+        if (matchedCount != other.matchedCount) {
+            return false;
+        }
+        if (maximumEntries != other.maximumEntries) {
+            return false;
+        }
+        if (name == null) {
+            if (other.name != null) {
+                return false;
+            }
+        } else if (!name.equals(other.name)) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        if (wildcards != other.wildcards) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFVendorStatistics.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/statistics/OFVendorStatistics.java
new file mode 100644 (file)
index 0000000..0257a6a
--- /dev/null
@@ -0,0 +1,83 @@
+/**
+*    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.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * The base class for vendor implemented statistics
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFVendorStatistics implements OFStatistics {
+    protected int vendor;
+    protected byte[] body;
+
+    // non-message fields
+    protected int length = 0;
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.vendor = data.readInt();
+        if (body == null)
+            body = new byte[length - 4];
+        data.readBytes(body);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(this.vendor);
+        if (body != null)
+            data.writeBytes(body);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 457;
+        int result = 1;
+        result = prime * result + vendor;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFVendorStatistics)) {
+            return false;
+        }
+        OFVendorStatistics other = (OFVendorStatistics) obj;
+        if (vendor != other.vendor) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int getLength() {
+        return length;
+    }
+
+    public void setLength(int length) {
+        this.length = length;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java
new file mode 100644 (file)
index 0000000..1f0e14b
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.openflow.protocol.Instantiable;
+
+/**
+ * Subclass of OFVendorDataType that works with any vendor data format that
+ * begins with a integral value to indicate the format of the remaining data.
+ * It maps from the per-vendor-id integral data type code to the object
+ * used to instantiate the class associated with that vendor data type.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFBasicVendorDataType extends OFVendorDataType {
+    
+    /**
+     * The data type value at the beginning of the vendor data.
+     */
+    protected long type;
+    
+    /**
+     * Construct an empty (i.e. no specified data type value) vendor data type.
+     */
+    public OFBasicVendorDataType() {
+        super();
+        this.type = 0;
+    }
+    
+    /**
+     * Store some information about the vendor data type, including wire protocol
+     * type number, derived class and instantiator.
+     *
+     * @param type Wire protocol number associated with this vendor data type
+     * @param instantiator An Instantiator<OFVendorData> implementation that
+     *              creates an instance of an appropriate subclass of OFVendorData.
+     */
+    public OFBasicVendorDataType(long type, Instantiable<OFVendorData> instantiator) {
+        super(instantiator);
+        this.type = type;
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this OFVendorDataType
+     */
+    public long getTypeValue() {
+        return this.type;
+    }
+    
+    /**
+     * @param type the wire protocol value for this data type
+     */
+    public void setTypeValue(long type) {
+        this.type = type;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java
new file mode 100644 (file)
index 0000000..5f789dc
--- /dev/null
@@ -0,0 +1,162 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.Instantiable;
+
+/**
+ * Basic subclass of OFVendorId that works with any vendor data format where
+ * the data begins with an integral data type value.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFBasicVendorId extends OFVendorId {
+    
+    /**
+     * The size of the data type value at the beginning of all vendor
+     * data associated with this vendor id. The data type size must be
+     * either 1, 2, 4 or 8.
+     */
+    protected int dataTypeSize;
+    
+    /**
+     * Map of the vendor data types that have been registered for this
+     * vendor id.
+     */
+    protected Map<Long, OFBasicVendorDataType> dataTypeMap =
+            new HashMap<Long, OFBasicVendorDataType>();
+    
+    /**
+     * Construct an OFVendorId that where the vendor data begins
+     * with a data type value whose size is dataTypeSize.
+     * @param id the id of the vendor, typically the OUI of a vendor
+     *     prefixed with 0.
+     * @param dataTypeSize the size of the integral data type value
+     *     at the beginning of the vendor data. The value must be the
+     *     size of an integeral data type (i.e. either 1,2,4 or 8).
+     */
+    public OFBasicVendorId(int id, int dataTypeSize) {
+        super(id);
+        assert (dataTypeSize == 1) || (dataTypeSize == 2) ||
+               (dataTypeSize == 4) || (dataTypeSize == 8);
+        this.dataTypeSize = dataTypeSize;
+    }
+
+    /**
+     * Get the size of the data type value at the beginning of the vendor
+     * data. OFBasicVendorId assumes that this value is common across all of
+     * the vendor data formats associated with a given vendor id.
+     * @return
+     */
+    public int getDataTypeSize() {
+        return dataTypeSize;
+    }
+    
+    /**
+     * Register a vendor data type with this vendor id.
+     * @param vendorDataType
+     */
+    public void registerVendorDataType(OFBasicVendorDataType vendorDataType) {
+        dataTypeMap.put(vendorDataType.getTypeValue(), vendorDataType);
+    }
+    
+    /**
+     * Lookup the OFVendorDataType instance that has been registered with
+     * this vendor id.
+     * 
+     * @param vendorDataType the integer code that was parsed from the 
+     * @return
+     */
+    public OFVendorDataType lookupVendorDataType(int vendorDataType) {
+        return dataTypeMap.get(Long.valueOf(vendorDataType));
+    }
+
+    /**
+     * This function parses enough of the data from the buffer to be able
+     * to determine the appropriate OFVendorDataType for the data. It is meant
+     * to be a reasonably generic implementation that will work for most
+     * formats of vendor extensions. If the vendor data doesn't fit the
+     * assumptions listed below, then this method will need to be overridden
+     * to implement custom parsing.
+     * 
+     * This implementation assumes that the vendor data begins with a data
+     * type code that is used to distinguish different formats of vendor
+     * data associated with a particular vendor ID.
+     * The exact format of the data is vendor-defined, so we don't know how
+     * how big the code is (or really even if there is a code). This code
+     * assumes that the common case will be that the data does include
+     * an initial type code (i.e. so that the vendor can have multiple
+     * message/data types) and that the size is either 1, 2 or 4 bytes.
+     * The size of the initial type code is configured by the subclass of
+     * OFVendorId.
+     * 
+     * @param data the channel buffer containing the vendor data.
+     * @param length the length to the end of the enclosing message
+     * @return the OFVendorDataType that can be used to instantiate the
+     *         appropriate subclass of OFVendorData.
+     */
+    public OFVendorDataType parseVendorDataType(ChannelBuffer data, int length) {
+        OFVendorDataType vendorDataType = null;
+        
+        // Parse out the type code from the vendor data.
+        long dataTypeValue = 0;
+        if ((length == 0) || (length >= dataTypeSize)) {
+            switch (dataTypeSize) {
+                case 1:
+                    dataTypeValue = data.readByte();
+                    break;
+                case 2:
+                    dataTypeValue = data.readShort();
+                    break;
+                case 4:
+                    dataTypeValue = data.readInt();
+                    break;
+                case 8:
+                    dataTypeValue = data.readLong();
+                    break;
+                default:
+                    // This would be indicative of a coding error where the
+                    // dataTypeSize was specified incorrectly. This should have been
+                    // caught in the constructor for OFVendorId.
+                    assert false;
+            }
+            
+            vendorDataType = dataTypeMap.get(dataTypeValue);
+        }
+        
+        // If we weren't able to parse/map the data to a known OFVendorDataType,
+        // then map it to a generic vendor data type.
+        if (vendorDataType == null) {
+            vendorDataType = new OFBasicVendorDataType(dataTypeValue,
+                new Instantiable<OFVendorData>() {
+                    @Override
+                    public OFVendorData instantiate() {
+                        return new OFByteArrayVendorData();
+                    }
+                }
+            );
+        }
+        
+        return vendorDataType;
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java
new file mode 100644 (file)
index 0000000..08fa003
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Basic implementation of OFVendorData that just treats the data as a
+ * byte array. This is used if there's an OFVendor message where there's
+ * no registered OFVendorId or no specific OFVendorDataType that can be
+ * determined from the data.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFByteArrayVendorData implements OFVendorData {
+
+    protected byte[] bytes;
+    
+    /**
+     * Construct vendor data with an empty byte array.
+     */
+    public OFByteArrayVendorData() {
+    }
+    
+    /**
+     * Construct vendor data with the specified byte array.
+     * @param bytes
+     */
+    public OFByteArrayVendorData(byte[] bytes) {
+        this.bytes = bytes;
+    }
+    
+    /**
+     * Get the associated byte array for this vendor data.
+     * @return the byte array containing the raw vendor data.
+     */
+    public byte[] getBytes() {
+        return bytes;
+    }
+    
+    /**
+     * Set the byte array for the vendor data.
+     * @param bytes the raw byte array containing the vendor data.
+     */
+    public void setBytes(byte[] bytes) {
+        this.bytes = bytes;
+    }
+    
+    /**
+     * Get the length of the vendor data. In this case it's just then length
+     * of the underlying byte array.
+     * @return the length of the vendor data
+     */
+    @Override
+    public int getLength() {
+        return (bytes != null) ? bytes.length : 0;
+    }
+
+    /**
+     * Read the vendor data from the ChannelBuffer into the byte array.
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    @Override
+    public void readFrom(ChannelBuffer data, int length) {
+        bytes = new byte[length];
+        data.readBytes(bytes);
+    }
+
+    /**
+     * Write the vendor data bytes to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        if (bytes != null)
+            data.writeBytes(bytes);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorData.java
new file mode 100644 (file)
index 0000000..6dfb4e6
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * The base class for all vendor data.
+ *
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public interface OFVendorData {
+    /**
+     * @return length of the data
+     */
+    public int getLength();
+    
+    /**
+     * Read the vendor data from the specified ChannelBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data, int length);
+
+    /**
+     * Write the vendor data to the specified ChannelBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java
new file mode 100644 (file)
index 0000000..ecae482
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.openflow.protocol.Instantiable;
+
+/**
+ * Class that represents a specific vendor data type format in an
+ * OFVendor message. Typically the vendor data will begin with an integer
+ * code that determines the format of the rest of the data, but this
+ * class does not assume that. It's basically just a holder for an
+ * instantiator of the appropriate subclass of OFVendorData.
+ *
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFVendorDataType {
+
+    /**
+     * Object that instantiates the subclass of OFVendorData 
+     * associated with this data type.
+     */
+    protected Instantiable<OFVendorData> instantiable;
+
+    /**
+     * Construct an empty vendor data type.
+     */
+    public OFVendorDataType() {
+        super();
+    }
+
+    /**
+     * Construct a vendor data type with the specified instantiable.
+     * @param instantiable object that creates the subclass of OFVendorData
+     *     associated with this data type.
+     */
+    public OFVendorDataType(Instantiable<OFVendorData> instantiable) {
+        this.instantiable = instantiable;
+    }
+    
+    /**
+     * Returns a new instance of a subclass of OFVendorData associated with
+     * this OFVendorDataType.
+     * 
+     * @return the new object
+     */
+    public OFVendorData newInstance() {
+        return instantiable.instantiate();
+    }
+
+    /**
+     * @return the instantiable
+     */
+    public Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * @param instantiable the instantiable to set
+     */
+    public void setInstantiable(Instantiable<OFVendorData> instantiable) {
+        this.instantiable = instantiable;
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorId.java b/third-party/openflowj_netty/src/main/java/org/openflow/protocol/vendor/OFVendorId.java
new file mode 100644 (file)
index 0000000..f0af8a7
--- /dev/null
@@ -0,0 +1,85 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Base class for the vendor ID corresponding to vendor extensions from a
+ * given vendor. It is responsible for knowing how to parse out some sort of
+ * data type value from the vendor data in an OFVendor message so that we can
+ * dispatch to the different subclasses of OFVendorData corresponding to the
+ * different formats of data for the vendor extensions.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public abstract class OFVendorId {
+    static Map<Integer, OFVendorId> mapping = new HashMap<Integer, OFVendorId>();
+
+    /**
+     * The vendor id value, typically the OUI of the vendor prefixed with 0.
+     */
+    protected int id;
+    
+    /**
+     * Register a new vendor id.
+     * @param vendorId the vendor id to register
+     */
+    public static void registerVendorId(OFVendorId vendorId) {
+        mapping.put(vendorId.getId(), vendorId);
+    }
+    
+    /**
+     * Lookup the OFVendorId instance corresponding to the given id value.
+     * @param id the integer vendor id value
+     * @return the corresponding OFVendorId that's been registered for the
+     *     given value, or null if there id has not been registered.
+     */
+    public static OFVendorId lookupVendorId(int id) {
+        return mapping.get(id);
+    }
+    
+    /**
+     * Create an OFVendorId with the give vendor id value
+     * @param id
+     */
+    public OFVendorId(int id) {
+        this.id = id;
+    }
+    
+    /**
+     * @return the vendor id value
+     */
+    public int getId() {
+        return id;
+    }
+    
+    /**
+     * This function parses enough of the data from the channel buffer to be
+     * able to determine the appropriate OFVendorDataType for the data.
+     * 
+     * @param data the channel buffer containing the vendor data.
+     * @param length the length to the end of the enclosing message
+     * @return the OFVendorDataType that can be used to instantiate the
+     *         appropriate subclass of OFVendorData.
+     */
+    public abstract OFVendorDataType parseVendorDataType(ChannelBuffer data, int length);
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/HexString.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/HexString.java
new file mode 100644 (file)
index 0000000..b562824
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+*    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.util;
+
+import java.math.BigInteger;
+
+public class HexString {
+    /**
+     * Convert a string of bytes to a ':' separated hex string
+     * @param bytes
+     * @return "0f:ca:fe:de:ad:be:ef"
+     */
+    public static String toHexString(byte[] bytes) {
+        if (bytes == null) return "";
+        int i;
+        String ret = "";
+        String tmp;
+        for(i=0; i< bytes.length; i++) {
+            if(i> 0)
+                ret += ":";
+            tmp = Integer.toHexString(U8.f(bytes[i]));
+            if (tmp.length() == 1)
+                ret += "0";
+            ret += tmp; 
+        }
+        return ret;
+    }
+    
+    public static String toHexString(long val, int padTo) {
+        char arr[] = Long.toHexString(val).toCharArray();
+        String ret = "";
+        // prepend the right number of leading zeros
+        int i = 0;
+        for (; i < (padTo * 2 - arr.length); i++) {
+            ret += "0";
+            if ((i % 2) != 0)
+                ret += ":";
+        }
+        for (int j = 0; j < arr.length; j++) {
+            ret += arr[j];
+            if ((((i + j) % 2) != 0) && (j < (arr.length - 1)))
+                ret += ":";
+        }
+        return ret;        
+    }
+   
+    public static String toHexString(long val) {
+        return toHexString(val, 8);
+    }
+    
+    
+    /**
+     * Convert a string of hex values into a string of bytes
+     * @param values "0f:ca:fe:de:ad:be:ef"
+     * @return [15, 5 ,2, 5, 17] 
+     * @throws NumberFormatException If the string can not be parsed
+     */ 
+    public static byte[] fromHexString(String values) throws NumberFormatException {
+        String[] octets = values.split(":");
+        byte[] ret = new byte[octets.length];
+        
+        for(int i = 0; i < octets.length; i++) {
+            if (octets[i].length() > 2)
+                throw new NumberFormatException("Invalid octet length");
+            ret[i] = Integer.valueOf(octets[i], 16).byteValue();
+        }
+        return ret;
+    }
+    
+    public static long toLong(String values) throws NumberFormatException {
+        // Long.parseLong() can't handle HexStrings with MSB set. Sigh. 
+        BigInteger bi = new BigInteger(values.replaceAll(":", ""),16);
+        if (bi.bitLength() > 64) 
+            throw new NumberFormatException("Input string too big to fit in long: " + values);
+        return bi.longValue();
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/IProducer.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/IProducer.java
new file mode 100644 (file)
index 0000000..52ae79a
--- /dev/null
@@ -0,0 +1,9 @@
+package org.openflow.util;
+
+public interface IProducer {
+
+    public void registerConsumer(Class<?> iface, Object anObj);
+
+    public void deregisterConsumer(Class<?> iface, Object anObj);
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/LRULinkedHashMap.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/LRULinkedHashMap.java
new file mode 100644 (file)
index 0000000..7f05381
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+*    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.util;
+
+import java.util.LinkedHashMap;
+
+public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
+    private static final long serialVersionUID = -2964986094089626647L;
+    protected int maximumCapacity;
+
+    public LRULinkedHashMap(int initialCapacity, int maximumCapacity) {
+        super(initialCapacity, 0.75f, true);
+        this.maximumCapacity = maximumCapacity;
+    }
+
+    public LRULinkedHashMap(int maximumCapacity) {
+        super(16, 0.75f, true);
+        this.maximumCapacity = maximumCapacity;
+    }
+
+    @Override
+    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
+        if (this.size() > maximumCapacity)
+            return true;
+        return false;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/ProducerConsumer.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/ProducerConsumer.java
new file mode 100644 (file)
index 0000000..f2244ef
--- /dev/null
@@ -0,0 +1,223 @@
+package org.openflow.util;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The following implement a producer/consumer design pattern in which both
+ * producers and consumers explicitly employ a centralized registration
+ * mechanism, and java Interfaces are used as contracts.<br>
+ */
+public class ProducerConsumer {
+
+    /*
+     * Class variables
+     */
+    protected static ProducerConsumer singleton;
+
+    /*
+     * Default constructor
+     */
+    protected ProducerConsumer() {
+        producerMap = new Hashtable<Class<?>, Set<IProducer>>();
+    }
+
+    /*
+     * Instance variables
+     */
+
+    // Interface/IProducer map
+    protected Map<Class<?>, Set<IProducer>> producerMap;
+
+    /*
+     * Protected methods
+     */
+
+    protected void _registerConsumer(Object consumer, Class<?>[] interfaces,
+                                     Set<Class<?>> iSet,
+                                     Set<Class<?>> iUniqueSet) {
+        // *...Process all interfaces...*/
+        for (Class<?> iface : interfaces) {
+
+            // *...Protect against repeated interfaces...*/
+            if (!iUniqueSet.contains(iface)) {
+                iUniqueSet.add(iface);
+
+                Set<IProducer> producers = producerMap.get(iface);
+
+                if (producers != null) {
+                    for (IProducer producer : producers)
+                        producer.registerConsumer(iface, consumer);
+                    iSet.add(iface);
+                }
+
+                // *...Recurse...*/
+                _registerConsumer(consumer, iface.getInterfaces(), iSet,
+                                  iUniqueSet);
+            }
+        }
+    }
+
+    protected void _registerConsumer(Object consumer, Class<?> clazz,
+                                     Set<Class<?>> iSet,
+                                     Set<Class<?>> iUniqueSet) {
+        if (clazz != null) {
+            // *...Process all interfaces...*/
+            _registerConsumer(consumer, clazz.getInterfaces(), iSet,
+                              iUniqueSet);
+
+            // *...Recurse the class hierarchy...*/
+            _registerConsumer(consumer, clazz.getSuperclass(), iSet,
+                              iUniqueSet);
+        }
+    }
+
+    protected int _deregisterConsumer(Object consumer,
+                                      Class<?>[] interfaces,
+                                      Set<Class<?>> iUniqueSet) {
+        int count = 0;
+
+        // *...Process all interfaces...*/
+        for (Class<?> iface : interfaces) {
+
+            // *...Protect against repeated interfaces...*/
+            if (!iUniqueSet.contains(iface)) {
+                iUniqueSet.add(iface);
+
+                Set<IProducer> producers = producerMap.get(iface);
+
+                if (producers != null) {
+                    for (IProducer producer : producers)
+                        producer.deregisterConsumer(iface, consumer);
+
+                    count++;
+                }
+
+                // *...Recurse...*/
+                count += _deregisterConsumer(consumer,
+                                             iface.getInterfaces(),
+                                             iUniqueSet);
+            }
+        }
+
+        return count;
+    }
+
+    protected int _deregisterConsumer(Object consumer, Class<?> clazz,
+                                      Set<Class<?>> iUniqueSet) {
+        int count = 0;
+
+        if (clazz != null) {
+            // *...Process all interfaces...*/
+            count += _deregisterConsumer(consumer, clazz.getInterfaces(),
+                                         iUniqueSet);
+
+            // *...Recurse the class hierarchy...*/
+            count += _deregisterConsumer(consumer, clazz.getSuperclass(),
+                                         iUniqueSet);
+        }
+
+        return count;
+    }
+
+    /*
+     * Singleton API
+     */
+
+    /**
+     * @return singleton ProducerConsumer
+     */
+    public static synchronized ProducerConsumer getSingleton() {
+        if (singleton == null) singleton = new ProducerConsumer();
+
+        return singleton;
+    }
+
+    /*
+     * Producer APIs
+     */
+
+    /**
+     * Producer registration
+     * 
+     * @param producer
+     *            object that implements IProducer
+     * @param iface
+     *            interface supported by the producer
+     * @return whether there was a previously registered producer, or true if
+     *         one or more the arguments were invalid
+     */
+    public boolean registerProducer(IProducer producer, Class<?> iface) {
+        if (producer != null && iface != null && iface.isInterface()) {
+            Set<IProducer> producers = producerMap.get(iface);
+
+            if (producers == null) {
+                producers = new HashSet<IProducer>();
+                producerMap.put(iface, producers);
+            }
+
+            return producers.add(producer);
+        } else
+            return true;
+    }
+
+    /**
+     * Producer deregistration
+     * 
+     * @param producer
+     *            object that implements IProducer
+     * @param iface
+     *            interface supported by the producer
+     * @return whether the interface/producer pair was removed, or false if one
+     *         or more the arguments were invalid
+     */
+    public boolean deregisterProducer(IProducer producer, Class<?> iface) {
+        if (producer != null && iface != null && iface.isInterface()) {
+            Set<IProducer> producers = producerMap.get(iface);
+
+            if (producers != null) return producers.remove(producer);
+        }
+
+        return false;
+    }
+
+    /*
+     * Consumer APIs
+     */
+
+    /**
+     * Consumer registration
+     * 
+     * @param consumer
+     *            object that implements producer-specific interfaces
+     * @return set of supported interfaces
+     */
+    public Set<Class<?>> registerConsumer(Object consumer) {
+        Set<Class<?>> iSet = new HashSet<Class<?>>();
+
+        if (consumer != null)
+                             _registerConsumer(consumer,
+                                               consumer.getClass(), iSet,
+                                               new HashSet<Class<?>>());
+
+        return iSet;
+    }
+
+    /**
+     * Consumer deregistration
+     * 
+     * @param consumer
+     *            object to deregister
+     * @return number of unregistered interfaces
+     */
+    public int deregisterConsumer(Object consumer) {
+        if (consumer != null)
+            return _deregisterConsumer(consumer, consumer.getClass(),
+                                       new HashSet<Class<?>>());
+        else
+            return 0;
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/StringByteSerializer.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/StringByteSerializer.java
new file mode 100644 (file)
index 0000000..9287fd2
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+*    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.util;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+public class StringByteSerializer {
+    public static String readFrom(ChannelBuffer data, int length) {
+        byte[] stringBytes = new byte[length];
+        data.readBytes(stringBytes);
+        // find the first index of 0
+        int index = 0;
+        for (byte b : stringBytes) {
+            if (0 == b)
+                break;
+            ++index;
+        }
+        return new String(Arrays.copyOf(stringBytes, index),
+                Charset.forName("ascii"));
+    }
+
+    public static void writeTo(ChannelBuffer data, int length, String value) {
+        try {
+            byte[] name = value.getBytes("ASCII");
+            if (name.length < length) {
+                data.writeBytes(name);
+                for (int i = name.length; i < length; ++i) {
+                    data.writeByte((byte) 0);
+                }
+            } else {
+                data.writeBytes(name, 0, length-1);
+                data.writeByte((byte) 0);
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/U16.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/U16.java
new file mode 100644 (file)
index 0000000..0d8917d
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+*    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.util;
+
+public class U16 {
+    public static int f(short i) {
+        return (int)i & 0xffff;
+    }
+
+    public static short t(int l) {
+        return (short) l;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/U32.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/U32.java
new file mode 100644 (file)
index 0000000..3aab400
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+*    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.util;
+
+public class U32 {
+    public static long f(int i) {
+        return (long)i & 0xffffffffL;
+    }
+
+    public static int t(long l) {
+        return (int) l;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/U64.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/U64.java
new file mode 100644 (file)
index 0000000..c6ae0f7
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+*    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.util;
+
+import java.math.BigInteger;
+
+public class U64 {
+    public static BigInteger f(long i) {
+        return new BigInteger(Long.toBinaryString(i), 2);
+    }
+
+    public static long t(BigInteger l) {
+        return l.longValue();
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/U8.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/U8.java
new file mode 100644 (file)
index 0000000..0b575ad
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+*    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.util;
+
+public class U8 {
+    public static short f(byte i) {
+        return (short) ((short)i & 0xff);
+    }
+
+    public static byte t(short l) {
+        return (byte) l;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/util/Unsigned.java b/third-party/openflowj_netty/src/main/java/org/openflow/util/Unsigned.java
new file mode 100644 (file)
index 0000000..0754a3f
--- /dev/null
@@ -0,0 +1,212 @@
+/**
+*    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.util;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+/*****
+ * A util library class for dealing with the lack of unsigned datatypes in Java
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+
+public class Unsigned {
+    /**
+     * Get an unsigned byte from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the byte from
+     * @return an unsigned byte contained in a short
+     */
+    public static short getUnsignedByte(ByteBuffer bb) {
+        return ((short) (bb.get() & (short) 0xff));
+    }
+
+    /**
+     * Get an unsigned byte from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the byte from
+     * @param offset the offset to get the byte from
+     * @return an unsigned byte contained in a short
+     */
+    public static short getUnsignedByte(ByteBuffer bb, int offset) {
+        return ((short) (bb.get(offset) & (short) 0xff));
+    }
+
+    /**
+     * Put an unsigned byte into the specified ByteBuffer at the current
+     * position
+     *
+     * @param bb ByteBuffer to put the byte into
+     * @param v the short containing the unsigned byte
+     */
+    public static void putUnsignedByte(ByteBuffer bb, short v) {
+        bb.put((byte) (v & 0xff));
+    }
+
+    /**
+     * Put an unsigned byte into the specified ByteBuffer at the specified
+     * offset
+     *
+     * @param bb ByteBuffer to put the byte into
+     * @param v the short containing the unsigned byte
+     * @param offset the offset to insert the unsigned byte at
+     */
+    public static void putUnsignedByte(ByteBuffer bb, short v, int offset) {
+        bb.put(offset, (byte) (v & 0xff));
+    }
+
+    /**
+     * Get an unsigned short from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the byte from
+     * @return an unsigned short contained in a int
+     */
+    public static int getUnsignedShort(ByteBuffer bb) {
+        return (bb.getShort() & 0xffff);
+    }
+
+    /**
+     * Get an unsigned short from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the short from
+     * @param offset the offset to get the short from
+     * @return an unsigned short contained in a int
+     */
+    public static int getUnsignedShort(ByteBuffer bb, int offset) {
+        return (bb.getShort(offset) & 0xffff);
+    }
+
+    /**
+     * Put an unsigned short into the specified ByteBuffer at the current
+     * position
+     *
+     * @param bb ByteBuffer to put the short into
+     * @param v the int containing the unsigned short
+     */
+    public static void putUnsignedShort(ByteBuffer bb, int v) {
+        bb.putShort((short) (v & 0xffff));
+    }
+
+    /**
+     * Put an unsigned short into the specified ByteBuffer at the specified
+     * offset
+     *
+     * @param bb ByteBuffer to put the short into
+     * @param v the int containing the unsigned short
+     * @param offset the offset to insert the unsigned short at
+     */
+    public static void putUnsignedShort(ByteBuffer bb, int v, int offset) {
+        bb.putShort(offset, (short) (v & 0xffff));
+    }
+
+    /**
+     * Get an unsigned int from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the int from
+     * @return an unsigned int contained in a long
+     */
+    public static long getUnsignedInt(ByteBuffer bb) {
+        return ((long) bb.getInt() & 0xffffffffL);
+    }
+
+    /**
+     * Get an unsigned int from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the int from
+     * @param offset the offset to get the int from
+     * @return an unsigned int contained in a long
+     */
+    public static long getUnsignedInt(ByteBuffer bb, int offset) {
+        return ((long) bb.getInt(offset) & 0xffffffffL);
+    }
+
+    /**
+     * Put an unsigned int into the specified ByteBuffer at the current position
+     *
+     * @param bb ByteBuffer to put the int into
+     * @param v the long containing the unsigned int
+     */
+    public static void putUnsignedInt(ByteBuffer bb, long v) {
+        bb.putInt((int) (v & 0xffffffffL));
+    }
+
+    /**
+     * Put an unsigned int into the specified ByteBuffer at the specified offset
+     *
+     * @param bb ByteBuffer to put the int into
+     * @param v the long containing the unsigned int
+     * @param offset the offset to insert the unsigned int at
+     */
+    public static void putUnsignedInt(ByteBuffer bb, long v, int offset) {
+        bb.putInt(offset, (int) (v & 0xffffffffL));
+    }
+
+    /**
+     * Get an unsigned long from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the long from
+     * @return an unsigned long contained in a BigInteger
+     */
+    public static BigInteger getUnsignedLong(ByteBuffer bb) {
+        byte[] v = new byte[8];
+        for (int i = 0; i < 8; ++i) {
+            v[i] = bb.get(i);
+        }
+        return new BigInteger(1, v);
+    }
+
+    /**
+     * Get an unsigned long from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the long from
+     * @param offset the offset to get the long from
+     * @return an unsigned long contained in a BigInteger
+     */
+    public static BigInteger getUnsignedLong(ByteBuffer bb, int offset) {
+        byte[] v = new byte[8];
+        for (int i = 0; i < 8; ++i) {
+            v[i] = bb.get(offset+i);
+        }
+        return new BigInteger(1, v);
+    }
+
+    /**
+     * Put an unsigned long into the specified ByteBuffer at the current
+     * position
+     *
+     * @param bb ByteBuffer to put the long into
+     * @param v the BigInteger containing the unsigned long
+     */
+    public static void putUnsignedLong(ByteBuffer bb, BigInteger v) {
+        bb.putLong(v.longValue());
+    }
+
+    /**
+     * Put an unsigned long into the specified ByteBuffer at the specified
+     * offset
+     *
+     * @param bb  ByteBuffer to put the long into
+     * @param v the BigInteger containing the unsigned long
+     * @param offset the offset to insert the unsigned long at
+     */
+    public static void putUnsignedLong(ByteBuffer bb, BigInteger v, int offset) {
+        bb.putLong(offset, v.longValue());
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java
new file mode 100644 (file)
index 0000000..687d544
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Base class for vendor data corresponding to a Nicira vendor extension.
+ * Nicira vendor data always starts with a 4-byte integer data type value.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFNiciraVendorData implements OFVendorData {
+
+    public static final int NX_VENDOR_ID = 0x00002320;
+    /**
+     * The value of the integer data type at the beginning of the vendor data
+     */
+    protected int dataType;
+    
+    /**
+     * Construct empty (i.e. unspecified data type) Nicira vendor data.
+     */
+    public OFNiciraVendorData() {
+    }
+    
+    /**
+     * Contruct Nicira vendor data with the specified data type
+     * @param dataType the data type value at the beginning of the vendor data.
+     */
+    public OFNiciraVendorData(int dataType) {
+        this.dataType = dataType;
+    }
+    
+    /**
+     * Get the data type value at the beginning of the vendor data
+     * @return the integer data type value
+     */
+    public int getDataType() {
+        return dataType;
+    }
+    
+    /**
+     * Set the data type value
+     * @param dataType the integer data type value at the beginning of the
+     *     vendor data.
+     */
+    public void setDataType(int dataType) {
+        this.dataType = dataType;
+    }
+    
+    /**
+     * Get the length of the vendor data. This implementation will normally
+     * be the superclass for another class that will override this to return
+     * the overall vendor data length. This implementation just returns the 
+     * length of the part that includes the 4-byte integer data type value
+     * at the beginning of the vendor data.
+     */
+    @Override
+    public int getLength() {
+        return 4;
+    }
+
+    /**
+     * Read the vendor data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    @Override
+    public void readFrom(ChannelBuffer data, int length) {
+        dataType = data.readInt();
+    }
+
+    /**
+     * Write the vendor data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(dataType);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java
new file mode 100644 (file)
index 0000000..98f88b2
--- /dev/null
@@ -0,0 +1,30 @@
+package org.openflow.vendor.nicira;
+
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorId;
+
+public class OFNiciraVendorExtensions {
+    private static boolean initialized = false;
+
+    public static synchronized void initialize() {
+        if (initialized)
+            return;
+
+        // Configure openflowj to be able to parse the role request/reply
+        // vendor messages.
+        OFBasicVendorId niciraVendorId =
+                new OFBasicVendorId(OFNiciraVendorData.NX_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(niciraVendorId);
+        OFBasicVendorDataType roleRequestVendorData =
+                new OFBasicVendorDataType(OFRoleRequestVendorData.NXT_ROLE_REQUEST,
+                        OFRoleRequestVendorData.getInstantiable());
+        niciraVendorId.registerVendorDataType(roleRequestVendorData);
+        OFBasicVendorDataType roleReplyVendorData =
+                new OFBasicVendorDataType(OFRoleReplyVendorData.NXT_ROLE_REPLY,
+                        OFRoleReplyVendorData.getInstantiable());
+        niciraVendorId.registerVendorDataType(roleReplyVendorData);
+
+        initialized = true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java
new file mode 100644 (file)
index 0000000..fa28c71
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Subclass of OFVendorData representing the vendor data associated with
+ * a role reply vendor extension.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFRoleReplyVendorData extends OFRoleVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFRoleReplyVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFRoleReplyVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a role reply
+     */
+    public static final int NXT_ROLE_REPLY = 11;
+
+    /**
+     * Construct a role reply vendor data with an unspecified role value.
+     */
+    public OFRoleReplyVendorData() {
+        super(NXT_ROLE_REPLY);
+    }
+    
+    /**
+     * Construct a role reply vendor data with the specified role value.
+     * @param role the role value for the role reply. Should be one of
+     *      NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE.
+     */
+    public OFRoleReplyVendorData(int role) {
+        super(NXT_ROLE_REPLY, role);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java
new file mode 100644 (file)
index 0000000..e7dbe71
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Subclass of OFVendorData representing the vendor data associated with
+ * a role request vendor extension.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFRoleRequestVendorData extends OFRoleVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFRoleRequestVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFRoleRequestVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a role request
+     */
+    public static final int NXT_ROLE_REQUEST = 10;
+
+    /**
+     * Construct a role request vendor data with an unspecified role value.
+     */
+    public OFRoleRequestVendorData() {
+        super(NXT_ROLE_REQUEST);
+    }
+    
+    /**
+     * Construct a role request vendor data with the specified role value.
+     * @param role the role value for the role request. Should be one of
+     *      NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE.
+     */
+    public OFRoleRequestVendorData(int role) {
+        super(NXT_ROLE_REQUEST, role);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java
new file mode 100644 (file)
index 0000000..e7c8bf2
--- /dev/null
@@ -0,0 +1,113 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Class that represents the vendor data in the role request
+ * extension implemented by Open vSwitch to support high availability.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFRoleVendorData extends OFNiciraVendorData {
+    
+    /**
+     * Role value indicating that the controller is in the OTHER role.
+     */
+    public static final int NX_ROLE_OTHER = 0;
+    
+    /**
+     * Role value indicating that the controller is in the MASTER role.
+     */
+    public static final int NX_ROLE_MASTER = 1;
+    
+    /**
+     * Role value indicating that the controller is in the SLAVE role.
+     */
+    public static final int NX_ROLE_SLAVE = 2;
+
+    protected int role;
+
+    /** 
+     * Construct an uninitialized OFRoleVendorData
+     */
+    public OFRoleVendorData() {
+        super();
+    }
+    
+    /**
+     * Construct an OFRoleVendorData with the specified data type
+     * (i.e. either request or reply) and an unspecified role.
+     * @param dataType
+     */
+    public OFRoleVendorData(int dataType) {
+        super(dataType);
+    }
+    
+    /**
+     * Construct an OFRoleVendorData with the specified data type
+     * (i.e. either request or reply) and role (i.e. one of of
+     * master, slave, or other).
+     * @param dataType either role request or role reply data type
+     */
+    public OFRoleVendorData(int dataType, int role) {
+        super(dataType);
+        this.role = role;
+    }
+    /**
+     * @return the role value of the role vendor data
+     */
+    public int getRole() {
+        return role;
+    }
+    
+    /**
+     * @param role the role value of the role vendor data
+     */
+    public void setRole(int role) {
+        this.role = role;
+    }
+
+    /**
+     * @return the total length of the role vendor data
+     */
+    @Override
+    public int getLength() {
+        return super.getLength() + 4;
+    }
+    
+    /**
+     * Read the role vendor data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    public void readFrom(ChannelBuffer data, int length) {
+        super.readFrom(data, length);
+        role = data.readInt();
+    }
+
+    /**
+     * Write the role vendor data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(role);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java
new file mode 100644 (file)
index 0000000..9be821f
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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.vendor.openflow;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Base class for vendor data corresponding to extensions to OpenFlow 1.0.
+ * Based on org.openflow.vendor.nicira
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFOpenFlowVendorData implements OFVendorData {
+
+    public static final int OF_VENDOR_ID = 0x000026e1;
+
+    /**
+     * The value of the integer data type at the beginning of the vendor data
+     */
+    protected int dataType;
+
+    /**
+     * Construct empty (i.e. unspecified data type) OpenFlow vendor data.
+     */
+    public OFOpenFlowVendorData() {
+    }
+
+    /**
+     * Construct OpenFlow vendor data with the specified data type
+     * @param dataType the data type value at the beginning of the vendor data.
+     */
+    public OFOpenFlowVendorData(int dataType) {
+        this.dataType = dataType;
+    }
+
+    /**
+     * Get the data type value at the beginning of the vendor data
+     * @return the integer data type value
+     */
+    public int getDataType() {
+        return dataType;
+    }
+
+    /**
+     * Set the data type value
+     * @param dataType the integer data type value at the beginning of the
+     *     vendor data.
+     */
+    public void setDataType(int dataType) {
+        this.dataType = dataType;
+    }
+
+    /**
+     * Get the length of the vendor data. This implementation will normally
+     * be the superclass for another class that will override this to return
+     * the overall vendor data length. This implementation just returns the
+     * length of the part that includes the 4-byte integer data type value
+     * at the beginning of the vendor data.
+     */
+    @Override
+    public int getLength() {
+        return 4;
+    }
+
+    /**
+     * Read the vendor data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    @Override
+    public void readFrom(ChannelBuffer data, int length) {
+        dataType = data.readInt();
+    }
+
+    /**
+     * Write the vendor data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(dataType);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java
new file mode 100644 (file)
index 0000000..3fa1029
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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.vendor.openflow;
+
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorId;
+
+public class OFOpenFlowVendorExtensions {
+    private static boolean initialized = false;
+
+    public static synchronized void initialize() {
+        if (initialized)
+            return;
+
+        // Configure openflowj to be able to parse the OpenFlow extensions.
+        OFBasicVendorId openflowVendorId =
+                new OFBasicVendorId(OFOpenFlowVendorData.OF_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(openflowVendorId);
+
+        OFBasicVendorDataType queueModifyVendorData =
+                new OFBasicVendorDataType(OFQueueModifyVendorData.OFP_EXT_QUEUE_MODIFY,
+                        OFQueueModifyVendorData.getInstantiable());
+        openflowVendorId.registerVendorDataType(queueModifyVendorData);
+
+        OFBasicVendorDataType queueDeleteVendorData =
+                new OFBasicVendorDataType(OFQueueDeleteVendorData.OFP_EXT_QUEUE_DELETE,
+                        OFQueueModifyVendorData.getInstantiable());
+        openflowVendorId.registerVendorDataType(queueDeleteVendorData);
+
+        initialized = true;
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java
new file mode 100644 (file)
index 0000000..4fc52ba
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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.vendor.openflow;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Class that represents the vendor data in the queue delete request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueDeleteVendorData extends OFQueueVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFQueueDeleteVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFQueueDeleteVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a queue delete request
+     */
+    public static final int OFP_EXT_QUEUE_DELETE = 1;
+
+    public OFQueueDeleteVendorData() {
+        super(OFP_EXT_QUEUE_DELETE);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java
new file mode 100644 (file)
index 0000000..0d2f31b
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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.vendor.openflow;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Class that represents the vendor data in the queue modify request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueModifyVendorData extends OFQueueVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFQueueModifyVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFQueueModifyVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a queue modify request
+     */
+    public static final int OFP_EXT_QUEUE_MODIFY = 0;
+
+    public OFQueueModifyVendorData() {
+        super(OFP_EXT_QUEUE_MODIFY);
+    }
+}
diff --git a/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java b/third-party/openflowj_netty/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java
new file mode 100644 (file)
index 0000000..eeae9aa
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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.vendor.openflow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFPacketQueue;
+
+/**
+ * Class that represents the vendor data in a queue modify or delete request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueVendorData extends OFOpenFlowVendorData {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short portNumber;
+    protected List<OFPacketQueue> queues = new ArrayList<OFPacketQueue>();
+
+    public OFQueueVendorData(int dataType) {
+        super(dataType);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param port the port on which the queue is
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+
+    /**
+     * @return the queues
+     */
+    public List<OFPacketQueue> getQueues() {
+        return queues;
+    }
+
+    /**
+     * @param queues the queues to modify or delete
+     */
+    public void setQueues(List<OFPacketQueue> queues) {
+        this.queues = queues;
+    }
+
+    /**
+     * @return the total length of the queue modify or delete msg
+     */
+    @Override
+    public int getLength() {
+        int queuesLength = 0;
+
+        for (OFPacketQueue queue : queues) {
+            queuesLength += queue.getLength();
+        }
+
+        return super.getLength() + MINIMUM_LENGTH + queuesLength;
+    }
+
+    /**
+     * Read the queue message data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    public void readFrom(ChannelBuffer data, int length) {
+        super.readFrom(data, length);
+        portNumber = data.readShort();
+        data.readInt();   // pad
+        data.readShort(); // pad
+
+        int availLength = (length - MINIMUM_LENGTH);
+        this.queues.clear();
+
+        while (availLength > 0) {
+            OFPacketQueue queue = new OFPacketQueue();
+            queue.readFrom(data);
+            queues.add(queue);
+            availLength -= queue.getLength();
+        }
+    }
+
+    /**
+     * Write the queue message data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeInt(0);   // pad
+        data.writeShort(0); // pad
+
+        for (OFPacketQueue queue : queues) {
+            queue.writeTo(data);
+        }
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/BasicFactoryTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/BasicFactoryTest.java
new file mode 100644 (file)
index 0000000..312fcd3
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+*    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;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.action.MockVendorAction;
+import org.openflow.protocol.action.MockVendorActionFactory;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionVendorGeneric;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFVendorActionRegistry;
+import org.openflow.util.U16;
+
+public class BasicFactoryTest extends TestCase {
+
+    public void testCreateAndParse() throws MessageParseException {
+        BasicFactory factory = new BasicFactory();
+        OFMessage m = factory.getMessage(OFType.HELLO);
+        m.setVersion((byte) 1);
+        m.setType(OFType.ECHO_REQUEST);
+        m.setLength(U16.t(8));
+        m.setXid(0xdeadbeef);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        ChannelBuffer bb2 = ChannelBuffers.dynamicBuffer();
+        m.writeTo(bb);
+        bb2.writeBytes(bb, bb.readableBytes()-1);
+        TestCase.assertNull(factory.parseMessage(bb2));
+        bb2.writeByte(bb.readByte());
+        List<OFMessage> message = factory.parseMessage(bb2);
+        TestCase.assertNotNull(message);
+        TestCase.assertEquals(message.size(), 1);
+        TestCase.assertTrue(message.get(0).getType() == OFType.ECHO_REQUEST);
+    }
+
+    public void testInvalidMsgParse() throws MessageParseException {
+        BasicFactory factory = new BasicFactory();
+        OFMessage m = factory.getMessage(OFType.HELLO);
+        m.setVersion((byte) 1);
+        m.setType(OFType.ECHO_REQUEST);
+        m.setLength(U16.t(16));
+        m.setXid(0xdeadbeef);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        m.writeTo(bb);
+        List<OFMessage> message = factory.parseMessage(bb);
+        TestCase.assertNull(message);
+    }
+
+    public void testCurrouptedMsgParse() throws MessageParseException {
+        BasicFactory factory = new BasicFactory();
+        OFMessage m = factory.getMessage(OFType.HELLO);
+        m.setVersion((byte) 1);
+        m.setType(OFType.ERROR);
+        m.setLength(U16.t(8));
+        m.setXid(0xdeadbeef);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        m.writeTo(bb);
+        try {
+                factory.parseMessage(bb);
+        }
+        catch(Exception e) {
+            TestCase.assertEquals(MessageParseException.class, e.getClass());
+        }
+    }
+
+    public void testCustomVendorAction() throws MessageParseException {
+        BasicFactory factory = new BasicFactory();
+        OFVendorActionRegistry.getInstance().register(
+                MockVendorAction.VENDOR_ID, new MockVendorActionFactory());
+
+
+        byte[] deadBeefMessage = {
+            (byte) 0xff, (byte) 0xff,          // action vendor
+            0x00, 0x10,                        // length
+            (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte)0xef,            // deadbeaf
+            0x01, 0x02, 0x03, 0x04,
+            0x05, 0x06, 0x07, 0x08               // pad
+        };
+
+        ChannelBuffer buf = ChannelBuffers.copiedBuffer(deadBeefMessage);
+
+        List<OFAction> actions = factory.parseActions(buf,deadBeefMessage.length);
+        assertEquals(1, actions.size());
+        OFAction ofAction = actions.get(0);
+        assertTrue("Action should be MockVendorAction, but is "+ofAction.getClass(), ofAction instanceof MockVendorAction);
+        assertArrayEquals( new byte[]  { 1,2,3,4,5,6,7,8}, ((MockVendorAction)ofAction).getMockData());
+
+
+    }
+
+    public void testGenericVendorAction() throws MessageParseException {
+        byte[] nonDeadBeefMessage = {
+                (byte) 0xff, (byte) 0xff,          // action vendor
+                0x00, 0x10,                        // length
+                (byte) 0x7e, (byte) 0xe7, (byte) 0xbe, (byte)0xef,            // deadbeaf
+                0x01, 0x02, 0x03, 0x04,
+                0x05, 0x06, 0x07, 0x08               // pad
+            };
+
+        BasicFactory factory = new BasicFactory();
+        OFVendorActionRegistry.getInstance().register(
+                MockVendorAction.VENDOR_ID, new MockVendorActionFactory());
+
+        ChannelBuffer buf = ChannelBuffers.copiedBuffer(nonDeadBeefMessage);
+
+        List<OFAction> actions = factory.parseActions(buf,nonDeadBeefMessage.length);
+        assertEquals(1, actions.size());
+        OFAction ofAction = actions.get(0);
+        assertTrue("Action should be OFActionVendorGeneric, but is "+ofAction.getClass(), ofAction instanceof OFActionVendorGeneric);
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFActionTypeTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFActionTypeTest.java
new file mode 100644 (file)
index 0000000..ed8386c
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+*    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;
+
+
+import org.junit.Test;
+import org.openflow.protocol.action.OFActionType;
+
+import junit.framework.TestCase;
+
+
+public class OFActionTypeTest extends TestCase {
+    @Test
+    public void testMapping() throws Exception {
+        TestCase.assertEquals(OFActionType.OUTPUT,
+                OFActionType.valueOf((short) 0));
+        TestCase.assertEquals(OFActionType.OPAQUE_ENQUEUE,
+                OFActionType.valueOf((short) 11));
+        TestCase.assertEquals(OFActionType.VENDOR,
+                OFActionType.valueOf((short) 0xffff));
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java
new file mode 100644 (file)
index 0000000..7e447bb
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFBarrierReplyTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFBarrierReply msg = (OFBarrierReply) messageFactory
+                .getMessage(OFType.BARRIER_REPLY);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.BARRIER_REPLY, msg.getType());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java
new file mode 100644 (file)
index 0000000..3aa9cb4
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFBarrierRequestTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFBarrierRequest msg = (OFBarrierRequest) messageFactory
+                .getMessage(OFType.BARRIER_REQUEST);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.BARRIER_REQUEST, msg.getType());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFErrorTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFErrorTest.java
new file mode 100644 (file)
index 0000000..45d5257
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+*    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;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.OFError.OFErrorType;
+import org.openflow.protocol.OFError.OFHelloFailedCode;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.util.OFTestCase;
+
+public class OFErrorTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFError msg = (OFError) messageFactory.getMessage(OFType.ERROR);
+        msg.setMessageFactory(messageFactory);
+        msg.setErrorType((short) OFErrorType.OFPET_HELLO_FAILED.getValue());
+        msg.setErrorCode((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE
+                .ordinal());
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.getValue(),
+                msg.getErrorType());
+        TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE
+                .ordinal(), msg.getErrorType());
+        TestCase.assertNull(msg.getOffendingMsg());
+
+        msg.setOffendingMsg(new OFHello());
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.getValue(),
+                msg.getErrorType());
+        TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE
+                .ordinal(), msg.getErrorType());
+        TestCase.assertNotNull(msg.getOffendingMsg());
+        TestCase.assertEquals(OFHello.MINIMUM_LENGTH,
+                msg.getOffendingMsg().length);
+    }
+
+    public void testGarbageAtEnd() throws MessageParseException {
+        // This is a OFError msg (12 bytes), that encaps a OFVendor msg (24
+        // bytes)
+        // AND some zeros at the end (40 bytes) for a total of 76 bytes
+        // THIS is what an NEC sends in reply to Nox's VENDOR request
+        byte[] oferrorRaw = { 0x01, 0x01, 0x00, 0x4c, 0x00, 0x00, 0x10,
+                (byte) 0xcc, 0x00, 0x01, 0x00, 0x01, 0x01, 0x04, 0x00, 0x18,
+                0x00, 0x00, 0x10, (byte) 0xcc, 0x00, 0x00, 0x23, 0x20, 0x00,
+                0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00 };
+        OFMessageFactory factory = new BasicFactory();
+        ChannelBuffer oferrorBuf = 
+                ChannelBuffers.wrappedBuffer(oferrorRaw);
+        List<OFMessage> msg = factory.parseMessage(oferrorBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertEquals(76, msg.get(0).getLengthU());
+        ChannelBuffer out = ChannelBuffers.dynamicBuffer();
+        msg.get(0).writeTo(out);
+        TestCase.assertEquals(76, out.readableBytes());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java
new file mode 100644 (file)
index 0000000..62e491a
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+*    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;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+
+public class OFFeaturesReplyTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFFeaturesReply ofr = (OFFeaturesReply) messageFactory
+                .getMessage(OFType.FEATURES_REPLY);
+        List<OFPhysicalPort> ports = new ArrayList<OFPhysicalPort>();
+        OFPhysicalPort port = new OFPhysicalPort();
+        port.setHardwareAddress(new byte[6]);
+        port.setName("eth0");
+        ports.add(port);
+        ofr.setPorts(ports);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        ofr.writeTo(bb);
+        ofr.readFrom(bb);
+        TestCase.assertEquals(1, ofr.getPorts().size());
+        TestCase.assertEquals("eth0", ofr.getPorts().get(0).getName());
+
+        // test a 15 character name
+        ofr.getPorts().get(0).setName("012345678901234");
+        bb.clear();
+        ofr.writeTo(bb);
+        ofr.readFrom(bb);
+        TestCase.assertEquals("012345678901234", ofr.getPorts().get(0).getName());
+
+        // test a 16 character name getting truncated
+        ofr.getPorts().get(0).setName("0123456789012345");
+        bb.clear();
+        ofr.writeTo(bb);
+        ofr.readFrom(bb);
+        TestCase.assertEquals("012345678901234", ofr.getPorts().get(0).getName());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java
new file mode 100644 (file)
index 0000000..11746e7
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.OFFlowRemoved.OFFlowRemovedReason;
+import org.openflow.util.OFTestCase;
+
+public class OFFlowRemovedTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFFlowRemoved msg = (OFFlowRemoved) messageFactory
+                .getMessage(OFType.FLOW_REMOVED);
+        msg.setMatch(new OFMatch());
+        byte[] hwAddr = new byte[6];
+        msg.getMatch().setDataLayerDestination(hwAddr);
+        msg.getMatch().setDataLayerSource(hwAddr);
+        msg.setReason(OFFlowRemovedReason.OFPRR_DELETE);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.FLOW_REMOVED, msg.getType());
+        TestCase.assertEquals(OFFlowRemovedReason.OFPRR_DELETE, msg.getReason());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java
new file mode 100644 (file)
index 0000000..c1f1f67
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFGetConfigReplyTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFSetConfig msg = (OFSetConfig) messageFactory
+                .getMessage(OFType.SET_CONFIG);
+        msg.setFlags((short) 1);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.SET_CONFIG, msg.getType());
+        TestCase.assertEquals((short)1, msg.getFlags());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java
new file mode 100644 (file)
index 0000000..94d9036
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFGetConfigRequestTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFGetConfigRequest msg = (OFGetConfigRequest) messageFactory
+                .getMessage(OFType.GET_CONFIG_REQUEST);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.GET_CONFIG_REQUEST, msg.getType());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFMatchTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFMatchTest.java
new file mode 100644 (file)
index 0000000..fd7863a
--- /dev/null
@@ -0,0 +1,92 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+public class OFMatchTest extends TestCase {
+    public void testFromString() {
+        OFMatch correct = new OFMatch();
+        OFMatch tester = new OFMatch();
+
+        // Various combinations of "all"/"any"
+        tester.fromString("OFMatch[]");
+        // correct is already wildcarded
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("all");
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("ANY");
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("");
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("[]");
+        TestCase.assertEquals(correct, tester);
+
+        // ip_src
+        correct.setWildcards(~OFMatch.OFPFW_NW_SRC_MASK);
+        correct.setNetworkSource(0x01010203);
+        tester.fromString("nw_src=1.1.2.3");
+        TestCase.assertEquals(correct.getNetworkSourceMaskLen(), tester
+                .getNetworkSourceMaskLen());
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("IP_sRc=1.1.2.3");
+        TestCase.assertEquals(correct.getNetworkSourceMaskLen(), tester
+                .getNetworkSourceMaskLen());
+        TestCase.assertEquals(correct, tester);
+        
+        // 0xVlan
+        correct = new OFMatch();
+        correct.setDataLayerVirtualLan((short)65535);
+        correct.setWildcards(~OFMatch.OFPFW_DL_VLAN);
+        tester = new OFMatch();
+        tester.fromString("dl_vlan=0xffff");
+        TestCase.assertEquals(correct, tester);
+        }
+
+    public void testToString() {
+        OFMatch match = new OFMatch();
+        match.fromString("nw_dst=3.4.5.6/8");
+        TestCase.assertEquals(8, match.getNetworkDestinationMaskLen());
+        String correct = "OFMatch[nw_dst=3.0.0.0/8]";
+        String tester = match.toString();
+
+        TestCase.assertEquals(correct, tester);
+        tester = "OFMatch[dl_type=35020]";
+        correct = "OFMatch[dl_type=0x88cc]";
+        match = new OFMatch();
+        match.fromString(tester);
+        TestCase.assertEquals(correct, match.toString());
+        OFMatch match2 = new OFMatch();
+        match2.fromString(correct);
+        TestCase.assertEquals(match, match2);
+    }
+
+    public void testClone() {
+        OFMatch match1 = new OFMatch();
+        OFMatch match2 = match1.clone();
+        TestCase.assertEquals(match1, match2);
+        match2.setNetworkProtocol((byte) 4);
+        match2.setWildcards(match2.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
+        TestCase.assertNotSame(match1, match2);
+    }
+
+    public void testIpToString() {
+        String test = OFMatch.ipToString(-1);
+        TestCase.assertEquals("255.255.255.255", test);
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java
new file mode 100644 (file)
index 0000000..60a9e73
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+public class OFMessageContextStoreTest extends TestCase {
+    public void testStoreAndGet() {
+        OFMessage msg = new OFMessage();
+        OFMessageContextStore<String> store = new OFMessageContextStore<String>(msg, this.getName());
+        String key = "mykey";
+        String value = "myvalue";
+        store.put(key, value);
+        TestCase.assertEquals(value, store.get(key));
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPacketOutTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPacketOutTest.java
new file mode 100644 (file)
index 0000000..55b5455
--- /dev/null
@@ -0,0 +1,45 @@
+package org.openflow.protocol;
+
+import org.junit.Test;
+
+public class OFPacketOutTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBothBufferIdAndPayloadSet() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(12);
+        packetOut.setPacketData(new byte[] { 1, 2, 3 });
+    }
+
+    @Test
+    public void testOnlyBufferIdSet() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(12);
+        packetOut.setPacketData(null);
+        packetOut.setPacketData(new byte[] {});
+        packetOut.validate();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNeitherBufferIdNorPayloadSet() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+        packetOut.setPacketData(null);
+        packetOut.validate();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNeitherBufferIdNorPayloadSet2() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+        packetOut.setPacketData(new byte[] {});
+        packetOut.validate();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNeitherBufferIdNorPayloadSet3() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.validate();
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPortConfigTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPortConfigTest.java
new file mode 100644 (file)
index 0000000..9b115eb
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFPortConfigTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFPortMod msg = (OFPortMod) messageFactory
+                .getMessage(OFType.PORT_MOD);
+        msg.setHardwareAddress(new byte[6]);
+        msg.portNumber = 1;
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.PORT_MOD, msg.getType());
+        TestCase.assertEquals(1, msg.getPortNumber());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPortStatusTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFPortStatusTest.java
new file mode 100644 (file)
index 0000000..4fab64e
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.OFPortStatus.OFPortReason;
+import org.openflow.util.OFTestCase;
+
+public class OFPortStatusTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFPortStatus msg = (OFPortStatus) messageFactory
+                .getMessage(OFType.PORT_STATUS);
+        msg.setDesc(new OFPhysicalPort());
+        msg.getDesc().setHardwareAddress(new byte[6]);
+        msg.getDesc().setName("eth0");
+        msg.setReason((byte) OFPortReason.OFPPR_ADD.ordinal());
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.PORT_STATUS, msg.getType());
+        TestCase.assertEquals((byte) OFPortReason.OFPPR_ADD.ordinal(), msg
+                .getReason());
+        TestCase.assertNotNull(msg.getDesc());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFSetConfigTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFSetConfigTest.java
new file mode 100644 (file)
index 0000000..2a9e86f
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+*    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;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFSetConfigTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFGetConfigReply msg = (OFGetConfigReply) messageFactory
+                .getMessage(OFType.GET_CONFIG_REPLY);
+        msg.setFlags((short) 1);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.GET_CONFIG_REPLY, msg.getType());
+        TestCase.assertEquals((short)1, msg.getFlags());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java
new file mode 100644 (file)
index 0000000..50bac8f
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+*    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;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.util.OFTestCase;
+
+public class OFStatisticsReplyTest extends OFTestCase {
+    public void testOFFlowStatisticsReply() throws Exception {
+        byte[] packet = new byte[] { 0x01, 0x11, 0x01, 0x2c, 0x00, 0x00, 0x00,
+                0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, (byte) 0xff,
+                (byte) 0xff, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00,
+                0x0a, 0x00, 0x00, 0x03, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, (byte) 0xa6,
+                (byte) 0xa6, 0x00, (byte) 0xff, (byte) 0xff, 0x00, 0x05, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                (byte) 0xc4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00,
+                0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x02, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x08, 0x06,
+                0x00, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x03, 0x0a, 0x00,
+                0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x3b, 0x2f, (byte) 0xfa, 0x40, (byte) 0xff, (byte) 0xff, 0x00,
+                0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+                0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x03, (byte) 0xff, (byte) 0xff, 0x00, 0x62, 0x08,
+                0x00, 0x00, 0x01, 0x62, 0x37, 0x0a, 0x00, 0x00, 0x02, 0x0a,
+                0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x3a, (byte) 0xc5, 0x2a, (byte) 0x80, (byte) 0xff,
+                (byte) 0xff, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xc4, 0x00, 0x00, 0x00,
+                0x08, 0x00, 0x02, 0x00, 0x00 };
+
+        OFMessageFactory factory = new BasicFactory();
+        ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet);
+        List<OFMessage> msg = factory.parseMessage(packetBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertTrue(msg.get(0) instanceof OFStatisticsReply);
+        OFStatisticsReply sr = (OFStatisticsReply) msg.get(0);
+        TestCase.assertEquals(OFStatisticsType.FLOW, sr.getStatisticType());
+        TestCase.assertEquals(3, sr.getStatistics().size());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java
new file mode 100644 (file)
index 0000000..74af6f4
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+*    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;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.protocol.statistics.OFVendorStatistics;
+import org.openflow.util.OFTestCase;
+
+public class OFStatisticsRequestTest extends OFTestCase {
+    public void testOFFlowStatisticsRequest() throws Exception {
+        byte[] packet = new byte[] { 0x01, 0x10, 0x00, 0x38, 0x00, 0x00, 0x00,
+                0x16, 0x00, 0x01, 0x00, 0x00, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                (byte) 0xff, 0x00, (byte) 0xff, (byte) 0xff };
+
+        OFMessageFactory factory = new BasicFactory();
+        ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet);
+        List<OFMessage> msg = factory.parseMessage(packetBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertTrue(msg.get(0) instanceof OFStatisticsRequest);
+        OFStatisticsRequest sr = (OFStatisticsRequest) msg.get(0);
+        TestCase.assertEquals(OFStatisticsType.FLOW, sr.getStatisticType());
+        TestCase.assertEquals(1, sr.getStatistics().size());
+        TestCase.assertTrue(sr.getStatistics().get(0) instanceof OFFlowStatisticsRequest);
+    }
+
+    public void testOFStatisticsRequestVendor() throws Exception {
+        byte[] packet = new byte[] { 0x01, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00,
+                0x63, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x4c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x01, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20,
+                (byte) 0xe0, 0x00, 0x11, 0x00, 0x0c, 0x29, (byte) 0xc5,
+                (byte) 0x95, 0x57, 0x02, 0x25, 0x5c, (byte) 0xca, 0x00, 0x02,
+                (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x50, 0x04,
+                0x00, 0x00, 0x00, 0x00, (byte) 0xff, 0x00, 0x00, 0x00,
+                (byte) 0xff, (byte) 0xff, 0x4e, 0x20 };
+
+        OFMessageFactory factory = new BasicFactory();
+        ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet);
+        List<OFMessage> msg = factory.parseMessage(packetBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertTrue(msg.get(0) instanceof OFStatisticsRequest);
+        OFStatisticsRequest sr = (OFStatisticsRequest) msg.get(0);
+        TestCase.assertEquals(OFStatisticsType.VENDOR, sr.getStatisticType());
+        TestCase.assertEquals(1, sr.getStatistics().size());
+        TestCase.assertTrue(sr.getStatistics().get(0) instanceof OFVendorStatistics);
+        TestCase.assertEquals(68, ((OFVendorStatistics)sr.getStatistics().get(0)).getLength());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java
new file mode 100644 (file)
index 0000000..d44ef7f
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+*    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;
+
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.openflow.protocol.statistics.OFStatisticsType;
+
+
+public class OFStatisticsTypeTest extends TestCase {
+    @Test
+    public void testMapping() throws Exception {
+        TestCase.assertEquals(OFStatisticsType.DESC,
+                OFStatisticsType.valueOf((short) 0, OFType.STATS_REQUEST));
+        TestCase.assertEquals(OFStatisticsType.QUEUE,
+                OFStatisticsType.valueOf((short) 5, OFType.STATS_REQUEST));
+        TestCase.assertEquals(OFStatisticsType.VENDOR,
+                OFStatisticsType.valueOf((short) 0xffff, OFType.STATS_REQUEST));
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFTypeTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFTypeTest.java
new file mode 100644 (file)
index 0000000..c6bf0a3
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+*    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;
+
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+
+public class OFTypeTest extends TestCase {
+
+    public void testOFTypeCreate() throws Exception {
+        OFType foo = OFType.HELLO;
+        Class<? extends OFMessage> c = foo.toClass();
+        TestCase.assertEquals(c, OFHello.class);
+    }
+
+    @Test
+    public void testMapping() throws Exception {
+        TestCase.assertEquals(OFType.HELLO, OFType.valueOf((byte) 0));
+        TestCase.assertEquals(OFType.BARRIER_REPLY, OFType.valueOf((byte) 19));
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFVendorTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/OFVendorTest.java
new file mode 100644 (file)
index 0000000..b85a915
--- /dev/null
@@ -0,0 +1,215 @@
+/**
+*    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;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.vendor.OFByteArrayVendorData;
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorData;
+import org.openflow.protocol.vendor.OFVendorId;
+import org.openflow.util.OFTestCase;
+
+public class OFVendorTest extends OFTestCase {
+
+    public static int ACME_VENDOR_ID = 0x00112233;
+    
+    static class AcmeVendorData implements OFVendorData {
+        protected int dataType;
+        
+        public int getLength() {
+            return 4;
+        }
+        
+        public void readFrom(ChannelBuffer data, int length) {
+            dataType = data.readInt();
+        }
+        
+        public void writeTo(ChannelBuffer data) {
+            data.writeInt(dataType);
+        }
+    }
+    
+    static class AcmeVendorData1 extends AcmeVendorData {
+        public short flags;
+        public short value;
+        
+        public static int DATA_TYPE = 1;
+        
+        public AcmeVendorData1() {
+        }
+        
+        public AcmeVendorData1(short flags, short value) {
+            this.dataType = DATA_TYPE;
+            this.flags = flags;
+            this.value = value;
+        }
+        
+        public short getFlags() {
+            return flags;
+        }
+        
+        public short getValue() {
+            return value;
+        }
+        
+        public int getLength() {
+            return 8;
+        }
+        
+        public void readFrom(ChannelBuffer data, int length) {
+            super.readFrom(data, length);
+            flags = data.readShort();
+            value = data.readShort();
+
+        }
+        public void writeTo(ChannelBuffer data) {
+            super.writeTo(data);
+            data.writeShort(flags);
+            data.writeShort(value);
+        }
+        
+        public static Instantiable<OFVendorData> getInstantiable() {
+            return new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new AcmeVendorData1();
+                }
+            };
+        }
+    }
+    
+    static class AcmeVendorData2 extends AcmeVendorData {
+        public int type;
+        public int subtype;
+
+        public static int DATA_TYPE = 2;
+
+        public AcmeVendorData2() {
+        }
+        
+        public AcmeVendorData2(int type, int subtype) {
+            this.dataType = DATA_TYPE;
+            this.type = type;
+            this.subtype = subtype;
+        }
+        
+        public int getType() {
+            return type;
+        }
+        
+        public int getSubtype() {
+            return subtype;
+        }
+        
+        public int getLength() {
+            return 12;
+        }
+        
+        public void readFrom(ChannelBuffer data, int length) {
+            super.readFrom(data, length);
+            type = data.readShort();
+            subtype = data.readShort();
+
+        }
+        public void writeTo(ChannelBuffer data) {
+            super.writeTo(data);
+            data.writeShort(type);
+            data.writeShort(subtype);
+        }
+        
+        public static Instantiable<OFVendorData> getInstantiable() {
+            return new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new AcmeVendorData2();
+                }
+            };
+        }
+    }
+    
+    {
+        OFBasicVendorId acmeVendorId = new OFBasicVendorId(ACME_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(acmeVendorId);
+        OFBasicVendorDataType acmeVendorData1 = new OFBasicVendorDataType(
+            AcmeVendorData1.DATA_TYPE, AcmeVendorData1.getInstantiable());
+        acmeVendorId.registerVendorDataType(acmeVendorData1);
+        OFBasicVendorDataType acmeVendorData2 = new OFBasicVendorDataType(
+            AcmeVendorData2.DATA_TYPE, AcmeVendorData2.getInstantiable());
+        acmeVendorId.registerVendorDataType(acmeVendorData2);
+    }
+    
+    private OFVendor makeVendorMessage(int vendor) {
+        OFVendor msg = (OFVendor) messageFactory.getMessage(OFType.VENDOR);
+        msg.setVendorDataFactory(new BasicFactory());
+        msg.setVendor(vendor);
+        return msg;
+    }
+    
+    public void testWriteRead() throws Exception {
+        OFVendor msg = makeVendorMessage(1);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(1, msg.getVendor());
+    }
+    
+    public void testVendorData() throws Exception {
+        OFVendor msg = makeVendorMessage(ACME_VENDOR_ID);
+        OFVendorData vendorData = new AcmeVendorData1((short)11, (short)22);
+        msg.setVendorData(vendorData);
+        msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength());
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        assertEquals(ACME_VENDOR_ID, msg.getVendor());
+        AcmeVendorData1 vendorData1 = (AcmeVendorData1) msg.getVendorData();
+        assertEquals(11, vendorData1.getFlags());
+        assertEquals(22, vendorData1.getValue());
+        
+        vendorData = new AcmeVendorData2(33, 44);
+        msg.setVendorData(vendorData);
+        msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength());
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        assertEquals(ACME_VENDOR_ID, msg.getVendor());
+        AcmeVendorData2 vendorData2 = (AcmeVendorData2) msg.getVendorData();
+        assertEquals(33, vendorData2.getType());
+        assertEquals(44, vendorData2.getSubtype());
+        
+        final int DUMMY_VENDOR_ID = 55;
+        msg.setVendor(DUMMY_VENDOR_ID);
+        byte[] genericVendorDataBytes = new byte[] {0x55, 0x66};
+        vendorData = new OFByteArrayVendorData(genericVendorDataBytes);
+        msg.setVendorData(vendorData);
+        msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength());
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        assertEquals(DUMMY_VENDOR_ID, msg.getVendor());
+        OFByteArrayVendorData genericVendorData = (OFByteArrayVendorData) msg.getVendorData();
+        assertTrue(Arrays.equals(genericVendorDataBytes, genericVendorData.getBytes()));
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/WildcardsTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/WildcardsTest.java
new file mode 100644 (file)
index 0000000..5bf8d12
--- /dev/null
@@ -0,0 +1,162 @@
+package org.openflow.protocol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+
+import org.junit.Test;
+import org.openflow.protocol.Wildcards.Flag;
+
+public class WildcardsTest {
+
+    @Test
+    public void testBasic() {
+        int[] intMasks = { 0, 0x3820e0, OFMatch.OFPFW_ALL_SANITIZED };
+        for (int i : intMasks) {
+            Wildcards w = Wildcards.of(i);
+            assertEquals(i, w.getInt());
+        }
+    }
+
+    @Test
+    public void testAllSanitize() {
+        Wildcards w = Wildcards.of(OFMatch.OFPFW_ALL);
+        assertEquals(OFMatch.OFPFW_ALL_SANITIZED, w.getInt());
+        assertTrue(w.isFull());
+        assertFalse(w.isExact());
+    }
+
+    @Test
+    public void testAll() {
+        Wildcards all = Wildcards.FULL;
+        assertTrue(all.isFull());
+        assertFalse(all.isExact());
+        assertEquals(0, all.getNwDstMask());
+        assertEquals(0, all.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards stillAll = all.wildcard(Flag.IN_PORT);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+
+        // so is setting a >= 32 netmask
+
+        stillAll = all.withNwSrcMask(0);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+
+        stillAll = all.withNwDstMask(0);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+    }
+
+    @Test
+    public void testNone() {
+        Wildcards none = Wildcards.EXACT;
+        assertTrue(none.isExact());
+        assertEquals(32, none.getNwDstMask());
+        assertEquals(32, none.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards stillNone = none.matchOn(Flag.IN_PORT);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+
+        // so is setting a >= 32 netmask
+        stillNone = none.withNwSrcMask(32);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+
+        stillNone = none.withNwDstMask(32);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+    }
+
+    @Test
+    public void testSetOneFlag() {
+        Wildcards none = Wildcards.EXACT;
+        assertTrue(none.isExact());
+        assertFalse(none.isWildcarded(Flag.DL_SRC));
+        Wildcards one = none.wildcard(Flag.DL_SRC);
+        assertFalse(one.isExact());
+        assertTrue(one.isWildcarded(Flag.DL_SRC));
+        assertEquals(OFMatch.OFPFW_DL_SRC, one.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC), one.getWildcardedFlags());
+    }
+
+    @Test
+    public void testSetTwoFlags() {
+        Wildcards none = Wildcards.EXACT;
+
+        // set two flags
+        Wildcards two = none.wildcard(Flag.DL_SRC, Flag.DL_DST);
+        assertFalse(two.isExact());
+        assertTrue(two.isWildcarded(Flag.DL_SRC));
+        assertTrue(two.isWildcarded(Flag.DL_DST));
+        assertEquals(OFMatch.OFPFW_DL_SRC | OFMatch.OFPFW_DL_DST, two.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC, Flag.DL_DST), two.getWildcardedFlags());
+
+        // unset dl_dst
+        Wildcards gone = two.matchOn(Flag.DL_DST);
+        assertFalse(gone.isExact());
+        assertTrue(gone.isWildcarded(Flag.DL_SRC));
+        assertFalse(gone.isWildcarded(Flag.DL_DST));
+        assertEquals(OFMatch.OFPFW_DL_SRC, gone.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC), gone.getWildcardedFlags());
+    }
+
+    @Test
+    public void testSetNwSrc() {
+        Wildcards none = Wildcards.EXACT;
+        assertEquals(32, none.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards nwSet = none.withNwSrcMask(8);
+        assertFalse(nwSet.isExact());
+        assertEquals(EnumSet.noneOf(Flag.class), nwSet.getWildcardedFlags());
+        assertEquals(8, nwSet.getNwSrcMask());
+        assertEquals((32 - 8) << OFMatch.OFPFW_NW_SRC_SHIFT, nwSet.getInt());
+    }
+
+    @Test
+    public void testSetNwDst() {
+        Wildcards none = Wildcards.EXACT;
+        assertEquals(32, none.getNwDstMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards nwSet = none.withNwDstMask(8);
+        assertFalse(nwSet.isExact());
+        assertEquals(EnumSet.noneOf(Flag.class), nwSet.getWildcardedFlags());
+        assertEquals(8, nwSet.getNwDstMask());
+        assertEquals((32 - 8) << OFMatch.OFPFW_NW_DST_SHIFT, nwSet.getInt());
+    }
+
+    @Test
+    public void testToString() {
+        String s = Wildcards.FULL.toString();
+        assertNotNull(s);
+        assertTrue(s.length() > 0);
+    }
+
+    @Test
+    public void testInvert() {
+        assertEquals(Wildcards.FULL, Wildcards.EXACT.inverted());
+
+        Wildcards some = Wildcards.of(Flag.DL_VLAN, Flag.DL_VLAN_PCP);
+        Wildcards inv = some.inverted();
+
+        for(Flag f : Flag.values()) {
+            boolean shouldBeSet = (f == Flag.DL_VLAN || f == Flag.DL_VLAN_PCP);
+
+            assertEquals("Flag " + f + " "
+                         + (shouldBeSet ? "should be set " : "should not be set"),
+                    shouldBeSet, some.isWildcarded(f));
+            assertEquals(!(f == Flag.DL_VLAN || f == Flag.DL_VLAN_PCP), inv.isWildcarded(f));
+        }
+        assertEquals(0, inv.getNwDstMask());
+        assertEquals(0, inv.getNwSrcMask());
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/MockVendorAction.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/MockVendorAction.java
new file mode 100644 (file)
index 0000000..49b69fb
--- /dev/null
@@ -0,0 +1,41 @@
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+
+public class MockVendorAction extends OFActionVendor {
+    public static final int VENDOR_ID = 0xdeadbeef;
+
+    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    private byte[] mockData;
+
+    public byte[] getMockData() {
+        return mockData;
+    }
+
+    public void setMockData(byte[] mockData) {
+        this.mockData = mockData;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+
+        int dataLength = getLength() - MINIMUM_LENGTH;
+        if(dataLength > 0) {
+            mockData = new byte[dataLength];
+            data.readBytes(mockData);
+        } else {
+            mockData = EMPTY_BYTE_ARRAY;
+        }
+
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeBytes(mockData);
+    }
+
+
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java
new file mode 100644 (file)
index 0000000..bbc254c
--- /dev/null
@@ -0,0 +1,15 @@
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.factory.OFVendorActionFactory;
+
+public class MockVendorActionFactory implements OFVendorActionFactory {
+
+    @Override
+    public OFActionVendor readFrom(ChannelBuffer data) {
+        MockVendorAction action = new MockVendorAction();
+        action.readFrom(data);
+        return action;
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java
new file mode 100644 (file)
index 0000000..31ad675
--- /dev/null
@@ -0,0 +1,17 @@
+package org.openflow.protocol.action;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.openflow.protocol.factory.OFVendorActionRegistry;
+
+public class OFVendorActionRegistryTest {
+
+    @Test
+    public void test() {
+        MockVendorActionFactory factory = new MockVendorActionFactory();
+        OFVendorActionRegistry.getInstance().register(MockVendorAction.VENDOR_ID, factory);
+        assertEquals(factory, OFVendorActionRegistry.getInstance().get(MockVendorAction.VENDOR_ID));
+    }
+
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/util/HexStringTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/util/HexStringTest.java
new file mode 100644 (file)
index 0000000..a8f8ba4
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+*    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.util;
+
+import org.junit.Test;
+
+import junit.framework.TestCase;
+
+/**
+ * Does hexstring conversion work?
+ * 
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ * 
+ */
+
+public class HexStringTest extends TestCase {
+    
+    @Test
+    public void testMarshalling() throws Exception {
+        String dpidStr = "00:00:00:23:20:2d:16:71";
+        long dpid = HexString.toLong(dpidStr);
+        String testStr = HexString.toHexString(dpid);
+        TestCase.assertEquals(dpidStr, testStr);
+    }
+    
+    @Test
+    public void testToLong() {
+        String dpidStr = "3e:1f:01:fc:72:8c:63:31";
+        long valid = 0x3e1f01fc728c6331L;
+        long testLong = HexString.toLong(dpidStr);
+        TestCase.assertEquals(valid, testLong);
+    }
+    
+    @Test
+    public void testToLongMSB() {
+        String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
+        long valid = -3856102927509056101L;
+        long testLong = HexString.toLong(dpidStr);
+        TestCase.assertEquals(valid, testLong);
+    }
+    
+    @Test
+    public void testToLongError() {
+        String dpidStr = "09:08:07:06:05:04:03:02:01";
+        try {
+            HexString.toLong(dpidStr);
+            fail("HexString.toLong() should have thrown a NumberFormatException");
+        }
+        catch (NumberFormatException expected) {
+            // do nothing
+        }
+    }
+
+    @Test
+    public void testToStringBytes() {
+        byte[] dpid = { 0, 0, 0, 0, 0, 0, 0, -1 };
+        String valid = "00:00:00:00:00:00:00:ff";
+        String testString = HexString.toHexString(dpid);
+        TestCase.assertEquals(valid, testString);
+    }
+    
+    @Test
+    public void testFromHexStringError() {
+        String invalidStr = "00:00:00:00:00:00:ffff";
+        try {
+            HexString.fromHexString(invalidStr);
+            fail("HexString.fromHexString() should have thrown a NumberFormatException");
+        }
+        catch (NumberFormatException expected) {
+            // do nothing
+        }
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/util/OFTestCase.java b/third-party/openflowj_netty/src/test/java/org/openflow/util/OFTestCase.java
new file mode 100644 (file)
index 0000000..5132c2c
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+*    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.util;
+
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+
+import junit.framework.TestCase;
+
+public class OFTestCase extends TestCase {
+    public OFMessageFactory messageFactory;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        messageFactory = new BasicFactory();
+    }
+
+    public void test() throws Exception {
+    }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/util/U16Test.java b/third-party/openflowj_netty/src/test/java/org/openflow/util/U16Test.java
new file mode 100644 (file)
index 0000000..ba87e7b
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+*    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.util;
+
+import junit.framework.TestCase;
+
+public class U16Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of a short
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      int val = 0xffff;
+      TestCase.assertEquals((short)-1, U16.t(val));
+      TestCase.assertEquals((short)32767, U16.t(0x7fff));
+      TestCase.assertEquals(val, U16.f((short)-1));
+  }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/util/U32Test.java b/third-party/openflowj_netty/src/test/java/org/openflow/util/U32Test.java
new file mode 100644 (file)
index 0000000..223c103
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+*    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.util;
+
+import junit.framework.TestCase;
+
+public class U32Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of an int
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      long val = 0xffffffffL;
+      TestCase.assertEquals(-1, U32.t(val));
+      TestCase.assertEquals(val, U32.f(-1));
+  }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/util/U64Test.java b/third-party/openflowj_netty/src/test/java/org/openflow/util/U64Test.java
new file mode 100644 (file)
index 0000000..0a97e30
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+*    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.util;
+
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+
+public class U64Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of a long
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      BigInteger val = new BigInteger("ffffffffffffffff", 16);
+      TestCase.assertEquals(-1, U64.t(val));
+      TestCase.assertEquals(val, U64.f(-1));
+  }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/util/U8Test.java b/third-party/openflowj_netty/src/test/java/org/openflow/util/U8Test.java
new file mode 100644 (file)
index 0000000..2c06c4d
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+*    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.util;
+
+import junit.framework.TestCase;
+
+public class U8Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of a byte
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      short val = 0xff;
+      TestCase.assertEquals(-1, U8.t(val));
+      TestCase.assertEquals(val, U8.f((byte)-1));
+  }
+}
diff --git a/third-party/openflowj_netty/src/test/java/org/openflow/util/UnsignedTest.java b/third-party/openflowj_netty/src/test/java/org/openflow/util/UnsignedTest.java
new file mode 100644 (file)
index 0000000..7cdf739
--- /dev/null
@@ -0,0 +1,83 @@
+/**
+*    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.util;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+import junit.framework.TestCase;
+
+public class UnsignedTest extends TestCase {
+    public static String ULONG_MAX = "18446744073709551615";
+
+  /**
+   * Tests that we correctly extract an unsigned long into a BigInteger
+   * @throws Exception
+   */
+  public void testGetUnsignedLong() throws Exception {
+    ByteBuffer bb = ByteBuffer.allocate(8);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.position(0);
+    bb.limit(8);
+    BigInteger bi = Unsigned.getUnsignedLong(bb);
+    BigInteger uLongMax = new BigInteger(ULONG_MAX);
+    for (int i = 0; i < uLongMax.bitCount(); ++i) {
+        TestCase.assertTrue("Bit: " + i + " should be: " + uLongMax.testBit(i),
+                uLongMax.testBit(i) == bi.testBit(i));
+    }
+    TestCase.assertEquals(ULONG_MAX, bi.toString());
+
+    bb = ByteBuffer.allocate(10);
+    bb.put((byte)0x00);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.put((byte)0x00);
+    bb.position(0);
+    bb.limit(10);
+    bi = Unsigned.getUnsignedLong(bb, 1);
+    uLongMax = new BigInteger(ULONG_MAX);
+    for (int i = 0; i < uLongMax.bitCount(); ++i) {
+        TestCase.assertTrue("Bit: " + i + " should be: " + uLongMax.testBit(i),
+                uLongMax.testBit(i) == bi.testBit(i));
+    }
+    TestCase.assertEquals(ULONG_MAX, bi.toString());
+  }
+
+  /**
+   * Tests that we correctly put an unsigned long into a ByteBuffer
+   * @throws Exception
+   */
+  public void testPutUnsignedLong() throws Exception {
+    ByteBuffer bb = ByteBuffer.allocate(8);
+    BigInteger uLongMax = new BigInteger(ULONG_MAX);
+    Unsigned.putUnsignedLong(bb, uLongMax);
+    for (int i = 0; i < 8; ++i) {
+        TestCase.assertTrue("Byte: " + i + " should be 0xff, was: " + bb.get(i),
+                (bb.get(i) & (short)0xff) == 0xff);
+    }
+
+    bb = ByteBuffer.allocate(10);
+    Unsigned.putUnsignedLong(bb, uLongMax, 1);
+    int offset = 1;
+    for (int i = 0; i < 8; ++i) {
+        TestCase.assertTrue("Byte: " + i + " should be 0xff, was: " +
+                bb.get(offset+i), (bb.get(offset+i) & (short)0xff) == 0xff);
+    }
+  }
+}