Refactor of UpfProgrammable APIs
Change-Id: I792659ad4a163d7115d7320bb33c11534edd484a
Signed-off-by: Daniele Moro <daniele@opennetworking.org>
(cherry picked from commit a57652d92bdd01b1e77bffbac78a44f96fb385f3)
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/ForwardingActionRule.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/ForwardingActionRule.java
deleted file mode 100644
index bfed1ce..0000000
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/ForwardingActionRule.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Copyright 2021-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.net.behaviour.upf;
-
-import org.onlab.packet.Ip4Address;
-import org.onlab.util.ImmutableByteSequence;
-
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * A single Forwarding Action Rule (FAR), an entity described in the 3GPP
- * specifications (although that does not mean that this class is 3GPP
- * compliant). An instance of this class will be generated by a logical switch
- * write request to the database-style FAR P4 table, and the resulting instance
- * should contain all the information needed to reproduce that logical switch
- * FAR in the event of a client read request. The instance should also contain
- * sufficient information (or expose the means to retrieve such information) to
- * generate the corresponding dataplane forwarding state that implements the FAR.
- */
-public final class ForwardingActionRule {
- // Match Keys
- private final ImmutableByteSequence sessionId; // The PFCP session identifier that created this FAR
- private final int farId; // PFCP session-local identifier for this FAR
- // Action parameters
- private final boolean notifyFlag; // Should this FAR notify the control plane when it sees a packet?
- private final boolean dropFlag;
- private final boolean bufferFlag;
- private final GtpTunnel tunnel; // The GTP tunnel that this FAR should encapsulate packets with (if downlink)
-
- private static final int SESSION_ID_BITWIDTH = 96;
-
- private ForwardingActionRule(ImmutableByteSequence sessionId, Integer farId,
- boolean notifyFlag, GtpTunnel tunnel, boolean dropFlag, boolean bufferFlag) {
- this.sessionId = sessionId;
- this.farId = farId;
- this.notifyFlag = notifyFlag;
- this.tunnel = tunnel;
- this.dropFlag = dropFlag;
- this.bufferFlag = bufferFlag;
- }
-
- /**
- * Return a new instance of this FAR with the action parameters stripped, leaving only the match keys.
- *
- * @return a new FAR with only match keys
- */
- public ForwardingActionRule withoutActionParams() {
- return ForwardingActionRule.builder()
- .setFarId(farId)
- .withSessionId(sessionId)
- .build();
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Return a string representing the dataplane action applied by this FAR.
- *
- * @return a string representing the FAR action
- */
- public String actionString() {
- String actionName;
- String actionParams = "";
- if (dropFlag) {
- actionName = "Drop";
- } else if (bufferFlag) {
- actionName = "Buffer";
- } else if (tunnel != null) {
- actionName = "Encap";
- actionParams = String.format("Src=%s, SPort=%d, TEID=%s, Dst=%s",
- tunnel.src().toString(), tunnel.srcPort(),
- tunnel.teid().toString(), tunnel.dst().toString());
- } else {
- actionName = "Forward";
- }
- if (notifyFlag) {
- actionName += "+NotifyCP";
- }
-
- return String.format("%s(%s)", actionName, actionParams);
- }
-
- @Override
- public String toString() {
- String matchKeys = String.format("ID=%d, SEID=%s", farId, sessionId.toString());
- String actionString = actionString();
-
- return String.format("FAR{Match(%s) -> %s}", matchKeys, actionString);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- ForwardingActionRule that = (ForwardingActionRule) obj;
-
- // Safe comparisons between potentially null objects
- return (this.dropFlag == that.dropFlag &&
- this.bufferFlag == that.bufferFlag &&
- this.notifyFlag == that.notifyFlag &&
- this.farId == that.farId &&
- Objects.equals(this.tunnel, that.tunnel) &&
- Objects.equals(this.sessionId, that.sessionId));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(sessionId, farId, notifyFlag, tunnel, dropFlag, bufferFlag);
- }
-
- /**
- * Get the ID of the PFCP Session that produced this FAR.
- *
- * @return PFCP session ID
- */
- public ImmutableByteSequence sessionId() {
- return sessionId;
- }
-
- /**
- * Get the PFCP session-local ID of the FAR that should apply to packets that match this PDR.
- *
- * @return PFCP session-local FAR ID
- */
- public int farId() {
- return farId;
- }
-
- /**
- * True if this FAR does not drop packets.
- *
- * @return true if FAR is forwards
- */
- public boolean forwards() {
- return !dropFlag;
- }
-
- /**
- * True if this FAR encapsulates packets in a GTP tunnel, and false otherwise.
- *
- * @return true is FAR encapsulates
- */
- public boolean encaps() {
- return tunnel != null;
- }
-
- /**
- * Returns true if this FAR drops packets, and false otherwise.
- *
- * @return true if this FAR drops
- */
- public boolean drops() {
- return dropFlag;
- }
-
- /**
- * Returns true if this FAR notifies the control plane on receiving a packet, and false otherwise.
- *
- * @return true if this FAR notifies the cp
- */
- public boolean notifies() {
- return notifyFlag;
- }
-
-
- /**
- * Returns true if this FAR buffers incoming packets, and false otherwise.
- *
- * @return true if this FAR buffers
- */
- public boolean buffers() {
- return bufferFlag;
- }
-
- /**
- * A description of the tunnel that this FAR will encapsulate packets with, if it is a downlink FAR. If the FAR
- * is uplink, there will be no such tunnel and this method wil return null.
- *
- * @return A GtpTunnel instance containing a tunnel sourceIP, destIP, and GTPU TEID, or null if the FAR is uplink.
- */
- public GtpTunnel tunnel() {
- return tunnel;
- }
-
- /**
- * Get the source UDP port of the GTP tunnel that this FAR will encapsulate packets with.
- *
- * @return GTP tunnel source UDP port
- */
- public Short tunnelSrcPort() {
- return tunnel != null ? tunnel.srcPort() : null;
- }
-
- /**
- * Get the source IP of the GTP tunnel that this FAR will encapsulate packets with.
- *
- * @return GTP tunnel source IP
- */
- public Ip4Address tunnelSrc() {
- if (tunnel == null) {
- return null;
- }
- return tunnel.src();
- }
-
- /**
- * Get the destination IP of the GTP tunnel that this FAR will encapsulate packets with.
- *
- * @return GTP tunnel destination IP
- */
- public Ip4Address tunnelDst() {
- if (tunnel == null) {
- return null;
- }
- return tunnel.dst();
- }
-
- /**
- * Get the identifier of the GTP tunnel that this FAR will encapsulate packets with.
- *
- * @return GTP tunnel ID
- */
- public ImmutableByteSequence teid() {
- if (tunnel == null) {
- return null;
- }
- return tunnel.teid();
- }
-
- public static class Builder {
- private ImmutableByteSequence sessionId = null;
- private Integer farId = null;
- private GtpTunnel tunnel = null;
- private boolean dropFlag = false;
- private boolean bufferFlag = false;
- private boolean notifyCp = false;
-
- public Builder() {
- }
-
- /**
- * Set the ID of the PFCP session that created this FAR.
- *
- * @param sessionId PFC session ID
- * @return This builder object
- */
- public Builder withSessionId(ImmutableByteSequence sessionId) {
- this.sessionId = sessionId;
- return this;
- }
-
- /**
- * Set the ID of the PFCP session that created this FAR.
- *
- * @param sessionId PFC session ID
- * @return This builder object
- */
- public Builder withSessionId(long sessionId) {
- try {
- this.sessionId = ImmutableByteSequence.copyFrom(sessionId).fit(SESSION_ID_BITWIDTH);
- } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
- // This error is literally impossible
- }
- return this;
- }
-
- /**
- * Set the PFCP Session-local ID of this FAR.
- *
- * @param farId PFCP session-local FAR ID
- * @return This builder object
- */
- public Builder setFarId(int farId) {
- this.farId = farId;
- return this;
- }
-
- /**
- * Make this FAR forward incoming packets.
- *
- * @param flag the flag value to set
- * @return This builder object
- */
- public Builder setForwardFlag(boolean flag) {
- this.dropFlag = !flag;
- return this;
- }
-
- /**
- * Make this FAR drop incoming packets.
- *
- * @param flag the flag value to set
- * @return This builder object
- */
- public Builder setDropFlag(boolean flag) {
- this.dropFlag = flag;
- return this;
- }
-
- /**
- * Make this FAR buffer incoming packets.
- *
- * @param flag the flag value to set
- * @return This builder object
- */
- public Builder setBufferFlag(boolean flag) {
- this.bufferFlag = flag;
- return this;
- }
-
- /**
- * Set a flag specifying if the control plane should be notified when this FAR is hit.
- *
- * @param notifyCp true if FAR notifies control plane
- * @return This builder object
- */
- public Builder setNotifyFlag(boolean notifyCp) {
- this.notifyCp = notifyCp;
- return this;
- }
-
- /**
- * Set the GTP tunnel that this FAR should encapsulate packets with.
- *
- * @param tunnel GTP tunnel
- * @return This builder object
- */
- public Builder setTunnel(GtpTunnel tunnel) {
- this.tunnel = tunnel;
- return this;
- }
-
- /**
- * Set the unidirectional GTP tunnel that this FAR should encapsulate packets with.
- *
- * @param src GTP tunnel source IP
- * @param dst GTP tunnel destination IP
- * @param teid GTP tunnel ID
- * @return This builder object
- */
- public Builder setTunnel(Ip4Address src, Ip4Address dst, ImmutableByteSequence teid) {
- return this.setTunnel(GtpTunnel.builder()
- .setSrc(src)
- .setDst(dst)
- .setTeid(teid)
- .build());
- }
-
- /**
- * Set the unidirectional GTP tunnel that this FAR should encapsulate packets with.
- *
- * @param src GTP tunnel source IP
- * @param dst GTP tunnel destination IP
- * @param teid GTP tunnel ID
- * @param srcPort GTP tunnel UDP source port (destination port is hardcoded as 2152)
- * @return This builder object
- */
- public Builder setTunnel(Ip4Address src, Ip4Address dst, ImmutableByteSequence teid, short srcPort) {
- return this.setTunnel(GtpTunnel.builder()
- .setSrc(src)
- .setDst(dst)
- .setTeid(teid)
- .setSrcPort(srcPort)
- .build());
- }
-
- public ForwardingActionRule build() {
- // All match keys are required
- checkNotNull(sessionId, "Session ID is required");
- checkNotNull(farId, "FAR ID is required");
- return new ForwardingActionRule(sessionId, farId, notifyCp, tunnel, dropFlag, bufferFlag);
- }
- }
-}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/GtpTunnel.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/GtpTunnel.java
deleted file mode 100644
index bc262c7..0000000
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/GtpTunnel.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2021-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.net.behaviour.upf;
-
-import org.onlab.packet.Ip4Address;
-import org.onlab.util.ImmutableByteSequence;
-
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * A structure representing a unidirectional GTP tunnel.
- */
-public final class GtpTunnel {
- private final Ip4Address src; // The source address of the unidirectional tunnel
- private final Ip4Address dst; // The destination address of the unidirectional tunnel
- private final ImmutableByteSequence teid; // Tunnel Endpoint Identifier
- private final short srcPort; // Tunnel destination port, default 2152
-
- private GtpTunnel(Ip4Address src, Ip4Address dst, ImmutableByteSequence teid,
- Short srcPort) {
- this.src = src;
- this.dst = dst;
- this.teid = teid;
- this.srcPort = srcPort;
- }
-
- public static GtpTunnelBuilder builder() {
- return new GtpTunnelBuilder();
- }
-
- @Override
- public String toString() {
- return String.format("GTP-Tunnel(%s -> %s, TEID:%s)",
- src.toString(), dst.toString(), teid.toString());
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- GtpTunnel that = (GtpTunnel) obj;
-
- return (this.src.equals(that.src) &&
- this.dst.equals(that.dst) &&
- this.teid.equals(that.teid) &&
- (this.srcPort == that.srcPort));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(src, dst, teid, srcPort);
- }
-
- /**
- * Get the source IP address of this unidirectional GTP tunnel.
- *
- * @return tunnel source IP
- */
- public Ip4Address src() {
- return this.src;
- }
-
- /**
- * Get the destination address of this unidirectional GTP tunnel.
- *
- * @return tunnel destination IP
- */
- public Ip4Address dst() {
- return this.dst;
- }
-
- /**
- * Get the ID of this unidirectional GTP tunnel.
- *
- * @return tunnel ID
- */
- public ImmutableByteSequence teid() {
- return this.teid;
- }
-
-
- /**
- * Get the source L4 port of this unidirectional GTP tunnel.
- *
- * @return tunnel source port
- */
- public Short srcPort() {
- return this.srcPort;
- }
-
- public static class GtpTunnelBuilder {
- private Ip4Address src;
- private Ip4Address dst;
- private ImmutableByteSequence teid;
- private short srcPort = 2152; // Default value is equal to GTP tunnel dst port
-
- public GtpTunnelBuilder() {
- this.src = null;
- this.dst = null;
- this.teid = null;
- }
-
- /**
- * Set the source IP address of the unidirectional GTP tunnel.
- *
- * @param src GTP tunnel source IP
- * @return This builder object
- */
- public GtpTunnelBuilder setSrc(Ip4Address src) {
- this.src = src;
- return this;
- }
-
- /**
- * Set the destination IP address of the unidirectional GTP tunnel.
- *
- * @param dst GTP tunnel destination IP
- * @return This builder object
- */
- public GtpTunnelBuilder setDst(Ip4Address dst) {
- this.dst = dst;
- return this;
- }
-
- /**
- * Set the identifier of this unidirectional GTP tunnel.
- *
- * @param teid tunnel ID
- * @return This builder object
- */
- public GtpTunnelBuilder setTeid(ImmutableByteSequence teid) {
- this.teid = teid;
- return this;
- }
-
- /**
- * Set the identifier of this unidirectional GTP tunnel.
- *
- * @param teid tunnel ID
- * @return This builder object
- */
- public GtpTunnelBuilder setTeid(long teid) {
- this.teid = ImmutableByteSequence.copyFrom(teid);
- return this;
- }
-
- /**
- * Set the source port of this unidirectional GTP tunnel.
- *
- * @param srcPort tunnel source port
- * @return this builder object
- */
- public GtpTunnelBuilder setSrcPort(short srcPort) {
- this.srcPort = srcPort;
- return this;
- }
-
- public GtpTunnel build() {
- checkNotNull(src, "Tunnel source address cannot be null");
- checkNotNull(dst, "Tunnel destination address cannot be null");
- checkNotNull(teid, "Tunnel TEID cannot be null");
- return new GtpTunnel(this.src, this.dst, this.teid, srcPort);
- }
- }
-}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/GtpTunnelPeer.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/GtpTunnelPeer.java
new file mode 100644
index 0000000..a3cf662
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/GtpTunnelPeer.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2021-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.net.behaviour.upf;
+
+import com.google.common.annotations.Beta;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * A structure representing a GTP tunnel peer.
+ * The GTP Tunnel Peer is used by UPF to identify a second end of a GTP tunnel.
+ * The source and destination tunnel IPv4 addresses, and source UDP port are set
+ * based on the information from this structure.
+ */
+@Beta
+public final class GtpTunnelPeer implements UpfEntity {
+ // Match keys
+ private final byte tunPeerId;
+ // Action parameters
+ private final Ip4Address src; // The source address of the unidirectional tunnel
+ private final Ip4Address dst; // The destination address of the unidirectional tunnel
+ private final short srcPort; // Tunnel source port, default 2152
+
+ private GtpTunnelPeer(byte tunPeerId, Ip4Address src, Ip4Address dst, short srcPort) {
+ this.tunPeerId = tunPeerId;
+ this.src = src;
+ this.dst = dst;
+ this.srcPort = srcPort;
+ }
+
+ public static GtpTunnelPeer.Builder builder() {
+ return new GtpTunnelPeer.Builder();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("GTP-Tunnel-Peer(%s -> src:%s, dst:%s srcPort:%s)",
+ tunPeerId, src.toString(), dst.toString(), srcPort);
+ }
+
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+
+ if (object == null) {
+ return false;
+ }
+
+ if (getClass() != object.getClass()) {
+ return false;
+ }
+
+ GtpTunnelPeer that = (GtpTunnelPeer) object;
+ return (this.tunPeerId == that.tunPeerId &&
+ this.src.equals(that.src) &&
+ this.dst.equals(that.dst) &&
+ (this.srcPort == that.srcPort));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(src, dst, srcPort);
+ }
+
+ /**
+ * Get the ID of the GTP tunnel peer.
+ *
+ * @return GTP tunnel peer ID
+ */
+ public byte tunPeerId() {
+ return tunPeerId;
+ }
+
+ /**
+ * Get the source IP address of this unidirectional GTP tunnel.
+ *
+ * @return tunnel source IP
+ */
+ public Ip4Address src() {
+ return this.src;
+ }
+
+ /**
+ * Get the destination address of this unidirectional GTP tunnel.
+ *
+ * @return tunnel destination IP
+ */
+ public Ip4Address dst() {
+ return this.dst;
+ }
+
+ /**
+ * Get the source L4 port of this unidirectional GTP tunnel.
+ *
+ * @return tunnel source port
+ */
+ public short srcPort() {
+ return this.srcPort;
+ }
+
+ @Override
+ public UpfEntityType type() {
+ return UpfEntityType.TUNNEL_PEER;
+ }
+
+ public static class Builder {
+ private Byte tunPeerId = null;
+ private Ip4Address src = null;
+ private Ip4Address dst = null;
+ private short srcPort = 2152; // Default value is equal to GTP tunnel dst port
+
+ public Builder() {
+
+ }
+
+ /**
+ * Set the ID of the GTP Tunnel peer.
+ *
+ * @param tunPeerId GTP tunnel peer ID
+ * @return This builder object
+ */
+ public GtpTunnelPeer.Builder withTunnelPeerId(byte tunPeerId) {
+ this.tunPeerId = tunPeerId;
+ return this;
+ }
+
+ /**
+ * Set the source IP address of the unidirectional GTP tunnel.
+ *
+ * @param src GTP tunnel source IP
+ * @return This builder object
+ */
+ public GtpTunnelPeer.Builder withSrcAddr(Ip4Address src) {
+ this.src = src;
+ return this;
+ }
+
+ /**
+ * Set the destination IP address of the unidirectional GTP tunnel.
+ *
+ * @param dst GTP tunnel destination IP
+ * @return This builder object
+ */
+ public GtpTunnelPeer.Builder withDstAddr(Ip4Address dst) {
+ this.dst = dst;
+ return this;
+ }
+
+ /**
+ * Set the source port of this unidirectional GTP tunnel.
+ *
+ * @param srcPort tunnel source port
+ * @return this builder object
+ */
+ public GtpTunnelPeer.Builder withSrcPort(short srcPort) {
+ this.srcPort = srcPort;
+ return this;
+ }
+
+ public GtpTunnelPeer build() {
+ checkArgument(tunPeerId != null, "Tunnel Peer ID must be provided");
+ checkArgument(src != null, "Tunnel source address cannot be null");
+ checkArgument(dst != null, "Tunnel destination address cannot be null");
+ return new GtpTunnelPeer(this.tunPeerId, this.src, this.dst, srcPort);
+ }
+
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/PacketDetectionRule.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/PacketDetectionRule.java
deleted file mode 100644
index f607d87..0000000
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/PacketDetectionRule.java
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright 2021-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.net.behaviour.upf;
-
-import org.onlab.packet.Ip4Address;
-import org.onlab.util.ImmutableByteSequence;
-
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-/**
- * A single Packet Detection Rule (PDR), an entity described in the 3GPP
- * specifications (although that does not mean that this class is 3GPP
- * compliant). An instance of this class will be generated by a logical switch
- * write request to the database-style PDR P4 table, and the resulting instance
- * should contain all the information needed to reproduce that logical switch
- * PDR in the event of a client read request. The instance should also contain
- * sufficient information (or expose the means to retrieve such information) to
- * generate the corresponding dataplane forwarding state that implements the PDR.
- */
-public final class PacketDetectionRule {
- // Match keys
- private final Ip4Address ueAddr; // The UE IP address that this PDR matches on
- private final ImmutableByteSequence teid; // The Tunnel Endpoint ID that this PDR matches on
- private final Ip4Address tunnelDst; // The tunnel destination address that this PDR matches on
- // Action parameters
- private final ImmutableByteSequence sessionId; // The ID of the PFCP session that created this PDR
- private final Integer ctrId; // Counter ID unique to this PDR
- private final Integer farId; // The PFCP session-local ID of the FAR that should apply after this PDR hits
- private final Type type;
-
- private final Byte qfi; // QoS Flow Identifier of this PDR
- private final boolean qfiPush; // True when QFI should be pushed to the packet
- private final boolean qfiMatch; // True when QFI should be matched
-
- private static final int SESSION_ID_BITWIDTH = 96;
-
- private PacketDetectionRule(ImmutableByteSequence sessionId, Integer ctrId,
- Integer farId, Ip4Address ueAddr, Byte qfi,
- ImmutableByteSequence teid, Ip4Address tunnelDst,
- Type type, boolean qfiPush, boolean qfiMatch) {
- this.ueAddr = ueAddr;
- this.teid = teid;
- this.tunnelDst = tunnelDst;
- this.sessionId = sessionId;
- this.ctrId = ctrId;
- this.farId = farId;
- this.qfi = qfi;
- this.type = type;
- this.qfiPush = qfiPush;
- this.qfiMatch = qfiMatch;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Return a string representing the match conditions of this PDR.
- *
- * @return a string representing the PDR match conditions
- */
- public String matchString() {
- if (matchesEncapped()) {
- return matchQfi() ?
- String.format("Match(Dst=%s, TEID=%s, QFI=%s)", tunnelDest(), teid(), qfi()) :
- String.format("Match(Dst=%s, TEID=%s)", tunnelDest(), teid());
- } else {
- return String.format("Match(Dst=%s, !GTP)", ueAddress());
- }
- }
-
- @Override
- public String toString() {
- String actionParams = "";
- if (hasActionParameters()) {
- actionParams = hasQfi() && !matchQfi() ?
- String.format("SEID=%s, FAR=%d, CtrIdx=%d, QFI=%s",
- sessionId.toString(), farId, ctrId, qfi) :
- String.format("SEID=%s, FAR=%d, CtrIdx=%d",
- sessionId.toString(), farId, ctrId);
- actionParams = pushQfi() ? String.format("%s, QFI_PUSH", actionParams) : actionParams;
- }
-
- return String.format("PDR{%s -> LoadParams(%s)}",
- matchString(), actionParams);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- PacketDetectionRule that = (PacketDetectionRule) obj;
-
- // Safe comparisons between potentially null objects
- return (this.type.equals(that.type) &&
- Objects.equals(this.teid, that.teid) &&
- Objects.equals(this.tunnelDst, that.tunnelDst) &&
- Objects.equals(this.ueAddr, that.ueAddr) &&
- Objects.equals(this.ctrId, that.ctrId) &&
- Objects.equals(this.sessionId, that.sessionId) &&
- Objects.equals(this.farId, that.farId) &&
- Objects.equals(this.qfi, that.qfi) &&
- Objects.equals(this.qfiPush, that.qfiPush) &&
- Objects.equals(this.qfiMatch, that.qfiMatch));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(ueAddr, teid, tunnelDst, sessionId, ctrId, farId,
- qfi, type);
- }
-
- /**
- * Instances created as a result of DELETE write requests will not have
- * action parameters, only match keys. This method should be used to avoid
- * null pointer exceptions in those instances.
- *
- * @return true if this instance has PDR action parameters, false otherwise.
- */
- public boolean hasActionParameters() {
- return type == Type.MATCH_ENCAPPED || type == Type.MATCH_UNENCAPPED;
- }
-
- /**
- * Return a new instance of this PDR with the action parameters stripped,
- * leaving only the match keys.
- *
- * @return a new PDR with only match keys
- */
- public PacketDetectionRule withoutActionParams() {
- if (matchesEncapped()) {
- PacketDetectionRule.Builder pdrBuilder = PacketDetectionRule.builder()
- .withTeid(teid)
- .withTunnelDst(tunnelDst);
- if (this.hasQfi() && this.matchQfi()) {
- pdrBuilder.withQfiMatch();
- pdrBuilder.withQfi(qfi);
- }
- return pdrBuilder.build();
- } else {
- return PacketDetectionRule.builder()
- .withUeAddr(ueAddr).build();
- }
- }
-
- /**
- * True if this PDR matches on packets received with a GTP header, and false
- * otherwise.
- *
- * @return true if the PDR matches only encapsulated packets
- */
- public boolean matchesEncapped() {
- return type == Type.MATCH_ENCAPPED ||
- type == Type.MATCH_ENCAPPED_NO_ACTION;
- }
-
- /**
- * True if this PDR matches on packets received without a GTP header, and
- * false otherwise.
- *
- * @return true if the PDR matches only un-encapsulated packets
- */
- public boolean matchesUnencapped() {
- return type == Type.MATCH_UNENCAPPED ||
- type == Type.MATCH_UNENCAPPED_NO_ACTION;
- }
-
- /**
- * Get the ID of the PFCP session that produced this PDR.
- *
- * @return PFCP session ID
- */
- public ImmutableByteSequence sessionId() {
- return sessionId;
- }
-
- /**
- * Get the UE IP address that this PDR matches on.
- *
- * @return UE IP address
- */
- public Ip4Address ueAddress() {
- return ueAddr;
- }
-
- /**
- * Get the identifier of the GTP tunnel that this PDR matches on.
- *
- * @return GTP tunnel ID
- */
- public ImmutableByteSequence teid() {
- return teid;
- }
-
- /**
- * Get the destination IP of the GTP tunnel that this PDR matches on.
- *
- * @return GTP tunnel destination IP
- */
- public Ip4Address tunnelDest() {
- return tunnelDst;
- }
-
- /**
- * Get the dataplane PDR counter cell ID that this PDR is assigned.
- *
- * @return PDR counter cell ID
- */
- public int counterId() {
- return ctrId;
- }
-
- /**
- * Get the PFCP session-local ID of the far that should apply to packets
- * that this PDR matches.
- *
- * @return PFCP session-local FAR ID
- */
- public int farId() {
- return farId;
- }
-
- /**
- * Get the QoS Flow Identifier for this PDR.
- *
- * @return QoS Flow Identifier
- */
- public byte qfi() {
- return qfi;
- }
-
- /**
- * Returns whether QFi should be pushed to the packet.
- *
- * @return True if the QFI should be pushed to the packet, false otherwise
- */
- public boolean pushQfi() {
- return qfiPush;
- }
-
- /**
- * Returns whether QFI should be matched on the packet or not.
- *
- * @return True if QFI should be matched on the packet, false otherwise
- */
- public boolean matchQfi() {
- return qfiMatch;
- }
-
- /**
- * Checks if the PDR has a QFI to match upon or to push on the packet.
- *
- * @return True if the PDR has a QFI, false otherwise
- */
- public boolean hasQfi() {
- return qfi != null;
- }
-
- private enum Type {
- /**
- * Match on packets that are encapsulated in a GTP tunnel.
- */
- MATCH_ENCAPPED,
- /**
- * Match on packets that are not encapsulated in a GTP tunnel.
- */
- MATCH_UNENCAPPED,
- /**
- * For PDRs that match on encapsulated packets but do not yet have any
- * action parameters set.
- * These are usually built in the context of P4Runtime DELETE write requests.
- */
- MATCH_ENCAPPED_NO_ACTION,
- /**
- * For PDRs that match on unencapsulated packets but do not yet have any
- * action parameters set.
- * These are usually built in the context of P4Runtime DELETE write requests.
- */
- MATCH_UNENCAPPED_NO_ACTION
- }
-
- public static class Builder {
- private ImmutableByteSequence sessionId = null;
- private Integer ctrId = null;
- private Integer localFarId = null;
- private Integer schedulingPriority = null;
- private Ip4Address ueAddr = null;
- private ImmutableByteSequence teid = null;
- private Ip4Address tunnelDst = null;
- private Byte qfi = null;
- private boolean qfiPush = false;
- private boolean qfiMatch = false;
-
- public Builder() {
-
- }
-
- /**
- * Set the ID of the PFCP session that produced this PDR.
- *
- * @param sessionId PFCP session ID
- * @return This builder object
- */
- public Builder withSessionId(ImmutableByteSequence sessionId) {
- this.sessionId = sessionId;
- return this;
- }
-
- /**
- * Set the ID of the PFCP session that produced this PDR.
- *
- * @param sessionId PFCP session ID
- * @return This builder object
- */
- public Builder withSessionId(long sessionId) {
- try {
- this.sessionId = ImmutableByteSequence.copyFrom(sessionId)
- .fit(SESSION_ID_BITWIDTH);
- } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
- // This error is literally impossible
- }
- return this;
- }
-
- /**
- * Set the UE IP address that this PDR matches on.
- *
- * @param ueAddr UE IP address
- * @return This builder object
- */
- public Builder withUeAddr(Ip4Address ueAddr) {
- this.ueAddr = ueAddr;
- return this;
- }
-
- /**
- * Set the dataplane PDR counter cell ID that this PDR is assigned.
- *
- * @param ctrId PDR counter cell ID
- * @return This builder object
- */
- public Builder withCounterId(int ctrId) {
- this.ctrId = ctrId;
- return this;
- }
-
-
- /**
- * Set the PFCP session-local ID of the far that should apply to packets that this PDR matches.
- *
- * @param localFarId PFCP session-local FAR ID
- * @return This builder object
- */
- public Builder withLocalFarId(int localFarId) {
- this.localFarId = localFarId;
- return this;
- }
-
- /**
- * Set the QoS Flow Identifier for this PDR.
- *
- * @param qfi GTP Tunnel QFI
- * @return This builder object
- */
- public Builder withQfi(byte qfi) {
- this.qfi = qfi;
- return this;
- }
-
- /**
- * The QoS Flow Identifier should be pushed to the packet.
- * This is valid for downstream packets and for 5G traffic only.
- *
- * @return This builder object
- */
- public Builder withQfiPush() {
- this.qfiPush = true;
- return this;
- }
-
- /**
- * The QoS Flow Identifier should be matched to the packet.
- * This is valid for upstream packets and for 5G traffic only.
- *
- * @return This builder object
- */
- public Builder withQfiMatch() {
- this.qfiMatch = true;
- return this;
- }
-
- /**
- * Set the identifier of the GTP tunnel that this PDR matches on.
- *
- * @param teid GTP tunnel ID
- * @return This builder object
- */
- public Builder withTeid(int teid) {
- this.teid = ImmutableByteSequence.copyFrom(teid);
- return this;
- }
-
- /**
- * Set the identifier of the GTP tunnel that this PDR matches on.
- *
- * @param teid GTP tunnel ID
- * @return This builder object
- */
- public Builder withTeid(ImmutableByteSequence teid) {
- this.teid = teid;
- return this;
- }
-
- /**
- * Set the destination IP of the GTP tunnel that this PDR matches on.
- *
- * @param tunnelDst GTP tunnel destination IP
- * @return This builder object
- */
- public Builder withTunnelDst(Ip4Address tunnelDst) {
- this.tunnelDst = tunnelDst;
- return this;
- }
-
- /**
- * Set the tunnel ID and destination IP of the GTP tunnel that this PDR matches on.
- *
- * @param teid GTP tunnel ID
- * @param tunnelDst GTP tunnel destination IP
- * @return This builder object
- */
- public Builder withTunnel(ImmutableByteSequence teid, Ip4Address tunnelDst) {
- this.teid = teid;
- this.tunnelDst = tunnelDst;
- return this;
- }
-
- /**
- * Set the tunnel ID, destination IP and QFI of the GTP tunnel that this PDR matches on.
- *
- * @param teid GTP tunnel ID
- * @param tunnelDst GTP tunnel destination IP
- * @param qfi GTP QoS Flow Identifier
- * @return This builder object
- */
- public Builder withTunnel(ImmutableByteSequence teid, Ip4Address tunnelDst, byte qfi) {
- this.teid = teid;
- this.tunnelDst = tunnelDst;
- this.qfi = qfi;
- return this;
- }
-
- public PacketDetectionRule build() {
- // Some match keys are required.
- checkArgument(
- (ueAddr != null && teid == null && tunnelDst == null) ||
- (ueAddr == null && teid != null && tunnelDst != null),
- "Either a UE address or a TEID and Tunnel destination must be provided, but not both.");
- // Action parameters are optional but must be all provided together if they are provided
- checkArgument(
- (sessionId != null && ctrId != null && localFarId != null) ||
- (sessionId == null && ctrId == null && localFarId == null),
- "PDR action parameters must be provided together or not at all.");
- checkArgument(!qfiPush || !qfiMatch,
- "Either match of push QFI can be true, not both.");
- checkArgument(!qfiPush || qfi != null,
- "A QFI must be provided when pushing QFI to the packet.");
- checkArgument(!qfiMatch || qfi != null,
- "A QFI must be provided when matching QFI on the packet.");
- Type type;
- if (teid != null) {
- if (sessionId != null) {
- type = Type.MATCH_ENCAPPED;
- } else {
- type = Type.MATCH_ENCAPPED_NO_ACTION;
- }
- } else {
- if (sessionId != null) {
- type = Type.MATCH_UNENCAPPED;
- } else {
- type = Type.MATCH_UNENCAPPED_NO_ACTION;
- }
- }
- return new PacketDetectionRule(sessionId, ctrId, localFarId, ueAddr,
- qfi, teid, tunnelDst, type,
- qfiPush, qfiMatch);
- }
- }
-}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/SessionDownlink.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/SessionDownlink.java
new file mode 100644
index 0000000..c35410b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/SessionDownlink.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2021-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.net.behaviour.upf;
+
+import com.google.common.annotations.Beta;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A structure representing the UE Session on the UPF-programmable device.
+ * Provides means to set up the UE Session in the downlink direction.
+ */
+@Beta
+public final class SessionDownlink implements UpfEntity {
+ // Match Keys
+ private final Ip4Address ueAddress;
+ // Action parameters
+ private final Byte tunPeerId;
+ private final boolean buffering;
+ private final boolean dropping;
+
+ private SessionDownlink(Ip4Address ipv4Address,
+ Byte tunPeerId,
+ boolean buffering,
+ boolean drop) {
+ this.ueAddress = ipv4Address;
+ this.tunPeerId = tunPeerId;
+ this.buffering = buffering;
+ this.dropping = drop;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object == null) {
+ return false;
+ }
+ if (getClass() != object.getClass()) {
+ return false;
+ }
+
+ SessionDownlink that = (SessionDownlink) object;
+
+ return this.buffering == that.buffering &&
+ this.dropping == that.dropping &&
+ Objects.equals(ueAddress, that.ueAddress) &&
+ Objects.equals(tunPeerId, that.tunPeerId);
+ }
+
+ public int hashCode() {
+ return java.util.Objects.hash(ueAddress, tunPeerId, buffering, dropping);
+ }
+
+ @Override
+ public String toString() {
+ return "UESessionDL{" + matchString() + " -> " + actionString();
+ }
+
+ private String matchString() {
+ return "Match(ue_addr=" + this.ueAddress() + ")";
+ }
+
+ private String actionString() {
+ StringBuilder actionStrBuilder = new StringBuilder("(");
+ if (this.needsBuffering() && this.needsDropping()) {
+ actionStrBuilder.append("BUFF+DROP, ");
+ } else if (this.needsBuffering()) {
+ actionStrBuilder.append("BUFF, ");
+ } else if (this.needsDropping()) {
+ actionStrBuilder.append("DROP, ");
+ } else {
+ actionStrBuilder.append("FWD, ");
+ }
+ return actionStrBuilder.append(" tun_peer=").append(this.tunPeerId()).append(")")
+ .toString();
+ }
+
+ /**
+ * True if this UE Session needs buffering of the downlink traffic.
+ *
+ * @return true if the UE Session needs buffering.
+ */
+ public boolean needsBuffering() {
+ return buffering;
+ }
+
+ /**
+ * True if this UE Session needs dropping of the downlink traffic.
+ *
+ * @return true if the UE Session needs dropping.
+ */
+ public boolean needsDropping() {
+ return dropping;
+ }
+
+ /**
+ * Get the UE IP address of this downlink UE session.
+ *
+ * @return UE IP address
+ */
+ public Ip4Address ueAddress() {
+ return ueAddress;
+ }
+
+ /**
+ * Get the GTP tunnel peer ID that is set by this UE Session rule.
+ *
+ * @return GTP tunnel peer ID
+ */
+ public Byte tunPeerId() {
+ return tunPeerId;
+ }
+
+ @Override
+ public UpfEntityType type() {
+ return UpfEntityType.SESSION_DOWNLINK;
+ }
+
+ public static class Builder {
+ private Ip4Address ueAddress = null;
+ private Byte tunPeerId = null;
+ private boolean buffer = false;
+ private boolean drop = false;
+
+ public Builder() {
+
+ }
+
+ /**
+ * Set the UE IP address that this downlink UE session rule matches on.
+ *
+ * @param ueAddress UE IP address
+ * @return This builder object
+ */
+ public Builder withUeAddress(Ip4Address ueAddress) {
+ this.ueAddress = ueAddress;
+ return this;
+ }
+
+ /**
+ * Set the GTP tunnel peer ID that is set by this UE Session rule.
+ *
+ * @param tunnelPeerId GTP tunnel peer ID
+ * @return This builder object
+ */
+ public Builder withGtpTunnelPeerId(Byte tunnelPeerId) {
+ this.tunPeerId = tunnelPeerId;
+ return this;
+ }
+
+ /**
+ * Sets whether to buffer downlink UE session traffic or not.
+ *
+ * @param buffer True if request to buffer, false otherwise
+ * @return This builder object
+ */
+ public Builder needsBuffering(boolean buffer) {
+ this.buffer = buffer;
+ return this;
+ }
+
+ /**
+ * Sets whether to drop downlink UE session traffic or not.
+ *
+ * @param drop True if request to buffer, false otherwise
+ * @return This builder object
+ */
+ public Builder needsDropping(boolean drop) {
+ this.drop = drop;
+ return this;
+ }
+
+ public SessionDownlink build() {
+ // Match fields are required
+ checkNotNull(ueAddress, "UE address must be provided");
+ return new SessionDownlink(ueAddress, tunPeerId, buffer, drop);
+ }
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/SessionUplink.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/SessionUplink.java
new file mode 100644
index 0000000..70db84c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/SessionUplink.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2021-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.net.behaviour.upf;
+
+import com.google.common.annotations.Beta;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A structure representing the UE Session on the UPF-programmable device.
+ * Provides means to set up the UE Session in the uplink direction.
+ */
+@Beta
+public final class SessionUplink implements UpfEntity {
+ // Match Keys
+ private final Ip4Address tunDestAddr; // The tunnel destination address (N3/S1U IPv4 address)
+ private final Integer teid; // The Tunnel Endpoint ID that this UeSession matches on
+
+ // Action parameters
+ private final boolean dropping; // Used to convey dropping information
+
+ private SessionUplink(Ip4Address tunDestAddr,
+ Integer teid,
+ boolean drop) {
+ this.tunDestAddr = tunDestAddr;
+ this.teid = teid;
+ this.dropping = drop;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object == null) {
+ return false;
+ }
+ if (getClass() != object.getClass()) {
+ return false;
+ }
+
+ SessionUplink that = (SessionUplink) object;
+
+ return this.dropping == that.dropping &&
+ Objects.equals(tunDestAddr, that.tunDestAddr) &&
+ Objects.equals(teid, that.teid);
+ }
+
+ public int hashCode() {
+ return Objects.hash(tunDestAddr, teid, dropping);
+ }
+
+ @Override
+ public String toString() {
+ return "UESessionUL{" + matchString() + " -> " + actionString();
+ }
+
+ private String matchString() {
+ return "Match(tun_dst_addr=" + this.tunDstAddr() + ", TEID=" + this.teid() + ")";
+ }
+
+ private String actionString() {
+ StringBuilder actionStrBuilder = new StringBuilder("(");
+ if (this.needsDropping()) {
+ actionStrBuilder.append("DROP");
+
+ } else {
+ actionStrBuilder.append("FWD");
+ }
+ return actionStrBuilder.append(")").toString();
+ }
+
+ /**
+ * True if this UE Session needs dropping of the uplink traffic.
+ *
+ * @return true if the UE Session needs dropping.
+ */
+ public boolean needsDropping() {
+ return dropping;
+ }
+
+ /**
+ * Get the tunnel destination IP address in the uplink UE session (N3/S1U IP address).
+ *
+ * @return UE IP address
+ */
+ public Ip4Address tunDstAddr() {
+ return tunDestAddr;
+ }
+
+ /**
+ * Get the identifier of the GTP tunnel that this UE Session rule matches on.
+ *
+ * @return GTP tunnel ID
+ */
+ public Integer teid() {
+ return teid;
+ }
+
+ @Override
+ public UpfEntityType type() {
+ return UpfEntityType.SESSION_UPLINK;
+ }
+
+ public static class Builder {
+ private Ip4Address tunDstAddr = null;
+ private Integer teid = null;
+ private boolean drop = false;
+
+ public Builder() {
+
+ }
+
+ /**
+ * Set the tunnel destination IP address (N3/S1U address) that this UE Session rule matches on.
+ *
+ * @param tunDstAddr The tunnel destination IP address
+ * @return This builder object
+ */
+ public Builder withTunDstAddr(Ip4Address tunDstAddr) {
+ this.tunDstAddr = tunDstAddr;
+ return this;
+ }
+
+ /**
+ * Set the identifier of the GTP tunnel that this UE Session rule matches on.
+ *
+ * @param teid GTP tunnel ID
+ * @return This builder object
+ */
+ public Builder withTeid(Integer teid) {
+ this.teid = teid;
+ return this;
+ }
+
+
+ /**
+ * Sets whether to drop uplink UE session traffic or not.
+ *
+ * @param drop True if request to buffer, false otherwise
+ * @return This builder object
+ */
+ public Builder needsDropping(boolean drop) {
+ this.drop = drop;
+ return this;
+ }
+
+ public SessionUplink build() {
+ // Match keys are required.
+ checkNotNull(tunDstAddr, "Tunnel destination must be provided");
+ checkNotNull(teid, "TEID must be provided");
+ return new SessionUplink(tunDstAddr, teid, drop);
+ }
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/PdrStats.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfCounter.java
similarity index 76%
rename from core/api/src/main/java/org/onosproject/net/behaviour/upf/PdrStats.java
rename to core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfCounter.java
index eb4ea18..4eee3fe 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/PdrStats.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfCounter.java
@@ -17,21 +17,26 @@
package org.onosproject.net.behaviour.upf;
+import com.google.common.annotations.Beta;
+
import static com.google.common.base.Preconditions.checkNotNull;
/**
- * A structure for compactly passing PDR counter values for a given counter ID.
- * Contains four counts: Ingress Packets, Ingress Bytes, Egress Packets, Egress Bytes
+ * A structure for compactly passing UPF counter values for a given counter ID.
+ * Contains four counts: Ingress Packets, Ingress Bytes, Egress Packets, Egress Bytes.
+ * UpfCounter can be used ONLY on {@code apply} and {@code readAll} calls in the
+ * {@link UpfDevice} interface.
*/
-public final class PdrStats {
+@Beta
+public final class UpfCounter implements UpfEntity {
private final int cellId;
private final long ingressPkts;
private final long ingressBytes;
private final long egressPkts;
private final long egressBytes;
- private PdrStats(int cellId, long ingressPkts, long ingressBytes,
- long egressPkts, long egressBytes) {
+ private UpfCounter(int cellId, long ingressPkts, long ingressBytes,
+ long egressPkts, long egressBytes) {
this.cellId = cellId;
this.ingressPkts = ingressPkts;
this.ingressBytes = ingressBytes;
@@ -45,12 +50,12 @@
@Override
public String toString() {
- return String.format("PDR-Stats:{ CellID: %d, Ingress:(%dpkts,%dbytes), Egress:(%dpkts,%dbytes) }",
+ return String.format("Stats:{ CellID: %d, Ingress:(%dpkts,%dbytes), Egress:(%dpkts,%dbytes) }",
cellId, ingressPkts, ingressBytes, egressPkts, egressBytes);
}
/**
- * Get the cell ID (index) of the dataplane PDR counter that produced this set of stats.
+ * Get the cell ID (index) of the dataplane counter that produced this set of stats.
*
* @return counter cell ID
*/
@@ -94,6 +99,11 @@
return egressBytes;
}
+ @Override
+ public UpfEntityType type() {
+ return UpfEntityType.COUNTER;
+ }
+
public static class Builder {
private Integer cellId;
private long ingressPkts;
@@ -109,7 +119,7 @@
}
/**
- * Set the Cell ID (index) of the datalane PDR counter that produced this set of stats.
+ * Set the Cell ID (index) of the datalane counter that produced this set of stats.
*
* @param cellId the counter cell ID
* @return This builder
@@ -120,7 +130,7 @@
}
/**
- * Set the number of packets and bytes that hit the PDR counter in the dataplane ingress pipeline.
+ * Set the number of packets and bytes that hit the counter in the dataplane ingress pipeline.
*
* @param ingressPkts ingress packet count
* @param ingressBytes egress packet count
@@ -133,7 +143,7 @@
}
/**
- * Set the number of packets and bytes that hit the PDR counter in the dataplane egress pipeline.
+ * Set the number of packets and bytes that hit the counter in the dataplane egress pipeline.
*
* @param egressPkts egress packet count
* @param egressBytes egress byte count
@@ -145,9 +155,9 @@
return this;
}
- public PdrStats build() {
+ public UpfCounter build() {
checkNotNull(cellId, "CellID must be provided");
- return new PdrStats(cellId, ingressPkts, ingressBytes, egressPkts, egressBytes);
+ return new UpfCounter(cellId, ingressPkts, ingressBytes, egressPkts, egressBytes);
}
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfDevice.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfDevice.java
index e0d9fb4..2b17421 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfDevice.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfDevice.java
@@ -28,157 +28,94 @@
public interface UpfDevice {
/**
- * Remove any state previously created by this API.
+ * Removes any state previously created by this API.
*/
void cleanUp();
/**
- * Remove all interfaces currently installed on the UPF-programmable device.
- */
- void clearInterfaces();
-
- /**
- * Remove all UE flows (PDRs, FARs) currently installed on the UPF-programmable device.
- */
- void clearFlows();
-
- /**
- * Get all ForwardingActionRules currently installed on the UPF-programmable device.
+ * Applies the given UPF entity to the UPF-programmable device.
*
- * @return a collection of installed FARs
- * @throws UpfProgrammableException if FARs are unable to be read
+ * @param entity The UPF entity to be applied.
+ * @throws UpfProgrammableException if the given UPF entity can not be applied or
+ * the operation is not supported on the given UPF entity.
*/
- Collection<ForwardingActionRule> getFars() throws UpfProgrammableException;
+ void apply(UpfEntity entity) throws UpfProgrammableException;
/**
- * Get all PacketDetectionRules currently installed on the UPF-programmable device.
+ * Reads all the UPF entities of the given type from the UPF-programmable device.
*
- * @return a collection of installed PDRs
- * @throws UpfProgrammableException if PDRs are unable to be read
+ * @param entityType The type of entities to read.
+ * @return A collection of installed UPF entities.
+ * @throws UpfProgrammableException if UPF entity type is not available to be read or
+ * the operation is not supported on the given UPF entity type.
*/
- Collection<PacketDetectionRule> getPdrs() throws UpfProgrammableException;
+ Collection<? extends UpfEntity> readAll(UpfEntityType entityType) throws UpfProgrammableException;
/**
- * Get all UPF interface lookup entries currently installed on the UPF-programmable device.
+ * Reads the given UPF counter ID from the UPF-programmable device.
*
- * @return a collection of installed interfaces
- * @throws UpfProgrammableException if interfaces are unable to be read
+ * @param counterId The counter ID from which to read.
+ * @return The content of the UPF counter.
+ * @throws UpfProgrammableException if the counter ID is out of bounds.
*/
- Collection<UpfInterface> getInterfaces() throws UpfProgrammableException;
+ UpfCounter readCounter(int counterId) throws UpfProgrammableException;
/**
- * Add a Packet Detection Rule (PDR) to the given device.
- *
- * @param pdr The PDR to be added
- * @throws UpfProgrammableException if the PDR cannot be installed, or the counter index is out
- * of bounds
- */
- void addPdr(PacketDetectionRule pdr) throws UpfProgrammableException;
-
- /**
- * Remove a previously installed Packet Detection Rule (PDR) from the target device.
- *
- * @param pdr The PDR to be removed
- * @throws UpfProgrammableException if the PDR cannot be found
- */
- void removePdr(PacketDetectionRule pdr) throws UpfProgrammableException;
-
- /**
- * Add a Forwarding Action Rule (FAR) to the given device.
- *
- * @param far The FAR to be added
- * @throws UpfProgrammableException if the FAR cannot be installed
- */
- void addFar(ForwardingActionRule far) throws UpfProgrammableException;
-
- /**
- * Remove a previously installed Forwarding Action Rule (FAR) from the target device.
- *
- * @param far The FAR to be removed
- * @throws UpfProgrammableException if the FAR cannot be found
- */
- void removeFar(ForwardingActionRule far) throws UpfProgrammableException;
-
- /**
- * Install a new interface on the UPF device's interface lookup tables.
- *
- * @param upfInterface the interface to install
- * @throws UpfProgrammableException if the interface cannot be installed
- */
- void addInterface(UpfInterface upfInterface) throws UpfProgrammableException;
-
- /**
- * Remove a previously installed UPF interface from the target device.
- *
- * @param upfInterface the interface to be removed
- * @throws UpfProgrammableException if the interface cannot be found
- */
- void removeInterface(UpfInterface upfInterface) throws UpfProgrammableException;
-
- /**
- * Read the the given cell (Counter index) of the PDR counters from the given device.
- *
- * @param counterIdx The counter cell index from which to read
- * @return A structure containing ingress and egress packet and byte counts for the given
- * cellId.
- * @throws UpfProgrammableException if the cell ID is out of bounds
- */
- PdrStats readCounter(int counterIdx) throws UpfProgrammableException;
-
- /**
- * Return the number of PDR counter cells available. The number of cells in the ingress and
- * egress PDR counters are equivalent.
- *
- * @return PDR counter size
- */
- long pdrCounterSize();
-
- /**
- * Return the number of maximum number of table entries the FAR table supports.
- *
- * @return the number of FARs that can be installed
- */
- long farTableSize();
-
- /**
- * Return the total number of table entries the downlink and uplink PDR tables support. Both
- * tables support an equal number of entries, so the total is twice the size of either.
- *
- * @return the total number of PDRs that can be installed
- */
- long pdrTableSize();
-
- /**
- * Read the counter contents for all cell indices that are valid on the hardware switch.
- * {@code maxCounterId} parameter is used to limit the number of counters
- * retrieved from the UPF device. If the limit given is larger than the
- * physical limit, the physical limit will be used. A limit of -1 removes
- * limitations.
+ * Reads the UPF counter contents for all indices that are valid on the
+ * UPF-programmable device. {@code maxCounterId} parameter is used to limit
+ * the number of counters retrieved from the UPF. If the limit given is
+ * larger than the physical limit, the physical limit will be used.
+ * A limit of -1 removes limitations, and it is equivalent of calling
+ * {@link #readAll(UpfEntityType)} passing the {@code COUNTER} {@link UpfEntityType}.
*
* @param maxCounterId Maximum counter ID to retrieve from the UPF device.
- * @return A collection of counter values for all valid hardware counter cells
- * @throws UpfProgrammableException if the counters are unable to be read
+ * @return A collection of UPF counters for all valid hardware counter cells.
+ * @throws UpfProgrammableException if the counters are unable to be read.
*/
- Collection<PdrStats> readAllCounters(long maxCounterId) throws UpfProgrammableException;
+ Collection<UpfCounter> readCounters(long maxCounterId) throws UpfProgrammableException;
+
+ /**
+ * Deletes the given UPF entity from the UPF-programmable device.
+ *
+ * @param entity The UPF entity to be removed.
+ * @throws UpfProgrammableException if the given UPF entity is not found or
+ * the operation is not supported on the given UPF entity.
+ */
+ void delete(UpfEntity entity) throws UpfProgrammableException;
+
+ /**
+ * Deletes the given UPF entity from the UPF-programmable device.
+ *
+ * @param entityType The UPF entity type to be removed.
+ * @throws UpfProgrammableException if the given UPF entity is not found or
+ * the operation is not supported on the given UPF entity.
+ */
+ void deleteAll(UpfEntityType entityType) throws UpfProgrammableException;
+
+ /**
+ * Returns the total number of UPF entities of the given type supported by
+ * the UPF-programmable device. For entities that have a direction,returns
+ * the total amount of entities including both the downlink and the uplink
+ * directions.
+ * @param entityType The type of UPF programmable entities to retrieve the size from.
+ * @return The total number of supported UPF entities.
+ * @throws UpfProgrammableException if the operation is not supported on the given UPF entity.
+ */
+ long tableSize(UpfEntityType entityType) throws UpfProgrammableException;
/**
* Instructs the UPF-programmable device to use GTP-U extension PDU Session Container (PSC) when
* doing encap of downlink packets, with the given QoS Flow Identifier (QFI).
*
- * @param defaultQfi QFI to be used by default for all encapped packets.
* @throws UpfProgrammableException if operation is not available
*/
- // FIXME: remove once we expose QFI in logical pipeline
- // QFI should be set by the SMF using PFCP
- void enablePscEncap(int defaultQfi) throws UpfProgrammableException;
+ void enablePscEncap() throws UpfProgrammableException;
/**
- * Disable PSC encap previously enabled with {@link #enablePscEncap(int)}.
+ * Disable PSC encap previously enabled with {@link #enablePscEncap()}.
*
* @throws UpfProgrammableException if operation is not available
*/
- // FIXME: remove once we expose QFI in logical pipeline
- // QFI should be set by the SMF using PFCP
void disablePscEncap() throws UpfProgrammableException;
/**
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfEntity.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfEntity.java
new file mode 100644
index 0000000..ad1fbaa
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfEntity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021-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.net.behaviour.upf;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Abstraction of a UPF entity used to interact with the UPF-programmable device.
+ */
+@Beta
+public interface UpfEntity {
+ /**
+ * Returns the type of this entity.
+ *
+ * @return entity type
+ */
+ UpfEntityType type();
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfEntityType.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfEntityType.java
new file mode 100644
index 0000000..7ec3b19
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfEntityType.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-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.net.behaviour.upf;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Type of UPF entity.
+ */
+@Beta
+public enum UpfEntityType {
+ INTERFACE("interface"),
+ TERMINATION_DOWNLINK("termination_downlink"),
+ TERMINATION_UPLINK("termination_uplink"),
+ SESSION_DOWNLINK("session_downlink"),
+ SESSION_UPLINK("session_downlink"),
+ TUNNEL_PEER("tunnel_peer"),
+ COUNTER("counter");
+
+ private final String humanReadableName;
+
+ UpfEntityType(String humanReadableName) {
+ this.humanReadableName = humanReadableName;
+ }
+
+ /**
+ * Returns a human readable representation of this UPF entity type (useful
+ * for logging).
+ *
+ * @return string
+ */
+ public String humanReadableName() {
+ return humanReadableName;
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfInterface.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfInterface.java
index 3fee11a..f697d15 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfInterface.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfInterface.java
@@ -16,6 +16,7 @@
package org.onosproject.net.behaviour.upf;
+import com.google.common.annotations.Beta;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
@@ -26,7 +27,8 @@
/**
* A UPF device interface, such as a S1U or UE IP address pool.
*/
-public final class UpfInterface {
+@Beta
+public final class UpfInterface implements UpfEntity {
private final Ip4Prefix prefix;
private final Type type;
@@ -134,7 +136,6 @@
return type == Type.CORE;
}
-
/**
* Check if this UPF interface is for receiving buffered packets as they are released from the dbuf
* buffering device.
@@ -154,6 +155,11 @@
return this.prefix;
}
+ @Override
+ public UpfEntityType type() {
+ return UpfEntityType.INTERFACE;
+ }
+
public enum Type {
/**
* Unknown UPF interface type.
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammable.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammable.java
index 159adb0..052084e 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammable.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammable.java
@@ -30,13 +30,12 @@
public interface UpfProgrammable extends HandlerBehaviour, UpfDevice {
/**
* Apps are expected to call this method as the first one when they are ready
- * to install PDRs and FARs.
+ * to install any UPF entity.
*
* @return True if initialized, false otherwise.
*/
boolean init();
-
/**
* Checks if the given flow rule has been generated by this UPF behaviour.
*
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammableException.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammableException.java
index 7daa806..96f8c85 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammableException.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfProgrammableException.java
@@ -16,14 +16,20 @@
package org.onosproject.net.behaviour.upf;
+import com.google.common.annotations.Beta;
+
+import java.util.Optional;
+
/**
* An exception indicating a an error happened in the UPF programmable behaviour.
* Possible errors include the attempted insertion of a malformed flow rule, the
* reading or writing of an out-of-bounds counter cell, the deletion of a non-existent
* flow rule, and the attempted insertion of a flow rule into a full table.
*/
+@Beta
public class UpfProgrammableException extends Exception {
private final Type type;
+ private final UpfEntityType entityType;
public enum Type {
/**
@@ -31,13 +37,13 @@
*/
UNKNOWN,
/**
- * The target table is at capacity.
+ * The target entity is at capacity.
*/
- TABLE_EXHAUSTED,
+ ENTITY_EXHAUSTED,
/**
- * A provided counter cell index was out of range.
+ * A provided index was out of range.
*/
- COUNTER_INDEX_OUT_OF_RANGE,
+ ENTITY_OUT_OF_RANGE,
/**
* The UpfProgrammable implementation doesn't support the operation.
*/
@@ -52,6 +58,7 @@
public UpfProgrammableException(String message) {
super(message);
this.type = Type.UNKNOWN;
+ this.entityType = null;
}
/**
@@ -63,6 +70,20 @@
public UpfProgrammableException(String message, Type type) {
super(message);
this.type = type;
+ this.entityType = null;
+ }
+
+ /**
+ * Creates a new exception for the given message, type and entity type.
+ *
+ * @param message exception message
+ * @param type exception type
+ * @param entityType entity type
+ */
+ public UpfProgrammableException(String message, Type type, UpfEntityType entityType) {
+ super(message);
+ this.type = type;
+ this.entityType = entityType;
}
/**
@@ -73,4 +94,13 @@
public Type getType() {
return type;
}
+
+ /**
+ * Get the type of the entity that generated the exception.
+ *
+ * @return entity type
+ */
+ public Optional<UpfEntityType> getEntityType() {
+ return Optional.ofNullable(entityType);
+ }
}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfTerminationDownlink.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfTerminationDownlink.java
new file mode 100644
index 0000000..3bc9a91
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfTerminationDownlink.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2021-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.net.behaviour.upf;
+
+import com.google.common.annotations.Beta;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A structure representing the UE Termination in the downlink direction on the
+ * UPF-programmable device.
+ * Provides means to configure the traffic behavior (e.g. set Traffic Class, GTP TEID, or QFI).
+ */
+@Beta
+public final class UpfTerminationDownlink implements UpfEntity {
+ // Match Keys
+ private final Ip4Address ueSessionId; // UE Session ID, use UE IP address to uniquely identify a session.
+ // Action parameters
+ private final Integer ctrId; // Counter ID unique to this UPF Termination Rule
+ private final Byte trafficClass;
+ private final Integer teid; // Tunnel Endpoint Identifier
+ private final Byte qfi; // QoS Flow Identifier
+ private final boolean dropping;
+
+ private UpfTerminationDownlink(Ip4Address ueSessionId, Integer ctrId, Byte trafficClass,
+ Integer teid, Byte qfi, boolean dropping) {
+ this.ueSessionId = ueSessionId;
+ this.ctrId = ctrId;
+ this.trafficClass = trafficClass;
+ this.teid = teid;
+ this.qfi = qfi;
+ this.dropping = dropping;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ UpfTerminationDownlink that = (UpfTerminationDownlink) obj;
+
+ // Safe comparisons between potentially null objects
+ return this.dropping == that.dropping &&
+ Objects.equals(this.ueSessionId, that.ueSessionId) &&
+ Objects.equals(this.ctrId, that.ctrId) &&
+ Objects.equals(this.trafficClass, that.trafficClass) &&
+ Objects.equals(this.teid, that.teid) &&
+ Objects.equals(this.qfi, that.qfi);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ueSessionId, ctrId, trafficClass, teid, qfi, dropping);
+ }
+
+ /**
+ * Get UE Session ID associated with UPF Termination rule.
+ *
+ * @return UE Session ID
+ */
+ public Ip4Address ueSessionId() {
+ return ueSessionId;
+ }
+
+ /**
+ * Get PDR Counter ID associated with UPF Termination rule.
+ *
+ * @return PDR counter cell ID
+ */
+ public Integer counterId() {
+ return ctrId;
+ }
+
+ /**
+ * Get Traffic Class set by this UPF Termination rule.
+ *
+ * @return Traffic Class
+ */
+ public Byte trafficClass() {
+ return trafficClass;
+ }
+
+ /**
+ * Get GTP TEID set by this UPF Termination rule.
+ *
+ * @return GTP tunnel ID
+ */
+ public Integer teid() {
+ return teid;
+ }
+
+ /**
+ * Get QoS Flow Identifier set by this UPF Termination rule.
+ *
+ * @return QoS Flow Identifier
+ */
+ public Byte qfi() {
+ return qfi;
+ }
+
+ /**
+ * True if this UPF Termination needs to drop traffic.
+ *
+ * @return true if the UPF Termination needs dropping.
+ */
+ public boolean needsDropping() {
+ return dropping;
+ }
+
+ @Override
+ public UpfEntityType type() {
+ return UpfEntityType.TERMINATION_DOWNLINK;
+ }
+
+ @Override
+ public String toString() {
+ return "TerminationUL{" + matchString() + "->" + actionString() + "}";
+ }
+
+ private String matchString() {
+ return "Match(ue_addr=" + this.ueSessionId() + ")";
+ }
+
+ private String actionString() {
+ return "(TEID=" + this.teid() +
+ ", CTR_ID=" + this.counterId() +
+ ", QFI=" + this.qfi() +
+ ", TC=" + this.trafficClass() +
+ ")";
+ }
+
+ public static class Builder {
+ private Ip4Address ueSessionId = null;
+ private Integer ctrId = null;
+ private Byte trafficClass = null;
+ private Integer teid = null;
+ private Byte qfi = null;
+ private boolean drop = false;
+
+ public Builder() {
+
+ }
+
+ /**
+ * Set the ID of the UE session.
+ *
+ * @param ueSessionId UE session ID
+ * @return This builder object
+ */
+ public Builder withUeSessionId(Ip4Address ueSessionId) {
+ this.ueSessionId = ueSessionId;
+ return this;
+ }
+
+ /**
+ * Set the dataplane counter cell ID.
+ *
+ * @param ctrId PDR counter cell ID
+ * @return This builder object
+ */
+ public Builder withCounterId(int ctrId) {
+ this.ctrId = ctrId;
+ return this;
+ }
+
+ /**
+ * Set the Traffic Class.
+ *
+ * @param trafficClass Traffic Class
+ * @return This builder object
+ */
+ public Builder withTrafficClass(byte trafficClass) {
+ this.trafficClass = trafficClass;
+ return this;
+ }
+
+ /**
+ * Set the identifier of the unidirectional GTP tunnel that should be used for the UE Session.
+ *
+ * @param teid tunnel ID
+ * @return This builder object
+ */
+ public Builder withTeid(Integer teid) {
+ this.teid = teid;
+ return this;
+ }
+
+ /**
+ * Set the QoS Flow Identifier.
+ *
+ * @param qfi GTP Tunnel QFI
+ * @return This builder object
+ */
+ public Builder withQfi(byte qfi) {
+ this.qfi = qfi;
+ return this;
+ }
+
+ /**
+ * Sets whether to drop downlink UPF termination traffic or not.
+ *
+ * @param drop True if request to buffer, false otherwise
+ * @return This builder object
+ */
+ public Builder needsDropping(boolean drop) {
+ this.drop = drop;
+ return this;
+ }
+
+
+ public UpfTerminationDownlink build() {
+ // Match fields must be provided
+ checkNotNull(ueSessionId, "UE session ID must be provided");
+
+ checkNotNull(ctrId, "Counter ID must be provided");
+ // TODO: should we verify that when dropping no other fields are provided
+ return new UpfTerminationDownlink(
+ this.ueSessionId, this.ctrId, this.trafficClass, this.teid,
+ this.qfi, this.drop
+ );
+ }
+
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfTerminationUplink.java b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfTerminationUplink.java
new file mode 100644
index 0000000..74dbc01
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/upf/UpfTerminationUplink.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2021-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.net.behaviour.upf;
+
+import com.google.common.annotations.Beta;
+import org.onlab.packet.Ip4Address;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A structure representing the UE Termination in the uplink direction on the
+ * UPF-programmable device.
+ * Provides means to configure the traffic behavior (e.g. set Traffic Class).
+ */
+@Beta
+public final class UpfTerminationUplink implements UpfEntity {
+ // Match Keys
+ private final Ip4Address ueSessionId; // UE Session ID, use UE IP address to uniquely identify a session.
+ // Action parameters
+ private final Integer ctrId; // Counter ID unique to this UPF Termination Rule
+ private final Byte trafficClass;
+ private final boolean dropping;
+
+ private UpfTerminationUplink(Ip4Address ueSessionId, Integer ctrId, Byte trafficClass,
+ boolean dropping) {
+ this.ueSessionId = ueSessionId;
+ this.ctrId = ctrId;
+ this.trafficClass = trafficClass;
+ this.dropping = dropping;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ UpfTerminationUplink that = (UpfTerminationUplink) obj;
+
+ // Safe comparisons between potentially null objects
+ return this.dropping == that.dropping &&
+ Objects.equals(this.ueSessionId, that.ueSessionId) &&
+ Objects.equals(this.ctrId, that.ctrId) &&
+ Objects.equals(this.trafficClass, that.trafficClass);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ueSessionId, ctrId, trafficClass, dropping);
+ }
+
+ /**
+ * Get UE Session ID associated with UPF Termination rule.
+ *
+ * @return UE Session ID
+ */
+ public Ip4Address ueSessionId() {
+ return ueSessionId;
+ }
+
+ /**
+ * Get PDR Counter ID associated with UPF Termination rule.
+ *
+ * @return PDR counter cell ID
+ */
+ public Integer counterId() {
+ return ctrId;
+ }
+
+ /**
+ * Get Traffic Class set by this UPF Termination rule.
+ *
+ * @return Traffic Class
+ */
+ public Byte trafficClass() {
+ return trafficClass;
+ }
+
+ /**
+ * True if this UPF Termination needs to drop traffic.
+ *
+ * @return true if the UPF Termination needs dropping.
+ */
+ public boolean needsDropping() {
+ return dropping;
+ }
+
+ @Override
+ public UpfEntityType type() {
+ return UpfEntityType.TERMINATION_UPLINK;
+ }
+
+ @Override
+ public String toString() {
+ return "TerminationDL{" + matchString() + "->" + actionString() + "}";
+ }
+
+ private String matchString() {
+ return "Match(ue_addr=" + this.ueSessionId() + ")";
+ }
+
+ private String actionString() {
+ return "(CTR_ID=" + this.counterId() + ", TC=" + this.trafficClass() + ")";
+ }
+
+ public static class Builder {
+ private Ip4Address ueSessionId = null;
+ private Integer ctrId = null;
+ private Byte trafficClass = null;
+ private boolean dropping = false;
+
+ public Builder() {
+
+ }
+
+ /**
+ * Set the ID of the UE session.
+ *
+ * @param ueSessionId UE session ID
+ * @return This builder object
+ */
+ public Builder withUeSessionId(Ip4Address ueSessionId) {
+ this.ueSessionId = ueSessionId;
+ return this;
+ }
+
+ /**
+ * Set the dataplane counter cell ID.
+ *
+ * @param ctrId PDR counter cell ID
+ * @return This builder object
+ */
+ public Builder withCounterId(int ctrId) {
+ this.ctrId = ctrId;
+ return this;
+ }
+
+ /**
+ * Set the Traffic Class.
+ *
+ * @param trafficClass Traffic Class
+ * @return This builder object
+ */
+ public Builder withTrafficClass(byte trafficClass) {
+ this.trafficClass = trafficClass;
+ return this;
+ }
+
+ /**
+ * Sets whether to drop uplink UPF termination traffic or not.
+ *
+ * @param dropping True if request to buffer, false otherwise
+ * @return This builder object
+ */
+ public Builder needsDropping(boolean dropping) {
+ this.dropping = dropping;
+ return this;
+ }
+
+ public UpfTerminationUplink build() {
+ // Match fields must be provided
+ checkNotNull(ueSessionId, "UE session ID must be provided");
+
+ checkNotNull(ctrId, "Counter ID must be provided");
+ // TODO: should we verify that when dropping no other fields are provided
+ return new UpfTerminationUplink(
+ this.ueSessionId, this.ctrId, this.trafficClass, this.dropping);
+ }
+
+ }
+
+}