[ONOS-2337,ONOS-2338,ONOS-2339]Pcep Controller

Change-Id: I27fee4669ec923a55d83993b493699c1c46a1b36
diff --git a/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepClientController.java b/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepClientController.java
old mode 100755
new mode 100644
index 1a7cd39..603c35b
--- a/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepClientController.java
+++ b/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepClientController.java
@@ -15,7 +15,7 @@
  */
 package org.onosproject.pcep.controller;
 
-import java.util.List;
+import java.util.Collection;
 
 import org.onosproject.pcepio.protocol.PcepMessage;
 
@@ -31,7 +31,7 @@
      *
      * @return list of PcepClient elements
      */
-    public List<PcepClient> getClients();
+    Collection<PcepClient> getClients();
 
     /**
      * Returns the actual pcc client for the given ip address.
@@ -39,7 +39,7 @@
      * @param pccId the id of the pcc client to fetch
      * @return the interface to this pcc client
      */
-    public PcepClient getClient(PccId pccId);
+    PcepClient getClient(PccId pccId);
 
     /**
      * Register a listener for meta events that occur to pcep
@@ -47,28 +47,28 @@
      *
      * @param listener the listener to notify
      */
-    public void addListener(PcepClientListener listener);
+    void addListener(PcepClientListener listener);
 
     /**
      * Unregister a listener.
      *
      * @param listener the listener to unregister
      */
-    public void removeListener(PcepClientListener listener);
+    void removeListener(PcepClientListener listener);
 
     /**
      * Register a listener for OF msg events.
      *
      * @param listener the listener to notify
      */
-    public void addEventListener(PcepEventListener listener);
+    void addEventListener(PcepEventListener listener);
 
     /**
      * Unregister a listener.
      *
      * @param listener the listener to unregister
      */
-    public void removeEventListener(PcepEventListener listener);
+    void removeEventListener(PcepEventListener listener);
 
     /**
      * Send a message to a particular pcc client.
@@ -76,7 +76,7 @@
      * @param pccId the id of the client to send message.
      * @param msg the message to send
      */
-    public void writeMessage(PccId pccId, PcepMessage msg);
+    void writeMessage(PccId pccId, PcepMessage msg);
 
     /**
      * Process a message and notify the appropriate listeners.
@@ -84,10 +84,10 @@
      * @param pccId id of the client the message arrived on
      * @param msg the message to process.
      */
-    public void processClientMessage(PccId pccId, PcepMessage msg);
+    void processClientMessage(PccId pccId, PcepMessage msg);
 
     /**
      * Close all connected PCC clients.
      */
-    public void closeConnectedClients();
+    void closeConnectedClients();
 }
diff --git a/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepPacketStats.java b/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepPacketStats.java
index 92bb2db..60126a1 100755
--- a/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepPacketStats.java
+++ b/pcep/api/src/main/java/org/onosproject/pcep/controller/PcepPacketStats.java
@@ -42,6 +42,27 @@
     public int wrongPacketCount();
 
     /**
+     * Increments the received packet counter.
+     */
+    public void addInPacket();
+
+    /**
+     * Increments the sent packet counter.
+     */
+    public void addOutPacket();
+
+    /**
+     * Increments the sent packet counter by specified value.
+     * @param value of no of packets sent
+     */
+    public void addOutPacket(int value);
+
+    /**
+     * Increments the wrong packet counter.
+     */
+    public void addWrongPacket();
+
+    /**
      * Returns the time value.
      *
      * @return long value of time
diff --git a/pcep/ctl/pom.xml b/pcep/ctl/pom.xml
new file mode 100644
index 0000000..35ec429
--- /dev/null
+++ b/pcep/ctl/pom.xml
@@ -0,0 +1,66 @@
+<!--
+  ~ Copyright 2014 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.
+  -->
+<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>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-pcep-controller</artifactId>
+        <version>1.3.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-pcep-controller-impl</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>ONOS PCEP controller subsystem API</description>
+
+    <dependencies>
+        <dependency>
+            <!-- FIXME once experimenter gets merged to upstream -->
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-pcep-controller-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-misc</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/Controller.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/Controller.java
new file mode 100644
index 0000000..9c27810
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/Controller.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+import static org.onlab.util.Tools.groupedThreads;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.group.ChannelGroup;
+import org.jboss.netty.channel.group.DefaultChannelGroup;
+import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.onosproject.pcep.controller.PccId;
+import org.onosproject.pcep.controller.PcepPacketStats;
+import org.onosproject.pcep.controller.driver.PcepAgent;
+import org.onosproject.pcep.controller.driver.PcepClientDriver;
+import org.onosproject.pcepio.protocol.PcepFactories;
+import org.onosproject.pcepio.protocol.PcepFactory;
+import org.onosproject.pcepio.protocol.PcepVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The main controller class. Handles all setup and network listeners -
+ * Distributed ownership control of pcc through IControllerRegistryService
+ */
+public class Controller {
+
+    private static final Logger log = LoggerFactory.getLogger(Controller.class);
+
+    private static final PcepFactory FACTORY1 = PcepFactories.getFactory(PcepVersion.PCEP_1);
+
+    private ChannelGroup cg;
+
+    // Configuration options
+    private int pcepPort = 4189;
+    private int workerThreads = 10;
+
+    // Start time of the controller
+    private long systemStartTime;
+
+    private PcepAgent agent;
+
+    private NioServerSocketChannelFactory execFactory;
+
+    // Perf. related configuration
+    private static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
+
+    /**
+     * Returns factory version for processing pcep messages.
+     *
+     * @return instance of factory version
+     */
+    public PcepFactory getPcepMessageFactory1() {
+        return FACTORY1;
+    }
+
+    /**
+     * To get system start time.
+     *
+     * @return system start time in milliseconds
+     */
+    public long getSystemStartTime() {
+        return (this.systemStartTime);
+    }
+
+    /**
+     * Tell controller that we're ready to accept pcc connections.
+     */
+    public void run() {
+        try {
+            final ServerBootstrap bootstrap = createServerBootStrap();
+
+            bootstrap.setOption("reuseAddr", true);
+            bootstrap.setOption("child.keepAlive", true);
+            bootstrap.setOption("child.tcpNoDelay", true);
+            bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
+
+            ChannelPipelineFactory pfact = new PcepPipelineFactory(this);
+
+            bootstrap.setPipelineFactory(pfact);
+            InetSocketAddress sa = new InetSocketAddress(pcepPort);
+            cg = new DefaultChannelGroup();
+            cg.add(bootstrap.bind(sa));
+            log.info("Listening for PCC connection on {}", sa);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Creates server boot strap.
+     *
+     * @return ServerBootStrap
+     */
+    private ServerBootstrap createServerBootStrap() {
+        if (workerThreads == 0) {
+            execFactory = new NioServerSocketChannelFactory(
+                    Executors.newCachedThreadPool(groupedThreads("onos/pcep", "boss-%d")),
+                    Executors.newCachedThreadPool(groupedThreads("onos/pcep", "worker-%d")));
+            return new ServerBootstrap(execFactory);
+        } else {
+            execFactory = new NioServerSocketChannelFactory(
+                    Executors.newCachedThreadPool(groupedThreads("onos/pcep", "boss-%d")),
+                    Executors.newCachedThreadPool(groupedThreads("onos/pcep", "worker-%d")), workerThreads);
+            return new ServerBootstrap(execFactory);
+        }
+    }
+
+    /**
+     * Initialize internal data structures.
+     */
+    public void init() {
+        // These data structures are initialized here because other
+        // module's startUp() might be called before ours
+        this.systemStartTime = System.currentTimeMillis();
+    }
+
+    public Map<String, Long> getMemory() {
+        Map<String, Long> m = new HashMap<>();
+        Runtime runtime = Runtime.getRuntime();
+        m.put("total", runtime.totalMemory());
+        m.put("free", runtime.freeMemory());
+        return m;
+    }
+
+    public Long getUptime() {
+        RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
+        return rb.getUptime();
+    }
+
+    /**
+     * Creates instance of Pcep client.
+     *
+     * @param pccId pcc identifier
+     * @param sessionID session id
+     * @param pv pcep version
+     * @param pktStats pcep packet statistics
+     * @return instance of PcepClient
+     */
+    protected PcepClientDriver getPcepClientInstance(PccId pccId, int sessionID, PcepVersion pv,
+            PcepPacketStats pktStats) {
+        PcepClientDriver pcepClientDriver = new PcepClientImpl();
+        pcepClientDriver.init(pccId, pv, pktStats);
+        pcepClientDriver.setAgent(agent);
+        return pcepClientDriver;
+    }
+
+    /**
+     * Starts the pcep controller.
+     *
+     * @param ag Pcep agent
+     */
+    public void start(PcepAgent ag) {
+        log.info("Started");
+        this.agent = ag;
+        this.init();
+        this.run();
+    }
+
+    /**
+     * Stops the pcep controller.
+     */
+    public void stop() {
+        log.info("Stopped");
+        execFactory.shutdown();
+        cg.close();
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepChannelHandler.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepChannelHandler.java
new file mode 100644
index 0000000..01e8431
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepChannelHandler.java
@@ -0,0 +1,652 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.channels.ClosedChannelException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.handler.timeout.IdleState;
+import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
+import org.jboss.netty.handler.timeout.IdleStateEvent;
+import org.jboss.netty.handler.timeout.IdleStateHandler;
+import org.jboss.netty.handler.timeout.ReadTimeoutException;
+import org.onlab.packet.IpAddress;
+import org.onosproject.pcep.controller.PccId;
+import org.onosproject.pcep.controller.driver.PcepClientDriver;
+import org.onosproject.pcepio.exceptions.PcepParseException;
+import org.onosproject.pcepio.protocol.PcepError;
+import org.onosproject.pcepio.protocol.PcepErrorInfo;
+import org.onosproject.pcepio.protocol.PcepErrorMsg;
+import org.onosproject.pcepio.protocol.PcepErrorObject;
+import org.onosproject.pcepio.protocol.PcepFactory;
+import org.onosproject.pcepio.protocol.PcepMessage;
+import org.onosproject.pcepio.protocol.PcepOpenMsg;
+import org.onosproject.pcepio.protocol.PcepOpenObject;
+import org.onosproject.pcepio.protocol.PcepType;
+import org.onosproject.pcepio.protocol.PcepVersion;
+import org.onosproject.pcepio.types.ErrorObjListWithOpen;
+import org.onosproject.pcepio.types.PceccCapabilityTlv;
+import org.onosproject.pcepio.types.StatefulPceCapabilityTlv;
+import org.onosproject.pcepio.types.PcepErrorDetailInfo;
+import org.onosproject.pcepio.types.PcepValueType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Channel handler deals with the pcc client connection and dispatches
+ * messages from client to the appropriate locations.
+ */
+class PcepChannelHandler extends IdleStateAwareChannelHandler {
+    static final byte DEADTIMER_MAXIMUM_VALUE = (byte) 0xFF;
+    static final byte KEEPALIVE_MULTIPLE_FOR_DEADTIMER = 4;
+    private static final Logger log = LoggerFactory.getLogger(PcepChannelHandler.class);
+    private final Controller controller;
+    private PcepClientDriver pc;
+    private PccId thispccId;
+    private Channel channel;
+    private byte sessionId = 0;
+    private byte keepAliveTime;
+    private byte deadTime;
+    private PcepPacketStatsImpl pcepPacketStats;
+    static final int MAX_WRONG_COUNT_PACKET = 5;
+    static final int BYTE_MASK = 0xFF;
+
+    // State needs to be volatile because the HandshakeTimeoutHandler
+    // needs to check if the handshake is complete
+    private volatile ChannelState state;
+
+    // When a pcc client with a ip addresss is found (i.e we already have a
+    // connected client with the same ip), the new client is immediately
+    // disconnected. At that point netty callsback channelDisconnected() which
+    // proceeds to cleaup client state - we need to ensure that it does not cleanup
+    // client state for the older (still connected) client
+    private volatile Boolean duplicatePccIdFound;
+
+    //Indicates the pcep version used by this pcc client
+    protected PcepVersion pcepVersion;
+    protected PcepFactory factory1;
+
+    /**
+     * Create a new unconnected PcepChannelHandler.
+     * @param controller parent controller
+     */
+    PcepChannelHandler(Controller controller) {
+        this.controller = controller;
+        this.state = ChannelState.INIT;
+        factory1 = controller.getPcepMessageFactory1();
+        duplicatePccIdFound = Boolean.FALSE;
+        pcepPacketStats = new PcepPacketStatsImpl();
+    }
+
+    /**
+     * To disconnect a PCC.
+     */
+    public void disconnectClient() {
+        pc.disconnectClient();
+    }
+
+    //*************************
+    //  Channel State Machine
+    //*************************
+
+    /**
+     * The state machine for handling the client/channel state. All state
+     * transitions should happen from within the state machine (and not from other
+     * parts of the code)
+     */
+    enum ChannelState {
+        /**
+         * Initial state before channel is connected.
+         */
+        INIT(false) {
+
+        },
+        /**
+         * Once the session is established, wait for open message.
+         */
+        OPENWAIT(false) {
+            @Override
+            void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
+
+                log.debug("Message received in OPEN WAIT State");
+
+                //check for open message
+                if (m.getType() != PcepType.OPEN) {
+                    // When the message type is not open message increment the wrong packet statistics
+                    h.processUnknownMsg();
+                    log.debug("message is not OPEN message");
+                } else {
+
+                    h.pcepPacketStats.addInPacket();
+                    PcepOpenMsg pOpenmsg = (PcepOpenMsg) m;
+                    // do Capability validation.
+                    if (h.capabilityValidation(pOpenmsg)) {
+                        log.debug("Sending handshake OPEN message");
+                        h.sessionId = pOpenmsg.getPcepOpenObject().getSessionId();
+                        h.pcepVersion = pOpenmsg.getPcepOpenObject().getVersion();
+
+                        //setting keepalive and deadTimer
+                        byte yKeepalive = pOpenmsg.getPcepOpenObject().getKeepAliveTime();
+                        byte yDeadTimer = pOpenmsg.getPcepOpenObject().getDeadTime();
+                        h.keepAliveTime = yKeepalive;
+                        if (yKeepalive < yDeadTimer) {
+                            h.deadTime = yDeadTimer;
+                        } else {
+                            if (DEADTIMER_MAXIMUM_VALUE > (yKeepalive * KEEPALIVE_MULTIPLE_FOR_DEADTIMER)) {
+                                h.deadTime = (byte) (yKeepalive * KEEPALIVE_MULTIPLE_FOR_DEADTIMER);
+                            } else {
+                                h.deadTime = DEADTIMER_MAXIMUM_VALUE;
+                            }
+                        }
+                        h.sendHandshakeOpenMessage();
+                        h.pcepPacketStats.addOutPacket();
+                        h.setState(KEEPWAIT);
+                    } else {
+                        log.debug("Capability validation failed. Sending PCEP-ERROR message to PCC.");
+                        // Send PCEP-ERROR message.
+                        PcepErrorMsg errMsg = h.getErrorMsg(PcepErrorDetailInfo.ERROR_TYPE_2,
+                                PcepErrorDetailInfo.ERROR_VALUE_2);
+                        h.channel.write(Collections.singletonList(errMsg));
+                    }
+                }
+            }
+        },
+        /**
+         * Once the open messages are exchanged, wait for keep alive message.
+         */
+        KEEPWAIT(false) {
+            @Override
+            void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
+                log.debug("message received in KEEPWAIT state");
+                //check for keep alive message
+                if (m.getType() != PcepType.KEEP_ALIVE) {
+                    // When the message type is not keep alive message increment the wrong packet statistics
+                    h.processUnknownMsg();
+                    log.debug("message is not KEEPALIVE message");
+                } else {
+                    // Set the client connected status
+                    h.pcepPacketStats.addInPacket();
+                    final SocketAddress address = h.channel.getRemoteAddress();
+                    if (!(address instanceof InetSocketAddress)) {
+                        throw new IOException("Invalid client connection. Pcc is indentifed based on IP");
+                    }
+                    log.debug("sending keep alive message in KEEPWAIT state");
+
+                    final InetSocketAddress inetAddress = (InetSocketAddress) address;
+                    h.thispccId = PccId.pccId(IpAddress.valueOf(inetAddress.getAddress()));
+                    h.pc = h.controller.getPcepClientInstance(h.thispccId, h.sessionId, h.pcepVersion,
+                            h.pcepPacketStats);
+                    // set the status of pcc as connected
+                    h.pc.setConnected(true);
+                    h.pc.setChannel(h.channel);
+
+                    // set any other specific parameters to the pcc
+                    h.pc.setPcVersion(h.pcepVersion);
+                    h.pc.setPcSessionId(h.sessionId);
+                    h.pc.setPcKeepAliveTime(h.keepAliveTime);
+                    h.pc.setPcDeadTime(h.deadTime);
+                    int keepAliveTimer = h.keepAliveTime & BYTE_MASK;
+                    int deadTimer = h.deadTime & BYTE_MASK;
+                    if (0 == h.keepAliveTime) {
+                        h.deadTime = 0;
+                    }
+                    // handle keep alive and dead time
+                    if (keepAliveTimer != PcepPipelineFactory.DEFAULT_KEEP_ALIVE_TIME
+                            || deadTimer != PcepPipelineFactory.DEFAULT_DEAD_TIME) {
+
+                        h.channel.getPipeline().replace("idle", "idle",
+                                new IdleStateHandler(PcepPipelineFactory.TIMER, deadTimer, keepAliveTimer, 0));
+                    }
+                    log.debug("Dead timer : " + deadTimer);
+                    log.debug("Keep alive time : " + keepAliveTimer);
+
+                    //set the state handshake completion.
+                    h.sendKeepAliveMessage();
+                    h.pcepPacketStats.addOutPacket();
+                    h.setHandshakeComplete(true);
+
+                    if (!h.pc.connectClient()) {
+                        disconnectDuplicate(h);
+                    } else {
+                        h.setState(ESTABLISHED);
+                    }
+                }
+            }
+        },
+        /**
+         * Once the keep alive messages are exchanged, the state is established.
+         */
+        ESTABLISHED(true) {
+            @Override
+            void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
+
+                //h.channel.getPipeline().remove("waittimeout");
+                log.debug("Message received in established state " + m.getType());
+                //dispatch the message
+                h.dispatchMessage(m);
+            }
+        };
+        private boolean handshakeComplete;
+
+        ChannelState(boolean handshakeComplete) {
+            this.handshakeComplete = handshakeComplete;
+        }
+
+        void processPcepMessage(PcepChannelHandler h, PcepMessage m) throws IOException, PcepParseException {
+            // do nothing
+        }
+
+        /**
+         * Is this a state in which the handshake has completed.
+         *
+         * @return true if the handshake is complete
+         */
+        public boolean isHandshakeComplete() {
+            return this.handshakeComplete;
+        }
+
+        protected void disconnectDuplicate(PcepChannelHandler h) {
+            log.error("Duplicated Pcc IP or incompleted cleanup - " + "disconnecting channel {}",
+                    h.getClientInfoString());
+            h.duplicatePccIdFound = Boolean.TRUE;
+            h.channel.disconnect();
+        }
+
+        /**
+         * Sets handshake complete status.
+         *
+         * @param handshakeComplete status of handshake
+         */
+        public void setHandshakeComplete(boolean handshakeComplete) {
+            this.handshakeComplete = handshakeComplete;
+        }
+
+    }
+
+    @Override
+    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+        channel = e.getChannel();
+        log.info("PCC connected from {}", channel.getRemoteAddress());
+
+        // Wait for open message from pcc client
+        setState(ChannelState.OPENWAIT);
+    }
+
+    @Override
+    public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+        log.info("Pcc disconnected callback for pc:{}. Cleaning up ...", getClientInfoString());
+        if (thispccId != null) {
+            if (!duplicatePccIdFound) {
+                // if the disconnected client (on this ChannelHandler)
+                // was not one with a duplicate-dpid, it is safe to remove all
+                // state for it at the controller. Notice that if the disconnected
+                // client was a duplicate-ip, calling the method below would clear
+                // all state for the original client (with the same ip),
+                // which we obviously don't want.
+                log.debug("{}:removal called", getClientInfoString());
+                if (pc != null) {
+                    pc.removeConnectedClient();
+                }
+            } else {
+                // A duplicate was disconnected on this ChannelHandler,
+                // this is the same client reconnecting, but the original state was
+                // not cleaned up - XXX check liveness of original ChannelHandler
+                log.debug("{}:duplicate found", getClientInfoString());
+                duplicatePccIdFound = Boolean.FALSE;
+            }
+        } else {
+            log.warn("no pccip in channelHandler registered for " + "disconnected client {}", getClientInfoString());
+        }
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
+        PcepErrorMsg errMsg;
+        log.info("exceptionCaught: " + e.toString());
+
+        if (e.getCause() instanceof ReadTimeoutException) {
+            if (ChannelState.OPENWAIT == state) {
+                // When ReadTimeout timer is expired in OPENWAIT state, it is considered
+                // OpenWait timer.
+                errMsg = getErrorMsg(PcepErrorDetailInfo.ERROR_TYPE_1, PcepErrorDetailInfo.ERROR_VALUE_2);
+                log.debug("Sending PCEP-ERROR message to PCC.");
+                channel.write(Collections.singletonList(errMsg));
+                channel.close();
+                state = ChannelState.INIT;
+                return;
+            } else if (ChannelState.KEEPWAIT == state) {
+                // When ReadTimeout timer is expired in KEEPWAIT state, is is considered
+                // KeepWait timer.
+                errMsg = getErrorMsg(PcepErrorDetailInfo.ERROR_TYPE_1, PcepErrorDetailInfo.ERROR_VALUE_7);
+                log.debug("Sending PCEP-ERROR message to PCC.");
+                channel.write(Collections.singletonList(errMsg));
+                channel.close();
+                state = ChannelState.INIT;
+                return;
+            }
+        } else if (e.getCause() instanceof ClosedChannelException) {
+            log.debug("Channel for pc {} already closed", getClientInfoString());
+        } else if (e.getCause() instanceof IOException) {
+            log.error("Disconnecting client {} due to IO Error: {}", getClientInfoString(), e.getCause().getMessage());
+            if (log.isDebugEnabled()) {
+                // still print stack trace if debug is enabled
+                log.debug("StackTrace for previous Exception: ", e.getCause());
+            }
+            channel.close();
+        } else if (e.getCause() instanceof PcepParseException) {
+            PcepParseException errMsgParse = (PcepParseException) e.getCause();
+            byte errorType = errMsgParse.getErrorType();
+            byte errorValue = errMsgParse.getErrorValue();
+
+            if ((errorType == (byte) 0x0) && (errorValue == (byte) 0x0)) {
+                processUnknownMsg();
+            } else {
+                errMsg = getErrorMsg(errorType, errorValue);
+                log.debug("Sending PCEP-ERROR message to PCC.");
+                channel.write(Collections.singletonList(errMsg));
+            }
+        } else if (e.getCause() instanceof RejectedExecutionException) {
+            log.warn("Could not process message: queue full");
+        } else {
+            log.error("Error while processing message from client " + getClientInfoString() + "state " + this.state);
+            channel.close();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getClientInfoString();
+    }
+
+    @Override
+    public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
+        if (!isHandshakeComplete()) {
+            return;
+        }
+
+        if (e.getState() == IdleState.READER_IDLE) {
+            // When no message is received on channel for read timeout, then close
+            // the channel
+            log.info("Disconnecting client {} due to read timeout", getClientInfoString());
+            ctx.getChannel().close();
+        } else if (e.getState() == IdleState.WRITER_IDLE) {
+            // Send keep alive message
+            log.debug("Sending keep alive message due to IdleState timeout " + pc.toString());
+            pc.sendMessage(Collections.singletonList(pc.factory().buildKeepaliveMsg().build()));
+        }
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        if (e.getMessage() instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<PcepMessage> msglist = (List<PcepMessage>) e.getMessage();
+            for (PcepMessage pm : msglist) {
+                // Do the actual packet processing
+                state.processPcepMessage(this, pm);
+            }
+        } else {
+            state.processPcepMessage(this, (PcepMessage) e.getMessage());
+        }
+    }
+
+    /**
+     * To set the handshake status.
+     *
+     * @param handshakeComplete value is handshake status
+     */
+    public void setHandshakeComplete(boolean handshakeComplete) {
+        this.state.setHandshakeComplete(handshakeComplete);
+    }
+
+    /**
+     * Is this a state in which the handshake has completed.
+     *
+     * @return true if the handshake is complete
+     */
+    public boolean isHandshakeComplete() {
+        return this.state.isHandshakeComplete();
+    }
+
+    /**
+     * To handle the pcep message.
+     *
+     * @param m pcep message
+     */
+    private void dispatchMessage(PcepMessage m) {
+        pc.handleMessage(m);
+    }
+
+    /**
+     * Return a string describing this client based on the already available
+     * information (ip address and/or remote socket).
+     *
+     * @return display string
+     */
+    private String getClientInfoString() {
+        if (pc != null) {
+            return pc.toString();
+        }
+        String channelString;
+        if (channel == null || channel.getRemoteAddress() == null) {
+            channelString = "?";
+        } else {
+            channelString = channel.getRemoteAddress().toString();
+        }
+        String pccIpString;
+        // TODO : implement functionality to get pcc id string
+        pccIpString = "?";
+        return String.format("[%s PCCIP[%s]]", channelString, pccIpString);
+    }
+
+    /**
+     * Update the channels state. Only called from the state machine.
+     *
+     * @param state
+     */
+    private void setState(ChannelState state) {
+        this.state = state;
+    }
+
+    /**
+     * Send handshake open message.
+     *
+     * @throws IOException,PcepParseException
+     */
+    private void sendHandshakeOpenMessage() throws IOException, PcepParseException {
+        PcepOpenObject pcepOpenobj = factory1.buildOpenObject()
+                .setSessionId(sessionId)
+                .setKeepAliveTime(keepAliveTime)
+                .setDeadTime(deadTime)
+                .build();
+        PcepMessage msg = factory1.buildOpenMsg()
+                .setPcepOpenObj(pcepOpenobj)
+                .build();
+        log.debug("Sending OPEN message to {}", channel.getRemoteAddress());
+        channel.write(Collections.singletonList(msg));
+    }
+
+    /**
+     * Capability Validation.
+     *
+     * @param pOpenmsg pcep open message
+     * @return success or failure
+     */
+    private boolean capabilityValidation(PcepOpenMsg pOpenmsg) {
+        LinkedList<PcepValueType> tlvList = pOpenmsg.getPcepOpenObject().getOptionalTlv();
+        boolean bFoundPceccCapability = false;
+        boolean bFoundStatefulPceCapability = false;
+        boolean bFoundPcInstantiationCapability = false;
+
+        ListIterator<PcepValueType> listIterator = tlvList.listIterator();
+        while (listIterator.hasNext()) {
+            PcepValueType tlv = listIterator.next();
+
+            switch (tlv.getType()) {
+            case PceccCapabilityTlv.TYPE:
+                bFoundPceccCapability = true;
+                break;
+            case StatefulPceCapabilityTlv.TYPE:
+                bFoundStatefulPceCapability = true;
+                StatefulPceCapabilityTlv stetefulPcCapTlv = (StatefulPceCapabilityTlv) tlv;
+                if (stetefulPcCapTlv.getIFlag()) {
+                    bFoundPcInstantiationCapability = true;
+                }
+                break;
+            default:
+                continue;
+            }
+        }
+
+        return (bFoundPceccCapability && bFoundStatefulPceCapability && bFoundPcInstantiationCapability) ? true : false;
+    }
+
+    /**
+     * Send keep alive message.
+     *
+     * @throws IOException when channel is disconnected
+     * @throws PcepParseException while building keep alive message
+     */
+    private void sendKeepAliveMessage() throws IOException, PcepParseException {
+        PcepMessage msg = factory1.buildKeepaliveMsg().build();
+        log.debug("Sending KEEPALIVE message to {}", channel.getRemoteAddress());
+        channel.write(Collections.singletonList(msg));
+    }
+
+    /**
+     * Send error message and close channel with pcc.
+     */
+    private void sendErrMsgAndCloseChannel() {
+        // TODO send error message
+        channel.close();
+    }
+
+    /**
+     * Send error message when an invalid message is received.
+     *
+     * @throws PcepParseException while building error message
+     */
+    private void sendErrMsgForInvalidMsg() throws PcepParseException {
+        byte errorType = 0x02;
+        byte errorValue = 0x00;
+        PcepErrorMsg errMsg = getErrorMsg(errorType, errorValue);
+        channel.write(Collections.singletonList(errMsg));
+    }
+
+    /**
+     * Builds pcep error message based on error value and error type.
+     *
+     * @param errorType  pcep error type
+     * @param errorValue pcep error value
+     * @return pcep error message
+     * @throws PcepParseException while bulding error message
+     */
+    public PcepErrorMsg getErrorMsg(byte errorType, byte errorValue) throws PcepParseException {
+        LinkedList<PcepErrorObject> llerrObj = new LinkedList<PcepErrorObject>();
+        PcepErrorMsg errMsg;
+
+        PcepErrorObject errObj = factory1.buildPcepErrorObject()
+                .setErrorValue(errorValue)
+                .setErrorType(errorType)
+                .build();
+
+        llerrObj.add(errObj);
+
+        if (state == ChannelState.OPENWAIT) {
+            //If Error caught in Openmessage
+            PcepOpenObject openObj = null;
+            ErrorObjListWithOpen errorObjListWithOpen = null;
+
+            if (0 != sessionId) {
+                openObj = factory1.buildOpenObject().setSessionId(sessionId).build();
+                errorObjListWithOpen = new ErrorObjListWithOpen(llerrObj, openObj);
+            } else {
+                errorObjListWithOpen = new ErrorObjListWithOpen(llerrObj, null);
+            }
+
+            errMsg = factory1.buildPcepErrorMsg()
+                    .setErrorObjListWithOpen(errorObjListWithOpen)
+                    .build();
+        } else {
+
+            //If Error caught in other than Openmessage
+            LinkedList<PcepError> llPcepErr = new LinkedList<PcepError>();
+
+            PcepError pcepErr = factory1.buildPcepError()
+                    .setErrorObjList(llerrObj)
+                    .build();
+
+            llPcepErr.add(pcepErr);
+
+            PcepErrorInfo errInfo = factory1.buildPcepErrorInfo()
+                    .setPcepErrorList(llPcepErr)
+                    .build();
+
+            errMsg = factory1.buildPcepErrorMsg()
+                    .setPcepErrorInfo(errInfo)
+                    .build();
+        }
+        return errMsg;
+    }
+
+    /**
+     * Process unknown pcep message received.
+     *
+     * @throws PcepParseException while building pcep error message
+     */
+    public void processUnknownMsg() throws PcepParseException {
+        Date now = null;
+        if (pcepPacketStats.wrongPacketCount() == 0) {
+            now = new Date();
+            pcepPacketStats.setTime(now.getTime());
+            pcepPacketStats.addWrongPacket();
+            sendErrMsgForInvalidMsg();
+        }
+
+        if (pcepPacketStats.wrongPacketCount() > 1) {
+            Date lastest = new Date();
+            pcepPacketStats.addWrongPacket();
+            //converting to seconds
+            if (((lastest.getTime() - pcepPacketStats.getTime()) / 1000) > 60) {
+                now = lastest;
+                pcepPacketStats.setTime(now.getTime());
+                pcepPacketStats.resetWrongPacket();
+                pcepPacketStats.addWrongPacket();
+            } else if (((int) (lastest.getTime() - now.getTime()) / 1000) < 60) {
+                if (MAX_WRONG_COUNT_PACKET <= pcepPacketStats.wrongPacketCount()) {
+                    //reset once wrong packet count reaches MAX_WRONG_COUNT_PACKET
+                    pcepPacketStats.resetWrongPacket();
+                    // max wrong packets received send error message and close the session
+                    sendErrMsgAndCloseChannel();
+                }
+            }
+        }
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepClientControllerImpl.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepClientControllerImpl.java
new file mode 100644
index 0000000..c22f548
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepClientControllerImpl.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+import static org.onlab.util.Tools.groupedThreads;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+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.net.driver.DriverService;
+import org.onosproject.pcep.controller.PccId;
+import org.onosproject.pcep.controller.PcepClient;
+import org.onosproject.pcep.controller.PcepClientController;
+import org.onosproject.pcep.controller.PcepClientListener;
+import org.onosproject.pcep.controller.PcepEventListener;
+import org.onosproject.pcep.controller.driver.PcepAgent;
+import org.onosproject.pcepio.protocol.PcepMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+@Component(immediate = true)
+@Service
+public class PcepClientControllerImpl implements PcepClientController {
+
+    private static final Logger log = LoggerFactory.getLogger(PcepClientControllerImpl.class);
+
+    //@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DriverService driverService;
+
+    private final ExecutorService executorMsgs =
+            Executors.newFixedThreadPool(32, groupedThreads("onos/pcep", "event-stats-%d"));
+
+    private final ExecutorService executorBarrier =
+            Executors.newFixedThreadPool(4, groupedThreads("onos/pcep", "event-barrier-%d"));
+
+    protected ConcurrentHashMap<PccId, PcepClient> connectedClients =
+            new ConcurrentHashMap<PccId, PcepClient>();
+
+    protected PcepClientAgent agent = new PcepClientAgent();
+    protected Set<PcepClientListener> pcepClientListener = new HashSet<>();
+
+    protected Set<PcepEventListener> pcepEventListener = Sets.newHashSet();
+
+    private final Controller ctrl = new Controller();
+
+    @Activate
+    public void activate() {
+        ctrl.start(agent);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        // Close all connected clients
+        closeConnectedClients();
+        ctrl.stop();
+        log.info("Stopped");
+    }
+
+    @Override
+    public Collection<PcepClient> getClients() {
+        return connectedClients.values();
+    }
+
+    @Override
+    public PcepClient getClient(PccId pccId) {
+        return connectedClients.get(pccId);
+    }
+
+    @Override
+    public void addListener(PcepClientListener listener) {
+        if (!pcepClientListener.contains(listener)) {
+            this.pcepClientListener.add(listener);
+        }
+    }
+
+    @Override
+    public void removeListener(PcepClientListener listener) {
+        this.pcepClientListener.remove(listener);
+    }
+
+    @Override
+    public void addEventListener(PcepEventListener listener) {
+        pcepEventListener.add(listener);
+    }
+
+    @Override
+    public void removeEventListener(PcepEventListener listener) {
+        pcepEventListener.remove(listener);
+    }
+
+    @Override
+    public void writeMessage(PccId pccId, PcepMessage msg) {
+        this.getClient(pccId).sendMessage(msg);
+    }
+
+    @Override
+    public void processClientMessage(PccId pccId, PcepMessage msg) {
+        PcepClient pc = getClient(pccId);
+
+        switch (msg.getType()) {
+        case NONE:
+            break;
+        case OPEN:
+            break;
+        case KEEP_ALIVE:
+            break;
+        case PATH_COMPUTATION_REQUEST:
+            break;
+        case PATH_COMPUTATION_REPLY:
+            break;
+        case NOTIFICATION:
+            break;
+        case ERROR:
+            break;
+        case CLOSE:
+            log.info("Sending Close Message  to {" + pccId.toString() + "}");
+            pc.sendMessage(Collections.singletonList(pc.factory().buildCloseMsg().build()));
+            //now disconnect client
+            pc.disconnectClient();
+            break;
+        case REPORT:
+            for (PcepEventListener l : pcepEventListener) {
+                l.handleMessage(pccId, msg);
+            }
+            break;
+        case UPDATE:
+            for (PcepEventListener l : pcepEventListener) {
+                l.handleMessage(pccId, msg);
+            }
+            break;
+        case INITIATE:
+            for (PcepEventListener l : pcepEventListener) {
+                l.handleMessage(pccId, msg);
+            }
+            break;
+        case LABEL_UPDATE:
+            break;
+        case MAX:
+            break;
+        case END:
+            break;
+        default:
+            break;
+        }
+    }
+
+    @Override
+    public void closeConnectedClients() {
+        PcepClient pc;
+        for (PccId id : connectedClients.keySet()) {
+            pc = getClient(id);
+            pc.disconnectClient();
+        }
+    }
+
+    /**
+     * Implementation of an Pcep Agent which is responsible for
+     * keeping track of connected clients and the state in which
+     * they are.
+     */
+    public class PcepClientAgent implements PcepAgent {
+
+        private final Logger log = LoggerFactory.getLogger(PcepClientAgent.class);
+        private final Lock clientLock = new ReentrantLock();
+
+        @Override
+        public boolean addConnectedClient(PccId pccId, PcepClient pc) {
+
+            if (connectedClients.get(pccId) != null) {
+                log.error("Trying to add connectedClient but found a previous "
+                        + "value for pcc ip: {}", pccId.toString());
+                return false;
+            } else {
+                log.debug("Added Client {}", pccId.toString());
+                connectedClients.put(pccId, pc);
+                for (PcepClientListener l : pcepClientListener) {
+                    l.clientConnected(pccId);
+                }
+                return true;
+            }
+        }
+
+        @Override
+        public boolean validActivation(PccId pccId) {
+            if (connectedClients.get(pccId) == null) {
+                log.error("Trying to activate client but is not in "
+                        + "connected client: pccIp {}. Aborting ..", pccId.toString());
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public void removeConnectedClient(PccId pccId) {
+
+            connectedClients.remove(pccId);
+            for (PcepClientListener l : pcepClientListener) {
+                log.warn("removal for {}", pccId.toString());
+                l.clientDisconnected(pccId);
+            }
+        }
+
+        @Override
+        public void processPcepMessage(PccId pccId, PcepMessage m) {
+            processClientMessage(pccId, m);
+        }
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepClientImpl.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepClientImpl.java
new file mode 100644
index 0000000..a10ff5c
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepClientImpl.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.jboss.netty.channel.Channel;
+import org.onlab.packet.IpAddress;
+import org.onosproject.pcep.controller.PccId;
+import org.onosproject.pcep.controller.PcepPacketStats;
+import org.onosproject.pcep.controller.driver.PcepAgent;
+import org.onosproject.pcep.controller.driver.PcepClientDriver;
+import org.onosproject.pcepio.protocol.PcepFactories;
+import org.onosproject.pcepio.protocol.PcepFactory;
+import org.onosproject.pcepio.protocol.PcepMessage;
+import org.onosproject.pcepio.protocol.PcepVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * An abstract representation of an OpenFlow switch. Can be extended by others
+ * to serve as a base for their vendor specific representation of a switch.
+ */
+public class PcepClientImpl implements PcepClientDriver {
+
+    protected final Logger log = LoggerFactory.getLogger(PcepClientImpl.class);
+
+    private static final String SHUTDOWN_MSG = "Worker has already been shutdown";
+
+    private Channel channel;
+    protected String channelId;
+
+    private boolean connected;
+    protected boolean startDriverHandshakeCalled = false;
+    protected boolean isHandShakeComplete = false;
+    protected boolean isSyncComplete = false;
+    private PccId pccId;
+    private PcepAgent agent;
+
+    private PcepVersion pcepVersion;
+    private byte keepAliveTime;
+    private byte deadTime;
+    private byte sessionId;
+    private PcepPacketStatsImpl pktStats;
+
+    @Override
+    public void init(PccId pccId, PcepVersion pcepVersion, PcepPacketStats pktStats) {
+        this.pccId = pccId;
+        this.pcepVersion = pcepVersion;
+        this.pktStats = (PcepPacketStatsImpl) pktStats;
+    }
+
+    @Override
+    public final void disconnectClient() {
+        this.channel.close();
+    }
+
+    @Override
+    public final void sendMessage(PcepMessage m) {
+        log.debug("Sending message to {}", channel.getRemoteAddress());
+        try {
+            channel.write(Collections.singletonList(m));
+            this.pktStats.addOutPacket();
+        } catch (RejectedExecutionException e) {
+            log.warn(e.getMessage());
+            if (!e.getMessage().contains(SHUTDOWN_MSG)) {
+                throw e;
+            }
+        }
+    }
+
+    @Override
+    public final void sendMessage(List<PcepMessage> msgs) {
+        try {
+            channel.write(msgs);
+            this.pktStats.addOutPacket(msgs.size());
+        } catch (RejectedExecutionException e) {
+            log.warn(e.getMessage());
+            if (!e.getMessage().contains(SHUTDOWN_MSG)) {
+                throw e;
+            }
+        }
+    }
+
+    @Override
+    public final boolean isConnected() {
+        return this.connected;
+    }
+
+    @Override
+    public final void setConnected(boolean connected) {
+        this.connected = connected;
+    };
+
+    @Override
+    public final void setChannel(Channel channel) {
+        this.channel = channel;
+        final SocketAddress address = channel.getRemoteAddress();
+        if (address instanceof InetSocketAddress) {
+            final InetSocketAddress inetAddress = (InetSocketAddress) address;
+            final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
+            if (ipAddress.isIp4()) {
+                channelId = ipAddress.toString() + ':' + inetAddress.getPort();
+            } else {
+                channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
+            }
+        }
+    };
+
+    @Override
+    public String channelId() {
+        return channelId;
+    }
+
+    @Override
+    public final PccId getPccId() {
+        return this.pccId;
+    }
+
+    @Override
+    public final String getStringId() {
+        return this.pccId.toString();
+    }
+
+    @Override
+    public final void setPcVersion(PcepVersion pcepVersion) {
+        this.pcepVersion = pcepVersion;
+    }
+
+    @Override
+    public void setPcKeepAliveTime(byte keepAliveTime) {
+        this.keepAliveTime = keepAliveTime;
+    }
+
+    @Override
+    public void setPcDeadTime(byte deadTime) {
+        this.deadTime = deadTime;
+    }
+
+    @Override
+    public void setPcSessionId(byte sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    @Override
+    public void setIsSyncComplete(boolean value) {
+        this.isSyncComplete = value;
+    }
+
+    @Override
+    public boolean isSyncComplete() {
+        return isSyncComplete;
+    }
+
+    @Override
+    public final void handleMessage(PcepMessage m) {
+        this.pktStats.addInPacket();
+        this.agent.processPcepMessage(pccId, m);
+    }
+
+    @Override
+    public final boolean connectClient() {
+        return this.agent.addConnectedClient(pccId, this);
+    }
+
+    @Override
+    public final void removeConnectedClient() {
+        this.agent.removeConnectedClient(pccId);
+    }
+
+    @Override
+    public PcepFactory factory() {
+        return PcepFactories.getFactory(pcepVersion);
+    }
+
+    @Override
+    public boolean isHandshakeComplete() {
+        return isHandShakeComplete;
+    }
+
+    @Override
+    public final void setAgent(PcepAgent ag) {
+        if (this.agent == null) {
+            this.agent = ag;
+        }
+    }
+
+    @Override
+    public boolean isOptical() {
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("channel", channelId())
+                .add("pccId", getPccId())
+                .toString();
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepMessageDecoder.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepMessageDecoder.java
new file mode 100644
index 0000000..e918725
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepMessageDecoder.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+import java.util.LinkedList;
+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.onosproject.pcepio.protocol.PcepFactories;
+import org.onosproject.pcepio.protocol.PcepMessage;
+import org.onosproject.pcepio.protocol.PcepMessageReader;
+import org.onosproject.pcepio.util.HexDump;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Decode an pcep message from a Channel, for use in a netty pipeline.
+ */
+public class PcepMessageDecoder extends FrameDecoder {
+
+    protected static final Logger log = LoggerFactory.getLogger(PcepMessageDecoder.class);
+
+    @Override
+    protected Object decode(ChannelHandlerContext ctx, Channel channel,
+            ChannelBuffer buffer) throws Exception {
+        log.debug("Message received.");
+        if (!channel.isConnected()) {
+            log.info("Channel is not connected.");
+            // In testing, I see decode being called AFTER decode last.
+            // This check avoids that from reading corrupted frames
+            return null;
+        }
+
+        HexDump.pcepHexDump(buffer);
+
+        // Note that a single call to decode results in reading a single
+        // PcepMessage from the channel buffer, which is passed on to, and processed
+        // by, the controller (in PcepChannelHandler).
+        // This is different from earlier behavior (with the original pcepIO),
+        // where we parsed all the messages in the buffer, before passing on
+        // a list of the parsed messages to the controller.
+        // The performance *may or may not* not be as good as before.
+        PcepMessageReader<PcepMessage> reader = PcepFactories.getGenericReader();
+        List<PcepMessage> msgList = new LinkedList<PcepMessage>();
+
+        while (buffer.readableBytes() > 0) {
+            PcepMessage message = reader.readFrom(buffer);
+            msgList.add(message);
+        }
+        return msgList;
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepMessageEncoder.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepMessageEncoder.java
new file mode 100644
index 0000000..ae97221
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepMessageEncoder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+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.onosproject.pcepio.protocol.PcepMessage;
+import org.onosproject.pcepio.util.HexDump;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Encode an pcep message for output into a ChannelBuffer, for use in a
+ * netty pipeline.
+ */
+public class PcepMessageEncoder extends OneToOneEncoder {
+    protected static final Logger log = LoggerFactory.getLogger(PcepMessageEncoder.class);
+
+    @Override
+    protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
+        log.debug("Sending message");
+        if (!(msg instanceof List)) {
+            log.debug("Invalid msg.");
+            return msg;
+        }
+
+        @SuppressWarnings("unchecked")
+        List<PcepMessage> msglist = (List<PcepMessage>) msg;
+
+        ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
+
+        for (PcepMessage pm : msglist) {
+            pm.writeTo(buf);
+        }
+
+        HexDump.pcepHexDump(buf);
+
+        return buf;
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepPacketStatsImpl.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepPacketStatsImpl.java
new file mode 100644
index 0000000..61964a0
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepPacketStatsImpl.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+
+import org.onosproject.pcep.controller.PcepPacketStats;
+/**
+ * A representation of a packet context which allows any provider
+ * to view a packet in event, but may block the response to the
+ * event if blocked has been called. This packet context can be used
+ * to react to the packet in event with a packet out.
+ */
+public class PcepPacketStatsImpl implements PcepPacketStats {
+
+    private int inPacketCount;
+    private int outPacketCount;
+    private int wrongPacketCount;
+    private long time;
+
+    public PcepPacketStatsImpl() {
+        this.inPacketCount = 0;
+        this.outPacketCount = 0;
+        this.wrongPacketCount = 0;
+        this.time = 0;
+    }
+
+    @Override
+    public int outPacketCount() {
+        return outPacketCount;
+    }
+
+    @Override
+    public int inPacketCount() {
+        return inPacketCount;
+    }
+
+    @Override
+    public int wrongPacketCount() {
+        return wrongPacketCount;
+    }
+
+    /**
+     * Increments the received packet counter.
+     */
+    public void addInPacket() {
+        this.inPacketCount++;
+    }
+
+    /**
+     * Increments the sent packet counter.
+     */
+    public void addOutPacket() {
+        this.outPacketCount++;
+    }
+
+    /**
+     * Increments the sent packet counter by specified value.
+     *
+     * @param value of no of packets sent
+     */
+    public void addOutPacket(int value) {
+        this.outPacketCount = this.outPacketCount + value;
+    }
+
+    /**
+     * Increments the wrong packet counter.
+     */
+    public void addWrongPacket() {
+        this.wrongPacketCount++;
+    }
+
+    public void resetWrongPacket() {
+        this.wrongPacketCount = 0;
+    }
+
+    @Override
+    public long getTime() {
+        return this.time;
+    }
+
+    /**
+     * Sets the time value.
+     *
+     * @param time long value of time
+     */
+    public void setTime(long time) {
+        this.time = time;
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepPipelineFactory.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepPipelineFactory.java
new file mode 100644
index 0000000..f32b87a
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/PcepPipelineFactory.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 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.pcep.controller.impl;
+
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.handler.timeout.IdleStateHandler;
+import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
+import org.jboss.netty.util.ExternalResourceReleasable;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+
+/**
+ * Creates a ChannelPipeline for a server-side pcep channel.
+ */
+public class PcepPipelineFactory
+    implements ChannelPipelineFactory, ExternalResourceReleasable {
+
+    protected Controller controller;
+    static final Timer TIMER = new HashedWheelTimer();
+    protected IdleStateHandler idleHandler;
+    protected ReadTimeoutHandler readTimeoutHandler;
+    static final int DEFAULT_KEEP_ALIVE_TIME = 30;
+    static final int DEFAULT_DEAD_TIME = 120;
+    static final int DEFAULT_WAIT_TIME = 60;
+
+    public PcepPipelineFactory(Controller controller) {
+        super();
+        this.controller = controller;
+        this.idleHandler = new IdleStateHandler(TIMER, DEFAULT_DEAD_TIME, DEFAULT_KEEP_ALIVE_TIME, 0);
+        this.readTimeoutHandler = new ReadTimeoutHandler(TIMER, DEFAULT_WAIT_TIME);
+    }
+
+    @Override
+    public ChannelPipeline getPipeline() throws Exception {
+        PcepChannelHandler handler = new PcepChannelHandler(controller);
+
+        ChannelPipeline pipeline = Channels.pipeline();
+        pipeline.addLast("pcepmessagedecoder", new PcepMessageDecoder());
+        pipeline.addLast("pcepmessageencoder", new PcepMessageEncoder());
+        pipeline.addLast("idle", idleHandler);
+        pipeline.addLast("waittimeout", readTimeoutHandler);
+        pipeline.addLast("handler", handler);
+        return pipeline;
+    }
+
+    @Override
+    public void releaseExternalResources() {
+        TIMER.stop();
+    }
+}
diff --git a/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/package-info.java b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/package-info.java
new file mode 100644
index 0000000..589d345
--- /dev/null
+++ b/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 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 the PCEP controller subsystem.
+ */
+package org.onosproject.pcep.controller.impl;
diff --git a/pcep/pcepio/src/main/java/org/onosproject/pcepio/util/HexDump.java b/pcep/pcepio/src/main/java/org/onosproject/pcepio/util/HexDump.java
new file mode 100644
index 0000000..ad06793
--- /dev/null
+++ b/pcep/pcepio/src/main/java/org/onosproject/pcepio/util/HexDump.java
@@ -0,0 +1,38 @@
+package org.onosproject.pcepio.util;

+

+import org.jboss.netty.buffer.ChannelBuffer;

+import org.slf4j.Logger;

+import org.slf4j.LoggerFactory;

+

+public final class HexDump {

+    protected static final Logger log = LoggerFactory.getLogger(HexDump.class);

+

+    private HexDump() {

+    }

+

+    public static void pcepHexDump(ChannelBuffer buff) {

+

+        log.debug("==================== HEX DUMP ======================");

+        try {

+            byte[] yTemp;

+            yTemp = buff.array();

+

+            int iStartIndex = buff.readerIndex();

+            int iEndIndex = buff.writerIndex();

+            do {

+                StringBuilder sb = new StringBuilder();

+                for (int k = 0; (k < 16) && (iStartIndex < iEndIndex); ++k) {

+                    if (0 == k % 4) {

+                        sb.append(String.format(" ")); //blank after 4 bytes

+                    }

+                    sb.append(String.format("%02X ", yTemp[iStartIndex++]));

+                }

+                log.debug(sb.toString());

+            } while (iStartIndex < iEndIndex);

+        } catch (Exception e) {

+            log.error("[HexDump] Invalid buffer: " + e.toString());

+        }

+

+        log.debug("===================================================");

+    }

+}

diff --git a/pcep/pom.xml b/pcep/pom.xml
index 2ab2505..e3d470b 100755
--- a/pcep/pom.xml
+++ b/pcep/pom.xml
@@ -33,6 +33,7 @@
 
     <modules>
         <module>api</module>
+        <module>ctl</module>
         <module>pcepio</module>
     </modules>