[VOL-4180] Multi UNI feature implemented to OLT application.

Change-Id: I3d45719ebdce304ba94652ed9de553e40d76a77c

EAPOL flow bug-fixed

review fixes finshed

Multi UNI feature implemented to OLT application.

- It's possible to fetch a meter by annotations. (OltPipeline)
- New meters can be created for bandwidth profiles of OLT device.
- Olt meterId is transported via writeMetadata so that voltha/rw-core can parse it and assign the correct meters to ONU and OLT flows.

Change-Id: Ia6c9909b5f03b0f3fe329bd11580f891bfab3a32
diff --git a/impl/src/main/java/org/opencord/olt/driver/OltPipeline.java b/impl/src/main/java/org/opencord/olt/driver/OltPipeline.java
index 5232eb8..459526c 100644
--- a/impl/src/main/java/org/opencord/olt/driver/OltPipeline.java
+++ b/impl/src/main/java/org/opencord/olt/driver/OltPipeline.java
@@ -94,6 +94,10 @@
 import java.util.stream.Collectors;
 
 import static org.onosproject.core.CoreService.CORE_APP_NAME;
+import static org.opencord.olt.impl.OsgiPropertyConstants.DOWNSTREAM_OLT;
+import static org.opencord.olt.impl.OsgiPropertyConstants.DOWNSTREAM_ONU;
+import static org.opencord.olt.impl.OsgiPropertyConstants.UPSTREAM_OLT;
+import static org.opencord.olt.impl.OsgiPropertyConstants.UPSTREAM_ONU;
 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -542,7 +546,7 @@
     private void installNoModificationRules(ForwardingObjective fwd) {
         Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
         Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
-        Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
+        Instructions.MeterInstruction meter = fwd.treatment().metered();
 
         TrafficSelector selector = fwd.selector();
 
@@ -627,6 +631,9 @@
     private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
                                                 TrafficSelector outerSelector, TrafficSelector innerSelector) {
 
+        Instruction onuDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_ONU));
+        Instruction oltDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_OLT));
+
         List<Pair<Instruction, Instruction>> vlanOps =
                 vlanOps(fwd,
                         L2ModificationInstruction.L2SubType.VLAN_POP);
@@ -640,11 +647,11 @@
         TrafficTreatment innerTreatment;
         VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
         if (VlanId.NONE.equals(setVlanId)) {
-            innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
-                                             writeMetadataIncludingOnlyTp(fwd), output));
+            innerTreatment = (buildTreatment(popAndRewrite.getLeft(), onuDsMeter,
+                    writeMetadataIncludingOnlyTp(fwd), output));
         } else {
             innerTreatment = (buildTreatment(popAndRewrite.getRight(),
-                                             fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
+                    onuDsMeter, writeMetadataIncludingOnlyTp(fwd), output));
         }
 
         List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
@@ -676,7 +683,7 @@
                 .withPriority(fwd.priority())
                 .withSelector(outerSelector)
                 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
-                                              innerPbitSet, fetchMeter(fwd),
+                                              innerPbitSet, oltDsMeter,
                                               fetchWriteMetadata(fwd),
                                               Instructions.transition(QQ_TABLE)));
 
@@ -696,6 +703,9 @@
     private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
                                                   TrafficSelector outerSelector, TrafficSelector innerSelector) {
 
+        Instruction onuDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_ONU));
+        Instruction oltDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_OLT));
+
         //match: in port (nni), s-tag
         //action: immediate: write metadata, pop vlan, meter and go to table 1
         FlowRule.Builder outer = DefaultFlowRule.builder()
@@ -704,7 +714,7 @@
                 .makePermanent()
                 .withPriority(fwd.priority())
                 .withSelector(outerSelector)
-                .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
+                .withTreatment(buildTreatment(Instructions.popVlan(), oltDsMeter,
                                               fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
 
         //match: in port (nni) and s-tag
@@ -716,8 +726,7 @@
                 .makePermanent()
                 .withPriority(fwd.priority())
                 .withSelector(innerSelector)
-                .withTreatment(buildTreatment(fetchMeter(fwd),
-                                              writeMetadataIncludingOnlyTp(fwd), output));
+                .withTreatment(buildTreatment(onuDsMeter, writeMetadataIncludingOnlyTp(fwd), output));
 
         applyRules(fwd, inner, outer);
     }
@@ -755,6 +764,9 @@
                                               Pair<Instruction, Instruction> innerPair,
                                               Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
 
+        Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
+        Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
+
         List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
                                                            fwd.treatment().allInstructions());
 
@@ -768,11 +780,11 @@
 
         TrafficTreatment innerTreatment;
         if (noneValueVlanStatus) {
-            innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
+            innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), onuUsMeter,
                                             fetchWriteMetadata(fwd), innerPbitSet,
                                             Instructions.transition(QQ_TABLE));
         } else {
-            innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
+            innerTreatment = buildTreatment(innerPair.getRight(), onuUsMeter, fetchWriteMetadata(fwd),
                                             innerPbitSet, Instructions.transition(QQ_TABLE));
         }
 
@@ -803,8 +815,8 @@
                 .makePermanent()
                 .withPriority(fwd.priority())
                 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
-                                              fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
-                                              outerPbitSet, output));
+                        oltUsMeter, writeMetadataIncludingOnlyTp(fwd),
+                        outerPbitSet, output));
 
         if (innerPbitSet != null) {
             byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
@@ -821,6 +833,8 @@
                                                 Pair<Instruction, Instruction> outerPair) {
 
         log.debug("Installing upstream rules for any value vlan");
+        Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
+        Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
 
         //match: in port and any-vlan (coming from OLT app.)
         //action: write metadata, go to table 1 and meter
@@ -830,8 +844,7 @@
                 .makePermanent()
                 .withPriority(fwd.priority())
                 .withSelector(fwd.selector())
-                .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
-                                              fetchWriteMetadata(fwd)));
+                .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), onuUsMeter, fetchWriteMetadata(fwd)));
 
         //match: in port and any-vlan (coming from OLT app.)
         //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
@@ -843,7 +856,7 @@
                 .withPriority(fwd.priority())
                 .withSelector(fwd.selector())
                 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
-                                              fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
+                        oltUsMeter, writeMetadataIncludingOnlyTp(fwd), output));
 
         applyRules(fwd, inner, outer);
     }
@@ -886,16 +899,15 @@
         return output;
     }
 
-    private Instruction fetchMeter(ForwardingObjective fwd) {
-        Instruction meter = fwd.treatment().metered();
-
-        if (meter == null) {
-            log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
+    private Instruction fetchMeterById(ForwardingObjective fwd, String meterId) {
+        Optional<Instructions.MeterInstruction> meter = fwd.treatment().meters().stream()
+                .filter(meterInstruction -> meterInstruction.meterId().toString().equals(meterId)).findAny();
+        if (meter.isEmpty()) {
+            log.debug("Meter instruction is not found for the meterId: {} ", meterId);
             return null;
         }
-
-        log.debug("Meter instruction is found.");
-        return meter;
+        log.debug("Meter instruction is found for the meterId: {} ", meterId);
+        return meter.get();
     }
 
     private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {