blob: 39302ebe3791688f145f5471a81aa02c358016b9 [file] [log] [blame]
Daniele Moro909b9582022-01-26 15:47:29 +01001/*
2 * Copyright 2022-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
Daniele Moro31faf952022-03-09 10:52:32 +010019import com.google.common.annotations.Beta;
Daniele Moro909b9582022-01-26 15:47:29 +010020import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.Maps;
22import org.onosproject.net.meter.Band;
23import org.onosproject.net.meter.DefaultBand;
24
25import java.util.Map;
26import java.util.Objects;
27import java.util.Optional;
28
29import static com.google.common.base.Preconditions.checkArgument;
30import static com.google.common.base.Preconditions.checkNotNull;
31import static org.onosproject.net.behaviour.upf.UpfEntityType.APPLICATION_METER;
32import static org.onosproject.net.behaviour.upf.UpfEntityType.SESSION_METER;
Daniele Moro31faf952022-03-09 10:52:32 +010033import static org.onosproject.net.behaviour.upf.UpfEntityType.SLICE_METER;
Daniele Moro909b9582022-01-26 15:47:29 +010034import static org.onosproject.net.meter.Band.Type.MARK_RED;
35import static org.onosproject.net.meter.Band.Type.MARK_YELLOW;
36
37/**
Daniele Moro31faf952022-03-09 10:52:32 +010038 * A structure representing a UPF meter, either for metering session (UE),
39 * application traffic, or slice traffic.
40 * UPF meters represent PFCP QER MBR and GBR information and slice maximum rate.
41 * UPF meters of type session and slice support only the peak band.
Daniele Moro909b9582022-01-26 15:47:29 +010042 * UPF meters of type application support both peak and committed bands.
43 */
Daniele Moro31faf952022-03-09 10:52:32 +010044@Beta
Daniele Moro909b9582022-01-26 15:47:29 +010045public final class UpfMeter implements UpfEntity {
46 private final int cellId;
47 private final ImmutableMap<Band.Type, Band> meterBands;
48 private final UpfEntityType type;
49
50 private UpfMeter(int cellId, Map<Band.Type, Band> meterBands, UpfEntityType type) {
51 this.cellId = cellId;
52 this.meterBands = ImmutableMap.copyOf(meterBands);
53 this.type = type;
54 }
55
56 @Override
57 public String toString() {
58 return String.format("UpfMeter(type=%s, index=%d, committed=%s, peak=%s)",
59 type, cellId, committedBand().orElse(null),
60 peakBand().orElse(null));
61 }
62
63 @Override
64 public boolean equals(Object object) {
65 if (this == object) {
66 return true;
67 }
68
69 if (object == null) {
70 return false;
71 }
72
73 if (getClass() != object.getClass()) {
74 return false;
75 }
76
77 UpfMeter that = (UpfMeter) object;
78 return this.type.equals(that.type) &&
79 this.cellId == that.cellId &&
80 this.meterBands.equals(that.meterBands);
81 }
82
83 @Override
84 public int hashCode() {
85 return Objects.hash(type, cellId, meterBands);
86 }
87
88 @Override
89 public UpfEntityType type() {
90 return this.type;
91 }
92
93 /**
94 * Get the meter cell index of this meter.
95 *
96 * @return the cell index
97 */
98 public int cellId() {
99 return this.cellId;
100 }
101
102 /**
103 * Get the committed band of this meter.
104 *
105 * @return the committed band, Empty if none
106 */
107 public Optional<Band> committedBand() {
108 return Optional.ofNullable(meterBands.getOrDefault(MARK_YELLOW, null));
109 }
110
111 /**
112 * Get the peak band of this meter.
113 *
114 * @return the peak band, Empty if none
115 */
116 public Optional<Band> peakBand() {
117 return Optional.ofNullable(meterBands.getOrDefault(MARK_RED, null));
118 }
119
120 /**
121 * Check if this UPF meter is for sessions (UE) traffic.
122 *
123 * @return true if the meter is for session traffic
124 */
125 public boolean isSession() {
126 return type.equals(SESSION_METER);
127 }
128
129 /**
130 * Check if this UPF meter is for application traffic.
131 *
132 * @return true if the meter is for application traffic
133 */
134 public boolean isApplication() {
135 return type.equals(APPLICATION_METER);
136 }
137
138 /**
139 * Check if this UPF meter is a reset.
140 *
141 * @return true if this represents a meter reset.
142 */
143 public boolean isReset() {
144 return meterBands.isEmpty();
145 }
146
147 /**
148 * Return a session UPF meter with no bands. Used to reset the meter.
149 *
150 * @param cellId the meter cell index of this meter
151 * @return a UpfMeter of type session with no bands
152 */
153 public static UpfMeter resetSession(int cellId) {
154 return new UpfMeter(cellId, Maps.newHashMap(), SESSION_METER);
155 }
156
157 /**
158 * Return an application UPF meter with no bands. Used to reset the meter.
159 *
160 * @param cellId the meter cell index of this meter
161 * @return a UpfMeter of type application with no bands
162 */
163 public static UpfMeter resetApplication(int cellId) {
164 return new UpfMeter(cellId, Maps.newHashMap(), APPLICATION_METER);
165 }
166
Daniele Moro31faf952022-03-09 10:52:32 +0100167 /**
168 * Return a slice meter with no bands. Used to reset the meter.
169 *
170 * @param cellId the meter cell index of this meter
171 * @return a UpfMeter of type slice with no bands
172 */
173 public static UpfMeter resetSlice(int cellId) {
174 return new UpfMeter(cellId, Maps.newHashMap(), SLICE_METER);
175 }
176
Daniele Moro909b9582022-01-26 15:47:29 +0100177 public static Builder builder() {
178 return new Builder();
179 }
180
181 /**
Daniele Moro31faf952022-03-09 10:52:32 +0100182 * Builder of UpfMeter object. Use {@link #resetApplication(int)},
183 * {@link #resetSession(int)}, or {@link #resetSlice(int)} to reset the
184 * meter config.
Daniele Moro909b9582022-01-26 15:47:29 +0100185 */
186 public static class Builder {
187 private Integer cellId = null;
188 private Map<Band.Type, Band> bands = Maps.newHashMap();
189 private UpfEntityType type;
190
191 public Builder() {
192
193 }
194
195 /**
196 * Set the meter cell index of this meter.
197 *
198 * @param cellId the meter cell index
199 * @return this builder object
200 */
201 public Builder setCellId(int cellId) {
202 this.cellId = cellId;
203 return this;
204 }
205
206 /**
207 * Set the committed band of this meter.
208 * Valid only for meter of type application.
209 *
210 * @param cir the Committed Information Rate in bytes/s
211 * @param cburst the Committed Burst in bytes
212 * @return this builder object
213 */
214 public Builder setCommittedBand(long cir, long cburst) {
215 this.bands.put(MARK_YELLOW,
216 DefaultBand.builder()
217 .ofType(MARK_YELLOW)
218 .withRate(cir)
219 .burstSize(cburst)
220 .build()
221 );
222 return this;
223 }
224
225 /**
226 * Set the peak band of this meter.
227 *
228 * @param pir the Peak Information Rate in bytes/s
229 * @param pburst the Peak Burst in bytes
230 * @return this builder object
231 */
232 public Builder setPeakBand(long pir, long pburst) {
233 this.bands.put(MARK_RED,
234 DefaultBand.builder()
235 .ofType(MARK_RED)
236 .withRate(pir)
237 .burstSize(pburst)
238 .build()
239 );
240 return this;
241 }
242
243 /**
244 * Make this meter a session meter.
245 *
246 * @return this builder object
247 */
248 public Builder setSession() {
249 this.type = SESSION_METER;
250 return this;
251 }
252
253 /**
254 * Make this meter an application meter.
255 *
256 * @return this builder object
257 */
258 public Builder setApplication() {
259 this.type = APPLICATION_METER;
260 return this;
261 }
262
Daniele Moro31faf952022-03-09 10:52:32 +0100263 /**
264 * Make this meter a slice meter.
265 *
266 * @return this builder object
267 */
268 public Builder setSlice() {
269 this.type = SLICE_METER;
270 return this;
271 }
272
Daniele Moro909b9582022-01-26 15:47:29 +0100273 public UpfMeter build() {
274 checkNotNull(type, "A meter type must be assigned");
275 switch (type) {
276 case SESSION_METER:
Daniele Moro31faf952022-03-09 10:52:32 +0100277 case SLICE_METER:
Daniele Moro909b9582022-01-26 15:47:29 +0100278 checkArgument(!bands.containsKey(MARK_YELLOW),
Daniele Moro31faf952022-03-09 10:52:32 +0100279 "Committed band can not be provided for " + type + " meter!");
Daniele Moro909b9582022-01-26 15:47:29 +0100280 break;
281 case APPLICATION_METER:
282 checkArgument((bands.containsKey(MARK_YELLOW) && bands.containsKey(MARK_RED)) || bands.isEmpty(),
283 "Bands (committed and peak) must be provided together or not at all!");
284 break;
285 default:
286 // I should never reach this point
287 throw new IllegalArgumentException("Invalid meter type, I should never reach this point");
288 }
289 checkNotNull(cellId, "Meter cell ID must be provided!");
290 return new UpfMeter(cellId, bands, type);
291 }
292 }
293}