IGMP ssm translate

Change-Id: Id5654702ad55b6294323e4cb753fe28ea1f61276
diff --git a/apps/igmp/src/main/java/org/onosproject/igmp/IgmpSnoop.java b/apps/igmp/src/main/java/org/onosproject/igmp/IgmpSnoop.java
index 6b914ca..0393ed9 100644
--- a/apps/igmp/src/main/java/org/onosproject/igmp/IgmpSnoop.java
+++ b/apps/igmp/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) {
diff --git a/apps/igmp/src/main/java/org/onosproject/igmp/IgmpSsmTranslateConfig.java b/apps/igmp/src/main/java/org/onosproject/igmp/IgmpSsmTranslateConfig.java
new file mode 100644
index 0000000..ea2d983
--- /dev/null
+++ b/apps/igmp/src/main/java/org/onosproject/igmp/IgmpSsmTranslateConfig.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.igmp;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.onlab.packet.IpAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.mcast.McastRoute;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by jono on 2/16/16.
+ */
+public class IgmpSsmTranslateConfig extends Config<ApplicationId> {
+    private static final String SSM_TRANSLATE = "ssmTranslate";
+    private static final String SOURCE = "source";
+    private static final String GROUP = "group";
+
+    public List<McastRoute> getSsmTranslations() {
+        List<McastRoute> translations = new ArrayList();
+        for (JsonNode node : array) {
+            translations.add(
+                    new McastRoute(
+                            IpAddress.valueOf(node.path(SOURCE).asText().trim()),
+                            IpAddress.valueOf(node.path(GROUP).asText().trim()),
+                            McastRoute.Type.STATIC));
+        }
+
+        return translations;
+    }
+}