CORD-1622 CORD-1624 Add IPv6 mutlicast in McastHandler and OFDPA2.0 Drivers

Change-Id: Ibbb402b62999b39f8aea2cd236b959fc61fb94ac
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
index 9f91712..bbbbc3c 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
@@ -253,7 +253,7 @@
         }
 
         // Process the ingress device
-        addFilterToDevice(source.deviceId(), source.port(), assignedVlan(source));
+        addFilterToDevice(source.deviceId(), source.port(), assignedVlan(source), mcastIp);
 
         // When source and sink are on the same device
         if (source.deviceId().equals(sink.deviceId())) {
@@ -277,7 +277,7 @@
             links.forEach(link -> {
                 addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
                         assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
-                addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null));
+                addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null), mcastIp);
             });
 
             // Process the egress device
@@ -344,7 +344,7 @@
                     links.forEach(link -> {
                         addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
                                 assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
-                        addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null));
+                        addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null), mcastIp);
                     });
                     // Setup new transit mcast role
                     mcastRoleStore.put(new McastStoreKey(mcastIp,
@@ -365,7 +365,7 @@
      * @param port ingress port number
      * @param assignedVlan assigned VLAN ID
      */
-    private void addFilterToDevice(DeviceId deviceId, PortNumber port, VlanId assignedVlan) {
+    private void addFilterToDevice(DeviceId deviceId, PortNumber port, VlanId assignedVlan, IpAddress mcastIp) {
         // Do nothing if the port is configured as suppressed
         ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
         SegmentRoutingAppConfig appConfig = srManager.cfgService
@@ -376,7 +376,7 @@
         }
 
         FilteringObjective.Builder filtObjBuilder =
-                filterObjBuilder(deviceId, port, assignedVlan);
+                filterObjBuilder(deviceId, port, assignedVlan, mcastIp);
         ObjectiveContext context = new DefaultObjectiveContext(
                 (objective) -> log.debug("Successfully add filter on {}/{}, vlan {}",
                         deviceId, port.toLong(), assignedVlan),
@@ -596,9 +596,17 @@
     private ForwardingObjective.Builder fwdObjBuilder(IpAddress mcastIp,
             VlanId assignedVlan, int nextId) {
         TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
-        IpPrefix mcastPrefix = IpPrefix.valueOf(mcastIp, IpPrefix.MAX_INET_MASK_LENGTH);
-        sbuilder.matchEthType(Ethernet.TYPE_IPV4);
-        sbuilder.matchIPDst(mcastPrefix);
+        IpPrefix mcastPrefix = mcastIp.toIpPrefix();
+
+        if (mcastIp.isIp4()) {
+            sbuilder.matchEthType(Ethernet.TYPE_IPV4);
+            sbuilder.matchIPDst(mcastPrefix);
+        } else {
+            sbuilder.matchEthType(Ethernet.TYPE_IPV6);
+            sbuilder.matchIPv6Dst(mcastPrefix);
+        }
+
+
         TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
         metabuilder.matchVlanId(assignedVlan);
 
@@ -621,14 +629,22 @@
      * @return filtering objective builder
      */
     private FilteringObjective.Builder filterObjBuilder(DeviceId deviceId, PortNumber ingressPort,
-            VlanId assignedVlan) {
+            VlanId assignedVlan, IpAddress mcastIp) {
         FilteringObjective.Builder filtBuilder = DefaultFilteringObjective.builder();
-        filtBuilder.withKey(Criteria.matchInPort(ingressPort))
-                .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
-                        MacAddress.IPV4_MULTICAST_MASK))
-                .addCondition(Criteria.matchVlanId(egressVlan()))
-                .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
 
+        if (mcastIp.isIp4()) {
+            filtBuilder.withKey(Criteria.matchInPort(ingressPort))
+            .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
+                    MacAddress.IPV4_MULTICAST_MASK))
+            .addCondition(Criteria.matchVlanId(egressVlan()))
+            .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
+        } else {
+            filtBuilder.withKey(Criteria.matchInPort(ingressPort))
+            .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV6_MULTICAST,
+                     MacAddress.IPV6_MULTICAST_MASK))
+            .addCondition(Criteria.matchVlanId(egressVlan()))
+            .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
+        }
         TrafficTreatment tt = DefaultTrafficTreatment.builder()
                 .pushVlan().setVlanId(assignedVlan).build();
         filtBuilder.withMeta(tt);
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
index 95dcfa1..9f2e84c 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2Pipeline.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
@@ -491,10 +492,30 @@
                         + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
             }
         } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
-            if (buildIpv6Selector(filteredSelector, fwd) < 0) {
-                return Collections.emptyList();
+            IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
+            if (ipv6Dst.isMulticast()) {
+                if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
+                    log.debug("Multicast specific IPv6 forwarding objective can only be /128");
+                    fail(fwd, ObjectiveError.BADPARAMS);
+                    return ImmutableSet.of();
+                }
+                VlanId assignedVlan = readVlanFromSelector(fwd.meta());
+                if (assignedVlan == null) {
+                    log.debug("VLAN ID required by multicast specific fwd obj is missing. Abort.");
+                    fail(fwd, ObjectiveError.BADPARAMS);
+                    return ImmutableSet.of();
+                }
+                filteredSelector.matchVlanId(assignedVlan);
+                filteredSelector.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
+                forTableId = MULTICAST_ROUTING_TABLE;
+                log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
+                        + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
+            } else {
+                if (buildIpv6Selector(filteredSelector, fwd) < 0) {
+                    return Collections.emptyList();
+                }
+                forTableId = UNICAST_ROUTING_TABLE;
             }
-            forTableId = UNICAST_ROUTING_TABLE;
         } else {
             filteredSelector
                 .matchEthType(Ethernet.MPLS_UNICAST)
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
index cc85cbf..c0c6639 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Sets;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
@@ -857,6 +858,7 @@
 
     protected List<FlowRule> processMcastEthDstFilter(EthCriterion ethCriterion,
                                                       ApplicationId applicationId) {
+        ImmutableList.Builder<FlowRule> builder = ImmutableList.builder();
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
         selector.matchEthType(Ethernet.TYPE_IPV4);
@@ -870,7 +872,22 @@
                 .fromApp(applicationId)
                 .makePermanent()
                 .forTable(TMAC_TABLE).build();
-        return ImmutableList.<FlowRule>builder().add(rule).build();
+        builder.add(rule);
+
+        selector = DefaultTrafficSelector.builder();
+        treatment = DefaultTrafficTreatment.builder();
+        selector.matchEthType(Ethernet.TYPE_IPV6);
+        selector.matchEthDstMasked(ethCriterion.mac(), ethCriterion.mask());
+        treatment.transition(MULTICAST_ROUTING_TABLE);
+        rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DEFAULT_PRIORITY)
+                .fromApp(applicationId)
+                .makePermanent()
+                .forTable(TMAC_TABLE).build();
+        return builder.add(rule).build();
     }
 
     private Collection<FlowRule> processForward(ForwardingObjective fwd) {
@@ -1281,16 +1298,34 @@
 
         IpPrefix ipv6Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
         if (ipv6Dst.isMulticast()) {
-            log.warn("IPv6 Multicast is currently not supported");
-            fail(fwd, ObjectiveError.BADPARAMS);
-            return -1;
-        }
-        if (ipv6Dst.prefixLength() != 0) {
-            builderToUpdate.matchIPv6Dst(ipv6Dst);
-        }
+            if (ipv6Dst.prefixLength() != IpAddress.INET6_BIT_LENGTH) {
+                log.warn("Multicast specific forwarding objective can only be /128");
+                fail(fwd, ObjectiveError.BADPARAMS);
+                return -1;
+            }
+            VlanId assignedVlan = readVlanFromSelector(fwd.meta());
+            if (assignedVlan == null) {
+                log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
+                fail(fwd, ObjectiveError.BADPARAMS);
+                return -1;
+            }
+            if (requireVlanExtensions()) {
+                OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan);
+                builderToUpdate.extension(ofdpaMatchVlanVid, deviceId);
+            } else {
+                builderToUpdate.matchVlanId(assignedVlan);
+            }
+            builderToUpdate.matchEthType(Ethernet.TYPE_IPV6).matchIPv6Dst(ipv6Dst);
+            log.debug("processing IPv6 multicast specific forwarding objective {} -> next:{}"
+                              + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
+        } else {
+           if (ipv6Dst.prefixLength() != 0) {
+               builderToUpdate.matchIPv6Dst(ipv6Dst);
+           }
         builderToUpdate.matchEthType(Ethernet.TYPE_IPV6);
         log.debug("processing IPv6 unicast specific forwarding objective {} -> next:{}"
                               + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
+        }
         return 0;
     }
 
diff --git a/utils/misc/src/main/java/org/onlab/packet/MacAddress.java b/utils/misc/src/main/java/org/onlab/packet/MacAddress.java
index e41fb05..b048794 100644
--- a/utils/misc/src/main/java/org/onlab/packet/MacAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/MacAddress.java
@@ -56,6 +56,14 @@
      */
     public static final MacAddress IPV4_MULTICAST_MASK = valueOf("ff:ff:ff:80:00:00");
     /**
+     * IPv6 multicast MAC address.
+     */
+    public static final MacAddress IPV6_MULTICAST = valueOf("33:33:00:00:00:00");
+    /**
+     * IPv6 multicast MAC mask.
+     */
+    public static final MacAddress IPV6_MULTICAST_MASK = valueOf("FF:FF:00:00:00:00");
+    /**
      * A set of LLDP MAC addresses.
      */
     public static final Set<MacAddress> LLDP = ImmutableSet.of(