blob: c39500970500a083689f660d04e49f999af9080d [file] [log] [blame]
Daniele Moro5e66f982021-06-11 16:41:48 +02001/*
2 * Copyright 2021-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.net.behaviour.upf;
18
tosinski36ba33a2021-11-22 16:53:00 +010019import com.google.common.annotations.Beta;
20
Daniele Morof3a5ab02022-01-26 16:47:08 +010021import java.util.Objects;
Daniele Moroe7198362022-04-28 19:37:32 +020022import java.util.Optional;
Daniele Morof3a5ab02022-01-26 16:47:08 +010023
Daniele Moroe7198362022-04-28 19:37:32 +020024import static com.google.common.base.Preconditions.checkArgument;
Daniele Moro5e66f982021-06-11 16:41:48 +020025import static com.google.common.base.Preconditions.checkNotNull;
Daniele Moroe7198362022-04-28 19:37:32 +020026import static org.onosproject.net.behaviour.upf.UpfEntityType.COUNTER;
27import static org.onosproject.net.behaviour.upf.UpfEntityType.EGRESS_COUNTER;
28import static org.onosproject.net.behaviour.upf.UpfEntityType.INGRESS_COUNTER;
Daniele Moro5e66f982021-06-11 16:41:48 +020029
30/**
Daniele Moroe7198362022-04-28 19:37:32 +020031 * A structure for compactly passing UPF counter (ingress, egress or both) values
32 * for a given counter ID. Contains four counts: Ingress Packets, Ingress Bytes,
33 * Egress Packets, Egress Bytes. UpfCounter can be used ONLY on {@code apply}
34 * and {@code readAll} calls in the {@link UpfDevice} interface.
Daniele Moro5e66f982021-06-11 16:41:48 +020035 */
tosinski36ba33a2021-11-22 16:53:00 +010036@Beta
37public final class UpfCounter implements UpfEntity {
Daniele Moro5e66f982021-06-11 16:41:48 +020038 private final int cellId;
Daniele Moroe7198362022-04-28 19:37:32 +020039 private final Long ingressPkts;
40 private final Long ingressBytes;
41 private final Long egressPkts;
42 private final Long egressBytes;
43 private final UpfEntityType type;
Daniele Moro5e66f982021-06-11 16:41:48 +020044
Daniele Moroe7198362022-04-28 19:37:32 +020045 private UpfCounter(int cellId, Long ingressPkts, Long ingressBytes,
46 Long egressPkts, Long egressBytes, UpfEntityType type) {
Daniele Moro5e66f982021-06-11 16:41:48 +020047 this.cellId = cellId;
48 this.ingressPkts = ingressPkts;
49 this.ingressBytes = ingressBytes;
50 this.egressPkts = egressPkts;
51 this.egressBytes = egressBytes;
Daniele Moroe7198362022-04-28 19:37:32 +020052 this.type = type;
Daniele Moro5e66f982021-06-11 16:41:48 +020053 }
54
55 public static Builder builder() {
56 return new Builder();
57 }
58
59 @Override
60 public String toString() {
Daniele Moroe7198362022-04-28 19:37:32 +020061 switch (this.type) {
62 case COUNTER:
63 return String.format("UpfStats(cell_id=%d, ingress=(%dpkts,%dbytes), egress=(%dpkts,%dbytes))",
64 cellId, ingressPkts, ingressBytes, egressPkts, egressBytes);
65 case INGRESS_COUNTER:
66 return String.format("UpfIngressCounter(cell_id=%d, packets=%d, bytes=%d))",
67 cellId, ingressPkts, ingressBytes);
68 case EGRESS_COUNTER:
69 return String.format("UpfEgressCounter(cell_id=%d, packets=%d, bytes=%d))",
70 cellId, egressPkts, egressBytes);
71 default:
72 throw new IllegalStateException("I should never reach this point!");
73 }
Daniele Moro5e66f982021-06-11 16:41:48 +020074 }
75
Daniele Morof3a5ab02022-01-26 16:47:08 +010076 @Override
77 public boolean equals(Object object) {
78 if (object == this) {
79 return true;
80 }
81 if (object == null) {
82 return false;
83 }
84 if (getClass() != object.getClass()) {
85 return false;
86 }
87 UpfCounter that = (UpfCounter) object;
Daniele Moroe7198362022-04-28 19:37:32 +020088 return this.cellId == that.cellId && this.type == that.type;
Daniele Morof3a5ab02022-01-26 16:47:08 +010089 }
90
91 /**
92 * Returns whether this UpfCounter is exactly equal to the given UpfCounter,
93 * including their packets and bytes values.
94 *
95 * @param that other {@link UpfCounter} instance to compare
96 * @return true if exactly equals, false otherwise
97 */
98 public boolean exactlyEquals(UpfCounter that) {
99 return this.equals(that) &&
Daniele Moroe7198362022-04-28 19:37:32 +0200100 (this.ingressPkts == that.ingressPkts || this.ingressPkts.equals(that.ingressPkts)) &&
101 (this.ingressBytes == that.ingressBytes || this.ingressBytes.equals(that.ingressBytes)) &&
102 (this.egressPkts == that.egressPkts || this.egressPkts.equals(that.egressPkts)) &&
103 (this.egressBytes == that.egressBytes || this.egressBytes.equals(that.egressBytes));
Daniele Morof3a5ab02022-01-26 16:47:08 +0100104 }
105
Daniele Morof3a5ab02022-01-26 16:47:08 +0100106 @Override
107 public int hashCode() {
Daniele Moroe7198362022-04-28 19:37:32 +0200108 return Objects.hash(cellId, type);
Daniele Morof3a5ab02022-01-26 16:47:08 +0100109 }
110
Daniele Moro5e66f982021-06-11 16:41:48 +0200111 /**
tosinski36ba33a2021-11-22 16:53:00 +0100112 * Get the cell ID (index) of the dataplane counter that produced this set of stats.
Daniele Moro5e66f982021-06-11 16:41:48 +0200113 *
114 * @return counter cell ID
115 */
116 public int getCellId() {
117 return cellId;
118 }
119
120 /**
121 * Get the number of packets that hit this counter in the dataplane ingress pipeline.
Daniele Moroe7198362022-04-28 19:37:32 +0200122 * Return a value only if the counter is of type {@code UpfEntityType.COUNTER}
123 * or {@code UpfEntityType.INGRESS_COUNTER}, otherwise an empty Optional.
Daniele Moro5e66f982021-06-11 16:41:48 +0200124 *
Daniele Moroe7198362022-04-28 19:37:32 +0200125 * @return ingress packet count or empty if this is of type {@code UpfEntityType.EGRESS_COUNTER}
Daniele Moro5e66f982021-06-11 16:41:48 +0200126 */
Daniele Moroe7198362022-04-28 19:37:32 +0200127 public Optional<Long> getIngressPkts() {
128 return Optional.ofNullable(ingressPkts);
Daniele Moro5e66f982021-06-11 16:41:48 +0200129 }
130
131 /**
132 * Get the number of packets that hit this counter in the dataplane egress pipeline.
Daniele Moroe7198362022-04-28 19:37:32 +0200133 * Return a value only if the counter is of type {@code UpfEntityType.COUNTER}
134 * or {@code UpfEntityType.EGRESS_COUNTER}, otherwise an empty Optional.
Daniele Moro5e66f982021-06-11 16:41:48 +0200135 *
Daniele Moroe7198362022-04-28 19:37:32 +0200136 * @return egress packet count or empty if this is of type {@code UpfEntityType.INGRESS_COUNTER}
Daniele Moro5e66f982021-06-11 16:41:48 +0200137 */
Daniele Moroe7198362022-04-28 19:37:32 +0200138 public Optional<Long> getEgressPkts() {
139 return Optional.ofNullable(egressPkts);
Daniele Moro5e66f982021-06-11 16:41:48 +0200140 }
141
142 /**
143 * Get the number of packet bytes that hit this counter in the dataplane ingress pipeline.
Daniele Moroe7198362022-04-28 19:37:32 +0200144 * Return value only if the counter is of type {{@code UpfEntityType.COUNTER}
145 * or {@code UpfEntityType.INGRESS_COUNTER}, otherwise an empty Optional.
Daniele Moro5e66f982021-06-11 16:41:48 +0200146 *
Daniele Moroe7198362022-04-28 19:37:32 +0200147 * @return ingress byte count or empty if this is of type {@code UpfEntityType.EGRESS_COUNTER}
Daniele Moro5e66f982021-06-11 16:41:48 +0200148 */
Daniele Moroe7198362022-04-28 19:37:32 +0200149 public Optional<Long> getIngressBytes() {
150 return Optional.ofNullable(ingressBytes);
Daniele Moro5e66f982021-06-11 16:41:48 +0200151 }
152
153 /**
154 * Get the number of packet bytes that hit this counter in the dataplane egress pipeline.
Daniele Moroe7198362022-04-28 19:37:32 +0200155 * Return a value only if the counter is of type {@code UpfEntityType.COUNTER}
156 * or {@code UpfEntityType.EGRESS_COUNTER}, otherwise an empty Optional.
Daniele Moro5e66f982021-06-11 16:41:48 +0200157 *
Daniele Moroe7198362022-04-28 19:37:32 +0200158 * @return egress byte count or empty if this is of type {@code UpfEntityType.INGRESS_COUNTER}
Daniele Moro5e66f982021-06-11 16:41:48 +0200159 */
Daniele Moroe7198362022-04-28 19:37:32 +0200160 public Optional<Long> getEgressBytes() {
161 return Optional.ofNullable(egressBytes);
Daniele Moro5e66f982021-06-11 16:41:48 +0200162 }
163
tosinski36ba33a2021-11-22 16:53:00 +0100164 @Override
165 public UpfEntityType type() {
Daniele Moroe7198362022-04-28 19:37:32 +0200166 return type;
tosinski36ba33a2021-11-22 16:53:00 +0100167 }
168
Daniele Moroe7198362022-04-28 19:37:32 +0200169 /**
170 * Sum the content of the given UpfCounter to the counter values contained
171 * in this instance.
172 *
173 * @param that The UpfCounter to sum to this instance
174 * @return a new UpfCounter instance with sum counters.
175 * @throws IllegalArgumentException if the given UpfCounter is not referring
176 * to the same type and id as this
177 */
178 public UpfCounter sum(UpfCounter that) throws IllegalArgumentException {
179 if (!this.equals(that)) {
180 throw new IllegalArgumentException(
181 "The given UpfCounter is not of the same type or refers to a different index");
182 }
183 UpfCounter.Builder builder = UpfCounter.builder().withCellId(this.getCellId());
184 if (this.type.equals(UpfEntityType.COUNTER) || this.type.equals(UpfEntityType.INGRESS_COUNTER)) {
185 builder.setIngress(this.ingressPkts + that.ingressPkts,
186 this.ingressBytes + that.ingressBytes);
187 }
188 if (this.type.equals(UpfEntityType.COUNTER) || this.type.equals(UpfEntityType.EGRESS_COUNTER)) {
189 builder.setEgress(this.egressPkts + that.egressPkts,
190 this.egressBytes + that.egressBytes);
191 }
192 return builder.build();
193 }
194
195 /**
196 * Builder for UpfCounter.
197 */
Daniele Moro5e66f982021-06-11 16:41:48 +0200198 public static class Builder {
199 private Integer cellId;
Daniele Moroe7198362022-04-28 19:37:32 +0200200 private Long ingressPkts;
201 private Long ingressBytes;
202 private Long egressPkts;
203 private Long egressBytes;
204 private UpfEntityType type = COUNTER;
Daniele Moro5e66f982021-06-11 16:41:48 +0200205
206 public Builder() {
Daniele Moro5e66f982021-06-11 16:41:48 +0200207 }
208
209 /**
tosinski36ba33a2021-11-22 16:53:00 +0100210 * Set the Cell ID (index) of the datalane counter that produced this set of stats.
Daniele Moro5e66f982021-06-11 16:41:48 +0200211 *
212 * @param cellId the counter cell ID
213 * @return This builder
214 */
215 public Builder withCellId(int cellId) {
216 this.cellId = cellId;
217 return this;
218 }
219
220 /**
tosinski36ba33a2021-11-22 16:53:00 +0100221 * Set the number of packets and bytes that hit the counter in the dataplane ingress pipeline.
Daniele Moro5e66f982021-06-11 16:41:48 +0200222 *
223 * @param ingressPkts ingress packet count
224 * @param ingressBytes egress packet count
225 * @return This builder
226 */
227 public Builder setIngress(long ingressPkts, long ingressBytes) {
228 this.ingressPkts = ingressPkts;
229 this.ingressBytes = ingressBytes;
230 return this;
231 }
232
233 /**
tosinski36ba33a2021-11-22 16:53:00 +0100234 * Set the number of packets and bytes that hit the counter in the dataplane egress pipeline.
Daniele Moro5e66f982021-06-11 16:41:48 +0200235 *
236 * @param egressPkts egress packet count
237 * @param egressBytes egress byte count
238 * @return This builder
239 */
240 public Builder setEgress(long egressPkts, long egressBytes) {
241 this.egressPkts = egressPkts;
242 this.egressBytes = egressBytes;
243 return this;
244 }
245
Daniele Moroe7198362022-04-28 19:37:32 +0200246 /**
247 * Set the counter as ingress only counter.
248 *
249 * @return This builder
250 */
251 public Builder isIngressCounter() {
252 this.type = INGRESS_COUNTER;
253 return this;
254 }
255
256 /**
257 * Set the counter as egress only counter.
258 *
259 * @return This builder
260 */
261 public Builder isEgressCounter() {
262 this.type = EGRESS_COUNTER;
263 return this;
264 }
265
tosinski36ba33a2021-11-22 16:53:00 +0100266 public UpfCounter build() {
Daniele Moro5e66f982021-06-11 16:41:48 +0200267 checkNotNull(cellId, "CellID must be provided");
Daniele Moroe7198362022-04-28 19:37:32 +0200268 switch (type) {
269 case INGRESS_COUNTER:
270 checkArgument(this.ingressBytes != null && this.ingressPkts != null,
271 "Ingress counter values must be provided");
272 this.egressBytes = null;
273 this.egressPkts = null;
274 break;
275 case EGRESS_COUNTER:
276 checkArgument(this.egressBytes != null && this.egressPkts != null,
277 "Egress counter values must be provided");
278 this.ingressBytes = null;
279 this.ingressPkts = null;
280 break;
281 case COUNTER:
282 checkArgument(this.ingressBytes != null && this.ingressPkts != null &&
283 this.egressBytes != null && this.egressPkts != null,
284 "Ingress and egress counter values must be provided");
285 break;
286 default:
287 // I should never reach this point
288 throw new IllegalArgumentException("I should never reach this point!");
289 }
290 return new UpfCounter(cellId, ingressPkts, ingressBytes, egressPkts, egressBytes, type);
Daniele Moro5e66f982021-06-11 16:41:48 +0200291 }
292 }
293}