Pce Load Balancing

Change-Id: I417e7473db86fa26f7a2dc46122dcacdeb584108
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceDeleteLoadBalancingPathCommand.java b/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceDeleteLoadBalancingPathCommand.java
new file mode 100644
index 0000000..75b95c1
--- /dev/null
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceDeleteLoadBalancingPathCommand.java
@@ -0,0 +1,51 @@
+/*
+ * 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.pce.cli;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.pce.pceservice.api.PceService;
+
+import org.slf4j.Logger;
+
+/**
+ * Supports deleting pce load balancing path.
+ */
+@Command(scope = "onos", name = "pce-delete-load-balancing-path",
+        description = "Supports deleting pce load balancing path.")
+public class PceDeleteLoadBalancingPathCommand extends AbstractShellCommand {
+    private final Logger log = getLogger(getClass());
+
+    @Argument(index = 0, name = "name", description = "load balancing path name", required = true,
+            multiValued = false)
+    String name = null;
+
+    @Override
+    protected void execute() {
+        log.info("executing pce-delete-load-balancing-path");
+
+        PceService service = get(PceService.class);
+
+        if (!service.releasePath(name)) {
+            error("Path deletion failed.");
+            return;
+        }
+    }
+}
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceQueryLoadBalancingPathCommand.java b/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceQueryLoadBalancingPathCommand.java
new file mode 100644
index 0000000..9250ba2e
--- /dev/null
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceQueryLoadBalancingPathCommand.java
@@ -0,0 +1,94 @@
+/*
+ * 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.pce.cli;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.tunnel.Tunnel;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.pce.pceservice.api.PceService;
+
+import org.slf4j.Logger;
+
+import java.util.List;
+
+/**
+ * Supports quering PCE load balanced path.
+ */
+@Command(scope = "onos", name = "pce-query-load-balancing-path",
+        description = "Supports querying PCE path.")
+public class PceQueryLoadBalancingPathCommand extends AbstractShellCommand {
+    private final Logger log = getLogger(getClass());
+    public static final String COST_TYPE = "costType";
+
+    @Argument(index = 0, name = "pathName", description = "load balencing path name", required = true,
+            multiValued = false)
+    String name = null;
+
+    @Override
+    protected void execute() {
+        log.info("executing pce-query-load-balancing-path");
+
+        PceService service = get(PceService.class);
+
+        if (name == null) {
+            print("Path name is mandatory");
+            return;
+        }
+
+        List<TunnelId> tunnelIds = service.queryLoadBalancingPath(name);
+        if (tunnelIds == null || tunnelIds.isEmpty()) {
+            print("Release path failed");
+            return;
+        }
+
+        for (TunnelId id : tunnelIds) {
+            Tunnel tunnel = service.queryPath(id);
+            if (tunnel == null) {
+                print("Path doesnot exists");
+                return;
+            }
+            display(tunnel);
+        }
+    }
+
+    /**
+     * Display tunnel information on the terminal.
+     *
+     * @param tunnel pce tunnel
+     */
+    void display(Tunnel tunnel) {
+
+        print("\npath-id                  : %s \n" +
+                "source                   : %s \n" +
+                "destination              : %s \n" +
+                "path-type                : %s \n" +
+                "symbolic-path-name       : %s \n" +
+                "constraints:            \n" +
+                "   cost                  : %s \n" +
+                "   bandwidth             : %s",
+                tunnel.tunnelId().id(), tunnel.path().src().deviceId().toString(),
+                tunnel.path().dst().deviceId().toString(),
+                tunnel.type().name(), tunnel.tunnelName(), tunnel.annotations().value(COST_TYPE),
+                tunnel.annotations().value(AnnotationKeys.BANDWIDTH));
+        print("Path                     : %s", tunnel.path().toString());
+    }
+}
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceSetupPathCommand.java b/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceSetupPathCommand.java
index 18e2ce8..b3c07b8 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceSetupPathCommand.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/cli/PceSetupPathCommand.java
@@ -95,6 +95,10 @@
             required = false, multiValued = true)
     String[] explicitPathInfoStrings;
 
+    @Option(name = "-l", aliases = "--loadBalancing", description = "The load balancing option for user. ",
+            required = false, multiValued = false)
+    boolean loadBalancing = false;
+
     //explicitPathInfo format : Type/SubType/Value(DeviceId or Link info)
     //If Value is Device : Type/SubType/deviceId
     //If Value is Link : Type/SubType/SourceDeviceId/SourcePortNo/DestinationDeviceId/DestinationPortNo
@@ -188,6 +192,15 @@
                 explicitPathInfo.add(obj);
             }
         }
+
+        //with load balancing option
+        if (loadBalancing) {
+            if (!service.setupPath(srcDevice, dstDevice, name, listConstrnt, lspType, loadBalancing)) {
+                error("Path creation failed.");
+            }
+            return;
+        }
+
         if (!service.setupPath(srcDevice, dstDevice, name, listConstrnt, lspType, explicitPathInfo)) {
             error("Path creation failed.");
         }
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
index bc80a7f..658dcbb 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
@@ -17,6 +17,7 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import org.onosproject.net.DisjointPath;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -168,6 +169,7 @@
     private ApplicationId appId;
 
     private final TopologyListener topologyListener = new InternalTopologyListener();
+    public static final String LOAD_BALANCING_PATH_NAME = "loadBalancingPathName";
 
     private List<TunnelId> rsvpTunnelsWithLocalBw = new ArrayList<>();
 
@@ -421,13 +423,26 @@
     @Override
     public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
                              LspType lspType) {
-        return setupPath(src, dst, tunnelName, constraints, lspType, null);
+        return setupPath(src, dst, tunnelName, constraints, lspType, null, false);
     }
 
     //[TODO:] handle requests in queue
     @Override
     public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
                              LspType lspType, List<ExplicitPathInfo> explicitPathInfo) {
+        return setupPath(src, dst, tunnelName, constraints, lspType, explicitPathInfo, false);
+
+    }
+
+    @Override
+    public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
+                             LspType lspType, boolean loadBalancing) {
+        return setupPath(src, dst, tunnelName, constraints, lspType, null, loadBalancing);
+    }
+
+    @Override
+    public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
+                             LspType lspType, List<ExplicitPathInfo> explicitPathInfo, boolean loadBalancing) {
         checkNotNull(src);
         checkNotNull(dst);
         checkNotNull(tunnelName);
@@ -439,7 +454,8 @@
 
         if (srcDevice == null || dstDevice == null) {
             // Device is not known.
-            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
+                    loadBalancing));
             return false;
         }
 
@@ -449,7 +465,8 @@
 
         if (srcLsrId == null || dstLsrId == null) {
             // LSR id is not known.
-            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
+                    loadBalancing));
             return false;
         }
 
@@ -457,7 +474,8 @@
         DeviceCapability cfg = netCfgService.getConfig(DeviceId.deviceId(srcLsrId), DeviceCapability.class);
         if (cfg == null) {
             log.debug("No session to ingress.");
-            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
+                    loadBalancing));
             return false;
         }
 
@@ -495,6 +513,11 @@
         }
         Set<Path> computedPathSet = Sets.newLinkedHashSet();
 
+        if (loadBalancing) {
+            return setupDisjointPaths(src, dst, constraints, tunnelName, bwConstraintValue, lspType, costConstraint,
+                    srcEndPoint, dstEndPoint);
+        }
+
         if (explicitPathInfo != null && !explicitPathInfo.isEmpty()) {
             List<Path> finalComputedPath = computeExplicitPath(explicitPathInfo, src, dst, constraints);
             if (finalComputedPath == null) {
@@ -516,7 +539,8 @@
 
         // NO-PATH
         if (computedPathSet.isEmpty()) {
-            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
+                    loadBalancing));
             return false;
         }
 
@@ -550,14 +574,15 @@
         if (bwConstraintValue != 0) {
             if (!reserveBandwidth(computedPath, bwConstraintValue, null)) {
                 pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints,
-                        lspType, explicitPathInfo));
+                        lspType, explicitPathInfo, loadBalancing));
                 return false;
             }
         }
 
         TunnelId tunnelId = tunnelService.setupTunnel(appId, src, tunnel, computedPath);
         if (tunnelId == null) {
-            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo));
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, explicitPathInfo,
+                    loadBalancing));
 
             if (bwConstraintValue != 0) {
                 computedPath.links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
@@ -574,6 +599,114 @@
         return true;
     }
 
+    private boolean setupDisjointPaths(DeviceId src, DeviceId dst, List<Constraint> constraints, String tunnelName,
+                                       double bwConstraintValue, LspType lspType, CostConstraint costConstraint,
+                                       TunnelEndPoint srcEndPoint, TunnelEndPoint dstEndPoint) {
+        Set<DisjointPath> paths = pathService.getDisjointPaths(src, dst, weight(constraints));
+
+        // NO-PATH
+        if (paths.isEmpty()) {
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
+            return false;
+        }
+
+        DisjointPath path = null;
+        if (!paths.isEmpty()) {
+            path = paths.iterator().next();
+        }
+
+        Builder annotationBuilder = DefaultAnnotations.builder();
+        double bw = 0;
+        if (bwConstraintValue != 0) {
+            //TODO: BW needs to be divided by 2 :: bwConstraintValue/2
+            bw = bwConstraintValue / 2;
+            annotationBuilder.set(BANDWIDTH, String.valueOf(bw));
+        }
+        if (costConstraint != null) {
+            annotationBuilder.set(COST_TYPE, String.valueOf(costConstraint.type()));
+        }
+        annotationBuilder.set(LSP_SIG_TYPE, lspType.name());
+        annotationBuilder.set(PCE_INIT, TRUE);
+        annotationBuilder.set(DELEGATE, TRUE);
+        annotationBuilder.set(LOAD_BALANCING_PATH_NAME, tunnelName);
+
+        //Path computedPath = computedPathSet.iterator().next();
+
+        if (lspType != WITH_SIGNALLING) {
+            /*
+             * Local LSP id which is assigned by RSVP for RSVP signalled LSPs, will be assigned by
+             * PCE for non-RSVP signalled LSPs.
+             */
+            annotationBuilder.set(LOCAL_LSP_ID, String.valueOf(getNextLocalLspId()));
+        }
+
+        //Generate different tunnel name for disjoint paths
+        String tunnel1 = (new StringBuilder()).append(tunnelName).append("_1").toString();
+        String tunnel2 = (new StringBuilder()).append(tunnelName).append("_2").toString();
+
+        // For SR-TE tunnels, call SR manager for label stack and put it inside tunnel.
+        Tunnel tunnelPrimary = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
+                TunnelName.tunnelName(tunnel1), path.primary(),
+                annotationBuilder.build());
+
+        Tunnel tunnelBackup = new DefaultTunnel(null, srcEndPoint, dstEndPoint, MPLS, INIT, null, null,
+                TunnelName.tunnelName(tunnel2), path.backup(),
+                annotationBuilder.build());
+
+        // Allocate bandwidth.
+        if (bwConstraintValue != 0) {
+            if (!reserveBandwidth(path.primary(), bw, null)) {
+                pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel1, constraints,
+                                                           lspType, null, true));
+                return false;
+            }
+
+            if (!reserveBandwidth(path.backup(), bw, null)) {
+                //Release bandwidth resource for tunnel1
+                if (bwConstraintValue != 0) {
+                    path.primary().links().forEach(ln ->
+                                         bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
+                                         Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
+                }
+
+                pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnel2, constraints,
+                                                           lspType, null, true));
+                return false;
+            }
+        }
+
+        TunnelId tunnelId1 = tunnelService.setupTunnel(appId, src, tunnelPrimary, path.primary());
+        if (tunnelId1 == null) {
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
+
+            if (bwConstraintValue != 0) {
+                path.primary().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
+                                                   Double.parseDouble(tunnelPrimary.annotations().value(BANDWIDTH))));
+            }
+
+            return false;
+        }
+
+        TunnelId tunnelId2 = tunnelService.setupTunnel(appId, src, tunnelBackup, path.backup());
+        if (tunnelId2 == null) {
+            //Release 1st tunnel
+            releasePath(tunnelId2);
+
+            pceStore.addFailedPathInfo(new PcePathInfo(src, dst, tunnelName, constraints, lspType, null, true));
+
+            if (bwConstraintValue != 0) {
+                path.backup().links().forEach(ln -> bandwidthMgmtService.releaseLocalReservedBw(LinkKey.linkKey(ln),
+                                                    Double.parseDouble(tunnelBackup.annotations().value(BANDWIDTH))));
+            }
+
+            return false;
+        }
+
+        pceStore.addLoadBalancingTunnelIdsInfo(tunnelName, tunnelId1, tunnelId2);
+        //pceStore.addDisjointPathInfo(tunnelName, path);
+        return true;
+    }
+
     @Override
     public boolean updatePath(TunnelId tunnelId, List<Constraint> constraints) {
         checkNotNull(tunnelId);
@@ -751,6 +884,26 @@
     }
 
     @Override
+    public boolean releasePath(String loadBalancingPathName) {
+        checkNotNull(loadBalancingPathName);
+
+        List<TunnelId> tunnelIds = pceStore.getLoadBalancingTunnelIds(loadBalancingPathName);
+        if (tunnelIds != null && !tunnelIds.isEmpty()) {
+            for (TunnelId id : tunnelIds) {
+                if (!tunnelService.downTunnel(appId, id)) {
+                    return false;
+                }
+            }
+
+            //pceStore.removeDisjointPathInfo(loadBalancedPathName);
+            pceStore.removeLoadBalancingTunnelIdsInfo(loadBalancingPathName);
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
     public Iterable<Tunnel> queryAllPath() {
         return tunnelService.queryTunnel(MPLS);
     }
@@ -907,7 +1060,8 @@
                 pceStore.addFailedPathInfo(new PcePathInfo(tunnel.path().src().deviceId(), tunnel
                         .path().dst().deviceId(), tunnel.tunnelName().value(), constraintList,
                         LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE)),
-                         pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value())));
+                         pceStore.getTunnelNameExplicitPathInfoMap(tunnel.tunnelName().value()),
+                        tunnel.annotations().value(LOAD_BALANCING_PATH_NAME) != null ? true : false));
                 //Release that tunnel calling PCInitiate
                 releasePath(tunnel.tunnelId());
             }
@@ -1079,7 +1233,8 @@
                                                                   links.get(links.size() - 1).dst().deviceId(),
                                                                   tunnel.tunnelName().value(), constraints, lspType,
                                                                   pceStore.getTunnelNameExplicitPathInfoMap(tunnel
-                                                                          .tunnelName().value())));
+                                                                          .tunnelName().value()), tunnel.annotations()
+                            .value(LOAD_BALANCING_PATH_NAME) != null ? true : false));
                 }
 
                 break;
@@ -1115,6 +1270,11 @@
         return pceStore.getTunnelNameExplicitPathInfoMap(tunnelName);
     }
 
+    @Override
+    public List<TunnelId> queryLoadBalancingPath(String pathName) {
+        return pceStore.getLoadBalancingTunnelIds(pathName);
+    }
+
     //Computes path from tunnel store and also path failed to setup.
     private void callForOptimization() {
         //Recompute the LSPs which it was delegated [LSPs stored in PCE store (failed paths)]
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/api/PceService.java b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/api/PceService.java
index fdfdb73..db2bdfb 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/api/PceService.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/api/PceService.java
@@ -57,6 +57,35 @@
                       List<ExplicitPathInfo> explicitPathInfo);
 
     /**
+     * Creates new path based on constraints and LSP type with load balancing option.
+     *
+     * @param src source device
+     * @param dst destination device
+     * @param tunnelName name of the tunnel
+     * @param constraints list of constraints to be applied on path
+     * @param lspType type of path to be setup
+     * @param loadBalancing load balancing option enable or not
+     * @return false on failure and true on successful path creation
+     */
+    boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints, LspType lspType,
+                      boolean loadBalancing);
+
+    /**
+     * Creates new path based on constraints and LSP type with load balancing and explicit path options.
+     *
+     * @param src source device
+     * @param dst destination device
+     * @param tunnelName name of the tunnel
+     * @param constraints list of constraints to be applied on path
+     * @param lspType type of path to be setup
+     * @param explicitPathInfo list of explicit path info
+     * @param loadBalancing load balancing option enable or not
+     * @return false on failure and true on successful path creation
+     */
+    boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints, LspType lspType,
+                      List<ExplicitPathInfo> explicitPathInfo, boolean loadBalancing);
+
+    /**
      * Updates an existing path.
      *
      * @param tunnelId tunnel identifier
@@ -74,6 +103,14 @@
     boolean releasePath(TunnelId tunnelId);
 
     /**
+     * Releases load balancing paths.
+     *
+     * @param loadBalancingPathName load balance path name
+     * @return false on failure and true on successful paths removal
+     */
+    boolean releasePath(String loadBalancingPathName);
+
+    /**
      * Queries all paths.
      *
      * @return iterable of existing tunnels
@@ -95,4 +132,12 @@
      * @return list of explicit path info
      */
     List<ExplicitPathInfo> explicitPathInfoList(String tunnelName);
+
+    /**
+     * Queries load balancing paths on load balance path name.
+     *
+     * @param pathName load balance path name
+     * @return list of load balancing tunnels
+     */
+    List<TunnelId> queryLoadBalancingPath(String pathName);
 }
\ No newline at end of file
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/DistributedPceStore.java b/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/DistributedPceStore.java
index eb6fadd..18d291e 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/DistributedPceStore.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/DistributedPceStore.java
@@ -16,6 +16,7 @@
 package org.onosproject.pce.pcestore;
 
 import com.google.common.collect.ImmutableSet;
+import java.util.Arrays;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -23,6 +24,7 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.util.KryoNamespace;
+import org.onosproject.incubator.net.tunnel.TunnelId;
 import org.onosproject.pce.pceservice.ExplicitPathInfo;
 import org.onosproject.pce.pceservice.LspType;
 import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
@@ -57,6 +59,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected StorageService storageService;
 
+    //Mapping tunnel name with Disjoint paths
+    private ConsistentMap<String, List<TunnelId>> tunnelNameDisjoinTunnelIdInfo;
+
     // List of Failed path info
     private DistributedSet<PcePathInfo> failedPathSet;
 
@@ -96,6 +101,15 @@
                                 .build()))
                 .build();
 
+        tunnelNameDisjoinTunnelIdInfo = storageService.<String, List<TunnelId>>consistentMapBuilder()
+                .withName("onos-pce-disjointTunnelIds")
+                .withSerializer(Serializer.using(
+                        new KryoNamespace.Builder()
+                                .register(KryoNamespaces.API)
+                                .register(TunnelId.class)
+                                .build()))
+                .build();
+
         log.info("Started");
     }
 
@@ -157,4 +171,51 @@
         return null;
     }
 
+/*    @Override
+    public DisjointPath getDisjointPaths(String tunnelName) {
+        if (tunnelNameDisjointPathInfo.get(tunnelName) != null) {
+            return tunnelNameDisjointPathInfo.get(tunnelName).value();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean addDisjointPathInfo(String tunnelName, DisjointPath path) {
+        checkNotNull(tunnelName);
+        checkNotNull(path);
+        return tunnelNameDisjointPathInfo.put(tunnelName, path) != null ? true : false;
+    }*/
+
+    @Override
+    public boolean addLoadBalancingTunnelIdsInfo(String tunnelName, TunnelId... tunnelIds) {
+        checkNotNull(tunnelName);
+        checkNotNull(tunnelIds);
+        return tunnelNameDisjoinTunnelIdInfo.put(tunnelName, Arrays.asList(tunnelIds)) != null ? true : false;
+    }
+
+    @Override
+    public List<TunnelId> getLoadBalancingTunnelIds(String tunnelName) {
+        if (tunnelNameDisjoinTunnelIdInfo.get(tunnelName) != null) {
+            return tunnelNameDisjoinTunnelIdInfo.get(tunnelName).value();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean removeLoadBalancingTunnelIdsInfo(String tunnelName) {
+        if (tunnelNameDisjoinTunnelIdInfo.remove(tunnelName) == null) {
+            log.error("Failed to remove entry {} for this tunnelName in DisjointTunnelIdsInfoMap" + tunnelName);
+            return false;
+        }
+        return true;
+    }
+
+ /*   @Override
+    public boolean removeDisjointPathInfo(String tunnelName) {
+        if (tunnelNameDisjointPathInfo.remove(tunnelName) == null) {
+            log.error("Failed to remove entry {} for this tunnelName in DisjointPathInfoMap", tunnelName);
+            return false;
+        }
+        return true;
+    }*/
 }
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/PcePathInfo.java b/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/PcePathInfo.java
index 6497e36..3f38ddd 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/PcePathInfo.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/PcePathInfo.java
@@ -43,6 +43,8 @@
 
     private List<ExplicitPathInfo> explicitPathInfo; //Explicit path info to compute explicit path
 
+    private boolean loadBalancing; //load balancing option
+
     /**
      * Initialization of member variables.
      *
@@ -52,19 +54,22 @@
      * @param constraints list of constraints
      * @param lspType lsp type
      * @param explicitPathInfo explicit path info
+     * @param loadBalancing load balancing option
      */
     public PcePathInfo(DeviceId src,
                     DeviceId dst,
                     String name,
                     List<Constraint> constraints,
                     LspType lspType,
-                    List<ExplicitPathInfo> explicitPathInfo) {
+                    List<ExplicitPathInfo> explicitPathInfo,
+                    boolean loadBalancing) {
        this.src = src;
        this.dst = dst;
        this.name = name;
        this.constraints = constraints;
        this.lspType = lspType;
        this.explicitPathInfo = explicitPathInfo;
+       this.loadBalancing = loadBalancing;
     }
 
     /**
@@ -77,6 +82,7 @@
        this.constraints = null;
        this.lspType = null;
        this.explicitPathInfo = null;
+       this.loadBalancing = false;
     }
 
     /**
@@ -187,9 +193,27 @@
         this.explicitPathInfo = explicitPathInfo;
     }
 
+    /**
+     * Returns whether stored path has enabled load balancing.
+     *
+     * @return load balancing option is enable
+     */
+    public boolean isLoadBalancing() {
+        return loadBalancing;
+    }
+
+    /**
+     * Sets load balancing option is enable.
+     *
+     * @param loadBalancing load balancing option is enable
+     */
+    public void loadBalancing(boolean loadBalancing) {
+        this.loadBalancing = loadBalancing;
+    }
+
     @Override
     public int hashCode() {
-        return Objects.hash(src, dst, name, constraints, lspType, explicitPathInfo);
+        return Objects.hash(src, dst, name, constraints, lspType, explicitPathInfo, loadBalancing);
     }
 
     @Override
@@ -204,7 +228,8 @@
                     Objects.equals(this.name, other.name) &&
                     Objects.equals(this.constraints, other.constraints) &&
                     Objects.equals(this.lspType, other.lspType) &&
-                    Objects.equals(this.explicitPathInfo, other.explicitPathInfo);
+                    Objects.equals(this.explicitPathInfo, other.explicitPathInfo) &&
+                    Objects.equals(this.loadBalancing, other.loadBalancing);
         }
         return false;
     }
@@ -219,6 +244,7 @@
                 .add("Constraints", constraints)
                 .add("explicitPathInfo", explicitPathInfo)
                 .add("LspType", lspType)
+                .add("loadBalancing", loadBalancing)
                 .toString();
     }
 }
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/api/PceStore.java b/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/api/PceStore.java
index 61f7fda..9ca38cb 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/api/PceStore.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/pcestore/api/PceStore.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.pce.pcestore.api;
 
+import org.onosproject.incubator.net.tunnel.TunnelId;
 import org.onosproject.pce.pceservice.ExplicitPathInfo;
 import org.onosproject.pce.pcestore.PcePathInfo;
 
@@ -79,4 +80,35 @@
      * @return list of explicit path info
      */
     List<ExplicitPathInfo> getTunnelNameExplicitPathInfoMap(String tunnelName);
+
+    //DisjointPath getDisjointPaths(String tunnelName);
+
+    //boolean addDisjointPathInfo(String tunnelName, DisjointPath path);
+
+    /**
+     * Stores load balancing tunnels by load balance path name.
+     *
+     * @param loadBalancingPathName load balancing path name
+     * @param tunnelIds list load balancing tunnels
+     * @return success or failure
+     */
+    boolean addLoadBalancingTunnelIdsInfo(String loadBalancingPathName, TunnelId... tunnelIds);
+
+    /**
+     * Query load balancing tunnels by load balance path name.
+     *
+     * @param loadBalancingPathName load balancing path name
+     * @return list of load balancing tunnels
+     */
+    List<TunnelId> getLoadBalancingTunnelIds(String loadBalancingPathName);
+
+    /**
+     * Removes load balancing tunnel info.
+     *
+     * @param loadBalancingPathName load balancing path name
+     * @return success or failure
+     */
+    boolean removeLoadBalancingTunnelIdsInfo(String loadBalancingPathName);
+
+    //boolean removeDisjointPathInfo(String tunnelName);
 }
diff --git a/apps/pce/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/pce/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 9704c5c..1d4d5a3 100644
--- a/apps/pce/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/pce/app/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -27,5 +27,11 @@
     <command>
       <action class="org.onosproject.pce.cli.PceDeletePathCommand"/>
     </command>
+    <command>
+      <action class="org.onosproject.pce.cli.PceQueryLoadBalancingPathCommand"/>
+    </command>
+    <command>
+      <action class="org.onosproject.pce.cli.PceDeleteLoadBalancingPathCommand"/>
+    </command>
   </command-bundle>
 </blueprint>
diff --git a/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/DistributedPceStoreTest.java b/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/DistributedPceStoreTest.java
index 0039c3c..ccefcf4 100644
--- a/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/DistributedPceStoreTest.java
+++ b/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/DistributedPceStoreTest.java
@@ -119,7 +119,7 @@
        Constraint bandwidth1 = BandwidthConstraint.of(200, DataRateUnit.BPS);
        constraints1.add(bandwidth1);
 
-       failedPathInfo1 = new PcePathInfo(src1, dst1, name1, constraints1, lspType1, null);
+       failedPathInfo1 = new PcePathInfo(src1, dst1, name1, constraints1, lspType1, null, false);
 
        // Creates failedPathInfo2
        DeviceId src2 = DeviceId.deviceId("foo2");
@@ -130,7 +130,7 @@
        Constraint bandwidth2 = BandwidthConstraint.of(400, DataRateUnit.BPS);
        constraints2.add(bandwidth2);
 
-       failedPathInfo2 = new PcePathInfo(src2, dst2, name2, constraints2, lspType2, null);
+       failedPathInfo2 = new PcePathInfo(src2, dst2, name2, constraints2, lspType2, null, false);
 
        // Creates failedPathInfo3
        DeviceId src3 = DeviceId.deviceId("foo3");
@@ -141,7 +141,7 @@
        Constraint bandwidth3 = BandwidthConstraint.of(500, DataRateUnit.BPS);
        constraints3.add(bandwidth3);
 
-       failedPathInfo3 = new PcePathInfo(src3, dst3, name3, constraints3, lspType3, null);
+       failedPathInfo3 = new PcePathInfo(src3, dst3, name3, constraints3, lspType3, null, false);
 
        // Creates failedPathInfo4
        DeviceId src4 = DeviceId.deviceId("foo4");
@@ -152,7 +152,7 @@
        Constraint bandwidth4 = BandwidthConstraint.of(600, DataRateUnit.BPS);
        constraints4.add(bandwidth4);
 
-       failedPathInfo4 = new PcePathInfo(src4, dst4, name4, constraints4, lspType4, null);
+       failedPathInfo4 = new PcePathInfo(src4, dst4, name4, constraints4, lspType4, null, false);
     }
 
     @After
diff --git a/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/PcePathInfoTest.java b/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/PcePathInfoTest.java
index a13c634..fa2bc21 100644
--- a/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/PcePathInfoTest.java
+++ b/apps/pce/app/src/test/java/org/onosproject/pce/pcestore/PcePathInfoTest.java
@@ -53,10 +53,10 @@
         Constraint bandwidth13 = BandwidthConstraint.of(300, DataRateUnit.BPS);
         constraints1.add(bandwidth13);
 
-        PcePathInfo pathInfo1 = new PcePathInfo(src1, dst1, name1, constraints1, lspType1, null);
+        PcePathInfo pathInfo1 = new PcePathInfo(src1, dst1, name1, constraints1, lspType1, null, false);
 
         // create same object as above object
-        PcePathInfo samePathInfo1 = new PcePathInfo(src1, dst1, name1, constraints1, lspType1, null);
+        PcePathInfo samePathInfo1 = new PcePathInfo(src1, dst1, name1, constraints1, lspType1, null, false);
 
         // Create different object.
         DeviceId src2 = DeviceId.deviceId("foo2");
@@ -69,7 +69,7 @@
         Constraint bandwidth22 = BandwidthConstraint.of(800, DataRateUnit.BPS);
         constraints2.add(bandwidth22);
 
-        PcePathInfo pathInfo2 = new PcePathInfo(src2, dst2, name2, constraints2, lspType2, null);
+        PcePathInfo pathInfo2 = new PcePathInfo(src2, dst2, name2, constraints2, lspType2, null, false);
 
         new EqualsTester().addEqualityGroup(pathInfo1, samePathInfo1)
                           .addEqualityGroup(pathInfo2)
@@ -93,7 +93,7 @@
         Constraint bandwidth3 = BandwidthConstraint.of(300, DataRateUnit.BPS);
         constraints.add(bandwidth3);
 
-        PcePathInfo pathInfo = new PcePathInfo(src, dst, name, constraints, lspType, null);
+        PcePathInfo pathInfo = new PcePathInfo(src, dst, name, constraints, lspType, null, false);
 
         assertThat(src, is(pathInfo.src()));
         assertThat(dst, is(pathInfo.dst()));
diff --git a/apps/pce/app/src/test/java/org/onosproject/pce/util/PceStoreAdapter.java b/apps/pce/app/src/test/java/org/onosproject/pce/util/PceStoreAdapter.java
index 8688fb3..76e0e84 100644
--- a/apps/pce/app/src/test/java/org/onosproject/pce/util/PceStoreAdapter.java
+++ b/apps/pce/app/src/test/java/org/onosproject/pce/util/PceStoreAdapter.java
@@ -16,12 +16,15 @@
 package org.onosproject.pce.util;
 
 import com.google.common.collect.ImmutableSet;
+import org.onosproject.incubator.net.tunnel.TunnelId;
 import org.onosproject.pce.pceservice.ExplicitPathInfo;
 import org.onosproject.pce.pcestore.PcePathInfo;
 import org.onosproject.pce.pcestore.api.PceStore;
 
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Arrays;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -39,6 +42,9 @@
     // Locally maintain with tunnel name as key and corresponding list of explicit path object
     private Map<String, List<ExplicitPathInfo>> tunnelNameExplicitPathInfoMap = new HashMap<>();
 
+    //Mapping tunnel name with Disjoint paths
+    private Map<String, List<TunnelId>> loadBalancingPathNameTunnelIdInfo = new HashMap<>();
+
     @Override
     public boolean existsFailedPathInfo(PcePathInfo pathInfo) {
         return failedPathInfoSet.contains(pathInfo);
@@ -77,4 +83,47 @@
     public List<ExplicitPathInfo> getTunnelNameExplicitPathInfoMap(String tunnelName) {
         return tunnelNameExplicitPathInfoMap.get(tunnelName);
     }
+
+/*    @Override
+    public DisjointPath getDisjointPaths(String tunnelName) {
+        if (tunnelNameDisjointPathInfo.get(tunnelName) != null) {
+            return tunnelNameDisjointPathInfo.get(tunnelName);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean addDisjointPathInfo(String tunnelName, DisjointPath path) {
+        return tunnelNameDisjointPathInfo.put(tunnelName, path) != null ? true : false;
+    }*/
+
+    @Override
+    public boolean addLoadBalancingTunnelIdsInfo(String loadBalancingPathName, TunnelId... tunnelIds) {
+        return loadBalancingPathNameTunnelIdInfo.put(loadBalancingPathName,
+                Arrays.asList(tunnelIds)) != null ? true : false;
+    }
+
+    @Override
+    public List<TunnelId> getLoadBalancingTunnelIds(String loadBalancingPathName) {
+        if (loadBalancingPathNameTunnelIdInfo.get(loadBalancingPathName) != null) {
+            return loadBalancingPathNameTunnelIdInfo.get(loadBalancingPathName);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean removeLoadBalancingTunnelIdsInfo(String loadBalancingPathName) {
+        if (loadBalancingPathNameTunnelIdInfo.remove(loadBalancingPathName) == null) {
+            return false;
+        }
+        return true;
+    }
+
+/*    @Override
+    public boolean removeDisjointPathInfo(String tunnelName) {
+        if (tunnelNameDisjointPathInfo.remove(tunnelName) == null) {
+            return false;
+        }
+        return true;
+    }*/
 }
diff --git a/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java b/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java
index 20a53e1..2a316ca 100644
--- a/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java
+++ b/apps/pce/pcerest/src/test/java/org/onosproject/pcerest/PcePathResourceTest.java
@@ -286,7 +286,7 @@
      */
     @Test
     public void testDelete() {
-        expect(pceService.releasePath(anyObject()))
+        expect(pceService.releasePath(TunnelId.valueOf("1")))
                          .andReturn(true)
                          .anyTimes();
         replay(pceService);
diff --git a/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovMessageHandler.java b/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovMessageHandler.java
index 5c47248..a899d95 100644
--- a/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovMessageHandler.java
+++ b/apps/pce/pceweb/src/main/java/org/onosproject/pceweb/PceWebTopovMessageHandler.java
@@ -16,9 +16,11 @@
 
 package org.onosproject.pceweb;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.IpAddress;
 import org.onlab.util.DataRateUnit;
@@ -50,10 +52,12 @@
 import org.onosproject.ui.topo.LinkHighlight;
 import org.onosproject.ui.topo.Mod;
 import org.onosproject.ui.topo.NodeBadge;
+import org.onosproject.ui.topo.TopoJson;
 import org.onosproject.ui.topo.TopoUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
@@ -85,6 +89,7 @@
     private static final String DST = "DST";
     private static final String SRC = "SRC";
     private static final String BANDWIDTH = "bw";
+    private static final String LOADBALANCING = "lb";
     private static final String BANDWIDTHTYPE = "bwtype";
     private static final String COSTTYPE = "ctype";
     private static final String LSPTYPE = "lsptype";
@@ -198,6 +203,7 @@
             String bandWidth = string(payload, BANDWIDTH);
             String bandWidthType = string(payload, BANDWIDTHTYPE);
             String costType = string(payload, COSTTYPE);
+            String loadBalancing = string(payload, LOADBALANCING);
             String lspType = string(payload, LSPTYPE);
             String tunnelName = string(payload, TUNNEL_NAME);
 
@@ -226,7 +232,7 @@
             }
 
             if ((src != null) && (dst != null)) {
-                findAndSendPaths(src, dst, bandWidth, bandWidthType, costType, lspType, tunnelName);
+                findAndSendPaths(src, dst, bandWidth, bandWidthType, costType, lspType, tunnelName, loadBalancing);
             }
         }
     }
@@ -371,8 +377,26 @@
             for (Tunnel tunnel : tunnelSet) {
                 if (tunnel.type() == MPLS) {
                     if (tunnel.state().equals(ACTIVE)) {
-                        arrayNode.add(tunnel.tunnelId().toString());
-                        arrayNode.add(tunnel.tunnelName().toString());
+
+                        if (tunnel.annotations().value("loadBalancingPathName") != null) {
+                            boolean present = false;
+                            if (!arrayNode.isNull()) {
+                                for (JsonNode node : arrayNode) {
+                                    if (node.asText().equals(tunnel.annotations().value("loadBalancingPathName"))) {
+                                        present = true;
+                                        break;
+                                    }
+                                }
+                                if (!present) {
+                                    arrayNode.add("");
+                                    arrayNode.add(tunnel.annotations().value("loadBalancingPathName"));
+                                }
+                            }
+
+                        } else {
+                            arrayNode.add(tunnel.tunnelId().toString());
+                            arrayNode.add(tunnel.tunnelName().toString());
+                        }
                     }
                 }
             }
@@ -394,12 +418,22 @@
         @Override
         public void process(ObjectNode payload) {
             String tunnelId = string(payload, TUNNEL_ID);
+            String pathName = string(payload, "tunnelname");
 
-            if (tunnelId == null) {
-                log.error("PCE update path is failed.");
+            //TODO: if tunnel id null it is load banlanced path
+            if (tunnelId.equals("") && pathName != null) {
+                findAndSendPathsRemove(STRING_NULL, pathName);
+             /*   List<TunnelId> tunnelIds = pceService.getLoadBalancedPath(pathName);
+                for (TunnelId id : tunnelIds) {
+                    Tunnel tunnel = tunnelService.queryTunnel(id);
+                    if (tunnel != null) {
+
+                    }
+                }*/
+            } else {
+                findAndSendPathsRemove(tunnelId, null);
             }
 
-            findAndSendPathsRemove(tunnelId);
         }
     }
 
@@ -421,8 +455,27 @@
             tunnelSet = tunnelService.queryTunnel(MPLS);
             for (Tunnel tunnel : tunnelSet) {
                 if (tunnel.state().equals(ACTIVE)) {
-                    arrayNode.add(tunnel.tunnelId().toString());
-                    arrayNode.add(tunnel.tunnelName().toString());
+                    //TODO: if it is load balancing need to check whether to send tunnel ID as null or some negative
+                    //TODO;value
+                    if (tunnel.annotations().value("loadBalancingPathName") != null) {
+                        boolean present = false;
+                        if (!arrayNode.isNull()) {
+                            for (JsonNode node : arrayNode) {
+                                if (node.asText().equals(tunnel.annotations().value("loadBalancingPathName"))) {
+                                    present = true;
+                                    break;
+                                }
+                            }
+                            if (!present) {
+                                arrayNode.add("");
+                                arrayNode.add(tunnel.annotations().value("loadBalancingPathName"));
+                            }
+                        }
+
+                    } else {
+                        arrayNode.add(tunnel.tunnelId().toString());
+                        arrayNode.add(tunnel.tunnelName().toString());
+                    }
                 }
             }
 
@@ -443,26 +496,24 @@
         @Override
         public void process(ObjectNode payload) {
             String tunnelIdStr = string(payload, TUNNEL_ID);
+            String pathName = string(payload, "tunnelname");
 
-            if (tunnelIdStr == null) {
-                log.error("Tunnel Id is NULL.");
-                return;
-            }
-
-            if (tunnelIdStr.equals(STRING_NULL)) {
-                log.error("Tunnel Id is NULL.");
-                return;
-            }
-
-            if (pceService == null) {
-                log.error("PCE service is not active");
-                return;
-            }
-
-            TunnelId tunnelId = TunnelId.valueOf(tunnelIdStr);
-            Tunnel tunnel = tunnelService.queryTunnel(tunnelId);
-            if (tunnel != null) {
-                highlightsForTunnel(tunnel);
+            if (tunnelIdStr.equals("")) {
+                List<Tunnel> tunnels = Lists.newLinkedList();
+                List<TunnelId> tunnelIds = pceService.queryLoadBalancingPath(pathName);
+                for (TunnelId id : tunnelIds) {
+                    Tunnel t = tunnelService.queryTunnel(id);
+                    tunnels.add(t);
+                }
+                if (!tunnels.isEmpty()) {
+                    highlightsForTunnel(tunnels);
+                }
+            } else {
+                TunnelId tunnelId = TunnelId.valueOf(tunnelIdStr);
+                Tunnel t = tunnelService.queryTunnel(tunnelId);
+                if (t != null) {
+                    highlightsForTunnel(t);
+                }
             }
         }
     }
@@ -492,7 +543,7 @@
      */
     private void findAndSendPaths(ElementId src, ElementId dst, String bandWidth,
                                   String bandWidthType, String costType,
-                                  String lspType, String tunnelName) {
+                                  String lspType, String tunnelName, String loadBalancing) {
         log.debug("src={}; dst={};", src, dst);
         boolean path;
         List<Constraint> listConstrnt;
@@ -515,9 +566,17 @@
                 break;
         }
 
+        boolean loadBalancingOpt = Boolean.parseBoolean(loadBalancing);
+
         //TODO: need to get explicit paths [temporarily using null as the value]
-        path = pceService.setupPath((DeviceId) src, (DeviceId) dst,
-                tunnelName, listConstrnt, lspTypeVal, null);
+
+        if (loadBalancingOpt) {
+            path = pceService.setupPath((DeviceId) src, (DeviceId) dst, tunnelName, listConstrnt, lspTypeVal,
+                    loadBalancingOpt);
+        } else {
+            path = pceService.setupPath((DeviceId) src, (DeviceId) dst, tunnelName, listConstrnt, lspTypeVal,
+                    null);
+        }
 
         if (!path) {
             log.error("setup path is failed");
@@ -562,19 +621,24 @@
      *
      * @param tunnelIdStr tunnelId
      */
-    private void findAndSendPathsRemove(String tunnelIdStr) {
-        if (tunnelIdStr != null) {
+    private void findAndSendPathsRemove(String tunnelIdStr, String pathName) {
             if (pceService == null) {
                 log.error("PCE service is not active");
                 return;
             }
+            boolean path;
 
-            TunnelId tunnelId = TunnelId.valueOf(tunnelIdStr);
-            boolean path = pceService.releasePath(tunnelId);
+            if (tunnelIdStr.equals(STRING_NULL) && !pathName.equals(STRING_NULL)) {
+                path = pceService.releasePath(pathName);
+            } else {
+                TunnelId tunnelId = TunnelId.valueOf(tunnelIdStr);
+                path = pceService.releasePath(tunnelId);
+            }
+
             if (!path) {
                 log.error("remove path is failed");
             }
-        }
+
     }
 
     private ImmutableSet.Builder<Link> buildPaths(ImmutableSet.Builder<Link> pathBuilder) {
@@ -747,12 +811,22 @@
         hilightAndSendPaths(highlights);
     }
 
+    private void highlightsForTunnel(Tunnel... tunnels) {
+        highlightsForTunnel(Arrays.asList(tunnels));
+    }
     /**
      * Handles the event of topology listeners.
      */
-    private void highlightsForTunnel(Tunnel tunnel) {
+    private void highlightsForTunnel(List<Tunnel> tunnels) {
         Highlights highlights = new Highlights();
         paths.removeAll(paths);
+
+        if (tunnels.isEmpty()) {
+            log.error("path does not exist");
+            sendMessage(TopoJson.highlightsMessage(highlights));
+            return;
+        }
+        for (Tunnel tunnel : tunnels) {
         if (tunnel.path() == null) {
             log.error("path does not exist");
             sendMessage(highlightsMessage(highlights));
@@ -777,6 +851,7 @@
             }
         }
         paths.add(tunnel.path());
+        }
 
         ImmutableSet.Builder<Link> builder = ImmutableSet.builder();
         allPathLinks = buildPaths(builder).build();
diff --git a/apps/pce/pceweb/src/main/resources/app/view/pcewebTopov/pcewebTopovDemo.js b/apps/pce/pceweb/src/main/resources/app/view/pcewebTopov/pcewebTopovDemo.js
index 7729289..4a1b2f1 100644
--- a/apps/pce/pceweb/src/main/resources/app/view/pcewebTopov/pcewebTopovDemo.js
+++ b/apps/pce/pceweb/src/main/resources/app/view/pcewebTopov/pcewebTopovDemo.js
@@ -121,6 +121,10 @@
         addAttribute('pce-cost-type-name', 'pce-cost-type', 'Cost Type', 'checkbox');
         addAttribute('pce-cost-type-valname', 'pce-cost-type-igp', 'IGP', 'radio');
         addAttribute('pce-cost-type-valname', 'pce-cost-type-te', 'TE', 'radio');
+
+        //Add the load balancing related inputs.
+        addAttribute('pce-load-balancing-option-name', 'pce-load-balance', 'Load balancing', 'checkbox');
+
         //Add the LSP type related inputs.
         p.append('span').text("Lsp Type *");
         p.append('br');
@@ -200,6 +204,11 @@
                 return;
             }
 
+            if (val == 'LoadBalancing') {
+                constType = 'LB';
+                return;
+            }
+
             if (constType == 'TUNNEL') {
                 p.append('span').text('Tunnel Id: ');
                 p.append('span').text(val);
@@ -464,6 +473,8 @@
                 }
             }
 
+            var loadBalancedOption = isChecked('pce-load-balance');
+
             var lspTypeVal = null;
 
             if (isChecked('pce-lsp-type-cr')) {
@@ -480,6 +491,7 @@
                 bw: bandValue,
                 bwtype: bandType,
                 ctype: costTypeVal,
+                lb: loadBalancedOption,
                 lsptype: lspTypeVal,
                 tunnelname: getCheckedValue('pce-tunnel-name-id')
             });
@@ -515,7 +527,8 @@
             var tunnelNameVal = isChecked('tunnel-id-remove-'+idx);
             if (tunnelNameVal) {
                 wss.sendEvent(remPathmsg, {
-                    tunnelid: tunnelNameDataRemove.a[idx]
+                    tunnelid: tunnelNameDataRemove.a[idx],
+                    tunnelname: tunnelNameDataRemove.a[++idx]
                 });
             }
             idx++;
@@ -530,7 +543,8 @@
             var tunnelNameVal = isChecked('tunnel-id-query-'+idx);
             if (tunnelNameVal) {
                 wss.sendEvent(showTunnelHighlightMsg, {
-                    tunnelid: tunnelNameDataQuery.a[idx]
+                    tunnelid: tunnelNameDataQuery.a[idx],
+                    tunnelname: tunnelNameDataQuery.a[++idx]
                 });
             }
             idx++;