Added McastConnectPoint to track membership source
for egress ConnectPoints by STATIC config, PIM and
IGMP.

Change-Id: Ia913ee697e0cae32dd74db508e5ea2cba0d47c45
diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java
index 5172691..3ce2925 100644
--- a/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java
@@ -20,6 +20,7 @@
 import org.onlab.packet.IpPrefix;

 import org.onosproject.cli.AbstractShellCommand;

 

+import org.onosproject.mfwd.impl.McastConnectPoint;

 import org.onosproject.mfwd.impl.McastRouteBase;

 import org.onosproject.mfwd.impl.McastRouteTable;

 

@@ -76,21 +77,13 @@
         if (ingressPort != null) {

             String inCP = ingressPort;

             log.debug("Ingress port provided: " + inCP);

-            String [] cp = inCP.split("/");

-            mr.addIngressPoint(cp[0], Long.parseLong(cp[1]));

-        } else {

-            return;

-        }

-

-        if (ports == null) {

-            return;

+            mr.addIngressPoint(inCP);

         }

 

         for (int i = 0; i < ports.length; i++) {

             String egCP = ports[i];

             log.debug("Egress port provided: " + egCP);

-            String [] cp = egCP.split("/");

-            mr.addEgressPoint(cp[0], Long.parseLong(cp[1]));

+            mr.addEgressPoint(egCP, McastConnectPoint.JoinSource.STATIC);

         }

         print("Added the mcast route");

     }

diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java
index 750fac9..215ee84 100644
--- a/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java
@@ -72,7 +72,7 @@
                 inPort = mg.getIngressPoint().toString();
                 log.info("Multicast Ingress: " + inPort);
             }
-            Set<ConnectPoint> eps = mg.getEgressPoints();
+            Set<ConnectPoint> eps = mg.getEgressConnectPoints();
             if (eps != null && !eps.isEmpty()) {
                 outPorts = eps.toString();
             }
diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java
new file mode 100644
index 0000000..e2a6ff0
--- /dev/null
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 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.mfwd.impl;
+
+import org.onosproject.net.ConnectPoint;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * Mulitcast ConnectPoint adds a variable to track the usage
+ * of these multicast endpoints.
+ */
+public class McastConnectPoint {
+
+    private ConnectPoint connectPoint;
+
+    public enum JoinSource {
+        STATIC, IGMP, PIM;
+    }
+
+    public EnumSet<JoinSource> interest = EnumSet.noneOf(JoinSource.class);
+
+    public McastConnectPoint(ConnectPoint cp) {
+        this.connectPoint = cp;
+    }
+
+    public McastConnectPoint(ConnectPoint cp, JoinSource src) {
+        this.connectPoint = cp;
+        interest.add(src);
+    }
+
+    public McastConnectPoint(String connectPoint, JoinSource src) {
+        ConnectPoint cp = ConnectPoint.deviceConnectPoint(connectPoint);
+        this.connectPoint = cp;
+        this.interest.add(src);
+    }
+
+    /**
+     * Get the connect point.
+     *
+     * @return connectPoint
+     */
+    public ConnectPoint getConnectPoint() {
+        return connectPoint;
+    }
+
+    /**
+     * Get the sources of interest for this egressPoint.
+     *
+     * @return interest flags
+     */
+    public Set<JoinSource> getInterest() {
+        return interest;
+    }
+}
diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
index bcba060..f5bd1e0 100644
--- a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java
@@ -222,7 +222,7 @@
     private void forwardPacketToDst(PacketContext context, McastRoute entry) {
 
         // Send the pack out each of the respective egress ports
-        for (ConnectPoint egress : entry.getEgressPoints()) {
+        for (ConnectPoint egress : entry.getEgressConnectPoints()) {
             TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                     .setOutput(egress.port()).build();
 
diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java
index c3709e6..90f65c9 100644
--- a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java
@@ -101,8 +101,8 @@
                         .appId(McastForwarding.getAppId())
                         .selector(selector.build())
                         .treatment(treatment)
-                        .ingressPoint(mroute.getIngressPoint())
-                        .egressPoints(mroute.getEgressPoints()).
+                        .ingressPoint(mroute.getIngressPoint().getConnectPoint())
+                        .egressPoints(mroute.getEgressConnectPoints()).
                         build();
 
         intentService.submit(intent);
diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
index d56488e..e78c257 100644
--- a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java
@@ -57,48 +57,91 @@
     public boolean isIp6();
 
     /**
-     * Add the ingress ConnectPoint with a ConnectPoint.
+     * Add the ingress ConnectPoint.
      *
-     * @param ingress ingress point
+     * @param cpstr string representing a ConnectPoint
+     * @return whether ingress has been added, only add if ingressPoint is null
      */
-    public void addIngressPoint(ConnectPoint ingress);
+    public boolean addIngressPoint(String cpstr);
 
     /**
-     * Add the ingress Connect Point using. ..
+     * Add the ingress ConnectPoint.
      *
-     * @param deviceId device ID
-     * @param portNum port number
+     * @param cp the ConnectPoint of incoming traffic.
+     * @return whether ingress has been added, only add if ingressPoint is null
      */
-    public void addIngressPoint(String deviceId, long portNum);
+    public boolean addIngressPoint(ConnectPoint cp);
 
     /**
      * Get the ingress connect point.
      *
      * @return the ingress connect point
      */
-    public ConnectPoint getIngressPoint();
+    public McastConnectPoint getIngressPoint();
 
     /**
      * Add an egress connect point.
      *
-     * @param member the egress ConnectPoint to be added
+     * @param cp the egress McastConnectPoint to be added
+     * @return return the McastConnectPoint
      */
-    public void addEgressPoint(ConnectPoint member);
+    public McastConnectPoint addEgressPoint(ConnectPoint cp);
 
     /**
      * Add an egress connect point.
      *
-     * @param deviceId the device ID of the connect point
-     * @param portNum the port number of the connect point
+     * @param connectPoint deviceId/portNum
+     * @return return the McastConnectPoint
      */
-    public void addEgressPoint(String deviceId, long portNum);
+    public McastConnectPoint addEgressPoint(String connectPoint);
+
+    /**
+     * Add an egress connect point.
+     *
+     * @param cp the egress McastConnectPoint to be added
+     * @param interest the protocol that has shown interest in this route
+     * @return return the McastConnectPoint
+     */
+    public McastConnectPoint addEgressPoint(ConnectPoint cp, McastConnectPoint.JoinSource interest);
+
+    /**
+     * Add an egress connect point.
+     *
+     * @param connectPoint deviceId/portNum
+     * @param interest the protocol that has shown interest in this route
+     * @return return the McastConnectPoint
+     */
+    public McastConnectPoint addEgressPoint(String connectPoint, McastConnectPoint.JoinSource interest);
 
     /**
      * Get the egress connect points.
      *
      * @return a set of egress connect points
      */
-    public Set<ConnectPoint> getEgressPoints();
+    public Set<McastConnectPoint> getEgressPoints();
+
+    /**
+     * Get the egress connect points.
+     *
+     * @return a set of egress connect points
+     */
+    public Set<ConnectPoint> getEgressConnectPoints();
+
+    /**
+     * Find the egress connect point if it exists.
+     *
+     * @return the connect point when found, null otherwise.
+     */
+    public McastConnectPoint findEgressConnectPoint(ConnectPoint cp);
+
+    /**
+     * remove Interest from a McastConnectPoint.
+     *
+     * @param mcp connect point.
+     * @param interest the protocol interested in this multicast stream
+     * @return whether or not interest was removed
+     */
+    public boolean removeInterest(McastConnectPoint mcp, McastConnectPoint.JoinSource interest);
 
     /**
      * Increment the punt count.
diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
index 36582ad..730acfa 100644
--- a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java
@@ -17,10 +17,9 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import org.apache.commons.collections.set.ListOrderedSet;
 import org.onlab.packet.IpPrefix;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
 import org.onosproject.net.intent.SinglePointToMultiPointIntent;
 import org.onosproject.net.intent.Key;
 
@@ -34,11 +33,13 @@
     protected final IpPrefix gaddr;
     protected final IpPrefix saddr;
 
-    protected ConnectPoint ingressPoint;
-    protected Set<ConnectPoint> egressPoints;
+    protected McastConnectPoint ingressPoint;
+    protected Set<McastConnectPoint> egressPoints;
 
     protected boolean isGroup = false;
 
+    protected boolean dirty = false;
+
     /**
      * How may times has this packet been punted.
      */
@@ -160,58 +161,120 @@
     }
 
     /**
+     * Get the dirty state.
+     *
+     * @return whether this route is dirty or not.
+     */
+    public boolean getDirty() {
+        return this.dirty;
+    }
+
+    /**
+     * Set the dirty state to indicate that something changed.
+     * This may require an update to the flow tables (intents).
+     *
+     * @param dirty set the dirty bit
+     */
+    public void setDirty(boolean dirty) {
+        this.dirty = dirty;
+    }
+
+    /**
      * Add an ingress point to this route.
      *
      * @param ingress incoming connect point
+     * @return whether ingress has been added, only add if ingressPoint is null
      */
-    @Override
-    public void addIngressPoint(ConnectPoint ingress) {
-        ingressPoint = checkNotNull(ingress);
+    public boolean addIngressPoint(ConnectPoint ingress) {
+
+        // Do NOT add the ingressPoint if it is not null.
+        if (this.ingressPoint != null) {
+            // TODO: Log an warning.
+            return false;
+        }
+        this.ingressPoint = new McastConnectPoint(checkNotNull(ingress));
+        setDirty(true);
+        return true;
     }
 
     /**
      * Add or modify the ingress connect point.
      *
-     * @param deviceId the switch device Id
-     * @param portNum the ingress port number
+     * @param connectPoint string switch device Id
+     * @return whether ingress has been added, only add if ingressPoint is null
      */
-    @Override
-    public void addIngressPoint(String deviceId, long portNum) {
-        ingressPoint = new ConnectPoint(
-                DeviceId.deviceId(deviceId),
-                PortNumber.portNumber(portNum));
+    public boolean addIngressPoint(String connectPoint) {
+
+        if (this.ingressPoint != null) {
+            // TODO: log a warning.
+            return false;
+        }
+        ConnectPoint cp = ConnectPoint.deviceConnectPoint(checkNotNull(connectPoint));
+        return this.addIngressPoint(cp);
     }
 
     /**
-     * Get the ingress ConnectPoint.
+     * Get the ingress McastConnectPoint.
      *
-     * @return the ingress ConnectPoint
+     * @return the ingress McastConnectPoint
      */
-    @Override
-    public ConnectPoint getIngressPoint() {
+    public McastConnectPoint getIngressPoint() {
         return this.ingressPoint;
     }
 
     /**
-     * Add an egress ConnectPoint.
+     * Add an egress McastConnectPoint.
      *
-     * @param member member egress connect point
+     * @param cp egress connect point
+     * @return return the McastConnectPoint
      */
-    @Override
-    public void addEgressPoint(ConnectPoint member) {
-        egressPoints.add(checkNotNull(member));
+    public McastConnectPoint addEgressPoint(ConnectPoint cp) {
+        McastConnectPoint mcp = this.findEgressConnectPoint(cp);
+        if (mcp == null) {
+            mcp = new McastConnectPoint(checkNotNull(cp));
+            egressPoints.add(mcp);
+            setDirty(true);
+        }
+        return mcp;
     }
 
     /**
-     * Add an egress ConnectPoint.
+     * Add an egress connect point from a string.
      *
-     * @param deviceId deviceId of the connect point
-     * @param portNum portNum of the connect point
+     * @param connectPoint string representing a connect point
+     * @return the MulticastConnectPoint
      */
-    @Override
-    public void addEgressPoint(String deviceId, long portNum) {
-        ConnectPoint cp = new ConnectPoint(DeviceId.deviceId(deviceId), PortNumber.portNumber(portNum));
-        this.egressPoints.add(cp);
+    public McastConnectPoint addEgressPoint(String connectPoint) {
+        checkNotNull(connectPoint);
+        return this.addEgressPoint(ConnectPoint.deviceConnectPoint(connectPoint));
+    }
+
+    /**
+     * Add an egress McastConnectPoint.
+     *
+     * @param cp the egress connect point
+     * @param interest the source of interest for mcast traffic
+     */
+    public McastConnectPoint addEgressPoint(ConnectPoint cp, McastConnectPoint.JoinSource interest) {
+        checkNotNull(cp);
+        checkNotNull(interest);
+        McastConnectPoint mcp = this.addEgressPoint(cp);
+        if (mcp != null) {
+            mcp.interest.add(interest);
+            setDirty(true);
+        }
+        return mcp;
+    }
+
+    /**
+     * Add an egress McastConnectPoint.
+     *
+     * @param cpstr deviceId/port of the connect point
+     */
+    public McastConnectPoint addEgressPoint(String cpstr, McastConnectPoint.JoinSource interest) {
+        checkNotNull(cpstr);
+        checkNotNull(interest);
+        return this.addEgressPoint(ConnectPoint.deviceConnectPoint(cpstr), interest);
     }
 
     /**
@@ -219,12 +282,57 @@
      *
      * @return Set of egress connect points
      */
-    @Override
-    public Set<ConnectPoint> getEgressPoints() {
+    public Set<McastConnectPoint> getEgressPoints() {
         return egressPoints;
     }
 
     /**
+     * Get egress McastConnectPoints points as ConnectPoints for intent system.
+     *
+     * @return Set of egress ConnectPoints
+     */
+    public Set<ConnectPoint> getEgressConnectPoints() {
+        Set<ConnectPoint> cps = new ListOrderedSet();
+
+        for (McastConnectPoint mcp : egressPoints) {
+            cps.add(mcp.getConnectPoint());
+        }
+        return cps;
+    }
+
+    /**
+     * Find the Multicast Connect Point that contains the ConnectPoint.
+     *
+     * @param cp the regular ConnectPoint to match
+     * @return the McastConnectPoint that contains cp or null if not found.
+     */
+    public McastConnectPoint findEgressConnectPoint(ConnectPoint cp) {
+        for (McastConnectPoint mcp : this.egressPoints) {
+            if (mcp.getConnectPoint().equals(cp)) {
+                return mcp;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Remove specified interest from the given ConnectPoint.
+     *
+     * @param mcp connect point.
+     * @param interest the protocol interested in this multicast stream
+     * @return true if removed, false otherwise
+     */
+    public boolean removeInterest(McastConnectPoint mcp, McastConnectPoint.JoinSource interest) {
+        checkNotNull(mcp);
+        if (mcp.interest.contains(interest)) {
+            mcp.interest.remove(interest);
+            setDirty(true);
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Get the number of times the packet has been punted.
      *
      * @return the punt count
@@ -264,7 +372,7 @@
     /**
      * Set the Intent key.
      *
-     * @param intent intent
+     * @param intent the multicast intent
      */
     @Override
     public void setIntent(SinglePointToMultiPointIntent intent) {
@@ -312,8 +420,8 @@
         out += (ingressPoint == null) ? "NULL" : ingressPoint.toString();
         out += "\n\tegress: {\n";
         if (egressPoints != null && !egressPoints.isEmpty()) {
-            for (ConnectPoint eg : egressPoints) {
-                out += "\t\t" + eg.toString() + "\n";
+            for (McastConnectPoint eg : egressPoints) {
+                out += "\t\t" + eg.getConnectPoint().toString() + "\n";
             }
         }
         out += ("\t}\n");
diff --git a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
index ff7a026..5a07bec 100644
--- a/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
+++ b/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java
@@ -157,7 +157,7 @@
             if (gpfx.isIp4()) {
                 this.mrib4.put(gpfx, group);
             } else if (gpfx.isIp6() && ipv6Enabled) {
-                    this.mrib6.put(gpfx, group);
+                this.mrib6.put(gpfx, group);
             }
         }
 
@@ -259,7 +259,7 @@
         if (group.isIp4()) {
             g = mrib4.get(group);
         } else if (group.isIp6() && ipv6Enabled) {
-                g = mrib6.get(group);
+            g = mrib6.get(group);
         }
         return g;
     }