IGMP ssm translate

Change-Id: Id5654702ad55b6294323e4cb753fe28ea1f61276
diff --git a/src/main/java/org/onosproject/igmp/IgmpSnoop.java b/src/main/java/org/onosproject/igmp/IgmpSnoop.java
index 6b914ca..0393ed9 100644
--- a/src/main/java/org/onosproject/igmp/IgmpSnoop.java
+++ b/src/main/java/org/onosproject/igmp/IgmpSnoop.java
@@ -66,6 +66,7 @@
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -131,6 +132,8 @@
 
     private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
 
+    private Map<IpAddress, IpAddress> ssmTranslateTable = new ConcurrentHashMap<>();
+
     private DeviceListener deviceListener = new InternalDeviceListener();
     private IgmpPacketProcessor processor = new IgmpPacketProcessor();
     private static ApplicationId appId;
@@ -150,6 +153,15 @@
                 }
             };
 
+    private ConfigFactory<ApplicationId, IgmpSsmTranslateConfig> ssmTranslateConfigFactory =
+            new ConfigFactory<ApplicationId, IgmpSsmTranslateConfig>(
+                    SubjectFactories.APP_SUBJECT_FACTORY, IgmpSsmTranslateConfig.class, "ssmTranslate", true) {
+                @Override
+                public IgmpSsmTranslateConfig createConfig() {
+                    return new IgmpSsmTranslateConfig();
+                }
+            };
+
 
     private ByteBuffer queryPacket;
 
@@ -161,6 +173,7 @@
         packetService.addProcessor(processor, PacketProcessor.director(1));
 
         networkConfig.registerConfigFactory(configFactory);
+        networkConfig.registerConfigFactory(ssmTranslateConfigFactory);
         networkConfig.addListener(configListener);
 
         networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
@@ -175,6 +188,16 @@
                 }
         );
 
+        IgmpSsmTranslateConfig ssmTranslateConfig =
+                networkConfig.getConfig(appId, IgmpSsmTranslateConfig.class);
+
+        if (ssmTranslateConfig != null) {
+            Collection<McastRoute> translations = ssmTranslateConfig.getSsmTranslations();
+            for (McastRoute route : translations) {
+                ssmTranslateTable.put(route.group(), route.source());
+            }
+        }
+
         oltData.keySet().stream()
                 .flatMap(did -> deviceService.getPorts(did).stream())
                 .filter(p -> !oltData.get(p.element().id()).uplink().equals(p.number()))
@@ -201,6 +224,7 @@
         deviceService.removeListener(deviceListener);
         networkConfig.removeListener(configListener);
         networkConfig.unregisterConfigFactory(configFactory);
+        networkConfig.unregisterConfigFactory(ssmTranslateConfigFactory);
         queryTask.cancel(true);
         queryService.shutdownNow();
         log.info("Stopped");
@@ -248,9 +272,15 @@
 
             IGMPMembership membership = (IGMPMembership) group;
 
-            McastRoute route = new McastRoute(IpAddress.valueOf("0.0.0.0"),
-                                              group.getGaddr(),
-                                              McastRoute.Type.IGMP);
+            // TODO allow pulling source from IGMP packet
+            IpAddress source = IpAddress.valueOf("0.0.0.0");
+            if (ssmTranslateTable.containsKey(group.getGaddr())) {
+                source = ssmTranslateTable.get(group.getGaddr());
+            }
+
+            McastRoute route = new McastRoute(source,
+                    group.getGaddr(),
+                    McastRoute.Type.IGMP);
 
             if (membership.getRecordType() == IGMPMembership.MODE_IS_INCLUDE ||
                     membership.getRecordType() == IGMPMembership.CHANGE_TO_INCLUDE_MODE) {