blob: dabeda02e07ce79c2d25742df1db998b1b7fda67 [file] [log] [blame]
alshabibe27055b2015-07-09 21:43:10 -07001/*
2 * Copyright 2015 Open Networking Laboratory
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.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;
alshabib1d2bc402015-07-31 17:04:11 -070023
alshabibc7911792015-07-30 17:55:30 -070024import com.google.common.cache.RemovalNotification;
25import com.google.common.collect.Maps;
26import org.apache.felix.scr.annotations.Activate;
alshabibe27055b2015-07-09 21:43:10 -070027import org.apache.felix.scr.annotations.Component;
alshabibc7911792015-07-30 17:55:30 -070028import org.apache.felix.scr.annotations.Deactivate;
alshabibe27055b2015-07-09 21:43:10 -070029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabibbc371962015-07-09 22:26:21 -070031import org.onosproject.net.DeviceId;
alshabib1d2bc402015-07-31 17:04:11 -070032import org.onosproject.incubator.net.meter.Meter;
33import org.onosproject.incubator.net.meter.MeterFailReason;
34import org.onosproject.incubator.net.meter.MeterOperation;
35import org.onosproject.incubator.net.meter.MeterOperations;
36import org.onosproject.incubator.net.meter.MeterProvider;
37import org.onosproject.incubator.net.meter.MeterProviderRegistry;
38import org.onosproject.incubator.net.meter.MeterProviderService;
alshabibe27055b2015-07-09 21:43:10 -070039import org.onosproject.net.provider.AbstractProvider;
40import org.onosproject.net.provider.ProviderId;
alshabibc7911792015-07-30 17:55:30 -070041import org.onosproject.openflow.controller.Dpid;
alshabibe27055b2015-07-09 21:43:10 -070042import org.onosproject.openflow.controller.OpenFlowController;
alshabibc7911792015-07-30 17:55:30 -070043import org.onosproject.openflow.controller.OpenFlowEventListener;
44import org.onosproject.openflow.controller.OpenFlowSwitch;
45import org.onosproject.openflow.controller.OpenFlowSwitchListener;
46import org.onosproject.openflow.controller.RoleState;
47import org.projectfloodlight.openflow.protocol.OFErrorMsg;
48import org.projectfloodlight.openflow.protocol.OFErrorType;
49import org.projectfloodlight.openflow.protocol.OFMessage;
50import org.projectfloodlight.openflow.protocol.OFPortStatus;
51import org.projectfloodlight.openflow.protocol.OFStatsReply;
52import org.projectfloodlight.openflow.protocol.OFVersion;
53import org.projectfloodlight.openflow.protocol.errormsg.OFMeterModFailedErrorMsg;
alshabibe27055b2015-07-09 21:43:10 -070054import org.slf4j.Logger;
55
alshabibc7911792015-07-30 17:55:30 -070056import java.util.Map;
57import java.util.concurrent.TimeUnit;
58import java.util.concurrent.atomic.AtomicLong;
59
alshabibe27055b2015-07-09 21:43:10 -070060import static org.slf4j.LoggerFactory.getLogger;
61
62/**
63 * Provider which uses an OpenFlow controller to handle meters.
64 */
Thomas Vachuskac87348d2015-07-31 12:33:50 -070065@Component(immediate = true, enabled = false)
alshabibe27055b2015-07-09 21:43:10 -070066public class OpenFlowMeterProvider extends AbstractProvider implements MeterProvider {
67
alshabibc7911792015-07-30 17:55:30 -070068
alshabibe27055b2015-07-09 21:43:10 -070069 private final Logger log = getLogger(getClass());
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected OpenFlowController controller;
73
alshabibc7911792015-07-30 17:55:30 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected MeterProviderRegistry providerRegistry;
76
77 private MeterProviderService providerService;
78
79 private static final AtomicLong XID_COUNTER = new AtomicLong(1);
80
81 static final int POLL_INTERVAL = 10;
82 static final long TIMEOUT = 30;
83
84 private Cache<Integer, MeterOperation> pendingOperations;
85 private Cache<Long, MeterOperation> pendingXid;
86
87
88 private InternalMeterListener listener = new InternalMeterListener();
89 private Map<Dpid, MeterStatsCollector> collectors = Maps.newHashMap();
alshabibe27055b2015-07-09 21:43:10 -070090
91 /**
92 * Creates a OpenFlow meter provider.
93 */
94 public OpenFlowMeterProvider() {
95 super(new ProviderId("of", "org.onosproject.provider.meter"));
96 }
alshabibbc371962015-07-09 22:26:21 -070097
alshabibc7911792015-07-30 17:55:30 -070098 @Activate
99 public void activate() {
100 providerService = providerRegistry.register(this);
101
102 pendingOperations = CacheBuilder.newBuilder()
103 .expireAfterWrite(TIMEOUT, TimeUnit.SECONDS)
104 .removalListener((RemovalNotification<Integer, MeterOperation> notification) -> {
105 if (notification.getCause() == RemovalCause.EXPIRED) {
106 providerService.meterOperationFailed(notification.getValue(),
107 MeterFailReason.TIMEOUT);
108 }
109 }).build();
110
111 controller.addEventListener(listener);
112 controller.addListener(listener);
113
114 controller.getSwitches().forEach((sw -> createStatsCollection(sw)));
115 }
116
117 @Deactivate
118 public void deactivate() {
119 providerRegistry.unregister(this);
120 controller.removeEventListener(listener);
121 controller.removeListener(listener);
122 providerService = null;
123 }
124
alshabibbc371962015-07-09 22:26:21 -0700125 @Override
126 public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) {
alshabibc7911792015-07-30 17:55:30 -0700127 Dpid dpid = Dpid.dpid(deviceId.uri());
128 OpenFlowSwitch sw = controller.getSwitch(dpid);
129 if (sw == null) {
130 log.error("Unknown device {}", deviceId);
131 meterOps.operations().forEach(op ->
132 providerService.meterOperationFailed(op,
133 MeterFailReason.UNKNOWN_DEVICE)
134 );
135 return;
136 }
alshabibbc371962015-07-09 22:26:21 -0700137
alshabibc7911792015-07-30 17:55:30 -0700138 meterOps.operations().forEach(op -> performOperation(sw, op));
alshabibbc371962015-07-09 22:26:21 -0700139 }
140
141 @Override
142 public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
alshabibc7911792015-07-30 17:55:30 -0700143 Dpid dpid = Dpid.dpid(deviceId.uri());
144 OpenFlowSwitch sw = controller.getSwitch(dpid);
145 if (sw == null) {
146 log.error("Unknown device {}", deviceId);
147 providerService.meterOperationFailed(meterOp,
148 MeterFailReason.UNKNOWN_DEVICE);
149 return;
150 }
alshabibbc371962015-07-09 22:26:21 -0700151
152 }
alshabibc7911792015-07-30 17:55:30 -0700153
154 private void performOperation(OpenFlowSwitch sw, MeterOperation op) {
155
156 pendingOperations.put(op.meter().id().id(), op);
157
158
159 Meter meter = op.meter();
160 MeterModBuilder builder = MeterModBuilder.builder(meter.id().id(), sw.factory());
161 if (meter.isBurst()) {
162 builder.burst();
163 }
164 builder.withBands(meter.bands())
165 .withId(meter.id())
166 .withRateUnit(meter.unit());
167
168 switch (op.type()) {
169 case ADD:
170 sw.sendMsg(builder.add());
171 break;
172 case REMOVE:
173 sw.sendMsg(builder.remove());
174 break;
175 case MODIFY:
176 sw.sendMsg(builder.modify());
177 break;
178 default:
179 log.warn("Unknown Meter command {}; not sending anything",
180 op.type());
181 providerService.meterOperationFailed(op,
182 MeterFailReason.UNKNOWN_COMMAND);
183 }
184
185 }
186
187 private void createStatsCollection(OpenFlowSwitch sw) {
188 if (isMeterSupported(sw)) {
189 MeterStatsCollector msc = new MeterStatsCollector(sw, POLL_INTERVAL);
190 msc.start();
191 collectors.put(new Dpid(sw.getId()), msc);
192 }
193 }
194
195 private boolean isMeterSupported(OpenFlowSwitch sw) {
196 if (sw.factory().getVersion() == OFVersion.OF_10 ||
197 sw.factory().getVersion() == OFVersion.OF_11 ||
198 sw.factory().getVersion() == OFVersion.OF_12) {
199 return false;
200 }
201
202 return true;
203 }
204
205 private void pushMeterStats(Dpid dpid, OFStatsReply msg) {
206
207 }
208
209 private void signalMeterError(OFMeterModFailedErrorMsg meterError,
210 MeterOperation op) {
211 switch (meterError.getCode()) {
212 case UNKNOWN:
213 providerService.meterOperationFailed(op,
214 MeterFailReason.UNKNOWN_DEVICE);
215 break;
216 case METER_EXISTS:
217 providerService.meterOperationFailed(op,
218 MeterFailReason.EXISTING_METER);
219 break;
220 case INVALID_METER:
221 providerService.meterOperationFailed(op,
222 MeterFailReason.INVALID_METER);
223 break;
224 case UNKNOWN_METER:
225 providerService.meterOperationFailed(op,
226 MeterFailReason.UNKNOWN);
227 break;
228 case BAD_COMMAND:
229 providerService.meterOperationFailed(op,
230 MeterFailReason.UNKNOWN_COMMAND);
231 break;
232 case BAD_FLAGS:
233 providerService.meterOperationFailed(op,
234 MeterFailReason.UNKNOWN_FLAGS);
235 break;
236 case BAD_RATE:
237 providerService.meterOperationFailed(op,
238 MeterFailReason.BAD_RATE);
239 break;
240 case BAD_BURST:
241 providerService.meterOperationFailed(op,
242 MeterFailReason.BAD_BURST);
243 break;
244 case BAD_BAND:
245 providerService.meterOperationFailed(op,
246 MeterFailReason.BAD_BAND);
247 break;
248 case BAD_BAND_VALUE:
249 providerService.meterOperationFailed(op,
250 MeterFailReason.BAD_BAND_VALUE);
251 break;
252 case OUT_OF_METERS:
253 providerService.meterOperationFailed(op,
254 MeterFailReason.OUT_OF_METERS);
255 break;
256 case OUT_OF_BANDS:
257 providerService.meterOperationFailed(op,
258 MeterFailReason.OUT_OF_BANDS);
259 break;
260 default:
261 providerService.meterOperationFailed(op,
262 MeterFailReason.UNKNOWN);
263 }
264 }
265
266 private class InternalMeterListener
267 implements OpenFlowSwitchListener, OpenFlowEventListener {
268 @Override
269 public void handleMessage(Dpid dpid, OFMessage msg) {
270 switch (msg.getType()) {
271 case STATS_REPLY:
272 pushMeterStats(dpid, (OFStatsReply) msg);
273 break;
274 case ERROR:
275 OFErrorMsg error = (OFErrorMsg) msg;
276 if (error.getErrType() == OFErrorType.METER_MOD_FAILED) {
277 MeterOperation op =
278 pendingOperations.getIfPresent(error.getXid());
279 pendingOperations.invalidate(error.getXid());
280 if (op == null) {
281 log.warn("Unknown Meter operation failed {}", error);
282 } else {
283 OFMeterModFailedErrorMsg meterError =
284 (OFMeterModFailedErrorMsg) error;
285 signalMeterError(meterError, op);
286 }
287 }
288 break;
289 default:
290 break;
291 }
292
293 }
294
295 @Override
296 public void switchAdded(Dpid dpid) {
297 createStatsCollection(controller.getSwitch(dpid));
298 }
299
300 @Override
301 public void switchRemoved(Dpid dpid) {
302 MeterStatsCollector msc = collectors.remove(dpid);
303 if (msc != null) {
304 msc.stop();
305 }
306 }
307
308 @Override
309 public void switchChanged(Dpid dpid) {
310
311 }
312
313 @Override
314 public void portChanged(Dpid dpid, OFPortStatus status) {
315
316 }
317
318 @Override
319 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
320
321 }
322 }
323
324
325
alshabibe27055b2015-07-09 21:43:10 -0700326}