Merge branch 'master' into dev-karaf-4.2.1

Change-Id: If6c7d5f1dc6434ac8ea2fd9716b8ebeee38daa50
diff --git a/.gitreview b/.gitreview
index b86ceb3..328aec6 100644
--- a/.gitreview
+++ b/.gitreview
@@ -3,4 +3,4 @@
 port=29418
 project=onos.git
 defaultremote=origin
-defaultbranch=dev-karaf-4.2.1
+defaultbranch=master
diff --git a/apps/dhcprelay/app/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java b/apps/dhcprelay/app/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java
index 4145cd2..da6a4ac 100644
--- a/apps/dhcprelay/app/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java
+++ b/apps/dhcprelay/app/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java
@@ -199,7 +199,13 @@
         });
     }
 
-    private String ip4State(DhcpRecord record) {
+    /**
+     * To return ipv4state.
+     *
+     * @param record DhcpRecord object
+     * @return ipState type String
+     */
+    public String ip4State(DhcpRecord record) {
         String nextHopIp = findNextHopIp(IpAddress::isIp4,
                                          record.nextHop().orElse(null),
                                          record.vlanId());
@@ -209,7 +215,14 @@
                        nextHopIp);
     }
 
-    private String ip6State(DhcpRecord record) {
+    /**
+     * To return ipv6state.
+     *
+     * @param record DhcpRecord object
+     * @return ipState type String
+     */
+
+    public String ip6State(DhcpRecord record) {
         String nextHopIp = findNextHopIp6(IpAddress::isIp6,
                                          record.nextHop().orElse(null),
                                          record.vlanId());
diff --git a/apps/dhcprelay/web/src/main/java/org/onosproject/dhcprelay/rest/DhcpRelayWebResource.java b/apps/dhcprelay/web/src/main/java/org/onosproject/dhcprelay/rest/DhcpRelayWebResource.java
index 9338a4b..1a48ea5 100644
--- a/apps/dhcprelay/web/src/main/java/org/onosproject/dhcprelay/rest/DhcpRelayWebResource.java
+++ b/apps/dhcprelay/web/src/main/java/org/onosproject/dhcprelay/rest/DhcpRelayWebResource.java
@@ -19,7 +19,15 @@
 
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
+import org.onlab.util.Tools;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.dhcprelay.api.DhcpRelayService;
+import org.onosproject.dhcprelay.api.DhcpServerInfo;
+import org.onosproject.dhcprelay.cli.DhcpRelayCommand;
+import org.onosproject.dhcprelay.store.DhcpRecord;
+import org.onosproject.dhcprelay.store.DhcpRelayCounters;
 import org.onosproject.rest.AbstractWebResource;
 import org.onosproject.routeservice.Route;
 import org.onosproject.routeservice.RouteStore;
@@ -27,11 +35,18 @@
 import org.slf4j.Logger;
 
 import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
 import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.List;
 import java.util.Optional;
 
 import static org.slf4j.LoggerFactory.getLogger;
@@ -42,6 +57,13 @@
 @Path("fpm-delete")
 public class DhcpRelayWebResource extends AbstractWebResource {
     private static final Logger LOG = getLogger(DhcpRelayWebResource.class);
+    private final ObjectMapper mapper = new ObjectMapper();
+    private final DhcpRelayService dhcpDelayService = get(DhcpRelayService.class);
+    private static final String NA = "N/A";
+    List<DhcpServerInfo> defaultDhcpServerInfoList = dhcpDelayService.getDefaultDhcpServerInfoList();
+    List<DhcpServerInfo> indirectDhcpServerInfoList = dhcpDelayService.getIndirectDhcpServerInfoList();
+    Collection<DhcpRecord> records = dhcpDelayService.getDhcpRecords();
+
 
     /**
      * Deletes the fpm route from fpm record.
@@ -74,5 +96,170 @@
 
         return Response.noContent().build();
     }
+    /**
+     * Returns the response object with list of dhcp servers without counters.
+     *
+     * @return 200 OK with component properties of given component and variable
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("dhcp-relay")
+    public Response getDhcpServers() {
+        ObjectNode node = getdhcpRelayJsonOutput(null, null);
+        return Response.status(200).entity(node).build();
+    }
+
+    /**
+     * Returns dhcp servers details with counters.
+     *
+     * @param counter source ip identifier
+     * @return 200 OK with component properties of given component and variable
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("dhcp-relay/{counter}")
+    public Response getDhcpRelayCounter(@PathParam("counter") String counter) {
+        ObjectNode node = getdhcpRelayJsonOutput(counter, null);
+        return Response.status(200).entity(node).build();
+    }
+
+    /**
+     * To reset the dhcp relay counters.
+     *
+     * @param counter type String
+     * @param reset   type String
+     * @return 200 OK with component properties of given component and variable
+     */
+    @PUT
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("dhcp-relay/{counter}/{reset}")
+    public Response resetDhcpRelayCounter(@PathParam("counter") String counter, @PathParam("reset") String reset) {
+        ObjectNode node = getdhcpRelayJsonOutput(counter, reset);
+        return Response.status(200).entity(node).build();
+    }
+
+
+    /**
+     * To create json output.
+     *
+     * @param counter type String
+     * @param reset  type String
+     * @return node type ObjectNode.
+     */
+    private ObjectNode getdhcpRelayJsonOutput(String counter, String reset) {
+        ObjectNode node = mapper.createObjectNode();
+        ObjectNode dhcpRelayServerNode = mapper.createObjectNode();
+            if (!defaultDhcpServerInfoList.isEmpty()) {
+                ArrayNode defaultDhcpServers = listServers(defaultDhcpServerInfoList);
+                dhcpRelayServerNode.put("Default-DHCP-Server", defaultDhcpServers);
+            }
+            if (!indirectDhcpServerInfoList.isEmpty()) {
+                ArrayNode indirectDhcpServers = listServers(indirectDhcpServerInfoList);
+                dhcpRelayServerNode.put("Indirect-DHCP-Server", indirectDhcpServers);
+            }
+
+            ArrayNode dhcpRecords = dhcpRelayRecords(records);
+            dhcpRelayServerNode.put("DHCP-Relay-Records([D]:Directly-Connected)", dhcpRecords);
+            if (counter != null && !counter.equals("counter")) {
+                ArrayNode counterArray = dhcpRelayCounters(reset);
+                dhcpRelayServerNode.put("DHCP-Relay-Counter", counterArray);
+            }
+            node.put("Default-DHCP-Servers", dhcpRelayServerNode);
+
+        return node;
+
+    }
+    /**
+     * To get the liset of dhcp servers.
+     *
+     * @param dhcpServerInfoList type List
+     * @return servers type ArrayNode.
+     */
+    private ArrayNode listServers(List<DhcpServerInfo> dhcpServerInfoList) {
+        ArrayNode servers = mapper.createArrayNode();
+        dhcpServerInfoList.forEach(dhcpServerInfo -> {
+            ObjectNode serverNode = mapper.createObjectNode();
+            String connectPoint = dhcpServerInfo.getDhcpServerConnectPoint()
+                    .map(cp -> cp.toString()).orElse(NA);
+            String serverMac = dhcpServerInfo.getDhcpConnectMac()
+                    .map(mac -> mac.toString()).orElse(NA);
+            String gatewayAddress;
+            String serverIp;
+
+            switch (dhcpServerInfo.getVersion()) {
+                case DHCP_V4:
+                    gatewayAddress = dhcpServerInfo.getDhcpGatewayIp4()
+                            .map(gw -> gw.toString()).orElse(null);
+                    serverIp = dhcpServerInfo.getDhcpServerIp4()
+                            .map(ip -> ip.toString()).orElse(NA);
+                    break;
+                case DHCP_V6:
+                    gatewayAddress = dhcpServerInfo.getDhcpGatewayIp6()
+                            .map(gw -> gw.toString()).orElse(null);
+                    serverIp = dhcpServerInfo.getDhcpServerIp6()
+                            .map(ip -> ip.toString()).orElse(NA);
+                    break;
+                default:
+                    return;
+            }
+
+            serverNode.put("connectPoint", connectPoint);
+            if (gatewayAddress != null) {
+                serverNode.put("server", serverIp.concat(" via ").concat(gatewayAddress));
+            } else {
+                serverNode.put("server", serverIp);
+            }
+            serverNode.put("mac", serverMac);
+            servers.add(serverNode);
+        });
+       return servers;
+}
+
+    /**
+     * To get the list of dhcp relay records.
+     *
+     * @param records type Collections
+     * @return dhcpRelayRecords type ArrayNode.
+     */
+    private ArrayNode dhcpRelayRecords(Collection<DhcpRecord> records) {
+        DhcpRelayCommand dhcpRelayCommand = new DhcpRelayCommand();
+        ArrayNode dhcpRelayRecords = mapper.createArrayNode();
+        records.forEach(record -> {
+            ObjectNode dhcpRecord = mapper.createObjectNode();
+            dhcpRecord.put("id", record.macAddress() + "/" + record.vlanId());
+            dhcpRecord.put("locations", record.locations().toString());
+            dhcpRecord.put("last-seen", Tools.timeAgo(record.lastSeen()));
+            dhcpRecord.put("IPv4", dhcpRelayCommand.ip4State(record));
+            dhcpRecord.put("IPv6", dhcpRelayCommand.ip6State(record));
+            dhcpRelayRecords.add(dhcpRecord);
+        });
+        return dhcpRelayRecords;
+    }
+
+   /**
+     * To get the details of dhcp relay counters.
+     *
+     * @param reset type String
+     * @return counterArray type ArrayNode.
+     */
+    private ArrayNode dhcpRelayCounters(String reset) {
+        ObjectNode counters = mapper.createObjectNode();
+        ObjectNode counterPackets = mapper.createObjectNode();
+        ArrayNode counterArray = mapper.createArrayNode();
+        records.forEach(record -> {
+            DhcpRelayCounters v6Counters = record.getV6Counters();
+            if (reset != null && reset.equals("reset")) {
+                v6Counters.resetCounters();
+            }
+            Map<String, Integer> countersMap = v6Counters.getCounters();
+            countersMap.forEach((name, value) -> {
+                counterPackets.put(name, value);
+
+            });
+            counters.put(record.locations().toString(), counterPackets);
+            counterArray.add(counters);
+        });
+        return counterArray;
+    }
 
 }
diff --git a/apps/kafka-integration/BUILD b/apps/kafka-integration/BUILD
index c0b04d9..9077b7e 100644
--- a/apps/kafka-integration/BUILD
+++ b/apps/kafka-integration/BUILD
@@ -1,19 +1,17 @@
-# FIXME: Work in progress
-
 BUNDLES = [
-    "@kafka-clients//jar",
-    "@protobuf-java-3.2.0//jar",
+    "@kafka_clients//jar",
+    "@runtime_protobuf//jar",
     "//incubator/protobuf/models:onos-incubator-protobuf-models",
-    "//incubator/protobuf/models:onos-incubator-protobuf-models-proto",
+    "//incubator/protobuf/models/proto:onos-incubator-protobuf-models-proto",
     "//apps/kafka-integration/api:onos-apps-kafka-integration-api",
     "//apps/kafka-integration/app:onos-apps-kafka-integration-app",
 ]
 
-#onos_app (
-#  title = "Kafka Integration",
-#  category = "Integration",
-#  url = "http://onosproject.org",
-#  description = "Provides integration of ONOS and Kafka message bus so that internal ONOS events " +
-#    "can be broadcast over the Kafka message bus to off-platform applications.",
-#  included_bundles = BUNDLES,
-#)
+onos_app(
+    category = "Integration",
+    description = "Provides integration of ONOS and Kafka message bus so that internal ONOS events " +
+                  "can be broadcast over the Kafka message bus to off-platform applications.",
+    included_bundles = BUNDLES,
+    title = "Kafka Integration",
+    url = "http://onosproject.org",
+)
diff --git a/apps/kafka-integration/app/BUILD b/apps/kafka-integration/app/BUILD
index d711987..2b39734 100644
--- a/apps/kafka-integration/app/BUILD
+++ b/apps/kafka-integration/app/BUILD
@@ -1,21 +1,20 @@
-# FIXME: Work in progress
-
 COMPILE_DEPS = CORE_DEPS + JACKSON + KRYO + CLI + [
     "//apps/kafka-integration/api:onos-apps-kafka-integration-api",
     "//core/store/serializers:onos-core-serializers",
     "@kafka_clients//jar",
-    "@protobuf-java-3.2.0//jar",
-    "//lib:GRPC_1.3",
+    "@javax_ws_rs_api//jar",
+    "//utils/rest:onlab-rest",
+    "@com_google_protobuf//:protobuf_java",
     "//incubator/protobuf/models:onos-incubator-protobuf-models",
-    "//incubator/protobuf/models:onos-incubator-protobuf-models-proto",
+    "//incubator/protobuf/models/proto:onos-incubator-protobuf-models-proto",
 ]
 
-#osgi_jar_with_tests (
-#    deps = COMPILE_DEPS,
-#    test_deps = TEST_ADAPTERS,
-#    web_context = "/onos/kafka-integration",
-#    api_title = "Kafka Integration",
-#    api_version = "1.0",
-#    api_description = "REST API for Kafka Integration",
-#    api_package = "org.onosproject.kafkaintegration.rest",
-#)
+osgi_jar_with_tests(
+    api_description = "REST API for Kafka Integration",
+    api_package = "org.onosproject.kafkaintegration.rest",
+    api_title = "Kafka Integration",
+    api_version = "1.0",
+    test_deps = TEST_ADAPTERS,
+    web_context = "/onos/kafka-integration",
+    deps = COMPILE_DEPS,
+)
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index 2021aa8..ec7204e 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -63,7 +63,6 @@
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
-import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.IP;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
@@ -98,11 +97,13 @@
 import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
 import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.floatingIpByInstancePort;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
-import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
@@ -245,14 +246,16 @@
                     targetMac = instPort.macAddress();
                 }
 
-                OpenstackNode gw = getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
+                OpenstackNode gw =
+                        getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
 
                 if (gw == null) {
                     return;
                 }
 
                 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
-                if (!Objects.equals(gw.intgBridge(), context.inPacket().receivedFrom().deviceId())) {
+                if (!Objects.equals(gw.intgBridge(),
+                                context.inPacket().receivedFrom().deviceId())) {
                     return;
                 }
             }
@@ -290,8 +293,10 @@
 
             try {
 
-                Set<String> extRouterIps = osNetworkService.externalPeerRouters().
-                        stream().map(r -> r.ipAddress().toString()).collect(Collectors.toSet());
+                Set<String> extRouterIps = osNetworkService.externalPeerRouters()
+                        .stream()
+                        .map(r -> r.ipAddress().toString())
+                        .collect(Collectors.toSet());
 
                 // if SPA is NOT contained in existing external router IP set, we ignore it
                 if (!extRouterIps.contains(spa.toString())) {
@@ -358,7 +363,8 @@
      * @param gateway gateway node
      * @param install flow rule installation flag
      */
-    private void setFloatingIpArpRuleForGateway(OpenstackNode gateway, boolean install) {
+    private void setFloatingIpArpRuleForGateway(OpenstackNode gateway,
+                                                boolean install) {
         if (ARP_BROADCAST_MODE.equals(getArpMode())) {
 
             Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
@@ -371,14 +377,16 @@
                         finalGws.remove(gateway);
                         osRouterAdminService.floatingIps().forEach(fip -> {
                             if (fip.getPortId() != null) {
-                                setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
+                                setFloatingIpArpRule(fip, fip.getPortId(),
+                                                     finalGws, false);
                                 finalGws.add(gateway);
                             }
                         });
                     }
                     osRouterAdminService.floatingIps().forEach(fip -> {
                         if (fip.getPortId() != null) {
-                            setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
+                            setFloatingIpArpRule(fip, fip.getPortId(),
+                                                 finalGws, true);
                         }
                     });
                 } else {
@@ -389,14 +397,16 @@
                     finalGws.add(gateway);
                     osRouterAdminService.floatingIps().forEach(fip -> {
                         if (fip.getPortId() != null) {
-                            setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
+                            setFloatingIpArpRule(fip, fip.getPortId(),
+                                                 finalGws, false);
                         }
                     });
                     finalGws.remove(gateway);
                     if (completedGws.size() >= 1) {
                         osRouterAdminService.floatingIps().forEach(fip -> {
                             if (fip.getPortId() != null) {
-                                setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
+                                setFloatingIpArpRule(fip, fip.getPortId(),
+                                                     finalGws, true);
                             }
                         });
                     }
@@ -520,15 +530,16 @@
     }
 
     private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
-        setFakeGatewayArpRuleByGateway(router.getId(), router.getExternalGatewayInfo(), install);
+        setFakeGatewayArpRuleByGateway(router.getId(), install);
     }
 
-    private Set<IP> getExternalGatewaySnatIps(String routerId, ExternalGateway extGw) {
+    private Set<IP> getExternalGatewaySnatIps(String routerId) {
         if (routerId == null) {
             return ImmutableSet.of();
         }
 
-        Set<String> portIds = osRouterAdminService.routerInterfaces(routerId).stream()
+        Set<String> portIds = osRouterAdminService.routerInterfaces(routerId)
+                .stream()
                 .map(RouterInterface::getPortId)
                 .collect(Collectors.toSet());
 
@@ -539,14 +550,9 @@
                 .collect(Collectors.toSet());
     }
 
-    private void setFakeGatewayArpRuleByGateway(String routerId, ExternalGateway extGw, boolean install) {
+    private void setFakeGatewayArpRuleByGateway(String routerId, boolean install) {
         if (ARP_BROADCAST_MODE.equals(getArpMode())) {
-
-            if (extGw == null) {
-                return;
-            }
-
-            setFakeGatewayArpRuleByIps(getExternalGatewaySnatIps(routerId, extGw), install);
+            setFakeGatewayArpRuleByIps(getExternalGatewaySnatIps(routerId), install);
         }
     }
 
@@ -611,12 +617,14 @@
                 case OPENSTACK_PORT_CREATED:
                 case OPENSTACK_PORT_UPDATED:
                     eventExecutor.execute(() ->
-                        setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), true)
+                        setFakeGatewayArpRuleByIps(
+                                (Set<IP>) event.port().getFixedIps(), true)
                     );
                     break;
                 case OPENSTACK_PORT_REMOVED:
                     eventExecutor.execute(() ->
-                        setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), false)
+                        setFakeGatewayArpRuleByIps(
+                                (Set<IP>) event.port().getFixedIps(), false)
                     );
                     break;
                 default:
@@ -660,58 +668,60 @@
                 case OPENSTACK_ROUTER_GATEWAY_ADDED:
                     eventExecutor.execute(() ->
                         // add a gateway manually after adding a router
-                        setFakeGatewayArpRuleByGateway(event.subject().getId(),
-                                                        event.externalGateway(), true)
+                        setFakeGatewayArpRuleByGateway(event.subject().getId(), true)
                     );
                     break;
                 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
                     eventExecutor.execute(() ->
                         // remove a gateway from an existing router
-                        setFakeGatewayArpRuleByGateway(event.subject().getId(),
-                                                        event.externalGateway(), false)
+                        setFakeGatewayArpRuleByGateway(event.subject().getId(), false)
                     );
                     break;
                 case OPENSTACK_FLOATING_IP_ASSOCIATED:
-                    if (getValidPortId(event) != null) {
-                        eventExecutor.execute(() -> {
-                            // associate a floating IP with an existing VM
-                            setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
-                                    completedGws, true);
-                        });
-                    }
+                    eventExecutor.execute(() -> {
+                        if (getValidPortId(event) == null) {
+                            return;
+                        }
+                        // associate a floating IP with an existing VM
+                        setFloatingIpArpRule(event.floatingIp(),
+                                getValidPortId(event), completedGws, true);
+                    });
                     break;
                 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
-                    if (getValidPortId(event) != null) {
-                        eventExecutor.execute(() -> {
-                            // disassociate a floating IP with an existing VM
-                            setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
-                                    completedGws, false);
-                        });
-                    }
+                    eventExecutor.execute(() -> {
+                        if (getValidPortId(event) == null) {
+                            return;
+                        }
+                        // disassociate a floating IP with an existing VM
+                        setFloatingIpArpRule(event.floatingIp(),
+                                getValidPortId(event), completedGws, false);
+                    });
                     break;
                 case OPENSTACK_FLOATING_IP_CREATED:
                     // during floating IP creation, if the floating IP is
                     // associated with any port of VM, then we will set
                     // floating IP related ARP rules to gateway node
-                    if (getValidPortId(event) != null) {
-                        eventExecutor.execute(() -> {
-                            // associate a floating IP with an existing VM
-                            setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
-                                    completedGws, true);
-                        });
-                    }
+                    eventExecutor.execute(() -> {
+                        if (getValidPortId(event) == null) {
+                            return;
+                        }
+                        // associate a floating IP with an existing VM
+                        setFloatingIpArpRule(event.floatingIp(),
+                                getValidPortId(event), completedGws, true);
+                    });
                     break;
                 case OPENSTACK_FLOATING_IP_REMOVED:
                     // during floating IP deletion, if the floating IP is
                     // still associated with any port of VM, then we will
                     // remove floating IP related ARP rules from gateway node
-                    if (getValidPortId(event) != null) {
-                        eventExecutor.execute(() -> {
-                            // associate a floating IP with an existing VM
-                            setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
-                                    completedGws, false);
-                        });
-                    }
+                    eventExecutor.execute(() -> {
+                        if (getValidPortId(event) == null) {
+                            return;
+                        }
+                        // associate a floating IP with an existing VM
+                        setFloatingIpArpRule(event.floatingIp(),
+                                getValidPortId(event), completedGws, false);
+                    });
                     break;
                 default:
                     // do nothing for the other events
@@ -754,50 +764,52 @@
 
             switch (event.type()) {
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
-
-                    osRouterAdminService.floatingIps().stream()
-                            .filter(f -> f.getPortId() != null)
-                            .filter(f -> f.getPortId().equals(instPort.portId()))
-                            .forEach(f -> setFloatingIpArpRule(f, instPort.portId(), gateways, true));
-
+                    eventExecutor.execute(() ->
+                            osRouterAdminService.floatingIps().stream()
+                                .filter(f -> f.getPortId() != null)
+                                .filter(f -> f.getPortId().equals(instPort.portId()))
+                                .forEach(f -> setFloatingIpArpRule(f,
+                                        instPort.portId(), gateways, true))
+                    );
                     break;
                 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
-
-                    if (gateways.size() == 1) {
-                        return;
-                    }
-
-                    if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
-                        eventExecutor.execute(() ->
-                            setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
-                                    gateways, true)
-                        );
-                    }
-
-                    break;
-                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
-
-                    InstancePort revisedInstPort = swapStaleLocation(event.subject());
-
-                    if (gateways.size() == 1) {
-                        return;
-                    }
-
-                    if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
-                        DeviceId newDeviceId = event.subject().deviceId();
-                        DeviceId oldDeviceId = revisedInstPort.deviceId();
-
-                        OpenstackNode oldGw = getGwByComputeDevId(gateways, oldDeviceId);
-                        OpenstackNode newGw = getGwByComputeDevId(gateways, newDeviceId);
-
-                        if (oldGw != null && oldGw.equals(newGw)) {
+                    eventExecutor.execute(() -> {
+                        if (gateways.size() == 1) {
                             return;
                         }
 
-                        eventExecutor.execute(() ->
-                                setFloatingIpArpRuleWithPortEvent(fip,
-                                        revisedInstPort, gateways, false));
-                    }
+                        if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
+                            setFloatingIpArpRuleWithPortEvent(fip,
+                                        event.subject(), gateways, true);
+                        }
+                    });
+
+                    break;
+                case OPENSTACK_INSTANCE_MIGRATION_ENDED:
+                    eventExecutor.execute(() -> {
+                        InstancePort revisedInstPort = swapStaleLocation(event.subject());
+
+                        if (gateways.size() == 1) {
+                            return;
+                        }
+
+                        if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
+                            DeviceId newDeviceId = event.subject().deviceId();
+                            DeviceId oldDeviceId = revisedInstPort.deviceId();
+
+                            OpenstackNode oldGw =
+                                    getGwByComputeDevId(gateways, oldDeviceId);
+                            OpenstackNode newGw =
+                                    getGwByComputeDevId(gateways, newDeviceId);
+
+                            if (oldGw != null && oldGw.equals(newGw)) {
+                                return;
+                            }
+
+                            setFloatingIpArpRuleWithPortEvent(fip,
+                                        revisedInstPort, gateways, false);
+                        }
+                    });
                     break;
                 default:
                     break;
@@ -819,44 +831,52 @@
             OpenstackNode osNode = event.subject();
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    setDefaultArpRule(osNode, true);
-                    setFloatingIpArpRuleForGateway(osNode, true);
-                    sendGratuitousArpToSwitch(event.subject(), true);
+                    eventExecutor.execute(() -> {
+                        setDefaultArpRule(osNode, true);
+                        setFloatingIpArpRuleForGateway(osNode, true);
+                        sendGratuitousArpToSwitch(event.subject(), true);
+                    });
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
-                    setDefaultArpRule(osNode, false);
-                    setFloatingIpArpRuleForGateway(osNode, false);
-                    sendGratuitousArpToSwitch(event.subject(), false);
+                    eventExecutor.execute(() -> {
+                        setDefaultArpRule(osNode, false);
+                        setFloatingIpArpRuleForGateway(osNode, false);
+                        sendGratuitousArpToSwitch(event.subject(), false);
+                    });
                     break;
                 case OPENSTACK_NODE_REMOVED:
-                    sendGratuitousArpToSwitch(event.subject(), false);
+                    eventExecutor.execute(() -> {
+                        sendGratuitousArpToSwitch(event.subject(), false);
+                    });
                     break;
-
                 default:
                     break;
             }
         }
 
-        private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode, boolean isCompleteCase) {
-            Set<OpenstackNode> completeGws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
+        private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode,
+                                               boolean isCompleteCase) {
+            Set<OpenstackNode> completeGws =
+                    ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
 
             if (isCompleteCase) {
-                osNodeService.completeNodes(COMPUTE)
-                        .stream()
-                        .filter(node -> isGwSelectedByComputeNode(completeGws, node, gatewayNode))
-                        .forEach(node -> processGratuitousArpPacketForComputeNode(node, gatewayNode));
+                osNodeService.completeNodes(COMPUTE).stream()
+                        .filter(node -> isGwSelectedByComputeNode(completeGws,
+                                                                  node, gatewayNode))
+                        .forEach(node -> processGarpPacketForComputeNode(node, gatewayNode));
 
             } else {
                 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
                 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
                 oldCompleteGws.add(gatewayNode);
 
-                osNodeService.completeNodes(COMPUTE)
-                        .stream()
-                        .filter(node -> isGwSelectedByComputeNode(oldCompleteGws, node, gatewayNode))
+                osNodeService.completeNodes(COMPUTE).stream()
+                        .filter(node -> isGwSelectedByComputeNode(oldCompleteGws,
+                                                                  node, gatewayNode))
                         .forEach(node -> {
-                            OpenstackNode newSelectedGatewayNode = getGwByComputeDevId(completeGws, node.intgBridge());
-                            processGratuitousArpPacketForComputeNode(node, newSelectedGatewayNode);
+                            OpenstackNode newSelectedGatewayNode =
+                                    getGwByComputeDevId(completeGws, node.intgBridge());
+                            processGarpPacketForComputeNode(node, newSelectedGatewayNode);
                         });
             }
         }
@@ -869,16 +889,20 @@
                     .intgBridge().equals(gwNode.intgBridge());
         }
 
-        private void processGratuitousArpPacketForComputeNode(OpenstackNode computeNode, OpenstackNode gatewayNode) {
-            instancePortService.instancePort(computeNode.intgBridge()).forEach(instancePort -> {
-                NetFloatingIP floatingIP = OpenstackNetworkingUtil.floatingIpByInstancePort(instancePort,
-                        osRouterAdminService);
+        private void processGarpPacketForComputeNode(OpenstackNode computeNode,
+                                                     OpenstackNode gatewayNode) {
+            instancePortService.instancePort(computeNode.intgBridge())
+                    .forEach(instancePort -> {
+                NetFloatingIP floatingIP =
+                        floatingIpByInstancePort(instancePort, osRouterAdminService);
                 Network network = osNetworkService.network(instancePort.networkId());
-                ExternalPeerRouter externalPeerRouter = OpenstackNetworkingUtil.externalPeerRouterForNetwork(network,
-                        osNetworkService, osRouterAdminService);
+                ExternalPeerRouter externalPeerRouter =
+                        externalPeerRouterForNetwork(network, osNetworkService,
+                                                            osRouterAdminService);
                 if (floatingIP != null && externalPeerRouter != null) {
-                    processGratuitousArpPacketForFloatingIp(
-                            floatingIP, instancePort, externalPeerRouter.vlanId(), gatewayNode, packetService);
+                    processGarpPacketForFloatingIp(
+                            floatingIP, instancePort, externalPeerRouter.vlanId(),
+                                                        gatewayNode, packetService);
                 }
             });
         }
@@ -903,7 +927,8 @@
             }
         }
 
-        private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
+        private void setDefaultArpRuleForProxyMode(OpenstackNode osNode,
+                                                   boolean install) {
             TrafficSelector selector = DefaultTrafficSelector.builder()
                     .matchEthType(EthType.EtherType.ARP.ethType().toShort())
                     .build();
@@ -923,7 +948,8 @@
             );
         }
 
-        private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
+        private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
+                                                       boolean install) {
             // we only match ARP_REPLY in gateway node, because controller
             // somehow need to process ARP_REPLY which is issued from
             // external router...
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index b2cb36e..f04e14a 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -85,7 +85,7 @@
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
-import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
@@ -440,7 +440,8 @@
     }
 
     private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
-                                  InstancePort instPort, ExternalPeerRouter externalPeerRouter,
+                                  InstancePort instPort,
+                                  ExternalPeerRouter externalPeerRouter,
                                   boolean install) {
         IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
         TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
@@ -515,12 +516,13 @@
         ExternalPeerRouter externalPeerRouter =
                 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
         if (externalPeerRouter == null) {
-            log.error("Failed to process GARP packet for floating ip {} because no external peer router found");
+            log.error("Failed to process GARP packet for floating ip {} " +
+                                        "because no external peer router found");
             return;
         }
 
-        processGratuitousArpPacketForFloatingIp(floatingIP, instancePort, externalPeerRouter.vlanId(),
-                selectedGw, packetService);
+        processGarpPacketForFloatingIp(floatingIP, instancePort,
+                        externalPeerRouter.vlanId(), selectedGw, packetService);
 
     }
 
@@ -604,7 +606,8 @@
                             preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
                                     OPENSTACK_PORT_PRE_REMOVE, instancePortService,
                                     this.getClass().getName());
-                            log.info("Unsubscribed the port {} on listening pre-remove event", osFip.getPortId());
+                            log.info("Unsubscribed the port {} on listening pre-remove event",
+                                     osFip.getPortId());
                         }
                         log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
                     });
@@ -746,17 +749,19 @@
 
             switch (event.type()) {
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
-                    if (instPort != null && instPort.portId() != null) {
-                        osRouterAdminService.floatingIps().stream()
-                                .filter(f -> f.getPortId() != null)
-                                .filter(f -> f.getPortId().equals(instPort.portId()))
-                                .forEach(f -> setFloatingIpRules(f, instPort, null, true));
-                    }
 
+                    eventExecutor.execute(() -> {
+                        if (instPort != null && instPort.portId() != null) {
+                            osRouterAdminService.floatingIps().stream()
+                                    .filter(f -> f.getPortId() != null)
+                                    .filter(f -> f.getPortId().equals(instPort.portId()))
+                                    .forEach(f -> setFloatingIpRules(f,
+                                            instPort, null, true));
+                        }
+                    });
                     break;
 
                 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
-
                     fip = associatedFloatingIp(event.subject(), ips);
 
                     if (fip == null) {
@@ -765,7 +770,8 @@
 
                     osPort = osNetworkService.port(fip.getPortId());
                     osNet = osNetworkService.network(osPort.getNetworkId());
-                    externalPeerRouter = externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
+                    externalPeerRouter = externalPeerRouterForNetwork(osNet,
+                                         osNetworkService, osRouterAdminService);
 
                     if (externalPeerRouter == null) {
                         final String errorFormat = ERR_FLOW + "no external peer router found";
@@ -798,7 +804,8 @@
 
                     osPort = osNetworkService.port(fip.getPortId());
                     osNet = osNetworkService.network(osPort.getNetworkId());
-                    externalPeerRouter = externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
+                    externalPeerRouter = externalPeerRouterForNetwork(osNet,
+                                         osNetworkService, osRouterAdminService);
 
                     if (externalPeerRouter == null) {
                         final String errorFormat = ERR_FLOW + "no external peer router found";
@@ -859,29 +866,31 @@
         public void event(OpenstackNetworkEvent event) {
             switch (event.type()) {
                 case OPENSTACK_PORT_PRE_REMOVE:
-                    InstancePort instPort =
-                            instancePortService.instancePort(event.port().getId());
-
-                    if (instPort == null) {
-                        break;
-                    }
-
-                    NetFloatingIP fip =
-                            associatedFloatingIp(instPort, osRouterAdminService.floatingIps());
-
-                    if (fip != null) {
-                        instancePortService.updateInstancePort(
-                                            instPort.updateState(REMOVE_PENDING));
-                        eventExecutor.execute(() -> updateFipStore(event.port().getId()));
-                    } else {
-                        instancePortService.removeInstancePort(instPort.portId());
-                    }
+                    eventExecutor.execute(() -> processPortPreRemove(event));
                     break;
                 default:
                     break;
             }
         }
 
+        private void processPortPreRemove(OpenstackNetworkEvent event) {
+            InstancePort instPort = instancePortService.instancePort(
+                                                        event.port().getId());
+            if (instPort == null) {
+                return;
+            }
+            NetFloatingIP fip = associatedFloatingIp(instPort,
+                    osRouterAdminService.floatingIps());
+
+            if (fip != null) {
+                instancePortService.updateInstancePort(
+                        instPort.updateState(REMOVE_PENDING));
+                updateFipStore(event.port().getId());
+            } else {
+                instancePortService.removeInstancePort(instPort.portId());
+            }
+        }
+
         private void updateFipStore(String portId) {
 
             if (portId == null) {
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
index 70d75cc..af81c2f 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
@@ -101,6 +101,7 @@
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
+import static org.openstack4j.model.network.NetworkType.FLAT;
 
 /**
  * Handles OpenStack router events.
@@ -280,7 +281,7 @@
         }
 
         setInternalRoutes(osRouter, osSubnet, true);
-        setGatewayIcmp(osSubnet, true);
+        setGatewayIcmp(osSubnet, osRouter, true);
         ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
         if (exGateway != null && exGateway.isEnableSnat()) {
             setSourceNat(osRouterIface, true);
@@ -304,7 +305,7 @@
         }
 
         setInternalRoutes(osRouter, osSubnet, false);
-        setGatewayIcmp(osSubnet, false);
+        setGatewayIcmp(osSubnet, osRouter, false);
         ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
         if (exGateway != null && exGateway.isEnableSnat()) {
             setSourceNat(osRouterIface, false);
@@ -336,7 +337,7 @@
         Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
         Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
 
-        if (osNet.getNetworkType() == NetworkType.FLAT) {
+        if (osNet.getNetworkType() == FLAT) {
             return;
         }
 
@@ -423,7 +424,7 @@
         }
     }
 
-    private void setGatewayIcmp(Subnet osSubnet, boolean install) {
+    private void setGatewayIcmp(Subnet osSubnet, Router osRouter, boolean install) {
         OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
 
         if (sourceNatGateway == null) {
@@ -437,26 +438,30 @@
 
         // take ICMP request to a subnet gateway through gateway node group
         Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
+        Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
+
         switch (network.getNetworkType()) {
             case VXLAN:
                 osNodeService.completeNodes(COMPUTE).stream()
                         .filter(cNode -> cNode.dataIp() != null)
-                        .forEach(cNode -> setRulesToGatewayWithDstIp(
+                        .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
                                 cNode,
                                 sourceNatGateway,
                                 network.getProviderSegID(),
-                                IpAddress.valueOf(osSubnet.getGateway()),
+                                osSubnet,
+                                routableSubnets,
                                 NetworkMode.VXLAN,
                                 install));
                 break;
             case VLAN:
                 osNodeService.completeNodes(COMPUTE).stream()
                         .filter(cNode -> cNode.vlanPortNum() != null)
-                        .forEach(cNode -> setRulesToGatewayWithDstIp(
+                        .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
                                 cNode,
                                 sourceNatGateway,
                                 network.getProviderSegID(),
-                                IpAddress.valueOf(osSubnet.getGateway()),
+                                osSubnet,
+                                routableSubnets,
                                 NetworkMode.VLAN,
                                 install));
                 break;
@@ -663,7 +668,6 @@
 
     private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
                                    NetworkType networkType, boolean install) {
-        TrafficTreatment treatment;
         OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
 
         if (sourceNatGateway == null) {
@@ -747,6 +751,26 @@
                 install);
     }
 
+    private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode, OpenstackNode sourceNatGateway,
+                                                      String segmentId, Subnet updatedSubnet,
+                                                      Set<Subnet> routableSubnets, NetworkMode networkMode,
+                                                      boolean install) {
+        //At first we install flow rules to gateway with segId and gatewayIp of updated subnet
+        setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId, IpAddress.valueOf(updatedSubnet.getGateway()),
+                networkMode, install);
+
+        routableSubnets.forEach(subnet -> {
+            setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
+                    segmentId, IpAddress.valueOf(subnet.getGateway()),
+                    networkMode, install);
+
+            Network network = osNetworkAdminService.network(subnet.getNetworkId());
+            setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
+                    network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
+                    networkMode, install);
+        });
+    }
+
     private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
                                             String segmentId, IpAddress dstIp,
                                             NetworkMode networkMode, boolean install) {
@@ -758,6 +782,7 @@
 
         switch (networkMode) {
             case VXLAN:
+                sBuilder.matchTunnelId(Long.parseLong(segmentId));
                 tBuilder.extension(buildExtension(
                         deviceService,
                         osNode.intgBridge(),
@@ -767,6 +792,7 @@
                 break;
 
             case VLAN:
+                sBuilder.matchVlanId(VlanId.vlanId(segmentId));
                 tBuilder.setOutput(osNode.vlanPortNum());
                 break;
 
@@ -975,10 +1001,12 @@
                             event.routerIface()));
                     break;
                 case OPENSTACK_ROUTER_GATEWAY_ADDED:
-                    log.debug("Router external gateway {} added", event.externalGateway().getNetworkId());
+                    log.debug("Router external gateway {} added",
+                                        event.externalGateway().getNetworkId());
                     break;
                 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
-                    log.debug("Router external gateway {} removed", event.externalGateway().getNetworkId());
+                    log.debug("Router external gateway {} removed",
+                                        event.externalGateway().getNetworkId());
                     break;
                 case OPENSTACK_FLOATING_IP_CREATED:
                 case OPENSTACK_FLOATING_IP_UPDATED:
@@ -1083,7 +1111,7 @@
         }
 
         private void instPortDetected(InstancePort instPort) {
-            if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
+            if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == FLAT) {
                 return;
             }
 
@@ -1099,7 +1127,7 @@
         }
 
         private void instPortRemoved(InstancePort instPort) {
-            if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
+            if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == FLAT) {
                 return;
             }
 
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
index dc734a9..6558410 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
@@ -770,20 +770,22 @@
                 case OPENSTACK_INSTANCE_PORT_UPDATED:
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
                 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
-                    installSecurityGroupRules(event, instPort);
+                    eventExecutor.execute(() ->
+                                    installSecurityGroupRules(event, instPort));
                     break;
                 case OPENSTACK_INSTANCE_PORT_VANISHED:
-                    Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
-                    eventExecutor.execute(() ->
-                            setSecurityGroupRules(instPort, osPort, false)
-                    );
-                    removedOsPortStore.remove(instPort.portId());
+                    eventExecutor.execute(() -> {
+                        Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
+                        setSecurityGroupRules(instPort, osPort, false);
+                        removedOsPortStore.remove(instPort.portId());
+                    });
                     break;
                 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
-                    InstancePort revisedInstPort = swapStaleLocation(instPort);
-                    Port port = osNetService.port(instPort.portId());
-                    eventExecutor.execute(() ->
-                            setSecurityGroupRules(revisedInstPort, port, false));
+                    eventExecutor.execute(() -> {
+                        InstancePort revisedInstPort = swapStaleLocation(instPort);
+                        Port port = osNetService.port(instPort.portId());
+                        setSecurityGroupRules(revisedInstPort, port, false);
+                    });
                     break;
                 default:
                     break;
@@ -825,7 +827,8 @@
 
             switch (event.type()) {
                 case OPENSTACK_PORT_PRE_REMOVE:
-                    removedOsPortStore.put(osPort.getId(), osPort);
+                    eventExecutor.execute(() ->
+                                removedOsPortStore.put(osPort.getId(), osPort));
                     break;
                 default:
                     // do nothing for the other events
@@ -948,7 +951,8 @@
         public void event(OpenstackNodeEvent event) {
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    resetSecurityGroupRules();
+                    eventExecutor.execute(OpenstackSecurityGroupHandler.this::
+                                                        resetSecurityGroupRules);
                     break;
                 case OPENSTACK_NODE_CREATED:
                 case OPENSTACK_NODE_REMOVED:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index d88c05d..a4696d5 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -70,8 +70,11 @@
 import java.util.Dictionary;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
@@ -150,6 +153,9 @@
     private final InstancePortListener instancePortListener = new InternalInstancePortListener();
     private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
 
+    private final ExecutorService eventExecutor = newSingleThreadExecutor(
+            groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+
 
     private ApplicationId appId;
     private NodeId localNodeId;
@@ -177,6 +183,7 @@
         instancePortService.removeListener(instancePortListener);
         leadershipService.withdraw(appId.name());
         configService.unregisterProperties(getClass(), false);
+        eventExecutor.shutdown();
 
         log.info("Stopped");
     }
@@ -545,7 +552,8 @@
             if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
                 return;
             }
-            processPacketIn(context, ethPacket);
+
+            eventExecutor.execute(() -> processPacketIn(context, ethPacket));
         }
     }
 
@@ -588,10 +596,14 @@
             switch (event.type()) {
                 case OPENSTACK_SUBNET_CREATED:
                 case OPENSTACK_SUBNET_UPDATED:
-                    setFakeGatewayArpRule(event.subnet(), true, null);
+                    eventExecutor.execute(() -> {
+                        setFakeGatewayArpRule(event.subnet(), true, null);
+                    });
                     break;
                 case OPENSTACK_SUBNET_REMOVED:
-                    setFakeGatewayArpRule(event.subnet(), false, null);
+                    eventExecutor.execute(() -> {
+                        setFakeGatewayArpRule(event.subnet(), false, null);
+                    });
                     break;
                 case OPENSTACK_NETWORK_CREATED:
                 case OPENSTACK_NETWORK_UPDATED:
@@ -626,12 +638,16 @@
             OpenstackNode osNode = event.subject();
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    setDefaultArpRule(osNode, true);
-                    setAllArpRules(osNode, true);
+                    eventExecutor.execute(() -> {
+                        setDefaultArpRule(osNode, true);
+                        setAllArpRules(osNode, true);
+                    });
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
-                    setDefaultArpRule(osNode, false);
-                    setAllArpRules(osNode, false);
+                    eventExecutor.execute(() -> {
+                        setDefaultArpRule(osNode, false);
+                        setAllArpRules(osNode, false);
+                    });
                     break;
                 default:
                     break;
@@ -747,20 +763,28 @@
             switch (event.type()) {
                 case OPENSTACK_INSTANCE_PORT_DETECTED:
                 case OPENSTACK_INSTANCE_PORT_UPDATED:
-                    setArpRequestRule(event.subject(), true);
-                    setArpReplyRule(event.subject(), true);
+                    eventExecutor.execute(() -> {
+                        setArpRequestRule(event.subject(), true);
+                        setArpReplyRule(event.subject(), true);
+                    });
                     break;
                 case OPENSTACK_INSTANCE_PORT_VANISHED:
-                    setArpRequestRule(event.subject(), false);
-                    setArpReplyRule(event.subject(), false);
+                    eventExecutor.execute(() -> {
+                        setArpRequestRule(event.subject(), false);
+                        setArpReplyRule(event.subject(), false);
+                    });
                     break;
                 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
-                    setArpRequestRule(event.subject(), true);
-                    setArpReplyRule(event.subject(), true);
+                    eventExecutor.execute(() -> {
+                        setArpRequestRule(event.subject(), true);
+                        setArpReplyRule(event.subject(), true);
+                    });
                     break;
                 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
-                    InstancePort revisedInstPort = swapStaleLocation(event.subject());
-                    setArpRequestRule(revisedInstPort, false);
+                    eventExecutor.execute(() -> {
+                        InstancePort revisedInstPort = swapStaleLocation(event.subject());
+                        setArpRequestRule(revisedInstPort, false);
+                    });
                     break;
                 default:
                     break;
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
index 71fa4d1..113feb9 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
@@ -71,8 +71,10 @@
 import java.util.Dictionary;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.ExecutorService;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_BroadcastAddress;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_Classless_Static_Route;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DHCPServerIp;
@@ -84,6 +86,7 @@
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_SubnetMask;
 import static org.onlab.packet.DHCP.MsgType.DHCPACK;
 import static org.onlab.packet.DHCP.MsgType.DHCPOFFER;
+import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE;
 import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.DHCP_SERVER_MAC;
@@ -153,6 +156,9 @@
     private final PacketProcessor packetProcessor = new InternalPacketProcessor();
     private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
 
+    private final ExecutorService eventExecutor = newSingleThreadExecutor(
+            groupedThreads(this.getClass().getSimpleName(), "event-handler"));
+
     private ApplicationId appId;
     private NodeId localNodeId;
 
@@ -174,6 +180,7 @@
         osNodeService.removeListener(osNodeListener);
         configService.unregisterProperties(getClass(), false);
         leadershipService.withdraw(appId.name());
+        eventExecutor.shutdown();
 
         log.info("Stopped");
     }
@@ -215,7 +222,8 @@
             }
 
             DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
-            processDhcp(context, dhcpPacket);
+
+            eventExecutor.execute(() -> processDhcp(context, dhcpPacket));
         }
 
         private void processDhcp(PacketContext context, DHCP dhcpPacket) {
@@ -550,10 +558,10 @@
             OpenstackNode osNode = event.subject();
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    setDhcpRule(osNode, true);
+                    eventExecutor.execute(() -> setDhcpRule(osNode, true));
                     break;
                 case OPENSTACK_NODE_INCOMPLETE:
-                    setDhcpRule(osNode, false);
+                    eventExecutor.execute(() -> setDhcpRule(osNode, false));
                     break;
                 case OPENSTACK_NODE_CREATED:
                 case OPENSTACK_NODE_UPDATED:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
index f6977a3..47fad9d 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
@@ -47,7 +47,6 @@
 import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
-import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.openstack4j.model.network.Network;
@@ -130,9 +129,6 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected OpenstackNodeService osNodeService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    protected OpenstackSecurityGroupService securityGroupService;
-
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler"));
     private final InstancePortListener instancePortListener = new InternalInstancePortListener();
@@ -798,7 +794,7 @@
             boolean isNwAdminStateUp = event.subject().isAdminStateUp();
             boolean isPortAdminStateUp = event.port().isAdminStateUp();
 
-            InstancePort instPort = instancePortService.instancePort(event.port().getId());
+            String portId = event.port().getId();
 
             switch (event.type()) {
                 case OPENSTACK_NETWORK_CREATED:
@@ -813,20 +809,20 @@
                     break;
                 case OPENSTACK_PORT_CREATED:
                 case OPENSTACK_PORT_UPDATED:
-
-                    if (instPort != null) {
-                        eventExecutor.execute(() ->
-                                setPortBlockRules(instPort, !isPortAdminStateUp));
-                    }
-
+                    eventExecutor.execute(() -> {
+                        InstancePort instPort = instancePortService.instancePort(portId);
+                        if (instPort != null) {
+                            setPortBlockRules(instPort, !isPortAdminStateUp);
+                        }
+                    });
                     break;
                 case OPENSTACK_PORT_REMOVED:
-
-                    if (instPort != null) {
-                        eventExecutor.execute(() ->
-                                setPortBlockRules(instPort, false));
-                    }
-
+                    eventExecutor.execute(() -> {
+                        InstancePort instPort = instancePortService.instancePort(portId);
+                        if (instPort != null) {
+                            setPortBlockRules(instPort, false);
+                        }
+                    });
                     break;
                 default:
                     break;
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index 92005cf..8b190d0 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -304,11 +304,11 @@
 
         @Override
         public boolean isRelevant(DeviceEvent event) {
-            Device device = event.subject();
-            if (!mastershipService.isLocalMaster(device.id())) {
+            if (!mastershipService.isLocalMaster(event.subject().id())) {
                 // do not allow to proceed without mastership
                 return false;
             }
+
             Port port = event.port();
             if (port == null) {
                 return false;
@@ -388,8 +388,10 @@
 
         private void processCompleteNode(OpenstackNode osNode) {
             deviceService.getPorts(osNode.intgBridge()).stream()
-                    .filter(port -> vnicType(port.annotations().value(PORT_NAME)).equals(Constants.VnicType.NORMAL) ||
-                            vnicType(port.annotations().value(PORT_NAME)).equals(Constants.VnicType.DIRECT))
+                    .filter(port -> vnicType(port.annotations().value(PORT_NAME))
+                                    .equals(Constants.VnicType.NORMAL) ||
+                            vnicType(port.annotations().value(PORT_NAME))
+                                    .equals(Constants.VnicType.DIRECT))
                     .filter(Port::isEnabled)
                     .forEach(port -> {
                         log.debug("Instance port {} is detected from {}",
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index db15e15..25a7e41 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -884,11 +884,11 @@
      * @param gatewayNode gateway node
      * @param packetService packet service
      */
-    public static void processGratuitousArpPacketForFloatingIp(NetFloatingIP floatingIP,
-                                                               InstancePort instancePort,
-                                                               VlanId vlanId,
-                                                               OpenstackNode gatewayNode,
-                                                               PacketService packetService) {
+    public static void processGarpPacketForFloatingIp(NetFloatingIP floatingIP,
+                                                      InstancePort instancePort,
+                                                      VlanId vlanId,
+                                                      OpenstackNode gatewayNode,
+                                                      PacketService packetService) {
         Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
 
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
diff --git a/cli/src/main/java/org/onosproject/cli/net/ResourcesCommand.java b/cli/src/main/java/org/onosproject/cli/net/ResourcesCommand.java
index d4c1a40..cddf7e1 100644
--- a/cli/src/main/java/org/onosproject/cli/net/ResourcesCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/ResourcesCommand.java
@@ -177,10 +177,18 @@
         List<Resource> nonAggregatable = new ArrayList<>();
 
         for (Resource r : children) {
-            if (!isPrintTarget(r)) {
+            if (!isPrintTarget(r)) { // A
                 continue;
             }
 
+            if (r instanceof DiscreteResource) {
+
+                if (resourceService.getRegisteredResources(((DiscreteResource) r).id()).isEmpty()) {
+                    // resource which has children should be printed
+                    continue;
+                }
+            }
+
             if (r instanceof ContinuousResource) {
                 // non-aggregatable terminal node
                 nonAggregatable.add(r);
@@ -193,6 +201,7 @@
             }
         }
 
+
         // print aggregated (terminal)
         aggregatables.asMap().entrySet()
             .forEach(e -> {
@@ -241,12 +250,7 @@
 
         String resourceName = resource.simpleTypeName();
         if (resource instanceof DiscreteResource) {
-            // TODO This distributed store access incurs overhead.
-            //      This should be merged with the one in printResource()
-            if (!resourceService.getRegisteredResources(((DiscreteResource) resource).id()).isEmpty()) {
-                // resource which has children should be printed
-                return true;
-            }
+
             if (availablesOnly && !resourceService.isAvailable(resource)) {
                 // don't print unavailable discrete resource
                 return false;
@@ -255,7 +259,6 @@
             log.warn("Unexpected resource class: {}", resource.getClass().getSimpleName());
             return false;
         }
-
         return typesToPrint.contains(resourceName);
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java b/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
index 5af7f7a..ce3c094 100644
--- a/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
+++ b/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
@@ -216,6 +216,11 @@
     public static final String SSHKEY = "sshkey";
 
     /**
+     * Annotation key for the protocol layer.
+     */
+    public static final String LAYER = "layer";
+
+    /**
      * Returns the value annotated object for the specified annotation key.
      * The annotated value is expected to be String that can be parsed as double.
      * If parsing fails, the returned value will be {@value #DEFAULT_VALUE}.
diff --git a/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java b/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java
index 1a38bfd..d0a9d54 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java
@@ -19,6 +19,7 @@
 import com.google.common.base.MoreObjects;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.Link;
 import org.onosproject.net.ResourceGroup;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -38,6 +39,8 @@
     private final FilteredConnectPoint ingressPoint;
     private final FilteredConnectPoint egressPoint;
 
+    private final List<Link> suggestedPath;
+
     /**
      * Returns a new point to point intent builder. The application id,
      * ingress point and egress point are required fields.  If they are
@@ -57,6 +60,8 @@
         FilteredConnectPoint ingressPoint;
         FilteredConnectPoint egressPoint;
 
+        List<Link> suggestedPath;
+
         private Builder() {
             // Hide constructor
         }
@@ -121,12 +126,36 @@
         }
 
         /**
+         * Sets the suggested path as list of links.
+         *
+         * @param links list of suggested links
+         * @return this builder
+         */
+        public Builder suggestedPath(List<Link> links) {
+            this.suggestedPath = links;
+            return this;
+        }
+
+        /**
          * Builds a point to point intent from the accumulated parameters.
          *
          * @return point to point intent
          */
         public PointToPointIntent build() {
-
+            if (suggestedPath != null &&
+                    suggestedPath.size() > 0 &&
+                    (!suggestedPath.get(0)
+                            .src()
+                            .deviceId()
+                            .equals(ingressPoint.connectPoint().deviceId()) ||
+                     !suggestedPath.get(suggestedPath.size() - 1)
+                             .dst()
+                             .deviceId()
+                             .equals(egressPoint.connectPoint().deviceId()))
+                    ) {
+                throw new IllegalArgumentException(
+                        "Suggested path not compatible with ingress and egress connect points");
+            }
             return new PointToPointIntent(
                     appId,
                     key,
@@ -136,6 +165,7 @@
                     egressPoint,
                     constraints,
                     priority,
+                    suggestedPath,
                     resourceGroup
             );
         }
@@ -147,16 +177,17 @@
      * Creates a new point-to-point intent with the supplied ingress/egress
      * ports and constraints.
      *
-     * @param appId        application identifier
-     * @param key          key of the intent
-     * @param selector     traffic selector
-     * @param treatment    treatment
-     * @param ingressPoint filtered ingress port
-     * @param egressPoint  filtered egress port
-     * @param constraints  optional list of constraints
-     * @param priority     priority to use for flows generated by this intent
+     * @param appId             application identifier
+     * @param key               key of the intent
+     * @param selector          traffic selector
+     * @param treatment         treatment
+     * @param ingressPoint      filtered ingress port
+     * @param egressPoint       filtered egress port
+     * @param constraints       optional list of constraints
+     * @param priority          priority to use for flows generated by this intent
+     * @param suggestedPath     suggested path
      * @throws NullPointerException if {@code ingressPoint} or
-     *        {@code egressPoints} or {@code appId} is null.
+     *        {@code egressPoints} or {@code appId} is null or {@code path} is null.
      */
     private PointToPointIntent(ApplicationId appId,
                                Key key,
@@ -166,15 +197,24 @@
                                FilteredConnectPoint egressPoint,
                                List<Constraint> constraints,
                                int priority,
+                               List<Link> suggestedPath,
                                ResourceGroup resourceGroup) {
-        super(appId, key, Collections.emptyList(), selector, treatment, constraints,
-                priority, resourceGroup);
+        super(appId,
+              key,
+              suggestedPath != null ? resources(suggestedPath) : Collections.emptyList(),
+              selector,
+              treatment,
+              constraints,
+              priority,
+              resourceGroup);
 
         checkArgument(!ingressPoint.equals(egressPoint),
                 "ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint);
 
         this.ingressPoint = checkNotNull(ingressPoint);
         this.egressPoint = checkNotNull(egressPoint);
+        this.suggestedPath = suggestedPath;
+
     }
 
     /**
@@ -184,6 +224,7 @@
         super();
         this.ingressPoint = null;
         this.egressPoint = null;
+        this.suggestedPath = null;
     }
 
     /**
@@ -205,6 +246,16 @@
         return egressPoint;
     }
 
+
+    /**
+     * Return the suggested path (as a list of links) that the compiler should use.
+     *
+     * @return suggested path
+     */
+    public List<Link> suggestedPath() {
+        return suggestedPath;
+    }
+
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
@@ -218,6 +269,7 @@
                 .add("ingress", filteredIngressPoint())
                 .add("egress", filteredEgressPoint())
                 .add("constraints", constraints())
+                .add("links", suggestedPath())
                 .add("resourceGroup", resourceGroup())
                 .toString();
     }
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index 48b4a87..2b8c6d7 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -20,6 +20,8 @@
 import org.onlab.graph.ScalarWeight;
 import org.onlab.graph.Weight;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultLink;
 import org.onosproject.net.DefaultPath;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.ElementId;
@@ -41,6 +43,7 @@
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
+import org.onosproject.net.link.LinkServiceAdapter;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.topology.DefaultTopologyEdge;
 import org.onosproject.net.topology.DefaultTopologyVertex;
@@ -58,7 +61,10 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import static org.onosproject.net.Link.Type.DIRECT;
 import static org.onosproject.net.NetTestTools.*;
 
 /**
@@ -189,6 +195,71 @@
     }
 
     /**
+     * Mock path service for creating paths within the test with multiple possible paths.
+     */
+    public static class MockMultiplePathService extends PathServiceAdapter {
+
+        final String[][] pathsHops;
+
+        /**
+         * Constructor that provides a set of hops to mock.
+         *
+         * @param pathHops multiple path hops to mock
+         */
+        public MockMultiplePathService(String[][] pathHops) {
+            this.pathsHops = pathHops;
+        }
+
+        @Override
+        public Set<Path> getPaths(ElementId src, ElementId dst) {
+
+            //Extracts all the paths that goes from src to dst
+            Set<Path> allPaths = new HashSet<>();
+            allPaths.addAll(IntStream.range(0, pathsHops.length)
+                    .filter(i -> src.toString().endsWith(pathsHops[i][0])
+                            && dst.toString().endsWith(pathsHops[i][pathsHops[i].length - 1]))
+                    .mapToObj(i -> createPath(src instanceof HostId,
+                                              dst instanceof HostId,
+                                              pathsHops[i]))
+                    .collect(Collectors.toSet()));
+
+            // Maintain only the shortest paths
+            int minPathLength = allPaths.stream()
+                    .mapToInt(o -> o.links().size())
+                    .min()
+                    .orElse(Integer.MAX_VALUE);
+            Set<Path> shortestPaths = allPaths.stream()
+                    .filter(path -> path.links().size() <= minPathLength)
+                    .collect(Collectors.toSet());
+
+            return shortestPaths;
+        }
+
+
+        @Override
+        public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeigher weigher) {
+            Set<Path> paths = getPaths(src, dst);
+
+            for (Path path : paths) {
+                DeviceId srcDevice = path.src().elementId() instanceof DeviceId ? path.src().deviceId() : null;
+                DeviceId dstDevice = path.dst().elementId() instanceof DeviceId ? path.dst().deviceId() : null;
+                if (srcDevice != null && dstDevice != null) {
+                    TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice);
+                    TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice);
+                    Link link = link(src.toString(), 1, dst.toString(), 1);
+
+                    Weight weightValue = weigher.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link));
+                    if (weightValue.isNegative()) {
+                        return new HashSet<>();
+                    }
+                }
+            }
+            return paths;
+        }
+    }
+
+
+    /**
      * Mock path service for creating paths within the test.
      *
      */
@@ -249,6 +320,22 @@
     }
 
     /**
+     * Mock active and direct link.
+     */
+    public static class FakeLink extends DefaultLink {
+
+        /**
+         * Constructor that provides source and destination of the fake link.
+         *
+         * @param src Source connect point of the fake link
+         * @param dst Destination connect point of the fake link
+         */
+        public FakeLink(ConnectPoint src, ConnectPoint dst) {
+            super(null, src, dst, DIRECT, Link.State.ACTIVE);
+        }
+    }
+
+    /**
      * Mock path service for creating paths for MP2SP intent tests, returning
      * pre-determined paths.
      */
@@ -319,6 +406,38 @@
         }
     }
 
+    /**
+     * Mock link service for getting links to check path availability
+     * when a suggested path is submitted.
+     */
+    public static class MockLinkService extends LinkServiceAdapter {
+        final String[][] linksHops;
+
+        /**
+         * Constructor that provides a set of links (as a list of hops).
+         *
+         * @param linksHops links to to mock (link as a set of hops)
+         */
+        public MockLinkService(String[][] linksHops) {
+            this.linksHops = linksHops;
+        }
+
+        @Override
+        public Set<Link> getLinks() {
+            return Arrays.asList(linksHops).stream()
+                    .map(path -> createPath(path).links())
+                    .flatMap(List::stream)
+                    .collect(Collectors.toSet());
+        }
+        @Override
+        public Set<Link> getLinks(ConnectPoint connectPoint) {
+            return getLinks().stream()
+                    .filter(link -> link.src().deviceId().equals(connectPoint.deviceId())
+                    || link.dst().deviceId().equals(connectPoint.deviceId()))
+                    .collect(Collectors.toSet());
+        }
+    }
+
     private static final IntentTestsMocks.MockSelector SELECTOR =
             new IntentTestsMocks.MockSelector();
     private static final IntentTestsMocks.MockTreatment TREATMENT =
diff --git a/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java b/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
index 3b170a0..c0257c0 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
@@ -17,8 +17,15 @@
 
 import org.junit.Test;
 import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.Link;
 
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass;
 
 /**
@@ -59,6 +66,34 @@
         assertEquals("incorrect egress", FP2, intent.filteredEgressPoint());
     }
 
+    @Test
+    public void suggestedPath() {
+        List<Link> suggestedPath = new LinkedList<>();
+        suggestedPath.add(new IntentTestsMocks.FakeLink(FP1.connectPoint(), FP2.connectPoint()));
+
+        PointToPointIntent intent = createWithSuggestedPath(suggestedPath);
+        assertEquals("incorrect id", APPID, intent.appId());
+        assertEquals("incorrect match", MATCH, intent.selector());
+        assertEquals("incorrect ingress", FP1, intent.filteredIngressPoint());
+        assertEquals("incorrect egress", FP2, intent.filteredEgressPoint());
+        assertEquals("incorrect suggested path", suggestedPath, intent.suggestedPath());
+
+    }
+
+    @Test
+    public void failSuggestedPath() {
+        List<Link> suggestedPath = new LinkedList<>();
+        try {
+            suggestedPath.add(new IntentTestsMocks.FakeLink(FP3.connectPoint(), FP2.connectPoint()));
+
+            createWithSuggestedPath(suggestedPath);
+            fail("Point to Point intent building with incompatible suggested path "
+                         + "not throw exception.");
+        } catch (IllegalArgumentException exception) {
+            assertThat(exception.getMessage(), containsString("Suggested path not compatible"));
+        }
+    }
+
     @Override
     protected PointToPointIntent createOne() {
         return PointToPointIntent.builder()
@@ -101,4 +136,15 @@
                 .filteredEgressPoint(FP2)
                 .build();
     }
+
+    protected PointToPointIntent createWithSuggestedPath(List<Link> suggestedPath) {
+        return PointToPointIntent.builder()
+                .appId(APPID)
+                .selector(MATCH)
+                .treatment(NOP)
+                .filteredIngressPoint(FP1)
+                .filteredEgressPoint(FP2)
+                .suggestedPath(suggestedPath)
+                .build();
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java
index a90f84c..16b0e69 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java
@@ -318,13 +318,17 @@
 
         if (obj instanceof FilteringObjective) {
             FilteringObjQueueKey k = new FilteringObjQueueKey(deviceId, priority, ((FilteringObjective) obj).key());
-            filtObjQueueHead.invalidate(k);
+            if (!ObjectiveError.INSTALLATIONTIMEOUT.equals(error)) {
+                filtObjQueueHead.invalidate(k);
+            }
             filtObjQueue.remove(k, obj);
             remaining = filtObjQueue.get(k);
         } else if (obj instanceof ForwardingObjective) {
             ForwardingObjQueueKey k =
                     new ForwardingObjQueueKey(deviceId, priority, ((ForwardingObjective) obj).selector());
-            fwdObjQueueHead.invalidate(k);
+            if (!ObjectiveError.INSTALLATIONTIMEOUT.equals(error)) {
+                fwdObjQueueHead.invalidate(k);
+            }
             fwdObjQueue.remove(k, obj);
             remaining = fwdObjQueue.get(k);
         } else if (obj instanceof NextObjective) {
@@ -345,7 +349,9 @@
                 }
             }
             NextObjQueueKey k = new NextObjQueueKey(deviceId, obj.id());
-            nextObjQueueHead.invalidate(k);
+            if (!ObjectiveError.INSTALLATIONTIMEOUT.equals(error)) {
+                nextObjQueueHead.invalidate(k);
+            }
             nextObjQueue.remove(k, obj);
             remaining = nextObjQueue.get(k);
         } else {
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java
index 666128c..a35af7b 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java
@@ -161,6 +161,28 @@
     }
 
     /**
+     * Computes all the paths between two ConnectPoints.
+     *
+     * @param intent intent on which behalf path is being computed
+     * @param one    start of the path
+     * @param two    end of the path
+     * @return Paths between the two, or null if no path can be found
+     */
+    protected List<Path> getPaths(ConnectivityIntent intent,
+                           ElementId one, ElementId two) {
+        Set<Path> paths = pathService.getPaths(one, two, weigher(intent.constraints()));
+        final List<Constraint> constraints = intent.constraints();
+        ImmutableList<Path> filtered = FluentIterable.from(paths)
+                .filter(path -> checkPath(path, constraints))
+                .toList();
+        if (filtered.isEmpty()) {
+            return null;
+        }
+
+        return filtered;
+    }
+
+    /**
      * Computes a disjoint path between two ConnectPoints.
      *
      * @param intent intent on which behalf path is being computed
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java
index ad65e46..0079fe5 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.intent.impl.compiler;
 
 import com.google.common.collect.ImmutableSet;
+import org.apache.commons.lang3.tuple.Pair;
 import org.onlab.graph.ScalarWeight;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultPath;
@@ -74,6 +75,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
 import static java.util.Arrays.asList;
@@ -124,6 +126,18 @@
         ConnectPoint ingressPoint = intent.filteredIngressPoint().connectPoint();
         ConnectPoint egressPoint = intent.filteredEgressPoint().connectPoint();
 
+        //TODO: handle protected path case with suggested path!!
+        //Idea: use suggested path as primary and another path from path service as protection
+        if (intent.suggestedPath() != null && intent.suggestedPath().size() > 0) {
+            Path path = new DefaultPath(PID, intent.suggestedPath(), new ScalarWeight(1));
+            //Check intent constraints against suggested path and suggested path availability
+            if (checkPath(path, intent.constraints()) && pathAvailable(intent)) {
+                allocateIntentBandwidth(intent, path);
+                return asList(createLinkCollectionIntent(ImmutableSet.copyOf(intent.suggestedPath()),
+                                                         DEFAULT_COST, intent));
+            }
+        }
+
         if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
             return createZeroHopLinkCollectionIntent(intent);
         }
@@ -143,6 +157,21 @@
         }
     }
 
+    private void allocateIntentBandwidth(PointToPointIntent intent, Path path) {
+        ConnectPoint ingressCP = intent.filteredIngressPoint().connectPoint();
+        ConnectPoint egressCP = intent.filteredEgressPoint().connectPoint();
+
+        List<ConnectPoint> pathCPs =
+                path.links().stream()
+                        .flatMap(l -> Stream.of(l.src(), l.dst()))
+                        .collect(Collectors.toList());
+
+        pathCPs.add(ingressCP);
+        pathCPs.add(egressCP);
+
+        allocateBandwidth(intent, pathCPs);
+    }
+
     private List<Intent> createZeroHopIntent(ConnectPoint ingressPoint,
                                              ConnectPoint egressPoint,
                                              PointToPointIntent intent) {
@@ -161,18 +190,7 @@
                                        intent.filteredEgressPoint().connectPoint().deviceId());
 
         // Allocate bandwidth if a bandwidth constraint is set
-        ConnectPoint ingressCP = intent.filteredIngressPoint().connectPoint();
-        ConnectPoint egressCP = intent.filteredEgressPoint().connectPoint();
-
-        List<ConnectPoint> pathCPs =
-                path.links().stream()
-                            .flatMap(l -> Stream.of(l.src(), l.dst()))
-                            .collect(Collectors.toList());
-
-        pathCPs.add(ingressCP);
-        pathCPs.add(egressCP);
-
-        allocateBandwidth(intent, pathCPs);
+        allocateIntentBandwidth(intent, path);
 
         return asList(createLinkCollectionIntent(ImmutableSet.copyOf(path.links()),
                                                  path.cost(),
@@ -291,19 +309,7 @@
             return reusableIntents;
         } else {
             // Allocate bandwidth if a bandwidth constraint is set
-            ConnectPoint ingressCP = intent.filteredIngressPoint().connectPoint();
-            ConnectPoint egressCP = intent.filteredEgressPoint().connectPoint();
-
-            List<ConnectPoint> pathCPs =
-                    onlyPath.links().stream()
-                            .flatMap(l -> Stream.of(l.src(), l.dst()))
-                            .collect(Collectors.toList());
-
-            pathCPs.add(ingressCP);
-            pathCPs.add(egressCP);
-
-            // Allocate bandwidth if a bandwidth constraint is set
-            allocateBandwidth(intent, pathCPs);
+            allocateIntentBandwidth(intent, onlyPath);
 
             links.add(createEdgeLink(ingressPoint, true));
             links.addAll(onlyPath.links());
@@ -694,4 +700,47 @@
 
         groupService.addBucketsToGroup(src.deviceId(), groupKey, addBuckets, groupKey, intent.appId());
     }
+
+    /**
+     * Checks suggested path availability.
+     * It checks:
+     * - single links availability;
+     * - that first and last device of the path are coherent with ingress and egress devices;
+     * - links contiguity.
+     *
+     * @param intent    Intent with suggested path to check
+     * @return true if the suggested path is available
+     */
+    private boolean pathAvailable(PointToPointIntent intent) {
+        // Check links availability
+        List<Link> suggestedPath = intent.suggestedPath();
+        for (Link link : suggestedPath) {
+            if (!(link instanceof EdgeLink) && !linkService.getLinks(link.src()).contains(link)) {
+                return false;
+            }
+        }
+
+        //Check that first and last device of the path are intent ingress and egress devices
+        if (!suggestedPath.get(0).src()
+                .deviceId().equals(intent.filteredIngressPoint().connectPoint().deviceId())) {
+            return false;
+        }
+        if (!suggestedPath.get(suggestedPath.size() - 1).dst()
+                .deviceId().equals(intent.filteredEgressPoint().connectPoint().deviceId())) {
+            return false;
+        }
+
+        // Check contiguity
+        List<Pair<Link, Link>> linkPairs = IntStream.
+            range(0, suggestedPath.size() - 1)
+            .mapToObj(i -> Pair.of(suggestedPath.get(i), suggestedPath.get(i + 1)))
+            .collect(Collectors.toList());
+
+        for (Pair<Link, Link> linkPair : linkPairs) {
+            if (!linkPair.getKey().dst().deviceId().equals(linkPair.getValue().src().deviceId())) {
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
index ff63efe..78dd986 100644
--- a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
+++ b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
@@ -345,6 +345,7 @@
     }
 
     private DefaultForwardingObjective.Builder createBuilder(PacketRequest request) {
+        ApplicationId requestedAppId = coreService.getAppId(request.appId().name()); // Validate app id
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .punt()
                 .wipeDeferred()
@@ -353,7 +354,7 @@
         return DefaultForwardingObjective.builder()
                 .withPriority(request.priority().priorityValue())
                 .withSelector(request.selector())
-                .fromApp(appId)
+                .fromApp(requestedAppId == null ? appId : requestedAppId)
                 .withFlag(ForwardingObjective.Flag.VERSATILE)
                 .withTreatment(treatment)
                 .makePermanent();
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java
index a811ad6..31c15ee 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java
@@ -25,6 +25,7 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.Link;
+import org.onosproject.net.NetTestTools;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.ResourceGroup;
 import org.onosproject.net.flow.TrafficSelector;
@@ -200,6 +201,54 @@
     }
 
     /**
+     * Creates a PointToPoint intent based on ingress and egress deviceIds
+     * and a suggested path.
+     * @param ingress           the ingress connect point
+     * @param egress            the egress connect point
+     * @param suggestedPath     the suggested path
+     * @return the PointToPointIntent connecting the two connect points with
+     * the suggested path (if available)
+     */
+    private PointToPointIntent makeIntentSuggestedPath(ConnectPoint ingress,
+                                                       ConnectPoint egress,
+                                                       List<Link> suggestedPath) {
+        return PointToPointIntent.builder()
+                .appId(APPID)
+                .selector(selector)
+                .treatment(treatment)
+                .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                .filteredEgressPoint(new FilteredConnectPoint(egress))
+                .suggestedPath(suggestedPath)
+                .build();
+    }
+
+    /**
+     * Creates a PointToPoint intent based on ingress and egress deviceIds and
+     * constraints with a suggested path.
+     *
+     * @param ingress         the ingress connect point
+     * @param egress          the egress connect point
+     * @param suggestedPath   the suggested path
+     * @param constraints     constraints
+     * @return the PointToPointIntent connecting the two connect points with
+     * constraints and a suggested path
+     */
+    private PointToPointIntent makeIntentSuggestedPath(ConnectPoint ingress,
+                                          ConnectPoint egress,
+                                          List<Link> suggestedPath,
+                                          List<Constraint> constraints) {
+        return PointToPointIntent.builder()
+                .appId(APPID)
+                .selector(selector)
+                .treatment(treatment)
+                .filteredIngressPoint(new FilteredConnectPoint(ingress))
+                .filteredEgressPoint(new FilteredConnectPoint(egress))
+                .constraints(constraints)
+                .suggestedPath(suggestedPath)
+                .build();
+    }
+
+    /**
      * Creates a compiler for HostToHost intents.
      *
      * @param hops string array describing the path hops to use when compiling
@@ -210,6 +259,41 @@
     }
 
     /**
+     * Creates a compiler for PointToPoint intents with suggested paths.
+     *
+     * @param paths all the possible paths in the network
+     * @return PointToPoint intent compiler
+     */
+    private PointToPointIntentCompiler makeCompilerSuggestedPath(String[][] paths) {
+        final PointToPointIntentCompiler compiler = new PointToPointIntentCompiler();
+        compiler.pathService = new IntentTestsMocks.MockMultiplePathService(paths);
+        compiler.linkService = new IntentTestsMocks.MockLinkService(paths);
+        return compiler;
+    }
+
+    /**
+     * Creates a point to point intent compiler for suggested path case.
+     *
+     * @param paths             all the possible paths in the network
+     * @param resourceService   service to use for resource allocation requests
+     * @return point to point compiler
+     */
+    private PointToPointIntentCompiler makeCompilerSuggestedPath(String[][] paths,
+                                                    ResourceService resourceService) {
+        final PointToPointIntentCompiler compiler = new PointToPointIntentCompiler();
+        compiler.pathService = new IntentTestsMocks.MockMultiplePathService(paths);
+        compiler.linkService = new IntentTestsMocks.MockLinkService(paths);
+
+        if (resourceService == null) {
+            compiler.resourceService = new MockResourceService();
+        } else {
+            compiler.resourceService = resourceService;
+        }
+
+        return compiler;
+    }
+
+    /**
      * Creates a point to point intent compiler for a three switch linear
      * topology.
      *
@@ -582,4 +666,151 @@
         assertThat(resourceAllocations, hasSize(6));
         assertEquals(expectedresourceAllocations, resourceAllocations);
     }
+
+    /**
+     * Test if a suggested path is correctly applied.
+     */
+    @Test
+    public void testSuggestedPath() {
+        String[] suggestedPathHops = {S1, S3, S4, S5, S6, S8};
+        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();
+
+        PointToPointIntent intent = makeIntentSuggestedPath(new ConnectPoint(DID_1, PORT_1),
+                                                            new ConnectPoint(DID_8, PORT_2),
+                                                            suggestedPath);
+
+        String[][] paths = {{S1, S2, S8}, suggestedPathHops};
+        PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(paths);
+
+        List<Intent> result = compiler.compile(intent, null);
+        assertThat(result, is(Matchers.notNullValue()));
+        assertThat(result, hasSize(1));
+        Intent resultIntent = result.get(0);
+        assertThat(resultIntent instanceof LinkCollectionIntent, is(true));
+
+        if (resultIntent instanceof LinkCollectionIntent) {
+            LinkCollectionIntent resultLinkIntent = (LinkCollectionIntent) resultIntent;
+            FilteredConnectPoint ingressPoint = new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1));
+            FilteredConnectPoint egressPoint = new FilteredConnectPoint(new ConnectPoint(DID_8, PORT_2));
+            // 5 links for the hops, plus one default link on ingress and egress
+            assertThat(resultLinkIntent.links(), hasSize(suggestedPathHops.length - 1));
+            assertThat(resultLinkIntent.links(), linksHasPath(S1, S3));
+            assertThat(resultLinkIntent.links(), linksHasPath(S3, S4));
+            assertThat(resultLinkIntent.links(), linksHasPath(S4, S5));
+            assertThat(resultLinkIntent.links(), linksHasPath(S5, S6));
+            assertThat(resultLinkIntent.links(), linksHasPath(S6, S8));
+            assertThat(resultLinkIntent.filteredIngressPoints(), is(ImmutableSet.of(ingressPoint)));
+            assertThat(resultLinkIntent.filteredEgressPoints(), is(ImmutableSet.of(egressPoint)));
+        }
+        assertThat("key is inherited", resultIntent.key(), is(intent.key()));
+    }
+
+    /**
+     * Test that if a suggested path isn't available it applies another available path.
+     */
+    @Test
+    public void testSuggestedPathNotAvailable() {
+        String[] suggestedPathHops = {S1, S3, S8};
+        String[] shortestPath = {S1, S2, S8};
+        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();
+
+        PointToPointIntent intent = makeIntentSuggestedPath(new ConnectPoint(DID_1, PORT_1),
+                                                            new ConnectPoint(DID_8, PORT_2),
+                                                            suggestedPath);
+
+        String[][] path = {shortestPath};
+        PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(path);
+
+        List<Intent> result = compiler.compile(intent, null);
+        assertThat(result, is(Matchers.notNullValue()));
+        assertThat(result, hasSize(1));
+        Intent resultIntent = result.get(0);
+        assertThat(resultIntent instanceof LinkCollectionIntent, is(true));
+
+        if (resultIntent instanceof LinkCollectionIntent) {
+            LinkCollectionIntent resultLinkIntent = (LinkCollectionIntent) resultIntent;
+            FilteredConnectPoint ingressPoint = new FilteredConnectPoint(new ConnectPoint(DID_1, PORT_1));
+            FilteredConnectPoint egressPoint = new FilteredConnectPoint(new ConnectPoint(DID_8, PORT_2));
+            // 5 links for the hops, plus one default link on ingress and egress
+            assertThat(resultLinkIntent.links(), hasSize(shortestPath.length - 1));
+            assertThat(resultLinkIntent.links(), linksHasPath(S1, S2));
+            assertThat(resultLinkIntent.links(), linksHasPath(S2, S8));
+            assertThat(resultLinkIntent.filteredIngressPoints(), is(ImmutableSet.of(ingressPoint)));
+            assertThat(resultLinkIntent.filteredEgressPoints(), is(ImmutableSet.of(egressPoint)));
+        }
+        assertThat("key is inherited", resultIntent.key(), is(intent.key()));
+    }
+
+    /**
+     * Tests that requests with suggested path
+     * and with sufficient available bandwidth succeed.
+     */
+    @Test
+    public void testSuggestedPathBandwidthConstrainedIntentSuccess() {
+        final double bpsTotal = 1000.0;
+        final double bpsToReserve = 100.0;
+
+        final ResourceService resourceService =
+                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
+        final List<Constraint> constraints =
+                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(bpsToReserve)));
+
+        String[] suggestedPathHops = {S1, S4, S5, S3};
+        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();
+
+        final PointToPointIntent intent = makeIntentSuggestedPath(
+                new ConnectPoint(DID_1, PORT_1),
+                new ConnectPoint(DID_3, PORT_2),
+                suggestedPath,
+                constraints);
+
+        String[][] hops = {{S1, S2, S3}, suggestedPathHops};
+        final PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(hops,
+                                                                 resourceService);
+
+        final List<Intent> compiledIntents = compiler.compile(intent, null);
+
+        assertThat(compiledIntents, Matchers.notNullValue());
+        assertThat(compiledIntents, hasSize(1));
+
+        assertThat("key is inherited",
+                   compiledIntents.stream().map(Intent::key).collect(Collectors.toList()),
+                   everyItem(is(intent.key())));
+
+    }
+
+    /**
+     * Tests that requests with insufficient available bandwidth fail.
+     */
+    @Test
+    public void testSuggestedPathBandwidthConstrainedIntentFailure() {
+        final double bpsTotal = 10.0;
+
+        final ResourceService resourceService =
+                MockResourceService.makeCustomBandwidthResourceService(bpsTotal);
+        final List<Constraint> constraints =
+                Collections.singletonList(new BandwidthConstraint(Bandwidth.bps(BPS_TO_RESERVE)));
+
+        String[] suggestedPathHops = {S1, S4, S5, S3};
+        List<Link> suggestedPath = NetTestTools.createPath(suggestedPathHops).links();
+
+        try {
+            final PointToPointIntent intent = makeIntentSuggestedPath(
+                    new ConnectPoint(DID_1, PORT_1),
+                    new ConnectPoint(DID_3, PORT_2),
+                    suggestedPath,
+                    constraints);
+
+            String[][] paths = {{S1, S2, S3}, suggestedPathHops};
+            final PointToPointIntentCompiler compiler = makeCompilerSuggestedPath(paths,
+                                                                     resourceService);
+
+            compiler.compile(intent, null);
+
+            fail("Point to Point compilation with insufficient bandwidth does "
+                         + "not throw exception.");
+        } catch (PathNotFoundException noPath) {
+            assertThat(noPath.getMessage(), containsString("No path"));
+        }
+    }
 }
diff --git a/drivers/arista/src/main/java/org/onosproject/drivers/arista/LinkDiscoveryAristaImpl.java b/drivers/arista/src/main/java/org/onosproject/drivers/arista/LinkDiscoveryAristaImpl.java
index 49ed615..a32c6b7 100644
--- a/drivers/arista/src/main/java/org/onosproject/drivers/arista/LinkDiscoveryAristaImpl.java
+++ b/drivers/arista/src/main/java/org/onosproject/drivers/arista/LinkDiscoveryAristaImpl.java
@@ -261,7 +261,7 @@
         ConnectPoint local = new ConnectPoint(localDevId, localPort.number());
         ConnectPoint remote = new ConnectPoint(remoteDevId, remotePort.number());
         DefaultAnnotations annotations = DefaultAnnotations.builder()
-                .set("layer", "ETHERNET")
+                .set(AnnotationKeys.LAYER, "ETHERNET")
                 .build();
 
         linkDescriptions.add(new DefaultLinkDescription(
diff --git a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/FlowRuleJuniperImpl.java b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/FlowRuleJuniperImpl.java
index cb07843..3f4adb6 100644
--- a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/FlowRuleJuniperImpl.java
+++ b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/FlowRuleJuniperImpl.java
@@ -381,7 +381,7 @@
         DeviceService deviceService = this.handler().get(DeviceService.class);
         //Using only links with adjacency discovered by the LLDP protocol (see LinkDiscoveryJuniperImpl)
         Map<DeviceId, Port> dstPorts = links.stream().filter(l ->
-                IP_STRING.toUpperCase().equals(l.annotations().value("layer")))
+                IP_STRING.toUpperCase().equals(l.annotations().value(AnnotationKeys.LAYER)))
                 .collect(Collectors.toMap(
                         l -> l.dst().deviceId(),
                         l -> deviceService.getPort(l.dst().deviceId(), l.dst().port())));
diff --git a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
index fca4697..d6a6f65 100644
--- a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
+++ b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/JuniperUtils.java
@@ -502,12 +502,37 @@
         ConnectPoint local = new ConnectPoint(localDevId, localPort.number());
         ConnectPoint remote = new ConnectPoint(remoteDevId, remotePort.number());
         DefaultAnnotations annotations = DefaultAnnotations.builder()
-                .set("layer", "IP")
+                .set(AnnotationKeys.LAYER, "ETHERNET")
                 .build();
         descs.add(new DefaultLinkDescription(
-                local, remote, Link.Type.INDIRECT, false, annotations));
+                local, remote, Link.Type.DIRECT, true, annotations));
         descs.add(new DefaultLinkDescription(
-                remote, local, Link.Type.INDIRECT, false, annotations));
+                remote, local, Link.Type.DIRECT, true, annotations));
+    }
+
+    /**
+     * Create one way LinkDescriptions.
+     *
+     * @param localDevId  the identity of the local device
+     * @param localPort   the port of the local device
+     * @param remoteDevId the identity of the remote device
+     * @param remotePort  the port of the remote device
+     * @param descs       the collection to which the link descriptions
+     *                    should be added
+     */
+    public static void createOneWayLinkDescription(DeviceId localDevId,
+                                                   Port localPort,
+                                                   DeviceId remoteDevId,
+                                                   Port remotePort,
+                                                   Set<LinkDescription> descs) {
+
+        ConnectPoint local = new ConnectPoint(localDevId, localPort.number());
+        ConnectPoint remote = new ConnectPoint(remoteDevId, remotePort.number());
+        DefaultAnnotations annotations = DefaultAnnotations.builder()
+                .set(AnnotationKeys.LAYER, "ETHERNET")
+                .build();
+        descs.add(new DefaultLinkDescription(
+                remote, local, Link.Type.DIRECT, true, annotations));
     }
 
     /**
diff --git a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/LinkDiscoveryJuniperImpl.java b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/LinkDiscoveryJuniperImpl.java
index 37e655a..e78779e 100644
--- a/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/LinkDiscoveryJuniperImpl.java
+++ b/drivers/juniper/src/main/java/org/onosproject/drivers/juniper/LinkDiscoveryJuniperImpl.java
@@ -136,12 +136,11 @@
                 continue;
             }
 
-            JuniperUtils.createBiDirLinkDescription(localDeviceId,
-                                                    localPort.get(),
-                                                    remoteDevice.id(),
-                                                    remotePort.get(),
-                                                    descriptions);
-
+            JuniperUtils.createOneWayLinkDescription(localDeviceId,
+                                                     localPort.get(),
+                                                     remoteDevice.id(),
+                                                     remotePort.get(),
+                                                     descriptions);
         }
         return descriptions;
     }
diff --git a/incubator/protobuf/models/BUILD b/incubator/protobuf/models/BUILD
new file mode 100644
index 0000000..a46e781
--- /dev/null
+++ b/incubator/protobuf/models/BUILD
@@ -0,0 +1,7 @@
+COMPILE_DEPS = CORE_DEPS + [
+    "//incubator/protobuf/models/proto:onos-incubator-protobuf-models-proto",
+]
+
+osgi_jar_with_tests(
+    deps = COMPILE_DEPS,
+)
diff --git a/incubator/protobuf/models/proto/BUILD b/incubator/protobuf/models/proto/BUILD
new file mode 100644
index 0000000..e0d5c37
--- /dev/null
+++ b/incubator/protobuf/models/proto/BUILD
@@ -0,0 +1,495 @@
+load("//tools/build/bazel:osgi_java_library.bzl", "osgi_proto_jar")
+
+PROTO_SOURCE_ROOT = "incubator/protobuf/models/proto"
+
+osgi_proto_jar(
+    proto_libs = [
+        ":ApplicationsEnums_proto",
+        ":ConfigPropertyEnums_proto",
+        ":ConfigProperty_proto",
+        ":NodeId_proto",
+        ":RoleInfo_proto",
+        ":ApplicationId_proto",
+        ":ApplicationProto_proto",
+        ":Version_proto",
+        ":DeviceDescription_proto",
+        ":DeviceEnums_proto",
+        ":DeviceEvent_proto",
+        ":PortDescription_proto",
+        ":PortEnums_proto",
+        ":PortStatistics_proto",
+        ":Criterion_proto",
+        ":Instruction_proto",
+        ":Instructions_proto",
+        ":FlowEntryEnums_proto",
+        ":FlowEntry_proto",
+        ":FlowRuleEnums_proto",
+        ":FlowRule_proto",
+        ":TraficSelector_proto",
+        ":TrafficTreatment_proto",
+        ":HostDescription_proto",
+        ":HostEnums_proto",
+        ":HostEvent_proto",
+        ":LinkDescription_proto",
+        ":LinkEnums_proto",
+        ":LinkEvent_proto",
+        ":BandEnums_proto",
+        ":Band_proto",
+        ":MeterEnums_proto",
+        ":MeterEvent_proto",
+        ":Meter_proto",
+        ":MeterRequest_proto",
+        ":OutboundPacket_proto",
+        ":PacketEnums_proto",
+        ":PacketEvent_proto",
+        ":PacketProcessorEntry_proto",
+        ":PacketProcessor_proto",
+        ":PacketRequest_proto",
+        ":RegionEnums_proto",
+        ":ConnectPoint_proto",
+        ":Device_proto",
+        ":DisjointPath_proto",
+        ":HostId_proto",
+        ":HostLocation_proto",
+        ":Host_proto",
+        ":Link_proto",
+        ":MastershipRole_proto",
+        ":Path_proto",
+        ":Port_proto",
+        ":ProviderId_proto",
+        ":Region_proto",
+        ":Permission_proto",
+    ],
+)
+
+### app ###
+proto_library(
+    name = "ApplicationsEnums_proto",
+    srcs = ["app/ApplicationEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+### cfg ###
+proto_library(
+    name = "ConfigPropertyEnums_proto",
+    srcs = ["cfg/ConfigPropertyEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "ConfigProperty_proto",
+    srcs = ["cfg/ConfigPropertyProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":ConfigPropertyEnums_proto"],
+)
+
+### cluster ###
+proto_library(
+    name = "NodeId_proto",
+    srcs = ["cluster/NodeIdProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "RoleInfo_proto",
+    srcs = ["cluster/RoleInfoProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":NodeId_proto"],
+)
+
+### core ###
+
+proto_library(
+    name = "ApplicationId_proto",
+    srcs = ["core/ApplicationIdProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "ApplicationProto_proto",
+    srcs = ["core/ApplicationProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":ApplicationId_proto",
+        ":ApplicationsEnums_proto",
+        ":Permission_proto",
+        ":Version_proto",
+    ],
+)
+
+proto_library(
+    name = "Version_proto",
+    srcs = ["core/VersionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+### net ###
+
+### device ###
+proto_library(
+    name = "DeviceDescription_proto",
+    srcs = ["net/device/DeviceDescriptionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":DeviceEnums_proto"],
+)
+
+proto_library(
+    name = "DeviceEnums_proto",
+    srcs = ["net/device/DeviceEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "DeviceEvent_proto",
+    srcs = ["net/device/DeviceEventProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":DeviceEnums_proto",
+        ":Device_proto",
+        ":Port_proto",
+    ],
+)
+
+proto_library(
+    name = "PortDescription_proto",
+    srcs = ["net/device/PortDescriptionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":PortEnums_proto"],
+)
+
+proto_library(
+    name = "PortEnums_proto",
+    srcs = ["net/device/PortEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "PortStatistics_proto",
+    srcs = ["net/device/PortStatisticsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+### flow ###
+## criteria ##
+proto_library(
+    name = "Criterion_proto",
+    srcs = ["net/flow/criteria/CriterionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+## instrcutions ##
+proto_library(
+    name = "Instruction_proto",
+    srcs = ["net/flow/instructions/InstructionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "Instructions_proto",
+    srcs = ["net/flow/instructions/InstructionsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "FlowEntryEnums_proto",
+    srcs = ["net/flow/FlowEntryEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "FlowEntry_proto",
+    srcs = ["net/flow/FlowEntryProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = ["FlowEntryEnums_proto"],
+)
+
+proto_library(
+    name = "FlowRuleEnums_proto",
+    srcs = ["net/flow/FlowRuleEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "FlowRule_proto",
+    srcs = ["net/flow/FlowRuleProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":FlowRuleEnums_proto",
+        ":TrafficTreatment_proto",
+        ":TraficSelector_proto",
+    ],
+)
+
+proto_library(
+    name = "TraficSelector_proto",
+    srcs = ["net/flow/TrafficSelectorProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":Criterion_proto"],
+)
+
+proto_library(
+    name = "TrafficTreatment_proto",
+    srcs = ["net/flow/TrafficTreatmentProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        "Instruction_proto",
+        ":Instructions_proto",
+    ],
+)
+
+#### host ####
+
+proto_library(
+    name = "HostDescription_proto",
+    srcs = ["net/host/HostDescriptionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":HostLocation_proto"],
+)
+
+proto_library(
+    name = "HostEnums_proto",
+    srcs = ["net/host/HostEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "HostEvent_proto",
+    srcs = ["net/host/HostEventProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":HostEnums_proto",
+        ":Host_proto",
+    ],
+)
+
+#### link ####
+
+proto_library(
+    name = "LinkDescription_proto",
+    srcs = ["net/link/LinkDescriptionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":ConnectPoint_proto",
+        ":LinkEnums_proto",
+    ],
+)
+
+proto_library(
+    name = "LinkEnums_proto",
+    srcs = ["net/link/LinkEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "LinkEvent_proto",
+    srcs = ["net/link/LinkEventProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":LinkEnums_proto",
+        ":Link_proto",
+    ],
+)
+
+### meter ####
+
+proto_library(
+    name = "BandEnums_proto",
+    srcs = ["net/meter/BandEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "Band_proto",
+    srcs = ["net/meter/BandProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":BandEnums_proto"],
+)
+
+proto_library(
+    name = "MeterEnums_proto",
+    srcs = ["net/meter/MeterEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "MeterEvent_proto",
+    srcs = ["net/meter/MeterEventProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":MeterEnums_proto",
+        ":Meter_proto",
+    ],
+)
+
+proto_library(
+    name = "Meter_proto",
+    srcs = ["net/meter/MeterProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        "MeterEnums_proto",
+        ":ApplicationId_proto",
+        ":Band_proto",
+    ],
+)
+
+proto_library(
+    name = "MeterRequest_proto",
+    srcs = ["net/meter/MeterRequestProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":ApplicationId_proto",
+        ":Band_proto",
+        ":MeterEnums_proto",
+    ],
+)
+
+### packet ####
+
+proto_library(
+    name = "OutboundPacket_proto",
+    srcs = ["net/packet/OutboundPacketProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":TrafficTreatment_proto"],
+)
+
+proto_library(
+    name = "PacketEnums_proto",
+    srcs = ["net/packet/PacketEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "PacketEvent_proto",
+    srcs = ["net/packet/PacketEventProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":OutboundPacket_proto",
+        ":PacketEnums_proto",
+    ],
+)
+
+proto_library(
+    name = "PacketProcessorEntry_proto",
+    srcs = ["net/packet/PacketProcessorEntryProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":PacketProcessor_proto"],
+)
+
+proto_library(
+    name = "PacketProcessor_proto",
+    srcs = ["net/packet/PacketProcessorProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "PacketRequest_proto",
+    srcs = ["net/packet/PacketRequestProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":ApplicationId_proto",
+        ":NodeId_proto",
+        ":TraficSelector_proto",
+    ],
+)
+
+#### region ####
+
+proto_library(
+    name = "RegionEnums_proto",
+    srcs = ["net/region/RegionEnumsProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "ConnectPoint_proto",
+    srcs = ["net/ConnectPointProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "Device_proto",
+    srcs = ["net/DeviceProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":DeviceEnums_proto"],
+)
+
+proto_library(
+    name = "DisjointPath_proto",
+    srcs = ["net/DisjointPathProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":Path_proto"],
+)
+
+proto_library(
+    name = "HostId_proto",
+    srcs = ["net/HostIdProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "HostLocation_proto",
+    srcs = ["net/HostLocationProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":ConnectPoint_proto"],
+)
+
+proto_library(
+    name = "Host_proto",
+    srcs = ["net/HostProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":HostId_proto",
+        ":HostLocation_proto",
+        ":ProviderId_proto",
+    ],
+)
+
+proto_library(
+    name = "Link_proto",
+    srcs = ["net/LinkProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [
+        ":ConnectPoint_proto",
+        ":LinkEnums_proto",
+        ":ProviderId_proto",
+    ],
+)
+
+proto_library(
+    name = "MastershipRole_proto",
+    srcs = ["net/MastershipRoleProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "Path_proto",
+    srcs = ["net/PathProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":Link_proto"],
+)
+
+proto_library(
+    name = "Port_proto",
+    srcs = ["net/PortProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":PortEnums_proto"],
+)
+
+proto_library(
+    name = "ProviderId_proto",
+    srcs = ["net/ProviderIdProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
+
+proto_library(
+    name = "Region_proto",
+    srcs = ["net/RegionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+    deps = [":RegionEnums_proto"],
+)
+
+proto_library(
+    name = "Permission_proto",
+    srcs = ["security/PermissionProto.proto"],
+    proto_source_root = PROTO_SOURCE_ROOT,
+)
diff --git a/incubator/protobuf/models/src/main/proto/app/ApplicationEnumsProto.proto b/incubator/protobuf/models/proto/app/ApplicationEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/app/ApplicationEnumsProto.proto
rename to incubator/protobuf/models/proto/app/ApplicationEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/cfg/ConfigPropertyEnumsProto.proto b/incubator/protobuf/models/proto/cfg/ConfigPropertyEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/cfg/ConfigPropertyEnumsProto.proto
rename to incubator/protobuf/models/proto/cfg/ConfigPropertyEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/cfg/ConfigPropertyProto.proto b/incubator/protobuf/models/proto/cfg/ConfigPropertyProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/cfg/ConfigPropertyProto.proto
rename to incubator/protobuf/models/proto/cfg/ConfigPropertyProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/cluster/NodeIdProto.proto b/incubator/protobuf/models/proto/cluster/NodeIdProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/cluster/NodeIdProto.proto
rename to incubator/protobuf/models/proto/cluster/NodeIdProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/cluster/RoleInfoProto.proto b/incubator/protobuf/models/proto/cluster/RoleInfoProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/cluster/RoleInfoProto.proto
rename to incubator/protobuf/models/proto/cluster/RoleInfoProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/core/ApplicationIdProto.proto b/incubator/protobuf/models/proto/core/ApplicationIdProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/core/ApplicationIdProto.proto
rename to incubator/protobuf/models/proto/core/ApplicationIdProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/core/ApplicationProto.proto b/incubator/protobuf/models/proto/core/ApplicationProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/core/ApplicationProto.proto
rename to incubator/protobuf/models/proto/core/ApplicationProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/core/VersionProto.proto b/incubator/protobuf/models/proto/core/VersionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/core/VersionProto.proto
rename to incubator/protobuf/models/proto/core/VersionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/ConnectPointProto.proto b/incubator/protobuf/models/proto/net/ConnectPointProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/ConnectPointProto.proto
rename to incubator/protobuf/models/proto/net/ConnectPointProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/DeviceProto.proto b/incubator/protobuf/models/proto/net/DeviceProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/DeviceProto.proto
rename to incubator/protobuf/models/proto/net/DeviceProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/DisjointPathProto.proto b/incubator/protobuf/models/proto/net/DisjointPathProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/DisjointPathProto.proto
rename to incubator/protobuf/models/proto/net/DisjointPathProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/HostIdProto.proto b/incubator/protobuf/models/proto/net/HostIdProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/HostIdProto.proto
rename to incubator/protobuf/models/proto/net/HostIdProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/HostLocationProto.proto b/incubator/protobuf/models/proto/net/HostLocationProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/HostLocationProto.proto
rename to incubator/protobuf/models/proto/net/HostLocationProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/HostProto.proto b/incubator/protobuf/models/proto/net/HostProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/HostProto.proto
rename to incubator/protobuf/models/proto/net/HostProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/LinkProto.proto b/incubator/protobuf/models/proto/net/LinkProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/LinkProto.proto
rename to incubator/protobuf/models/proto/net/LinkProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/MastershipRoleProto.proto b/incubator/protobuf/models/proto/net/MastershipRoleProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/MastershipRoleProto.proto
rename to incubator/protobuf/models/proto/net/MastershipRoleProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/PathProto.proto b/incubator/protobuf/models/proto/net/PathProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/PathProto.proto
rename to incubator/protobuf/models/proto/net/PathProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/PortProto.proto b/incubator/protobuf/models/proto/net/PortProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/PortProto.proto
rename to incubator/protobuf/models/proto/net/PortProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/ProviderIdProto.proto b/incubator/protobuf/models/proto/net/ProviderIdProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/ProviderIdProto.proto
rename to incubator/protobuf/models/proto/net/ProviderIdProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/RegionProto.proto b/incubator/protobuf/models/proto/net/RegionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/RegionProto.proto
rename to incubator/protobuf/models/proto/net/RegionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/device/DeviceDescriptionProto.proto b/incubator/protobuf/models/proto/net/device/DeviceDescriptionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/device/DeviceDescriptionProto.proto
rename to incubator/protobuf/models/proto/net/device/DeviceDescriptionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/device/DeviceEnumsProto.proto b/incubator/protobuf/models/proto/net/device/DeviceEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/device/DeviceEnumsProto.proto
rename to incubator/protobuf/models/proto/net/device/DeviceEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/device/DeviceEventProto.proto b/incubator/protobuf/models/proto/net/device/DeviceEventProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/device/DeviceEventProto.proto
rename to incubator/protobuf/models/proto/net/device/DeviceEventProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/device/PortDescriptionProto.proto b/incubator/protobuf/models/proto/net/device/PortDescriptionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/device/PortDescriptionProto.proto
rename to incubator/protobuf/models/proto/net/device/PortDescriptionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/device/PortEnumsProto.proto b/incubator/protobuf/models/proto/net/device/PortEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/device/PortEnumsProto.proto
rename to incubator/protobuf/models/proto/net/device/PortEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/device/PortStatisticsProto.proto b/incubator/protobuf/models/proto/net/device/PortStatisticsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/device/PortStatisticsProto.proto
rename to incubator/protobuf/models/proto/net/device/PortStatisticsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryEnumsProto.proto b/incubator/protobuf/models/proto/net/flow/FlowEntryEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/FlowEntryEnumsProto.proto
rename to incubator/protobuf/models/proto/net/flow/FlowEntryEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/FlowEntryProto.proto b/incubator/protobuf/models/proto/net/flow/FlowEntryProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/FlowEntryProto.proto
rename to incubator/protobuf/models/proto/net/flow/FlowEntryProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/FlowRuleEnumsProto.proto b/incubator/protobuf/models/proto/net/flow/FlowRuleEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/FlowRuleEnumsProto.proto
rename to incubator/protobuf/models/proto/net/flow/FlowRuleEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/FlowRuleProto.proto b/incubator/protobuf/models/proto/net/flow/FlowRuleProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/FlowRuleProto.proto
rename to incubator/protobuf/models/proto/net/flow/FlowRuleProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/TrafficSelectorProto.proto b/incubator/protobuf/models/proto/net/flow/TrafficSelectorProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/TrafficSelectorProto.proto
rename to incubator/protobuf/models/proto/net/flow/TrafficSelectorProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/TrafficTreatmentProto.proto b/incubator/protobuf/models/proto/net/flow/TrafficTreatmentProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/TrafficTreatmentProto.proto
rename to incubator/protobuf/models/proto/net/flow/TrafficTreatmentProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/criteria/CriterionProto.proto b/incubator/protobuf/models/proto/net/flow/criteria/CriterionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/criteria/CriterionProto.proto
rename to incubator/protobuf/models/proto/net/flow/criteria/CriterionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/instructions/InstructionProto.proto b/incubator/protobuf/models/proto/net/flow/instructions/InstructionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/instructions/InstructionProto.proto
rename to incubator/protobuf/models/proto/net/flow/instructions/InstructionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/flow/instructions/InstructionsProto.proto b/incubator/protobuf/models/proto/net/flow/instructions/InstructionsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/flow/instructions/InstructionsProto.proto
rename to incubator/protobuf/models/proto/net/flow/instructions/InstructionsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/host/HostDescriptionProto.proto b/incubator/protobuf/models/proto/net/host/HostDescriptionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/host/HostDescriptionProto.proto
rename to incubator/protobuf/models/proto/net/host/HostDescriptionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/host/HostEnumsProto.proto b/incubator/protobuf/models/proto/net/host/HostEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/host/HostEnumsProto.proto
rename to incubator/protobuf/models/proto/net/host/HostEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/host/HostEventProto.proto b/incubator/protobuf/models/proto/net/host/HostEventProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/host/HostEventProto.proto
rename to incubator/protobuf/models/proto/net/host/HostEventProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/link/LinkDescriptionProto.proto b/incubator/protobuf/models/proto/net/link/LinkDescriptionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/link/LinkDescriptionProto.proto
rename to incubator/protobuf/models/proto/net/link/LinkDescriptionProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/link/LinkEnumsProto.proto b/incubator/protobuf/models/proto/net/link/LinkEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/link/LinkEnumsProto.proto
rename to incubator/protobuf/models/proto/net/link/LinkEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/link/LinkEventProto.proto b/incubator/protobuf/models/proto/net/link/LinkEventProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/link/LinkEventProto.proto
rename to incubator/protobuf/models/proto/net/link/LinkEventProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/meter/BandEnumsProto.proto b/incubator/protobuf/models/proto/net/meter/BandEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/meter/BandEnumsProto.proto
rename to incubator/protobuf/models/proto/net/meter/BandEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/meter/BandProto.proto b/incubator/protobuf/models/proto/net/meter/BandProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/meter/BandProto.proto
rename to incubator/protobuf/models/proto/net/meter/BandProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/meter/MeterEnumsProto.proto b/incubator/protobuf/models/proto/net/meter/MeterEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/meter/MeterEnumsProto.proto
rename to incubator/protobuf/models/proto/net/meter/MeterEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/meter/MeterEventProto.proto b/incubator/protobuf/models/proto/net/meter/MeterEventProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/meter/MeterEventProto.proto
rename to incubator/protobuf/models/proto/net/meter/MeterEventProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/meter/MeterProto.proto b/incubator/protobuf/models/proto/net/meter/MeterProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/meter/MeterProto.proto
rename to incubator/protobuf/models/proto/net/meter/MeterProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/meter/MeterRequestProto.proto b/incubator/protobuf/models/proto/net/meter/MeterRequestProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/meter/MeterRequestProto.proto
rename to incubator/protobuf/models/proto/net/meter/MeterRequestProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/packet/OutboundPacketProto.proto b/incubator/protobuf/models/proto/net/packet/OutboundPacketProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/packet/OutboundPacketProto.proto
rename to incubator/protobuf/models/proto/net/packet/OutboundPacketProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/packet/PacketEnumsProto.proto b/incubator/protobuf/models/proto/net/packet/PacketEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/packet/PacketEnumsProto.proto
rename to incubator/protobuf/models/proto/net/packet/PacketEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/packet/PacketEventProto.proto b/incubator/protobuf/models/proto/net/packet/PacketEventProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/packet/PacketEventProto.proto
rename to incubator/protobuf/models/proto/net/packet/PacketEventProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/packet/PacketProcessorEntryProto.proto b/incubator/protobuf/models/proto/net/packet/PacketProcessorEntryProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/packet/PacketProcessorEntryProto.proto
rename to incubator/protobuf/models/proto/net/packet/PacketProcessorEntryProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/packet/PacketProcessorProto.proto b/incubator/protobuf/models/proto/net/packet/PacketProcessorProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/packet/PacketProcessorProto.proto
rename to incubator/protobuf/models/proto/net/packet/PacketProcessorProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/packet/PacketRequestProto.proto b/incubator/protobuf/models/proto/net/packet/PacketRequestProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/packet/PacketRequestProto.proto
rename to incubator/protobuf/models/proto/net/packet/PacketRequestProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/net/region/RegionEnumsProto.proto b/incubator/protobuf/models/proto/net/region/RegionEnumsProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/net/region/RegionEnumsProto.proto
rename to incubator/protobuf/models/proto/net/region/RegionEnumsProto.proto
diff --git a/incubator/protobuf/models/src/main/proto/security/PermissionProto.proto b/incubator/protobuf/models/proto/security/PermissionProto.proto
similarity index 100%
rename from incubator/protobuf/models/src/main/proto/security/PermissionProto.proto
rename to incubator/protobuf/models/proto/security/PermissionProto.proto
diff --git a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/cluster/RoleInfoProtoTranslator.java b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/cluster/RoleInfoProtoTranslator.java
index ddea094..d879a08 100644
--- a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/cluster/RoleInfoProtoTranslator.java
+++ b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/cluster/RoleInfoProtoTranslator.java
@@ -38,7 +38,7 @@
         NodeId master = NodeIdProtoTranslator.translate(roleInfo.getMaster());
 
         List<NodeId> backups = Lists.newArrayList();
-        roleInfo.getBackupsList().stream().map(r ->
+        backups = roleInfo.getBackupsList().stream().map(r ->
                 NodeIdProtoTranslator.translate(r)).collect(Collectors.toList());
         return new RoleInfo(master, backups);
     }
diff --git a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/LinkProtoTranslator.java b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/LinkProtoTranslator.java
index fd139da..770d835 100644
--- a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/LinkProtoTranslator.java
+++ b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/LinkProtoTranslator.java
@@ -15,8 +15,8 @@
  */
 package org.onosproject.incubator.protobuf.models.net;
 
-import org.onosproject.grpc.net.models.LinkProtoOuterClass;
 import org.onosproject.incubator.protobuf.models.net.link.LinkEnumsProtoTranslator;
+import org.onosproject.grpc.net.models.LinkProtoOuterClass;
 import org.onosproject.net.Annotations;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultAnnotations;
diff --git a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/RegionProtoTranslator.java b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/RegionProtoTranslator.java
index 7512ebf..f426982 100644
--- a/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/RegionProtoTranslator.java
+++ b/incubator/protobuf/models/src/main/java/org/onosproject/incubator/protobuf/models/net/RegionProtoTranslator.java
@@ -16,9 +16,9 @@
 package org.onosproject.incubator.protobuf.models.net;
 
 import com.google.common.base.Strings;
+import org.onosproject.incubator.protobuf.models.net.region.RegionEnumsProtoTranslator;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.grpc.net.models.RegionProtoOuterClass;
-import org.onosproject.incubator.protobuf.models.net.region.RegionEnumsProtoTranslator;
 import org.onosproject.net.Annotations;
 import org.onosproject.net.region.DefaultRegion;
 import org.onosproject.net.region.Region;
diff --git a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java
index 6849119..8be22f9 100644
--- a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java
+++ b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java
@@ -788,6 +788,11 @@
         }
 
         @Override
+        public void setTtl(LinkKey key, short ttl) {
+            linkTimes.put(key, System.currentTimeMillis() - staleLinkAge + SECONDS.toMillis(ttl));
+        }
+
+        @Override
         public DeviceService deviceService() {
             return deviceService;
         }
diff --git a/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscovery.java b/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscovery.java
index 33e5f4d..bea59ee 100644
--- a/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscovery.java
+++ b/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscovery.java
@@ -25,13 +25,18 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.ONOSLLDP;
 import org.onlab.util.Timer;
+import org.onlab.util.Tools;
+import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultPort;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link.Type;
 import org.onosproject.net.LinkKey;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.link.DefaultLinkDescription;
 import org.onosproject.net.link.LinkDescription;
 import org.onosproject.net.link.ProbedLinkProvider;
@@ -42,6 +47,10 @@
 
 import java.nio.ByteBuffer;
 import java.util.Map;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
@@ -59,6 +68,9 @@
  */
 public class LinkDiscovery implements TimerTask {
 
+    private static final String SCHEME_NAME = "linkdiscovery";
+    private static final String ETHERNET = "ETHERNET";
+
     private final Logger log = getLogger(getClass());
 
     private final Device device;
@@ -166,6 +178,27 @@
             return false;
         }
 
+        if (processOnosLldp(packetContext, eth)) {
+            return true;
+        }
+
+        if (processLldp(packetContext, eth)) {
+            return true;
+        }
+
+        ONOSLLDP lldp = ONOSLLDP.parseLLDP(eth);
+
+        if (lldp == null) {
+            log.debug("Cannot parse the packet. It seems that it is not the lldp or bsn packet.");
+        } else {
+            log.debug("LLDP packet is dropped due to there are no handlers that properly handle this packet: {}",
+                    lldp.toString());
+        }
+
+        return false;
+    }
+
+    private boolean processOnosLldp(PacketContext packetContext, Ethernet eth) {
         ONOSLLDP onoslldp = ONOSLLDP.parseONOSLLDP(eth);
         if (onoslldp != null) {
             Type lt;
@@ -198,6 +231,7 @@
                     context.providerService().linkDetected(ld);
                     context.touchLink(LinkKey.linkKey(src, dst));
                 } catch (IllegalStateException e) {
+                    log.debug("There is a exception during link creation: {}", e);
                     return true;
                 }
                 return true;
@@ -206,6 +240,114 @@
         return false;
     }
 
+    private boolean processLldp(PacketContext packetContext, Ethernet eth) {
+        ONOSLLDP onoslldp = ONOSLLDP.parseLLDP(eth);
+        if (onoslldp != null) {
+            Type lt = eth.getEtherType() == Ethernet.TYPE_LLDP ?
+                    Type.DIRECT : Type.INDIRECT;
+
+            DeviceService deviceService = context.deviceService();
+            MacAddress srcChassisId = onoslldp.getChassisIdByMac();
+            String srcPortName = onoslldp.getPortNameString();
+            String srcPortDesc = onoslldp.getPortDescString();
+
+            log.debug("srcChassisId:{}, srcPortName:{}, srcPortDesc:{}", srcChassisId, srcPortName, srcPortDesc);
+
+            if (srcChassisId == null && srcPortDesc == null) {
+                log.warn("there are no valid port id");
+                return false;
+            }
+
+            Optional<Device> srcDevice = findSourceDeviceByChassisId(deviceService, srcChassisId);
+
+            if (!srcDevice.isPresent()) {
+                log.warn("source device not found. srcChassisId value: {}", srcChassisId);
+                return false;
+            }
+            Optional<Port> sourcePort = findSourcePortByName(
+                    srcPortName == null ? srcPortDesc : srcPortName,
+                    deviceService,
+                    srcDevice.get());
+
+            if (!sourcePort.isPresent()) {
+                log.warn("source port not found. sourcePort value: {}", sourcePort);
+                return false;
+            }
+
+            PortNumber srcPort = sourcePort.get().number();
+            PortNumber dstPort = packetContext.inPacket().receivedFrom().port();
+
+            DeviceId srcDeviceId = srcDevice.get().id();
+            DeviceId dstDeviceId = packetContext.inPacket().receivedFrom().deviceId();
+
+            ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort);
+            ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort);
+
+            DefaultAnnotations annotations = DefaultAnnotations.builder()
+                    .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
+                    .set(AnnotationKeys.LAYER, ETHERNET)
+                    .build();
+
+            LinkDescription ld = new DefaultLinkDescription(src, dst, lt, true, annotations);
+            try {
+                context.providerService().linkDetected(ld);
+                context.setTtl(LinkKey.linkKey(src, dst), onoslldp.getTtlBySeconds());
+            } catch (IllegalStateException e) {
+                log.debug("There is a exception during link creation: {}", e);
+                return true;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private Optional<Device> findSourceDeviceByChassisId(DeviceService deviceService, MacAddress srcChassisId) {
+        Supplier<Stream<Device>> deviceStream = () ->
+                StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false);
+        Optional<Device> remoteDeviceOptional = deviceStream.get()
+                .filter(device -> device.chassisId() != null
+                        && MacAddress.valueOf(device.chassisId().value()).equals(srcChassisId))
+                .findAny();
+
+        if (remoteDeviceOptional.isPresent()) {
+            log.debug("sourceDevice found by chassis id: {}", srcChassisId);
+            return remoteDeviceOptional;
+        } else {
+            remoteDeviceOptional = deviceStream.get().filter(device ->
+                    Tools.stream(deviceService.getPorts(device.id()))
+                            .anyMatch(port -> port.annotations().keys().contains(AnnotationKeys.PORT_MAC)
+                                    && MacAddress.valueOf(port.annotations().value(AnnotationKeys.PORT_MAC))
+                                    .equals(srcChassisId)))
+                    .findAny();
+            if (remoteDeviceOptional.isPresent()) {
+                log.debug("sourceDevice found by port mac: {}", srcChassisId);
+                return remoteDeviceOptional;
+            } else {
+                return Optional.empty();
+            }
+        }
+    }
+
+    private Optional<Port> findSourcePortByName(String remotePortName,
+                                                DeviceService deviceService,
+                                                Device remoteDevice) {
+        Optional<Port> remotePort = deviceService.getPorts(remoteDevice.id())
+                .stream().filter(port -> remotePortName.equals(port.annotations().value(AnnotationKeys.PORT_NAME)))
+                .findAny();
+
+        if (remotePort.isPresent()) {
+            return remotePort;
+        } else {
+            int portNumber = Integer.parseInt(remotePortName.replaceAll("\\D+", ""));
+            DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
+                    .set(AnnotationKeys.PORT_NAME, remotePortName);
+
+            return Optional.of(new DefaultPort(remoteDevice, PortNumber.portNumber(portNumber),
+                    true,
+                    annotations.build()));
+        }
+    }
+
     // true if *NOT* this cluster's own probe.
     private boolean notMy(String mac) {
         // if we are using DEFAULT_MAC, clustering hadn't initialized, so conservative 'yes'
diff --git a/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscoveryContext.java b/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscoveryContext.java
index a325b95..056e3e7 100644
--- a/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscoveryContext.java
+++ b/providers/lldpcommon/src/main/java/org/onosproject/provider/lldpcommon/LinkDiscoveryContext.java
@@ -76,6 +76,14 @@
     void touchLink(LinkKey key);
 
     /**
+     * Set the TTL to the link identified by the given key to indicate that it's active.
+     *
+     * @param key link key
+     * @param ttl ttl value(seconds)
+     */
+    void setTtl(LinkKey key, short ttl);
+
+    /**
      * Returns the cluster-wide unique identifier.
      *
      * @return the cluster identifier
diff --git a/providers/netcfglinks/src/main/java/org/onosproject/provider/netcfglinks/NetworkConfigLinksProvider.java b/providers/netcfglinks/src/main/java/org/onosproject/provider/netcfglinks/NetworkConfigLinksProvider.java
index ac00cf8..8bd4c41 100644
--- a/providers/netcfglinks/src/main/java/org/onosproject/provider/netcfglinks/NetworkConfigLinksProvider.java
+++ b/providers/netcfglinks/src/main/java/org/onosproject/provider/netcfglinks/NetworkConfigLinksProvider.java
@@ -264,6 +264,10 @@
         }
 
         @Override
+        public void setTtl(LinkKey key, short ttl) {
+        }
+
+        @Override
         public String fingerprint() {
             return buildSrcMac();
         }
diff --git a/tools/build/bazel/modules.bzl b/tools/build/bazel/modules.bzl
index 26a5da4..dfa5cfe 100644
--- a/tools/build/bazel/modules.bzl
+++ b/tools/build/bazel/modules.bzl
@@ -77,7 +77,8 @@
     "//web/api:onos-rest",
     # "//web/gui2:onos-gui2",
     "//web/gui:onos-gui",
-    # "//incubator/protobuf/models:onos-incubator-protobuf-models",
+    "//incubator/protobuf/models/proto:onos-incubator-protobuf-models-proto",
+    "//incubator/protobuf/models:onos-incubator-protobuf-models",
     # "//incubator/protobuf/services/nb:onos-incubator-protobuf-services-nb",
 ]
 
@@ -241,7 +242,7 @@
     "//apps/powermanagement:onos-apps-powermanagement-oar",
     "//apps/t3:onos-apps-t3-oar",
     "//apps/simplefabric:onos-apps-simplefabric-oar",
-    # "//apps/kafka-integration:onos-apps-kafka-integration-oar",
+    #"//apps/kafka-integration:onos-apps-kafka-integration-oar",
     "//apps/rabbitmq:onos-apps-rabbitmq-oar",
     "//apps/odtn/api:onos-apps-odtn-api-oar",
     "//apps/odtn/service:onos-apps-odtn-service-oar",
@@ -297,8 +298,8 @@
     "//apps/vtn/sfcmgr:onos-apps-vtn-sfcmgr",
     "//apps/vtn/vtnmgr:onos-apps-vtn-vtnmgr",
     "//apps/vtn/vtnweb:onos-apps-vtn-vtnweb",
-    "//apps/kafka-integration/api:onos-apps-kafka-integration-api",
-    # "//apps/kafka-integration/app:onos-apps-kafka-integration-app",
+    #"//apps/kafka-integration/api:onos-apps-kafka-integration-api",
+    #"//apps/kafka-integration/app:onos-apps-kafka-integration-app",
 ]
 
 FEATURES = [
diff --git a/tools/dev/mininet/onos.py b/tools/dev/mininet/onos.py
index c656a05..15232ac 100755
--- a/tools/dev/mininet/onos.py
+++ b/tools/dev/mininet/onos.py
@@ -127,7 +127,7 @@
     return env
 
 
-tarDefaultPath = 'buck-out/gen/tools/package/onos-package/onos.tar.gz'
+tarDefaultPath = "bazel-out/k8-fastbuild/bin/onos.tar.gz"
 
 def unpackONOS( destDir='/tmp', run=quietRun ):
     "Unpack ONOS and return its location"
@@ -280,7 +280,7 @@
         self.cmd( 'export PATH=%s:%s:$PATH' % ( onosbin, karafbin ) )
         self.cmd( 'cd', self.ONOS_HOME )
         self.ucmd( 'mkdir -p config && '
-                   'onos-gen-partitions config/cluster.json',
+                   'onos-gen-default-cluster  config/cluster.json --nodes ',
                    ' '.join( node.IP() for node in nodes ) )
 
     def intfsDown( self ):
@@ -397,6 +397,11 @@
                       ( self.IP(), self.IP(), CopycatPort )
             if nodeStr in result:
                 break
+
+			# just break if state is active 
+            if "state=ACTIVE" in result:
+                break
+
             info( '.' )
             self.sanityCheck()
             time.sleep( 1 )
diff --git a/tools/test/bin/onos-gen-default-cluster b/tools/test/bin/onos-gen-default-cluster
new file mode 100755
index 0000000..e557eda
--- /dev/null
+++ b/tools/test/bin/onos-gen-default-cluster
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+"""
+usage: onos-gen-default-cluster [-h] [-s PARTITION_SIZE] [-n NUM_PARTITIONS]
+                            [filename] [node_ip [node_ip ...]]
+
+Generate the partitions json file given a list of IPs or from the $OCC*
+environment variables.
+
+positional arguments:
+  filename              File to write output to. If none is provided, output
+                        is written to stdout.
+  node_ip               IP Address(es) of the node(s) in the cluster. If no
+                        IPs are given, will use the $OC* environment
+                        variables. NOTE: these arguments are only processed
+                        after the filename argument.
+
+optional arguments:
+  -h, --help            show this help message and exit
+"""
+
+from os import environ
+import argparse
+import re
+import json
+
+convert = lambda text: int(text) if text.isdigit() else text.lower()
+alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
+
+
+def get_vars_by_type(type):
+    vars = []
+    for var in environ:
+        if re.match(r"{}[0-9]+".format(type), var):
+            vars.append(var)
+    return sorted(vars, key=alphanum_key)
+
+
+def get_vars():
+    vars = get_vars_by_type('OCC')
+    if len(vars) == 0:
+        vars = get_vars_by_type('OC')
+    return vars
+
+
+def get_nodes(ips=None, default_port=9876):
+    node = lambda id, ip, port: {'id': id, 'ip': ip, 'port': port}
+    result = []
+    if not ips:
+        ips = [environ[v] for v in get_vars()]
+    i = 1
+    for ip_string in ips:
+        address_tuple = ip_string.split(":")
+        if len(address_tuple) == 3:
+            id = address_tuple[0]
+            ip = address_tuple[1]
+            port = int(address_tuple[2])
+        else:
+            i += 1
+            ip = ip_string
+            id = ip
+            port = default_port
+        result.append(node(id, ip, port))
+    return result
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description="Generate the partitions json file given a list of IPs or from environment variables.")
+   
+    parser.add_argument(
+        'filename', metavar='filename', type=str, nargs='?',
+        help='File to write output to. If none is provided, output is written to stdout.')
+
+    parser.add_argument(
+        '--nodes', '-n', metavar='node_ip', type=str, nargs='+',
+        help='IP Address(es) of the storage nodes. If no IPs are given, ' +
+             'will use the $OCC* or $OC* environment variables. NOTE: these arguments' +
+             ' are only processed after the filename argument.')
+
+    args = parser.parse_args()
+    filename = args.filename
+    nodes = get_nodes(args.nodes)
+
+    data = {
+        'name': 'onos',
+        'controller': nodes
+    }
+    output = json.dumps(data, indent=4)
+
+    if filename:
+        with open(filename, 'w') as f:
+            f.write(output)
+    else:
+        print output
diff --git a/utils/misc/src/main/java/org/onlab/packet/LLDP.java b/utils/misc/src/main/java/org/onlab/packet/LLDP.java
index 33b1f85..e555f1f 100644
--- a/utils/misc/src/main/java/org/onlab/packet/LLDP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/LLDP.java
@@ -37,8 +37,16 @@
 
     public static final byte PORT_TLV_TYPE = 2;
     public static final short PORT_TLV_SIZE = 5;
+
+    /**
+     * @deprecated since 1.15. Use the PORT_TLV_COMPONENT_SUBTYPE instead of PORT_TLV_SUBTYPE.
+     */
+    @Deprecated
     public static final byte PORT_TLV_SUBTYPE = 2;
 
+    public static final byte PORT_TLV_COMPONENT_SUBTYPE = PORT_TLV_SUBTYPE;
+    public static final byte PORT_TLV_INTERFACE_NAME_SUBTYPE = 5;
+
     public static final byte TTL_TLV_TYPE = 3;
     public static final short TTL_TLV_SIZE = 2;
 
diff --git a/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java b/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java
index f0b981c..7405bbf 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
@@ -31,16 +32,18 @@
 
 import static org.onlab.packet.LLDPOrganizationalTLV.OUI_LENGTH;
 import static org.onlab.packet.LLDPOrganizationalTLV.SUBTYPE_LENGTH;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  *  ONOS LLDP containing organizational TLV for ONOS device discovery.
  */
 public class ONOSLLDP extends LLDP {
 
+    private static final Logger log = getLogger(ONOSLLDP.class);
+
     public static final String DEFAULT_DEVICE = "INVALID";
     public static final String DEFAULT_NAME = "ONOS Discovery";
 
-
     protected static final byte NAME_SUBTYPE = 1;
     protected static final byte DEVICE_SUBTYPE = 2;
     protected static final byte DOMAIN_SUBTYPE = 3;
@@ -62,11 +65,7 @@
     private static final byte CHASSIS_TLV_SIZE = 7;
     private static final byte CHASSIS_TLV_SUBTYPE = 4;
 
-    private static final byte PORT_TLV_TYPE = 2;
-    private static final byte PORT_TLV_SUBTYPE = 2;
-
     private static final byte TTL_TLV_TYPE = 3;
-
     private static final byte PORT_DESC_TLV_TYPE = 4;
 
     private final byte[] ttlValue = new byte[] {0, 0x78};
@@ -137,7 +136,7 @@
     }
 
     public void setPortId(final int portNumber) {
-        byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_SUBTYPE},
+        byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_COMPONENT_SUBTYPE},
                 String.valueOf(portNumber).getBytes(StandardCharsets.UTF_8));
 
         LLDPTLV portTLV = new LLDPTLV();
@@ -147,6 +146,17 @@
         this.setPortId(portTLV);
     }
 
+    public void setPortName(final String portName) {
+        byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_INTERFACE_NAME_SUBTYPE},
+                portName.getBytes(StandardCharsets.UTF_8));
+
+        LLDPTLV portTLV = new LLDPTLV();
+        portTLV.setLength((short) port.length);
+        portTLV.setType(PORT_TLV_TYPE);
+        portTLV.setValue(port);
+        this.setPortId(portTLV);
+    }
+
     public void setTimestamp(long timestamp) {
         LLDPOrganizationalTLV tmtlv = opttlvs.get(TIMESTAMP_SUBTYPE);
         if (tmtlv == null) {
@@ -235,6 +245,17 @@
         return null;
     }
 
+    public LLDPTLV getPortDescTLV() {
+        for (LLDPTLV tlv : this.getOptionalTLVList()) {
+            if (tlv.getType() == PORT_DESC_TLV_TYPE) {
+                return tlv;
+            }
+        }
+
+        log.error("Cannot find the port description tlv type.");
+        return null;
+    }
+
     public String getNameString() {
         LLDPOrganizationalTLV tlv = getNameTLV();
         if (tlv != null) {
@@ -259,12 +280,57 @@
         return null;
     }
 
+    public String getPortDescString() {
+        LLDPTLV tlv = getPortDescTLV();
+        if (tlv != null) {
+            return new String(tlv.getValue(), StandardCharsets.UTF_8);
+        }
+        return null;
+    }
+
     public Integer getPort() {
         ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
-        portBB.position(1);
+        byte type = portBB.get();
 
-        return Integer.parseInt(new String(portBB.array(),
-                portBB.position(), portBB.remaining(), StandardCharsets.UTF_8));
+        if (type == PORT_TLV_COMPONENT_SUBTYPE) {
+            return Integer.parseInt(new String(portBB.array(),
+                    portBB.position(), portBB.remaining(), StandardCharsets.UTF_8));
+        } else {
+            return -1;
+        }
+    }
+
+    public String getPortNameString() {
+        ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
+        byte type = portBB.get();
+
+        if (type == PORT_TLV_INTERFACE_NAME_SUBTYPE) {
+            return new String(portBB.array(), portBB.position(), portBB.remaining(), StandardCharsets.UTF_8);
+        } else {
+            log.error("Cannot find the port name tlv type.");
+            return null;
+        }
+    }
+
+    public MacAddress getChassisIdByMac() {
+        ByteBuffer portBB = ByteBuffer.wrap(this.getChassisId().getValue());
+        byte type = portBB.get();
+
+        if (type == CHASSIS_TLV_SUBTYPE) {
+            byte[] bytes = new byte[portBB.remaining()];
+
+            System.arraycopy(portBB.array(), portBB.position(), bytes, 0, MacAddress.MAC_ADDRESS_LENGTH);
+
+            return new MacAddress(bytes);
+        } else {
+            return MacAddress.NONE;
+        }
+    }
+
+    public short getTtlBySeconds() {
+        ByteBuffer portBB = ByteBuffer.wrap(this.getTtl().getValue());
+
+        return portBB.getShort();
     }
 
     public long getTimestamp() {
@@ -303,6 +369,22 @@
     }
 
     /**
+     * Given an ethernet packet, returns the device the LLDP came from.
+     * @param eth an ethernet packet
+     * @return a the lldp packet or null
+     */
+    public static ONOSLLDP parseLLDP(Ethernet eth) {
+        if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
+                eth.getEtherType() == Ethernet.TYPE_BSN) {
+
+            return new ONOSLLDP((LLDP) eth.getPayload());
+        }
+
+        log.error("Packet is not the LLDP or BSN.");
+        return null;
+    }
+
+    /**
      * Creates a link probe for link discovery/verification.
      * @deprecated since 1.15. Insecure, do not use.
      *
diff --git a/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java b/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java
index b2494b5..2405998 100644
--- a/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java
+++ b/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java
@@ -30,6 +30,7 @@
     private static final Integer PORT_NUMBER = 2;
     private static final Integer PORT_NUMBER_2 = 98761234;
     private static final String PORT_DESC = "Ethernet1";
+    private static final String PORT_NAME = "Ethernet2";
     private static final String TEST_SECRET = "test";
 
     private ONOSLLDP onoslldp = ONOSLLDP.onosSecureLLDP(DEVICE_ID, CHASSIS_ID, PORT_NUMBER, PORT_DESC, TEST_SECRET);
@@ -39,11 +40,21 @@
      */
     @Test
     public void testPortNumber() throws Exception {
-        assertEquals("the value from constructor with getPort value is miss matched",
+        assertEquals("the value from constructor with getPort value is mismatched",
                 PORT_NUMBER, onoslldp.getPort());
 
         onoslldp.setPortId(PORT_NUMBER_2);
-        assertEquals("the value from setPortId with getPort value is miss matched",
+        assertEquals("the value from setPortId with getPort value is mismatched",
                 PORT_NUMBER_2, onoslldp.getPort());
     }
+
+    /**
+     * Tests port name and getters.
+     */
+    @Test
+    public void testPortName() throws Exception {
+        onoslldp.setPortName(PORT_NAME);
+        assertEquals("the value from setPortName with getPortNameString value is mismatched",
+                PORT_NAME, onoslldp.getPortNameString());
+    }
 }
\ No newline at end of file