Changes include:
      bug fix for host IP and MAC flows not being generated sometimes in multi-controller scenarios
      bug fix for filtering objectives not being sent sometimes when ports become available later
      npe fixes in ofdpa driver for cases where selectors or treatments may not be available
      new cli command to manually trigger routing and rule population
      portstats option on cli to display only those ports with non-zero stats
      group cli command tab completion displays choices in lower case (similar to flows)
      segment routing cli commands now start with sr-

Change-Id: Idcd641882d180acbd304e5560ed3483b5a943f96
diff --git a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 4265d0c..e2a040a 100644
--- a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -114,6 +114,11 @@
             log.warn(e.getMessage() + " Aborting populateIpRuleForHost.");
             return;
         }
+        if (fwdBuilder == null) {
+            log.warn("Aborting host routing table entries due "
+                    + "to error for dev:{} host:{}", deviceId, hostIp);
+            return;
+        }
         ObjectiveContext context = new DefaultObjectiveContext(
                 (objective) -> log.debug("IP rule for host {} populated", hostIp),
                 (objective, error) ->
@@ -191,7 +196,10 @@
                                     .matchVlanId(outvlan).build();
         int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
                                                              treatment, meta);
-
+        if (portNextObjId == -1) {
+            // warning log will come from getPortNextObjective method
+            return null;
+        }
         return DefaultForwardingObjective.builder()
                 .withSelector(selector)
                 .nextStep(portNextObjId)
@@ -464,7 +472,7 @@
      *
      * @param deviceId  the switch dpid for the router
      */
-    public void populateRouterMacVlanFilters(DeviceId deviceId) {
+    public boolean populateRouterMacVlanFilters(DeviceId deviceId) {
         log.debug("Installing per-port filtering objective for untagged "
                 + "packets in device {}", deviceId);
 
@@ -473,10 +481,17 @@
             deviceMac = config.getDeviceMac(deviceId);
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting populateRouterMacVlanFilters.");
-            return;
+            return false;
         }
 
-        for (Port port : srManager.deviceService.getPorts(deviceId)) {
+        List<Port> devPorts = srManager.deviceService.getPorts(deviceId);
+        if (devPorts != null && devPorts.size() == 0) {
+            log.warn("Device {} ports not available. Unable to add MacVlan filters",
+                     deviceId);
+            return false;
+        }
+
+        for (Port port : devPorts) {
             ConnectPoint connectPoint = new ConnectPoint(deviceId, port.number());
             // TODO: Handles dynamic port events when we are ready for dynamic config
             if (!srManager.deviceConfiguration.suppressSubnet().contains(connectPoint) &&
@@ -498,6 +513,7 @@
                     fob.withMeta(tt);
                 }
                 fob.permit().fromApp(srManager.appId);
+                log.debug("Sending filtering objective for dev/port:{}/{}", deviceId, port);
                 ObjectiveContext context = new DefaultObjectiveContext(
                         (objective) -> log.debug("Filter for {} populated", connectPoint),
                         (objective, error) ->
@@ -505,6 +521,7 @@
                 srManager.flowObjectiveService.filter(deviceId, fob.add(context));
             }
         }
+        return true;
     }
 
     /**