First implementation of BngProgrammable API
- BngProgrammable interface moved to ONOS core
- BngProgrammable implementation in fabric pipeliner
Change-Id: Ia020d19f305d8819eef7f70453b14cb00fd31af8
diff --git a/pipelines/fabric/impl/BUILD b/pipelines/fabric/impl/BUILD
index e4b427e..3e8824d 100644
--- a/pipelines/fabric/impl/BUILD
+++ b/pipelines/fabric/impl/BUILD
@@ -6,6 +6,7 @@
"//pipelines/basic:onos-pipelines-basic",
"//core/store/serializers:onos-core-serializers",
"//apps/inbandtelemetry/api:onos-apps-inbandtelemetry-api",
+ "//drivers/p4runtime:onos-drivers-p4runtime",
]
osgi_jar_with_tests(
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/FabricPipeconfManager.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/FabricPipeconfManager.java
index 76122d9..f366e99 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/FabricPipeconfManager.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/FabricPipeconfManager.java
@@ -17,6 +17,8 @@
package org.onosproject.pipelines.fabric.impl;
import org.onosproject.inbandtelemetry.api.IntProgrammable;
+
+import org.onosproject.net.behaviour.BngProgrammable;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.pi.model.DefaultPiPipeconf;
import org.onosproject.net.pi.model.PiPipeconf;
@@ -26,6 +28,7 @@
import org.onosproject.p4runtime.model.P4InfoParserException;
import org.onosproject.pipelines.fabric.FabricPipeconfService;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricIntProgrammable;
+import org.onosproject.pipelines.fabric.impl.behaviour.bng.FabricBngProgrammable;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricInterpreter;
import org.onosproject.pipelines.fabric.impl.behaviour.pipeliner.FabricPipeliner;
import org.osgi.service.component.annotations.Activate;
@@ -47,6 +50,7 @@
private static final String INT_PROFILE_SUFFIX = "-int";
private static final String FULL_PROFILE_SUFFIX = "-full";
+ private static final String BNG_PROFILE_SUFFIX = "-bng";
private static Logger log = getLogger(FabricPipeconfLoader.class);
@@ -90,7 +94,10 @@
profileName.endsWith(FULL_PROFILE_SUFFIX)) {
pipeconfBuilder.addBehaviour(IntProgrammable.class, FabricIntProgrammable.class);
}
-
+ // Add BngProgrammable behavior for BNG-enabled pipelines.
+ if (profileName.endsWith(BNG_PROFILE_SUFFIX)) {
+ pipeconfBuilder.addBehaviour(BngProgrammable.class, FabricBngProgrammable.class);
+ }
return pipeconfBuilder.build();
}
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/FabricBngProgrammable.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/FabricBngProgrammable.java
new file mode 100644
index 0000000..9b566c0
--- /dev/null
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/FabricBngProgrammable.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * 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.pipelines.fabric.impl.behaviour.bng;
+
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.drivers.p4runtime.AbstractP4RuntimeHandlerBehaviour;
+import org.onosproject.net.behaviour.BngProgrammable;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TableId;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PiCriterion;
+import org.onosproject.net.pi.model.PiCounterId;
+import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionParam;
+import org.onosproject.net.pi.runtime.PiCounterCell;
+import org.onosproject.net.pi.runtime.PiCounterCellData;
+import org.onosproject.net.pi.runtime.PiCounterCellHandle;
+import org.onosproject.net.pi.runtime.PiCounterCellId;
+import org.onosproject.p4runtime.api.P4RuntimeWriteClient;
+import org.onosproject.pipelines.fabric.impl.behaviour.FabricConstants;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class FabricBngProgrammable extends AbstractP4RuntimeHandlerBehaviour
+ implements BngProgrammable {
+
+ // Default priority of the inserted BNG rules.
+ private static final int DEFAULT_PRIORITY = 10;
+ // The index at which control plane packets are counted before the attachment is created.
+ private static final int DEFAULT_CONTROL_INDEX = 0;
+ // FIXME: retrieve this value from the table size in the PipelineModel
+ // Max number of supported attachments, useful to make sure to not read/write non-existing counters.
+ private static final int MAX_SUPPORTED_ATTACHMENTS = 1000;
+
+ private static final ImmutableBiMap<BngCounterType, PiCounterId> COUNTER_MAP =
+ ImmutableBiMap.<BngCounterType, PiCounterId>builder()
+ .put(BngCounterType.DOWNSTREAM_RX, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_C_LINE_RX)
+ .put(BngCounterType.DOWNSTREAM_TX, FabricConstants.FABRIC_EGRESS_BNG_EGRESS_DOWNSTREAM_C_LINE_TX)
+ .put(BngCounterType.UPSTREAM_TX, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_C_TERMINATED)
+ .put(BngCounterType.UPSTREAM_DROPPED, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_C_DROPPED)
+ .put(BngCounterType.CONTROL_PLANE, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_C_CONTROL)
+ .build();
+
+ // FIXME: add these counters to the BNG pipeline
+ private static final ImmutableSet<BngCounterType> UNSUPPORTED_COUNTER =
+ ImmutableSet.of(BngCounterType.UPSTREAM_RX, BngCounterType.DOWNSTREAM_DROPPED);
+
+ private FlowRuleService flowRuleService;
+
+ @Override
+ protected boolean setupBehaviour(String opName) {
+ if (!super.setupBehaviour(opName)) {
+ return false;
+ }
+ flowRuleService = handler().get(FlowRuleService.class);
+ return true;
+ }
+
+ @Override
+ public boolean init(ApplicationId appId) {
+ if (setupBehaviour("init()")) {
+ this.setupPuntToCpu(appId);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void cleanUp(ApplicationId appId) throws BngProgrammableException {
+ flowRuleService.removeFlowRulesById(appId);
+ this.resetControlTrafficCounter();
+ }
+
+ @Override
+ public void setupAttachment(Attachment attachmentInfo) throws BngProgrammableException {
+ checkArgument(attachmentInfo.type() == Attachment.AttachmentType.PPPoE);
+ List<FlowRule> lstFlowRules = Lists.newArrayList();
+ lstFlowRules.add(buildTLineMapFlowRule(attachmentInfo));
+ // If the line is not active do not generate the rule for the table
+ // t_pppoe_term_v4 since term_disabled is @defaultonly action
+ if (attachmentInfo.lineActive()) {
+ lstFlowRules.add(buildTPppoeTermV4FlowRule(attachmentInfo));
+ }
+ lstFlowRules.add(buildTLineSessionMapFlowRule(attachmentInfo));
+ // Clean-up attachment related counters
+ this.resetCounters(attachmentInfo);
+ lstFlowRules.forEach(flowRule -> flowRuleService.applyFlowRules(flowRule));
+ }
+
+ @Override
+ public void removeAttachment(Attachment attachmentInfo) {
+ checkArgument(attachmentInfo.type() == Attachment.AttachmentType.PPPoE);
+ List<FlowRule> lstFlowRules = Lists.newArrayList();
+ lstFlowRules.add(buildTLineMapFlowRule(attachmentInfo));
+ lstFlowRules.add(buildTPppoeTermV4FlowRule(attachmentInfo));
+ lstFlowRules.add(buildTLineSessionMapFlowRule(attachmentInfo));
+
+ lstFlowRules.forEach(flowRule -> flowRuleService.removeFlowRules(flowRule));
+ }
+
+ @Override
+ public Map<BngCounterType, PiCounterCellData> readCounters(Attachment attachmentInfo)
+ throws BngProgrammableException {
+ checkArgument(attachmentInfo.type() == Attachment.AttachmentType.PPPoE);
+ return readCounters(attachmentInfo.attachmentId().id(), Set.of(BngCounterType.values()));
+ }
+
+ @Override
+ public PiCounterCellData readCounter(Attachment attachmentInfo, BngCounterType counter)
+ throws BngProgrammableException {
+ checkArgument(attachmentInfo.type() == Attachment.AttachmentType.PPPoE);
+ return readCounters(attachmentInfo.attachmentId().id(), Set.of(counter))
+ .getOrDefault(counter, null);
+ }
+
+ @Override
+ public void resetCounters(Attachment attachmentInfo)
+ throws BngProgrammableException {
+ checkArgument(attachmentInfo.type() == Attachment.AttachmentType.PPPoE);
+ resetCounters(attachmentInfo.attachmentId().id(), Set.of(BngCounterType.values()));
+ }
+
+ @Override
+ public PiCounterCellData readControlTrafficCounter()
+ throws BngProgrammableException {
+ return readCounters(DEFAULT_CONTROL_INDEX, Set.of(BngCounterType.CONTROL_PLANE))
+ .get(BngCounterType.CONTROL_PLANE);
+ }
+
+ @Override
+ public void resetCounter(Attachment attachmentInfo, BngCounterType counter)
+ throws BngProgrammableException {
+ resetCounters(attachmentInfo.attachmentId().id(), Set.of(counter));
+ }
+
+ @Override
+ public void resetControlTrafficCounter() throws BngProgrammableException {
+ resetCounters(DEFAULT_CONTROL_INDEX, Set.of((BngCounterType.CONTROL_PLANE)));
+ }
+
+ /**
+ * Read the specified counter at a specific index.
+ *
+ * @param index The index of the counter.
+ * @param counters The set of counters to read.
+ * @throws BngProgrammableException
+ */
+ private Map<BngCounterType, PiCounterCellData> readCounters(
+ long index,
+ Set<BngCounterType> counters) throws BngProgrammableException {
+ checkIndex(index);
+ Map<BngCounterType, PiCounterCellData> readValues = Maps.newHashMap();
+ Set<PiCounterCellId> counterCellIds = counters.stream()
+ .filter(c -> !UNSUPPORTED_COUNTER.contains(c))
+ .map(c -> PiCounterCellId.ofIndirect(COUNTER_MAP.get(c), index))
+ .collect(Collectors.toSet());
+ // Check if there is any counter to read.
+ if (counterCellIds.size() != 0) {
+ Set<PiCounterCellHandle> counterCellHandles = counterCellIds.stream()
+ .map(cId -> PiCounterCellHandle.of(this.deviceId, cId))
+ .collect(Collectors.toSet());
+
+ // Query the device.
+ Collection<PiCounterCell> counterEntryResponse = client.read(
+ p4DeviceId, pipeconf)
+ .handles(counterCellHandles).submitSync()
+ .all(PiCounterCell.class);
+
+ if (counterEntryResponse.size() == 0) {
+ throw new BngProgrammableException(
+ String.format("Error in reading counters %s", counters.toString()));
+ }
+ readValues.putAll(counterEntryResponse.stream().collect(
+ Collectors.toMap(counterCell -> COUNTER_MAP.inverse()
+ .get(counterCell.cellId().counterId()),
+ PiCounterCell::data)));
+ }
+ return readValues;
+ }
+
+ /**
+ * Reset the specified counters at a specific index.
+ *
+ * @param index The index of the counter.
+ * @param counters The set of counters to reset.
+ */
+ private void resetCounters(long index, Set<BngCounterType> counters) throws BngProgrammableException {
+ checkIndex(index);
+ Set<PiCounterCellId> counterCellIds = counters.stream()
+ .filter(c -> !UNSUPPORTED_COUNTER.contains(c))
+ .map(c -> PiCounterCellId.ofIndirect(COUNTER_MAP.get(c), index))
+ .collect(Collectors.toSet());
+ if (counterCellIds.isEmpty()) {
+ // No counters to reset
+ log.info("No counters to reset.");
+ return;
+ }
+ Set<PiCounterCell> counterCellData = counterCellIds.stream()
+ .map(cId -> new PiCounterCell(cId, 0, 0))
+ .collect(Collectors.toSet());
+
+ // Query the device.
+ Collection<P4RuntimeWriteClient.EntityUpdateResponse> counterEntryResponse = client.write(
+ p4DeviceId, pipeconf)
+ .modify(counterCellData).submitSync()
+ .all();
+ counterEntryResponse.stream().filter(counterEntryResp -> !counterEntryResp.isSuccess())
+ .forEach(counterEntryResp -> log.warn("A counter was not reset correctly: {}",
+ counterEntryResp.explanation()));
+ }
+
+ /**
+ * Check if the index is in the range of max number of supported
+ * attachments.
+ *
+ * @param index
+ * @throws BngProgrammableException
+ */
+ private void checkIndex(long index) throws BngProgrammableException {
+ if (index > MAX_SUPPORTED_ATTACHMENTS) {
+ throw new BngProgrammableException("Counter index too big. Value:" +
+ index + ", MAX:" +
+ MAX_SUPPORTED_ATTACHMENTS);
+ }
+ }
+
+ /**
+ * Set the punt to CPU rules of the BNG from a specific Application ID.
+ *
+ * @param appId Application ID asking to recive BNG control plane packets.
+ */
+ private void setupPuntToCpu(ApplicationId appId) {
+ for (Criterion c : PuntCpuCriterionFactory.getAllPuntCriterion()) {
+ FlowRule flPuntCpu = buildTPppoeCpFlowRule((PiCriterion) c, appId);
+ flowRuleService.applyFlowRules(flPuntCpu);
+ }
+ }
+
+ /**
+ * Build the Flow Rule for the table t_pppoe_term_v4 of the ingress
+ * upstream.
+ *
+ * @param attachment
+ * @return
+ */
+ private FlowRule buildTPppoeTermV4FlowRule(Attachment attachment) {
+ PiCriterion criterion = PiCriterion.builder()
+ .matchExact(FabricConstants.HDR_LINE_ID,
+ attachment.attachmentId().id())
+ .matchExact(FabricConstants.HDR_IPV4_SRC,
+ attachment.ipAddress().toOctets())
+ .matchExact(FabricConstants.HDR_PPPOE_SESSION_ID,
+ attachment.pppoeSessionId())
+ // TODO: match on MAC SRC address (antispoofing)
+// .matchExact(FabricConstants.HDR_ETH_SRC,
+// attachment.macAddress.toBytes())
+ .build();
+ TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
+ .matchPi(criterion)
+ .build();
+ PiAction action = PiAction.builder()
+ .withId(attachment.lineActive() ?
+ FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_TERM_ENABLED_V4 :
+ FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_TERM_DISABLED)
+ .build();
+ TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
+ .piTableAction(action)
+ .build();
+ return buildFlowRule(trafficSelector,
+ instTreatment,
+ FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_T_PPPOE_TERM_V4,
+ attachment.appId());
+ }
+
+ /**
+ * Build the Flow Rule for the table t_line_session_map of the ingress
+ * downstream.
+ *
+ * @param attachment
+ * @return
+ */
+ private FlowRule buildTLineSessionMapFlowRule(Attachment attachment) {
+ PiCriterion criterion = PiCriterion.builder()
+ .matchExact(FabricConstants.HDR_LINE_ID,
+ attachment.attachmentId().id())
+ .build();
+ TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
+ .matchPi(criterion)
+ .build();
+ PiAction action;
+ if (attachment.lineActive()) {
+ action = PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_SET_SESSION)
+ .withParameter(new PiActionParam(FabricConstants.PPPOE_SESSION_ID,
+ attachment.pppoeSessionId()))
+ .build();
+ } else {
+ action = PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_DROP)
+ .build();
+ }
+ TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
+ .piTableAction(action)
+ .build();
+ return buildFlowRule(trafficSelector,
+ instTreatment,
+ FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_T_LINE_SESSION_MAP,
+ attachment.appId());
+ }
+
+ /**
+ * Build the flow rule for the table t_line_map of the BNG-U (common to both
+ * upstream and downstream).
+ *
+ * @param attachment
+ * @return
+ */
+ private FlowRule buildTLineMapFlowRule(Attachment attachment) {
+ PiCriterion criterion = PiCriterion.builder()
+ .matchExact(FabricConstants.HDR_S_TAG,
+ attachment.sTag().toShort())
+ .matchExact(FabricConstants.HDR_C_TAG,
+ attachment.cTag().toShort())
+ .build();
+ TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
+ .matchPi(criterion)
+ .build();
+ PiAction action = PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_SET_LINE)
+ .withParameter(new PiActionParam(FabricConstants.LINE_ID,
+ attachment.attachmentId().id()))
+ .build();
+ TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
+ .piTableAction(action)
+ .build();
+ return buildFlowRule(trafficSelector,
+ instTreatment,
+ FabricConstants.FABRIC_INGRESS_BNG_INGRESS_T_LINE_MAP,
+ attachment.appId());
+ }
+
+ /**
+ * Build the flow rule for the table t_pppoe_cp of the ingress upstream.
+ *
+ * @param criterion Criterion to build the flow rule.
+ * @return The built flow rule.
+ */
+ private FlowRule buildTPppoeCpFlowRule(PiCriterion criterion, ApplicationId appId) {
+ TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
+ .matchPi(criterion)
+ .build();
+ TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_PUNT_TO_CPU)
+ .build()
+ )
+ .build();
+ return buildFlowRule(trafficSelector,
+ instTreatment,
+ FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_T_PPPOE_CP,
+ appId);
+ }
+
+ private FlowRule buildFlowRule(TrafficSelector trafficSelector,
+ TrafficTreatment trafficTreatment,
+ TableId tableId,
+ ApplicationId appId) {
+ return DefaultFlowRule.builder()
+ .forDevice(data().deviceId())
+ .withSelector(trafficSelector)
+ .withTreatment(trafficTreatment)
+ .withPriority(DEFAULT_PRIORITY)
+ .forTable(tableId)
+ .fromApp(appId)
+ .makePermanent()
+ .build();
+ }
+}
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/PuntCpuCriterionFactory.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/PuntCpuCriterionFactory.java
new file mode 100644
index 0000000..ff40563
--- /dev/null
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/PuntCpuCriterionFactory.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * 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.pipelines.fabric.impl.behaviour.bng;
+
+import com.google.common.collect.ImmutableList;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PiCriterion;
+import org.onosproject.pipelines.fabric.impl.behaviour.FabricConstants;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Factory to build criteria to punt packet to the CPU from the BNG pipeline.
+ */
+final class PuntCpuCriterionFactory {
+
+ private static final ImmutableList<Byte> PPPOE_CODE =
+ ImmutableList.<Byte>builder()
+ .add((byte) 0x09) // PADI
+ .add((byte) 0x07) // PADO
+ .add((byte) 0x19) // PADR
+ .add((byte) 0x65) // PADS
+ .add((byte) 0xa7) // PADT
+ .build();
+
+ private static final ImmutableList<Short> PPP_PROTOCOL =
+ ImmutableList.<Short>builder()
+ .add((short) 0xc021) // LCP
+ .add((short) 0x8021) // IPCP
+ .add((short) 0xc023) // PAP
+ .add((short) 0xc223) // CHAP
+ .build();
+
+ private static final byte PPP_PROTOCOL_DEFAULT_MASK = (byte) 0xFFFF;
+
+ private PuntCpuCriterionFactory() {
+ // Hide constructor
+ }
+
+ /**
+ * Build all the Protocol Independent criteria starting from all the PPPoE
+ * codes.
+ *
+ * @return The list of Protocol Independent criteria.
+ */
+ static Set<Criterion> getAllPuntCriterion() {
+ Set<Criterion> criteria = PPPOE_CODE.stream()
+ .map(PuntCpuCriterionFactory::getPppoePiCriterion).collect(Collectors.toSet());
+
+ criteria.addAll(PPP_PROTOCOL.stream()
+ .map(PuntCpuCriterionFactory::getPppPiCriterion)
+ .collect(Collectors.toSet()));
+ return criteria;
+ }
+
+ /**
+ * Build the Protocol Independent criterion related to the specific PPPoE
+ * code.
+ *
+ * @param pppoeCode PPPoE code field.
+ * @return The built criterion.
+ */
+ private static PiCriterion getPppoePiCriterion(byte pppoeCode) {
+ return PiCriterion.builder()
+ .matchExact(FabricConstants.HDR_PPPOE_CODE, new byte[]{pppoeCode})
+ .build();
+ }
+
+ /**
+ * Build the Protocol Independent criterion related to the specified PPPoE
+ * code and PPP protocol matching.
+ * <p>
+ * Match on PPPoE Protocol will be done with 0xFFFF as mask.
+ *
+ * @param pppProtocol PPP protocol field.
+ * @return The built criterion.
+ */
+ private static PiCriterion getPppPiCriterion(short pppProtocol) {
+ return PiCriterion.builder()
+ .matchExact(FabricConstants.HDR_PPPOE_CODE, 0)
+ .matchTernary(FabricConstants.HDR_PPPOE_PROTOCOL,
+ pppProtocol,
+ PPP_PROTOCOL_DEFAULT_MASK)
+ .build();
+ }
+}
+
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/package-info.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/package-info.java
new file mode 100644
index 0000000..803c2b2
--- /dev/null
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/bng/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Implementation classes for BngProgrammable behaviour.
+ */
+package org.onosproject.pipelines.fabric.impl.behaviour.bng;
\ No newline at end of file