blob: aad015f54c40044a018797a955829cc6efb35ae2 [file] [log] [blame]
Andrea Campanellae3708782017-10-16 16:00:21 +02001/*
2 * Copyright 2017-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.meter.impl;
18
19import com.google.common.collect.Sets;
20import org.onosproject.mastership.MastershipService;
21import org.onosproject.net.Device;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.device.DeviceEvent;
24import org.onosproject.net.device.DeviceListener;
25import org.onosproject.net.device.DeviceService;
Andrea Campanellae3708782017-10-16 16:00:21 +020026import org.onosproject.net.meter.MeterOperation;
27import org.onosproject.net.meter.MeterOperations;
28import org.onosproject.net.meter.MeterProgrammable;
29import org.onosproject.net.meter.MeterProvider;
30
31import org.onosproject.net.meter.MeterProviderService;
32import org.onosproject.net.provider.AbstractProvider;
33import org.onosproject.net.provider.ProviderId;
34import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
Wailok Shumf013a782021-07-26 16:51:01 +080037import java.util.Collections;
Andrea Campanellae3708782017-10-16 16:00:21 +020038import java.util.Set;
Andrea Campanellae3708782017-10-16 16:00:21 +020039import java.util.concurrent.ScheduledExecutorService;
40import java.util.concurrent.ScheduledFuture;
41import java.util.concurrent.TimeUnit;
Andrea Campanellae3708782017-10-16 16:00:21 +020042
43import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
44import static org.onlab.util.Tools.groupedThreads;
45import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
46import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
47
48/**
49 * Driver-based Meter provider.
50 */
51public class MeterDriverProvider extends AbstractProvider implements MeterProvider {
Andrea Campanellae3708782017-10-16 16:00:21 +020052 // To be extracted for reuse as we deal with other.
53 private static final String SCHEME = "default";
54 private static final String PROVIDER_NAME = "org.onosproject.provider.meter";
55
pierventre26ac1512021-09-10 09:37:29 +020056 private static final Set<DeviceEvent.Type> POSITIVE_DEVICE_EVENT = Sets.immutableEnumSet(
57 DEVICE_ADDED, DEVICE_AVAILABILITY_CHANGED);
Andrea Campanellae3708782017-10-16 16:00:21 +020058
pierventre26ac1512021-09-10 09:37:29 +020059 private final Logger log = LoggerFactory.getLogger(getClass());
Andrea Campanellae3708782017-10-16 16:00:21 +020060 protected DeviceService deviceService;
61 protected MastershipService mastershipService;
62 MeterProviderService meterProviderService;
63 int pollFrequency;
64
65 private InternalDeviceListener deviceListener = new InternalDeviceListener();
66 private ScheduledExecutorService executor
67 = newSingleThreadScheduledExecutor(groupedThreads("MeterDriverProvider", "%d", log));
68 private ScheduledFuture<?> poller = null;
69
70 public MeterDriverProvider() {
71 super(new ProviderId(SCHEME, PROVIDER_NAME));
72 }
73
74 /**
75 * Initializes the provider with the necessary device service, meter provider service,
76 * mastership service and poll frequency.
77 *
78 * @param deviceService device service
79 * @param meterProviderService meter provider service
80 * @param mastershipService mastership service
81 * @param pollFrequency meter entry poll frequency
82 */
83 void init(DeviceService deviceService, MeterProviderService meterProviderService,
84 MastershipService mastershipService, int pollFrequency) {
85 this.deviceService = deviceService;
86 this.meterProviderService = meterProviderService;
87 this.mastershipService = mastershipService;
88 this.pollFrequency = pollFrequency;
89
90 deviceService.addListener(deviceListener);
91
92 if (poller != null && !poller.isCancelled()) {
93 poller.cancel(false);
94 }
95
96 poller = executor.scheduleAtFixedRate(this::pollMeters, pollFrequency,
97 pollFrequency, TimeUnit.SECONDS);
98
99 }
100
101 void terminate() {
102 deviceService.removeListener(deviceListener);
103 deviceService = null;
104 meterProviderService = null;
105 mastershipService = null;
106 poller.cancel(true);
107 executor.shutdown();
108 }
109
110 private void pollMeters() {
pierventre26ac1512021-09-10 09:37:29 +0200111 try {
112 deviceService.getAvailableDevices().forEach(device -> {
113 if (mastershipService.isLocalMaster(device.id()) && device.is(MeterProgrammable.class)) {
114 pollDeviceMeters(device);
115 }
116 });
117 } catch (Exception e) {
118 log.warn("Exception thrown while polling meters", e);
119 }
Andrea Campanellae3708782017-10-16 16:00:21 +0200120 }
121
122 @Override
123 public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) {
124 meterOps.operations().forEach(meterOperation -> performMeterOperation(deviceId, meterOperation));
125 }
126
127 @Override
128 public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
129 MeterProgrammable programmable = getMeterProgrammable(deviceId);
130 if (programmable != null) {
131 programmable.performMeterOperation(meterOp);
132 }
133 }
134
pierventre26ac1512021-09-10 09:37:29 +0200135 private void pollDeviceMeters(Device device) {
Andrea Campanellae3708782017-10-16 16:00:21 +0200136 try {
pierventre26ac1512021-09-10 09:37:29 +0200137 meterProviderService.pushMeterMetrics(device.id(), device.as(MeterProgrammable.class).getMeters()
138 .completeOnTimeout(Collections.emptySet(), pollFrequency, TimeUnit.SECONDS).get());
Wailok Shumf013a782021-07-26 16:51:01 +0800139 } catch (Exception e) {
pierventre26ac1512021-09-10 09:37:29 +0200140 log.warn("Unable to get the Meters from {}, error: {}", device, e.getMessage());
Wailok Shumf013a782021-07-26 16:51:01 +0800141 log.debug("Exception: ", e);
142 }
Wailok Shumf013a782021-07-26 16:51:01 +0800143 }
144
pierventre26ac1512021-09-10 09:37:29 +0200145 private void getMeterFeatures(Device device) {
146 try {
147 meterProviderService.pushMeterFeatures(device.id(), device.as(MeterProgrammable.class).getMeterFeatures()
148 .completeOnTimeout(Collections.emptySet(), pollFrequency, TimeUnit.SECONDS).get());
149 } catch (Exception e) {
150 log.warn("Unable to get the Meter Features from {}, error: {}", device.id(), e.getMessage());
151 log.debug("Exception: ", e);
152 }
pierventrec0914ec2021-08-27 15:25:02 +0200153 }
154
Andrea Campanellae3708782017-10-16 16:00:21 +0200155 private MeterProgrammable getMeterProgrammable(DeviceId deviceId) {
156 Device device = deviceService.getDevice(deviceId);
pierventre26ac1512021-09-10 09:37:29 +0200157 if (device != null && device.is(MeterProgrammable.class)) {
Andrea Campanellae3708782017-10-16 16:00:21 +0200158 return device.as(MeterProgrammable.class);
159 } else {
pierventre26ac1512021-09-10 09:37:29 +0200160 log.debug("Device {} is not meter programmable or does not exist", deviceId);
Andrea Campanellae3708782017-10-16 16:00:21 +0200161 return null;
162 }
163 }
164
165 private class InternalDeviceListener implements DeviceListener {
166
167 @Override
168 public void event(DeviceEvent event) {
169 executor.execute(() -> handleEvent(event));
170 }
171
172 @Override
173 public boolean isRelevant(DeviceEvent event) {
pierventre26ac1512021-09-10 09:37:29 +0200174 return event.subject().is(MeterProgrammable.class);
Andrea Campanellae3708782017-10-16 16:00:21 +0200175 }
176
177 private void handleEvent(DeviceEvent event) {
178 Device device = event.subject();
Wailok Shumf013a782021-07-26 16:51:01 +0800179
180 switch (event.type()) {
181 case DEVICE_ADDED:
pierventre26ac1512021-09-10 09:37:29 +0200182 getMeterFeatures(device);
Wailok Shumf013a782021-07-26 16:51:01 +0800183 break;
184 case DEVICE_REMOVED:
185 case DEVICE_SUSPENDED:
186 meterProviderService.deleteMeterFeatures(device.id());
187 break;
188 default:
189 break;
190 }
191
pierventre26ac1512021-09-10 09:37:29 +0200192 boolean isRelevant = POSITIVE_DEVICE_EVENT.contains(event.type()) &&
193 mastershipService.isLocalMaster(device.id()) && deviceService.isAvailable(device.id());
Andrea Campanellae3708782017-10-16 16:00:21 +0200194
195 if (isRelevant) {
pierventre26ac1512021-09-10 09:37:29 +0200196 pollDeviceMeters(device);
Andrea Campanellae3708782017-10-16 16:00:21 +0200197 }
198 }
199 }
200}