blob: e14a949d876ba3060e358276e5898681b4c4eec1 [file] [log] [blame]
alshabibe27055b2015-07-09 21:43:10 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
alshabibe27055b2015-07-09 21:43:10 -07003 *
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.provider.of.meter.impl;
18
alshabib1d2bc402015-07-31 17:04:11 -070019
alshabibc7911792015-07-30 17:55:30 -070020import com.google.common.cache.Cache;
21import com.google.common.cache.CacheBuilder;
22import com.google.common.cache.RemovalCause;
23import com.google.common.cache.RemovalNotification;
Yuta HIGUCHI67f2cca2017-01-19 19:31:58 -080024import com.google.common.collect.ImmutableSet;
alshabibc7911792015-07-30 17:55:30 -070025import com.google.common.collect.Maps;
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010026import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070027import org.osgi.service.component.annotations.Activate;
28import org.osgi.service.component.annotations.Component;
29import org.osgi.service.component.annotations.Deactivate;
30import org.osgi.service.component.annotations.Reference;
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010031import org.osgi.service.component.annotations.Modified;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070032import org.osgi.service.component.annotations.ReferenceCardinality;
Charles Chanb9cfc3a2017-08-04 17:50:21 -070033import org.onlab.util.ItemNotFoundException;
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010034import org.onlab.util.Tools;
35import org.onosproject.cfg.ComponentConfigService;
alshabib7bb05012015-08-05 10:15:09 -070036import org.onosproject.core.CoreService;
Charles Chana59f9b762017-07-30 18:09:44 -070037import org.onosproject.net.driver.Driver;
38import org.onosproject.net.driver.DriverService;
alshabib10c810b2015-08-18 16:59:04 -070039import org.onosproject.net.meter.Band;
40import org.onosproject.net.meter.DefaultBand;
41import org.onosproject.net.meter.DefaultMeter;
42import org.onosproject.net.meter.Meter;
43import org.onosproject.net.meter.MeterFailReason;
Jordi Ortizaa8de492016-12-01 00:21:36 +010044import org.onosproject.net.meter.MeterFeatures;
alshabib58fe6dc2015-08-19 17:16:13 -070045import org.onosproject.net.meter.MeterId;
alshabib10c810b2015-08-18 16:59:04 -070046import org.onosproject.net.meter.MeterOperation;
47import org.onosproject.net.meter.MeterOperations;
48import org.onosproject.net.meter.MeterProvider;
49import org.onosproject.net.meter.MeterProviderRegistry;
50import org.onosproject.net.meter.MeterProviderService;
51import org.onosproject.net.meter.MeterState;
Yuta HIGUCHI67f2cca2017-01-19 19:31:58 -080052import org.onosproject.net.Device;
alshabib7bb05012015-08-05 10:15:09 -070053import org.onosproject.net.DeviceId;
alshabibe27055b2015-07-09 21:43:10 -070054import org.onosproject.net.provider.AbstractProvider;
55import org.onosproject.net.provider.ProviderId;
alshabibc7911792015-07-30 17:55:30 -070056import org.onosproject.openflow.controller.Dpid;
alshabibe27055b2015-07-09 21:43:10 -070057import org.onosproject.openflow.controller.OpenFlowController;
alshabibc7911792015-07-30 17:55:30 -070058import org.onosproject.openflow.controller.OpenFlowEventListener;
59import org.onosproject.openflow.controller.OpenFlowSwitch;
60import org.onosproject.openflow.controller.OpenFlowSwitchListener;
61import org.onosproject.openflow.controller.RoleState;
Jordi Ortizaa8de492016-12-01 00:21:36 +010062import org.onosproject.provider.of.meter.util.MeterFeaturesBuilder;
alshabibc7911792015-07-30 17:55:30 -070063import org.projectfloodlight.openflow.protocol.OFErrorMsg;
64import org.projectfloodlight.openflow.protocol.OFErrorType;
65import org.projectfloodlight.openflow.protocol.OFMessage;
alshabib7bb05012015-08-05 10:15:09 -070066import org.projectfloodlight.openflow.protocol.OFMeterBandStats;
67import org.projectfloodlight.openflow.protocol.OFMeterConfigStatsReply;
Jordi Ortizaa8de492016-12-01 00:21:36 +010068import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
alshabib7bb05012015-08-05 10:15:09 -070069import org.projectfloodlight.openflow.protocol.OFMeterStats;
70import org.projectfloodlight.openflow.protocol.OFMeterStatsReply;
alshabibc7911792015-07-30 17:55:30 -070071import org.projectfloodlight.openflow.protocol.OFPortStatus;
72import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib7bb05012015-08-05 10:15:09 -070073import org.projectfloodlight.openflow.protocol.OFStatsType;
alshabibc7911792015-07-30 17:55:30 -070074import org.projectfloodlight.openflow.protocol.OFVersion;
75import org.projectfloodlight.openflow.protocol.errormsg.OFMeterModFailedErrorMsg;
alshabibe27055b2015-07-09 21:43:10 -070076import org.slf4j.Logger;
77
alshabib7bb05012015-08-05 10:15:09 -070078import java.util.Collection;
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010079import java.util.Dictionary;
Yuta HIGUCHI67f2cca2017-01-19 19:31:58 -080080import java.util.EnumSet;
alshabib7bb05012015-08-05 10:15:09 -070081import java.util.List;
alshabibc7911792015-07-30 17:55:30 -070082import java.util.Map;
Yuta HIGUCHI67f2cca2017-01-19 19:31:58 -080083import java.util.Set;
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010084import java.util.Properties;
alshabibc7911792015-07-30 17:55:30 -070085import java.util.concurrent.TimeUnit;
86import java.util.concurrent.atomic.AtomicLong;
alshabib7bb05012015-08-05 10:15:09 -070087import java.util.stream.Collectors;
Niraj Dubey47bde9f2019-10-07 18:03:57 +053088import java.util.concurrent.ConcurrentHashMap;
alshabibc7911792015-07-30 17:55:30 -070089
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010090import static org.onlab.util.Tools.getIntegerProperty;
Jordi Ortizaa8de492016-12-01 00:21:36 +010091import static org.onosproject.net.DeviceId.deviceId;
92import static org.onosproject.openflow.controller.Dpid.uri;
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010093import static org.onosproject.provider.of.meter.impl.OsgiPropertyConstants.*;
alshabibe27055b2015-07-09 21:43:10 -070094import static org.slf4j.LoggerFactory.getLogger;
95
96/**
97 * Provider which uses an OpenFlow controller to handle meters.
98 */
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +010099@Component(immediate = true, enabled = true, property = {
100 FORCE_STATS_AFTER_METER_REMOVAL + ":Boolean=" + FORCE_STATS_AFTER_METER_REMOVAL_ENABLED_DEFAULT,
101 METER_STATS_POLL_INTERVAL + ":Integer=" + METER_STATS_POLL_INTERVAL_DEFAULT,
102})
103
alshabibe27055b2015-07-09 21:43:10 -0700104public class OpenFlowMeterProvider extends AbstractProvider implements MeterProvider {
105
106 private final Logger log = getLogger(getClass());
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibe27055b2015-07-09 21:43:10 -0700109 protected OpenFlowController controller;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibc7911792015-07-30 17:55:30 -0700112 protected MeterProviderRegistry providerRegistry;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7bb05012015-08-05 10:15:09 -0700115 protected CoreService coreService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chana59f9b762017-07-30 18:09:44 -0700118 protected DriverService driverService;
119
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
121 protected ComponentConfigService cfgService;
122
alshabibc7911792015-07-30 17:55:30 -0700123 private MeterProviderService providerService;
124
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100125 private boolean forceStatsAfterMeterRemoval = FORCE_STATS_AFTER_METER_REMOVAL_ENABLED_DEFAULT;
126
127 private int meterStatsPollInterval = METER_STATS_POLL_INTERVAL_DEFAULT;
128
alshabibc7911792015-07-30 17:55:30 -0700129 private static final AtomicLong XID_COUNTER = new AtomicLong(1);
130
alshabibc7911792015-07-30 17:55:30 -0700131 static final long TIMEOUT = 30;
132
alshabib7bb05012015-08-05 10:15:09 -0700133 private Cache<Long, MeterOperation> pendingOperations;
alshabibc7911792015-07-30 17:55:30 -0700134
alshabibc7911792015-07-30 17:55:30 -0700135 private InternalMeterListener listener = new InternalMeterListener();
Niraj Dubey47bde9f2019-10-07 18:03:57 +0530136 private Map<Dpid, MeterStatsCollector> collectors = new ConcurrentHashMap<>();
alshabibe27055b2015-07-09 21:43:10 -0700137
Yuta HIGUCHI67f2cca2017-01-19 19:31:58 -0800138 private static final Set<Device.Type> NO_METER_SUPPORT =
139 ImmutableSet.copyOf(EnumSet.of(Device.Type.ROADM,
140 Device.Type.ROADM_OTN,
141 Device.Type.FIBER_SWITCH,
Andrea Campanella1c24fb92018-12-20 16:43:59 +0100142 Device.Type.OTN,
143 Device.Type.OLS,
144 Device.Type.TERMINAL_DEVICE));
Yuta HIGUCHI67f2cca2017-01-19 19:31:58 -0800145
alshabibe27055b2015-07-09 21:43:10 -0700146 /**
147 * Creates a OpenFlow meter provider.
148 */
149 public OpenFlowMeterProvider() {
150 super(new ProviderId("of", "org.onosproject.provider.meter"));
151 }
alshabibbc371962015-07-09 22:26:21 -0700152
alshabibc7911792015-07-30 17:55:30 -0700153 @Activate
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100154 public void activate(ComponentContext context) {
155 cfgService.registerProperties(getClass());
alshabibc7911792015-07-30 17:55:30 -0700156 providerService = providerRegistry.register(this);
157
158 pendingOperations = CacheBuilder.newBuilder()
159 .expireAfterWrite(TIMEOUT, TimeUnit.SECONDS)
alshabib7bb05012015-08-05 10:15:09 -0700160 .removalListener((RemovalNotification<Long, MeterOperation> notification) -> {
alshabibc7911792015-07-30 17:55:30 -0700161 if (notification.getCause() == RemovalCause.EXPIRED) {
Gamze Abakaa34469f2019-04-19 08:30:16 +0000162 log.debug("Expired on meter provider. Meter key {} and operation {}",
163 notification.getKey(), notification.getValue());
alshabibc7911792015-07-30 17:55:30 -0700164 providerService.meterOperationFailed(notification.getValue(),
165 MeterFailReason.TIMEOUT);
166 }
167 }).build();
168
169 controller.addEventListener(listener);
170 controller.addListener(listener);
171
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100172 modified(context);
173
174 if (collectors.isEmpty()) {
175 controller.getSwitches().forEach((sw -> createStatsCollection(sw)));
176 }
alshabibc7911792015-07-30 17:55:30 -0700177 }
178
179 @Deactivate
180 public void deactivate() {
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100181 cfgService.unregisterProperties(getClass(), false);
alshabibc7911792015-07-30 17:55:30 -0700182 providerRegistry.unregister(this);
Charles Chanecfdfb72015-11-24 19:05:50 -0800183 collectors.values().forEach(MeterStatsCollector::stop);
184 collectors.clear();
alshabibc7911792015-07-30 17:55:30 -0700185 controller.removeEventListener(listener);
186 controller.removeListener(listener);
187 providerService = null;
188 }
189
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100190 @Modified
191 public void modified(ComponentContext context) {
192 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
193
194 // update FORCE_STATS_AFTER_METER_REMOVAL if needed
195 Boolean forceStatsAfterMeterRemovalEnabled =
196 Tools.isPropertyEnabled(properties, FORCE_STATS_AFTER_METER_REMOVAL);
197 if (forceStatsAfterMeterRemovalEnabled == null) {
198 log.info("forceStatsAfterMeterRemoval is not configured, " +
199 "using current value of {}", forceStatsAfterMeterRemoval);
200 } else {
201 forceStatsAfterMeterRemoval = forceStatsAfterMeterRemovalEnabled;
202 log.info("Configured. forceStatsAfterMeterRemoval is {}",
203 forceStatsAfterMeterRemovalEnabled ? "enabled" : "disabled");
204 }
205
206 // update METER_STATS_POLL_INTERVAL if needed
207 Integer newMeterPollInterval = getIntegerProperty(properties, METER_STATS_POLL_INTERVAL);
208 if (newMeterPollInterval != null && newMeterPollInterval > 0
209 && newMeterPollInterval != meterStatsPollInterval) {
210 meterStatsPollInterval = newMeterPollInterval;
211 // restart meter stats collectors, old instances will be automatically purged before creation
212 // in the call to createStatsCollection
213 controller.getSwitches().forEach((sw -> {
214 createStatsCollection(sw);
215 }));
216 log.info("Configured. meterStatsPollInterval to {}", newMeterPollInterval);
217 } else if (newMeterPollInterval != null && newMeterPollInterval <= 0) {
218 log.warn("meterStatsPollInterval must be greater than 0");
219 // Reset property with the old value
220 cfgService.setProperty(getClass().getName(), METER_STATS_POLL_INTERVAL,
221 Integer.toString(meterStatsPollInterval));
222 }
223 }
224
alshabibbc371962015-07-09 22:26:21 -0700225 @Override
226 public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) {
alshabibc7911792015-07-30 17:55:30 -0700227 Dpid dpid = Dpid.dpid(deviceId.uri());
228 OpenFlowSwitch sw = controller.getSwitch(dpid);
229 if (sw == null) {
230 log.error("Unknown device {}", deviceId);
231 meterOps.operations().forEach(op ->
232 providerService.meterOperationFailed(op,
233 MeterFailReason.UNKNOWN_DEVICE)
234 );
235 return;
236 }
alshabibbc371962015-07-09 22:26:21 -0700237
alshabibc7911792015-07-30 17:55:30 -0700238 meterOps.operations().forEach(op -> performOperation(sw, op));
alshabibbc371962015-07-09 22:26:21 -0700239 }
240
241 @Override
242 public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
alshabibc7911792015-07-30 17:55:30 -0700243 Dpid dpid = Dpid.dpid(deviceId.uri());
244 OpenFlowSwitch sw = controller.getSwitch(dpid);
245 if (sw == null) {
246 log.error("Unknown device {}", deviceId);
247 providerService.meterOperationFailed(meterOp,
248 MeterFailReason.UNKNOWN_DEVICE);
249 return;
250 }
alshabibbc371962015-07-09 22:26:21 -0700251
alshabib7bb05012015-08-05 10:15:09 -0700252 performOperation(sw, meterOp);
253
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100254 if (forceStatsAfterMeterRemoval && meterOp.type().equals(MeterOperation.Type.REMOVE)) {
Jordi Ortiz9fe79a22017-04-25 12:57:11 +0200255 forceMeterStats(deviceId);
256 }
257
258 }
259
260 private void forceMeterStats(DeviceId deviceId) {
261 Dpid dpid = Dpid.dpid(deviceId.uri());
262 OpenFlowSwitch sw = controller.getSwitch(dpid);
263
264 MeterStatsCollector once = new MeterStatsCollector(sw, 1);
Palash Kalaf95c38b2017-05-15 23:52:48 +0900265 once.sendMeterStatisticRequest();
Jordi Ortiz9fe79a22017-04-25 12:57:11 +0200266
alshabibbc371962015-07-09 22:26:21 -0700267 }
alshabibc7911792015-07-30 17:55:30 -0700268
269 private void performOperation(OpenFlowSwitch sw, MeterOperation op) {
270
alshabibc7911792015-07-30 17:55:30 -0700271 Meter meter = op.meter();
272 MeterModBuilder builder = MeterModBuilder.builder(meter.id().id(), sw.factory());
273 if (meter.isBurst()) {
274 builder.burst();
275 }
276 builder.withBands(meter.bands())
277 .withId(meter.id())
278 .withRateUnit(meter.unit());
279
280 switch (op.type()) {
281 case ADD:
Gamze Abakaa34469f2019-04-19 08:30:16 +0000282 pendingOperations.put(op.meter().id().id(), op);
alshabibc7911792015-07-30 17:55:30 -0700283 sw.sendMsg(builder.add());
284 break;
285 case REMOVE:
286 sw.sendMsg(builder.remove());
287 break;
288 case MODIFY:
Gamze Abakaa34469f2019-04-19 08:30:16 +0000289 pendingOperations.put(op.meter().id().id(), op);
alshabibc7911792015-07-30 17:55:30 -0700290 sw.sendMsg(builder.modify());
291 break;
292 default:
293 log.warn("Unknown Meter command {}; not sending anything",
294 op.type());
295 providerService.meterOperationFailed(op,
296 MeterFailReason.UNKNOWN_COMMAND);
297 }
298
299 }
300
301 private void createStatsCollection(OpenFlowSwitch sw) {
Madan Jampani84382b92016-06-22 08:26:49 -0700302 if (sw != null && isMeterSupported(sw)) {
Miguel Borges de Freitasf0f344e2021-06-23 14:09:52 +0100303 MeterStatsCollector msc = new MeterStatsCollector(sw, meterStatsPollInterval);
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700304 stopCollectorIfNeeded(collectors.put(new Dpid(sw.getId()), msc));
Palash Kalaa439afe2017-05-16 14:53:15 +0900305 msc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700306 }
307 }
308
309 private void stopCollectorIfNeeded(MeterStatsCollector collector) {
310 if (collector != null) {
311 collector.stop();
alshabibc7911792015-07-30 17:55:30 -0700312 }
313 }
314
Charles Chan14967c22015-12-07 11:11:50 -0800315 // TODO: ONOS-3546 Support per device enabling/disabling via network config
alshabibc7911792015-07-30 17:55:30 -0700316 private boolean isMeterSupported(OpenFlowSwitch sw) {
317 if (sw.factory().getVersion() == OFVersion.OF_10 ||
318 sw.factory().getVersion() == OFVersion.OF_11 ||
Charles Chan14967c22015-12-07 11:11:50 -0800319 sw.factory().getVersion() == OFVersion.OF_12 ||
Yuta HIGUCHI67f2cca2017-01-19 19:31:58 -0800320 NO_METER_SUPPORT.contains(sw.deviceType()) ||
Charles Chana59f9b762017-07-30 18:09:44 -0700321 !isMeterCapable(sw)) {
sdn77b5cb82018-05-23 18:51:27 +0900322 log.debug("{} does not support Meter.\n", sw.getDpid());
alshabibc7911792015-07-30 17:55:30 -0700323 return false;
324 }
325
326 return true;
327 }
328
Charles Chana59f9b762017-07-30 18:09:44 -0700329 /**
330 * Determine whether the given switch is meter-capable.
331 *
332 * @param sw switch
333 * @return the boolean value of meterCapable property, or true if it is not configured.
334 */
335 private boolean isMeterCapable(OpenFlowSwitch sw) {
Charles Chanb9cfc3a2017-08-04 17:50:21 -0700336 Driver driver;
337
338 try {
339 driver = driverService.getDriver(DeviceId.deviceId(Dpid.uri(sw.getDpid())));
340 } catch (ItemNotFoundException e) {
341 driver = driverService.getDriver(sw.manufacturerDescription(), sw.hardwareDescription(),
342 sw.softwareDescription());
343 }
344
Charles Chana59f9b762017-07-30 18:09:44 -0700345 String isMeterCapable = driver.getProperty(METER_CAPABLE);
346 return isMeterCapable == null || Boolean.parseBoolean(isMeterCapable);
347 }
348
alshabibc7911792015-07-30 17:55:30 -0700349 private void pushMeterStats(Dpid dpid, OFStatsReply msg) {
alshabib7bb05012015-08-05 10:15:09 -0700350 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabibc7911792015-07-30 17:55:30 -0700351
alshabib7bb05012015-08-05 10:15:09 -0700352 if (msg.getStatsType() == OFStatsType.METER) {
353 OFMeterStatsReply reply = (OFMeterStatsReply) msg;
354 Collection<Meter> meters = buildMeters(deviceId, reply.getEntries());
355 //TODO do meter accounting here.
356 providerService.pushMeterMetrics(deviceId, meters);
357 } else if (msg.getStatsType() == OFStatsType.METER_CONFIG) {
358 OFMeterConfigStatsReply reply = (OFMeterConfigStatsReply) msg;
359 // FIXME: Map<Long, Meter> meters = collectMeters(deviceId, reply);
360 }
361
362 }
363
Jordi Ortizaa8de492016-12-01 00:21:36 +0100364 private MeterFeatures buildMeterFeatures(Dpid dpid, OFMeterFeatures mf) {
365 if (mf != null) {
366 return new MeterFeaturesBuilder(mf, deviceId(uri(dpid)))
367 .build();
368 } else {
369 // This will usually happen for OpenFlow devices prior to 1.3
370 return MeterFeaturesBuilder.noMeterFeatures(deviceId(uri(dpid)));
371 }
372 }
373
374 private void pushMeterFeatures(Dpid dpid, OFMeterFeatures meterFeatures) {
375 providerService.pushMeterFeatures(deviceId(uri(dpid)),
376 buildMeterFeatures(dpid, meterFeatures));
377 }
378
379 private void destroyMeterFeatures(Dpid dpid) {
380 providerService.deleteMeterFeatures(deviceId(uri(dpid)));
381 }
382
alshabib7bb05012015-08-05 10:15:09 -0700383 private Map<Long, Meter> collectMeters(DeviceId deviceId,
384 OFMeterConfigStatsReply reply) {
385 return Maps.newHashMap();
386 //TODO: Needs a fix to be applied to loxi MeterConfig stat is incorrect
387 }
388
389 private Collection<Meter> buildMeters(DeviceId deviceId,
390 List<OFMeterStats> entries) {
391 return entries.stream().map(stat -> {
392 DefaultMeter.Builder builder = DefaultMeter.builder();
393 Collection<Band> bands = buildBands(stat.getBandStats());
394 builder.forDevice(deviceId)
alshabib58fe6dc2015-08-19 17:16:13 -0700395 .withId(MeterId.meterId(stat.getMeterId()))
alshabib7bb05012015-08-05 10:15:09 -0700396 //FIXME: need to encode appId in meter id, but that makes
397 // things a little annoying for debugging
398 .fromApp(coreService.getAppId("org.onosproject.core"))
399 .withBands(bands);
400 DefaultMeter meter = builder.build();
401 meter.setState(MeterState.ADDED);
402 meter.setLife(stat.getDurationSec());
403 meter.setProcessedBytes(stat.getByteInCount().getValue());
404 meter.setProcessedPackets(stat.getPacketInCount().getValue());
Cem Türker3baff672017-10-12 15:09:01 +0300405 if (stat.getVersion().getWireVersion() < OFVersion.OF_15.getWireVersion()) {
406 meter.setReferenceCount(stat.getFlowCount());
407 }
alshabib7bb05012015-08-05 10:15:09 -0700408 // marks the meter as seen on the dataplane
409 pendingOperations.invalidate(stat.getMeterId());
410 return meter;
411 }).collect(Collectors.toSet());
412 }
413
414 private Collection<Band> buildBands(List<OFMeterBandStats> bandStats) {
415 return bandStats.stream().map(stat -> {
Jordi Ortizaf75c132017-06-22 16:06:36 +0200416 DefaultBand band = ((DefaultBand.Builder) DefaultBand.builder().ofType(DefaultBand.Type.DROP)).build();
alshabib7bb05012015-08-05 10:15:09 -0700417 band.setBytes(stat.getByteBandCount().getValue());
418 band.setPackets(stat.getPacketBandCount().getValue());
419 return band;
Jordi Ortizaf75c132017-06-22 16:06:36 +0200420 }).collect(Collectors.toList());
alshabibc7911792015-07-30 17:55:30 -0700421 }
422
423 private void signalMeterError(OFMeterModFailedErrorMsg meterError,
424 MeterOperation op) {
425 switch (meterError.getCode()) {
426 case UNKNOWN:
427 providerService.meterOperationFailed(op,
428 MeterFailReason.UNKNOWN_DEVICE);
429 break;
430 case METER_EXISTS:
431 providerService.meterOperationFailed(op,
432 MeterFailReason.EXISTING_METER);
433 break;
434 case INVALID_METER:
435 providerService.meterOperationFailed(op,
436 MeterFailReason.INVALID_METER);
437 break;
438 case UNKNOWN_METER:
439 providerService.meterOperationFailed(op,
440 MeterFailReason.UNKNOWN);
441 break;
442 case BAD_COMMAND:
443 providerService.meterOperationFailed(op,
444 MeterFailReason.UNKNOWN_COMMAND);
445 break;
446 case BAD_FLAGS:
447 providerService.meterOperationFailed(op,
448 MeterFailReason.UNKNOWN_FLAGS);
449 break;
450 case BAD_RATE:
451 providerService.meterOperationFailed(op,
452 MeterFailReason.BAD_RATE);
453 break;
454 case BAD_BURST:
455 providerService.meterOperationFailed(op,
456 MeterFailReason.BAD_BURST);
457 break;
458 case BAD_BAND:
459 providerService.meterOperationFailed(op,
460 MeterFailReason.BAD_BAND);
461 break;
462 case BAD_BAND_VALUE:
463 providerService.meterOperationFailed(op,
464 MeterFailReason.BAD_BAND_VALUE);
465 break;
466 case OUT_OF_METERS:
467 providerService.meterOperationFailed(op,
468 MeterFailReason.OUT_OF_METERS);
469 break;
470 case OUT_OF_BANDS:
471 providerService.meterOperationFailed(op,
472 MeterFailReason.OUT_OF_BANDS);
473 break;
474 default:
475 providerService.meterOperationFailed(op,
476 MeterFailReason.UNKNOWN);
477 }
478 }
479
480 private class InternalMeterListener
481 implements OpenFlowSwitchListener, OpenFlowEventListener {
482 @Override
483 public void handleMessage(Dpid dpid, OFMessage msg) {
484 switch (msg.getType()) {
485 case STATS_REPLY:
486 pushMeterStats(dpid, (OFStatsReply) msg);
487 break;
488 case ERROR:
489 OFErrorMsg error = (OFErrorMsg) msg;
490 if (error.getErrType() == OFErrorType.METER_MOD_FAILED) {
491 MeterOperation op =
492 pendingOperations.getIfPresent(error.getXid());
493 pendingOperations.invalidate(error.getXid());
494 if (op == null) {
495 log.warn("Unknown Meter operation failed {}", error);
496 } else {
497 OFMeterModFailedErrorMsg meterError =
498 (OFMeterModFailedErrorMsg) error;
499 signalMeterError(meterError, op);
500 }
501 }
502 break;
503 default:
504 break;
505 }
506
507 }
508
509 @Override
510 public void switchAdded(Dpid dpid) {
511 createStatsCollection(controller.getSwitch(dpid));
Jordi Ortizaa8de492016-12-01 00:21:36 +0100512 pushMeterFeatures(dpid, controller.getSwitch(dpid).getMeterFeatures());
alshabibc7911792015-07-30 17:55:30 -0700513 }
514
515 @Override
516 public void switchRemoved(Dpid dpid) {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700517 stopCollectorIfNeeded(collectors.remove(dpid));
Jordi Ortizaa8de492016-12-01 00:21:36 +0100518 destroyMeterFeatures(dpid);
alshabibc7911792015-07-30 17:55:30 -0700519 }
520
521 @Override
522 public void switchChanged(Dpid dpid) {
523
524 }
525
526 @Override
527 public void portChanged(Dpid dpid, OFPortStatus status) {
528
529 }
530
531 @Override
532 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
533
534 }
535 }
536
537
538
alshabibe27055b2015-07-09 21:43:10 -0700539}