Fixes bug where driver gets initialized only when device is available.
More explict handling of versatile forwarding flows in corsa driver.
Moving TunnelConnectivityManager to use flowObjectives instead of flowRules.

Change-Id: If43023f30a6e7a028dfdefbe1ffbcc710a1c7be3
diff --git a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
index e196fe5..1c1a74a 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
@@ -161,7 +161,7 @@
         connectivityManager = new TunnellingConnectivityManager(appId,
                                                                 configService,
                                                                 packetService,
-                                                                flowService);
+                                                                flowObjectiveService);
 
         icmpHandler = new IcmpHandler(configService, packetService);
 
@@ -252,7 +252,7 @@
 
             flowObjectiveService.forward(deviceId,
                                          generateRibFlowRule(fibEntry.prefix(), nextId).add());
-            log.trace("Sending flow forwarding objective {}->{}", fibEntry, nextId);
+            log.trace("Sending forwarding objective {} -> nextId:{}", fibEntry, nextId);
         }
 
     }
@@ -282,8 +282,6 @@
                 .matchIPDst(prefix)
                 .build();
 
-
-
         int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
 
         ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
diff --git a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/TunnellingConnectivityManager.java b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/TunnellingConnectivityManager.java
index d76b353..7d8ca7c 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/TunnellingConnectivityManager.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/TunnellingConnectivityManager.java
@@ -15,19 +15,21 @@
  */
 package org.onosproject.bgprouter;
 
+import static org.slf4j.LoggerFactory.getLogger;
+
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.TCP;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRuleOperations;
-import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
@@ -37,6 +39,7 @@
 import org.onosproject.routing.config.BgpSpeaker;
 import org.onosproject.routing.config.InterfaceAddress;
 import org.onosproject.routing.config.RoutingConfigurationService;
+import org.slf4j.Logger;
 
 
 /**
@@ -46,23 +49,25 @@
 public class TunnellingConnectivityManager {
 
     private static final short BGP_PORT = 179;
-
+    private final Logger log = getLogger(getClass());
     private final ApplicationId appId;
 
     private final BgpSpeaker bgpSpeaker;
 
     private final PacketService packetService;
     private final RoutingConfigurationService configService;
+    private final FlowObjectiveService flowObjectiveService;
 
     private final BgpProcessor processor = new BgpProcessor();
 
     public TunnellingConnectivityManager(ApplicationId appId,
                                          RoutingConfigurationService configService,
                                          PacketService packetService,
-                                         FlowRuleService flowService) {
+                                         FlowObjectiveService flowObjectiveService) {
         this.appId = appId;
         this.configService = configService;
         this.packetService = packetService;
+        this.flowObjectiveService = flowObjectiveService;
 
         BgpSpeaker bgpSpeaker = null;
         for (BgpSpeaker speaker : configService.getBgpSpeakers().values()) {
@@ -92,12 +97,27 @@
                 .punt()
                 .build();
 
-        FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
-        builder.add(new DefaultFlowRule(bgpSpeaker.connectPoint().deviceId(),
-                                        selectorSrc, treatment, 0, appId, 0, true));
-        builder.add(new DefaultFlowRule(bgpSpeaker.connectPoint().deviceId(),
-                                        selectorDst, treatment, 0, appId, 0, true));
-        flowService.apply(builder.build());
+        ForwardingObjective puntSrc = DefaultForwardingObjective.builder()
+                .fromApp(appId)
+                .makePermanent()
+                .withSelector(selectorSrc)
+                .withTreatment(treatment)
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .add();
+        flowObjectiveService.forward(bgpSpeaker.connectPoint().deviceId(),
+                                     puntSrc);
+
+        ForwardingObjective puntDst = DefaultForwardingObjective.builder()
+                .fromApp(appId)
+                .makePermanent()
+                .withSelector(selectorDst)
+                .withTreatment(treatment)
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .add();
+        flowObjectiveService.forward(bgpSpeaker.connectPoint().deviceId(),
+                                     puntDst);
+        log.info("Sent punt forwarding objective to {}", bgpSpeaker.connectPoint().deviceId());
+
     }
 
     public void start() {
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
index 79d486e..7acce65 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
@@ -67,7 +67,7 @@
 @Service
 public class FlowObjectiveManager implements FlowObjectiveService {
 
-    public static final int INSTALL_RETRY_ATTEMPTS = 5;
+    public static final int INSTALL_RETRY_ATTEMPTS = 10;
     public static final long INSTALL_RETRY_INTERVAL = 1000; // ms
 
     private final Logger log = LoggerFactory.getLogger(getClass());
@@ -167,7 +167,7 @@
                         pipeliner.filter((FilteringObjective) objective);
                     }
                 } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) {
-                    Thread.currentThread().sleep(INSTALL_RETRY_INTERVAL);
+                    Thread.sleep(INSTALL_RETRY_INTERVAL);
                     executorService.submit(this);
                 } else {
                     // Otherwise we've tried a few times and failed, report an
@@ -262,7 +262,9 @@
             switch (event.type()) {
                 case MASTER_CHANGED:
                     log.info("mastership changed on device {}", event.subject());
-                    setupPipelineHandler(event.subject());
+                    if (deviceService.isAvailable(event.subject())) {
+                        setupPipelineHandler(event.subject());
+                    }
                     break;
                 case BACKUPS_CHANGED:
                     break;
@@ -278,8 +280,6 @@
         public void event(DeviceEvent event) {
             switch (event.type()) {
                 case DEVICE_ADDED:
-                    setupPipelineHandler(event.subject().id());
-                    break;
                 case DEVICE_AVAILABILITY_CHANGED:
                     log.info("Device either added or availability changed {}",
                              event.subject().id());
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 a64b678..ee07183 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
@@ -194,7 +194,8 @@
 
                     @Override
                     public void onError(Objective objective, ObjectiveError error) {
-                        log.warn("Failed to install packet request flow: {}", error);
+                        log.warn("Failed to install packet request {}: {}",
+                                 request, error);
                     }
                 });
 
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
index 4d1284b..d56e7fa 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
@@ -19,8 +19,10 @@
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.RemovalCause;
 import com.google.common.cache.RemovalNotification;
+
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
@@ -240,12 +242,59 @@
     }
 
     private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
+        log.debug("Processing versatile forwarding objective");
+        TrafficSelector selector = fwd.selector();
+
+        Criteria.EthTypeCriterion ethType =
+                (Criteria.EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
+        if (ethType == null) {
+            log.error("Versatile forwarding objective must include ethType");
+            fail(fwd, ObjectiveError.UNKNOWN);
+            return Collections.emptySet();
+        }
+        if (ethType.ethType() == Ethernet.TYPE_ARP) {
+            log.warn("Driver automatically handles ARP packets by punting to controller "
+                    + " from ETHER table");
+            pass(fwd);
+            return Collections.emptySet();
+        } else if (ethType.ethType() == Ethernet.TYPE_LLDP ||
+                ethType.ethType() == Ethernet.TYPE_BSN) {
+            log.warn("Driver currently does not currently handle LLDP packets");
+            fail(fwd, ObjectiveError.UNSUPPORTED);
+            return Collections.emptySet();
+        } else if (ethType.ethType() == Ethernet.TYPE_IPV4) {
+            Criteria.IPCriterion ipSrc = (Criteria.IPCriterion) selector
+                    .getCriterion(Criterion.Type.IPV4_SRC);
+            Criteria.IPCriterion ipDst = (Criteria.IPCriterion) selector
+                    .getCriterion(Criterion.Type.IPV4_DST);
+            Criteria.IPProtocolCriterion ipProto = (Criteria.IPProtocolCriterion) selector
+                    .getCriterion(Criterion.Type.IP_PROTO);
+            if (ipSrc != null) {
+                log.warn("Driver currently does not currently handle matching Src IP");
+                fail(fwd, ObjectiveError.UNSUPPORTED);
+                return Collections.emptySet();
+            }
+            if (ipDst != null) {
+                log.error("Driver handles Dst IP matching as specific forwarding "
+                        + "objective, not versatile");
+                fail(fwd, ObjectiveError.UNSUPPORTED);
+                return Collections.emptySet();
+            }
+            if (ipProto != null && ipProto.protocol() == IPv4.PROTOCOL_TCP) {
+                log.warn("Driver automatically punts all packets reaching the "
+                        + "LOCAL table to the controller");
+                pass(fwd);
+                return Collections.emptySet();
+            }
+        }
+
+        log.warn("Driver does not support given versatile forwarding objective");
         fail(fwd, ObjectiveError.UNSUPPORTED);
         return Collections.emptySet();
     }
 
     private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
-        log.warn("Processing specific");
+        log.debug("Processing specific forwarding objective");
         TrafficSelector selector = fwd.selector();
         Criteria.EthTypeCriterion ethType =
                 (Criteria.EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);