Implements [CORD-546]

Changes:
- Adds new l2 tunnel and l2 tunnel policy;
- Extends cfg of the apps;
- Implements CRUD interfaces through netcfg;

Change-Id: I1a295da605e2496f4883f63fa5f6eca16e627d43
diff --git a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index e7cf32f..2d4cc45 100644
--- a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -78,8 +78,9 @@
 import org.onosproject.routing.config.RouterConfig;
 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
 import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
+import org.onosproject.segmentrouting.config.PwaasConfig;
 import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
+import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
 import org.onosproject.segmentrouting.config.XConnectConfig;
 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
@@ -88,6 +89,7 @@
 import org.onosproject.segmentrouting.storekey.SubnetAssignedVidStoreKey;
 import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
+import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
@@ -193,6 +195,7 @@
     private CordConfigHandler cordConfigHandler = null;
     private RouteHandler routeHandler = null;
     private SegmentRoutingNeighbourDispatcher neighbourHandler = null;
+    private L2TunnelHandler l2TunnelHandler = null;
     private InternalEventHandler eventHandler = new InternalEventHandler();
     private final InternalHostListener hostListener = new InternalHostListener();
     private final InternalConfigListener cfgListener = new InternalConfigListener(this);
@@ -240,6 +243,7 @@
                     return new SegmentRoutingDeviceConfig();
                 }
             };
+
     private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory =
             new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(
                     SubjectFactories.APP_SUBJECT_FACTORY,
@@ -249,6 +253,7 @@
                     return new SegmentRoutingAppConfig();
                 }
             };
+
     private final ConfigFactory<ApplicationId, XConnectConfig> xConnectConfigFactory =
             new ConfigFactory<ApplicationId, XConnectConfig>(
                     SubjectFactories.APP_SUBJECT_FACTORY,
@@ -258,6 +263,7 @@
                     return new XConnectConfig();
                 }
             };
+
     private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
             new ConfigFactory<ApplicationId, McastConfig>(
                     SubjectFactories.APP_SUBJECT_FACTORY,
@@ -268,6 +274,16 @@
                 }
             };
 
+    private final ConfigFactory<ApplicationId, PwaasConfig> pwaasConfigFactory =
+            new ConfigFactory<ApplicationId, PwaasConfig>(
+                    SubjectFactories.APP_SUBJECT_FACTORY,
+                    PwaasConfig.class, "pwaas") {
+                @Override
+                public PwaasConfig createConfig() {
+                    return new PwaasConfig();
+                }
+            };
+
     private Object threadSchedulerLock = new Object();
     private static int numOfEventsQueued = 0;
     private static int numOfEventsExecuted = 0;
@@ -367,12 +383,14 @@
         cordConfigHandler = new CordConfigHandler(this);
         routeHandler = new RouteHandler(this);
         neighbourHandler = new SegmentRoutingNeighbourDispatcher(this);
+        l2TunnelHandler = new L2TunnelHandler(this);
 
         cfgService.addListener(cfgListener);
         cfgService.registerConfigFactory(deviceConfigFactory);
         cfgService.registerConfigFactory(appConfigFactory);
         cfgService.registerConfigFactory(xConnectConfigFactory);
         cfgService.registerConfigFactory(mcastConfigFactory);
+        cfgService.registerConfigFactory(pwaasConfigFactory);
         hostService.addListener(hostListener);
         packetService.addProcessor(processor, PacketProcessor.director(2));
         linkService.addListener(linkListener);
@@ -411,6 +429,7 @@
         cfgService.unregisterConfigFactory(appConfigFactory);
         cfgService.unregisterConfigFactory(xConnectConfigFactory);
         cfgService.unregisterConfigFactory(mcastConfigFactory);
+        cfgService.unregisterConfigFactory(pwaasConfigFactory);
 
         packetService.removeProcessor(processor);
         linkService.removeListener(linkListener);
@@ -1153,6 +1172,21 @@
                     default:
                         break;
                 }
+            } else if (event.configClass().equals(PwaasConfig.class)) {
+                checkState(l2TunnelHandler != null, "L2TunnelHandler is not initialized");
+                switch (event.type()) {
+                    case CONFIG_ADDED:
+                        l2TunnelHandler.processPwaasConfigAdded(event);
+                        break;
+                    case CONFIG_UPDATED:
+                        l2TunnelHandler.processPwaasConfigUpdated(event);
+                        break;
+                    case CONFIG_REMOVED:
+                        l2TunnelHandler.processPwaasConfigRemoved(event);
+                        break;
+                    default:
+                        break;
+                }
             }
         }
     }
diff --git a/src/main/java/org/onosproject/segmentrouting/config/PwaasConfig.java b/src/main/java/org/onosproject/segmentrouting/config/PwaasConfig.java
new file mode 100644
index 0000000..1835fa3
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/config/PwaasConfig.java
@@ -0,0 +1,166 @@
+/*
+ * 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.segmentrouting.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.Config;
+import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
+import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
+import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
+import org.onosproject.segmentrouting.pwaas.L2Mode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+
+/**
+ * App configuration object for Pwaas.
+ */
+public class PwaasConfig extends Config<ApplicationId> {
+
+    private static Logger log = LoggerFactory
+            .getLogger(PwaasConfig.class);
+
+    private static final String SRC_CP = "cP1";
+    private static final String DST_CP = "cP2";
+    private static final String SRC_OUTER_TAG = "cP1OuterTag";
+    private static final String DST_OUTER_TAG = "cP2OuterTag";
+    private static final String SRC_INNER_TAG = "cP1InnerTag";
+    private static final String DST_INNER_TAG = "cP2InnerTag";
+    private static final String MODE = "mode";
+    private static final String ALL_VLAN = "allVlan";
+    private static final String SD_TAG = "sdTag";
+    private static final String PW_LABEL = "pwLabel";
+
+    /**
+     * Error message for missing parameters.
+     */
+    private static final String MISSING_PARAMS = "Missing parameters in pseudo wire description";
+
+    /**
+     * Error message for invalid l2 mode.
+     */
+    private static final String INVALID_L2_MODE = "Invalid pseudo wire mode";
+
+    /**
+     * Verify if the pwaas configuration block is valid.
+     *
+     * @return true, if the configuration block is valid.
+     *         False otherwise.
+     */
+    @Override
+    public boolean isValid() {
+        try {
+            getPwIds().forEach(this::getPwDescription);
+        } catch (IllegalArgumentException e) {
+            log.warn("{}", e.getMessage());
+            return false;
+        }
+        return true;
+
+    }
+
+    /**
+     * Returns all pseudo wire keys.
+     *
+     * @return all keys (tunnels id)
+     * @throws IllegalArgumentException if wrong format
+     */
+    public Set<Long> getPwIds() {
+        ImmutableSet.Builder<Long> builder = ImmutableSet.builder();
+        object.fields().forEachRemaining(entry -> {
+            Long tunnelId = Long.parseLong(entry.getKey());
+            builder.add(tunnelId);
+        });
+        return builder.build();
+    }
+
+    /**
+     * Returns pw description of given pseudo wire id.
+     *
+     * @param tunnelId pseudo wire key
+     * @return set of l2 tunnel descriptions
+     * @throws IllegalArgumentException if wrong format
+     */
+    public DefaultL2TunnelDescription getPwDescription(Long tunnelId) {
+        JsonNode pwDescription = object.get(tunnelId.toString());
+        if (!hasFields((ObjectNode) pwDescription,
+                      SRC_CP, SRC_INNER_TAG, SRC_OUTER_TAG,
+                      DST_CP, DST_INNER_TAG, DST_OUTER_TAG,
+                      MODE, ALL_VLAN, SD_TAG, PW_LABEL)) {
+            throw new IllegalArgumentException(MISSING_PARAMS);
+        }
+        String tempString;
+
+        tempString = pwDescription.get(SRC_CP).asText();
+        ConnectPoint srcCp = ConnectPoint.deviceConnectPoint(tempString);
+
+        tempString = pwDescription.get(DST_CP).asText();
+        ConnectPoint dstCp = ConnectPoint.deviceConnectPoint(tempString);
+
+        tempString = pwDescription.get(SRC_INNER_TAG).asText();
+        VlanId srcInnerTag = VlanId.vlanId(tempString);
+
+        tempString = pwDescription.get(SRC_OUTER_TAG).asText();
+        VlanId srcOuterTag = VlanId.vlanId(tempString);
+
+        tempString = pwDescription.get(DST_INNER_TAG).asText();
+        VlanId dstInnerTag = VlanId.vlanId(tempString);
+
+        tempString = pwDescription.get(DST_OUTER_TAG).asText();
+        VlanId dstOuterTag = VlanId.vlanId(tempString);
+
+        tempString = pwDescription.get(MODE).asText();
+
+        L2Mode l2Mode = L2Mode.valueOf(tempString);
+
+        boolean allVlan = pwDescription.get(ALL_VLAN).asBoolean();
+
+        tempString = pwDescription.get(SD_TAG).asText();
+        VlanId sdTag = VlanId.vlanId(tempString);
+
+        tempString = pwDescription.get(PW_LABEL).asText();
+        MplsLabel pwLabel = MplsLabel.mplsLabel(tempString);
+
+        DefaultL2Tunnel l2Tunnel = new DefaultL2Tunnel(
+                l2Mode,
+                sdTag,
+                tunnelId,
+                pwLabel
+        );
+
+        DefaultL2TunnelPolicy l2TunnelPolicy = new DefaultL2TunnelPolicy(
+                tunnelId,
+                srcCp,
+                srcInnerTag,
+                srcOuterTag,
+                dstCp,
+                dstInnerTag,
+                dstOuterTag,
+                allVlan
+        );
+
+        return new DefaultL2TunnelDescription(l2Tunnel, l2TunnelPolicy);
+    }
+
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2Tunnel.java b/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2Tunnel.java
new file mode 100644
index 0000000..8334a18
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2Tunnel.java
@@ -0,0 +1,194 @@
+/*
+ * 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.segmentrouting.pwaas;
+
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Implementation of the default l2 tunnel.
+ */
+public class DefaultL2Tunnel {
+
+    /**
+     * Mode of the pseudo wire.
+     */
+    private L2Mode pwMode;
+    /**
+     * Service delimiting tag.
+     */
+    private VlanId sdTag;
+    /**
+     * Tunnel id.
+     */
+    private long tunnelId;
+    /**
+     * Pseudo wire label.
+     */
+    private MplsLabel pwLabel;
+    /**
+     * Inter-CO label.
+     */
+    private MplsLabel interCoLabel;
+
+    /**
+     * Creates a inter-co l2 tunnel using the
+     * supplied parameters.
+     *
+     * @param mode the tunnel mode
+     * @param sdtag the service delimiting tag
+     * @param tunnelId the tunnel id
+     * @param pwLabel the pseudo wire label
+     * @param interCoLabel the inter central office label
+     */
+    public DefaultL2Tunnel(L2Mode mode,
+                           VlanId sdtag,
+                           long tunnelId,
+                           MplsLabel pwLabel,
+                           MplsLabel interCoLabel) {
+        checkNotNull(mode);
+        checkArgument(tunnelId > 0);
+        checkNotNull(pwLabel);
+        checkNotNull(interCoLabel);
+
+        this.pwMode = mode;
+        this.sdTag = sdtag;
+        this.tunnelId = tunnelId;
+        this.pwLabel = pwLabel;
+        this.interCoLabel = interCoLabel;
+    }
+
+    /**
+     * Creates a intra-co l2 tunnel using the
+     * supplied parameters.
+     *
+     * @param mode the tunnel mode
+     * @param sdtag the service delimiting tag
+     * @param tunnelId the tunnel id
+     * @param pwLabel the pseudo wire label
+     */
+    public DefaultL2Tunnel(L2Mode mode,
+                           VlanId sdtag,
+                           long tunnelId,
+                           MplsLabel pwLabel) {
+        this(mode, sdtag, tunnelId, pwLabel, MplsLabel.mplsLabel(MplsLabel.MAX_MPLS));
+    }
+
+    /**
+     * Creates an empty l2 tunnel.
+     *
+     **/
+    public DefaultL2Tunnel() {
+        this.pwMode = null;
+        this.sdTag = null;
+        this.tunnelId = 0;
+        this.pwLabel = null;
+        this.interCoLabel = null;
+    }
+
+    /**
+     * Returns the mode of the pseudo wire.
+     *
+     * @return the pseudo wire mode
+     */
+    public L2Mode pwMode() {
+        return pwMode;
+    }
+
+    /**
+     * Returns the service delimitation
+     * tag.
+     *
+     * @return the service delimitation vlan id
+     */
+    public VlanId sdTag() {
+        return sdTag;
+    }
+
+    /**
+     * Returns the tunnel id of the pseudo wire.
+     *
+     * @return the pseudo wire tunnel id
+     */
+    public long tunnelId() {
+        return tunnelId;
+    }
+
+    /**
+     * Returns the pw label.
+     *
+     * @return the mpls pw label
+     */
+    public MplsLabel pwLabel() {
+        return pwLabel;
+    }
+
+    /**
+     * Returns the inter-co label.
+     *
+     * @return the mpls inter-co label
+     */
+    public MplsLabel interCoLabel() {
+        return interCoLabel;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.tunnelId, this.pwLabel);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (getClass() != o.getClass()) {
+            return false;
+        }
+
+        if (o instanceof DefaultL2Tunnel) {
+            DefaultL2Tunnel that = (DefaultL2Tunnel) o;
+            return this.tunnelId == that.tunnelId &&
+                    this.pwMode.equals(that.pwMode) &&
+                    this.sdTag.equals(that.sdTag) &&
+                    this.pwLabel.equals(that.pwLabel) &&
+                    this.interCoLabel.equals(that.interCoLabel);
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("pwMode", pwMode())
+                .add("sdTag", sdTag())
+                .add("tunnelId", tunnelId())
+                .add("pwLabel", pwLabel())
+                .add("interCoLabel", interCoLabel())
+                .toString();
+    }
+
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelDescription.java b/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelDescription.java
new file mode 100644
index 0000000..f3fa5ab
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelDescription.java
@@ -0,0 +1,115 @@
+/*
+ * 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.segmentrouting.pwaas;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Helper class to carry the l2 tunnel
+ * and its policy.
+ */
+public class DefaultL2TunnelDescription {
+
+    /**
+     * The l2 tunnel.
+     */
+    private DefaultL2Tunnel l2Tunnel;
+
+    /**
+     * The l2 tunnel policy.
+     */
+    private DefaultL2TunnelPolicy l2TunnelPolicy;
+
+    /**
+     * Creates a l2 tunnel description using the given info.
+     *
+     * @param l2Tunnel the l2 tunnel
+     * @param l2TunnelPolicy the l2 tunnel description
+     */
+    public DefaultL2TunnelDescription(DefaultL2Tunnel l2Tunnel,
+                                      DefaultL2TunnelPolicy l2TunnelPolicy) {
+        checkNotNull(l2Tunnel);
+        checkNotNull(l2TunnelPolicy);
+
+        this.l2Tunnel = l2Tunnel;
+        this.l2TunnelPolicy = l2TunnelPolicy;
+    }
+
+    /**
+     * Creates an empty l2 tunnel description.
+     */
+    public DefaultL2TunnelDescription() {
+        this.l2Tunnel = null;
+        this.l2TunnelPolicy = null;
+    }
+
+    /**
+     * Returns the l2 tunnel.
+     *
+     * @return the l2 tunnel
+     */
+    public DefaultL2Tunnel l2Tunnel() {
+        return l2Tunnel;
+    }
+
+    /**
+     * Returns the l2 tunnel policy.
+     *
+     * @return the l2 tunnel policy.
+     */
+    public DefaultL2TunnelPolicy l2TunnelPolicy() {
+        return l2TunnelPolicy;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.l2Tunnel, this.l2TunnelPolicy);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (getClass() != o.getClass()) {
+            return false;
+        }
+
+        if (o instanceof DefaultL2TunnelDescription) {
+            DefaultL2TunnelDescription that = (DefaultL2TunnelDescription) o;
+            // Equality is based on tunnel id and pw label
+            // which is always the last label.
+            return this.l2Tunnel.equals(that.l2Tunnel) &&
+                    this.l2TunnelPolicy.equals(that.l2TunnelPolicy);
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("l2Tunnel", l2Tunnel())
+                .add("l2TunnelPolicy", l2TunnelPolicy())
+                .toString();
+    }
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelPolicy.java b/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelPolicy.java
new file mode 100644
index 0000000..53d040c
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelPolicy.java
@@ -0,0 +1,215 @@
+/*
+ * 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.segmentrouting.pwaas;
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Implementation of the default l2 tunnel policy.
+ */
+public class DefaultL2TunnelPolicy {
+
+    /**
+     * Id of the tunnel associated to this policy.
+     */
+    private long tunnelId;
+    /**
+     * First connect point.
+     */
+    private ConnectPoint cP1;
+    /**
+     * Second connect point.
+     */
+    private ConnectPoint cP2;
+    /**
+     * cP1 inner vlan tag. Used in QinQ packets.
+     */
+    private VlanId cP1InnerTag;
+    /**
+     * cP1 outer vlan tag.
+     */
+    private VlanId cP1OuterTag;
+    /**
+     * cP2 inner vlan tag. Used in QinQ packets.
+     */
+    private VlanId cP2InnerTag;
+    /**
+     * cP2 outer vlan tag.
+     */
+    private VlanId cP2OuterTag;
+    /**
+     * Boolean value to indicate if the pseudo wire is port based.
+     */
+    private boolean allVlan;
+
+    /**
+     * Creates a default l2 tunnel policy using
+     * the given parameters.
+     *
+     * @param tunnelId the tunnel id
+     * @param cP1 the first connect point
+     * @param cP1InnerTag the cP1 inner tag
+     * @param cP1OuterTag the cP1 outer tag
+     * @param cP2 the second connect point
+     * @param cP2InnerTag the cP2 inner tag
+     * @param cP2OuterTag the cP2 outer tag
+     * @param allVlan if the tunnel is port based or not
+     */
+    public DefaultL2TunnelPolicy(long tunnelId,
+                                 ConnectPoint cP1, VlanId cP1InnerTag, VlanId cP1OuterTag,
+                                 ConnectPoint cP2, VlanId cP2InnerTag, VlanId cP2OuterTag,
+                                 boolean allVlan) {
+        this.cP1 = checkNotNull(cP1);
+        this.cP2 = checkNotNull(cP2);
+        this.tunnelId = tunnelId;
+        this.cP1InnerTag = cP1InnerTag;
+        this.cP1OuterTag = cP1OuterTag;
+        this.cP2InnerTag = cP2InnerTag;
+        this.cP2OuterTag = cP2OuterTag;
+        this.allVlan = allVlan;
+    }
+
+    /**
+     * Returns the first connect point of the policy.
+     *
+     * @return first connect point
+     */
+    public ConnectPoint cP1() {
+        return cP1;
+    }
+
+    /**
+     * Returns the second connect point of the policy.
+     *
+     * @return second connect point
+     */
+    public ConnectPoint cP2() {
+        return cP2;
+    }
+
+    /**
+     * Returns the cP1 inner vlan tag of the policy.
+     *
+     * @return cP1 inner vlan tag
+     */
+    public VlanId cP1InnerTag() {
+        return cP1InnerTag;
+    }
+
+    /**
+     * Returns the cP1 outer vlan tag of the policy.
+     *
+     * @return cP1 outer vlan tag
+     */
+    public VlanId cP1OuterTag() {
+        return cP1OuterTag;
+    }
+
+    /**
+     * Returns the cP2 inner vlan tag of the policy.
+     *
+     * @return cP2 inner vlan tag
+     */
+    public VlanId cP2InnerTag() {
+        return cP2InnerTag;
+    }
+
+    /**
+     * Returns the cP2 outer vlan tag of the policy.
+     *
+     * @return cP2 outer vlan tag
+     */
+    public VlanId cP2OuterTag() {
+        return cP2OuterTag;
+    }
+
+    /**
+     * Return all vlan value.
+     *
+     * @return true, if the pw is port based. False if the traffic is sliced
+     *         through the inner and outer tags
+     */
+    public boolean isAllVlan() {
+        return allVlan;
+    }
+
+    /**
+     * Returns the tunnel ID of the policy.
+     *
+     * @return Tunnel ID
+     */
+    public long tunnelId() {
+        return this.tunnelId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(tunnelId,
+                            cP1,
+                            cP2,
+                            cP1InnerTag,
+                            cP1OuterTag,
+                            cP2InnerTag,
+                            cP2OuterTag,
+                            allVlan
+        );
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (o instanceof DefaultL2TunnelPolicy) {
+            DefaultL2TunnelPolicy that = (DefaultL2TunnelPolicy) o;
+            if (this.tunnelId == that.tunnelId &&
+                    this.cP1.equals(that.cP1) &&
+                    this.cP2.equals(that.cP2) &&
+                    this.cP1InnerTag.equals(that.cP1InnerTag) &&
+                    this.cP1OuterTag.equals(that.cP1OuterTag) &&
+                    this.cP2InnerTag.equals(that.cP2InnerTag) &&
+                    this.cP2OuterTag.equals(that.cP2OuterTag) &&
+                    this.allVlan == that.allVlan) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("tunnelId", tunnelId())
+                .add("cP1", cP1())
+                .add("cP2", cP2())
+                .add("cP1InnerTag", cP1InnerTag())
+                .add("cP1OuterTag", cP1OuterTag())
+                .add("cP2InnerTag", cP2InnerTag())
+                .add("cP2OuterTag", cP2OuterTag())
+                .add("allVlan", isAllVlan())
+                .toString();
+    }
+
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/pwaas/L2Mode.java b/src/main/java/org/onosproject/segmentrouting/pwaas/L2Mode.java
new file mode 100644
index 0000000..fe0a6b3
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/pwaas/L2Mode.java
@@ -0,0 +1,32 @@
+/*
+ * 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.segmentrouting.pwaas;
+
+/**
+ * Enum to identify mode of the pwaas.
+ */
+public enum L2Mode {
+    /**
+     * Raw mode.
+     */
+    RAW,
+    /**
+     * Tagged mode. In this case the packet need
+     * the sd tag.
+     */
+    TAGGED;
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java b/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
new file mode 100644
index 0000000..96fe6c9
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.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.segmentrouting.pwaas;
+
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.segmentrouting.SegmentRoutingManager;
+import org.onosproject.segmentrouting.config.PwaasConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handles pwaas related events.
+ */
+public class L2TunnelHandler {
+    private static final Logger log = LoggerFactory.getLogger(L2TunnelHandler.class);
+    private static final String CONFIG_NOT_FOUND = "Pwaas config not found";
+    private static final String NOT_MASTER = "Not master controller";
+    private final SegmentRoutingManager srManager;
+
+    public L2TunnelHandler(SegmentRoutingManager srManager) {
+        this.srManager = srManager;
+    }
+
+    /**
+     * Processes Pwaas Config added event.
+     *
+     * @param event network config added event
+     */
+    public void processPwaasConfigAdded(NetworkConfigEvent event) {
+        log.info("Processing Pwaas CONFIG_ADDED");
+        PwaasConfig config = (PwaasConfig) event.config().get();
+        config.getPwIds().forEach(pwId -> {
+            log.info("{}", config.getPwDescription(pwId));
+        });
+    }
+
+    /**
+     * Processes Pwaas Config updated event.
+     *
+     * @param event network config updated event
+     */
+    public void processPwaasConfigUpdated(NetworkConfigEvent event) {
+        log.info("Processing Pwaas CONFIG_UPDATED");
+        PwaasConfig config = (PwaasConfig) event.config().get();
+        config.getPwIds().forEach(pwId -> {
+            log.info("{}", config.getPwDescription(pwId));
+        });
+    }
+
+    /**
+     * Processes Pwaas Config removed event.
+     *
+     * @param event network config removed event
+     */
+    public void processPwaasConfigRemoved(NetworkConfigEvent event) {
+        log.info("Processing Pwaas CONFIG_REMOVED");
+        PwaasConfig config = (PwaasConfig) event.config().get();
+        config.getPwIds().forEach(pwId -> {
+            log.info("{}", config.getPwDescription(pwId));
+        });
+    }
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/pwaas/package-info.java b/src/main/java/org/onosproject/segmentrouting/pwaas/package-info.java
new file mode 100644
index 0000000..05d463b
--- /dev/null
+++ b/src/main/java/org/onosproject/segmentrouting/pwaas/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.
+ */
+
+/**
+ * Set of resources implementing the Pwaas.
+ */
+package org.onosproject.segmentrouting.pwaas;
\ No newline at end of file
diff --git a/src/test/java/org/onosproject/segmentrouting/config/PwaasConfigTest.java b/src/test/java/org/onosproject/segmentrouting/config/PwaasConfigTest.java
new file mode 100644
index 0000000..39712a3
--- /dev/null
+++ b/src/test/java/org/onosproject/segmentrouting/config/PwaasConfigTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.segmentrouting.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.segmentrouting.SegmentRoutingManager;
+import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
+import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
+import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
+import org.onosproject.segmentrouting.pwaas.L2Mode;
+
+import java.io.InputStream;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+
+/**
+ * Unit tests for class {@link PwaasConfig}.
+ */
+public class PwaasConfigTest {
+
+    private static final String TUNNEL_ID_1 = "1";
+    private static final String TUNNEL_ID_2 = "20";
+    private static final String NOT_PRESENT_TUNNEL_ID = "2";
+    private static final ConnectPoint INGRESS_1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
+    private static final ConnectPoint INGRESS_2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/1");
+    private static final ConnectPoint EGRESS_1 = ConnectPoint.deviceConnectPoint("of:0000000000000011/1");
+    private static final ConnectPoint EGRESS_2 = ConnectPoint.deviceConnectPoint("of:0000000000000012/1");
+    private static final VlanId INGRESS_INNER_TAG_1 = VlanId.vlanId("10");
+    private static final VlanId INGRESS_INNER_TAG_2 = VlanId.vlanId("100");
+    private static final VlanId INGRESS_OUTER_TAG_1 = VlanId.vlanId("20");
+    private static final VlanId INGRESS_OUTER_TAG_2 = VlanId.vlanId("200");
+    private static final VlanId EGRESS_INNER_TAG_1 = VlanId.vlanId("11");
+    private static final VlanId EGRESS_INNER_TAG_2 = VlanId.vlanId("110");
+    private static final VlanId EGRESS_OUTER_TAG_1 = VlanId.vlanId("21");
+    private static final VlanId EGRESS_OUTER_TAG_2 = VlanId.vlanId("210");
+    private static final String MODE_1 = "RAW";
+    private static final String MODE_2 = "TAGGED";
+    private static final boolean ALL_VLAN_1 = true;
+    private static final boolean ALL_VLAN_2 = false;
+    private static final VlanId SD_TAG_1 = VlanId.vlanId("40");
+    private static final VlanId SD_TAG_2 = VlanId.NONE;
+    private static final MplsLabel PW_LABEL_1 = MplsLabel.mplsLabel("255");
+    private static final MplsLabel PW_LABEL_2 = MplsLabel.mplsLabel("4095");
+
+    private PwaasConfig config;
+    private PwaasConfig invalidConfig;
+
+    @Before
+    public void setUp() throws Exception {
+        InputStream jsonStream = PwaasConfig.class
+                .getResourceAsStream("/pwaas.json");
+        InputStream invalidJsonStream = PwaasConfig.class
+                .getResourceAsStream("/pwaas-invalid.json");
+
+        String key = SegmentRoutingManager.APP_NAME;
+        ApplicationId subject = new TestApplicationId(key);
+        ObjectMapper mapper = new ObjectMapper();
+        JsonNode jsonNode = mapper.readTree(jsonStream);
+        JsonNode invalidJsonNode = mapper.readTree(invalidJsonStream);
+        ConfigApplyDelegate delegate = new MockDelegate();
+
+        config = new PwaasConfig();
+        config.init(subject, key, jsonNode, mapper, delegate);
+        invalidConfig = new PwaasConfig();
+        invalidConfig.init(subject, key, invalidJsonNode, mapper, delegate);
+    }
+
+    /**
+     * Tests config validity.
+     */
+    @Test
+    public void testIsValid() {
+        assertTrue(config.isValid());
+        assertFalse(invalidConfig.isValid());
+    }
+
+    /**
+     * Tests getPwIds.
+     */
+    @Test
+    public void testGetPwIds() {
+        Set<Long> pwIds = config.getPwIds();
+        assertThat(pwIds.size(), is(2));
+        assertTrue(pwIds.contains(Long.parseLong(TUNNEL_ID_1)));
+        assertTrue(pwIds.contains(Long.parseLong(TUNNEL_ID_2)));
+        assertFalse(pwIds.contains(Long.parseLong(NOT_PRESENT_TUNNEL_ID)));
+    }
+
+    /**
+     * Tests getPwDescription.
+     */
+    @Test
+    public void testGetPwDescription() {
+        DefaultL2TunnelDescription l2TunnelDescription = null;
+
+        DefaultL2Tunnel l2Tunnel = new DefaultL2Tunnel(
+            L2Mode.valueOf(MODE_1),
+            SD_TAG_1,
+            Long.parseLong(TUNNEL_ID_1),
+            PW_LABEL_1
+        );
+        DefaultL2TunnelPolicy l2TunnelPolicy = new DefaultL2TunnelPolicy(
+                Long.parseLong(TUNNEL_ID_1),
+                INGRESS_1,
+                INGRESS_INNER_TAG_1,
+                INGRESS_OUTER_TAG_1,
+                EGRESS_1,
+                EGRESS_INNER_TAG_1,
+                EGRESS_OUTER_TAG_1,
+                ALL_VLAN_1
+        );
+        l2TunnelDescription = config.getPwDescription(Long.parseLong(TUNNEL_ID_1));
+        assertThat(l2TunnelDescription.l2Tunnel().pwMode(), is(l2Tunnel.pwMode()));
+        assertThat(l2TunnelDescription.l2Tunnel().sdTag(), is(l2Tunnel.sdTag()));
+        assertThat(l2TunnelDescription.l2Tunnel().tunnelId(), is(l2Tunnel.tunnelId()));
+        assertThat(l2TunnelDescription.l2Tunnel().pwLabel(), is(l2Tunnel.pwLabel()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().tunnelId(), is(l2TunnelPolicy.tunnelId()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP1InnerTag(), is(l2TunnelPolicy.cP1InnerTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP1OuterTag(), is(l2TunnelPolicy.cP1OuterTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP2InnerTag(), is(l2TunnelPolicy.cP2InnerTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP2OuterTag(), is(l2TunnelPolicy.cP2OuterTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP1(), is(l2TunnelPolicy.cP1()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP2(), is(l2TunnelPolicy.cP2()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().isAllVlan(), is(l2TunnelPolicy.isAllVlan()));
+
+        l2Tunnel = new DefaultL2Tunnel(
+                L2Mode.valueOf(MODE_2),
+                SD_TAG_2,
+                Long.parseLong(TUNNEL_ID_2),
+                PW_LABEL_2
+        );
+        l2TunnelPolicy = new DefaultL2TunnelPolicy(
+                Long.parseLong(TUNNEL_ID_2),
+                INGRESS_2,
+                INGRESS_INNER_TAG_2,
+                INGRESS_OUTER_TAG_2,
+                EGRESS_2,
+                EGRESS_INNER_TAG_2,
+                EGRESS_OUTER_TAG_2,
+                ALL_VLAN_2
+        );
+        l2TunnelDescription = config.getPwDescription(Long.parseLong(TUNNEL_ID_2));
+        assertThat(l2TunnelDescription.l2Tunnel().pwMode(), is(l2Tunnel.pwMode()));
+        assertThat(l2TunnelDescription.l2Tunnel().sdTag(), is(l2Tunnel.sdTag()));
+        assertThat(l2TunnelDescription.l2Tunnel().tunnelId(), is(l2Tunnel.tunnelId()));
+        assertThat(l2TunnelDescription.l2Tunnel().pwLabel(), is(l2Tunnel.pwLabel()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().tunnelId(), is(l2TunnelPolicy.tunnelId()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP1InnerTag(), is(l2TunnelPolicy.cP1InnerTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP1OuterTag(), is(l2TunnelPolicy.cP1OuterTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP2OuterTag(), is(l2TunnelPolicy.cP2OuterTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP2OuterTag(), is(l2TunnelPolicy.cP2OuterTag()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP1(), is(l2TunnelPolicy.cP1()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().cP2(), is(l2TunnelPolicy.cP2()));
+        assertThat(l2TunnelDescription.l2TunnelPolicy().isAllVlan(), is(l2TunnelPolicy.isAllVlan()));
+
+    }
+
+    private class MockDelegate implements ConfigApplyDelegate {
+        @Override
+        public void onApply(Config config) {
+        }
+    }
+
+}
diff --git a/src/test/resources/pwaas-invalid.json b/src/test/resources/pwaas-invalid.json
new file mode 100644
index 0000000..f282abe
--- /dev/null
+++ b/src/test/resources/pwaas-invalid.json
@@ -0,0 +1,26 @@
+{
+  "1": {
+    "cP1": "of:0000000000000001/1",
+    "cP2": "of:0000000000000011/1",
+    "cP1InnerTag": "10",
+    "cP1OuterTag": "20",
+    "cP2InnerTag": "11",
+    "cP2OuterTag": "",
+    "mode": "1",
+    "allVlan": true,
+    "sdTag": "40",
+    "pwLabel": "255"
+  },
+  "20": {
+    "cP1": "of:0000000000000002/1",
+    "cP2": "of:0000000000000012/1",
+    "cP1InnerTag": "100",
+    "cP1OuterTag": "200",
+    "cP2InnerTag": "110",
+    "cP2OuterTag": "210",
+    "mode": "TAGGED",
+    "allVlan": false,
+    "sdTag": "-1",
+    "pwLabel": "4095"
+  }
+}
diff --git a/src/test/resources/pwaas.json b/src/test/resources/pwaas.json
new file mode 100644
index 0000000..902611e
--- /dev/null
+++ b/src/test/resources/pwaas.json
@@ -0,0 +1,26 @@
+{
+  "1": {
+    "cP1": "of:0000000000000001/1",
+    "cP2": "of:0000000000000011/1",
+    "cP1InnerTag": "10",
+    "cP1OuterTag": "20",
+    "cP2InnerTag": "11",
+    "cP2OuterTag": "21",
+    "mode": "RAW",
+    "allVlan": true,
+    "sdTag": "40",
+    "pwLabel": "255"
+  },
+  "20": {
+    "cP1": "of:0000000000000002/1",
+    "cP2": "of:0000000000000012/1",
+    "cP1InnerTag": "100",
+    "cP1OuterTag": "200",
+    "cP2InnerTag": "110",
+    "cP2OuterTag": "210",
+    "mode": "TAGGED",
+    "allVlan": false,
+    "sdTag": "-1",
+    "pwLabel": "4095"
+  }
+}