CORD-512 Support vSG <-> vRouter default route

- Support multiple subnets per port. getIpPort() will only return the first non-/32 and non-/0 subnet
    /32 is used as vSG subnet
    /0 is used as default gateway
- Support multiple L3 unicast group on a single port
    Change the way to generate the group ID and group key
- Special case for 0.0.0.0 host. Push a /0 to IP table instead of /32
- Implement vRouterConfig
    Put VR MAC to TMAC table of all leaves when config added
        When processEthDst see PortNumber.ANY in key, match ETH_DST only
- For OFDPA, wipe existing instruction before sending to controller
    So packet that misses L3 unicast table won't be sent to controller twice
- For SpringOpenTTP, pop VLAN before sending to controller
- Move several constant definitions to SegmentRoutingService
- Add minimum priority for IP rules such that /0 won't collide with zero priority default rules
- Update the config sample
    Use VLAN=-1 for hosts
    Add example for default route

Change-Id: Id751697ce36a7e5c13b3859350ff21b585c38525
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 592c0b1..32e03de 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -54,7 +54,8 @@
 import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
 import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
+import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
+import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
@@ -130,6 +131,12 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected MastershipService mastershipService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry cfgService;
+
     protected ArpHandler arpHandler = null;
     protected IcmpHandler icmpHandler = null;
     protected IpHandler ipHandler = null;
@@ -143,7 +150,9 @@
     private InternalPacketProcessor processor = null;
     private InternalLinkListener linkListener = null;
     private InternalDeviceListener deviceListener = null;
+    private NetworkConfigEventHandler netcfgHandler = null;
     private InternalEventHandler eventHandler = new InternalEventHandler();
+    private final InternalHostListener hostListener = new InternalHostListener();
 
     private ScheduledExecutorService executorService = Executors
             .newScheduledThreadPool(1);
@@ -181,27 +190,28 @@
     private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
     private EventuallyConsistentMap<String, Policy> policyStore = null;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected StorageService storageService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigRegistry cfgService;
-
     private final InternalConfigListener cfgListener =
             new InternalConfigListener(this);
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private final ConfigFactory cfgFactory =
-            new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
-                              SegmentRoutingConfig.class,
+    private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory =
+            new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
+                              SegmentRoutingDeviceConfig.class,
                               "segmentrouting") {
                 @Override
-                public SegmentRoutingConfig createConfig() {
-                    return new SegmentRoutingConfig();
+                public SegmentRoutingDeviceConfig createConfig() {
+                    return new SegmentRoutingDeviceConfig();
                 }
             };
 
-    private final InternalHostListener hostListener = new InternalHostListener();
+    private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory =
+            new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
+                    SegmentRoutingAppConfig.class,
+                    "segmentrouting") {
+                @Override
+                public SegmentRoutingAppConfig createConfig() {
+                    return new SegmentRoutingAppConfig();
+                }
+            };
 
     private Object threadSchedulerLock = new Object();
     private static int numOfEventsQueued = 0;
@@ -223,7 +233,7 @@
     @Activate
     protected void activate() {
         appId = coreService
-                .registerApplication("org.onosproject.segmentrouting");
+                .registerApplication(SR_APP_ID);
 
         kryoBuilder = new KryoNamespace.Builder()
             .register(NeighborSetNextObjectiveStoreKey.class,
@@ -309,14 +319,15 @@
                 .build();
 
         cfgService.addListener(cfgListener);
-        cfgService.registerConfigFactory(cfgFactory);
-
-        hostService.addListener(hostListener);
+        cfgService.registerConfigFactory(cfgDeviceFactory);
+        cfgService.registerConfigFactory(cfgAppFactory);
 
         processor = new InternalPacketProcessor();
         linkListener = new InternalLinkListener();
         deviceListener = new InternalDeviceListener();
+        netcfgHandler = new NetworkConfigEventHandler(this);
 
+        hostService.addListener(hostListener);
         packetService.addProcessor(processor, PacketProcessor.director(2));
         linkService.addListener(linkListener);
         deviceService.addListener(deviceListener);
@@ -334,7 +345,8 @@
     @Deactivate
     protected void deactivate() {
         cfgService.removeListener(cfgListener);
-        cfgService.unregisterConfigFactory(cfgFactory);
+        cfgService.unregisterConfigFactory(cfgDeviceFactory);
+        cfgService.unregisterConfigFactory(cfgAppFactory);
 
         // Withdraw ARP packet-in
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
@@ -456,10 +468,17 @@
             nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
         }
         for (Ip4Prefix unsub : unassignedSubnets) {
-            subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
-                               VlanId.vlanId(nextAssignedVlan--));
-            log.info("Assigned vlan: {} to subnet: {} on device: {}",
-                      nextAssignedVlan + 1, unsub, deviceId);
+            // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
+            if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
+                    unsub.prefixLength() == 0) {
+                subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
+                        VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
+            } else {
+                subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
+                        VlanId.vlanId(nextAssignedVlan--));
+                log.info("Assigned vlan: {} to subnet: {} on device: {}",
+                        nextAssignedVlan + 1, unsub, deviceId);
+            }
         }
 
         return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
@@ -766,6 +785,8 @@
             groupHandler.createGroupsForXConnect(device.id());
             routingRulePopulator.populateXConnectBroadcastRule(device.id());
         }
+
+        netcfgHandler.initVRouters(device.id());
     }
 
     private void processPortRemoved(Device device, Port port) {
@@ -851,14 +872,33 @@
 
         @Override
         public void event(NetworkConfigEvent event) {
-            if (event.configClass().equals(SegmentRoutingConfig.class)) {
-                if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
-                    log.info("Network configuration added.");
-                    configureNetwork();
+            // TODO move this part to NetworkConfigEventHandler
+            if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
+                switch (event.type()) {
+                    case CONFIG_ADDED:
+                        log.info("Segment Routing Config added.");
+                        configureNetwork();
+                        break;
+                    case CONFIG_UPDATED:
+                        log.info("Segment Routing Config updated.");
+                        // TODO support dynamic configuration
+                        break;
+                    default:
+                        break;
                 }
-                if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
-                    log.info("Network configuration updated.");
-                    // TODO support dynamic configuration
+            } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
+                switch (event.type()) {
+                    case CONFIG_ADDED:
+                        netcfgHandler.processVRouterConfigAdded(event);
+                        break;
+                    case CONFIG_UPDATED:
+                        netcfgHandler.processVRouterConfigUpdated(event);
+                        break;
+                    case CONFIG_REMOVED:
+                        netcfgHandler.processVRouterConfigRemoved(event);
+                        break;
+                    default:
+                        break;
                 }
             }
         }