Move PCE label handling from APP to protocol.

Change-Id: I26ae21b27ac2dc9ae3302030f6860e0e371c342c
diff --git a/protocols/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/BasicPceccHandler.java b/protocols/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/BasicPceccHandler.java
new file mode 100644
index 0000000..192b909
--- /dev/null
+++ b/protocols/pcep/ctl/src/main/java/org/onosproject/pcep/controller/impl/BasicPceccHandler.java
@@ -0,0 +1,577 @@
+/*
+ * 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.pcep.controller.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.LinkedList;
+
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onosproject.incubator.net.resource.label.DefaultLabelResource;
+import org.onosproject.incubator.net.resource.label.LabelResource;
+import org.onosproject.incubator.net.resource.label.LabelResourceId;
+import org.onosproject.incubator.net.resource.label.LabelResourceService;
+import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint;
+import org.onosproject.incubator.net.tunnel.Tunnel;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.pcelabelstore.DefaultLspLocalLabelInfo;
+import org.onosproject.pcelabelstore.PcepLabelOp;
+import org.onosproject.pcelabelstore.api.LspLocalLabelInfo;
+import org.onosproject.pcelabelstore.api.PceLabelStore;
+import org.onosproject.pcep.controller.LspType;
+import org.onosproject.pcep.controller.PccId;
+import org.onosproject.pcep.controller.PcepAnnotationKeys;
+import org.onosproject.pcep.controller.PcepClient;
+import org.onosproject.pcep.controller.PcepClientController;
+import org.onosproject.pcep.controller.SrpIdGenerators;
+import org.onosproject.pcepio.exceptions.PcepParseException;
+import org.onosproject.pcepio.protocol.PcepAttribute;
+import org.onosproject.pcepio.protocol.PcepBandwidthObject;
+import org.onosproject.pcepio.protocol.PcepEroObject;
+import org.onosproject.pcepio.protocol.PcepLabelObject;
+import org.onosproject.pcepio.protocol.PcepLabelUpdate;
+import org.onosproject.pcepio.protocol.PcepLabelUpdateMsg;
+import org.onosproject.pcepio.protocol.PcepLspObject;
+import org.onosproject.pcepio.protocol.PcepMsgPath;
+import org.onosproject.pcepio.protocol.PcepSrpObject;
+import org.onosproject.pcepio.protocol.PcepUpdateMsg;
+import org.onosproject.pcepio.protocol.PcepUpdateRequest;
+import org.onosproject.pcepio.types.IPv4SubObject;
+import org.onosproject.pcepio.types.NexthopIPv4addressTlv;
+import org.onosproject.pcepio.types.PathSetupTypeTlv;
+import org.onosproject.pcepio.types.PcepLabelDownload;
+import org.onosproject.pcepio.types.PcepValueType;
+import org.onosproject.pcepio.types.StatefulIPv4LspIdentifiersTlv;
+import org.onosproject.pcepio.types.SymbolicPathNameTlv;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+import static org.onosproject.pcep.controller.PcepAnnotationKeys.BANDWIDTH;
+import static org.onosproject.pcep.controller.PcepAnnotationKeys.LSP_SIG_TYPE;
+import static org.onosproject.pcep.controller.PcepAnnotationKeys.PCE_INIT;
+import static org.onosproject.pcep.controller.PcepAnnotationKeys.DELEGATE;
+
+/**
+ * Basic PCECC handler.
+ * In Basic PCECC, after path computation will configure IN and OUT label to nodes.
+ * [X]OUT---link----IN[Y]OUT---link-----IN[Z] where X, Y and Z are nodes.
+ * For generating labels, will go thorough links in the path from Egress to Ingress.
+ * In each link, will take label from destination node local pool as IN label,
+ * and assign this label as OUT label to source node.
+ */
+public final class BasicPceccHandler {
+    private static final Logger log = LoggerFactory.getLogger(BasicPceccHandler.class);
+    public static final int OUT_LABEL_TYPE = 0;
+    public static final int IN_LABEL_TYPE = 1;
+    public static final long IDENTIFIER_SET = 0x100000000L;
+    public static final long SET = 0xFFFFFFFFL;
+    private static final String LSRID = "lsrId";
+    private static final String LABEL_RESOURCE_SERVICE_NULL = "Label Resource Service cannot be null";
+    private static final String PCE_STORE_NULL = "PCE Store cannot be null";
+    private static BasicPceccHandler crHandlerInstance = null;
+    private LabelResourceService labelRsrcService;
+    private DeviceService deviceService;
+    private PceLabelStore pceStore;
+    private PcepClientController clientController;
+    private PcepLabelObject labelObj;
+
+    /**
+     * Initializes default values.
+     */
+    private BasicPceccHandler() {
+    }
+
+    /**
+     * Returns single instance of this class.
+     *
+     * @return this class single instance
+     */
+    public static BasicPceccHandler getInstance() {
+        if (crHandlerInstance == null) {
+            crHandlerInstance = new BasicPceccHandler();
+        }
+        return crHandlerInstance;
+    }
+
+    /**
+     * Initialization of label manager and pce store.
+     *
+     * @param labelRsrcService label resource service
+     * @param pceStore pce label store
+     */
+    public void initialize(LabelResourceService labelRsrcService,
+                           DeviceService deviceService,
+                           PceLabelStore pceStore,
+                           PcepClientController clientController) {
+        this.labelRsrcService = labelRsrcService;
+        this.deviceService = deviceService;
+        this.pceStore = pceStore;
+        this.clientController = clientController;
+    }
+
+    /**
+     * Allocates labels from local resource pool and configure these (IN and OUT) labels into devices.
+     *
+     * @param tunnel tunnel between ingress to egress
+     * @return success or failure
+     */
+    public boolean allocateLabel(Tunnel tunnel) {
+        long applyNum = 1;
+        boolean isLastLabelToPush = false;
+        Collection<LabelResource> labelRscList;
+
+        checkNotNull(labelRsrcService, LABEL_RESOURCE_SERVICE_NULL);
+        checkNotNull(pceStore, PCE_STORE_NULL);
+
+        List<Link> linkList = tunnel.path().links();
+        if ((linkList != null) && (linkList.size() > 0)) {
+            // Sequence through reverse order to push local labels into devices
+            // Generation of labels from egress to ingress
+            for (ListIterator<Link> iterator = linkList.listIterator(linkList.size()); iterator.hasPrevious();) {
+                Link link = iterator.previous();
+                DeviceId dstDeviceId = link.dst().deviceId();
+                DeviceId srcDeviceId = link.src().deviceId();
+                labelRscList = labelRsrcService.applyFromDevicePool(dstDeviceId, applyNum);
+                if ((labelRscList != null) && (labelRscList.size() > 0)) {
+                    // Link label value is taken from destination device local pool.
+                    // [X]OUT---link----IN[Y]OUT---link-----IN[Z] where X, Y and Z are nodes.
+                    // Link label value is used as OUT and IN for both ends
+                    // (source and destination devices) of the link.
+                    // Currently only one label is allocated to a device (destination device).
+                    // So, no need to iterate through list
+                    Iterator<LabelResource> labelIterator = labelRscList.iterator();
+                    DefaultLabelResource defaultLabelResource = (DefaultLabelResource) labelIterator.next();
+                    LabelResourceId labelId = defaultLabelResource.labelResourceId();
+                    log.debug("Allocated local label: " + labelId.toString()
+                              + "to device: " + defaultLabelResource.deviceId().toString());
+                    PortNumber dstPort = link.dst().port();
+
+                    // Check whether this is last link label to push
+                    if (!iterator.hasPrevious()) {
+                       isLastLabelToPush = true;
+                    }
+
+                    try {
+                        // Push into destination device
+                        // Destination device IN port is link.dst().port()
+                        pushLocalLabels(dstDeviceId, labelId, dstPort, tunnel, false,
+                                            Long.valueOf(LabelType.IN_LABEL.value), PcepLabelOp.ADD);
+
+                        // Push into source device
+                        // Source device OUT port will be link.dst().port(). Means its remote port used to send packet.
+                        pushLocalLabels(srcDeviceId, labelId, dstPort, tunnel, isLastLabelToPush,
+                                            Long.valueOf(LabelType.OUT_LABEL.value), PcepLabelOp.ADD);
+                    } catch (PcepParseException e) {
+                        log.error("Failed to push local label for device {} or {} for tunnel {}.",
+                                  dstDeviceId.toString(), srcDeviceId.toString(), tunnel.tunnelName().toString());
+                    }
+
+                    // Add or update pcecc tunnel info in pce store.
+                    updatePceccTunnelInfoInStore(srcDeviceId, dstDeviceId, labelId, dstPort,
+                                                 tunnel);
+                } else {
+                    log.error("Unable to allocate label to device id {}.", dstDeviceId.toString());
+                    releaseLabel(tunnel);
+                    return false;
+                }
+            }
+        } else {
+           log.error("Tunnel {} is having empty links.", tunnel.toString());
+           return false;
+        }
+        return true;
+    }
+
+    /**
+     * Updates list of local labels of PCECC tunnel info in pce store.
+     *
+     * @param srcDeviceId source device in a link
+     * @param dstDeviceId destination device in a link
+     * @param labelId label id of a link
+     * @param dstPort destination device port number of a link
+     * @param tunnel tunnel
+     */
+    public void updatePceccTunnelInfoInStore(DeviceId srcDeviceId, DeviceId dstDeviceId, LabelResourceId labelId,
+                                                PortNumber dstPort, Tunnel tunnel) {
+       // First try to retrieve device from store and update its label id if it is exists,
+       // otherwise add it
+       boolean dstDeviceUpdated = false;
+       boolean srcDeviceUpdated = false;
+
+       List<LspLocalLabelInfo> lspLabelInfoList = pceStore.getTunnelInfo(tunnel.tunnelId());
+       if ((lspLabelInfoList != null) && (lspLabelInfoList.size() > 0)) {
+           for (int i = 0; i < lspLabelInfoList.size(); ++i) {
+               LspLocalLabelInfo lspLocalLabelInfo =
+                       lspLabelInfoList.get(i);
+               LspLocalLabelInfo.Builder lspLocalLabelInfoBuilder = null;
+               if (dstDeviceId.equals(lspLocalLabelInfo.deviceId())) {
+                   lspLocalLabelInfoBuilder = DefaultLspLocalLabelInfo.builder(lspLocalLabelInfo);
+                   lspLocalLabelInfoBuilder.inLabelId(labelId);
+                   // Destination device IN port will be link destination port
+                   lspLocalLabelInfoBuilder.inPort(dstPort);
+                   dstDeviceUpdated = true;
+               } else if (srcDeviceId.equals(lspLocalLabelInfo.deviceId())) {
+                   lspLocalLabelInfoBuilder = DefaultLspLocalLabelInfo.builder(lspLocalLabelInfo);
+                   lspLocalLabelInfoBuilder.outLabelId(labelId);
+                   // Source device OUT port will be link destination (remote) port
+                   lspLocalLabelInfoBuilder.outPort(dstPort);
+                   srcDeviceUpdated = true;
+               }
+
+               // Update
+               if ((lspLocalLabelInfoBuilder != null) && (dstDeviceUpdated || srcDeviceUpdated)) {
+                   lspLabelInfoList.set(i, lspLocalLabelInfoBuilder.build());
+               }
+           }
+       }
+
+       // If it is not found in store then add it to store
+       if (!dstDeviceUpdated || !srcDeviceUpdated) {
+           // If tunnel info itself not available then create new one, otherwise add node to list.
+           if (lspLabelInfoList == null) {
+              lspLabelInfoList = new LinkedList<>();
+           }
+
+           if (!dstDeviceUpdated) {
+               LspLocalLabelInfo lspLocalLabelInfo = DefaultLspLocalLabelInfo.builder()
+                   .deviceId(dstDeviceId)
+                   .inLabelId(labelId)
+                   .outLabelId(null)
+                   .inPort(dstPort) // Destination device IN port will be link destination port
+                   .outPort(null)
+                   .build();
+               lspLabelInfoList.add(lspLocalLabelInfo);
+           }
+
+           if (!srcDeviceUpdated) {
+               LspLocalLabelInfo lspLocalLabelInfo = DefaultLspLocalLabelInfo.builder()
+                   .deviceId(srcDeviceId)
+                   .inLabelId(null)
+                   .outLabelId(labelId)
+                   .inPort(null)
+                   .outPort(dstPort) // Source device OUT port will be link destination (remote) port
+                   .build();
+               lspLabelInfoList.add(lspLocalLabelInfo);
+           }
+
+           pceStore.addTunnelInfo(tunnel.tunnelId(), lspLabelInfoList);
+       }
+    }
+
+    /**
+     * Deallocates unused labels to device pools.
+     *
+     * @param tunnel tunnel between ingress to egress
+     */
+    public void releaseLabel(Tunnel tunnel) {
+
+       checkNotNull(labelRsrcService, LABEL_RESOURCE_SERVICE_NULL);
+       checkNotNull(pceStore, PCE_STORE_NULL);
+
+       Multimap<DeviceId, LabelResource> release = ArrayListMultimap.create();
+       List<LspLocalLabelInfo> lspLocalLabelInfoList = pceStore.getTunnelInfo(tunnel.tunnelId());
+       if ((lspLocalLabelInfoList != null) && (lspLocalLabelInfoList.size() > 0)) {
+           for (Iterator<LspLocalLabelInfo> iterator = lspLocalLabelInfoList.iterator(); iterator.hasNext();) {
+               LspLocalLabelInfo lspLocalLabelInfo = iterator.next();
+               DeviceId deviceId = lspLocalLabelInfo.deviceId();
+               LabelResourceId inLabelId = lspLocalLabelInfo.inLabelId();
+               LabelResourceId outLabelId = lspLocalLabelInfo.outLabelId();
+               PortNumber inPort = lspLocalLabelInfo.inPort();
+               PortNumber outPort = lspLocalLabelInfo.outPort();
+
+               try {
+                   // Push into device
+                   if ((outLabelId != null) && (outPort != null)) {
+                       pushLocalLabels(deviceId, outLabelId, outPort, tunnel, false,
+                                       Long.valueOf(LabelType.OUT_LABEL.value), PcepLabelOp.REMOVE);
+                   }
+
+                   if ((inLabelId != null) && (inPort != null)) {
+                       pushLocalLabels(deviceId, inLabelId, inPort, tunnel, false,
+                                       Long.valueOf(LabelType.IN_LABEL.value), PcepLabelOp.REMOVE);
+                   }
+               } catch (PcepParseException e) {
+                   log.error("Failed to push local label for device {}for tunnel {}.", deviceId.toString(),
+                             tunnel.tunnelName().toString());
+               }
+
+               // List is stored from egress to ingress. So, using IN label id to release.
+               // Only one local label is assigned to device (destination node)
+               // and that is used as OUT label for source node.
+               // No need to release label for last node in the list from pool because label was not allocated to
+               // ingress node (source node).
+               if ((iterator.hasNext()) && (inLabelId != null)) {
+                   LabelResource labelRsc = new DefaultLabelResource(deviceId, inLabelId);
+                   release.put(deviceId, labelRsc);
+               }
+           }
+       }
+
+       // Release from label pool
+       if (!release.isEmpty()) {
+          labelRsrcService.releaseToDevicePool(release);
+       }
+
+       pceStore.removeTunnelInfo(tunnel.tunnelId());
+   }
+
+   //Pushes local labels to the device which is specific to path [CR-case].
+   private void pushLocalLabels(DeviceId deviceId, LabelResourceId labelId,
+            PortNumber portNum, Tunnel tunnel,
+            Boolean isBos, Long labelType, PcepLabelOp type) throws PcepParseException {
+
+        checkNotNull(deviceId);
+        checkNotNull(labelId);
+        checkNotNull(portNum);
+        checkNotNull(tunnel);
+        checkNotNull(labelType);
+        checkNotNull(type);
+
+        PcepClient pc = getPcepClient(deviceId);
+        if (pc == null) {
+            log.error("PCEP client not found");
+            return;
+        }
+
+        PcepLspObject lspObj;
+        LinkedList<PcepLabelUpdate> labelUpdateList = new LinkedList<>();
+        LinkedList<PcepLabelObject> labelObjects = new LinkedList<>();
+        PcepSrpObject srpObj;
+        PcepLabelDownload labelDownload = new PcepLabelDownload();
+        LinkedList<PcepValueType> optionalTlv = new LinkedList<>();
+
+        long portNo = portNum.toLong();
+        portNo = ((portNo & IDENTIFIER_SET) == IDENTIFIER_SET) ? portNo & SET : portNo;
+
+        optionalTlv.add(NexthopIPv4addressTlv.of((int) portNo));
+
+        PcepLabelObject labelObj = pc.factory().buildLabelObject()
+                                   .setOFlag(labelType == OUT_LABEL_TYPE ? true : false)
+                                   .setOptionalTlv(optionalTlv)
+                                   .setLabel((int) labelId.labelId())
+                                   .build();
+
+        /**
+         * Check whether transit node or not. For transit node, label update message should include IN and OUT labels.
+         * Hence store IN label object and next when out label comes add IN and OUT label objects and encode label
+         * update message and send to specified client.
+         */
+        if (!deviceId.equals(tunnel.path().src().deviceId()) && !deviceId.equals(tunnel.path().dst().deviceId())) {
+            //Device is transit node
+            if (labelType == OUT_LABEL_TYPE) {
+                //Store label object having IN label value
+                this.labelObj = labelObj;
+                return;
+            }
+            //Add IN label object
+            labelObjects.add(this.labelObj);
+        }
+
+        //Add OUT label object in case of transit node
+        labelObjects.add(labelObj);
+
+        srpObj = getSrpObject(pc, type, false);
+
+        String lspId = tunnel.annotations().value(PcepAnnotationKeys.LOCAL_LSP_ID);
+        String plspId = tunnel.annotations().value(PcepAnnotationKeys.PLSP_ID);
+        String tunnelIdentifier = tunnel.annotations().value(PcepAnnotationKeys.PCC_TUNNEL_ID);
+
+        LinkedList<PcepValueType> tlvs = new LinkedList<>();
+        StatefulIPv4LspIdentifiersTlv lspIdTlv = new StatefulIPv4LspIdentifiersTlv(((IpTunnelEndPoint) tunnel.src())
+                .ip().getIp4Address().toInt(), Short.valueOf(lspId), Short.valueOf(tunnelIdentifier),
+                ((IpTunnelEndPoint) tunnel.src()).ip().getIp4Address().toInt(),
+                ((IpTunnelEndPoint) tunnel.dst()).ip().getIp4Address().toInt());
+        tlvs.add(lspIdTlv);
+
+        if (tunnel.tunnelName().value() != null) {
+            SymbolicPathNameTlv pathNameTlv = new SymbolicPathNameTlv(tunnel.tunnelName().value().getBytes());
+            tlvs.add(pathNameTlv);
+        }
+
+        boolean delegated = (tunnel.annotations().value(DELEGATE) == null) ? false
+                                                                           : Boolean.valueOf(tunnel.annotations()
+                                                                                   .value(DELEGATE));
+        boolean initiated = (tunnel.annotations().value(PCE_INIT) == null) ? false
+                                                                           : Boolean.valueOf(tunnel.annotations()
+                                                                                   .value(PCE_INIT));
+
+        lspObj = pc.factory().buildLspObject()
+                .setRFlag(false)
+                .setAFlag(true)
+                .setDFlag(delegated)
+                .setCFlag(initiated)
+                .setPlspId(Integer.valueOf(plspId))
+                .setOptionalTlv(tlvs)
+                .build();
+
+        labelDownload.setLabelList(labelObjects);
+        labelDownload.setLspObject(lspObj);
+        labelDownload.setSrpObject(srpObj);
+
+        labelUpdateList.add(pc.factory().buildPcepLabelUpdateObject()
+                            .setLabelDownload(labelDownload)
+                            .build());
+
+        PcepLabelUpdateMsg labelMsg = pc.factory().buildPcepLabelUpdateMsg()
+                                      .setPcLabelUpdateList(labelUpdateList)
+                                      .build();
+
+        pc.sendMessage(labelMsg);
+
+        //If isBos is true, label download is done along the LSP, send PCEP update message.
+        if (isBos) {
+            sendPcepUpdateMsg(pc, lspObj, tunnel);
+        }
+    }
+
+   //Sends PCEP update message.
+   private void sendPcepUpdateMsg(PcepClient pc, PcepLspObject lspObj, Tunnel tunnel) throws PcepParseException {
+       LinkedList<PcepUpdateRequest> updateRequestList = new LinkedList<>();
+       LinkedList<PcepValueType> subObjects = createEroSubObj(tunnel.path());
+
+       if (subObjects == null) {
+           log.error("ERO subjects not present");
+           return;
+       }
+
+       // set PathSetupTypeTlv of SRP object
+       LinkedList<PcepValueType> llOptionalTlv = new LinkedList<PcepValueType>();
+       LspType lspSigType = LspType.valueOf(tunnel.annotations().value(LSP_SIG_TYPE));
+       llOptionalTlv.add(new PathSetupTypeTlv(lspSigType.type()));
+
+       PcepSrpObject srpObj = pc.factory().buildSrpObject()
+                              .setRFlag(false)
+                              .setSrpID(SrpIdGenerators.create())
+                              .setOptionalTlv(llOptionalTlv)
+                              .build();
+
+       PcepEroObject eroObj = pc.factory().buildEroObject()
+                             .setSubObjects(subObjects)
+                             .build();
+
+       float  iBandwidth = 0;
+       if (tunnel.annotations().value(BANDWIDTH) != null) {
+           //iBandwidth = Float.floatToIntBits(Float.parseFloat(tunnel.annotations().value(BANDWIDTH)));
+           iBandwidth = Float.parseFloat(tunnel.annotations().value(BANDWIDTH));
+       }
+       // build bandwidth object
+       PcepBandwidthObject bandwidthObject = pc.factory().buildBandwidthObject()
+                                             .setBandwidth(iBandwidth)
+                                             .build();
+       // build pcep attribute
+       PcepAttribute pcepAttribute = pc.factory().buildPcepAttribute()
+                                     .setBandwidthObject(bandwidthObject)
+                                     .build();
+
+       PcepMsgPath msgPath = pc.factory().buildPcepMsgPath()
+                             .setEroObject(eroObj)
+                             .setPcepAttribute(pcepAttribute)
+                             .build();
+
+       PcepUpdateRequest updateReq = pc.factory().buildPcepUpdateRequest()
+                                    .setSrpObject(srpObj)
+                                    .setMsgPath(msgPath)
+                                    .setLspObject(lspObj)
+                                    .build();
+
+       updateRequestList.add(updateReq);
+
+       //TODO: P = 1 is it P flag in PCEP obj header
+       PcepUpdateMsg updateMsg = pc.factory().buildUpdateMsg()
+                                 .setUpdateRequestList(updateRequestList)
+                                 .build();
+
+       pc.sendMessage(updateMsg);
+   }
+
+   private LinkedList<PcepValueType> createEroSubObj(Path path) {
+       LinkedList<PcepValueType> subObjects = new LinkedList<>();
+       List<Link> links = path.links();
+       ConnectPoint source = null;
+       ConnectPoint destination = null;
+       IpAddress ipDstAddress = null;
+       IpAddress ipSrcAddress = null;
+       PcepValueType subObj = null;
+       long portNo;
+
+       for (Link link : links) {
+           source = link.src();
+           if (!(source.equals(destination))) {
+               //set IPv4SubObject for ERO object
+               portNo = source.port().toLong();
+               portNo = ((portNo & IDENTIFIER_SET) == IDENTIFIER_SET) ? portNo & SET : portNo;
+               ipSrcAddress = Ip4Address.valueOf((int) portNo);
+               subObj = new IPv4SubObject(ipSrcAddress.getIp4Address().toInt());
+               subObjects.add(subObj);
+           }
+
+           destination = link.dst();
+           portNo = destination.port().toLong();
+           portNo = ((portNo & IDENTIFIER_SET) == IDENTIFIER_SET) ? portNo & SET : portNo;
+           ipDstAddress = Ip4Address.valueOf((int) portNo);
+           subObj = new IPv4SubObject(ipDstAddress.getIp4Address().toInt());
+           subObjects.add(subObj);
+       }
+       return subObjects;
+   }
+
+   private PcepSrpObject getSrpObject(PcepClient pc, PcepLabelOp type, boolean bSFlag)
+           throws PcepParseException {
+       PcepSrpObject srpObj;
+       boolean bRFlag = false;
+
+       if (!type.equals(PcepLabelOp.ADD)) {
+           // To cleanup labels, R bit is set
+           bRFlag = true;
+       }
+
+       srpObj = pc.factory().buildSrpObject()
+               .setRFlag(bRFlag)
+               .setSFlag(bSFlag)
+               .setSrpID(SrpIdGenerators.create())
+               .build();
+
+       return srpObj;
+   }
+
+   /**
+    * Returns PCEP client.
+    *
+    * @return PCEP client
+    */
+   private PcepClient getPcepClient(DeviceId deviceId) {
+       Device device = deviceService.getDevice(deviceId);
+
+       // In future projections instead of annotations will be used to fetch LSR ID.
+       String lsrId = device.annotations().value(LSRID);
+       PcepClient pcc = clientController.getClient(PccId.pccId(IpAddress.valueOf(lsrId)));
+       return pcc;
+   }
+}