Merge branch 'master' into dev-karaf-4.2.1

Change-Id: I059c6a95489ff5cdc51dd7e98ba44a8415238bc2
diff --git a/apps/odtn/service/src/test/resources/create-connectivity.json b/apps/odtn/service/src/test/resources/create-connectivity.json
index 35798f4..47fd6dc 100644
--- a/apps/odtn/service/src/test/resources/create-connectivity.json
+++ b/apps/odtn/service/src/test/resources/create-connectivity.json
@@ -26,8 +26,8 @@
                 "protection-role" : "WORK"
             }
         ],
-        "conn-constraint" : {},
-        "topo-constraint" : {},
+        "connectivity-constraint" : {},
+        "topology-constraint" : {},
         "resilience-constraint" : [ ]
     }
 }
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 51990d1..2021aa8 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
@@ -69,6 +69,7 @@
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Router;
+import org.openstack4j.model.network.RouterInterface;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -519,27 +520,33 @@
     }
 
     private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
-        setFakeGatewayArpRuleByGateway(router.getExternalGatewayInfo(), install);
+        setFakeGatewayArpRuleByGateway(router.getId(), router.getExternalGatewayInfo(), install);
     }
 
-    private Set<IP> getExternalGatewaySnatIps(ExternalGateway extGw) {
-        return osNetworkAdminService.ports().stream()
-                .filter(port ->
-                        Objects.equals(port.getNetworkId(), extGw.getNetworkId()))
-                .filter(port ->
-                        Objects.equals(port.getDeviceOwner(), DEVICE_OWNER_ROUTER_GW))
-                .flatMap(port -> port.getFixedIps().stream())
+    private Set<IP> getExternalGatewaySnatIps(String routerId, ExternalGateway extGw) {
+        if (routerId == null) {
+            return ImmutableSet.of();
+        }
+
+        Set<String> portIds = osRouterAdminService.routerInterfaces(routerId).stream()
+                .map(RouterInterface::getPortId)
+                .collect(Collectors.toSet());
+
+        return portIds.stream()
+                .map(pid -> osNetworkAdminService.port(pid))
+                .filter(p -> Objects.equals(p.getDeviceOwner(), DEVICE_OWNER_ROUTER_GW))
+                .flatMap(p -> p.getFixedIps().stream())
                 .collect(Collectors.toSet());
     }
 
-    private void setFakeGatewayArpRuleByGateway(ExternalGateway extGw, boolean install) {
+    private void setFakeGatewayArpRuleByGateway(String routerId, ExternalGateway extGw, boolean install) {
         if (ARP_BROADCAST_MODE.equals(getArpMode())) {
 
             if (extGw == null) {
                 return;
             }
 
-            setFakeGatewayArpRuleByIps(getExternalGatewaySnatIps(extGw), install);
+            setFakeGatewayArpRuleByIps(getExternalGatewaySnatIps(routerId, extGw), install);
         }
     }
 
@@ -653,13 +660,15 @@
                 case OPENSTACK_ROUTER_GATEWAY_ADDED:
                     eventExecutor.execute(() ->
                         // add a gateway manually after adding a router
-                        setFakeGatewayArpRuleByGateway(event.externalGateway(), true)
+                        setFakeGatewayArpRuleByGateway(event.subject().getId(),
+                                                        event.externalGateway(), true)
                     );
                     break;
                 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
                     eventExecutor.execute(() ->
                         // remove a gateway from an existing router
-                        setFakeGatewayArpRuleByGateway(event.externalGateway(), false)
+                        setFakeGatewayArpRuleByGateway(event.subject().getId(),
+                                                        event.externalGateway(), false)
                     );
                     break;
                 case OPENSTACK_FLOATING_IP_ASSOCIATED:
@@ -875,6 +884,11 @@
         }
 
         private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
+
+            if (getArpMode() == null) {
+                return;
+            }
+
             switch (getArpMode()) {
                 case ARP_PROXY_MODE:
                     setDefaultArpRuleForProxyMode(osNode, install);
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 1a9de18..edcf6ed 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
@@ -482,15 +482,15 @@
     private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
         Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
         Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
-        String updatedSegmendId = getSegmentId(updatedSubnet);
+        String updatedSegmentId = getSegmentId(updatedSubnet);
 
         // installs rule from/to my subnet intentionally to fix ICMP failure
         // to my subnet gateway if no external gateway added to the router
         osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
             setInternalRouterRules(
                     cNode.intgBridge(),
-                    updatedSegmendId,
-                    updatedSegmendId,
+                    updatedSegmentId,
+                    updatedSegmentId,
                     IpPrefix.valueOf(updatedSubnet.getCidr()),
                     IpPrefix.valueOf(updatedSubnet.getCidr()),
                     updatedNetwork.getNetworkType(),
@@ -500,7 +500,7 @@
             routableSubnets.forEach(subnet -> {
                 setInternalRouterRules(
                         cNode.intgBridge(),
-                        updatedSegmendId,
+                        updatedSegmentId,
                         getSegmentId(subnet),
                         IpPrefix.valueOf(updatedSubnet.getCidr()),
                         IpPrefix.valueOf(subnet.getCidr()),
@@ -510,7 +510,7 @@
                 setInternalRouterRules(
                         cNode.intgBridge(),
                         getSegmentId(subnet),
-                        updatedSegmendId,
+                        updatedSegmentId,
                         IpPrefix.valueOf(subnet.getCidr()),
                         IpPrefix.valueOf(updatedSubnet.getCidr()),
                         updatedNetwork.getNetworkType(),
@@ -854,7 +854,6 @@
                 .matchIPSrc(srcSubnet)
                 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
 
-
         switch (networkType) {
             case VXLAN:
                 sBuilder.matchTunnelId(Long.parseLong(segmentId));
@@ -886,7 +885,14 @@
                 GW_COMMON_TABLE,
                 install);
 
+        // TODO: we do not remove the IcmpReplyMatchRules with false installation flag
+        // need to find a better way to remove this rule
+        if (install) {
+            setIcmpReplyRules(deviceId, install);
+        }
+    }
 
+    private void setIcmpReplyRules(DeviceId deviceId, boolean install) {
         // Sends ICMP response to controller for SNATing ingress traffic
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
index 0fab57f..1cc02b7 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
@@ -93,6 +93,9 @@
     private static final String ERR_REQ = "Failed to handle ICMP request: ";
     private static final String ERR_DUPLICATE = " already exists";
 
+    private static final String VXLAN = "VXLAN";
+    private static final String VLAN = "VLAN";
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected CoreService coreService;
 
@@ -407,13 +410,26 @@
     }
 
     private void sendReply(Ethernet icmpReply, InstancePort instPort) {
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(instPort.portNumber())
-                .build();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
+                .setOutput(instPort.portNumber());
+
+        String netId = instPort.networkId();
+        String segId = osNetworkService.segmentId(netId);
+
+        switch (osNetworkService.networkType(netId)) {
+            case VXLAN:
+                tBuilder.setTunnelId(Long.valueOf(segId));
+                break;
+            case VLAN:
+                tBuilder.setVlanId(VlanId.vlanId(segId));
+                break;
+            default:
+                break;
+        }
 
         OutboundPacket packet = new DefaultOutboundPacket(
                 instPort.deviceId(),
-                treatment,
+                tBuilder.build(),
                 ByteBuffer.wrap(icmpReply.serialize()));
 
         packetService.emit(packet);
@@ -435,7 +451,8 @@
                 return;
             }
 
-            if (!gateways.isEmpty() && !gateways.contains(context.inPacket().receivedFrom().deviceId())) {
+            if (!gateways.isEmpty() &&
+                    !gateways.contains(context.inPacket().receivedFrom().deviceId())) {
                 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 863e40a..ba9ec96 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
@@ -42,6 +42,7 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.ExtensionSelector;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.InstancePortAdminService;
 import org.onosproject.openstacknetworking.api.InstancePortEvent;
@@ -54,7 +55,6 @@
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
 import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
-import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
@@ -176,13 +176,13 @@
             .build();
 
     private final InstancePortListener instancePortListener =
-                                        new InternalInstancePortListener();
+            new InternalInstancePortListener();
     private final OpenstackNetworkListener osNetworkListener =
-                                        new InternalOpenstackNetworkListener();
+            new InternalOpenstackNetworkListener();
     private final OpenstackNetworkListener osPortListener =
-                                        new InternalOpenstackPortListener();
+            new InternalOpenstackPortListener();
     private final OpenstackSecurityGroupListener securityGroupListener =
-                                        new InternalSecurityGroupListener();
+            new InternalSecurityGroupListener();
     private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
 
     private ConsistentMap<String, Port> removedOsPortStore;
@@ -335,10 +335,10 @@
                         SecurityGroupRule rSgRule =
                                 new NeutronSecurityGroupRule
                                         .SecurityGroupRuleConcreteBuilder()
-                                .from(sgRule)
-                                .direction(sgRule.getDirection().toUpperCase()
-                                            .equals(EGRESS) ? INGRESS : EGRESS)
-                                .build();
+                                        .from(sgRule)
+                                        .direction(sgRule.getDirection().toUpperCase()
+                                                .equals(EGRESS) ? INGRESS : EGRESS)
+                                        .build();
                         populateSecurityGroupRule(rSgRule, instPort, port,
                                 rInstPort.ipAddress().toIpPrefix(), install);
                         populateSecurityGroupRule(rSgRule, rInstPort, port,
@@ -347,7 +347,7 @@
         } else {
             populateSecurityGroupRule(sgRule, instPort, port,
                     sgRule.getRemoteIpPrefix() == null ? IP_PREFIX_ANY :
-                    IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
+                            IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
         }
     }
 
@@ -362,14 +362,25 @@
             return;
         }
 
+        // XXX All egress traffic needs to go through connection tracking module,
+        // which might hurt its performance.
+        ExtensionTreatment ctTreatment =
+                niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
+                        .commit(true)
+                        .build();
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .extension(ctTreatment, instPort.deviceId())
+                .transition(JUMP_TABLE)
+                .build();
+
         selectors.forEach(selector ->
                 osFlowRuleService.setRule(appId,
-                instPort.deviceId(),
-                selector,
-                DefaultTrafficTreatment.builder().transition(JUMP_TABLE).build(),
-                PRIORITY_ACL_RULE,
-                ACL_TABLE,
-                install));
+                        instPort.deviceId(),
+                        selector, treatment,
+                        PRIORITY_ACL_RULE,
+                        ACL_TABLE,
+                        install));
     }
 
     /**
@@ -490,7 +501,7 @@
                 sgRule.getPortRangeMin() < sgRule.getPortRangeMax()) {
             Map<TpPort, TpPort> portRangeMatchMap =
                     buildPortRangeMatches(sgRule.getPortRangeMin(),
-                    sgRule.getPortRangeMax());
+                            sgRule.getPortRangeMax());
             portRangeMatchMap.forEach((key, value) -> {
 
                 if (sgRule.getProtocol().toUpperCase().equals(PROTO_TCP)) {
@@ -527,9 +538,6 @@
                 sgRule.getPortRangeMin() == null ? 0 : sgRule.getPortRangeMin(),
                 sgRule.getPortRangeMax() == null ? 0 : sgRule.getPortRangeMax());
         buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
-        if (sgRule.getRemoteGroupId() != null && sgRule.getRemoteGroupId().isEmpty()) {
-            buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
-        }
     }
 
     private void buildTunnelId(TrafficSelector.Builder sBuilder, Port port) {
@@ -540,6 +548,8 @@
             sBuilder.matchVlanId(VlanId.vlanId(segId));
         } else if (VXLAN.equals(netType)) {
             sBuilder.matchTunnelId(Long.valueOf(segId));
+        } else {
+            log.warn("Cannot tag the VID due to lack of support of virtual network type {}", netType);
         }
     }
 
@@ -614,33 +624,31 @@
     private void resetSecurityGroupRules() {
 
         if (useSecurityGroup) {
-            osNodeService.completeNodes(OpenstackNode.NodeType.COMPUTE)
-                    .forEach(node -> osFlowRuleService
-                            .setUpTableMissEntry(node.intgBridge(), ACL_TABLE));
+            osNodeService.completeNodes(COMPUTE).forEach(node -> {
+                osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_TABLE);
+                initializeConnTrackTable(node.intgBridge(), true);
+            });
+
             securityGroupService.securityGroups().forEach(securityGroup ->
                     securityGroup.getRules().forEach(this::securityGroupRuleAdded));
-            osNodeService.nodes().stream()
-                    .filter(node -> node.type().equals(OpenstackNode.NodeType.COMPUTE))
-                    .forEach(node -> initializeConnTrackTable(node .intgBridge(), true));
         } else {
-            osNodeService.completeNodes(OpenstackNode.NodeType.COMPUTE)
-                    .forEach(node -> osFlowRuleService
-                            .connectTables(node.intgBridge(), ACL_TABLE, JUMP_TABLE));
+            osNodeService.completeNodes(COMPUTE).forEach(node -> {
+                osFlowRuleService.connectTables(node.intgBridge(), ACL_TABLE, JUMP_TABLE);
+                initializeConnTrackTable(node.intgBridge(), false);
+            });
+
             securityGroupService.securityGroups().forEach(securityGroup ->
                     securityGroup.getRules().forEach(this::securityGroupRuleRemoved));
-            osNodeService.nodes().stream()
-                    .filter(node -> node.type().equals(OpenstackNode.NodeType.COMPUTE))
-                    .forEach(node -> initializeConnTrackTable(node.intgBridge(), false));
         }
 
         log.info("Reset security group info " +
-                    (useSecurityGroup ? " with " : " without") + " Security Group");
+                (useSecurityGroup ? " with " : " without") + " Security Group");
     }
 
     private void securityGroupRuleAdded(SecurityGroupRule sgRule) {
         osNetService.ports().stream()
                 .filter(port -> port.getSecurityGroups()
-                                    .contains(sgRule.getSecurityGroupId()))
+                        .contains(sgRule.getSecurityGroupId()))
                 .forEach(port -> {
                     updateSecurityGroupRule(
                             instancePortService.instancePort(port.getId()),
@@ -655,7 +663,7 @@
 
         Sets.union(osNetService.ports(), removedPorts).stream()
                 .filter(port -> port.getSecurityGroups()
-                                    .contains(sgRule.getSecurityGroupId()))
+                        .contains(sgRule.getSecurityGroupId()))
                 .forEach(port -> {
                     updateSecurityGroupRule(
                             instancePortService.instancePort(port.getId()),
@@ -825,7 +833,7 @@
     }
 
     private class InternalOpenstackNetworkListener
-                                            implements OpenstackNetworkListener {
+            implements OpenstackNetworkListener {
 
         @Override
         public boolean isRelevant(OpenstackNetworkEvent event) {
@@ -881,7 +889,7 @@
     }
 
     private class InternalSecurityGroupListener
-                                    implements OpenstackSecurityGroupListener {
+            implements OpenstackSecurityGroupListener {
 
         @Override
         public boolean isRelevant(OpenstackSecurityGroupEvent event) {
@@ -936,22 +944,9 @@
 
         @Override
         public void event(OpenstackNodeEvent event) {
-            OpenstackNode osNode = event.subject();
-
             switch (event.type()) {
                 case OPENSTACK_NODE_COMPLETE:
-                    eventExecutor.execute(() -> {
-                        try {
-                            if (useSecurityGroup) {
-                                initializeConnTrackTable(osNode.intgBridge(), true);
-                                log.info("SG table initialization : {} is done",
-                                                            osNode.intgBridge());
-                            }
-                        } catch (IllegalArgumentException e) {
-                            log.error("ACL table initialization error : {}",
-                                                            e.getMessage());
-                        }
-                    });
+                    resetSecurityGroupRules();
                     break;
                 case OPENSTACK_NODE_CREATED:
                 case OPENSTACK_NODE_REMOVED:
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 b348d49..f6977a3 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
@@ -39,7 +39,6 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.instructions.ExtensionTreatment;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.InstancePortEvent;
 import org.onosproject.openstacknetworking.api.InstancePortListener;
@@ -49,7 +48,6 @@
 import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
-import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.openstack4j.model.network.Network;
@@ -501,25 +499,21 @@
                 .matchInPort(instPort.portNumber())
                 .build();
 
-        // XXX All egress traffic needs to go through connection tracking module,
-        // which might hurt its performance.
-        ExtensionTreatment ctTreatment =
-                RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
-                        .commit(true).build();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
+                .setTunnelId(getVni(instPort));
 
-        TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
-                .setTunnelId(getVni(instPort))
-                .transition(ARP_TABLE);
 
-        if (securityGroupService.isSecurityGroupEnabled() && ethType == Ethernet.TYPE_IPV4) {
-            tb.extension(ctTreatment, instPort.deviceId());
+        if (ethType == Ethernet.TYPE_ARP) {
+            tBuilder.transition(ARP_TABLE);
+        } else if (ethType == Ethernet.TYPE_IPV4) {
+            tBuilder.transition(ACL_TABLE);
         }
 
         osFlowRuleService.setRule(
                 appId,
                 instPort.deviceId(),
                 selector,
-                tb.build(),
+                tBuilder.build(),
                 PRIORITY_TUNNEL_TAG_RULE,
                 VTAG_TABLE,
                 install);
diff --git a/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RouteRemoveCommand.java b/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RouteRemoveCommand.java
index eb6f01c..8fb29ec 100644
--- a/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RouteRemoveCommand.java
+++ b/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RouteRemoveCommand.java
@@ -43,6 +43,10 @@
             required = true)
     String nextHopString = null;
 
+    @Argument(index = 2, name = "source", description = "Source type of the route",
+            required = false)
+    String source = null;
+
     @Override
     protected void doExecute() {
         RouteAdminService service = AbstractShellCommand.get(RouteAdminService.class);
@@ -50,7 +54,14 @@
         IpPrefix prefix = IpPrefix.valueOf(prefixString);
         IpAddress nextHop = IpAddress.valueOf(nextHopString);
 
-        service.withdraw(Collections.singleton(new Route(Route.Source.STATIC, prefix, nextHop)));
+        // Routes through cli without mentioning source then it is created as STATIC,
+        // otherwise routes are created with corresponding source.
+
+        Route route = source == null ?
+                new Route(Route.Source.STATIC, prefix, nextHop) :
+                new Route(Route.Source.valueOf(source), prefix, nextHop);
+
+        service.withdraw(Collections.singleton(route));
     }
 
 }
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
index ffc0e4d..ae35f7b 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
@@ -448,18 +448,37 @@
      * @param pairRemotePort pair remote port
      */
     private void probe(Host host, ConnectPoint location, DeviceId pairDeviceId, PortNumber pairRemotePort) {
+        //Check if the host still exists in the host store
+        if (hostService.getHost(host.id()) == null) {
+            log.debug("Host entry for host {} no more present. Aborting hostprobe discover for this host", host.id());
+            return;
+        }
+
         VlanId vlanToProbe = host.vlan().equals(VlanId.NONE) ?
                 srManager.getInternalVlanId(location) : host.vlan();
-        srManager.interfaceService.getInterfaces().stream()
-                .filter(i -> i.vlanTagged().contains(vlanToProbe) ||
-                        i.vlanUntagged().equals(vlanToProbe) ||
-                        i.vlanNative().equals(vlanToProbe))
-                .filter(i -> i.connectPoint().deviceId().equals(pairDeviceId))
-                .filter(i -> !i.connectPoint().port().equals(pairRemotePort))
-                .forEach(i -> {
-                    log.debug("Probing host {} on pair device {}", host.id(), i.connectPoint());
-                    srManager.probingService.probeHost(host, i.connectPoint(), ProbeMode.DISCOVER);
-                });
+        if (srManager.symmetricProbing) {
+            srManager.interfaceService.getInterfaces().stream()
+                    .filter(i -> i.vlanTagged().contains(vlanToProbe) ||
+                            i.vlanUntagged().equals(vlanToProbe) ||
+                            i.vlanNative().equals(vlanToProbe))
+                    .filter(i -> i.connectPoint().deviceId().equals(pairDeviceId))
+                    .filter(i -> i.connectPoint().port().equals(location.port()))
+                    .forEach(i -> {
+                        log.debug("Probing host {} on pair device {}", host.id(), i.connectPoint());
+                        srManager.probingService.probeHost(host, i.connectPoint(), ProbeMode.DISCOVER);
+                    });
+        } else {
+            srManager.interfaceService.getInterfaces().stream()
+                    .filter(i -> i.vlanTagged().contains(vlanToProbe) ||
+                            i.vlanUntagged().equals(vlanToProbe) ||
+                            i.vlanNative().equals(vlanToProbe))
+                    .filter(i -> i.connectPoint().deviceId().equals(pairDeviceId))
+                    .filter(i -> !i.connectPoint().port().equals(pairRemotePort))
+                    .forEach(i -> {
+                        log.debug("Probing host {} on pair device {}", host.id(), i.connectPoint());
+                        srManager.probingService.probeHost(host, i.connectPoint(), ProbeMode.DISCOVER);
+                    });
+        }
     }
 
     /**
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/OsgiPropertyConstants.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/OsgiPropertyConstants.java
index 399e95b..7b5a6fc 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/OsgiPropertyConstants.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/OsgiPropertyConstants.java
@@ -41,4 +41,7 @@
     public static final String PROP_PW_TRANSPORT_VLAN = "pwTransportVlan";
     public static final int PW_TRANSPORT_VLAN_DEFAULT = 4090;
 
+    static final String PROP_SYMMETRIC_PROBING = "symmetricProbing";
+    static final boolean SYMMETRIC_PROBING_DEFAULT = false;
+
 }
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 17e733c..c75de3c 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -165,10 +165,12 @@
 import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_RESPOND_TO_UNKNOWN_HOSTS;
 import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_ROUTE_DOUBLE_TAGGED_HOSTS;
 import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_SINGLE_HOMED_DOWN;
+import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_SYMMETRIC_PROBING;
 import static org.onosproject.segmentrouting.OsgiPropertyConstants.PW_TRANSPORT_VLAN_DEFAULT;
 import static org.onosproject.segmentrouting.OsgiPropertyConstants.RESPOND_TO_UNKNOWN_HOSTS_DEFAULT;
 import static org.onosproject.segmentrouting.OsgiPropertyConstants.ROUTE_DOUBLE_TAGGED_HOSTS_DEFAULT;
 import static org.onosproject.segmentrouting.OsgiPropertyConstants.SINGLE_HOMED_DOWN_DEFAULT;
+import static org.onosproject.segmentrouting.OsgiPropertyConstants.SYMMETRIC_PROBING_DEFAULT;
 
 /**
  * Segment routing manager.
@@ -183,6 +185,7 @@
         PROP_ROUTE_DOUBLE_TAGGED_HOSTS + ":Boolean=" + ROUTE_DOUBLE_TAGGED_HOSTS_DEFAULT,
         PROP_DEFAULT_INTERNAL_VLAN + ":Integer=" + DEFAULT_INTERNAL_VLAN_DEFAULT,
         PROP_PW_TRANSPORT_VLAN + ":Integer=" + PW_TRANSPORT_VLAN_DEFAULT,
+        PROP_SYMMETRIC_PROBING + ":Boolean=" + SYMMETRIC_PROBING_DEFAULT
     }
 )
 public class SegmentRoutingManager implements SegmentRoutingService {
@@ -256,6 +259,9 @@
     /** Enable active probing to discover dual-homed hosts. */
     boolean activeProbing = ACTIVE_PROBING_DEFAULT;
 
+    /** Enable only send probe on the same port number of the pair device. */
+    boolean symmetricProbing = SYMMETRIC_PROBING_DEFAULT;
+
     /** Enable administratively taking down single-homed hosts. */
     boolean singleHomedDown = SINGLE_HOMED_DOWN_DEFAULT;
 
@@ -625,6 +631,14 @@
             log.info("{} active probing", activeProbing ? "Enabling" : "Disabling");
         }
 
+
+        String strSymmetricProbing = Tools.get(properties, PROP_SYMMETRIC_PROBING);
+        boolean expectSymmetricProbing = Boolean.parseBoolean(strSymmetricProbing);
+        if (expectSymmetricProbing != symmetricProbing) {
+            symmetricProbing = expectSymmetricProbing;
+            log.info("{} symmetric probing", symmetricProbing ? "Enabling" : "Disabling");
+        }
+
         String strSingleHomedDown = Tools.get(properties, PROP_SINGLE_HOMED_DOWN);
         boolean expectSingleHomedDown = Boolean.parseBoolean(strSingleHomedDown);
         if (expectSingleHomedDown != singleHomedDown) {