blob: c63d042c76e6943e0e3280d21263fab2182b55e0 [file] [log] [blame]
Jian Lie0e01c22016-02-09 14:02:49 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Jian Lie0e01c22016-02-09 14:02:49 -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 */
16package org.onosproject.provider.of.message.impl;
17
Jian Li1d13c262016-02-09 14:58:28 -080018import com.google.common.collect.Maps;
Jian Lie0e01c22016-02-09 14:02:49 -080019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
Jian Li1d13c262016-02-09 14:58:28 -080024import org.onlab.metrics.MetricsService;
Jian Lia1d7f272016-03-28 17:21:47 -070025import org.onlab.util.SharedScheduledExecutorService;
Jian Li66f15262016-03-03 11:18:40 -080026import org.onlab.util.SharedScheduledExecutors;
Jian Lie0e01c22016-02-09 14:02:49 -080027import org.onosproject.cpman.message.ControlMessageProvider;
28import org.onosproject.cpman.message.ControlMessageProviderRegistry;
29import org.onosproject.cpman.message.ControlMessageProviderService;
Jian Li1d13c262016-02-09 14:58:28 -080030import org.onosproject.net.DeviceId;
Jian Lie0e01c22016-02-09 14:02:49 -080031import org.onosproject.net.provider.AbstractProvider;
32import org.onosproject.net.provider.ProviderId;
Jian Li1d13c262016-02-09 14:58:28 -080033import org.onosproject.openflow.controller.Dpid;
34import org.onosproject.openflow.controller.OpenFlowController;
Jian Lia78cdb22016-04-21 13:03:58 -070035import org.onosproject.openflow.controller.OpenFlowMessageListener;
Jian Li1d13c262016-02-09 14:58:28 -080036import org.onosproject.openflow.controller.OpenFlowSwitch;
37import org.onosproject.openflow.controller.OpenFlowSwitchListener;
38import org.onosproject.openflow.controller.RoleState;
39import org.projectfloodlight.openflow.protocol.OFMessage;
40import org.projectfloodlight.openflow.protocol.OFPortStatus;
Jian Li7ceb7b02016-04-04 12:42:40 -070041import org.projectfloodlight.openflow.protocol.OFType;
Jian Lie0e01c22016-02-09 14:02:49 -080042import org.slf4j.Logger;
43
Jian Li1d13c262016-02-09 14:58:28 -080044import java.util.HashMap;
Jian Lia78cdb22016-04-21 13:03:58 -070045import java.util.List;
Jian Li1d13c262016-02-09 14:58:28 -080046import java.util.concurrent.ScheduledFuture;
47import java.util.concurrent.TimeUnit;
48
49import static org.onosproject.net.DeviceId.deviceId;
50import static org.onosproject.openflow.controller.Dpid.uri;
Jian Lie0e01c22016-02-09 14:02:49 -080051import static org.slf4j.LoggerFactory.getLogger;
52
53/**
54 * Provider which uses an OpenFlow controller to collect control message.
55 */
56@Component(immediate = true)
57public class OpenFlowControlMessageProvider extends AbstractProvider
58 implements ControlMessageProvider {
59
Jian Li1d13c262016-02-09 14:58:28 -080060 private final Logger log = getLogger(getClass());
Jian Lie0e01c22016-02-09 14:02:49 -080061
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected ControlMessageProviderRegistry providerRegistry;
64
Jian Li1d13c262016-02-09 14:58:28 -080065 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected OpenFlowController controller;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected MetricsService metricsService;
70
Jian Lie0e01c22016-02-09 14:02:49 -080071 private ControlMessageProviderService providerService;
72
Jian Li1d13c262016-02-09 14:58:28 -080073 private final InternalDeviceProvider listener = new InternalDeviceProvider();
74
Jian Lia78cdb22016-04-21 13:03:58 -070075 private final InternalControlMessageListener messageListener =
76 new InternalControlMessageListener();
Jian Li1d13c262016-02-09 14:58:28 -080077
78 private HashMap<Dpid, OpenFlowControlMessageAggregator> aggregators = Maps.newHashMap();
Jian Lia1d7f272016-03-28 17:21:47 -070079 private SharedScheduledExecutorService executor;
Jian Li1d13c262016-02-09 14:58:28 -080080 private static final int AGGR_INIT_DELAY = 1;
81 private static final int AGGR_PERIOD = 1;
82 private static final TimeUnit AGGR_TIME_UNIT = TimeUnit.MINUTES;
83 private HashMap<Dpid, ScheduledFuture<?>> executorResults = Maps.newHashMap();
84
Jian Lie0e01c22016-02-09 14:02:49 -080085 /**
86 * Creates a provider with the supplier identifier.
87 */
88 public OpenFlowControlMessageProvider() {
89 super(new ProviderId("of", "org.onosproject.provider.openflow"));
90 }
91
92 @Activate
93 protected void activate() {
94 providerService = providerRegistry.register(this);
Jian Li1d13c262016-02-09 14:58:28 -080095
96 // listens all OpenFlow device related events
97 controller.addListener(listener);
98
Jian Lia78cdb22016-04-21 13:03:58 -070099 // listens all OpenFlow control message
100 controller.addMessageListener(messageListener);
Jian Li1d13c262016-02-09 14:58:28 -0800101
Jian Li66f15262016-03-03 11:18:40 -0800102 executor = SharedScheduledExecutors.getSingleThreadExecutor();
Jian Li1d13c262016-02-09 14:58:28 -0800103
104 connectInitialDevices();
105 log.info("Started");
Jian Lie0e01c22016-02-09 14:02:49 -0800106 }
107
108 @Deactivate
109 protected void deactivate() {
Kavitha Alagesan47b80fa2016-11-10 16:11:32 +0530110 disconnectDevices();
Jian Li1d13c262016-02-09 14:58:28 -0800111 controller.removeListener(listener);
Jian Lie0e01c22016-02-09 14:02:49 -0800112 providerRegistry.unregister(this);
113 providerService = null;
Jian Li1d13c262016-02-09 14:58:28 -0800114
Jian Lia78cdb22016-04-21 13:03:58 -0700115 // stops listening all OpenFlow control message events
116 controller.removeMessageListener(messageListener);
Jian Li1d13c262016-02-09 14:58:28 -0800117
118 log.info("Stopped");
119 }
120
121 private void connectInitialDevices() {
122 for (OpenFlowSwitch sw: controller.getSwitches()) {
123 try {
124 listener.switchAdded(new Dpid(sw.getId()));
125 } catch (Exception e) {
126 log.warn("Failed initially adding {} : {}", sw.getStringId(), e.getMessage());
127 log.debug("Error details:", e);
128 }
129 }
130 }
131
Kavitha Alagesan47b80fa2016-11-10 16:11:32 +0530132 private void disconnectDevices() {
133 for (OpenFlowSwitch sw: controller.getSwitches()) {
134 try {
135 listener.switchRemoved(new Dpid(sw.getId()));
136 } catch (Exception e) {
137 log.warn("Failed to remove {} : {}", sw.getStringId(), e.getMessage());
138 log.debug("Error details:", e);
139 }
140 }
141 }
142
Jian Li1d13c262016-02-09 14:58:28 -0800143 /**
144 * A listener for OpenFlow switch event.
145 */
146 private class InternalDeviceProvider implements OpenFlowSwitchListener {
147
148 @Override
149 public void switchAdded(Dpid dpid) {
150 if (providerService == null) {
151 return;
152 }
153
Jian Li1d13c262016-02-09 14:58:28 -0800154 DeviceId deviceId = deviceId(uri(dpid));
155 OpenFlowControlMessageAggregator ofcma =
156 new OpenFlowControlMessageAggregator(metricsService,
157 providerService, deviceId);
158 ScheduledFuture result = executor.scheduleAtFixedRate(ofcma,
Jian Lia1d7f272016-03-28 17:21:47 -0700159 AGGR_INIT_DELAY, AGGR_PERIOD, AGGR_TIME_UNIT, true);
Jian Li1d13c262016-02-09 14:58:28 -0800160 aggregators.put(dpid, ofcma);
161 executorResults.put(dpid, result);
162 }
163
164 @Override
165 public void switchRemoved(Dpid dpid) {
166 if (providerService == null) {
167 return;
168 }
169
Jian Li1d13c262016-02-09 14:58:28 -0800170 // removes the aggregator when switch is removed
171 // this also stops the aggregator from running
172 OpenFlowControlMessageAggregator aggregator = aggregators.remove(dpid);
173 if (aggregator != null) {
174 executorResults.get(dpid).cancel(true);
175 executorResults.remove(dpid);
176 }
177 }
178
179 @Override
180 public void switchChanged(Dpid dpid) {
181 }
182
183 @Override
184 public void portChanged(Dpid dpid, OFPortStatus status) {
185 }
186
187 @Override
188 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
189 }
190 }
191
192 /**
Jian Lia78cdb22016-04-21 13:03:58 -0700193 * A listener for all OpenFlow control messages.
Jian Li1d13c262016-02-09 14:58:28 -0800194 */
Jian Lia78cdb22016-04-21 13:03:58 -0700195 private class InternalControlMessageListener implements OpenFlowMessageListener {
Jian Li1d13c262016-02-09 14:58:28 -0800196
197 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700198 public void handleIncomingMessage(Dpid dpid, OFMessage msg) {
Jian Li7ceb7b02016-04-04 12:42:40 -0700199 if (msg.getType() == OFType.PACKET_IN ||
200 msg.getType() == OFType.FLOW_MOD ||
201 msg.getType() == OFType.STATS_REPLY) {
Jian Lia371e7a2016-04-06 17:40:41 -0700202 aggregators.computeIfPresent(dpid, (k, v) -> {
203 v.increment(msg);
204 return v;
205 });
Jian Li7ceb7b02016-04-04 12:42:40 -0700206 }
Jian Li1d13c262016-02-09 14:58:28 -0800207 }
Jian Li1d13c262016-02-09 14:58:28 -0800208
209 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700210 public void handleOutgoingMessage(Dpid dpid, List<OFMessage> msgs) {
211 for (OFMessage msg : msgs) {
212 if (msg.getType() == OFType.PACKET_OUT ||
213 msg.getType() == OFType.FLOW_MOD ||
214 msg.getType() == OFType.STATS_REQUEST) {
215 aggregators.computeIfPresent(dpid, (k, v) -> {
216 v.increment(msg);
217 return v;
218 });
219 }
220 }
Jian Li1d13c262016-02-09 14:58:28 -0800221 }
Jian Lie0e01c22016-02-09 14:02:49 -0800222 }
223}