ONOS-688 (ONOS-1835,1836,1837) :
 - Implements features to create and remove tunnels and tunnel flow policies.
 - Implements REST API to create/show/delete tunnels and policies.
 - Supports only single instance for now.
 - Fix "apply" actions to "write" actions of all flow rules
Change-Id: I3740ed82fed8eab4ab8b03839192da72d3e223f1
diff --git a/apps/segmentrouting/pom.xml b/apps/segmentrouting/pom.xml
index 71f888d..9b1eb57 100644
--- a/apps/segmentrouting/pom.xml
+++ b/apps/segmentrouting/pom.xml
@@ -32,6 +32,96 @@
 
     <properties>
         <onos.app.name>org.onosproject.segmentrouting</onos.app.name>
+        <web.context>/onos/segmentrouting</web.context>
     </properties>
 
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-cli</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            org.slf4j,
+                            org.osgi.framework,
+                            javax.ws.rs,
+                            javax.ws.rs.core,
+                            com.sun.jersey.api.core,
+                            com.sun.jersey.spi.container.servlet,
+                            com.sun.jersey.server.impl.container.servlet,
+                            com.fasterxml.jackson.databind,
+                            com.fasterxml.jackson.databind.node,
+                            com.fasterxml.jackson.core,
+                            org.apache.karaf.shell.commands,
+                            org.apache.commons.lang.math.*,
+                            com.google.common.*,
+                            org.onlab.packet.*,
+                            org.onlab.rest.*,
+                            org.onosproject.*,
+                            org.onlab.util.*,
+                            org.jboss.netty.util.*
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
 </project>
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java
new file mode 100644
index 0000000..f1c0216
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.segmentrouting.grouphandler.NeighborSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Tunnel class.
+ */
+public class DefaultTunnel implements Tunnel {
+
+    private static final Logger log = LoggerFactory
+            .getLogger(DefaultTunnel.class);
+
+    private final String tunnelId;
+    private final List<Integer> labelIds;
+    private final SegmentRoutingManager srManager;
+    private final DeviceConfiguration config;
+
+    private int groupId;
+
+    /**
+     * Creates a Tunnel reference.
+     *
+     * @param srm SegmentRoutingManager object
+     * @param tid  Tunnel ID
+     * @param labelIds Label stack of the tunnel
+     */
+    public DefaultTunnel(SegmentRoutingManager srm, String tid,
+                         List<Integer> labelIds) {
+        this.srManager = checkNotNull(srm);
+        this.tunnelId = checkNotNull(tid);
+        this.labelIds = Collections.unmodifiableList(labelIds);
+        this.config = srManager.deviceConfiguration;
+        this.groupId = -1;
+    }
+
+    /**
+     * Creates a Tunnel reference.
+     *
+     * @param tid  Tunnel ID
+     * @param labelIds Label stack of the tunnel
+     */
+    public DefaultTunnel(String tid, List<Integer> labelIds) {
+        this.srManager = null;
+        this.tunnelId = checkNotNull(tid);
+        this.labelIds = Collections.unmodifiableList(labelIds);
+        this.config = null;
+        this.groupId = -1;
+    }
+
+    /**
+     * Creates a new DefaultTunnel reference using the tunnel reference.
+     *
+     * @param tunnel DefaultTunnel reference
+     */
+    public DefaultTunnel(DefaultTunnel tunnel) {
+        this.srManager = tunnel.srManager;
+        this.tunnelId = tunnel.tunnelId;
+        this.labelIds = tunnel.labelIds;
+        this.config = tunnel.config;
+        this.groupId = tunnel.groupId;
+    }
+
+    @Override
+    public String id() {
+        return this.tunnelId;
+    }
+
+    @Override
+    public List<Integer> labelIds() {
+        return this.labelIds;
+    }
+
+    @Override
+    public boolean create() {
+
+        if (labelIds.isEmpty() || labelIds.size() < 3) {
+            log.error("More than one router needs to specified to created a tunnel");
+            return false;
+        }
+
+        groupId = createGroupsForTunnel();
+        if (groupId < 0) {
+            log.error("Failed to create groups for the tunnel");
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean remove() {
+
+        DeviceId deviceId = config.getDeviceId(labelIds.get(0));
+        srManager.removeNextObjective(deviceId, groupId);
+
+        return true;
+    }
+
+    @Override
+    public int groupId() {
+        return this.groupId;
+    }
+
+    @Override
+    public DeviceId source() {
+        return config.getDeviceId(labelIds.get(0));
+    }
+
+    private int createGroupsForTunnel() {
+
+        List<Integer> portNumbers;
+
+        int groupId;
+
+        DeviceId deviceId = config.getDeviceId(labelIds.get(0));
+        if (deviceId == null) {
+            log.warn("No device found for SID {}", labelIds.get(0));
+            return -1;
+        }
+        Set<DeviceId> deviceIds = new HashSet<>();
+        int sid = labelIds.get(1);
+        if (config.isAdjacencySid(deviceId, sid)) {
+            portNumbers = config.getPortsForAdjacencySid(deviceId, sid);
+            for (Link link: srManager.linkService.getDeviceEgressLinks(deviceId)) {
+                for (Integer port: portNumbers) {
+                    if (link.src().port().toLong() == port) {
+                        deviceIds.add(link.dst().deviceId());
+                    }
+                }
+            }
+        } else {
+            deviceIds.add(config.getDeviceId(sid));
+        }
+
+        NeighborSet ns = new NeighborSet(deviceIds, labelIds.get(2));
+        groupId = srManager.getNextObjectiveId(deviceId, ns);
+
+        return groupId;
+    }
+
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index ad8c0a3..d82eb5e 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -1,5 +1,6 @@
 package org.onosproject.segmentrouting;
 
+import com.google.common.collect.Lists;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.IpPrefix;
@@ -44,6 +45,7 @@
         boolean isEdge;
         HashMap<PortNumber, Ip4Address> gatewayIps;
         HashMap<PortNumber, Ip4Prefix> subnets;
+        List<SegmentRouterConfig.AdjacencySid> adjacencySids;
     }
 
     /**
@@ -80,8 +82,10 @@
                 info.gatewayIps.put(PortNumber.portNumber(s.getPortNo()),
                                     Ip4Address.valueOf(gatewayIp));
             }
+            info.adjacencySids = ((SegmentRouterConfig) cfg).getAdjacencySids();
             this.deviceConfigMap.put(info.deviceId, info);
             this.allSegmentIds.add(info.nodeSid);
+
         }
     }
 
@@ -352,4 +356,49 @@
 
         return false;
     }
+
+    /**
+     * Returns the ports corresponding to the adjacency Sid given.
+     *
+     * @param deviceId device identification of the router
+     * @param sid adjacency Sid
+     * @return list of port numbers
+     */
+    public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
+        if (deviceConfigMap.get(deviceId) != null) {
+            for (SegmentRouterConfig.AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
+                if (asid.getAdjSid() == sid) {
+                    return asid.getPorts();
+                }
+            }
+        }
+
+        return Lists.newArrayList();
+    }
+
+    /**
+     * Check if the Sid given is whether adjacency Sid of the router device or not.
+     *
+     * @param deviceId device identification of the router
+     * @param sid Sid to check
+     * @return true if the Sid given is the adjacency Sid of the device,
+     * otherwise false
+     */
+    public boolean isAdjacencySid(DeviceId deviceId, int sid) {
+        if (deviceConfigMap.get(deviceId) != null) {
+            if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) {
+                return false;
+            } else {
+                for (SegmentRouterConfig.AdjacencySid asid:
+                        deviceConfigMap.get(deviceId).adjacencySids) {
+                    if (asid.getAdjSid() == sid) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+
+        return false;
+    }
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Policy.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Policy.java
new file mode 100644
index 0000000..d47bc2e
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Policy.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting;
+
+import org.onosproject.net.flow.TrafficSelector;
+
+/**
+ * Interface for Segment Routing Policy.
+ */
+public interface Policy {
+    /**
+     * Enums for policy type.
+     */
+    enum Type {
+        // Tunnel flow policy type
+        TUNNEL_FLOW,
+
+        // Load balancing policy type
+        LOADBALANCE,
+
+        // policy to avoid specific routers or links
+        AVOID,
+
+        // Access Control policy type
+        DENY
+    }
+
+    /**
+     * Returns the policy ID.
+     *
+     * @return policy ID
+     */
+    String id();
+
+    /**
+     * Returns the traffic selector object.
+     *
+     * @return TrafficSelector object
+     */
+    TrafficSelector selector();
+
+    /**
+     * Returns the priority of the policy.
+     *
+     * @return priority
+     */
+    int priority();
+
+    /**
+     * Returns the policy type.
+     *
+     * @return policy type
+     */
+    Type type();
+
+    /**
+     * Creates a policy.
+     *
+     * @return true if succeeds, false otherwise
+     */
+    boolean create();
+
+    /**
+     * Removes the policy.
+     *
+     * @return true if succeeds, false otherwise
+     */
+    boolean remove();
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java
new file mode 100644
index 0000000..234dd20
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting;
+
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Segment Routing Policy Handler.
+ */
+public class PolicyHandler {
+
+    protected final Logger log = getLogger(getClass());
+
+    private final HashMap<String, Policy> policyMap;
+
+    /**
+     * Creates a reference.
+     */
+    public PolicyHandler() {
+        policyMap = new HashMap<>();
+    }
+
+    /**
+     * Returns the policies.
+     *
+     * @return policy list
+     */
+    public List<Policy> getPolicies() {
+        List<Policy> policies = new ArrayList<>();
+        policyMap.values().forEach(policy -> policies.add(
+                new TunnelPolicy((TunnelPolicy) policy)));
+
+        return policies;
+    }
+
+    /**
+     * Creates a policy using the policy information given.
+     *
+     * @param policy policy reference to create
+     */
+    public void createPolicy(Policy policy) {
+        policy.create();
+        policyMap.put(policy.id(), policy);
+    }
+
+    /**
+     * Removes the policy given.
+     *
+     * @param policyInfo policy information to remove
+     */
+    public void removePolicy(Policy policyInfo) {
+        if (policyMap.get(policyInfo.id()) != null) {
+            if (policyMap.get(policyInfo.id()).remove()) {
+                policyMap.remove(policyInfo.id());
+            } else {
+                log.error("Failed to remove the policy {}", policyInfo.id());
+            }
+        } else {
+            log.warn("Policy {} was not found", policyInfo.id());
+        }
+    }
+
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 7092093..8c84e39a 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -98,7 +98,8 @@
         sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
         sbuilder.matchEthType(Ethernet.TYPE_IPV4);
 
-        tbuilder.setEthDst(hostMac)
+        tbuilder.deferred()
+                .setEthDst(hostMac)
                 .setEthSrc(config.getDeviceMac(deviceId))
                 .setOutput(outPort);
 
@@ -163,10 +164,10 @@
         // If the next hop is the same as the final destination, then MPLS label
         // is not set.
         if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
-            tbuilder.decNwTtl();
+            tbuilder.deferred().decNwTtl();
             ns = new NeighborSet(nextHops);
         } else {
-            tbuilder.copyTtlOut();
+            tbuilder.deferred().copyTtlOut();
             ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
         }
 
@@ -295,15 +296,15 @@
 
         if (phpRequired) {
             log.debug("getMplsForwardingObjective: php required");
-            tbuilder.copyTtlIn();
+            tbuilder.deferred().copyTtlIn();
             if (isBos) {
-                tbuilder.popMpls(Ethernet.TYPE_IPV4).decNwTtl();
+                tbuilder.deferred().popMpls(Ethernet.TYPE_IPV4).decNwTtl();
             } else {
-                tbuilder.popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
+                tbuilder.deferred().popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
             }
         } else {
             log.debug("getMplsForwardingObjective: php not required");
-            tbuilder.decMplsTtl();
+            tbuilder.deferred().decMplsTtl();
         }
 
         if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
@@ -313,7 +314,8 @@
                 log.warn("No link from {} to {}", deviceId, nextHops);
                 return null;
             }
-            tbuilder.setEthSrc(config.getDeviceMac(deviceId))
+            tbuilder.deferred()
+                    .setEthSrc(config.getDeviceMac(deviceId))
                     .setEthDst(config.getDeviceMac(nextHop))
                     .setOutput(port);
             fwdBuilder.withTreatment(tbuilder.build());
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 87282b4..23eb668 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -20,6 +20,7 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.util.KryoNamespace;
@@ -60,6 +61,7 @@
 
 import java.net.URI;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -69,8 +71,9 @@
 import java.util.concurrent.TimeUnit;
 
 @SuppressWarnings("ALL")
+@Service
 @Component(immediate = true)
-public class SegmentRoutingManager {
+public class SegmentRoutingManager implements SegmentRoutingService {
 
     private static Logger log = LoggerFactory
             .getLogger(SegmentRoutingManager.class);
@@ -101,6 +104,7 @@
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected MastershipService mastershipService;
+
     protected ArpHandler arpHandler = null;
     protected IcmpHandler icmpHandler = null;
     protected IpHandler ipHandler = null;
@@ -108,7 +112,10 @@
     protected ApplicationId appId;
     protected DeviceConfiguration deviceConfiguration = null;
 
+
     private DefaultRoutingHandler defaultRoutingHandler = null;
+    private TunnelHandler tunnelHandler = null;
+    private PolicyHandler policyHandler = null;
     private InternalPacketProcessor processor = new InternalPacketProcessor();
     private InternalEventHandler eventHandler = new InternalEventHandler();
 
@@ -165,6 +172,8 @@
         ipHandler = new IpHandler(this);
         routingRulePopulator = new RoutingRulePopulator(this);
         defaultRoutingHandler = new DefaultRoutingHandler(this);
+        tunnelHandler = new TunnelHandler();
+        policyHandler = new PolicyHandler();
 
         packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
         linkService.addListener(new InternalLinkListener());
@@ -187,6 +196,7 @@
 
         defaultRoutingHandler.startPopulationProcess();
         log.info("Started");
+
     }
 
     @Deactivate
@@ -196,6 +206,51 @@
         log.info("Stopped");
     }
 
+
+    @Override
+    public List<Tunnel> getTunnels() {
+        return tunnelHandler.getTunnels();
+    }
+
+    @Override
+    public void createTunnel(Tunnel tunnel) {
+        tunnelHandler.createTunnel(tunnel);
+    }
+
+    @Override
+    public void removeTunnel(Tunnel tunnel) {
+        for (Policy policy: policyHandler.getPolicies()) {
+            if (policy.type() == Policy.Type.TUNNEL_FLOW) {
+                TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
+                if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
+                    log.warn("Cannot remove the tunnel used by a policy");
+                    return;
+                }
+            }
+        }
+        tunnelHandler.removeTunnel(tunnel);
+    }
+
+    @Override
+    public void removePolicy(Policy policy) {
+        policyHandler.removePolicy(policy);
+
+    }
+
+    @Override
+    public void createPolicy(Policy policy) {
+        policyHandler.createPolicy(policy);
+    }
+
+    @Override
+    public List<Policy> getPolicies() {
+        return policyHandler.getPolicies();
+    }
+
+    public Tunnel getTunnel(String tunnelId) {
+        return tunnelHandler.getTunnel(tunnelId);
+    }
+
     /**
      * Returns the GrouopKey object for the device and the NighborSet given.
      *
@@ -211,6 +266,12 @@
         return null;
     }
 
+    /**
+     *
+     * @param deviceId
+     * @param ns
+     * @return
+     */
     public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
 
         if (groupHandlerMap.get(deviceId) != null) {
@@ -223,6 +284,16 @@
         }
     }
 
+    /**
+     *
+     * @param deviceId
+     * @param objectiveId
+     * @return
+     */
+    public boolean removeNextObjective(DeviceId deviceId, int objectiveId) {
+        return groupHandlerMap.get(deviceId).removeGroup(objectiveId);
+    }
+
     private class InternalPacketProcessor implements PacketProcessor {
 
         @Override
@@ -295,7 +366,7 @@
         }
 
         log.trace("numOfEvents {}, numOfEventHanlderScheduled {}", numOfEvents,
-                  numOfHandlerScheduled);
+                numOfHandlerScheduled);
 
     }
 
@@ -403,4 +474,7 @@
             groupHandler.portDown(port.number());
         }
     }
+
+
+
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
new file mode 100644
index 0000000..2484369
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting;
+
+import java.util.List;
+
+/**
+ * Segment Routing Service for REST API.
+ */
+public interface SegmentRoutingService {
+
+    /**
+     * Returns all tunnels.
+     *
+     * @return list of tunnels
+     */
+    List<Tunnel> getTunnels();
+
+    /**
+     * Creates a tunnel.
+     *
+     * @param tunnel tunnel reference to create
+     */
+    void createTunnel(Tunnel tunnel);
+
+    /**
+     * Returns all policies.
+     *
+     * @return list of policy
+     */
+    List<Policy> getPolicies();
+
+    /**
+     * Creates a policy.
+     *
+     * @param policy policy reference to create
+     */
+    void createPolicy(Policy policy);
+
+    /**
+     * Removes a tunnel.
+     *
+     * @param tunnel tunnel reference to remove
+     */
+    void removeTunnel(Tunnel tunnel);
+
+    /**
+     * Removes a policy.
+     *
+     * @param policy policy reference to remove
+     */
+    void removePolicy(Policy policy);
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Tunnel.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Tunnel.java
new file mode 100644
index 0000000..0c35fba
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Tunnel.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting;
+
+import org.onosproject.net.DeviceId;
+
+import java.util.List;
+
+/**
+ * Tunnel interface.
+ */
+public interface Tunnel {
+
+    /**
+     * Returns the tunnel ID.
+     *
+     * @return tunnel ID
+     */
+    String id();
+
+    /**
+     * Returns Segment IDs for the tunnel including source and destination.
+     *
+     * @return List of Node ID
+     */
+    List<Integer> labelIds();
+
+    /**
+     * Creates a tunnel.
+     *
+     * @return true if succeeds, false otherwise
+     */
+    boolean create();
+
+    /**
+     * Removes the tunnel.
+     *
+     * @return true if succeeds, false otherwise.
+     */
+    boolean remove();
+
+    /**
+     * Returns the group ID for the tunnel.
+     *
+     * @return group ID
+     */
+    int groupId();
+
+    /**
+     * Returns the source device Id of the tunnel.
+     *
+     * @return source device Id
+     */
+    DeviceId source();
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
new file mode 100644
index 0000000..4a498c6
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting;
+
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Tunnel Handler.
+ */
+public class TunnelHandler {
+    protected final Logger log = getLogger(getClass());
+
+    private final HashMap<String, Tunnel> tunnelMap;
+
+    public TunnelHandler() {
+        tunnelMap = new HashMap<>();
+    }
+
+    /**
+     * Creates a tunnel.
+     *
+     * @param tunnel tunnel reference to create a tunnel
+     */
+    public void createTunnel(Tunnel tunnel) {
+        tunnel.create();
+        tunnelMap.put(tunnel.id(), tunnel);
+    }
+
+    /**
+     * Removes the tunnel with the tunnel ID given.
+     *
+     * @param tunnelInfo tunnel information to delete tunnels
+     */
+    public void removeTunnel(Tunnel tunnelInfo) {
+
+        Tunnel tunnel = tunnelMap.get(tunnelInfo.id());
+        if (tunnel != null) {
+            tunnel.remove();
+            tunnelMap.remove(tunnel.id());
+        } else {
+            log.warn("No tunnel found for tunnel ID {}", tunnelInfo.id());
+        }
+    }
+
+    /**
+     * Returns the tunnel with the tunnel ID given.
+     *
+     * @param tid Tunnel ID
+     * @return Tunnel reference
+     */
+    public Tunnel getTunnel(String tid) {
+        return tunnelMap.get(tid);
+    }
+
+    /**
+     * Returns all tunnels.
+     *
+     * @return list of Tunnels
+     */
+    public List<Tunnel> getTunnels() {
+        List<Tunnel> tunnels = new ArrayList<>();
+        tunnelMap.values().forEach(tunnel -> tunnels.add(
+                new DefaultTunnel((DefaultTunnel) tunnel)));
+
+        return tunnels;
+    }
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelPolicy.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelPolicy.java
new file mode 100644
index 0000000..c96c1f9
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelPolicy.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting;
+
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Tunnel Policy.
+ */
+public final class TunnelPolicy implements Policy {
+
+    private final SegmentRoutingManager srManager;
+    private final Type type;
+    private final String id;
+    private final TrafficSelector selector;
+    private final int priority;
+    private final String tunnelId;
+
+    private TunnelPolicy(SegmentRoutingManager srm, String policyId, Type type,
+                         TrafficSelector selector, int priority, String tunnelId) {
+        this.srManager = srm;
+        this.id = checkNotNull(policyId);
+        this.type = type;
+        this.tunnelId = tunnelId;
+        this.priority = priority;
+        this.selector = selector;
+    }
+
+    /**
+     * Creates a TunnelPolicy reference.
+     *
+     * @param p TunnelPolicy reference
+     */
+    public TunnelPolicy(TunnelPolicy p) {
+        this.srManager = p.srManager;
+        this.id = p.id;
+        this.type = p.type;
+        this.tunnelId = p.tunnelId;
+        this.priority = p.priority;
+        this.selector = p.selector;
+    }
+
+    /**
+     * Creates a TunnelPolicy reference.
+     *
+     * @param p TunnelPolicy reference
+     */
+    public TunnelPolicy(SegmentRoutingManager srm, TunnelPolicy p) {
+        this.srManager = srm;
+        this.id = p.id;
+        this.type = p.type;
+        this.tunnelId = p.tunnelId;
+        this.priority = p.priority;
+        this.selector = p.selector;
+    }
+
+    /**
+     * Returns the TunnelPolicy builder reference.
+     *
+     * @return TunnelPolicy builder
+     */
+    public static TunnelPolicy.Builder builder() {
+        return new Builder();
+    }
+
+    @Override
+    public String id() {
+        return this.id;
+    }
+
+    @Override
+    public TrafficSelector selector() {
+        return selector;
+    }
+
+    @Override
+    public int priority() {
+        return priority;
+    }
+
+    @Override
+    public Type type() {
+        return type;
+    }
+
+    @Override
+    public boolean create() {
+
+        Tunnel tunnel = srManager.getTunnel(tunnelId);
+
+        ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
+                .builder()
+                .fromApp(srManager.appId)
+                .makePermanent()
+                .nextStep(tunnel.groupId())
+                .withPriority(priority)
+                .withSelector(selector)
+                .withFlag(ForwardingObjective.Flag.VERSATILE);
+
+        srManager.flowObjectiveService.forward(tunnel.source(), fwdBuilder.add());
+
+        return true;
+    }
+
+    @Override
+    public boolean remove() {
+
+        Tunnel tunnel = srManager.getTunnel(tunnelId);
+
+        ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
+                .builder()
+                .fromApp(srManager.appId)
+                .makePermanent()
+                .withSelector(selector)
+                .withPriority(priority)
+                .nextStep(tunnel.groupId())
+                .withFlag(ForwardingObjective.Flag.VERSATILE);
+
+        srManager.flowObjectiveService.forward(tunnel.source(), fwdBuilder.remove());
+
+        return true;
+    }
+
+    /**
+     * Returns the tunnel ID of the policy.
+     *
+     * @return Tunnel ID
+     */
+    public String tunnelId() {
+        return this.tunnelId;
+    }
+
+    /**
+     * Tunnel Policy Builder.
+     */
+    public static final class Builder {
+
+        private SegmentRoutingManager srManager;
+        private String id;
+        private Type type;
+        private TrafficSelector selector;
+        private int priority;
+        private String tunnelId;
+
+        /**
+         * Sets the policy Id.
+         *
+         * @param id policy Id
+         * @return Builder object
+         */
+        public Builder setPolicyId(String id) {
+            this.id = id;
+
+            return this;
+        }
+
+        /**
+         * Sets the policy type.
+         *
+         * @param type policy type
+         * @return Builder object
+         */
+        public Builder setType(Type type) {
+            this.type = type;
+
+            return this;
+        }
+
+        /**
+         * Sets the TrafficSelector.
+         *
+         * @param selector TrafficSelector
+         * @return Builder object
+         */
+        public Builder setSelector(TrafficSelector selector) {
+            this.selector = selector;
+
+            return this;
+        }
+
+        /**
+         * Sets the priority of the policy.
+         *
+         * @param p priority
+         * @return Builder object
+         */
+        public Builder setPriority(int p) {
+            this.priority = p;
+
+            return this;
+        }
+
+        /**
+         * Sets the tunnel Id.
+         *
+         * @param tunnelId tunnel Id
+         * @return Builder object
+         */
+        public Builder setTunnelId(String tunnelId) {
+            this.tunnelId = tunnelId;
+
+            return this;
+        }
+
+        /**
+         * Sets the Segment Routing Manager reference.
+         *
+         * @param srm Segment Routing Manager reference
+         * @return Builder object
+         */
+        public Builder setManager(SegmentRoutingManager srm) {
+            this.srManager = srm;
+
+            return this;
+        }
+
+        /**
+         * Builds the policy.
+         *
+         * @return Tunnel Policy reference
+         */
+        public Policy build() {
+            return new TunnelPolicy(srManager, id, type, selector, priority, tunnelId);
+        }
+    }
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 1993d3f..4a25438 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -24,6 +24,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -418,7 +419,12 @@
         return nsSegmentIds;
     }
 
-    protected void createGroupsFromNeighborsets(Set<NeighborSet> nsSet) {
+    /**
+     * Creates Groups from a set of NeighborSet given.
+     *
+     * @param nsSet a set of NeighborSet
+     */
+    public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet) {
         for (NeighborSet ns : nsSet) {
             int nextId = flowObjectiveService.allocateNextId();
             NextObjective.Builder nextObjBuilder = DefaultNextObjective
@@ -451,7 +457,7 @@
             NextObjective nextObj = nextObjBuilder.add();
             flowObjectiveService.next(deviceId, nextObj);
             log.debug("createGroupsFromNeighborsets: Submited "
-                    + "next objective {} in device {}",
+                            + "next objective {} in device {}",
                     nextId, deviceId);
             nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, ns),
                                nextId);
@@ -462,4 +468,29 @@
         return new DefaultGroupKey(kryo.build().serialize(obj));
     }
 
+    /**
+     * Removes groups for the next objective ID given.
+     *
+     * @param objectiveId next objective ID to remove
+     * @return true if succeeds, false otherwise
+     */
+    public boolean removeGroup(int objectiveId) {
+
+        if (nsNextObjStore.containsValue(objectiveId)) {
+            NextObjective.Builder nextObjBuilder = DefaultNextObjective
+                    .builder().withId(objectiveId)
+                    .withType(NextObjective.Type.HASHED).fromApp(appId);
+            NextObjective nextObjective = nextObjBuilder.remove();
+            flowObjectiveService.next(deviceId, nextObjective);
+
+            for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
+                if (entry.getValue().equals(objectiveId)) {
+                    nsNextObjStore.remove(entry.getKey());
+                    break;
+                }
+            }
+        }
+
+        return false;
+    }
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java
new file mode 100644
index 0000000..1f9e576
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting.web;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.cli.net.IpProtocol;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.IPProtocolCriterion;
+import org.onosproject.segmentrouting.Policy;
+import org.onosproject.segmentrouting.TunnelPolicy;
+
+public final class PolicyCodec extends JsonCodec<Policy> {
+
+    // JSON field names
+    private static final String POLICY_ID = "policy_id";
+    private static final String PRIORITY = "priority";
+    private static final String TYPE = "policy_type";
+    private static final String TUNNEL_ID = "tunnel_id";
+    private static final String DST_IP = "dst_ip";
+    private static final String SRC_IP = "src_ip";
+    private static final String PROTO_TYPE = "proto_type";
+
+    @Override
+    public ObjectNode encode(Policy policy, CodecContext context) {
+        final ObjectNode result = context.mapper().createObjectNode()
+                .put(POLICY_ID, policy.id());
+
+        result.put(PRIORITY, policy.priority());
+        result.put(TYPE, policy.type().toString());
+
+        if (policy.selector().getCriterion(Criterion.Type.IPV4_DST) != null) {
+            IPCriterion criterion = (IPCriterion) policy.selector().getCriterion(
+                    Criterion.Type.IPV4_DST);
+            result.put(DST_IP, criterion.ip().toString());
+        }
+        if (policy.selector().getCriterion(Criterion.Type.IPV4_SRC) != null) {
+            IPCriterion criterion = (IPCriterion) policy.selector().getCriterion(
+                    Criterion.Type.IPV4_SRC);
+            result.put(SRC_IP, criterion.ip().toString());
+        }
+        if (policy.selector().getCriterion(Criterion.Type.IP_PROTO) != null) {
+            IPProtocolCriterion protocolCriterion =
+                    (IPProtocolCriterion) policy.selector().getCriterion(Criterion.Type.IP_PROTO);
+            result.put(PROTO_TYPE, protocolCriterion.toString());
+        }
+
+        if (policy.type() == Policy.Type.TUNNEL_FLOW) {
+            result.put(TUNNEL_ID, ((TunnelPolicy) policy).tunnelId());
+        }
+
+        return result;
+    }
+
+    @Override
+    public Policy decode(ObjectNode json, CodecContext context) {
+
+        String pid = json.path(POLICY_ID).asText();
+        String type = json.path(TYPE).asText();
+        int priority = json.path(PRIORITY).asInt();
+        String dstIp = json.path(DST_IP).asText();
+        String srcIp = json.path(SRC_IP).asText();
+        String tunnelId = json.path(TUNNEL_ID).asText();
+        String protoType = json.path(PROTO_TYPE).asText();
+
+        if (tunnelId != null) {
+            TrafficSelector.Builder tsb = DefaultTrafficSelector.builder();
+            tsb.matchEthType(Ethernet.TYPE_IPV4);
+            if (dstIp != null && !dstIp.isEmpty()) {
+                tsb.matchIPDst(IpPrefix.valueOf(dstIp));
+            }
+            if (srcIp != null && !srcIp.isEmpty()) {
+                tsb.matchIPSrc(IpPrefix.valueOf(srcIp));
+            }
+            if (protoType != null && !protoType.isEmpty()) {
+                Short ipProto = Short.valueOf(IpProtocol.valueOf(protoType).value());
+                tsb.matchIPProtocol(ipProto.byteValue());
+            }
+
+            TunnelPolicy.Builder tpb = TunnelPolicy.builder().setPolicyId(pid);
+            if (tunnelId != null) {
+                tpb.setTunnelId(tunnelId);
+            }
+            if (!json.path(PRIORITY).isMissingNode()) {
+                tpb.setPriority(priority);
+            }
+            if (!json.path(TYPE).isMissingNode()) {
+                tpb.setType(Policy.Type.valueOf(type));
+            }
+            tpb.setSelector(tsb.build());
+
+            return tpb.build();
+        } else {
+            // TODO: handle more policy types
+            return null;
+        }
+
+
+    }
+
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
new file mode 100644
index 0000000..97e836a
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import org.onosproject.rest.AbstractWebResource;
+import org.onosproject.segmentrouting.Policy;
+import org.onosproject.segmentrouting.SegmentRoutingManager;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.TunnelPolicy;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+@Path("policy")
+public class PolicyWebResource extends AbstractWebResource {
+
+    private static final PolicyCodec POLICY_CODEC = new PolicyCodec();
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getPolicy() {
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        List<Policy> policies = srService.getPolicies();
+        ObjectNode result = new ObjectMapper().createObjectNode();
+        result.set("policy", new PolicyCodec().encode(policies, this));
+
+        return ok(result.toString()).build();
+    }
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createPolicy(InputStream input) throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode policyJson = (ObjectNode) mapper.readTree(input);
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        Policy policyInfo = POLICY_CODEC.decode(policyJson, this);
+        if (policyInfo.type() == Policy.Type.TUNNEL_FLOW) {
+            TunnelPolicy policy = new TunnelPolicy((SegmentRoutingManager) srService, (TunnelPolicy) policyInfo);
+            srService.createPolicy(policy);
+
+            return Response.ok().build();
+        } else {
+            return Response.serverError().build();
+        }
+    }
+
+    @DELETE
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response removePolicy(InputStream input) throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode policyJson = (ObjectNode) mapper.readTree(input);
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        Policy policyInfo = POLICY_CODEC.decode(policyJson, this);
+        // TODO: Check the result
+        srService.removePolicy(policyInfo);
+        return Response.ok().build();
+
+    }
+
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelCodec.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelCodec.java
new file mode 100644
index 0000000..2f85afd
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelCodec.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.segmentrouting.DefaultTunnel;
+import org.onosproject.segmentrouting.Tunnel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class TunnelCodec extends JsonCodec<Tunnel> {
+
+    // JSON field names
+    private static final String TUNNEL_ID = "tunnel_id";
+    private static final String GROUP_ID = "group_id";
+    private static final String LABEL_PATH = "label_path";
+
+    @Override
+    public ObjectNode encode(Tunnel tunnel, CodecContext context) {
+        final ObjectNode result = context.mapper().createObjectNode()
+                .put(TUNNEL_ID, tunnel.id());
+
+        result.put(GROUP_ID, tunnel.groupId());
+
+        final ArrayNode jsonLabelIds = result.putArray(LABEL_PATH);
+
+        tunnel.labelIds().forEach(label -> jsonLabelIds.add(label.intValue()));
+
+        return result;
+    }
+
+    @Override
+    public DefaultTunnel decode(ObjectNode json, CodecContext context) {
+
+        String tid = json.path(TUNNEL_ID).asText();
+        List<Integer> labels = new ArrayList<>();
+
+        if (!json.path(LABEL_PATH).isMissingNode()) {
+            ArrayNode labelArray = (ArrayNode) json.path(LABEL_PATH);
+            for (JsonNode o : labelArray) {
+                labels.add(o.asInt());
+            }
+        }
+
+        return new DefaultTunnel(tid, labels);
+    }
+
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelWebResource.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelWebResource.java
new file mode 100644
index 0000000..c531e3f
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelWebResource.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import org.onosproject.rest.AbstractWebResource;
+import org.onosproject.segmentrouting.DefaultTunnel;
+import org.onosproject.segmentrouting.SegmentRoutingManager;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.Tunnel;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+@Path("tunnel")
+public class TunnelWebResource extends AbstractWebResource {
+
+    private static final TunnelCodec TUNNEL_CODEC = new TunnelCodec();
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getTunnel() {
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        List<Tunnel> tunnels = srService.getTunnels();
+        ObjectNode result = new ObjectMapper().createObjectNode();
+        result.set("tunnel", new TunnelCodec().encode(tunnels, this));
+
+        return ok(result.toString()).build();
+    }
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createTunnel(InputStream input) throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode tunnelJson = (ObjectNode) mapper.readTree(input);
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        Tunnel tunnelInfo = TUNNEL_CODEC.decode(tunnelJson, this);
+        Tunnel tunnel = new DefaultTunnel((SegmentRoutingManager) srService,
+                tunnelInfo.id(), tunnelInfo.labelIds());
+        srService.createTunnel(tunnel);
+
+        return Response.ok().build();
+    }
+
+    @DELETE
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response removeTunnel(InputStream input) throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectNode tunnelJson = (ObjectNode) mapper.readTree(input);
+        SegmentRoutingService srService = get(SegmentRoutingService.class);
+        Tunnel tunnelInfo = TUNNEL_CODEC.decode(tunnelJson, this);
+        srService.removeTunnel(tunnelInfo);
+
+        return Response.ok().build();
+    }
+
+}
diff --git a/apps/segmentrouting/src/main/webapp/WEB-INF/web.xml b/apps/segmentrouting/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..94c0d7d
--- /dev/null
+++ b/apps/segmentrouting/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2015 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.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>Segment Routing REST API v1.0</display-name>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
+            <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+        </init-param>
+        <init-param>
+            <param-name>com.sun.jersey.config.property.classnames</param-name>
+            <param-value>
+                org.onosproject.segmentrouting.web.TunnelWebResource,
+                org.onosproject.segmentrouting.web.PolicyWebResource
+            </param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java
index cc316fe..a034edb 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java
@@ -195,7 +195,6 @@
             checkNotNull(appId, "Must supply an application id");
             checkNotNull(id, "id cannot be null");
             checkNotNull(type, "The type cannot be null");
-            checkArgument(!treatments.isEmpty(), "Must have at least one treatment");
 
             return new DefaultNextObjective(id, treatments, appId, type, Operation.REMOVE);
         }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
index bb2315d..68db4ce 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -49,6 +49,7 @@
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.EthTypeCriterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.IPProtocolCriterion;
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
@@ -215,7 +216,7 @@
     public void next(NextObjective nextObjective) {
 
         if (nextObjective.op() == Objective.Operation.REMOVE) {
-            if (nextObjective.next() == null) {
+            if (nextObjective.next().isEmpty()) {
                 removeGroup(nextObjective);
             } else {
                 removeBucketFromGroup(nextObjective);
@@ -369,8 +370,89 @@
     }
 
     private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
-        fail(fwd, ObjectiveError.UNSUPPORTED);
-        return Collections.emptySet();
+        log.debug("Processing versatile forwarding objective");
+        TrafficSelector selector = fwd.selector();
+
+        EthTypeCriterion ethType =
+                (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
+        if (ethType == null) {
+            log.error("Versatile forwarding objective must include ethType");
+            fail(fwd, ObjectiveError.UNKNOWN);
+            return Collections.emptySet();
+        }
+
+        TrafficSelector.Builder filteredSelectorBuilder =
+                DefaultTrafficSelector.builder();
+        if (ethType.ethType() == Ethernet.TYPE_IPV4) {
+            IPCriterion ipSrc = (IPCriterion) selector
+                    .getCriterion(Criterion.Type.IPV4_SRC);
+            IPCriterion ipDst = (IPCriterion) selector
+                    .getCriterion(Criterion.Type.IPV4_DST);
+            IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
+                    .getCriterion(Criterion.Type.IP_PROTO);
+
+            filteredSelectorBuilder
+                    .matchEthType(Ethernet.TYPE_IPV4);
+
+            if (ipSrc != null) {
+                filteredSelectorBuilder.matchIPSrc(ipSrc.ip());
+            }
+            if (ipDst != null) {
+                filteredSelectorBuilder.matchIPDst(ipDst.ip());
+            }
+            if (ipProto != null) {
+                filteredSelectorBuilder.matchIPProtocol(
+                        Short.valueOf(ipProto.protocol()).byteValue());
+            }
+
+            log.debug("processing IPv4 specific forwarding objective");
+        } else {
+            log.warn("VERSATILE forwarding objective does not support {} yet.",
+                    ethType.ethType());
+            return Collections.emptySet();
+        }
+
+        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
+                .builder();
+        treatmentBuilder.wipeDeferred();
+
+        if (fwd.nextId() != null) {
+            NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
+
+            if (next != null) {
+                GroupKey key = appKryo.deserialize(next.data());
+
+                Group group = groupService.getGroup(deviceId, key);
+
+                if (group == null) {
+                    log.warn("The group left!");
+                    fail(fwd, ObjectiveError.GROUPMISSING);
+                    return Collections.emptySet();
+                }
+                treatmentBuilder.deferred().group(group.id());
+                log.debug("Adding OUTGROUP action");
+            }
+        } else {
+            log.warn("VERSATILE forwarding objective need next objective ID.");
+            return Collections.emptySet();
+        }
+
+        TrafficSelector filteredSelector = filteredSelectorBuilder.build();
+        TrafficTreatment treatment = treatmentBuilder.build();
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .fromApp(fwd.appId()).withPriority(fwd.priority())
+                .forDevice(deviceId).withSelector(filteredSelector)
+                .withTreatment(treatment);
+
+        if (fwd.permanent()) {
+            ruleBuilder.makePermanent();
+        } else {
+            ruleBuilder.makeTemporary(fwd.timeout());
+        }
+
+        ruleBuilder.forTable(aclTableId);
+        return Collections.singletonList(ruleBuilder.build());
     }
 
     protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
@@ -434,7 +516,7 @@
                     fail(fwd, ObjectiveError.GROUPMISSING);
                     return Collections.emptySet();
                 }
-                treatmentBuilder.group(group.id());
+                treatmentBuilder.deferred().group(group.id());
                 log.debug("Adding OUTGROUP action");
             } else {
                 log.warn("processSpecific: No associated next objective object");
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
index 5fa3baf..18f43bf 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -104,12 +104,12 @@
         List<OFInstruction> instructions = Lists.newLinkedList();
 
 
-        if (immediateActions.size() > 0) {
-            instructions.add(factory().instructions().applyActions(immediateActions));
-        }
         if (treatment.clearedDeferred()) {
             instructions.add(factory().instructions().clearActions());
         }
+        if (immediateActions.size() > 0) {
+            instructions.add(factory().instructions().applyActions(immediateActions));
+        }
         if (deferredActions.size() > 0) {
             instructions.add(factory().instructions().writeActions(deferredActions));
         }