[VOL-3816] Support PPPoED trap rules installation on Olt app.

Signed-off-by: Gustavo Silva <gsilva@furukawalatam.com>
Change-Id: I71868eddbeecc688095e7966b76f42fb158095ed
diff --git a/app/src/main/java/org/opencord/olt/impl/Olt.java b/app/src/main/java/org/opencord/olt/impl/Olt.java
index 408004c..24073b0 100644
--- a/app/src/main/java/org/opencord/olt/impl/Olt.java
+++ b/app/src/main/java/org/opencord/olt/impl/Olt.java
@@ -629,6 +629,8 @@
                                                       upstreamMeterId, uniTag, false, true);
         oltFlowService.processDhcpFilteringObjectives(deviceId, subscriberPort,
                                                       upstreamMeterId, uniTag, false, true);
+        oltFlowService.processPPPoEDFilteringObjectives(deviceId, subscriberPort,
+                                                        upstreamMeterId, uniTag, false, true);
 
         flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
             @Override
@@ -964,6 +966,11 @@
                                                               subscriberFlowInfo.getUniPort(),
                                                               subscriberFlowInfo.getUpId(),
                                                               tagInfo, true, true);
+
+                oltFlowService.processPPPoEDFilteringObjectives(subscriberFlowInfo.getDevId(),
+                                                                subscriberFlowInfo.getUniPort(),
+                                                                subscriberFlowInfo.getUpId(),
+                                                                tagInfo, true, true);
                 updateProgrammedSubscriber(new ConnectPoint(subscriberFlowInfo.getDevId(),
                                                             subscriberFlowInfo.getUniPort()),
                                            tagInfo, true);
diff --git a/app/src/main/java/org/opencord/olt/impl/OltFlowService.java b/app/src/main/java/org/opencord/olt/impl/OltFlowService.java
index 429dd95..14fa4f9 100644
--- a/app/src/main/java/org/opencord/olt/impl/OltFlowService.java
+++ b/app/src/main/java/org/opencord/olt/impl/OltFlowService.java
@@ -84,6 +84,7 @@
         ENABLE_DHCP_V6 + ":Boolean=" + ENABLE_DHCP_V6_DEFAULT,
         ENABLE_IGMP_ON_NNI + ":Boolean=" + ENABLE_IGMP_ON_NNI_DEFAULT,
         ENABLE_EAPOL + ":Boolean=" + ENABLE_EAPOL_DEFAULT,
+        ENABLE_PPPOE + ":Boolean=" + ENABLE_PPPOE_DEFAULT,
         DEFAULT_TP_ID + ":Integer=" + DEFAULT_TP_ID_DEFAULT
 })
 public class OltFlowService implements AccessDeviceFlowService {
@@ -149,6 +150,11 @@
     protected boolean enableEapol = ENABLE_EAPOL_DEFAULT;
 
     /**
+     * Send PPPoED authentication trap flows before subscriber provisioning.
+     **/
+    protected boolean enablePppoe = ENABLE_PPPOE_DEFAULT;
+
+    /**
      * Default technology profile id that is used for authentication trap flows.
      **/
     protected int defaultTechProfileId = DEFAULT_TP_ID_DEFAULT;
@@ -205,14 +211,20 @@
             enableEapol = eap;
         }
 
+        Boolean pppoe = Tools.isPropertyEnabled(properties, ENABLE_PPPOE);
+        if (pppoe != null) {
+            enablePppoe = pppoe;
+        }
+
         String tpId = get(properties, DEFAULT_TP_ID);
         defaultTechProfileId = isNullOrEmpty(tpId) ? DEFAULT_TP_ID_DEFAULT : Integer.parseInt(tpId.trim());
 
         log.info("modified. Values = enableDhcpOnNni: {}, enableDhcpV4: {}, " +
                          "enableDhcpV6:{}, enableIgmpOnNni:{}, " +
-                         "enableEapol{}, defaultTechProfileId: {}",
+                         "enableEapol{}, enablePppoe{}, defaultTechProfileId: {}",
                  enableDhcpOnNni, enableDhcpV4, enableDhcpV6,
-                 enableIgmpOnNni, enableEapol, defaultTechProfileId);
+                 enableIgmpOnNni, enableEapol,  enablePppoe,
+                 defaultTechProfileId);
 
     }
 
@@ -332,6 +344,77 @@
     }
 
     @Override
+    public void processPPPoEDFilteringObjectives(DeviceId devId, PortNumber portNumber,
+                                                 MeterId upstreamMeterId,
+                                                 UniTagInformation tagInformation,
+                                                 boolean install,
+                                                 boolean upstream) {
+        if (!enablePppoe) {
+            log.debug("PPPoED filtering is disabled. Ignoring request.");
+            return;
+        }
+
+        int techProfileId = NONE_TP_ID;
+        VlanId cTag = VlanId.NONE;
+        VlanId unitagMatch = VlanId.ANY;
+        Byte vlanPcp = null;
+
+        if (tagInformation != null) {
+            techProfileId = tagInformation.getTechnologyProfileId();
+            cTag = tagInformation.getPonCTag();
+            unitagMatch = tagInformation.getUniTagMatch();
+            if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
+                vlanPcp = (byte) tagInformation.getUsPonCTagPriority();
+            }
+        }
+
+        DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+        CompletableFuture<Object> meterFuture = new CompletableFuture<>();
+
+        if (upstreamMeterId != null) {
+            treatmentBuilder.meter(upstreamMeterId);
+        }
+
+        if (techProfileId != NONE_TP_ID) {
+            treatmentBuilder.writeMetadata(createTechProfValueForWm(cTag, techProfileId), 0);
+        }
+
+        DefaultFilteringObjective.Builder pppoedBuilder = (install ? builder.permit() : builder.deny())
+                .withKey(Criteria.matchInPort(portNumber))
+                .addCondition(Criteria.matchEthType(EthType.EtherType.PPPoED.ethType()))
+                .fromApp(appId)
+                .withPriority(10000);
+
+        if (upstream) {
+            treatmentBuilder.setVlanId(cTag);
+            if (!VlanId.vlanId(VlanId.NO_VID).equals(unitagMatch)) {
+                pppoedBuilder.addCondition(Criteria.matchVlanId(unitagMatch));
+            }
+            if (vlanPcp != null) {
+                treatmentBuilder.setVlanPcp(vlanPcp);
+            }
+        }
+        pppoedBuilder = pppoedBuilder.withMeta(treatmentBuilder.setOutput(PortNumber.CONTROLLER).build());
+
+        FilteringObjective pppoed = pppoedBuilder
+                .add(new ObjectiveContext() {
+                    @Override
+                    public void onSuccess(Objective objective) {
+                        log.info("PPPoED filter for {} on {} {}.",
+                                devId, portNumber, (install) ? INSTALLED : REMOVED);
+                    }
+
+                    @Override
+                    public void onError(Objective objective, ObjectiveError error) {
+                        log.info("PPPoED filter for {} on {} failed {} because {}",
+                                devId, portNumber, (install) ? INSTALLATION : REMOVAL, error);
+                    }
+                });
+        flowObjectiveService.filter(devId, pppoed);
+    }
+
+    @Override
     public void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
                                                MeterId upstreamMeterId,
                                                UniTagInformation tagInformation,
@@ -590,6 +673,7 @@
         processLldpFilteringObjective(devId, port, install);
         processDhcpFilteringObjectives(devId, port, null, null, install, false);
         processIgmpFilteringObjectives(devId, port, null, null, install, false);
+        processPPPoEDFilteringObjectives(devId, port, null, null, install, false);
     }
 
 
diff --git a/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java b/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java
index 82d414c..3d76ef6 100644
--- a/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java
+++ b/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java
@@ -51,6 +51,9 @@
     public static final String ENABLE_EAPOL = "enableEapol";
     public static final boolean ENABLE_EAPOL_DEFAULT = true;
 
+    public static final String ENABLE_PPPOE = "enablePppoe";
+    public static final boolean ENABLE_PPPOE_DEFAULT = false;
+
     public static final String EAPOL_DELETE_RETRY_MAX_ATTEMPS = "eapolDeleteRetryMaxAttempts";
     public static final int EAPOL_DELETE_RETRY_MAX_ATTEMPS_DEFAULT = 3;
 
diff --git a/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceFlowService.java b/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceFlowService.java
index d4cc09f..7de5b1a 100644
--- a/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceFlowService.java
+++ b/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceFlowService.java
@@ -80,6 +80,23 @@
                                          VlanId vlanId, boolean install);
 
     /**
+     * Trap PPPoE discovery packets to the controller.
+     *
+     * @param devId           the target device identifier
+     * @param portNumber      the uni port for which this trap flow is designated
+     * @param upstreamMeterId the upstream meter id that includes the upstream
+     *                        bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
+     *                        null can be sent
+     * @param tagInformation  the uni tag (ctag, stag) information
+     * @param install         true to install the flow, false to remove the flow
+     * @param upstream        true if trapped packets are flowing upstream towards
+     *                        server, false if packets are flowing downstream towards client
+     **/
+    void processPPPoEDFilteringObjectives(DeviceId devId, PortNumber portNumber,
+                                          MeterId upstreamMeterId, UniTagInformation tagInformation,
+                                          boolean install, boolean upstream);
+
+    /**
      * Trap lldp packets to the controller.
      *
      * @param devId   the device identifier
diff --git a/app/src/test/java/org/opencord/olt/impl/OltFlowTest.java b/app/src/test/java/org/opencord/olt/impl/OltFlowTest.java
index 033945e..3283886 100644
--- a/app/src/test/java/org/opencord/olt/impl/OltFlowTest.java
+++ b/app/src/test/java/org/opencord/olt/impl/OltFlowTest.java
@@ -182,6 +182,42 @@
     }
 
     @Test
+    public void testPppoedFiltering() {
+        oltFlowService.flowObjectiveService.clearQueue();
+
+        // ensure pppoed traps are not added if global config is off.
+        oltFlowService.enablePppoe = false;
+        oltFlowService.processPPPoEDFilteringObjectives(DEVICE_ID_1, uniPortNumber,
+                                                        usMeterId, uniTagInfo,
+                                                        true, true);
+        assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 0;
+
+        // ensure upstream pppoed traps can be added and removed
+        oltFlowService.enablePppoe = true;
+        oltFlowService.processPPPoEDFilteringObjectives(DEVICE_ID_1, uniPortNumber,
+                                                        usMeterId, uniTagInfo,
+                                                        true, true);
+        assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 1;
+        oltFlowService.processPPPoEDFilteringObjectives(DEVICE_ID_1, uniPortNumber,
+                                                        usMeterId, uniTagInfo,
+                                                        false, true);
+        assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
+
+        // ensure downstream pppoed traps can be added and removed
+        oltFlowService.processPPPoEDFilteringObjectives(DEVICE_ID_1, nniPortNumber,
+                                                        null, null,
+                                                        true, false);
+        assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 3;
+        oltFlowService.processPPPoEDFilteringObjectives(DEVICE_ID_1, nniPortNumber,
+                                                        null, null,
+                                                        false, false);
+        assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 4;
+
+        // cleanup
+        oltFlowService.flowObjectiveService.clearQueue();
+    }
+
+    @Test
     public void testIgmpFiltering() {
         oltFlowService.flowObjectiveService.clearQueue();
 
diff --git a/app/src/test/java/org/opencord/olt/impl/TestBase.java b/app/src/test/java/org/opencord/olt/impl/TestBase.java
index bc5a4d6..4d7bcd5 100644
--- a/app/src/test/java/org/opencord/olt/impl/TestBase.java
+++ b/app/src/test/java/org/opencord/olt/impl/TestBase.java
@@ -81,7 +81,6 @@
     }
 
     private class MockBpService implements BaseInformationService<BandwidthProfileInformation> {
-
         @Override
         public void invalidateAll() {
 
diff --git a/pom.xml b/pom.xml
index c546be0..5dddfc1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onosproject</groupId>
         <artifactId>onos-dependencies</artifactId>
-        <version>2.2.3</version>
+        <version>2.2.8-b3</version>
     </parent>
 
     <groupId>org.opencord</groupId>