[ONOS-6445] PPPoE Manager (move from onos/apps)

Change-Id: Ica3ebef3b2e0fcda1ae9e899b2870d05523cbb57
diff --git a/pppoe/api/pom.xml b/pppoe/api/pom.xml
new file mode 100755
index 0000000..e1ad9c0
--- /dev/null
+++ b/pppoe/api/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-pppoe</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.9.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-apps-pppoe-api</artifactId>
+
+    <packaging>bundle</packaging>
+    <description>PPPoE Management API</description>
+
+    <dependencies>
+    </dependencies>
+
+    <build>
+       <plugins>
+           <plugin>
+               <groupId>org.apache.felix</groupId>
+               <artifactId>maven-bundle-plugin</artifactId>
+               <extensions>true</extensions>
+           </plugin>
+       </plugins>
+    </build>
+
+</project>
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeClientInfo.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeClientInfo.java
new file mode 100755
index 0000000..219dc7c
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeClientInfo.java
@@ -0,0 +1,220 @@
+/*
+ * 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 Client.
+ * You may obtain a copy of the Client at
+ *
+ *     http://www.apache.org/clients/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Client is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Client for the specific language governing permissions and
+ * limitations under the Client.
+ */
+
+package org.onosproject.pppoe.api;
+
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+
+/**
+ * Implementation of PPPoE client information.
+ */
+public class PppoeClientInfo implements PppoeDeviceInfo {
+
+    private DeviceId deviceId;
+    private PppoeAdminState adminState;
+    private String serviceSpecificId;
+    private short sVlan;
+    private short cVlan;
+    private boolean endSession;
+    private boolean configured;
+    private String subscriber;
+    private PppoeSessionInfo session;
+    private PppoeDeviceType type;
+
+    public static enum PppoeAdminState {
+        ENABLE,
+        DISABLE
+    }
+
+    /**
+     * Generates a PPPoE client information instance.
+     */
+    public PppoeClientInfo() {
+        this.type = PppoeDeviceType.CLIENT;
+    }
+
+    /**
+     * Generates a PPPoE client information instance.
+     *
+     * @param state administrative state
+     * @param sVlan service provider VLAN
+     * @param cVlan customer VLAN
+     */
+    public PppoeClientInfo(PppoeAdminState state, short sVlan, short cVlan) {
+        this.type = PppoeDeviceType.CLIENT;
+        this.adminState = state;
+        this.sVlan = sVlan;
+        this.cVlan = cVlan;
+    }
+
+    /**
+     * Generates a PPPoE client information instance.
+     *
+     * @param state administrative state
+     */
+    public PppoeClientInfo(PppoeAdminState state) {
+        this.type = PppoeDeviceType.CLIENT;
+        this.adminState = state;
+        this.configured = true;
+    }
+
+    @Override
+    public PppoeDeviceType type() {
+        return type;
+    }
+
+    @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    @Override
+    public void setDeviceId(DeviceId deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    /**
+     * Returns administrative state.
+     *
+     * @return administrative state
+     */
+    public PppoeAdminState adminState() {
+        return adminState;
+    }
+
+    /**
+     * Sets administrative state.
+     *
+     * @param state administrative state
+     */
+    public void setAdminState(PppoeAdminState state) {
+        this.adminState = state;
+    }
+
+    /**
+     * Returns service specific ID.
+     *
+     * @return service specific ID
+     */
+    public String serviceSpecificId() {
+        return serviceSpecificId;
+    }
+
+    /**
+     * Sets service specific ID.
+     *
+     * @param ssid service specific ID
+     */
+    public void setServiceSpecificId(String ssid) {
+        this.serviceSpecificId = ssid;
+    }
+
+    /**
+     * Returns service provider VLAN.
+     *
+     * @return service provider VLAN
+     */
+    public short sVlan() {
+        return sVlan;
+    }
+
+    /**
+     * Returns customer VLAN.
+     *
+     * @return customer VLAN
+     */
+    public short cVlan() {
+        return cVlan;
+    }
+
+    /**
+     * Returns end session flag.
+     *
+     * @return end session flag
+     */
+    public boolean endSession() {
+        return endSession;
+    }
+
+    /**
+     * Sets end session flag.
+     *
+     * @param flag flag to end session
+     */
+    public void setEndSession(boolean flag) {
+        this.endSession = flag;
+    }
+
+    /**
+     * Returns configured flag.
+     *
+     * @return configured flag
+     */
+    public boolean configured() {
+        return configured;
+    }
+
+    /**
+     * Sets configured flag.
+     *
+     * @param flag flag for configured
+     */
+    public void setConfigured(boolean flag) {
+        this.configured = flag;
+    }
+
+    /**
+     * Sets associated subscriber information.
+     *
+     * @param info subscriber information
+     */
+    public void setSubscriber(String info) {
+        this.subscriber = info;
+    }
+
+    /**
+     * Clears information from remote.
+     */
+    public void clear() {
+        this.deviceId = null;
+        this.sVlan = 0;
+        this.cVlan = 0;
+        this.subscriber = null;
+    }
+
+    @Override
+    public String toString() {
+        if (deviceId == null) {
+            return toStringHelper("")
+                    .add("ssid", serviceSpecificId)
+                    .add("adminState", adminState.name().toLowerCase())
+                    .toString();
+        } else {
+            return toStringHelper("")
+                    .add("id", deviceId)
+                    .add("ssid", serviceSpecificId)
+                    .add("adminState", adminState.name().toLowerCase())
+                    .add("sVlanId", sVlan)
+                    .add("cVlanId", cVlan)
+                    .add("subscriber", subscriber)
+                    .toString();
+        }
+    }
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeClientInfoCodec.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeClientInfoCodec.java
new file mode 100755
index 0000000..9950fa3
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeClientInfoCodec.java
@@ -0,0 +1,63 @@
+/*
+ * 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.pppoe.api;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.pppoe.api.PppoeClientInfo.PppoeAdminState;
+
+
+/**
+ * Codec for encoding/decoding a PppoeClientInfo object to/from JSON.
+ */
+public final class PppoeClientInfoCodec extends JsonCodec<PppoeClientInfo> {
+
+    // JSON field names
+    private static final String ADMIN_STATE = "admin-state";
+    private static final String END_SESSION = "end-session";
+    private static final String SVLAN = "s-vlan";
+    private static final String CVLAN = "c-vlan";
+
+    @Override
+    public ObjectNode encode(PppoeClientInfo info, CodecContext context) {
+        checkNotNull(info, "PppoeClientInfo cannot be null");
+
+        final ObjectNode result = context.mapper().createObjectNode()
+                .put(ADMIN_STATE, info.adminState().name().toLowerCase())
+                .put(END_SESSION, info.endSession());
+
+        return result;
+    }
+
+    @Override
+    public PppoeClientInfo decode(ObjectNode json, CodecContext context) {
+        String state = json.path(ADMIN_STATE).asText();
+        Integer sVlan = new Integer(json.path(SVLAN).asInt());
+        Integer cVlan = new Integer(json.path(CVLAN).asInt());
+
+        checkNotNull(state);
+        checkNotNull(sVlan);
+        checkNotNull(cVlan);
+        PppoeAdminState adminState = PppoeAdminState.valueOf(state.toUpperCase());
+
+        return new PppoeClientInfo(adminState, sVlan.shortValue(), cVlan.shortValue());
+    }
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeDeviceInfo.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeDeviceInfo.java
new file mode 100755
index 0000000..756423d
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeDeviceInfo.java
@@ -0,0 +1,54 @@
+/*
+ * 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.pppoe.api;
+
+import org.onosproject.net.DeviceId;
+
+
+/**
+ * Implementation of PPPoE device information.
+ */
+public interface PppoeDeviceInfo {
+
+    static enum PppoeDeviceType {
+        SERVER,
+        CLIENT,
+        UNKNOWN
+    }
+
+    /**
+     * Returns device type.
+     *
+     * @return device type
+     */
+    public PppoeDeviceType type();
+
+    /**
+     * Returns device identifier.
+     *
+     * @return device identifier
+     */
+    public DeviceId deviceId();
+
+    /**
+     * Sets device identifier.
+     *
+     * @param deviceId device identifier
+     */
+    public void setDeviceId(DeviceId deviceId);
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeDeviceInfoCodec.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeDeviceInfoCodec.java
new file mode 100755
index 0000000..d3944bd
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeDeviceInfoCodec.java
@@ -0,0 +1,56 @@
+/*
+ * 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 Device.
+ * You may obtain a copy of the Device at
+ *
+ *     http://www.apache.org/devices/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Device is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Device for the specific language governing permissions and
+ * limitations under the Device.
+ */
+
+package org.onosproject.pppoe.api;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.pppoe.api.PppoeDeviceInfo.PppoeDeviceType;
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * Codec for encoding/decoding a PppoeDeviceInfo object to/from JSON.
+ */
+public final class PppoeDeviceInfoCodec extends JsonCodec<PppoeDeviceInfo> {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String TYPE = "type";
+
+
+    @Override
+    public PppoeDeviceInfo decode(ObjectNode json, CodecContext context) {
+        String strType = json.path(TYPE).asText();
+
+        checkNotNull(strType);
+        PppoeDeviceType type = PppoeDeviceType.valueOf(strType.toUpperCase());
+
+        if (type.equals(PppoeDeviceType.CLIENT)) {
+            return new PppoeClientInfo();
+        } else if (type.equals(PppoeDeviceType.SERVER)) {
+            return new PppoeServerInfo();
+        } else {
+            log.warn("decode(): Device Type is UNKNOWN");
+            return null;
+        }
+    }
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeServerInfo.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeServerInfo.java
new file mode 100755
index 0000000..ef2918d
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeServerInfo.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 Server.
+ * You may obtain a copy of the Server at
+ *
+ *     http://www.apache.org/servers/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Server is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Server for the specific language governing permissions and
+ * limitations under the Server.
+ */
+
+package org.onosproject.pppoe.api;
+
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+/**
+ * Implementation of PPPoE server information.
+ */
+public class PppoeServerInfo implements PppoeDeviceInfo {
+
+    private DeviceId deviceId;
+    private String radiusIp;
+    private String radiusKey;
+    private PppoeDeviceType type;
+
+    /**
+     * Generates a PPPoE server information instance.
+     */
+    public PppoeServerInfo() {
+        this.type = PppoeDeviceType.SERVER;
+    }
+
+    /**
+     * Generates a PPPoE server information instance.
+     *
+     * @param ip IP address of RADIUS server
+     * @param key shared secret key of RADIUS server
+     */
+    public PppoeServerInfo(String ip, String key) {
+        this.type = PppoeDeviceType.SERVER;
+        checkNotNull(ip);
+        checkNotNull(key);
+
+        this.radiusIp = ip;
+        this.radiusKey = key;
+    }
+
+    @Override
+    public PppoeDeviceType type() {
+        return type;
+    }
+
+    @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    @Override
+    public void setDeviceId(DeviceId deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    /**
+     * Returns IP address of RADIUS server.
+     *
+     * @return IP address of RADIUS server
+     */
+    public String radiusIp() {
+        return radiusIp;
+    }
+
+    /**
+     * Sets IP address of RADIUS server.
+     *
+     * @param ip IP address of RADIUS server
+     */
+    public void setRadiusIp(String ip) {
+        this.radiusIp = ip;
+    }
+
+    /**
+     * Returns shared secret key for RADIUS server.
+     *
+     * @return shared secret key for RADIUS server
+     */
+    public String radiusKey() {
+        return radiusKey;
+    }
+
+    /**
+     * Sets shared secret key for RADIUS server.
+     *
+     * @param key shared secret key for RADIUS server
+     */
+    public void setRadiusKey(String key) {
+        this.radiusKey = key;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper("")
+                .add("radiusIp", radiusIp)
+                .add("radiusKey", radiusKey)
+                .toString();
+    }
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeServerInfoCodec.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeServerInfoCodec.java
new file mode 100755
index 0000000..a9fff20
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeServerInfoCodec.java
@@ -0,0 +1,45 @@
+/*
+ * 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.pppoe.api;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+/**
+ * Codec for encoding/decoding a PppoeServerInfo object to/from JSON.
+ */
+public final class PppoeServerInfoCodec extends JsonCodec<PppoeServerInfo> {
+
+    private static final String RADIUS_IP = "radius-ip";
+    private static final String RADIUS_KEY = "radius-key";
+
+    @Override
+    public ObjectNode encode(PppoeServerInfo info, CodecContext context) {
+        checkNotNull(info, "PppoeServerInfo cannot be null");
+
+        final ObjectNode result = context.mapper().createObjectNode()
+                .put(RADIUS_IP, info.radiusIp())
+                .put(RADIUS_KEY, info.radiusKey());
+
+        return result;
+    }
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeService.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeService.java
new file mode 100755
index 0000000..8564387
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeService.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016-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.pppoe.api;
+
+import java.util.Collection;
+
+
+/**
+ * Service used to interact with PPPoE devices.
+ */
+public interface PppoeService {
+
+    /**
+     * Retrieves PPPoE server information.
+     *
+     * @return PPPoE server information
+     */
+    PppoeServerInfo getPppoeServer();
+
+    /**
+     * Retrieves PPPoE server information.
+     *
+     * @param paramName PPPoE server information paramName.
+     * @param paramValue PPPoE server information paramValue.
+     * @return true or false
+     */
+    boolean setPppoeServer(String paramName, String paramValue);
+
+    /**
+     * Retrieves all PPPoE client information.
+     *
+     * @param ssid service specific ID (ONU serial number)
+     * @return a list of PPPoE clients' information
+     */
+    Collection<PppoeClientInfo> getPppoeClients(String ssid);
+
+    /**
+     * Requests to change PPPoE client information.
+     *
+     * @param ssid service specific ID (ONU serial number)
+     * @param paramName PPPoE server information paramName.
+     * @param paramValue PPPoE server information paramValue.
+     * @return true or false
+     */
+    boolean setPppoeClient(String ssid, String paramName, String paramValue);
+
+    /**
+     * Retrieves all PPPoE session information.
+     *
+     * @return a list of PPPoE sessions' information
+     */
+    Collection<PppoeSessionInfo> getPppoeSessions();
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeSessionInfo.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeSessionInfo.java
new file mode 100755
index 0000000..3471cfc
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeSessionInfo.java
@@ -0,0 +1,159 @@
+/*
+ * 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 Session.
+ * You may obtain a copy of the Session at
+ *
+ *     http://www.apache.org/sessions/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Session is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Session for the specific language governing permissions and
+ * limitations under the Session.
+ */
+
+package org.onosproject.pppoe.api;
+
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+/**
+ * Implementation of PPPoE session information.
+ */
+public class PppoeSessionInfo {
+
+    private final DeviceId deviceId;
+    private final String serviceSpecificId;
+    private final String ip;
+    private final long rxPackets;
+    private final long txPackets;
+    private final long rxBytes;
+    private final long txBytes;
+
+    /**
+     * Generates a PPPoE session information instance.
+     *
+     * @param ip IP address of RADIUS session
+     * @param rxPackets number of packets received
+     * @param txPackets number of packets transmitted
+     * @param rxBytes number of bytes received
+     * @param txBytes number of bytes transmitted
+     */
+    public PppoeSessionInfo(String ip, long rxPackets, long txPackets, long rxBytes, long txBytes) {
+        checkNotNull(ip);
+        checkNotNull(rxPackets);
+        checkNotNull(txPackets);
+        checkNotNull(rxBytes);
+        checkNotNull(txBytes);
+
+        this.ip = ip;
+        this.rxPackets = rxPackets;
+        this.txPackets = txPackets;
+        this.rxBytes = rxBytes;
+        this.txBytes = txBytes;
+        this.deviceId = null;
+        this.serviceSpecificId = null;
+    }
+
+    /**
+     * Generates a PPPoE session information instance.
+     *
+     * @param sessionInfo PPPoE session information
+     * @param deviceId device identifier
+     * @param ssid service specific ID
+     */
+    public PppoeSessionInfo(PppoeSessionInfo sessionInfo, DeviceId deviceId, String ssid) {
+        checkNotNull(sessionInfo);
+        checkNotNull(deviceId);
+        checkNotNull(ssid);
+
+        this.ip = sessionInfo.ip();
+        this.rxPackets = sessionInfo.rxPackets();
+        this.txPackets = sessionInfo.txPackets();
+        this.rxBytes = sessionInfo.rxBytes();
+        this.txBytes = sessionInfo.txBytes();
+        this.deviceId = deviceId;
+        this.serviceSpecificId = ssid;
+    }
+
+    /**
+     * Returns device identifier.
+     *
+     * @return device identifier
+     */
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    /**
+     * Returns service specific ID.
+     *
+     * @return service specific ID
+     */
+    public String serviceSpecificId() {
+        return serviceSpecificId;
+    }
+
+    /**
+     * Returns assigned IP address.
+     *
+     * @return assigned IP address
+     */
+    public String ip() {
+        return ip;
+    }
+
+    /**
+     * Returns number of packets received.
+     *
+     * @return number of packets received
+     */
+    public long rxPackets() {
+        return rxPackets;
+    }
+
+    /**
+     * Returns number of packets transmitted.
+     *
+     * @return number of packets transmitted
+     */
+    public long txPackets() {
+        return txPackets;
+    }
+
+    /**
+     * Returns number of bytes received.
+     *
+     * @return number of bytes received
+     */
+    public long rxBytes() {
+        return rxBytes;
+    }
+
+    /**
+     * Returns number of bytes transmitted.
+     *
+     * @return number of bytes transmitted
+     */
+    public long txBytes() {
+        return txBytes;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper("")
+                .add("ssid", serviceSpecificId)
+                .add("ip", ip)
+                .add("rxPackets", rxPackets)
+                .add("txPackets", txPackets)
+                .add("rxBytes", rxBytes)
+                .add("txBytes", txBytes)
+                .toString();
+    }
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeSessionInfoCodec.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeSessionInfoCodec.java
new file mode 100755
index 0000000..063c45f
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/api/PppoeSessionInfoCodec.java
@@ -0,0 +1,50 @@
+/*
+ * 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.pppoe.api;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+/**
+ * Codec for encoding/decoding a PppoeSessionInfo object to/from JSON.
+ */
+public final class PppoeSessionInfoCodec extends JsonCodec<PppoeSessionInfo> {
+
+    private static final String IP = "ip";
+    private static final String RX_PACKETS = "rx-packets";
+    private static final String TX_PACKETS = "tx-packets";
+    private static final String RX_BYTES = "rx-bytes";
+    private static final String TX_BYTES = "tx-bytes";
+
+    @Override
+    public PppoeSessionInfo decode(ObjectNode json, CodecContext context) {
+        String ip = json.path(IP).asText();
+        long rxPackets = json.path(RX_PACKETS).asLong();
+        long txPackets = json.path(TX_PACKETS).asLong();
+        long rxBytes = json.path(RX_BYTES).asLong();
+        long txBytes = json.path(TX_BYTES).asLong();
+
+        checkNotNull(ip);
+
+        return new PppoeSessionInfo(ip, rxPackets, txPackets, rxBytes, txBytes);
+    }
+
+}
diff --git a/pppoe/api/src/main/java/org/onosproject/pppoe/api/package-info.java b/pppoe/api/src/main/java/org/onosproject/pppoe/api/package-info.java
new file mode 100755
index 0000000..95326d5
--- /dev/null
+++ b/pppoe/api/src/main/java/org/onosproject/pppoe/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.
+ */
+
+/**
+ * API for PPPoE Management application.
+ */
+package org.onosproject.pppoe.api;
diff --git a/pppoe/api/src/test/java/org/onosproject/pppoe/api/PppoeClientInfoTest.java b/pppoe/api/src/test/java/org/onosproject/pppoe/api/PppoeClientInfoTest.java
new file mode 100755
index 0000000..53d66ce
--- /dev/null
+++ b/pppoe/api/src/test/java/org/onosproject/pppoe/api/PppoeClientInfoTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.pppoe.api;
+
+import org.junit.Test;
+import org.onosproject.net.DeviceId;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+import static org.junit.Assert.*;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.pppoe.api.PppoeClientInfo.PppoeAdminState.*;
+
+/**
+ * Unit tests for PppoeClientInfo class.
+ */
+public class PppoeClientInfoTest {
+    private final short testsVlan = 16;
+    private final short testcVlan = 125;
+    private final PppoeClientInfo.PppoeAdminState state = ENABLE;
+    private final PppoeClientInfo client = new PppoeClientInfo(state, testsVlan, testcVlan);
+    private final String ssid = "0123456789abcd";
+
+    /**
+     * input DeviceId is null.
+     */
+    @Test
+    public void testtoStringDeviceidNull() throws Exception {
+        final String expectStr, outputStr;
+        // Set deviceId null.
+        client.setDeviceId(null);
+        client.setServiceSpecificId(ssid);
+        // Create expect string.
+        expectStr = toStringHelper("")
+                .add("ssid", ssid)
+                .add("adminState", state.name().toLowerCase())
+                .toString();
+        // Call toString().
+        outputStr = client.toString();
+        assertEquals("unexpected string", expectStr, outputStr);
+    }
+
+    /**
+     * input DeviceId is not null.
+     */
+    @Test
+    public void testtoStringDeviceidNotNull() throws Exception {
+        final String expectStr, outputStr;
+        final DeviceId deviceid = deviceId("rest:10.6.1.133:3000");
+        // Set deviceId not null.
+        client.setDeviceId(deviceid);
+        client.setServiceSpecificId(ssid);
+        // Create expect string.
+        expectStr = toStringHelper("")
+                .add("id", deviceid)
+                .add("ssid", ssid)
+                .add("adminState", state.name().toLowerCase())
+                .add("sVlanId", testsVlan)
+                .add("cVlanId", testcVlan)
+                .add("subscriber", null)
+                .toString();
+        // Call toString().
+        outputStr = client.toString();
+        assertEquals("unexpected string", expectStr, outputStr);
+    }
+
+}
diff --git a/pppoe/app/app.xml b/pppoe/app/app.xml
new file mode 100755
index 0000000..91c1c59
--- /dev/null
+++ b/pppoe/app/app.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<app name="org.onosproject.pppoe" origin="ON.Lab" version="${project.version}"
+     category="Traffic Steering" url="http://onosproject.org" title="PPPoE Mgmt App"
+     featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
+     features="${project.artifactId}" apps="org.onosproject.restsb,org.opencord.config,org.onosproject.olt">
+    <description>${project.description}</description>
+    <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
+    <artifact>mvn:${project.groupId}/onos-apps-pppoe-api/${project.version}</artifact>
+    <artifact>mvn:${project.groupId}/onos-apps-pppoe-driver/${project.version}</artifact>
+</app>
diff --git a/pppoe/app/features.xml b/pppoe/app/features.xml
new file mode 100755
index 0000000..24a52cc
--- /dev/null
+++ b/pppoe/app/features.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+    <feature name="${project.artifactId}" version="${project.version}"
+             description="${project.description}">
+        <feature>onos-api</feature>
+        <bundle>mvn:${project.groupId}/onos-apps-pppoe-api/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/onos-apps-pppoe-driver/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
+    </feature>
+</features>
diff --git a/pppoe/app/pom.xml b/pppoe/app/pom.xml
new file mode 100755
index 0000000..7a0ff8b
--- /dev/null
+++ b/pppoe/app/pom.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-pppoe</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.9.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-apps-pppoe-app</artifactId>
+    <packaging>bundle</packaging>
+    <description>PPPoE Management application</description>
+
+    <properties>
+        <onos.app.name>org.onosproject.pppoe</onos.app.name>
+        <onos.app.requires>
+            org.onosproject.restsb
+        </onos.app.requires>
+        <web.context>/onos/pppoe</web.context>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opencord</groupId>
+            <artifactId>cord-config</artifactId>
+            <version>1.1-rc1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opencord</groupId>
+            <artifactId>olt-api</artifactId>
+            <version>1.1-rc1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-apps-pppoe-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-apps-pppoe-driver</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-cli</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeBreakException.java b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeBreakException.java
new file mode 100755
index 0000000..553c885
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeBreakException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.pppoe;
+
+/**
+ * PPPoE for loop break exception.
+ *
+ */
+public class PppoeBreakException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public PppoeBreakException(String message) {
+        super(message);
+    }
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeClientManager.java b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeClientManager.java
new file mode 100755
index 0000000..a265696
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeClientManager.java
@@ -0,0 +1,361 @@
+/*
+ * 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.pppoe;
+
+import com.google.common.collect.ImmutableList;
+import org.onlab.packet.VlanId;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.DeviceId;
+import org.opencord.cordconfig.access.AccessDeviceData;
+import org.opencord.olt.AccessDeviceService;
+import org.onosproject.pppoe.api.PppoeDeviceInfo;
+import org.onosproject.pppoe.api.PppoeClientInfo;
+import org.onosproject.pppoe.api.PppoeSessionInfo;
+import org.onosproject.pppoe.driver.PppoeDeviceConfig;
+import org.slf4j.Logger;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
+import static org.onosproject.pppoe.api.PppoeClientInfo.PppoeAdminState;
+import static org.onosproject.pppoe.api.PppoeDeviceInfo.PppoeDeviceType;
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * PPPoE Management application to manage information of PPPoE client(s).
+ */
+public class PppoeClientManager {
+
+    private final Logger log = getLogger(getClass());
+
+    private final DeviceService deviceService;
+    private final DriverService driverService;
+    private final AccessDeviceService accessDeviceService;
+    private final MastershipService mastershipService;
+
+    private static final String ADMIN_STATE = "admin-state";
+    private static final PppoeAdminState DEFAULT_ADMIN_STATE = PppoeAdminState.ENABLE;
+
+    private ConcurrentMap<String, PppoeClientInfo> clients = new ConcurrentHashMap<>();
+
+    private boolean ssidFound;
+
+    /**
+     * Creates PPPoE Client Manager instance.
+     *
+     * @param deviceService {@link DeviceService} to be used
+     * @param driverService {@link DriverService} to be used
+     * @param mastershipService {@link MastershipService} to be used
+     * @param accessDeviceService {@link AccessDeviceService} to be used.
+     */
+    public PppoeClientManager(DeviceService deviceService, DriverService driverService,
+                              MastershipService mastershipService, AccessDeviceService accessDeviceService) {
+        this.deviceService = deviceService;
+        this.driverService = driverService;
+        this.mastershipService = mastershipService;
+        this.accessDeviceService = accessDeviceService;
+        this.ssidFound = false;
+    }
+
+    /**
+     * Configures/Changes PPPoE client information.
+     *
+     * @param ssid service specific ID
+     * @param paramName parameters name from user
+     * @param paramValue parameters value from user
+     * @return true or false
+     */
+    public boolean configClient(String ssid, String paramName, String paramValue) {
+        if (paramName.equals(ADMIN_STATE)) {
+            try {
+                PppoeAdminState state = PppoeAdminState.valueOf(paramValue.toUpperCase());
+
+                PppoeClientInfo clientInfo = clients.get(ssid);
+                if (clientInfo == null) {
+                    // Client configuration for undiscovered SSID
+                    clientInfo = new PppoeClientInfo(state);
+                    clientInfo.setServiceSpecificId(ssid);
+                    clients.put(ssid, clientInfo);
+                    return true;
+                }
+                clientInfo.setAdminState(state);
+                clientInfo.setConfigured(true);
+                if (clientInfo.deviceId() == null) {
+                    return true;
+                }
+                return updateClient(clientInfo);
+            } catch (Exception e) {
+                checkArgument(false, "Invalid parameter value %s", paramValue);
+                return false;
+            }
+        } else {
+            PppoeClientInfo clientInfo = clients.get(ssid);
+            if ((clientInfo == null) || (clientInfo.deviceId() == null)) {
+                log.error("No PPPoE client device for SSID {}", ssid);
+                return false;
+            }
+            clientInfo.setEndSession(true);
+            return updateClient(clientInfo);
+        }
+    }
+
+    /**
+     * Retrieves one or more PPPoE client information.
+     *
+     * @param ssid service specific ID if exists
+     * @return colletion of PPPoE client information
+     */
+    public Collection<PppoeClientInfo> getClients(String ssid) {
+        if (ssid == null) {
+            return ImmutableList.copyOf(clients.values());
+        }
+
+        PppoeClientInfo clientInfo = clients.get(ssid);
+        if (clientInfo == null) {
+            return Collections.emptyList();
+        }
+
+        List<PppoeClientInfo> clientList = new ArrayList<PppoeClientInfo>();
+        clientList.add(clientInfo);
+        return clientList;
+    }
+
+    /**
+     * Retrieves one or more PPPoE clients' session information.
+     *
+     * @return colletion of PPPoE clients' session information
+     */
+    public Collection<PppoeSessionInfo> getSessions() {
+        List<PppoeSessionInfo> sessionList = new ArrayList<PppoeSessionInfo>();
+
+        clients.values().forEach(clientInfo -> {
+            PppoeSessionInfo sessionInfo = getSession(clientInfo);
+            if (sessionInfo != null) {
+                sessionList.add(sessionInfo);
+            }
+        });
+        return sessionList;
+    }
+
+    /**
+     * Retrieves client information from PPPoE client, searches matching SSID,
+     * finds configuration information and updates remote PPPoE client.
+     *
+     * @param deviceInfo PPPoE device information
+     */
+    public void addClient(PppoeDeviceInfo deviceInfo) {
+        PppoeClientInfo clientInfo = getClient(deviceInfo.deviceId());
+        if (clientInfo == null) {
+            log.error("Failed to get client info from Device {}", deviceInfo.deviceId());
+            return;
+        }
+
+        if (!findServiceSpecificId(clientInfo)) {
+            log.warn("Could not find SSID for Device {} VLAN {}:{}",
+                    deviceInfo.deviceId(), clientInfo.sVlan(), clientInfo.cVlan());
+            return;
+        }
+
+        String ssid = clientInfo.serviceSpecificId();
+        clientInfo.setDeviceId(deviceInfo.deviceId());
+        PppoeClientInfo configInfo = clients.get(ssid);
+        if (configInfo == null) {
+            clientInfo.setAdminState(DEFAULT_ADMIN_STATE);
+        } else {
+            clients.remove(ssid);
+            clientInfo.setAdminState(configInfo.adminState());
+            clientInfo.setConfigured(true);
+        }
+        clients.put(ssid, clientInfo);
+
+        log.info("addClient(): Device {} SSID {} VLAN {}:{} Admin {}",
+                clientInfo.deviceId(), clientInfo.serviceSpecificId(),
+                clientInfo.sVlan(), clientInfo.cVlan(), clientInfo.adminState());
+        updateClient(clientInfo);
+    }
+
+    /**
+     * Removes PPPoE client information if automatically added during
+     * device discovery.
+     *
+     * @param deviceInfo PPPoE device information
+     */
+    public void removeClient(PppoeDeviceInfo deviceInfo) {
+        log.info("removeClient(): Device {}", deviceInfo.deviceId());
+        if ((deviceInfo != null) && deviceInfo.type().equals(PppoeDeviceType.CLIENT)) {
+            PppoeClientInfo clientInfo = (PppoeClientInfo) deviceInfo;
+            if ((clientInfo != null) && (!isNullOrEmpty(clientInfo.serviceSpecificId()))) {
+                if (clientInfo.configured()) {
+                    log.info("removeClient(): configured SSID {}",
+                            clientInfo.serviceSpecificId());
+                    // Clear information filled during device discovery
+                    clientInfo.clear();
+                } else {
+                    log.info("removeClient(): auto SSID {} VLAN {}:{}",
+                            clientInfo.serviceSpecificId(),
+                            clientInfo.sVlan(), clientInfo.cVlan());
+                    // Added during device discovery
+                    clients.remove(clientInfo.serviceSpecificId());
+                }
+            }
+        }
+    }
+
+    /**
+     * Searches matching SSID for PPPoE client.
+     *
+     * @param clientInfo PPPoE client information
+     * @return true or false
+     */
+    private boolean findServiceSpecificId(PppoeClientInfo clientInfo) {
+        Map<DeviceId, AccessDeviceData> olts = accessDeviceService.fetchOlts();
+        Collection<Map.Entry<ConnectPoint, VlanId>> subscribers = accessDeviceService.getSubscribers();
+        setSsidFound(false);
+
+        olts.keySet().forEach(did -> {
+            if (!getSsidFound() && (olts.get(did).vlan().toShort() == clientInfo.sVlan())) {
+                String oltId = did.toString();
+                subscribers.forEach(subscriber -> {
+                    ConnectPoint cp = subscriber.getKey();
+                    if (!getSsidFound() && oltId.equals(cp.elementId().toString()) &&
+                            (subscriber.getValue().toShort() == clientInfo.cVlan())) {
+                        deviceService.getPorts(did).forEach(port -> {
+                            if (!getSsidFound() && (port.number().toLong() == cp.port().toLong())) {
+                                String ssid = port.annotations().value(PORT_NAME);
+                                clientInfo.setServiceSpecificId(ssid);
+                                clientInfo.setSubscriber(cp.toString());
+                                // SSID found
+                                log.info("Found SSID: {}", clientInfo.serviceSpecificId());
+                                setSsidFound(true);
+                            }
+                        });
+                    }
+                });
+            }
+        });
+        return getSsidFound();
+    }
+
+    /**
+     * Retrieves PPPoE client information from remote device.
+     *
+     * @param deviceId PPPoE device identifier
+     * @return PPPoE client information
+     */
+    private PppoeClientInfo getClient(DeviceId deviceId) {
+        if (deviceId == null) {
+            return null;
+        }
+        if (!mastershipService.isLocalMaster(deviceId)) {
+            log.warn("Not master for Device {}", deviceId);
+            return null;
+        }
+
+        DriverHandler handler = driverService.createHandler(deviceId);
+        PppoeDeviceConfig behaviour = handler.behaviour(PppoeDeviceConfig.class);
+
+        PppoeClientInfo clientInfo = behaviour.getClient();
+        if (clientInfo == null) {
+            log.error("getClient() failed: Device {}", deviceId);
+        }
+        return clientInfo;
+    }
+
+    /**
+     * Retrieves PPPoE client session information from remote device.
+     *
+     * @param clientInfo PPPoE client information
+     * @return PPPoE session information
+     */
+    private PppoeSessionInfo getSession(PppoeClientInfo clientInfo) {
+        if (clientInfo.deviceId() == null) {
+            return null;
+        }
+        if (!mastershipService.isLocalMaster(clientInfo.deviceId())) {
+            log.warn("Not master for Device {}", clientInfo.deviceId());
+            return null;
+        }
+
+        DriverHandler handler = driverService.createHandler(clientInfo.deviceId());
+        PppoeDeviceConfig behaviour = handler.behaviour(PppoeDeviceConfig.class);
+
+        PppoeSessionInfo sessionInfo = behaviour.readSessionData();
+        if (sessionInfo == null) {
+            log.error("getSession() failed: Device {}", clientInfo.deviceId());
+            return null;
+        }
+
+        sessionInfo = new PppoeSessionInfo(sessionInfo, clientInfo.deviceId(), clientInfo.serviceSpecificId());
+        log.info("Session {}", sessionInfo);
+        return sessionInfo;
+    }
+
+    /**
+     * Changes PPPoE client information of remote device.
+     *
+     * @param clientInfo PPPoE client information
+     * @return true or false
+     */
+    private boolean updateClient(PppoeClientInfo clientInfo) {
+        if (!mastershipService.isLocalMaster(clientInfo.deviceId())) {
+            log.warn("Not master for Device {}", clientInfo.deviceId());
+            clientInfo.setEndSession(false);
+            return false;
+        }
+
+        DriverHandler handler = driverService.createHandler(clientInfo.deviceId());
+        PppoeDeviceConfig behaviour = handler.behaviour(PppoeDeviceConfig.class);
+
+        boolean result = behaviour.configClient(clientInfo);
+        if (!result) {
+            log.error("configClient() failed: Device {}", clientInfo.deviceId());
+        }
+        return result;
+    }
+
+    /**
+     * Set state of Searches matching SSID for PPPoE client.
+     *
+     * @param found state of SSID Searching
+     */
+    private void setSsidFound(boolean found) {
+        ssidFound = found;
+    }
+
+    /**
+     * Get state of Searches matching SSID for PPPoE client.
+     *
+     * @return true or false
+     */
+    private boolean getSsidFound() {
+        return ssidFound;
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeDeviceManager.java b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeDeviceManager.java
new file mode 100755
index 0000000..948551e
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeDeviceManager.java
@@ -0,0 +1,67 @@
+/*
+ * 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.pppoe;
+
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.pppoe.api.PppoeDeviceInfo;
+import org.onosproject.pppoe.driver.PppoeDeviceConfig;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * PPPoE Management application to manage information of PPPoE device(s).
+ */
+public class PppoeDeviceManager {
+
+    private final Logger log = getLogger(getClass());
+    private final DriverService driverService;
+
+
+    /**
+     * Creates PPPoE Device Manager instance.
+     *
+     * @param driverService {@link DriverService} to be used
+     */
+    public PppoeDeviceManager(DriverService driverService) {
+        this.driverService = driverService;
+    }
+
+    /**
+     * Retrieves basic PPPoE device information from remote.
+     *
+     * @param deviceId device identifier
+     * @return PPPoE device information
+     */
+    public PppoeDeviceInfo getDeviceInfo(DeviceId deviceId) {
+        DriverService driverService = DefaultServiceDirectory.getService(DriverService.class);
+
+        DriverHandler handler = driverService.createHandler(deviceId);
+        PppoeDeviceConfig behaviour = handler.behaviour(PppoeDeviceConfig.class);
+
+        PppoeDeviceInfo deviceInfo = behaviour.getDevice();
+        if (deviceInfo == null) {
+            log.warn("getDevice() failed for {}", deviceId);
+        }
+        return deviceInfo;
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeManager.java b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeManager.java
new file mode 100755
index 0000000..a67440d
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeManager.java
@@ -0,0 +1,339 @@
+/*
+ * 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.pppoe;
+
+import com.google.common.collect.ImmutableList;
+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.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.CoreService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.MastershipRole;
+import org.opencord.olt.AccessDeviceService;
+import org.onosproject.pppoe.api.PppoeService;
+import org.onosproject.pppoe.api.PppoeDeviceInfo;
+import org.onosproject.pppoe.api.PppoeClientInfo;
+import org.onosproject.pppoe.api.PppoeServerInfo;
+import org.onosproject.pppoe.api.PppoeSessionInfo;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onosproject.pppoe.api.PppoeDeviceInfo.PppoeDeviceType;
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * PPPoE Management application.
+ */
+@Component(immediate = true)
+@Service
+public class PppoeManager implements PppoeService {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DriverService driverService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MastershipService mastershipService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected AccessDeviceService accessDeviceService;
+
+    private static final String DEFAULT_RADIUS_SERVER_IP = "192.168.122.150";
+    @Property(name = RADIUS_IP_PROPERTY_NAME, value = DEFAULT_RADIUS_SERVER_IP,
+            label = "RADIUS server IP address")
+    protected String radiusServer = DEFAULT_RADIUS_SERVER_IP;
+
+    private static final String DEFAULT_RADIUS_SHARED_KEY = "default";
+    @Property(name = RADIUS_KEY_PROPERTY_NAME, value = DEFAULT_RADIUS_SHARED_KEY,
+            label = "RADIUS shared secret key")
+    protected String radiusKey = DEFAULT_RADIUS_SHARED_KEY;
+
+    private static final long DEFAULT_POLL_DELAY_SECONDS = 1;
+
+    private static final int DEFAULT_POLL_INTERVAL_SECONDS = 20;
+    @Property(name = POLL_INTERVAL_PROPERTY_NAME, intValue = DEFAULT_POLL_INTERVAL_SECONDS,
+            label = "Frequency (in seconds) for polling client devices")
+    protected int pollIntervalSeconds = DEFAULT_POLL_INTERVAL_SECONDS;
+
+    private static final String RADIUS_IP_PROPERTY_NAME = "radiusIp";
+    private static final String RADIUS_KEY_PROPERTY_NAME = "radiusKey";
+    private static final String POLL_INTERVAL_PROPERTY_NAME = "pollInterval";
+    private static final String PPPOE_APPLICATION_NAME = "org.onosproject.pppoe";
+    private static final String PPPOE_DRIVER_NAME = "rest-pppoe";
+    private static final String DEVICE_PROTOCOL_REST = "REST";
+
+    private ScheduledExecutorService pollExecutor = newSingleThreadScheduledExecutor();
+
+    private InternalDeviceListener deviceListener = new InternalDeviceListener();
+    private PppoeDeviceManager deviceManager;
+    private PppoeClientManager clientManager;
+    private PppoeServerManager serverManager;
+
+    // Devices available & active upon discovery
+    private ConcurrentMap<DeviceId, PppoeDeviceInfo> devices = new ConcurrentHashMap<>();
+
+
+    @Activate
+    public void activate(ComponentContext context) {
+        cfgService.registerProperties(getClass());
+        readComponentConfiguration(context);
+
+        deviceManager = new PppoeDeviceManager(driverService);
+        serverManager = new PppoeServerManager(driverService, radiusServer, radiusKey);
+        clientManager = new PppoeClientManager(deviceService, driverService,
+                                mastershipService, accessDeviceService);
+
+        ScheduledFuture<?> pollTask =
+                pollExecutor.scheduleAtFixedRate(new InternalPollTask(),
+                DEFAULT_POLL_DELAY_SECONDS, pollIntervalSeconds, TimeUnit.SECONDS);
+
+        coreService.registerApplication(PPPOE_APPLICATION_NAME);
+        deviceService.addListener(deviceListener);
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        deviceService.removeListener(deviceListener);
+        cfgService.unregisterProperties(getClass(), false);
+        pollExecutor.shutdown();
+
+        log.info("Stopped");
+    }
+
+    @Override
+    public PppoeServerInfo getPppoeServer() {
+        return serverManager.getServer();
+    }
+
+    @Override
+    public boolean setPppoeServer(String paramName, String paramValue) {
+        return serverManager.configServer(paramName, paramValue);
+    }
+
+    @Override
+    public Collection<PppoeClientInfo> getPppoeClients(String ssid) {
+        return clientManager.getClients(ssid);
+    }
+
+    @Override
+    public boolean setPppoeClient(String ssid, String paramName, String paramValue) {
+        return clientManager.configClient(ssid, paramName, paramValue);
+    }
+
+    @Override
+    public Collection<PppoeSessionInfo> getPppoeSessions() {
+        return clientManager.getSessions();
+    }
+
+    /**
+     * Extracts properties from the component configuration context.
+     * (on activation only)
+     *
+     * @param context the component context
+     */
+    private void readComponentConfiguration(ComponentContext context) {
+        if (context == null) {
+            log.info("No component configuration");
+            // All configurable parameters use default values
+            return;
+        }
+
+        Dictionary<?, ?> properties = context.getProperties();
+        String propertyName;
+        String strValue;
+        int intValue;
+
+        propertyName = RADIUS_IP_PROPERTY_NAME;
+        strValue = Tools.get(properties, propertyName);
+        if (!isNullOrEmpty(strValue)) {
+            radiusServer = strValue;
+        }
+        log.info("Settings: {} = {}", propertyName, radiusServer);
+
+        propertyName = RADIUS_KEY_PROPERTY_NAME;
+        strValue = Tools.get(properties, propertyName);
+        if (!isNullOrEmpty(strValue)) {
+            radiusKey = strValue;
+        }
+        log.info("Settings: {} = {}", propertyName, radiusKey);
+
+        propertyName = POLL_INTERVAL_PROPERTY_NAME;
+        strValue = Tools.get(properties, propertyName);
+        intValue = isNullOrEmpty(strValue) ?
+                pollIntervalSeconds : Integer.parseInt(strValue.trim());
+        pollIntervalSeconds = intValue;
+        log.info("Settings: {} = {}", propertyName, pollIntervalSeconds);
+    }
+
+    /**
+     * Handle PPPOE device that became available.
+     *
+     * @param deviceId device identifier
+     */
+    private void handleDeviceAvailable(DeviceId deviceId) {
+        checkNotNull(deviceId);
+        pollDevice(deviceId, true);
+    }
+
+    /**
+     * Poll PPPOE device to retrieve information and update.
+     *
+     * @param deviceId device identifier
+     */
+    private synchronized void pollDevice(DeviceId deviceId, boolean event) {
+        PppoeDeviceInfo deviceInfo = deviceManager.getDeviceInfo(deviceId);
+        if (deviceInfo != null) {
+            // Mark the device available
+            devices.put(deviceId, deviceInfo);
+            log.info("pollDevice(): Device {} Type {}",
+                    deviceId, deviceInfo.type());
+            if (deviceInfo.type() == PppoeDeviceType.SERVER) {
+                serverManager.addServer(deviceInfo);
+            } else {
+                clientManager.addClient(deviceInfo);
+            }
+        }
+    }
+
+    /**
+     * Remove unavailable PPPoE device.
+     *
+     * @param deviceId PPPoE device identifier
+     */
+    private void removeDevice(DeviceId deviceId) {
+        synchronized (devices) {
+            PppoeDeviceInfo deviceInfo = devices.get(deviceId);
+            if ((deviceInfo != null) && (deviceInfo.type().equals(PppoeDeviceType.CLIENT))) {
+                clientManager.removeClient(deviceInfo);
+            }
+            devices.remove(deviceId);
+        }
+    }
+
+    /**
+     * Internal listener for device service events.
+     */
+    private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public void event(DeviceEvent event) {
+            DeviceId deviceId = event.subject().id();
+            Driver driver = driverService.getDriver(deviceId);
+
+            if (!driver.name().equals(PPPOE_DRIVER_NAME)) {
+                log.debug("event(): Ignore for other driver: device {} {}", driver.name(), deviceId);
+                return;
+            }
+
+            Device device = deviceService.getDevice(deviceId);
+            if (device == null) {
+                log.warn("event(): Unknown device {}", deviceId);
+                return;
+            }
+            if (device.annotations() == null) {
+                log.warn("event(): No annotations {}", deviceId);
+                return;
+            }
+            String protocol = device.annotations().value(AnnotationKeys.PROTOCOL);
+            if ((protocol == null) || (!protocol.equals(DEVICE_PROTOCOL_REST))) {
+                // Ignore non-REST device.
+                return;
+            }
+
+            log.info("event(): {} {} {} {}", deviceId, event.type(),
+                deviceService.isAvailable(deviceId), deviceService.getRole(deviceId));
+            switch (event.type()) {
+                case DEVICE_ADDED:
+                case DEVICE_AVAILABILITY_CHANGED:
+                    if ((deviceService.isAvailable(deviceId))
+                            && (deviceService.getRole(deviceId).equals(MastershipRole.MASTER))) {
+                        handleDeviceAvailable(deviceId);
+                    } else {
+                        // Mark device unavailable
+                        removeDevice(deviceId);
+                        log.info("event(): Device removed: {}", deviceId);
+                    }
+                    break;
+                default:
+                    log.warn("event(): Unsupported event {} {}", deviceId, event.type());
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Implements PPPoE client device poll task to find SSID based
+     * on retrieved information from client.
+     */
+    private final class InternalPollTask implements Runnable {
+
+        @Override
+        public void run() {
+            List<PppoeDeviceInfo> deviceInfoList = ImmutableList.copyOf(devices.values());
+            for (PppoeDeviceInfo deviceInfo : deviceInfoList) {
+                log.debug("run(): {}", deviceInfo.deviceId());
+                if (deviceInfo.type().equals(PppoeDeviceType.CLIENT)) {
+                    PppoeClientInfo clientInfo = (PppoeClientInfo) deviceInfo;
+                    if ((clientInfo == null) || (isNullOrEmpty(clientInfo.serviceSpecificId()))) {
+                        // Retry to collect client info
+                        pollDevice(deviceInfo.deviceId(), false);
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeServerManager.java b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeServerManager.java
new file mode 100755
index 0000000..428b5bc
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/PppoeServerManager.java
@@ -0,0 +1,121 @@
+/*
+ * 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.pppoe;
+
+import com.google.common.net.InetAddresses;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.pppoe.api.PppoeDeviceInfo;
+import org.onosproject.pppoe.api.PppoeServerInfo;
+import org.onosproject.pppoe.driver.PppoeDeviceConfig;
+import org.slf4j.Logger;
+
+import java.net.InetAddress;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import static com.google.common.base.Preconditions.checkArgument;
+
+
+/**
+ * PPPoE Management application to manage information of PPPoE server.
+ */
+public class PppoeServerManager {
+
+    private final Logger log = getLogger(getClass());
+
+    private final DriverService driverService;
+
+    private static final String RADIUS_IP = "radius-ip";
+
+    private PppoeServerInfo serverInfo;
+
+
+    /**
+     * Creates PPPoE Server Manager instance.
+     *
+     * @param driverService {@link DriverService} to be used
+     * @param radiusIp radius server IP address
+     * @param radiusKey radius server shared secret key
+     */
+    public PppoeServerManager(DriverService driverService, String radiusIp, String radiusKey) {
+        this.driverService = driverService;
+        serverInfo = new PppoeServerInfo(radiusIp, radiusKey);
+    }
+
+    /**
+     * Retrieves PPPoE server information.
+     *
+     * @return PPPoE server information
+     */
+    public PppoeServerInfo getServer() {
+        return serverInfo;
+    }
+
+    /**
+     * Configures/Changes PPPoE server information.
+     *
+     * @param paramName parameters name to be changed
+     * @param paramValue parameters value to be changed
+     * @return true or false
+     */
+    public boolean configServer(String paramName, String paramValue) {
+        if (paramName.equals(RADIUS_IP)) {
+            try {
+                InetAddress inetAddress = InetAddresses.forString(paramValue);
+            } catch (IllegalArgumentException e) {
+                checkArgument(false, "Invalid IP address string %s", paramValue);
+            }
+            serverInfo.setRadiusIp(paramValue);
+        } else {
+            serverInfo.setRadiusKey(paramValue);
+        }
+        if (serverInfo.deviceId() != null) {
+            return updateServer(serverInfo);
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Add PPPoE server device.
+     *
+     * @param deviceInfo PPPoE device information
+     * @return true or false
+     */
+    public boolean addServer(PppoeDeviceInfo deviceInfo) {
+        serverInfo.setDeviceId(deviceInfo.deviceId());
+        return updateServer(serverInfo);
+    }
+
+    /**
+     * Changes PPPoE server information of remote device.
+     *
+     * @param serverInfo PPPoE server information
+     * @return true or false
+     */
+    private boolean updateServer(PppoeServerInfo serverInfo) {
+        DriverHandler handler = driverService.createHandler(serverInfo.deviceId());
+        PppoeDeviceConfig behaviour = handler.behaviour(PppoeDeviceConfig.class);
+
+        boolean result = behaviour.configServer(serverInfo);
+        if (!result) {
+            log.error("configServer() failed: Device {}", serverInfo.deviceId());
+        }
+        return result;
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeConfigClientCommand.java b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeConfigClientCommand.java
new file mode 100755
index 0000000..a1a30e6
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeConfigClientCommand.java
@@ -0,0 +1,88 @@
+/*
+ * 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.pppoe.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.pppoe.api.PppoeService;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+
+/**
+ * Changes/configures PPPoE client parameters.
+ */
+@Command(scope = "onos", name = "pppoe-client-config",
+        description = "Changes/configures PPPoE client parameters")
+public class PppoeConfigClientCommand extends AbstractShellCommand {
+
+    private static final String COLON = ":";
+    private static final String ADMIN_STATE = "admin-state";
+    private static final String END_SESSION = "end-session";
+    private static final Map<String, Integer> PPPOE_CLIENT_PARAMS = new HashMap<String, Integer>() {
+        {
+            put(ADMIN_STATE, 2);
+            put(END_SESSION, 1);
+        }
+    };
+
+    @Argument(index = 0, name = "ssid", description = "Service Specific ID",
+            required = true, multiValued = false)
+    String ssid = null;
+
+    @Argument(index = 1, name = "target", description = "parameter[:value]",
+            required = true, multiValued = false)
+    String target = null;
+
+    private static final Pattern PATTERN_SSID = Pattern.compile("[0-9a-fA-F]+");
+
+
+    @Override
+    protected void execute() {
+        PppoeService service = AbstractShellCommand.get(PppoeService.class);
+
+        Matcher matcher = PATTERN_SSID.matcher(ssid);
+        checkArgument(matcher.matches(), "Containing non-hexadecimal SSID %s", ssid);
+
+        boolean flag = ((ssid.length() % 2) == 0);
+        checkArgument(flag, "Invalid odd length SSID %s", ssid);
+
+        short argc = 0;
+
+        String[] data = target.split(COLON);
+        String paramName = data[argc++];
+        checkArgument(PPPOE_CLIENT_PARAMS.containsKey(paramName),
+                "Unsupported parameter %s", paramName);
+
+        checkArgument((data.length == PPPOE_CLIENT_PARAMS.get(paramName)),
+                "Invalid number of inputs %s", target);
+
+        String paramValue = "";
+        if (paramName.equals(ADMIN_STATE)) {
+            paramValue = data[argc++];
+        }
+        service.setPppoeClient(ssid, paramName, paramValue);
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeConfigServerCommand.java b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeConfigServerCommand.java
new file mode 100755
index 0000000..9e2c2d2
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeConfigServerCommand.java
@@ -0,0 +1,68 @@
+/*
+ * 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.pppoe.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.pppoe.api.PppoeService;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Changes/configures PPPoE server parameters.
+ */
+@Command(scope = "onos", name = "pppoe-server-config",
+        description = "Changes/configures PPPoE server parameters")
+public class PppoeConfigServerCommand extends AbstractShellCommand {
+
+    private static final String COLON = ":";
+    private static final String RADIUS_IP = "radius-ip";
+    private static final String RADIUS_KEY = "radius-key";
+    private static final Map<String, Integer> PPPOE_SERVER_PARAMS = new HashMap<String, Integer>() {
+        {
+            put(RADIUS_IP, 2);
+            put(RADIUS_KEY, 2);
+        }
+    };
+
+    @Argument(index = 0, name = "target", description = "parameter:value",
+            required = true, multiValued = false)
+    String target = null;
+
+    @Override
+    protected void execute() {
+        PppoeService service = AbstractShellCommand.get(PppoeService.class);
+
+        String[] data = target.split(COLON);
+        short argc = 0;
+
+        String paramName = data[argc++];
+        checkArgument(PPPOE_SERVER_PARAMS.containsKey(paramName),
+                "Unsupported parameter %s", paramName);
+
+        checkArgument((data.length == PPPOE_SERVER_PARAMS.get(paramName)),
+                "Invalid number of inputs %s", target);
+        String paramValue = data[argc++];
+
+        service.setPppoeServer(paramName, paramValue);
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetClientsCommand.java b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetClientsCommand.java
new file mode 100755
index 0000000..3622608
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetClientsCommand.java
@@ -0,0 +1,59 @@
+/*
+ * 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.pppoe.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.pppoe.api.PppoeService;
+import org.onosproject.pppoe.api.PppoeClientInfo;
+
+import java.util.Collection;
+
+
+/**
+ * Lists one or more PPPoE client information.
+ */
+@Command(scope = "onos", name = "pppoe-client-info",
+        description = "Lists one or more PPPoE client information")
+public class PppoeGetClientsCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "ssid", description = "Service Specific ID",
+            required = false, multiValued = false)
+    String ssid = null;
+
+    @Override
+    protected void execute() {
+
+        PppoeService service = AbstractShellCommand.get(PppoeService.class);
+
+        Collection<PppoeClientInfo> clients = service.getPppoeClients(ssid);
+
+        if (ssid == null) {
+            clients.forEach(client -> {
+                 print(client.toString());
+            });
+        } else {
+            clients.forEach(client -> {
+                 if (ssid.equals(client.serviceSpecificId())) {
+                     print(client.toString());
+                 }
+            });
+        }
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetServerCommand.java b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetServerCommand.java
new file mode 100755
index 0000000..240392b
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetServerCommand.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.pppoe.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.pppoe.api.PppoeService;
+import org.onosproject.pppoe.api.PppoeServerInfo;
+
+
+/**
+ * Lists PPPoE server information.
+ */
+@Command(scope = "onos", name = "pppoe-server-info",
+        description = "Lists PPPoE server information")
+public class PppoeGetServerCommand extends AbstractShellCommand {
+
+    @Override
+    protected void execute() {
+
+        PppoeService service = AbstractShellCommand.get(PppoeService.class);
+
+        PppoeServerInfo server = service.getPppoeServer();
+        print(server.toString());
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetSessionsCommand.java b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetSessionsCommand.java
new file mode 100755
index 0000000..17f29cf
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/PppoeGetSessionsCommand.java
@@ -0,0 +1,59 @@
+/*
+ * 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.pppoe.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.pppoe.api.PppoeService;
+import org.onosproject.pppoe.api.PppoeSessionInfo;
+
+import java.util.Collection;
+
+
+/**
+ * Lists one or more PPPoE session information.
+ */
+@Command(scope = "onos", name = "pppoe-session-info",
+        description = "Lists one or more PPPoE session information")
+public class PppoeGetSessionsCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "ssid", description = "Service Specific ID",
+            required = false, multiValued = false)
+    String ssid = null;
+
+    @Override
+    protected void execute() {
+
+        PppoeService service = AbstractShellCommand.get(PppoeService.class);
+
+        Collection<PppoeSessionInfo> sessions = service.getPppoeSessions();
+
+        if (ssid == null) {
+            sessions.forEach(session -> {
+                 print(session.toString());
+            });
+        } else {
+            sessions.forEach(session -> {
+                 if (ssid.equals(session.serviceSpecificId())) {
+                     print(session.toString());
+                 }
+            });
+        }
+    }
+
+}
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/cli/package-info.java b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/package-info.java
new file mode 100755
index 0000000..5f4dc47
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/cli/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.
+ */
+
+/**
+ * CLI for PPPoE Management Application.
+ */
+package org.onosproject.pppoe.cli;
diff --git a/pppoe/app/src/main/java/org/onosproject/pppoe/package-info.java b/pppoe/app/src/main/java/org/onosproject/pppoe/package-info.java
new file mode 100755
index 0000000..36af864
--- /dev/null
+++ b/pppoe/app/src/main/java/org/onosproject/pppoe/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-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.
+ */
+
+/**
+ * Service for PPPoE Management Application.
+ */
+package org.onosproject.pppoe;
diff --git a/pppoe/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/pppoe/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100755
index 0000000..b512127
--- /dev/null
+++ b/pppoe/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ Copyright 2016-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.
+  -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.onosproject.pppoe.cli.PppoeGetClientsCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.pppoe.cli.PppoeConfigClientCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.pppoe.cli.PppoeGetServerCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.pppoe.cli.PppoeConfigServerCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.pppoe.cli.PppoeGetSessionsCommand"/>
+        </command>
+    </command-bundle>
+
+</blueprint>
diff --git a/pppoe/app/src/test/java/org/onosproject/pppoe/PppoeClientManagerTest.java b/pppoe/app/src/test/java/org/onosproject/pppoe/PppoeClientManagerTest.java
new file mode 100755
index 0000000..4b889ba
--- /dev/null
+++ b/pppoe/app/src/test/java/org/onosproject/pppoe/PppoeClientManagerTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.pppoe;
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.mastership.MastershipService;
+import org.opencord.olt.AccessDeviceService;
+
+import org.onosproject.pppoe.api.PppoeDeviceInfo;
+import org.onosproject.pppoe.api.PppoeClientInfo;
+import org.onosproject.pppoe.api.PppoeServerInfo;
+import org.onosproject.pppoe.api.PppoeSessionInfo;
+
+import java.util.Collection;
+
+import static org.junit.Assert.*;
+import static org.onosproject.pppoe.api.PppoeDeviceInfo.PppoeDeviceType.*;
+import static org.onosproject.pppoe.api.PppoeClientInfo.PppoeAdminState;
+
+/**
+ * Unit tests for PppoeClientManager class.
+ */
+public class PppoeClientManagerTest {
+    private DriverService driverService;
+    private DeviceService deviceService;
+    private MastershipService mastershipService;
+    private AccessDeviceService accessDeviceService;
+    private PppoeClientManager clientManager;
+    private String ssid;
+
+    private static final String RADIUSSERVER = "192.168.122.150";
+    private static final String RADIUSKEY = "default";
+
+    @Before
+    public void setUp() throws Exception {
+        clientManager = new PppoeClientManager(deviceService, driverService, mastershipService, accessDeviceService);
+        ssid = "0123456789abcd";
+    }
+
+    /**
+     * Config client when session is not established.
+     */
+    @Test
+    public void testconfigClientSessionNotEstablish() throws Exception {
+        assertTrue("Incorrect response", clientManager.configClient(ssid, "admin-state", "enable"));
+        assertFalse("Incorrect response", clientManager.configClient(ssid, "end-session", ""));
+    }
+
+    /**
+     * Get client info when client rest server is not exist.
+     */
+    @Test
+    public void testgetClientsRestServerNotExist() throws Exception {
+        assertEquals("Incorrect response", 0, clientManager.getClients(null).size());
+        assertEquals("Incorrect response", 0, clientManager.getClients(ssid).size());
+    }
+
+    /**
+     * Get session info, session info is empty.
+     */
+    @Test
+    public void testgetSessionsSsidNull() throws Exception {
+        Collection<PppoeSessionInfo> sessionList;
+        sessionList = clientManager.getSessions();
+        assertEquals("Incorrect response", 0, sessionList.size());
+    }
+
+    /**
+     * Add client when device type is client and client info is null.
+     */
+    @Test
+    public void testaddClientDeviceTypeClient() throws Exception {
+        PppoeDeviceInfo pppoeDeviceInfo = new PppoeClientInfo(PppoeAdminState.ENABLE);
+        try {
+            clientManager.addClient(pppoeDeviceInfo);
+        } catch (Exception e) {
+            fail();
+        }
+    }
+
+    /**
+     * Remove client when device type is client and client info is null.
+     */
+    @Test
+    public void testremoveClientDeviceTypeClient() throws Exception {
+        PppoeDeviceInfo pppoeDeviceInfo = new PppoeClientInfo(PppoeAdminState.ENABLE);
+        try {
+            clientManager.removeClient(pppoeDeviceInfo);
+        } catch (Exception e) {
+            fail();
+        }
+    }
+
+    /**
+     * Remove client when device type is not client and client info is null.
+     */
+    @Test
+    public void testremoveClientDeviceTypeNotClient() throws Exception {
+
+        PppoeDeviceInfo pppoeDeviceInfo = new PppoeServerInfo(RADIUSSERVER, RADIUSKEY);
+        try {
+            clientManager.removeClient(pppoeDeviceInfo);
+        } catch (Exception e) {
+            fail();
+        }
+    }
+}
+
diff --git a/pppoe/driver/pom.xml b/pppoe/driver/pom.xml
new file mode 100755
index 0000000..1656f37
--- /dev/null
+++ b/pppoe/driver/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-pppoe</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.9.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <description>PPPoE REST device driver</description>
+
+    <artifactId>onos-apps-pppoe-driver</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-protocols-rest-api</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-cli</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-apps-pppoe-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+       <plugins>
+           <plugin>
+               <groupId>org.apache.felix</groupId>
+               <artifactId>maven-bundle-plugin</artifactId>
+               <extensions>true</extensions>
+           </plugin>
+       </plugins>
+    </build>
+
+</project>
diff --git a/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDeviceConfig.java b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDeviceConfig.java
new file mode 100755
index 0000000..0acc5fe
--- /dev/null
+++ b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDeviceConfig.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016-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.pppoe.driver;
+
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.pppoe.api.PppoeDeviceInfo;
+import org.onosproject.pppoe.api.PppoeClientInfo;
+import org.onosproject.pppoe.api.PppoeServerInfo;
+import org.onosproject.pppoe.api.PppoeSessionInfo;
+
+
+/**
+ * Behaviour for handling device information retrieval and configuration
+ * for PPPoE devices.
+ */
+public interface PppoeDeviceConfig extends HandlerBehaviour {
+
+    /**
+     * Retrieve PPPoE device information.
+     *
+     * @return device information
+     */
+    PppoeDeviceInfo getDevice();
+
+    /**
+     * Retrieve PPPoE server information of PPPoE device.
+     *
+     * @return server information
+     */
+    PppoeServerInfo getServer();
+
+    /**
+     * Retrieve PPPoE client information of PPPoE device.
+     *
+     * @return client information
+     */
+    PppoeClientInfo getClient();
+
+    /**
+     * Retrieve PPPoE session data of PPPoE device.
+     *
+     * @return session information
+     */
+    PppoeSessionInfo readSessionData();
+
+    /**
+     * Update PPPoE server of PPPoE device.
+     *
+     * @param serverInfo server information to update
+     * @return true - success, false - failure
+     */
+    boolean configServer(PppoeServerInfo serverInfo);
+
+    /**
+     * Update PPPoE client of PPPoE device.
+     *
+     * @param clientInfo client information to update
+     * @return true - success, false - failure
+     */
+    boolean configClient(PppoeClientInfo clientInfo);
+
+}
diff --git a/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDeviceConfigRestImpl.java b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDeviceConfigRestImpl.java
new file mode 100755
index 0000000..31451ea
--- /dev/null
+++ b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDeviceConfigRestImpl.java
@@ -0,0 +1,187 @@
+/*
+ * 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.pppoe.driver;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.protocol.rest.RestSBController;
+import org.onosproject.rest.AbstractWebResource;
+import org.onosproject.pppoe.api.PppoeClientInfo;
+import org.onosproject.pppoe.api.PppoeClientInfoCodec;
+import org.onosproject.pppoe.api.PppoeDeviceInfo;
+import org.onosproject.pppoe.api.PppoeDeviceInfoCodec;
+import org.onosproject.pppoe.api.PppoeServerInfo;
+import org.onosproject.pppoe.api.PppoeServerInfoCodec;
+import org.onosproject.pppoe.api.PppoeSessionInfo;
+import org.onosproject.pppoe.api.PppoeSessionInfoCodec;
+import org.slf4j.Logger;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * REST implementation for handling license information retrieval and other
+ * operations.
+ */
+public class PppoeDeviceConfigRestImpl extends AbstractHandlerBehaviour implements PppoeDeviceConfig {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String MEDIA_TYPE = "json";
+    private static final String PATH_CONFIG = "/pppoe/config";
+    private static final String PATH_DEVICE = "/pppoe/device";
+    private static final String PATH_INFO = "/pppoe/info";
+    private static final String PATH_SESSION = "/pppoe/session";
+
+    private final PppoeDeviceInfoCodec deviceInfoCodec = new PppoeDeviceInfoCodec();
+    private final PppoeServerInfoCodec serverInfoCodec = new PppoeServerInfoCodec();
+    private final PppoeClientInfoCodec clientInfoCodec = new PppoeClientInfoCodec();
+    private final PppoeSessionInfoCodec sessionInfoCodec = new PppoeSessionInfoCodec();
+    private final AbstractWebResource context = new AbstractWebResource();
+
+
+    @Override
+    public PppoeDeviceInfo getDevice() {
+        PppoeDeviceInfo deviceInfo = null;
+        DriverHandler handler = handler();
+        DeviceId deviceId = handler.data().deviceId();
+        String path = PATH_DEVICE;
+        ObjectNode json = getConfigJson(path);
+
+        if (json != null) {
+            deviceInfo = deviceInfoCodec.decode(json, context);
+            deviceInfo.setDeviceId(deviceId);
+        }
+        return deviceInfo;
+    }
+
+    @Override
+    public PppoeServerInfo getServer() {
+        PppoeServerInfo serverInfo = null;
+        String path = PATH_INFO;
+        ObjectNode json = getConfigJson(path);
+
+        if (json != null) {
+            serverInfo = serverInfoCodec.decode(json, context);
+        }
+        return serverInfo;
+    }
+
+    @Override
+    public PppoeClientInfo getClient() {
+        PppoeClientInfo clientInfo = null;
+        String path = PATH_INFO;
+        ObjectNode json = getConfigJson(path);
+
+        if (json != null) {
+            clientInfo = clientInfoCodec.decode(json, context);
+        }
+        return clientInfo;
+    }
+
+    @Override
+    public PppoeSessionInfo readSessionData() {
+        PppoeSessionInfo sessionInfo = null;
+        String path = PATH_SESSION;
+        ObjectNode json = getConfigJson(path);
+
+        if (json != null) {
+            sessionInfo = sessionInfoCodec.decode(json, context);
+        }
+        return sessionInfo;
+    }
+
+    @Override
+    public boolean configClient(PppoeClientInfo clientInfo) {
+        String path = PATH_CONFIG;
+        ObjectNode configNode = clientInfoCodec.encode(clientInfo, context);
+        clientInfo.setEndSession(false);
+
+        return putConfigJson(path, configNode);
+    }
+
+    @Override
+    public boolean configServer(PppoeServerInfo serverInfo) {
+        String path = PATH_CONFIG;
+        ObjectNode configNode = serverInfoCodec.encode(serverInfo, context);
+
+        return putConfigJson(path, configNode);
+    }
+
+    /**
+     * Get PPPoE information from rest.
+     *
+     * @param path target path
+     * @return PPPoE information
+     */
+    private ObjectNode getConfigJson(String path) {
+        DriverHandler handler = handler();
+        RestSBController controller = checkNotNull(handler.get(RestSBController.class));
+        DeviceId deviceId = handler.data().deviceId();
+        ObjectNode json = null;
+
+        try {
+            log.info("REST GET: {}{}", deviceId, path);
+            InputStream stream = controller.get(deviceId, path, MEDIA_TYPE);
+            if (stream == null) {
+                log.warn("REST GET Failed: {}{}", deviceId, path);
+            } else {
+                ObjectMapper mapper = new ObjectMapper();
+                json = (ObjectNode) mapper.readTree(stream);
+            }
+        } catch (IOException e) {
+            log.error("REST GET IOException: {}{} ", deviceId, path, e);
+        }
+        return json;
+    }
+
+    /**
+     * Put PPPoE configuration to rest.
+     *
+     * @param path target path
+     * @param configNode configuration
+     * @return result
+     */
+    private boolean putConfigJson(String path, ObjectNode configNode) {
+        boolean result = false;
+        DriverHandler handler = handler();
+        RestSBController controller = checkNotNull(handler.get(RestSBController.class));
+        DeviceId deviceId = handler.data().deviceId();
+
+        log.info("REST PUT: {}{} {}", deviceId, path, configNode.toString());
+
+        boolean success = controller.put(deviceId, path,
+            new ByteArrayInputStream(configNode.toString()
+            .getBytes(StandardCharsets.UTF_8)), MEDIA_TYPE);
+        if (success) {
+            result = true;
+        } else {
+            log.warn("REST PUT Failed: {}{}", deviceId, path);
+        }
+        return result;
+    }
+
+}
diff --git a/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDriverLoader.java b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDriverLoader.java
new file mode 100755
index 0000000..b7defa2
--- /dev/null
+++ b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/PppoeDriverLoader.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.pppoe.driver;
+
+import org.apache.felix.scr.annotations.Component;
+import org.onosproject.net.driver.AbstractDriverLoader;
+
+
+/**
+ * Loader for PPPoE device driver.
+ */
+@Component(immediate = true)
+public class PppoeDriverLoader extends AbstractDriverLoader {
+
+    private static final String DRIVER_XML = "/pppoe-drivers.xml";
+
+    public PppoeDriverLoader() {
+        super(DRIVER_XML);
+    }
+}
diff --git a/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/package-info.java b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/package-info.java
new file mode 100755
index 0000000..0d332c8
--- /dev/null
+++ b/pppoe/driver/src/main/java/org/onosproject/pppoe/driver/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.
+ */
+
+/**
+ * Package for REST device driver for PPPoE Management.
+ */
+package org.onosproject.pppoe.driver;
diff --git a/pppoe/driver/src/main/resources/pppoe-drivers.xml b/pppoe/driver/src/main/resources/pppoe-drivers.xml
new file mode 100755
index 0000000..e5b08c8
--- /dev/null
+++ b/pppoe/driver/src/main/resources/pppoe-drivers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016-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.
+  -->
+<drivers>
+    <driver name="rest-pppoe" manufacturer="" hwVersion="" swVersion="">
+        <behaviour api="org.onosproject.pppoe.driver.PppoeDeviceConfig"
+                   impl="org.onosproject.pppoe.driver.PppoeDeviceConfigRestImpl"/>
+    </driver>
+</drivers>
diff --git a/pppoe/pom.xml b/pppoe/pom.xml
new file mode 100755
index 0000000..f0f5394
--- /dev/null
+++ b/pppoe/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<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>
+        <artifactId>onos-dependencies</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.8.2</version>
+        <relativePath></relativePath>
+    </parent>
+
+    <artifactId>onos-pppoe</artifactId>
+    <version>1.9.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <description>PPPoE Management Applications</description>
+
+    <properties>
+        <onos.version>1.8.2</onos.version>
+    </properties>
+
+    <modules>
+        <module>api</module>
+        <module>driver</module>
+        <module>app</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+            <version>${onos.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${onos.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.onosproject</groupId>
+                <artifactId>onos-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>