blob: 212c03a15dad139825dd017bfb8b5f8716abdf5c [file] [log] [blame]
Daniele Moro94660a02019-12-02 12:02:07 -08001/*
Joey Armstronga68e7852024-01-28 13:27:02 -05002 * Copyright 2019-2024 Open Networking Foundation (ONF) and the ONF Contributors
Daniele Moro94660a02019-12-02 12:02:07 -08003 *
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
Daniele Moroad7057d2020-01-15 10:54:37 -080017package org.opencord.bng.impl;
Daniele Moro94660a02019-12-02 12:02:07 -080018
19import com.google.common.collect.Maps;
20import org.onlab.util.SharedScheduledExecutors;
21import org.onlab.util.Tools;
22import org.onosproject.cfg.ComponentConfigService;
23import org.onosproject.core.ApplicationId;
24import org.onosproject.core.CoreService;
25import org.onosproject.event.AbstractListenerManager;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.behaviour.BngProgrammable;
28import org.onosproject.net.device.DeviceService;
29import org.onosproject.net.pi.runtime.PiCounterCellData;
Daniele Moroad7057d2020-01-15 10:54:37 -080030import org.opencord.bng.BngAttachment;
31import org.opencord.bng.BngService;
32import org.opencord.bng.BngStatsEvent;
33import org.opencord.bng.BngStatsEventListener;
34import org.opencord.bng.BngStatsEventSubject;
35import org.opencord.bng.BngStatsService;
Daniele Moro94660a02019-12-02 12:02:07 -080036import org.osgi.service.component.ComponentContext;
37import org.osgi.service.component.annotations.Activate;
38import org.osgi.service.component.annotations.Component;
39import org.osgi.service.component.annotations.Deactivate;
40import org.osgi.service.component.annotations.Modified;
41import org.osgi.service.component.annotations.Reference;
42import org.osgi.service.component.annotations.ReferenceCardinality;
43import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
46import java.util.Dictionary;
47import java.util.Map;
48import java.util.Properties;
49import java.util.concurrent.ScheduledFuture;
50import java.util.concurrent.TimeUnit;
51
Daniele Moroad7057d2020-01-15 10:54:37 -080052import static org.opencord.bng.impl.OsgiPropertyConstants.BNG_STATISTICS_PROBE_RATE;
53import static org.opencord.bng.impl.OsgiPropertyConstants.BNG_STATISTICS_PROBE_RATE_DEFAULT;
Daniele Moro94660a02019-12-02 12:02:07 -080054
55@Component(immediate = true,
Daniele Moro94660a02019-12-02 12:02:07 -080056 property = {
57 BNG_STATISTICS_PROBE_RATE + ":Long=" + BNG_STATISTICS_PROBE_RATE_DEFAULT,
58 }
59)
60public class BngStatsManager
61 extends AbstractListenerManager<BngStatsEvent, BngStatsEventListener> implements BngStatsService {
62
63 private final Logger log = LoggerFactory.getLogger(getClass());
64 private final BngStatisticsMonitor bngStatsMonitor = new BngStatisticsMonitor();
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY)
67 protected ComponentConfigService componentConfigService;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY)
70 protected BngService bngService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY)
73 protected DeviceService deviceService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY)
76 protected CoreService coreService;
77
78 private ApplicationId appId;
79 /**
80 * The BNG statistics probe rate.
81 */
82 private long bngStatisticsProbeRate = BNG_STATISTICS_PROBE_RATE_DEFAULT;
83 private ScheduledFuture<?> timeout;
84
85 @Activate
86 protected void activate() {
87 eventDispatcher.addSink(BngStatsEvent.class, listenerRegistry);
88 componentConfigService.registerProperties(getClass());
89 appId = coreService.getAppId(BngManager.BNG_APP);
90 start();
91 log.info("BNG Statistics manager activated");
92 }
93
94 @Modified
95 protected void modified(ComponentContext context) {
96 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
97 Long probeRate = Tools.getLongProperty(properties, BNG_STATISTICS_PROBE_RATE);
98 if (probeRate != null) {
99 bngStatisticsProbeRate = probeRate;
100 }
101 }
102
103 @Deactivate
104 protected void deactivate() {
105 shutdown();
106 componentConfigService.unregisterProperties(getClass(), false);
107 eventDispatcher.removeSink(BngStatsEvent.class);
108 log.info("BNG Statistics manager deactivated");
109
110 }
111
112 /**
113 * Starts the BNG statistics monitor. Does nothing if the monitor is already
114 * running.
115 */
116 private void start() {
117 synchronized (bngStatsMonitor) {
118 if (timeout == null) {
119 timeout = SharedScheduledExecutors.newTimeout(bngStatsMonitor, 0, TimeUnit.MILLISECONDS);
120 }
121 }
122 }
123
124 /**
125 * Stops the BNG statistics monitor.
126 */
127 private void shutdown() {
128 synchronized (bngStatsMonitor) {
129 if (timeout != null) {
130 timeout.cancel(true);
131 timeout = null;
132 }
133 }
134 }
135
136 private Map<String, Map<BngProgrammable.BngCounterType, PiCounterCellData>> getStats(
137 Map<String, BngAttachment> attachments) {
138 Map<String, Map<BngProgrammable.BngCounterType, PiCounterCellData>>
139 stats = Maps.newHashMap();
140 attachments.forEach((key, value) -> stats.put(key, getStats(key)));
141 return stats;
142 }
143
144 @Override
145 public Map<BngProgrammable.BngCounterType, PiCounterCellData> getStats(
146 String bngAttachmentKey) {
147 BngProgrammable bngProgrammable = getBngProgrammable(bngService.getBngDeviceId());
148 BngAttachment attachment = bngService.getAttachment(bngAttachmentKey);
149 if (bngProgrammable != null && attachment != null) {
150 try {
151 return bngProgrammable.readCounters(attachment);
152 } catch (BngProgrammable.BngProgrammableException e) {
153 log.error("Error getting statistics of {}", bngAttachmentKey);
154 }
155 }
156 return Maps.newHashMap();
157 }
158
159 @Override
160 public PiCounterCellData getControlStats() {
161 BngProgrammable bngProgrammable = getBngProgrammable(bngService.getBngDeviceId());
162 if (bngProgrammable != null) {
163 try {
164 return bngProgrammable.readControlTrafficCounter();
165 } catch (BngProgrammable.BngProgrammableException e) {
166 log.error("Error control plane packets statistics");
167 }
168 }
169 return null;
170 }
171
172 private BngProgrammable getBngProgrammable(DeviceId deviceId) {
173 if (deviceId != null && deviceService.isAvailable(deviceId)) {
174 return deviceService.getDevice(deviceId).as(BngProgrammable.class);
175 }
176 return null;
177 }
178
179 private class BngStatisticsMonitor implements Runnable {
180 @Override
181 public void run() {
182 BngProgrammable bngProgrammable = getBngProgrammable(bngService.getBngDeviceId());
183 if (bngProgrammable != null) {
184 var attachments = bngService.getAttachments();
185 Map<String, Map<BngProgrammable.BngCounterType, PiCounterCellData>>
186 attachmentsStats = getStats(attachments);
187 // Create an event for each attachment statistics
188 attachmentsStats.forEach((attachmentKey, stats) -> {
189 BngStatsEventSubject evInfo =
190 new BngStatsEventSubject(attachmentKey,
191 attachments.get(attachmentKey),
192 stats);
193 post(new BngStatsEvent(BngStatsEvent.EventType.STATS_UPDATED, evInfo));
194 });
195 } else {
196 log.debug("BngProgrammable not available");
197 }
198 synchronized (this) {
199 if (timeout != null) {
200 timeout = SharedScheduledExecutors.newTimeout(this, bngStatisticsProbeRate, TimeUnit.MILLISECONDS);
201 }
202 }
203 }
204 }
205}
206
207