Various pseudowire fixes and improvements.

- Co-ordination when creating - removing pseudowires from
  different instances with a use of a DistributedLock.
- Fixed REST API To return json with specific error for
  the single pw instantiation.
- Fixed REST API to return specific error also for pseudowires
  that could not be decoded.
- Minor bug fix to return appropriate error when instantiating
  a pw from the command line that could not be decoded.
- Fixed bug when creating spine-leaf-leaf pseudowire where we observed flows in pending state.
- Improved logging.

Change-Id: I60dd0ebf8af63ca74d18cfe4801d01846641fb7b
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
index 277a1c3..d7d22b4 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
@@ -100,8 +100,9 @@
 
         try {
             tun = new DefaultL2Tunnel(parseMode(mode), parseVlan(sDTag), parsePwId(pwId), parsePWLabel(pwLabel));
-        } catch (Exception e) {
-            print("Exception while parsing L2Tunnel : {}", e);
+        } catch (IllegalArgumentException e) {
+            log.error("Exception while parsing L2Tunnel : \n\t %s", e.getMessage());
+            print("Exception while parsing L2Tunnel : \n\t %s", e.getMessage());
             return;
         }
 
@@ -111,13 +112,15 @@
                                                parseVlan(cP1OuterVlan), ConnectPoint.deviceConnectPoint(cP2),
                                                parseVlan(cP2InnerVlan), parseVlan(cP2OuterVlan));
 
-        } catch (Exception e) {
-            print("Exception while parsing L2TunnelPolicy : {}", e);
+        } catch (IllegalArgumentException e) {
+            log.error("Exception while parsing L2TunnelPolicy : \n\t %s", e.getMessage());
+            print("Exception while parsing L2TunnelPolicy : \n\t %s", e.getMessage());
             return;
         }
 
         L2TunnelDescription pw = new DefaultL2TunnelDescription(tun, policy);
         L2TunnelHandler.Result res = srService.addPseudowire(pw);
+        log.info("Deploying pseudowire {} via the command line.", pw);
         switch (res) {
             case WRONG_PARAMETERS:
                 print("Pseudowire could not be added , error in the parameters : \n\t%s",
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
index 362ebbb..d0f217d 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
@@ -49,11 +49,13 @@
         int pwIntId;
         try {
             pwIntId = parsePwId(pwId);
-        } catch (Exception e) {
-            print("Exception while parsing pseudowire id : {}", e);
+        } catch (IllegalArgumentException e) {
+            log.error("Exception while parsing pseudowire id : \n\t %s", e.getMessage());
+            print("Exception while parsing pseudowire id : \n\t %s", e.getMessage());
             return;
         }
 
+        log.info("Removing pseudowire {} from the command line.", pwIntId);
         L2TunnelHandler.Result res = mngr.removePseudowire(pwIntId);
         switch (res) {
             case WRONG_PARAMETERS:
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
index c736614..e40dcb8 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
@@ -52,8 +52,10 @@
 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.DistributedLock;
 import org.onosproject.store.service.DistributedSet;
 import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageException;
 import org.onosproject.store.service.Versioned;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -74,10 +76,11 @@
 import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*;
 
 /**
- * Handles pwaas related events.
+ * Handler for pseudowire management.
  */
 public class DefaultL2TunnelHandler implements L2TunnelHandler {
 
+    private static final String LOCK_NAME = "l2-tunnel-handler-lock";
     private static final Logger log = LoggerFactory.getLogger(DefaultL2TunnelHandler.class);
 
     private final SegmentRoutingManager srManager;
@@ -118,6 +121,13 @@
     private final DistributedSet<VlanId> vlanStore;
 
     /**
+     * Lock used when creating or removing pseudowires.
+     */
+    private final DistributedLock pwLock;
+
+    private static final long LOCK_TIMEOUT = 2000;
+
+    /**
      * Used for determining transport vlans for leaf-spine.
      */
     private short transportVlanUpper = 4093, transportVlanLower = 3500;
@@ -188,6 +198,11 @@
                                 .build()))
                 .build()
                 .asDistributedSet();
+
+        pwLock = srManager.storageService.lockBuilder()
+                .withName(LOCK_NAME)
+                .build()
+                .asLock(LOCK_TIMEOUT);
     }
 
     /**
@@ -281,10 +296,7 @@
     private Result manageIntermediateFiltering(L2TunnelDescription pw, boolean leafSpinePw) {
 
         // only leaf-spine-spine should need intermediate rules for now
-        if (!leafSpinePw) {
-            return Result.SUCCESS;
-        }
-        if (pw.l2Tunnel().pathUsed().size() != 2) {
+        if (!leafSpinePw || (pw.l2Tunnel().pathUsed().size() != 2)) {
             return Result.SUCCESS;
         }
 
@@ -292,7 +304,7 @@
         DeviceId intermediateSpineId = pw.l2Tunnel().pathUsed().get(0).dst().deviceId();
         L2Tunnel l2Tunnel = pw.l2Tunnel();
 
-        log.info("Installing intermediate filtering rules for spine {} , for pseudowire {}",
+        log.debug("Installing intermediate filtering rules for spine {} , for pseudowire {}",
                  intermediateSpineId, pw.l2Tunnel().tunnelId());
 
         MacAddress dstMac;
@@ -394,7 +406,7 @@
 
         if (!spinePw) {
 
-            log.info("Untagged transport with internal vlan {} for pseudowire!", UNTAGGED_TRANSPORT_VLAN);
+            log.debug("Untagged transport with internal vlan {} for pseudowire!", UNTAGGED_TRANSPORT_VLAN);
             return UNTAGGED_TRANSPORT_VLAN;
         } else {
             for (short i = transportVlanUpper; i > transportVlanLower; i--) {
@@ -403,12 +415,12 @@
                 if (!vlanStore.contains(vlanToUse)) {
 
                     vlanStore.add(vlanToUse);
-                    log.info("Transport vlan {} for pseudowire!", vlanToUse);
+                    log.debug("Transport vlan {} for pseudowire!", vlanToUse);
                     return vlanToUse;
                 }
             }
 
-            log.info("No available transport vlan found, pseudowire traffic will be carried untagged " +
+            log.warn("No available transport vlan found, pseudowire traffic will be carried untagged " +
                              "with internal vlan {}!", UNTAGGED_TRANSPORT_VLAN);
             return UNTAGGED_TRANSPORT_VLAN;
         }
@@ -455,6 +467,7 @@
      */
     private boolean isValidPath(List<Link> path, boolean leafSpinePw) {
 
+        log.debug("Checking path validity for pseudowire.");
         List<DeviceId> devices = getDevicesOnPath(path);
         if (devices.size() < 2) {
             log.error("Path size for pseudowire should be greater than 1!");
@@ -528,196 +541,202 @@
      */
     public Result deployPseudowire(L2TunnelDescription pw) {
 
-        Result result;
-        long l2TunnelId;
-
-        log.debug("Pseudowire with {} deployment started, check log for any errors in this process!",
-                  pw.l2Tunnel().tunnelId());
-
-        l2TunnelId = pw.l2Tunnel().tunnelId();
-        // The tunnel id cannot be 0.
-        if (l2TunnelId == 0) {
-            log.warn("Tunnel id id must be > 0");
-            return Result.WRONG_PARAMETERS
-                    .appendError("Tunnel id id must be > 0");
-        }
-
-        result = verifyGlobalValidity(pw);
-        if (result != SUCCESS) {
-            log.error("Global validity for pseudowire {} is wrong!", l2TunnelId);
-            return result;
-        }
-
-        // leafSpinePw determines if this is a leaf-leaf
-        // or leaf-spine pseudowire
-        boolean leafSpinePw;
-        ConnectPoint cp1 = pw.l2TunnelPolicy().cP1();
-        ConnectPoint cp2 = pw.l2TunnelPolicy().cP2();
         try {
-            // differentiate between leaf-leaf pseudowires and leaf-spine
-            if (!srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
-                    !srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
-                log.error("Can not deploy pseudowire from spine to spine!");
+            // take the lock
+            pwLock.lock();
+            Result result;
+            long l2TunnelId;
+            log.debug("Pseudowire with {} deployment started, check log for any errors in this process!",
+                      pw.l2Tunnel().tunnelId());
+            l2TunnelId = pw.l2Tunnel().tunnelId();
+            // The tunnel id cannot be 0.
+            if (l2TunnelId == 0) {
+                log.warn("Tunnel id id must be > 0 in {}", l2TunnelId);
                 return Result.WRONG_PARAMETERS
-                        .appendError("Can not deploy pseudowire from spine to spine!");
-            } else if (srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
-                    srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
-                leafSpinePw = false;
-            } else {
-                leafSpinePw = true;
+                        .appendError("Tunnel id id must be > 0");
             }
-        } catch (DeviceConfigNotFoundException e) {
-            log.error("Device for pseudowire connection points does not exist in the configuration");
-            return Result.INTERNAL_ERROR
-                    .appendError("Device for pseudowire connection points does not exist in the configuration");
+
+            result = verifyGlobalValidity(pw);
+            if (result != SUCCESS) {
+                log.error("Global validity for pseudowire {} is wrong!", l2TunnelId);
+                return result;
+            }
+
+            // leafSpinePw determines if this is a leaf-leaf
+            // or leaf-spine pseudowire
+            boolean leafSpinePw;
+            ConnectPoint cp1 = pw.l2TunnelPolicy().cP1();
+            ConnectPoint cp2 = pw.l2TunnelPolicy().cP2();
+            try {
+                // differentiate between leaf-leaf pseudowires and leaf-spine
+                if (!srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
+                        !srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
+                    log.error("Can not deploy pseudowire {} from spine to spine!", l2TunnelId);
+                    return Result.WRONG_PARAMETERS
+                            .appendError("Can not deploy pseudowire from spine to spine!");
+                } else if (srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
+                        srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
+                    leafSpinePw = false;
+                } else {
+                    leafSpinePw = true;
+                }
+            } catch (DeviceConfigNotFoundException e) {
+                log.error("Device for pseudowire {} connection points does not exist in the configuration", l2TunnelId);
+                return Result.INTERNAL_ERROR
+                        .appendError("Device for pseudowire connection points does not exist in the configuration");
+            }
+
+            // reverse the policy in order for leaf switch to be at CP1
+            // this will help us for re-using SRLinkWeigher for computing valid paths
+            L2TunnelPolicy reversedPolicy = reverseL2TunnelPolicy(pw.l2TunnelPolicy());
+            if (reversedPolicy == null) {
+                log.error("Error in reversing policy, device configuration was not found for pseudowire {}.",
+                          l2TunnelId);
+                return INTERNAL_ERROR
+                        .appendError("Device configuration not found when reversing the policy.");
+            }
+            pw.setL2TunnelPolicy(reversedPolicy);
+
+            // get path here, need to use the same for fwd and rev direction
+            List<Link> path = getPath(pw.l2TunnelPolicy().cP1(),
+                                      pw.l2TunnelPolicy().cP2());
+            if (path == null) {
+                log.error("Deploying process : No path between the connection points for pseudowire {}", l2TunnelId);
+                return PATH_NOT_FOUND.appendError("No path between the connection points for pseudowire!");
+            }
+
+            Link fwdNextHop;
+            Link revNextHop;
+            if (!isValidPath(path, leafSpinePw)) {
+                log.error("Deploying process : Path for pseudowire {} is not valid", l2TunnelId);
+                return INTERNAL_ERROR.appendError("Internal error : path for pseudowire is not valid!");
+            }
+            // oneHope flag is used to determine if we need to
+            // install transit mpls rules
+            boolean oneHop = true;
+            if (path.size() > 1) {
+                oneHop = false;
+            }
+
+            fwdNextHop = path.get(0);
+            revNextHop = reverseLink(path.get(path.size() - 1));
+
+            pw.l2Tunnel().setPath(path);
+            pw.l2Tunnel().setTransportVlan(determineTransportVlan(leafSpinePw));
+
+            // next hops for next objectives
+            log.info("Deploying process : Establishing forward direction for pseudowire {}", l2TunnelId);
+
+            VlanId egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP1OuterTag(),
+                                                    pw.l2TunnelPolicy().cP1InnerTag(),
+                                                    pw.l2TunnelPolicy().cP2OuterTag(),
+                                                    pw.l2TunnelPolicy().cP2InnerTag());
+            result = deployPseudoWireInit(pw.l2Tunnel(),
+                                          pw.l2TunnelPolicy().cP1(),
+                                          pw.l2TunnelPolicy().cP2(),
+                                          FWD,
+                                          fwdNextHop,
+                                          leafSpinePw,
+                                          oneHop,
+                                          egressVlan);
+            if (result != SUCCESS) {
+                log.error("Deploying process : Error in deploying pseudowire {} initiation for CP1", l2TunnelId);
+                return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire initiation for CP1");
+            }
+
+            result = deployPolicy(l2TunnelId,
+                                  pw.l2TunnelPolicy().cP1(),
+                                  pw.l2TunnelPolicy().cP1InnerTag(),
+                                  pw.l2TunnelPolicy().cP1OuterTag(),
+                                  egressVlan,
+                                  result.getNextId());
+            if (result != SUCCESS) {
+                log.error("Deploying process : Error in deploying pseudowire {} policy for CP1", l2TunnelId);
+                return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire policy for CP1");
+            }
+
+            PortNumber termPort = pw.l2Tunnel().pathUsed().get(pw.l2Tunnel().pathUsed().size() - 1).dst().port();
+            result = deployPseudoWireTerm(pw.l2Tunnel(),
+                                          pw.l2TunnelPolicy().cP2(),
+                                          egressVlan,
+                                          FWD,
+                                          leafSpinePw,
+                                          oneHop,
+                                          termPort);
+
+            if (result != SUCCESS) {
+                log.error("Deploying process : Error in deploying pseudowire {} termination for CP1", l2TunnelId);
+                return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP1");
+            }
+
+            // We establish the reverse tunnel.
+            log.info("Deploying process : Establishing reverse direction for pseudowire {}", l2TunnelId);
+            egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP2OuterTag(),
+                                             pw.l2TunnelPolicy().cP2InnerTag(),
+                                             pw.l2TunnelPolicy().cP1OuterTag(),
+                                             pw.l2TunnelPolicy().cP1InnerTag());
+
+            result = deployPseudoWireInit(pw.l2Tunnel(),
+                                          pw.l2TunnelPolicy().cP2(),
+                                          pw.l2TunnelPolicy().cP1(),
+                                          REV,
+                                          revNextHop,
+                                          leafSpinePw,
+                                          oneHop,
+                                          egressVlan);
+            if (result != SUCCESS) {
+                log.error("Deploying process : Error in deploying pseudowire {} initiation for CP2", l2TunnelId);
+                return Result.INTERNAL_ERROR
+                        .appendError("Error in deploying pseudowire initiation for CP2");
+            }
+
+            result = deployPolicy(l2TunnelId,
+                                  pw.l2TunnelPolicy().cP2(),
+                                  pw.l2TunnelPolicy().cP2InnerTag(),
+                                  pw.l2TunnelPolicy().cP2OuterTag(),
+                                  egressVlan,
+                                  result.getNextId());
+            if (result != SUCCESS) {
+                log.error("Deploying process : Error in deploying policy {} for CP2", l2TunnelId);
+                return Result.INTERNAL_ERROR
+                        .appendError("Deploying process : Error in deploying policy for CP2");
+            }
+
+            termPort = pw.l2Tunnel().pathUsed().get(0).src().port();
+            result = deployPseudoWireTerm(pw.l2Tunnel(),
+                                          pw.l2TunnelPolicy().cP1(),
+                                          egressVlan,
+                                          REV,
+                                          leafSpinePw,
+                                          oneHop,
+                                          termPort);
+
+            if (result != SUCCESS) {
+                log.error("Deploying process : Error in deploying pseudowire {} termination for CP2", l2TunnelId);
+                return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP2");
+            }
+
+            result = manageIntermediateFiltering(pw, leafSpinePw);
+            if (result != SUCCESS) {
+                log.error("Deploying process : Error in installing intermediate rules for " +
+                                  "tagged transport for pseudowire {}", l2TunnelId);
+                return Result.INTERNAL_ERROR.appendError("Error in installing intermediate rules for tagged transport");
+            }
+
+            log.info("Deploying process : Updating relevant information for pseudowire {}", l2TunnelId);
+
+            // Populate stores as the final step of the process
+            l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel());
+            l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy());
+
+            return Result.SUCCESS;
+        } catch (StorageException.Timeout e) {
+            log.error("Can not acquire distributed lock for pseudowire {}!", pw.l2Tunnel().tunnelId());
+            return Result.INTERNAL_ERROR.appendError("Can not acquire distributed lock!");
+        } finally {
+            // release the lock
+            pwLock.unlock();
         }
-
-        // reverse the policy in order for leaf switch to be at CP1
-        // this will help us for re-using SRLinkWeigher for computing valid paths
-        L2TunnelPolicy reversedPolicy = reverseL2TunnelPolicy(pw.l2TunnelPolicy());
-        if (reversedPolicy == null) {
-            log.error("Error in reversing policy, device configuration was not found!");
-            return  INTERNAL_ERROR
-                    .appendError("Device configuration not found when reversing the policy.");
-        }
-        pw.setL2TunnelPolicy(reversedPolicy);
-
-        // get path here, need to use the same for fwd and rev direction
-        List<Link> path = getPath(pw.l2TunnelPolicy().cP1(),
-                                  pw.l2TunnelPolicy().cP2());
-        if (path == null) {
-            log.error("Deploying process : No path between the connection points for pseudowire {}", l2TunnelId);
-            return PATH_NOT_FOUND.appendError("No path between the connection points for pseudowire!");
-        }
-
-        Link fwdNextHop;
-        Link revNextHop;
-        if (!isValidPath(path, leafSpinePw)) {
-            log.error("Deploying process : Path for pseudowire {} is not valid",
-                      l2TunnelId);
-            return INTERNAL_ERROR.appendError("Internal error : path for pseudowire is not valid!");
-        }
-
-        // oneHope flag is used to determine if we need to
-        // install transit mpls rules
-        boolean oneHop = true;
-        if (path.size() > 1) {
-            oneHop = false;
-        }
-
-        fwdNextHop = path.get(0);
-        revNextHop = reverseLink(path.get(path.size() - 1));
-
-        pw.l2Tunnel().setPath(path);
-        pw.l2Tunnel().setTransportVlan(determineTransportVlan(leafSpinePw));
-
-        // next hops for next objectives
-        log.info("Deploying process : Establishing forward direction for pseudowire {}", l2TunnelId);
-
-        VlanId egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP1OuterTag(),
-                                                pw.l2TunnelPolicy().cP1InnerTag(),
-                                                pw.l2TunnelPolicy().cP2OuterTag(),
-                                                pw.l2TunnelPolicy().cP2InnerTag());
-        // We establish the tunnel.
-        // result.nextId will be used in fwd
-        result = deployPseudoWireInit(pw.l2Tunnel(),
-                                      pw.l2TunnelPolicy().cP1(),
-                                      pw.l2TunnelPolicy().cP2(),
-                                      FWD,
-                                      fwdNextHop,
-                                      leafSpinePw,
-                                      oneHop,
-                                      egressVlan);
-        if (result != SUCCESS) {
-            log.info("Deploying process : Error in deploying pseudowire initiation for CP1");
-            return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire initiation for CP1");
-        }
-
-        // We create the policy.
-        result = deployPolicy(l2TunnelId,
-                              pw.l2TunnelPolicy().cP1(),
-                              pw.l2TunnelPolicy().cP1InnerTag(),
-                              pw.l2TunnelPolicy().cP1OuterTag(),
-                              egressVlan,
-                              result.getNextId());
-        if (result != SUCCESS) {
-            log.info("Deploying process : Error in deploying pseudowire policy for CP1");
-            return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire policy for CP1");
-        }
-
-        // We terminate the tunnel
-        result = deployPseudoWireTerm(pw.l2Tunnel(),
-                                       pw.l2TunnelPolicy().cP2(),
-                                       egressVlan,
-                                       FWD,
-                                       leafSpinePw,
-                                       oneHop);
-
-        if (result != SUCCESS) {
-            log.info("Deploying process : Error in deploying pseudowire termination for CP1");
-            return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP1");
-        }
-
-        log.info("Deploying process : Establishing reverse direction for pseudowire {}", l2TunnelId);
-
-        egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP2OuterTag(),
-                                         pw.l2TunnelPolicy().cP2InnerTag(),
-                                         pw.l2TunnelPolicy().cP1OuterTag(),
-                                         pw.l2TunnelPolicy().cP1InnerTag());
-
-        // We establish the reverse tunnel.
-        result = deployPseudoWireInit(pw.l2Tunnel(),
-                                       pw.l2TunnelPolicy().cP2(),
-                                       pw.l2TunnelPolicy().cP1(),
-                                       REV,
-                                       revNextHop,
-                                       leafSpinePw,
-                                       oneHop,
-                                       egressVlan);
-        if (result != SUCCESS) {
-            log.info("Deploying process : Error in deploying pseudowire initiation for CP2");
-            return Result.INTERNAL_ERROR
-                    .appendError("Error in deploying pseudowire initiation for CP2");
-        }
-
-
-        result = deployPolicy(l2TunnelId,
-                               pw.l2TunnelPolicy().cP2(),
-                               pw.l2TunnelPolicy().cP2InnerTag(),
-                               pw.l2TunnelPolicy().cP2OuterTag(),
-                               egressVlan,
-                               result.getNextId());
-        if (result != SUCCESS) {
-            log.info("Deploying process : Error in deploying policy for CP2");
-            return Result.INTERNAL_ERROR
-                    .appendError("Deploying process : Error in deploying policy for CP2");
-        }
-
-        result = deployPseudoWireTerm(pw.l2Tunnel(),
-                                      pw.l2TunnelPolicy().cP1(),
-                                      egressVlan,
-                                      REV,
-                                      leafSpinePw,
-                                      oneHop);
-
-        if (result != SUCCESS) {
-            log.info("Deploying process : Error in deploying pseudowire termination for CP2");
-            return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP2");
-        }
-
-        result = manageIntermediateFiltering(pw, leafSpinePw);
-        if (result != SUCCESS) {
-            log.info("Deploying process : Error in installing intermediate rules for tagged transport");
-            return Result.INTERNAL_ERROR.appendError("Error in installing intermediate rules for tagged transport");
-        }
-
-        log.info("Deploying process : Updating relevant information for pseudowire {}", l2TunnelId);
-
-        // Populate stores as the final step of the process
-        l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel());
-        l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy());
-
-        return Result.SUCCESS;
     }
 
     @Override
@@ -760,7 +779,7 @@
         CompletableFuture<ObjectiveError> revTermNextFuture = new CompletableFuture<>();
 
         if (l2TunnelId == 0) {
-            log.warn("Removal process : Tunnel id cannot be 0");
+            log.error("Removal process : Tunnel id cannot be 0");
             return Result.WRONG_PARAMETERS.appendError("Pseudowire id can not be 0.");
         }
 
@@ -825,10 +844,13 @@
 
             fwdTermNextFuture.thenAcceptAsync(status -> {
                 if (status == null) {
+                    PortNumber termPort = pwToRemove.l2Tunnel().pathUsed()
+                            .get(pwToRemove.l2Tunnel().pathUsed().size() - 1).dst().port();
                     tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
                                            pwToRemove.l2TunnelPolicy().cP2(),
                                            null,
-                                           FWD);
+                                           FWD,
+                                           termPort);
                 }
             });
         }
@@ -861,10 +883,12 @@
 
             revTermNextFuture.thenAcceptAsync(status -> {
                 if (status == null) {
+                    PortNumber termPort = pwToRemove.l2Tunnel().pathUsed().get(0).src().port();
                     tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
                                            pwToRemove.l2TunnelPolicy().cP1(),
                                            null,
-                                           REV);
+                                           REV,
+                                           termPort);
                 }
             });
         }
@@ -883,14 +907,25 @@
      */
     public Result tearDownPseudowire(long l2TunnelId) {
 
-        if (checkIfPwExists(l2TunnelId, true) == Result.SUCCESS) {
-            return tearDownConnectionPoints(l2TunnelId, true, true, true);
-        } else if (checkIfPwExists(l2TunnelId, false) == Result.SUCCESS) {
-            return tearDownConnectionPoints(l2TunnelId, true, true, false);
-        } else {
-            return Result.WRONG_PARAMETERS.appendError("Pseudowire with "
-                                                        + l2TunnelId
-                                                        + " did not reside in any store!");
+        try {
+            // take the lock
+            pwLock.lock();
+
+            if (checkIfPwExists(l2TunnelId, true) == Result.SUCCESS) {
+                return tearDownConnectionPoints(l2TunnelId, true, true, true);
+            } else if (checkIfPwExists(l2TunnelId, false) == Result.SUCCESS) {
+                return tearDownConnectionPoints(l2TunnelId, true, true, false);
+            } else {
+                return Result.WRONG_PARAMETERS.appendError("Pseudowire with "
+                                                                   + l2TunnelId
+                                                                   + " did not reside in any store!");
+            }
+        } catch (StorageException.Timeout e) {
+            log.error("Can not acquire distributed lock for pseudowire {}!", l2TunnelId);
+            return Result.INTERNAL_ERROR.appendError("Can not acquire distributed lock!");
+        } finally {
+            // release the lock
+            pwLock.unlock();
         }
     }
 
@@ -919,16 +954,17 @@
      * @param ingress      the ingress point
      * @param ingressInner the ingress inner tag
      * @param ingressOuter the ingress outer tag
-     * @param nextId       the next objective id
      * @param egressVlan   Vlan-id to set, depends on ingress vlan
      *                     combinations. For example, if pw is double tagged
      *                     then this is the value of the outer vlan, if single
      *                     tagged then it is the new value of the single tag.
      *                     Should be None for untagged traffic.
+     * @param nextId       the next objective id
      * @return the result of the operation
      */
     private Result deployPolicy(long tunnelId, ConnectPoint ingress, VlanId ingressInner,
                                 VlanId ingressOuter, VlanId egressVlan, int nextId) {
+        log.debug("Starting deploying policy for pseudowire {}.", tunnelId);
 
         List<Objective> objectives = Lists.newArrayList();
         // We create the forwarding objective for supporting
@@ -938,8 +974,9 @@
         ObjectiveContext context = new DefaultObjectiveContext((objective) ->
                                                                 log.debug("FwdObj for tunnel {} populated", tunnelId),
                                                                (objective, error) ->
-                                                                log.warn("Failed to populate fwdrObj " +
-                                                                                 "for tunnel {}", tunnelId, error));
+                                                                log.warn("Failed to populate fwdObj " +
+                                                                                 "for tunnel {} : {}",
+                                                                         tunnelId, error));
         objectives.add(fwdBuilder.add(context));
 
         // We create the filtering objective to define the
@@ -956,7 +993,8 @@
         // We create and add objective context.
         context = new DefaultObjectiveContext((objective) -> log.debug("FilterObj for tunnel {} populated", tunnelId),
                                               (objective, error) -> log.warn("Failed to populate filterObj for " +
-                                                                                     "tunnel {}", tunnelId, error));
+                                                                                     "tunnel {} : {}",
+                                                                             tunnelId, error));
         objectives.add(filtBuilder.add(context));
 
         for (Objective objective : objectives) {
@@ -985,9 +1023,10 @@
     private Result deployPseudoWireInit(L2Tunnel l2Tunnel, ConnectPoint ingress,
                                         ConnectPoint egress, Direction direction,
                                         Link nextHop, boolean spinePw, boolean oneHop, VlanId termVlanId) {
-
+        log.debug("Started deploying init next objectives for pseudowire {} for tunnel {} -> {}.",
+                  l2Tunnel.tunnelId(), ingress, egress);
         if (nextHop == null) {
-            log.warn("No path between ingress and egress cps for tunnel {}", l2Tunnel.tunnelId());
+            log.warn("No path between ingress and egress connection points for tunnel {}", l2Tunnel.tunnelId());
             return WRONG_PARAMETERS;
         }
 
@@ -1047,10 +1086,15 @@
      * @param egressVlan the expected vlan at egress
      * @param direction  the direction
      * @param spinePw if the pseudowire involves a spine switch
+     * @param inputTermPort the input port at the termination point for the pseudowire, used for installing special
+     *                      filtering rules at the termination
      * @return the result of the operation
      */
     private Result deployPseudoWireTerm(L2Tunnel l2Tunnel, ConnectPoint egress,
-                                        VlanId egressVlan, Direction direction, boolean spinePw, boolean oneHop) {
+                                        VlanId egressVlan, Direction direction,
+                                        boolean spinePw, boolean oneHop, PortNumber inputTermPort) {
+        log.debug("Started deploying termination objectives for pseudowire {} , direction {}.",
+                  l2Tunnel.tunnelId(), direction == FWD ? "forward" : "reverse");
 
         // We create the group relative to the termination.
         NextObjective.Builder nextObjectiveBuilder = createNextObjective(TERMINATION, egress, null,
@@ -1093,7 +1137,7 @@
         context = new DefaultObjectiveContext((objective) -> log.debug("FwdObj for tunnel termination {} populated",
                                                                        l2Tunnel.tunnelId()),
                                               (objective, error) -> log.warn("Failed to populate fwdrObj" +
-                                                                             " for tunnel termination {}",
+                                                                             " for tunnel termination {} : {}",
                                                                              l2Tunnel.tunnelId(), error));
         srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.add(context));
         log.debug("Creating new FwdObj for termination NextObj with id={} for tunnel {}",
@@ -1101,16 +1145,6 @@
 
         if (spinePw) {
 
-            // determine the input port at the
-            PortNumber inPort;
-
-            if (egress.deviceId().
-                    equals(l2Tunnel.pathUsed().get(0).dst().deviceId())) {
-                    inPort = l2Tunnel.pathUsed().get(0).dst().port();
-            } else {
-                    inPort = l2Tunnel.pathUsed().get(0).src().port();
-            }
-
             MacAddress dstMac;
             try {
                 dstMac = srManager.deviceConfiguration().getDeviceMac(egress.deviceId());
@@ -1122,10 +1156,10 @@
             log.info("Populating filtering objective for pseudowire transport" +
                              " with vlan = {}, port = {}, mac = {}",
                      l2Tunnel.transportVlan(),
-                     inPort,
+                     inputTermPort,
                      dstMac);
             FilteringObjective.Builder filteringObjectiveBuilder =
-                    createNormalPipelineFiltObjective(inPort, l2Tunnel.transportVlan(), dstMac);
+                    createNormalPipelineFiltObjective(inputTermPort, l2Tunnel.transportVlan(), dstMac);
             context = new DefaultObjectiveContext((objective) ->
                                                           log.debug("Special filtObj for  " + "for {} populated",
                                                                     l2Tunnel.tunnelId()),
@@ -1139,7 +1173,7 @@
             srManager.flowObjectiveService.filter(egress.deviceId(), filteringObjectiveBuilder.add(context));
             log.debug("Creating new special FiltObj for termination point with tunnel {} for port {}",
                       l2Tunnel.tunnelId(),
-                      inPort);
+                      inputTermPort);
         }
 
         return SUCCESS;
@@ -1157,7 +1191,7 @@
                                                                          VlanId vlanId,
                                                                          MacAddress dstMac) {
 
-        log.info("Creating filtering objective for pseudowire transport with vlan={}, port={}, mac={}",
+        log.debug("Creating filtering objective for pseudowire intermediate transport with vlan={}, port={}, mac={}",
                  vlanId,
                  inPort,
                  dstMac);
@@ -1186,7 +1220,7 @@
      */
     private FilteringObjective.Builder createFiltObjective(PortNumber inPort, VlanId innerTag, VlanId outerTag) {
 
-        log.info("Creating filtering objective for vlans {} / {}", outerTag, innerTag);
+        log.debug("Creating connection point filtering objective for vlans {} / {}", outerTag, innerTag);
         return DefaultFilteringObjective
                 .builder()
                 .withKey(Criteria.matchInPort(inPort))
@@ -1209,6 +1243,8 @@
     private ForwardingObjective.Builder createTermFwdObjective(MplsLabel pwLabel, long tunnelId,
                                                                PortNumber egressPort, int nextId) {
 
+        log.debug("Creating forwarding objective for termination for tunnel {} : pwLabel {}, egressPort {}, nextId {}",
+                 tunnelId, pwLabel, egressPort, nextId);
         TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
         TrafficTreatment.Builder trafficTreatment = DefaultTrafficTreatment.builder();
         // The flow has to match on the pw label and bos
@@ -1244,6 +1280,7 @@
      */
     private ForwardingObjective.Builder createInitFwdObjective(long tunnelId, PortNumber inPort, int nextId) {
 
+        log.debug("Creating forwarding objective for tunnel {} : Port {} , nextId {}", tunnelId, inPort, nextId);
         TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
 
         // The flow has to match on the mpls logical
@@ -1282,6 +1319,9 @@
                                                       ConnectPoint dstCp,  L2Tunnel l2Tunnel,
                                                       DeviceId egressId, boolean leafSpinePw,
                                                       boolean oneHop, VlanId termVlanId) {
+        log.debug("Creating {} next objective for pseudowire {}.",
+                  pipeline == TERMINATION ? "termination" : "inititation");
+
         NextObjective.Builder nextObjBuilder;
         TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
         if (pipeline == INITIATION) {
@@ -1292,7 +1332,7 @@
             // The pw label is the bottom of stack. It has to
             // be different -1.
             if (l2Tunnel.pwLabel().toInt() == MplsLabel.MAX_MPLS) {
-                log.warn("Pw label not configured");
+                log.error("Pw label not configured");
                 return null;
             }
             treatmentBuilder.pushMpls();
@@ -1318,7 +1358,7 @@
                     srLabel = MplsLabel.mplsLabel(srManager.deviceConfiguration().getPWRoutingLabel(egressId));
 
                 } catch (DeviceConfigNotFoundException e) {
-                    log.warn("Sr label for pw traffic not configured");
+                    log.error("Sr label for pw traffic not configured");
                     return null;
                 }
 
@@ -1333,7 +1373,7 @@
             try {
                 ingressMac = srManager.deviceConfiguration().getDeviceMac(srcCp.deviceId());
             } catch (DeviceConfigNotFoundException e) {
-                log.warn("Was not able to find the ingress mac");
+                log.error("Was not able to find the ingress mac");
                 return null;
             }
             treatmentBuilder.setEthSrc(ingressMac);
@@ -1341,7 +1381,7 @@
             try {
                 neighborMac = srManager.deviceConfiguration().getDeviceMac(dstCp.deviceId());
             } catch (DeviceConfigNotFoundException e) {
-                log.warn("Was not able to find the neighbor mac");
+                log.error("Was not able to find the neighbor mac");
                 return null;
             }
             treatmentBuilder.setEthDst(neighborMac);
@@ -1349,7 +1389,7 @@
             // if true we need to pop the vlan because
             // we instantiate a leaf to leaf pseudowire
             if (!leafSpinePw) {
-                log.info("We should carry this traffic UNTAGGED!");
+                log.debug("We should carry traffic UNTAGGED for pseudowire {}", l2Tunnel.tunnelId());
                 treatmentBuilder.popVlan();
             }
 
@@ -1386,6 +1426,8 @@
      *         current SRLinkWeigher
      */
     private L2TunnelPolicy reverseL2TunnelPolicy(L2TunnelPolicy policy) {
+
+        log.debug("Reversing policy for pseudowire.");
         try {
             // if cp1 is a leaf, just return
             if (srManager.deviceConfiguration().isEdgeDevice(policy.cP1().deviceId())) {
@@ -1470,7 +1512,7 @@
 
         String key = generateKey(tunnelId, direction);
         if (!l2InitiationNextObjStore.containsKey(key)) {
-            log.warn("Abort delete of policy for tunnel {}: next does not exist in the store", tunnelId);
+            log.error("Abort delete of policy for tunnel {}: next does not exist in the store", tunnelId);
             if (future != null) {
                 future.complete(null);
             }
@@ -1492,7 +1534,7 @@
 
             @Override
             public void onError(Objective objective, ObjectiveError error) {
-                log.warn("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error);
+                log.error("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error);
                 if (future != null) {
                     future.complete(error);
                 }
@@ -1532,10 +1574,11 @@
      */
     private void tearDownPseudoWireInit(long l2TunnelId, ConnectPoint ingress,
                                         CompletableFuture<ObjectiveError> future, Direction direction) {
-
+        log.debug("Starting tearing dowing initation of pseudowire {} for direction {}.",
+                  l2TunnelId, direction == FWD ? "forward" : "reverse");
         String key = generateKey(l2TunnelId, direction);
         if (!l2InitiationNextObjStore.containsKey(key)) {
-            log.info("Abort delete of {} for {}: next does not exist in the store", INITIATION, key);
+            log.error("Abort delete of {} for {}: next does not exist in the store", INITIATION, key);
             if (future != null) {
                 future.complete(null);
             }
@@ -1582,11 +1625,13 @@
     private void tearDownPseudoWireTerm(L2Tunnel l2Tunnel,
                                         ConnectPoint egress,
                                         CompletableFuture<ObjectiveError> future,
-                                        Direction direction) {
-
+                                        Direction direction,
+                                        PortNumber inPort) {
+        log.debug("Starting tearing down termination for pseudowire {} direction {}.",
+                  l2Tunnel.tunnelId(), direction == FWD ? "forward" : "reverse");
         String key = generateKey(l2Tunnel.tunnelId(), direction);
         if (!l2TerminationNextObjStore.containsKey(key)) {
-            log.info("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key);
+            log.error("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key);
             if (future != null) {
                 future.complete(null);
             }
@@ -1641,21 +1686,11 @@
         // spine-spine pws
         if (!l2Tunnel.transportVlan().equals(UNTAGGED_TRANSPORT_VLAN)) {
 
-            // determine the input port at the
-            PortNumber inPort;
-
-            if (egress.deviceId().
-                    equals(l2Tunnel.pathUsed().get(0).dst().deviceId())) {
-                inPort = l2Tunnel.pathUsed().get(0).dst().port();
-            } else {
-                inPort = l2Tunnel.pathUsed().get(0).src().port();
-            }
-
             MacAddress dstMac;
             try {
                 dstMac = srManager.deviceConfiguration().getDeviceMac(egress.deviceId());
             } catch (Exception e) {
-                log.info("Device not found in configuration, no programming of MAC address");
+                log.error("Device not found in configuration, no programming of MAC address");
                 dstMac = null;
             }
 
@@ -1668,9 +1703,11 @@
                     createNormalPipelineFiltObjective(inPort, l2Tunnel.transportVlan(), dstMac);
             context = new DefaultObjectiveContext((objective) ->
                                                           log.debug("Special filtObj for  " + "for {} removed",
-                                                                    l2Tunnel.tunnelId()), (objective, error) ->
-                    log.warn("Failed to populate " + "special filtObj " +
-                                     "rule for {}: {}", l2Tunnel.tunnelId(), error));
+                                                                    l2Tunnel.tunnelId()),
+                                                  (objective, error) ->
+                                                          log.warn("Failed to populate " + "special filtObj " +
+                                                                           "rule for {}: {}",
+                                                                   l2Tunnel.tunnelId(), error));
             TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
             filteringObjectiveBuilder.withMeta(treatment.build());
             srManager.flowObjectiveService.filter(egress.deviceId(), filteringObjectiveBuilder.remove(context));
@@ -1693,5 +1730,4 @@
     private String generateKey(long tunnelId, Direction direction) {
         return String.format("%s-%s", tunnelId, direction);
     }
-
 }
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
index 1673cde..ada38f4 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
@@ -32,6 +32,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
 /**
  * Utility class with static methods that help
  * parse pseudowire related information and also
@@ -63,12 +65,7 @@
         } else if (vlan.equals("") || vlan.equals("None")) {
             return VlanId.vlanId("None");
         } else {
-            try {
-                VlanId newVlan = VlanId.vlanId(vlan);
-                return newVlan;
-            } catch (IllegalArgumentException e) {
-                return null;
-            }
+            return VlanId.vlanId(vlan);
         }
     }
 
@@ -78,11 +75,8 @@
      * @return the L2Mode if input is correct
      */
     public static L2Mode parseMode(String mode) {
-
-        if (!mode.equals("RAW") && !mode.equals("TAGGED")) {
-            return null;
-        }
-
+        checkArgument(mode.equals("RAW") || mode.equals("TAGGED"),
+                      "Invalid pseudowire mode of operation, should be TAGGED or RAW.");
         return L2Mode.valueOf(mode);
     }
 
@@ -93,13 +87,7 @@
      * @throws IllegalArgumentException if label is invalid
      */
     public static MplsLabel parsePWLabel(String label) {
-
-        try {
-            MplsLabel pwLabel = MplsLabel.mplsLabel(label);
-            return pwLabel;
-        } catch (Exception e) {
-            return null;
-        }
+        return MplsLabel.mplsLabel(label);
     }
 
     /**
@@ -109,14 +97,9 @@
      * @return The id of pw as an Integer or null if it failed the conversion.
      */
     public static Integer parsePwId(String id) {
-        try {
-            return Integer.parseInt(id);
-        } catch (Exception e) {
-            return null;
-        }
+        return Integer.parseInt(id);
     }
 
-
     /**
      * Helper method to verify if the tunnel is whether or not
      * supported.
diff --git a/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java b/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java
index 00d20a7..8abfa71 100644
--- a/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java
+++ b/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.segmentrouting.web;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.commons.lang3.tuple.Pair;
@@ -27,9 +28,11 @@
 import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
 import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
 import org.onosproject.segmentrouting.pwaas.L2Mode;
+import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*;
@@ -69,13 +72,11 @@
 
         result.put(CP1_INNER_TAG, pseudowire.l2TunnelPolicy().cP1InnerTag().toString());
         result.put(CP1_OUTER_TAG, pseudowire.l2TunnelPolicy().cP1OuterTag().toString());
-
-
         result.put(CP2_INNER_TAG, pseudowire.l2TunnelPolicy().cP2InnerTag().toString());
         result.put(CP2_OUTER_TAG, pseudowire.l2TunnelPolicy().cP2OuterTag().toString());
+        result.put(SERVICE_DELIM_TAG, pseudowire.l2Tunnel().sdTag().toString());
 
         result.put(MODE, pseudowire.l2Tunnel().pwMode() == L2Mode.RAW ? "RAW" : "TAGGED");
-        result.put(SERVICE_DELIM_TAG, pseudowire.l2Tunnel().sdTag().toString());
         result.put(PW_LABEL, pseudowire.l2Tunnel().pwLabel().toString());
 
         return result;
@@ -101,25 +102,77 @@
     }
 
     /**
-     * Returns a JSON containing the failed pseudowires and the reason that its one failed.
+     * Encoded in an Object Node the undecoed pseudowire and the specificError it failed.
+     *
+     * @param failedPW The failed pseudowire in json format
+     * @param specificError The specificError it failed
+     * @param context Our context
+     * @return A node containing the information we provided
+     */
+    public ObjectNode encodeError(JsonNode failedPW, String specificError,
+                                  CodecContext context) {
+        ObjectNode result = context.mapper().createObjectNode();
+
+        result.set(FAILED_PW, failedPW);
+        result.put(REASON, specificError);
+
+        return result;
+    }
+
+    /**
+     * Returns a JSON containing the failed pseudowires and the reason that they failed.
      *
      * @param failedPws Pairs of pws and reasons.
+     * @param undecodedPws Pairs of pws that we could not decode with reason being illegal arguments.
      * @param context The context
      * @return ObjectNode representing the json to return
      */
     public ObjectNode encodeFailedPseudowires(
             List<Pair<DefaultL2TunnelDescription, String>> failedPws,
+            List<Pair<JsonNode, String>> undecodedPws,
             CodecContext context) {
 
         ArrayNode failedNodes = context.mapper().createArrayNode();
         failedPws.stream()
                 .forEach(failed -> failedNodes.add(encodeError(failed.getKey(), failed.getValue(), context)));
+        undecodedPws.stream()
+                .forEach(failed -> failedNodes.add(encodeError(failed.getKey(), failed.getValue(), context)));
         final ObjectNode toReturn = context.mapper().createObjectNode();
         toReturn.set(FAILED_PWS, failedNodes);
         return toReturn;
     }
 
     /**
+     *
+     * @param json The json containing the pseudowires.
+     * @param context The context
+     * @return A pair of lists.
+     *         First list contains pseudowires that we were not able to decode
+     *         along with the reason we could not decode them.
+     *         Second list contains successfully decoded pseudowires which we are
+     *         going to instantiate.
+     */
+    public Pair<List<Pair<JsonNode, String>>, List<L2TunnelDescription>> decodePws(ArrayNode json,
+                                                                                   CodecContext context) {
+
+        List<L2TunnelDescription> decodedPws = new ArrayList<>();
+        List<Pair<JsonNode, String>> notDecodedPws = new ArrayList<>();
+        for (JsonNode node : json) {
+            DefaultL2TunnelDescription l2Description;
+            try {
+                l2Description = decode((ObjectNode) node, context);
+                decodedPws.add(l2Description);
+            } catch (IllegalArgumentException e) {
+                // the reason why we could not decode this pseudowire is encoded in the
+                // exception, we need to store it now
+                notDecodedPws.add(Pair.of(node, e.getMessage()));
+            }
+        }
+
+        return Pair.of(notDecodedPws, decodedPws);
+    }
+
+    /**
      * Decodes a json containg a single field with the pseudowire id.
      *
      * @param json Json to decode.
@@ -127,8 +180,10 @@
      */
     public static Integer decodeId(ObjectNode json) {
 
-        Integer id = parsePwId(json.path(PW_ID).asText());
-        if (id == null) {
+        Integer id;
+        try {
+            id = parsePwId(json.path(PW_ID).asText());
+        } catch (IllegalArgumentException e) {
             log.error("Pseudowire id is not an integer!");
             return null;
         }
@@ -139,66 +194,25 @@
     @Override
     public DefaultL2TunnelDescription decode(ObjectNode json, CodecContext context) {
 
-        String tempString;
-
         Integer id = parsePwId(json.path(PW_ID).asText());
-        if (id == null) {
-            log.error("Pseudowire id is not an integer");
-            return null;
-        }
 
         ConnectPoint cP1, cP2;
-        try {
-            tempString = json.path(CP1).asText();
-            cP1 = ConnectPoint.deviceConnectPoint(tempString);
-        } catch (Exception e) {
-            log.error("cP1 is not a valid connect point!");
-            return null;
-        }
+        cP1 = ConnectPoint.deviceConnectPoint(json.path(CP1).asText());
+        cP2 = ConnectPoint.deviceConnectPoint(json.path(CP2).asText());
 
-        try {
-            tempString = json.path(CP2).asText();
-            cP2 = ConnectPoint.deviceConnectPoint(tempString);
-        } catch (Exception e) {
-            log.error("cP2 is not a valid connect point!");
-            return null;
-        }
-
-        VlanId cP1InnerVlan = parseVlan(json.path(CP1_INNER_TAG).asText());
-        VlanId cP1OuterVlan = parseVlan(json.path(CP1_OUTER_TAG).asText());
-        VlanId cP2InnerVlan = parseVlan(json.path(CP2_INNER_TAG).asText());
-        VlanId cP2OuterVlan = parseVlan(json.path(CP2_OUTER_TAG).asText());
-        if ((cP1InnerVlan == null) || (cP1OuterVlan == null) ||
-                (cP2InnerVlan == null) || (cP2OuterVlan == null)) {
-            log.error("One or more vlan for cp1 or cp2 is malformed, it shouldbe an integer / Any / None / *");
-            return null;
-        }
+        VlanId cP1InnerVlan, cP1OuterVlan, cP2InnerVlan, cP2OuterVlan, sdTag;
+        cP1InnerVlan = parseVlan(json.path(CP1_INNER_TAG).asText());
+        cP1OuterVlan = parseVlan(json.path(CP1_OUTER_TAG).asText());
+        cP2InnerVlan = parseVlan(json.path(CP2_INNER_TAG).asText());
+        cP2OuterVlan = parseVlan(json.path(CP2_OUTER_TAG).asText());
+        sdTag = parseVlan(json.path(SERVICE_DELIM_TAG).asText());
 
         L2Mode mode = parseMode(json.path(MODE).asText());
-        if (mode == null) {
-            log.error("Mode should be RAW or TAGGED!");
-            return null;
-        }
-
-        VlanId sdTag = parseVlan(json.path(SERVICE_DELIM_TAG).asText());
-        if (sdTag == null) {
-            log.error("SD tag is malformed, it should be an integer / Any / None / *");
-            return null;
-        }
-
         MplsLabel pwLabel = parsePWLabel(json.path(PW_LABEL).asText());
-        if (pwLabel == null) {
-            log.error("PW label is malformed, should be an integer!");
-            return null;
-        }
 
-        DefaultL2Tunnel l2Tunnel;
-        DefaultL2TunnelPolicy l2Policy;
-
-        l2Tunnel = new DefaultL2Tunnel(mode, sdTag, id, pwLabel);
-        l2Policy = new DefaultL2TunnelPolicy(id, cP1, cP1InnerVlan, cP1OuterVlan,
+        DefaultL2Tunnel l2Tunnel = new DefaultL2Tunnel(mode, sdTag, id, pwLabel);
+        DefaultL2TunnelPolicy l2Policy = new DefaultL2TunnelPolicy(id, cP1, cP1InnerVlan, cP1OuterVlan,
                                              cP2, cP2InnerVlan, cP2OuterVlan);
-
         return new DefaultL2TunnelDescription(l2Tunnel, l2Policy);
 
     }
diff --git a/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java b/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java
index 854697b..4867c90 100644
--- a/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java
+++ b/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java
@@ -24,6 +24,7 @@
 import org.onosproject.rest.AbstractWebResource;
 import org.onosproject.segmentrouting.SegmentRoutingService;
 import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
+import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
 import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
 import org.onosproject.segmentrouting.pwaas.L2Tunnel;
 import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
@@ -111,28 +112,36 @@
         ObjectMapper mapper = new ObjectMapper();
         ObjectNode pseudowireJson = readTreeFromStream(mapper, input);
         SegmentRoutingService srService = get(SegmentRoutingService.class);
+        List<Pair<DefaultL2TunnelDescription, String>> failed = new ArrayList<>();
+        List<Pair<JsonNode, String>> undecoded = new ArrayList<>();
 
-        DefaultL2TunnelDescription pseudowire = PSEUDOWIRE_CODEC.decode(pseudowireJson, this);
-        if (pseudowire == null) {
-            return Response.serverError().status(Response.Status.BAD_REQUEST).build();
+        DefaultL2TunnelDescription pseudowire;
+        try {
+            pseudowire = PSEUDOWIRE_CODEC.decode(pseudowireJson, this);
+
+            // pseudowire decoded, try to instantiate it, if we fail add it to failed list
+            long tunId = pseudowire.l2Tunnel().tunnelId();
+            log.debug("Creating pseudowire {} from rest api!", tunId);
+
+            L2TunnelHandler.Result res = srService.addPseudowire(pseudowire);
+            if (res != L2TunnelHandler.Result.SUCCESS) {
+                log.error("Could not create pseudowire {} : {}", pseudowire.l2Tunnel().tunnelId(),
+                          res.getSpecificError());
+                failed.add(Pair.of(pseudowire, res.getSpecificError()));
+            }
+        } catch (IllegalArgumentException e) {
+            log.debug("Pseudowire could not be decoded : {}", e.getMessage());
+            undecoded.add(Pair.of(pseudowireJson, e.getMessage()));
         }
 
-        long tunId = pseudowire.l2Tunnel().tunnelId();
-        log.debug("Creating pseudowire {} from rest api!", tunId);
-
-        L2TunnelHandler.Result res = srService.addPseudowire(pseudowire);
-        switch (res) {
-            case WRONG_PARAMETERS:
-            case CONFIGURATION_ERROR:
-            case PATH_NOT_FOUND:
-            case INTERNAL_ERROR:
-                log.error("Pseudowire {} could not be added : {}", tunId, res.getSpecificError());
-                return Response.serverError().status(Response.Status.INTERNAL_SERVER_ERROR).build();
-            case SUCCESS:
-                log.info("Pseudowire {} succesfully deployed!", pseudowire.l2Tunnel().tunnelId());
-                return Response.ok().build();
-            default:
-                return Response.ok().build();
+        if ((failed.size() == 0) && (undecoded.size() == 0)) {
+            // pseudowire instantiated correctly
+            return Response.ok().build();
+        } else {
+            // failed to decode or instantiate pseudowire, return the reason
+            PseudowireCodec pwCodec = new PseudowireCodec();
+            ObjectNode result = pwCodec.encodeFailedPseudowires(failed, undecoded, this);
+            return Response.serverError().entity(result).build();
         }
     }
 
@@ -152,33 +161,36 @@
         ObjectMapper mapper = new ObjectMapper();
         ObjectNode pseudowireJson = readTreeFromStream(mapper, input);
         SegmentRoutingService srService = get(SegmentRoutingService.class);
-        List<DefaultL2TunnelDescription> pseudowires;
+        Pair<List<Pair<JsonNode, String>>, List<L2TunnelDescription>> pseudowires;
 
         try {
             ArrayNode pseudowiresArray = nullIsIllegal((ArrayNode) pseudowireJson.get(PWS), PWS_KEY_ERROR);
-            pseudowires = PSEUDOWIRE_CODEC.decode(pseudowiresArray, this);
+            // get two lists, first one contains pseudowires that we were unable to decode
+            // that have faulty arguments, second one contains pseudowires that we decoded
+            // succesfully
+            pseudowires = PSEUDOWIRE_CODEC.decodePws(pseudowiresArray, this);
         } catch (ItemNotFoundException e) {
             return Response.serverError().status(Response.Status.BAD_REQUEST).build();
         }
 
         log.debug("Creating pseudowires {} from rest api!", pseudowires);
         List<Pair<DefaultL2TunnelDescription, String>> failed = new ArrayList<>();
-
-        for (DefaultL2TunnelDescription pw : pseudowires) {
+        for (L2TunnelDescription pw : pseudowires.getRight()) {
             L2TunnelHandler.Result res = srService.addPseudowire(pw);
-            if (!(res == L2TunnelHandler.Result.SUCCESS)) {
-                log.trace("Could not create pseudowire {} : {}", pw.l2Tunnel().tunnelId(), res.getSpecificError());
-                failed.add(Pair.of(pw, res.getSpecificError()));
+            if (res != L2TunnelHandler.Result.SUCCESS) {
+                log.error("Could not create pseudowire {} : {}", pw.l2Tunnel().tunnelId(), res.getSpecificError());
+                failed.add(Pair.of((DefaultL2TunnelDescription) pw, res.getSpecificError()));
             }
         }
+        List<Pair<JsonNode, String>> undecodedPws = pseudowires.getLeft();
 
-        if (failed.size() == 0) {
-            // all pseudowires were instantiated
+        if ((failed.size() == 0) && (undecodedPws.size() == 0)) {
+            // all pseudowires were decoded and instantiated succesfully
             return Response.ok().build();
         } else {
             PseudowireCodec pwCodec = new PseudowireCodec();
             // some failed, need to report them to user
-            ObjectNode result = pwCodec.encodeFailedPseudowires(failed, this);
+            ObjectNode result = pwCodec.encodeFailedPseudowires(failed, undecodedPws, this);
             return Response.serverError().entity(result).build();
         }
     }