ONOS-5449 Implemented skeleton of OFAgent application

Change-Id: Ie6c719872549a004471e466a43a2b531bc48b231
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgent.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgent.java
new file mode 100644
index 0000000..b44f48e
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgent.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.api;
+
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.onosproject.incubator.net.virtual.NetworkId;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Representation of an OF agent, which brokers virtual devices and external
+ * controllers by handling OpenFlow connections and messages between them.
+ */
+public interface OFAgent {
+
+    /**
+     * Returns the identifier of the virtual network that this agent cares for.
+     *
+     * @return id of the virtual network
+     */
+    NetworkId networkId();
+
+    /**
+     * Returns the external OpenFlow controllers of the virtual network.
+     *
+     * @return set of openflow controllers
+     */
+    Set<OFController> controllers();
+
+    /**
+     * Starts the OpenFlow agent.
+     */
+    void start();
+
+    /**
+     * Stops the OpenFlow agent.
+     */
+    void stop();
+
+    /**
+     * Builder of OF agent entities.
+     */
+    interface Builder {
+
+        /**
+         * Returns new OF agent.
+         *
+         * @return of agent
+         */
+        OFAgent build();
+
+        /**
+         * Returns OF agent builder with the supplied network ID.
+         *
+         * @param networkId id of the virtual network
+         * @return of agent builder
+         */
+        Builder networkId(NetworkId networkId);
+
+        /**
+         * Returns OF agent builder with the supplied network services for the
+         * virtual network.
+         *
+         * @param services network services for the virtual network
+         * @return of agent builder
+         */
+        Builder services(Map<Class<?>, Object> services);
+
+        /**
+         * Returns OF agent builder with the supplied controllers.
+         *
+         * @param controllers set of openflow controllers
+         * @return of agent builder
+         */
+        Builder controllers(Set<OFController> controllers);
+
+        /**
+         * Returns OF agent builder with the supplied event executor.
+         *
+         * @param eventExecutor event executor
+         * @return of agent builder
+         */
+        Builder eventExecutor(ExecutorService eventExecutor);
+
+        /**
+         * Returns OF agent builder with the supplied IO work group.
+         *
+         * @param ioWorker io worker group
+         * @return of agent builder
+         */
+        Builder ioWorker(NioEventLoopGroup ioWorker);
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgentService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgentService.java
new file mode 100644
index 0000000..c2b5e47
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgentService.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.api;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+
+import java.util.Set;
+
+/**
+ * Service for administering OF agents for a virtual network.
+ */
+public interface OFAgentService {
+
+    /**
+     * Returns the OpenFlow agent list.
+     *
+     * @return set of openflow agents
+     */
+    Set<OFAgent> agents();
+
+    /**
+     * Creates an OpenFlow agent for a given virtual network with given controllers.
+     *
+     * @param networkId   id of the virtual network
+     * @param controllers list of controllers
+     */
+    void createAgent(NetworkId networkId, OFController... controllers);
+
+    /**
+     * Removes the OpenFlow agent for the given virtual network.
+     *
+     * @param networkId virtual network identifier
+     */
+    void removeAgent(NetworkId networkId);
+
+    /**
+     * Starts the agent for the given network.
+     *
+     * @param networkId virtual network identifier
+     */
+    void startAgent(NetworkId networkId);
+
+    /**
+     * Stops the agent for the given network.
+     *
+     * @param networkId virtual network identifier
+     */
+    void stopAgent(NetworkId networkId);
+
+    /**
+     * Returns if the agent of the given network is active or not.
+     *
+     * @param networkId network id
+     * @return true if the agent is active
+     */
+    boolean isActive(NetworkId networkId);
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFController.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFController.java
new file mode 100644
index 0000000..fc81b03
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.api;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+
+/**
+ * Representation of an OF controller.
+ */
+public interface OFController {
+
+    /**
+     * Returns the IP address of the controller.
+     *
+     * @return ip address
+     */
+    IpAddress ip();
+
+    /**
+     * Returns the port number for OpenFlow channel connection.
+     *
+     * @return port number
+     */
+    TpPort port();
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFControllerRoleService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFControllerRoleService.java
new file mode 100644
index 0000000..1a98618
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFControllerRoleService.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.api;
+
+import io.netty.channel.Channel;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+
+import java.util.Set;
+
+/**
+ * Service for administering the OF role of multiple controllers.
+ */
+public interface OFControllerRoleService {
+
+    /**
+     * Adds a new controller channel.
+     * EQUAL role is set by default.
+     *
+     * @param channel openflow channel
+     */
+    void addControllerChannel(Channel channel);
+
+    /**
+     * Deletes the controller channel.
+     *
+     * @param channel openflow channel
+     */
+    void deleteControllerChannel(Channel channel);
+
+    /**
+     * Returns controller channels.
+     *
+     * @return set of controller channels
+     */
+    Set<Channel> controllerChannels();
+
+    /**
+     * Sets a role of the controller with a given channel.
+     *
+     * @param channel openflow channel
+     * @param role    role of the controller
+     */
+    void setRole(Channel channel, OFControllerRole role);
+
+    /**
+     * Returns a role of the controller with a given channel.
+     *
+     * @param channel openflow channel
+     * @return role of the controller
+     */
+    OFControllerRole role(Channel channel);
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitch.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitch.java
new file mode 100644
index 0000000..0252049
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitch.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.api;
+
+import org.onosproject.net.Device;
+
+/**
+ * Representation of virtual OpenFlow switch.
+ */
+public interface OFSwitch extends OFSwitchService, OFControllerRoleService {
+
+    /**
+     * Returns the device information.
+     *
+     * @return virtual device
+     */
+    Device device();
+
+    /**
+     * Returns the capabilities of the switch.
+     *
+     * @return capabilities
+     */
+    OFSwitchCapabilities capabilities();
+
+    /**
+     * Returns if the switch is connected to controllers or not.
+     *
+     * @return true if the switch is connected, false otherwise
+     */
+    boolean isConnected();
+
+    // TODO add builder interface
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchCapabilities.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchCapabilities.java
new file mode 100644
index 0000000..a385e8b
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchCapabilities.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.api;
+
+/**
+ * Representation of capabilities of a virtual OpenFlow switch.
+ */
+public interface OFSwitchCapabilities {
+
+    // TODO implement
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
new file mode 100644
index 0000000..de925b5
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.api;
+
+import io.netty.channel.Channel;
+import org.onosproject.net.Port;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.packet.InboundPacket;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+/**
+ * Service providing OpenFlow switch operations.
+ */
+public interface OFSwitchService {
+
+    /**
+     * Handles the switch starts.
+     */
+    void started();
+
+    /**
+     * Handles the switch stops.
+     */
+    void stopped();
+
+    /**
+     * Processes a new port of the switch.
+     * It sends out FEATURE_REPLY message to the controllers.
+     *
+     * @param port virtual port
+     */
+    void processPortAdded(Port port);
+
+    /**
+     * Processes port link down.
+     * It sends out PORT_STATUS asynchronous message to the controllers.
+     *
+     * @param port virtual port
+     */
+    void processPortDown(Port port);
+
+    /**
+     * Processes port link down.
+     * It sends out PORT_STATUS asynchronous message to the controllers.
+     *
+     * @param port virtual port
+     */
+    void processPortUp(Port port);
+
+    /**
+     * Processes flow removed.
+     * It sends out FLOW_REMOVED asynchronous message to the controllers.
+     *
+     * @param flowRule removed flow rule
+     */
+    void processFlowRemoved(FlowRule flowRule);
+
+    /**
+     * Processes packet in.
+     * It sends out PACKET_IN asynchronous message to the controllers.
+     *
+     * @param packet inbound packet
+     */
+    void processPacketIn(InboundPacket packet);
+
+    /**
+     * Processes commands from the controllers that modify the state of the switch.
+     * Possible message types include PACKET_OUT, FLOW_MOD, GROUP_MOD,
+     * PORT_MOD, TABLE_MOD. These types of messages can be denied based on a
+     * role of the request controller.
+     *
+     * @param channel received channel
+     * @param msg     command message received
+     */
+    void processControllerCommand(Channel channel, OFMessage msg);
+
+    /**
+     * Processes a stats request from the controllers.
+     * Targeted message type is MULTIPART_REQUEST with FLOW, PORT, GROUP,
+     * GROUP_DESC subtypes.
+     *
+     * @param channel received channel
+     * @param msg     stats request message received
+     */
+    void processStatsRequest(Channel channel, OFMessage msg);
+
+    /**
+     * Processes a role request from the controllers.
+     * Targeted message type is ROLE_REQUEST.
+     *
+     * @param channel received channel
+     * @param msg     role request message received
+     */
+    void processRoleRequest(Channel channel, OFMessage msg);
+
+    /**
+     * Processes a features request from the controllers.
+     *
+     * @param channel received channel
+     * @param msg     received features request
+     */
+    void processFeaturesRequest(Channel channel, OFMessage msg);
+
+    /**
+     * Processes LLDP packets from the controller.
+     *
+     * @param channel received channel
+     * @param msg     packet out message with lldp
+     */
+    void processLldp(Channel channel, OFMessage msg);
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/package-info.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/package-info.java
new file mode 100644
index 0000000..128bc7a
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * OpenFlow agent API definitions.
+ */
+package org.onosproject.ofagent.api;
\ No newline at end of file
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFAgent.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFAgent.java
new file mode 100644
index 0000000..6a6ba06
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFAgent.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleListener;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFController;
+import org.onosproject.ofagent.api.OFSwitch;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Implementation of OF agent.
+ */
+public final class DefaultOFAgent implements OFAgent {
+
+    private final NetworkId networkId;
+    private final Map<Class<?>, Object> services;
+    private final Set<OFController> controllers;
+    private final ExecutorService eventExecutor;
+    private final NioEventLoopGroup ioWorker;
+
+    private final ConcurrentHashMap<DeviceId, OFSwitch> switchMap = new ConcurrentHashMap<>();
+    private final DeviceListener deviceListener = new InternalDeviceListener();
+    private final FlowRuleListener flowRuleListener = new InternalFlowRuleListener();
+    private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+
+    private DefaultOFAgent(NetworkId networkId,
+                           Map<Class<?>, Object> services,
+                           Set<OFController> controllers,
+                           ExecutorService eventExecutor,
+                           NioEventLoopGroup ioWorker) {
+        this.networkId = networkId;
+        this.services = services;
+        this.controllers = controllers;
+        this.eventExecutor = eventExecutor;
+        this.ioWorker = ioWorker;
+    }
+
+    @Override
+    public NetworkId networkId() {
+        return null;
+    }
+
+    @Override
+    public Set<OFController> controllers() {
+        return null;
+    }
+
+    @Override
+    public void start() {
+        // TODO add listeners to the services
+        // TODO connect all virtual devices in this network to the controllers
+    }
+
+    @Override
+    public void stop() {
+        // TODO remove listeners from the services
+        // TODO disconnect all active connections
+    }
+
+    private void connect(OFSwitch ofSwitch, OFController controller) {
+        // TODO connect the switch to the controller
+    }
+
+    private void disconnect(OFSwitch ofSwitch, OFController controller) {
+        // TODO disconnect the controller from the ofSwitch
+    }
+
+    private class InternalFlowRuleListener implements FlowRuleListener {
+
+        @Override
+        public void event(FlowRuleEvent event) {
+            // TODO handle flow rule event
+        }
+    }
+
+    private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public void event(DeviceEvent event) {
+            // TODO handle device event
+            // device detected: connect the device to controllers
+            // device removed: disconnect and remove the switch from the map
+            // device state available: connect the switch to the controllers
+            // device state unavailable: disconnect the switch from the controllers
+            // port added: send out features reply
+            // port status change
+        }
+    }
+
+    private class InternalPacketProcessor implements PacketProcessor {
+
+        @Override
+        public void process(PacketContext context) {
+            // TODO handle packet-in
+        }
+    }
+
+    // TODO implement builder
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
new file mode 100644
index 0000000..01068c9
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.channel.Channel;
+import org.onosproject.net.Device;
+import org.onosproject.net.Port;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.ofagent.api.OFSwitch;
+import org.onosproject.ofagent.api.OFSwitchCapabilities;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.projectfloodlight.openflow.protocol.OFControllerRole.*;
+
+/**
+ * Implementation of OF switch.
+ */
+public final class DefaultOFSwitch implements OFSwitch {
+
+    private static final String ERR_CH_DUPLICATE = "Channel already exists: ";
+    private static final String ERR_CH_NOT_FOUND = "Channel not found: ";
+
+    private final Device device;
+    private final OFSwitchCapabilities capabilities;
+
+    private final ConcurrentHashMap<Channel, OFControllerRole> controllerRoleMap
+            = new ConcurrentHashMap<>();
+
+    private DefaultOFSwitch(Device device, OFSwitchCapabilities capabilities) {
+        this.device = device;
+        this.capabilities = capabilities;
+    }
+
+    // TODO add builder
+
+    @Override
+    public Device device() {
+        return null;
+    }
+
+    @Override
+    public OFSwitchCapabilities capabilities() {
+        return null;
+    }
+
+    @Override
+    public boolean isConnected() {
+        return false;
+    }
+
+    @Override
+    public void started() {
+        // TODO do some initial setups
+    }
+
+    @Override
+    public void stopped() {
+        // TODO implement
+    }
+
+    @Override
+    public void addControllerChannel(Channel channel) {
+        controllerRoleMap.compute(channel, (ch, existing) -> {
+            final String error = ERR_CH_DUPLICATE + channel.remoteAddress();
+            checkArgument(existing == null, error);
+            return ROLE_EQUAL;
+        });
+    }
+
+    @Override
+    public void deleteControllerChannel(Channel channel) {
+        if (controllerRoleMap.remove(channel) == null) {
+            final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
+            throw new IllegalStateException(error);
+        }
+    }
+
+    @Override
+    public void setRole(Channel channel, OFControllerRole role) {
+        controllerRoleMap.compute(channel, (ch, existing) -> {
+            final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
+            checkNotNull(existing, error);
+            return role;
+        });
+    }
+
+    @Override
+    public OFControllerRole role(Channel channel) {
+        OFControllerRole role = controllerRoleMap.get(channel);
+        if (role == null) {
+            final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
+            throw new IllegalStateException(error);
+        }
+        return role;
+    }
+
+    @Override
+    public Set<Channel> controllerChannels() {
+        return null;
+    }
+
+    @Override
+    public void processPortAdded(Port port) {
+        // TODO generate FEATURES_REPLY message and send it to the controller
+    }
+
+    @Override
+    public void processPortDown(Port port) {
+        // TODO generate PORT_STATUS message and send it to the controller
+    }
+
+    @Override
+    public void processPortUp(Port port) {
+        // TODO generate PORT_STATUS message and send it to the controller
+    }
+
+    @Override
+    public void processFlowRemoved(FlowRule flowRule) {
+        // TODO generate FLOW_REMOVED message and send it to the controller
+    }
+
+    @Override
+    public void processPacketIn(InboundPacket packet) {
+        // TODO generate PACKET_IN message and send it to the controller
+    }
+
+    @Override
+    public void processControllerCommand(Channel channel, OFMessage msg) {
+        // TODO process controller command
+    }
+
+    @Override
+    public void processStatsRequest(Channel channel, OFMessage msg) {
+        // TODO process request and send reply
+    }
+
+    @Override
+    public void processRoleRequest(Channel channel, OFMessage msg) {
+        // TODO process role request and send reply
+    }
+
+    @Override
+    public void processFeaturesRequest(Channel channel, OFMessage msg) {
+        // TODO process features request and send reply
+    }
+
+    @Override
+    public void processLldp(Channel channel, OFMessage msg) {
+        // TODO process lldp
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentManager.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentManager.java
new file mode 100644
index 0000000..3005f73
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentManager.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFAgentService;
+import org.onosproject.ofagent.api.OFController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+
+import static org.onlab.util.BoundedThreadPool.newFixedThreadPool;
+import static org.onlab.util.Tools.groupedThreads;
+
+/**
+ * Implementation of OpenFlow agent service.
+ */
+@Component(immediate = true)
+@Service
+public class OFAgentManager implements OFAgentService {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    // TODO make it to be configurable with component config
+    private static final int NUM_OF_THREADS = 1;
+    private final ExecutorService eventExecutor = newFixedThreadPool(
+            NUM_OF_THREADS,
+            groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+
+    // TODO change it to ConsistentMap and support multi-instance mode
+    private ConcurrentHashMap<NetworkId, OFAgent> agentMap = new ConcurrentHashMap<>();
+    private NioEventLoopGroup ioWorker;
+
+    @Activate
+    protected void activate() {
+        // TODO listen to the virtual network event
+        ioWorker = new NioEventLoopGroup();
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        ioWorker.shutdownGracefully();
+        eventExecutor.shutdown();
+        log.info("Stopped");
+    }
+
+    @Override
+    public Set<OFAgent> agents() {
+        // TODO return existing agents
+        return null;
+    }
+
+    @Override
+    public void createAgent(NetworkId networkId, OFController... controllers) {
+        // TODO create OFAgent instance with the given network ID, controllers
+        // TODO and device, flowRule, link, and packet service for the virtual network
+        // TODO start the OFAgent only if the virtual network state is active
+    }
+
+    @Override
+    public void removeAgent(NetworkId networkId) {
+        // TODO stop and remove the OFAgent for the network
+    }
+
+    @Override
+    public void startAgent(NetworkId networkId) {
+        // TODO starts the agent for the network
+    }
+
+    @Override
+    public void stopAgent(NetworkId networkId) {
+        // TODO stops the agent for the network
+    }
+
+    @Override
+    public boolean isActive(NetworkId networkId) {
+        // TODO manage the OF agent status
+        return false;
+    }
+
+    private class InternalVirtualNetworkListener implements VirtualNetworkListener {
+
+        @Override
+        public void event(VirtualNetworkEvent event) {
+            // TODO handle virtual network start and stop
+        }
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
new file mode 100644
index 0000000..b077af4
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.ReferenceCountUtil;
+import org.onosproject.ofagent.api.OFSwitch;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of OpenFlow channel handler.
+ * It processes OpenFlow message according to the channel state.
+ */
+public final class OFChannelHandler extends ChannelDuplexHandler {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final OFSwitch ofSwitch;
+
+    private Channel channel;
+    private ChannelState state;
+
+    private enum ChannelState {
+
+        INIT {
+            @Override
+            void processOFMessage(final OFChannelHandler handler,
+                                  final OFMessage msg) {
+                // TODO implement
+            }
+        },
+        WAIT_HELLO {
+            @Override
+            void processOFMessage(final OFChannelHandler handler,
+                                  final OFMessage msg) {
+                // TODO implement
+            }
+        },
+        WAIT_FEATURE_REQUEST {
+            @Override
+            void processOFMessage(final OFChannelHandler handler,
+                                  final OFMessage msg) {
+                // TODO implement
+            }
+        },
+        ESTABLISHED {
+            @Override
+            void processOFMessage(final OFChannelHandler handler,
+                                  final OFMessage msg) {
+                // TODO implement
+                // TODO add this channel to ofSwitch role service
+            }
+        };
+
+        abstract void processOFMessage(final OFChannelHandler handler,
+                                       final OFMessage msg);
+    }
+
+    /**
+     * Default constructor.
+     *
+     * @param ofSwitch openflow switch that owns this channel
+     */
+    public OFChannelHandler(OFSwitch ofSwitch) {
+        this.ofSwitch = ofSwitch;
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        super.channelActive(ctx);
+        this.channel = ctx.channel();
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg)
+            throws Exception {
+        try {
+            OFMessage ofMsg = (OFMessage) msg;
+            // TODO process OF message
+
+        } finally {
+            ReferenceCountUtil.release(msg);
+        }
+    }
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx)
+            throws Exception {
+        ctx.flush();
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+        ctx.close();
+    }
+
+    private void setState(ChannelState state) {
+        this.state = state;
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelInitializer.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelInitializer.java
new file mode 100644
index 0000000..a3be413
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelInitializer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.socket.SocketChannel;
+import org.onosproject.ofagent.api.OFSwitch;
+
+/**
+ * Implementation of OpenFlow channel initializer.
+ */
+public final class OFChannelInitializer extends ChannelInitializer<SocketChannel> {
+
+    private final OFSwitch ofSwitch;
+
+    /**
+     * Default constructor.
+     *
+     * @param ofSwitch openflow switch that owns this channel
+     */
+    public OFChannelInitializer(OFSwitch ofSwitch) {
+        this.ofSwitch = ofSwitch;
+    }
+
+    @Override
+    protected void initChannel(SocketChannel ch) throws Exception {
+
+        // TODO configure OF channel pipeline
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFConnectionHandler.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFConnectionHandler.java
new file mode 100644
index 0000000..27a6bc5
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFConnectionHandler.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.onosproject.ofagent.api.OFController;
+import org.onosproject.ofagent.api.OFSwitch;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Implementation of OpenFlow connection handler.
+ * It retries a connection for a certain amount of time and then give up.
+ */
+public final class OFConnectionHandler implements ChannelFutureListener {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final int MAX_RETRY = 10;
+
+    private final AtomicInteger retryCount = new AtomicInteger();
+    private final OFSwitch ofSwitch;
+    private final OFController controller;
+    private final NioEventLoopGroup workGroup;
+
+    /**
+     * Default constructor.
+     *
+     * @param ofSwitch   openflow switch that initiates this connection
+     * @param controller controller to connect
+     * @param workGroup  work group for connection
+     */
+    public OFConnectionHandler(OFSwitch ofSwitch, OFController controller,
+                               NioEventLoopGroup workGroup) {
+        this.ofSwitch = ofSwitch;
+        this.controller = controller;
+        this.workGroup = workGroup;
+    }
+
+    /**
+     * Creates a connection to the supplied controller.
+     */
+    public void connect() {
+        // TODO initiates a connection to the controller
+    }
+
+    @Override
+    public void operationComplete(ChannelFuture future) throws Exception {
+
+        if (future.isSuccess()) {
+            log.debug("{} is connected to controller {}", ofSwitch.device().id(), controller);
+            // TODO do something for a new connection if there's any
+        } else {
+            log.debug("{} failed to connect {}, retry..", ofSwitch.device().id(), controller);
+            // TODO retry connect if retry count is less than MAX
+        }
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageDecoder.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageDecoder.java
new file mode 100644
index 0000000..79d0f4e
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageDecoder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Decodes inbound byte buffer from OpenFlow channel to OFMessage.
+ */
+public final class OFMessageDecoder extends ByteToMessageDecoder {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
+            throws Exception {
+        log.trace("Received message from {}: {}", ctx.channel().remoteAddress(),
+                  in.readByte());
+
+        // TODO decode byte message to OFMessage
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageEncoder.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageEncoder.java
new file mode 100644
index 0000000..1a67602
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFMessageEncoder.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.onosproject.ofagent.impl;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+/**
+ * Encodes OFMessage to a byte buffer.
+ */
+public final class OFMessageEncoder extends MessageToByteEncoder<Iterable<OFMessage>> {
+
+    @Override
+    protected void encode(ChannelHandlerContext ctx, Iterable<OFMessage> msgList, ByteBuf out)
+            throws Exception {
+
+        // TODO encode OFMessage to ByteBuf
+    }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/package-info.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/package-info.java
new file mode 100644
index 0000000..14bdc60
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Implementation of OpenFlow agent.
+ */
+package org.onosproject.ofagent.impl;
\ No newline at end of file