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