blob: e23cb81b46eb3b87a8973b146cf53e7a20097784 [file] [log] [blame]
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +09001/*
2 * Copyright 2017-present 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 */
16package org.onosproject.ofagent.impl;
17
18import com.google.common.collect.ImmutableSet;
19import io.netty.channel.ChannelOutboundInvoker;
20import io.netty.channel.nio.NioEventLoopGroup;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090027import org.onosproject.cluster.ClusterService;
28import org.onosproject.cluster.LeadershipService;
29import org.onosproject.cluster.NodeId;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.incubator.net.virtual.NetworkId;
Hyunsun Moon53381e82017-03-28 19:58:28 +090033import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
34import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090035import org.onosproject.incubator.net.virtual.VirtualNetworkService;
36import org.onosproject.net.Device;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.device.DeviceEvent;
39import org.onosproject.net.device.DeviceListener;
40import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.flow.FlowRuleEvent;
42import org.onosproject.net.flow.FlowRuleListener;
43import org.onosproject.net.flow.FlowRuleService;
44import org.onosproject.net.packet.PacketContext;
45import org.onosproject.net.packet.PacketProcessor;
46import org.onosproject.net.packet.PacketService;
47import org.onosproject.ofagent.api.OFAgent;
48import org.onosproject.ofagent.api.OFAgentEvent;
49import org.onosproject.ofagent.api.OFAgentListener;
50import org.onosproject.ofagent.api.OFAgentService;
51import org.onosproject.ofagent.api.OFController;
52import org.onosproject.ofagent.api.OFSwitch;
53import org.onosproject.ofagent.api.OFSwitchCapabilities;
54import org.onosproject.ofagent.api.OFSwitchService;
55import org.projectfloodlight.openflow.types.DatapathId;
56import org.slf4j.Logger;
57import org.slf4j.LoggerFactory;
58
59import java.net.InetSocketAddress;
60import java.net.SocketAddress;
61import java.util.Objects;
62import java.util.Set;
63import java.util.concurrent.ConcurrentHashMap;
64import java.util.concurrent.ExecutorService;
65import java.util.stream.Collectors;
66
67import static com.google.common.base.Preconditions.checkArgument;
68import static org.onlab.util.BoundedThreadPool.newSingleThreadExecutor;
69import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon53381e82017-03-28 19:58:28 +090070import static org.onosproject.ofagent.api.OFAgent.State.STARTED;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090071import static org.onosproject.ofagent.api.OFAgentService.APPLICATION_NAME;
72
73/**
74 * Manages OF switches.
75 */
76@Component(immediate = true)
77@Service
78public class OFSwitchManager implements OFSwitchService {
79
80 private final Logger log = LoggerFactory.getLogger(getClass());
81
Hyunsun Moon53381e82017-03-28 19:58:28 +090082 private static final OFSwitchCapabilities DEFAULT_CAPABILITIES =
83 DefaultOFSwitchCapabilities.builder()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090084 .flowStats()
85 .tableStats()
86 .portStats()
87 .groupStats()
88 .queueStats()
89 .ipReasm()
90 .portBlocked()
91 .build();
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected LeadershipService leadershipService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected ClusterService clusterService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected VirtualNetworkService virtualNetService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected OFAgentService ofAgentService;
107
108 private final ConcurrentHashMap<DeviceId, OFSwitch> ofSwitchMap = new ConcurrentHashMap<>();
109 private final ExecutorService eventExecutor = newSingleThreadExecutor(
110 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
111 private final OFAgentListener ofAgentListener = new InternalOFAgentListener();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900112 private final VirtualNetworkListener vNetworkListener = new InternalVirtualNetworkListener();
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900113 private final DeviceListener deviceListener = new InternalDeviceListener();
114 private final FlowRuleListener flowRuleListener = new InternalFlowRuleListener();
115 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
116
117 private NioEventLoopGroup ioWorker;
118 private ApplicationId appId;
119 private NodeId localId;
120
121 @Activate
122 protected void activate() {
123 appId = coreService.registerApplication(APPLICATION_NAME);
124 localId = clusterService.getLocalNode().id();
125 ioWorker = new NioEventLoopGroup();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900126
127 ofAgentService.agents().forEach(this::processOFAgentCreated);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900128 ofAgentService.addListener(ofAgentListener);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900129 virtualNetService.addListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900130
131 log.info("Started");
132 }
133
134 @Deactivate
135 protected void deactivate() {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900136 virtualNetService.removeListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900137 ofAgentService.removeListener(ofAgentListener);
138 ofAgentService.agents().forEach(this::processOFAgentStopped);
139
140 ioWorker.shutdownGracefully();
141 eventExecutor.shutdown();
142
143 log.info("Stopped");
144 }
145
146 @Override
147 public Set<OFSwitch> ofSwitches() {
148 return ImmutableSet.copyOf(ofSwitchMap.values());
149 }
150
151 @Override
152 public Set<OFSwitch> ofSwitches(NetworkId networkId) {
153 Set<OFSwitch> ofSwitches = devices(networkId).stream()
154 .map(ofSwitchMap::get)
155 .filter(Objects::nonNull)
156 .collect(Collectors.toSet());
157 return ImmutableSet.copyOf(ofSwitches);
158 }
159
Hyunsun Moon53381e82017-03-28 19:58:28 +0900160 private void addOFSwitch(NetworkId networkId, DeviceId deviceId) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900161 OFSwitch ofSwitch = DefaultOFSwitch.of(
162 dpidWithDeviceId(deviceId),
163 DEFAULT_CAPABILITIES);
164 ofSwitchMap.put(deviceId, ofSwitch);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900165 log.info("Added virtual OF switch for {}", deviceId);
166
167 OFAgent ofAgent = ofAgentService.agent(networkId);
Eric Tangdf833c82017-06-04 22:55:49 +0800168 if (ofAgent == null) {
169 log.error("OFAgent for network {} does not exist", networkId);
170 return;
171 }
172
Hyunsun Moon53381e82017-03-28 19:58:28 +0900173 if (ofAgent.state() == STARTED) {
174 connectController(ofSwitch, ofAgent.controllers());
175 }
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900176 }
177
178 private void deleteOFSwitch(DeviceId deviceId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900179 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
180 ofSwitch.controllerChannels().forEach(ChannelOutboundInvoker::disconnect);
181
182 ofSwitchMap.remove(deviceId);
183 log.info("Removed virtual OFSwitch for {}", deviceId);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900184 }
185
186 private void connectController(OFSwitch ofSwitch, Set<OFController> controllers) {
187 controllers.forEach(controller -> {
188 OFConnectionHandler connectionHandler = new OFConnectionHandler(
189 ofSwitch,
190 controller,
191 ioWorker);
192 connectionHandler.connect();
193 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900194 }
195
196 private void disconnectController(OFSwitch ofSwitch, Set<OFController> controllers) {
197 Set<SocketAddress> controllerAddrs = controllers.stream()
Hyunsun Moon53381e82017-03-28 19:58:28 +0900198 .map(ctrl -> new InetSocketAddress(
199 ctrl.ip().toInetAddress(), ctrl.port().toInt()))
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900200 .collect(Collectors.toSet());
201
202 ofSwitch.controllerChannels().stream()
203 .filter(channel -> controllerAddrs.contains(channel.remoteAddress()))
204 .forEach(ChannelOutboundInvoker::disconnect);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900205 }
206
207 private Set<DeviceId> devices(NetworkId networkId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900208 Set<DeviceId> deviceIds = virtualNetService.getVirtualDevices(networkId)
209 .stream()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900210 .map(Device::id)
211 .collect(Collectors.toSet());
212 return ImmutableSet.copyOf(deviceIds);
213 }
214
215 private DatapathId dpidWithDeviceId(DeviceId deviceId) {
216 String strDeviceId = deviceId.toString().split(":")[1];
217 checkArgument(strDeviceId.length() == 16, "Invalid device ID " + strDeviceId);
218
219 String resultedHexString = "";
220 for (int i = 0; i < 8; i++) {
221 resultedHexString = resultedHexString + strDeviceId.charAt(2 * i)
222 + strDeviceId.charAt(2 * i + 1);
223 if (i != 7) {
224 resultedHexString += ":";
225 }
226 }
227 return DatapathId.of(resultedHexString);
228 }
229
230 private void processOFAgentCreated(OFAgent ofAgent) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900231 devices(ofAgent.networkId()).forEach(deviceId -> {
232 addOFSwitch(ofAgent.networkId(), deviceId);
233 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900234 }
235
236 private void processOFAgentRemoved(OFAgent ofAgent) {
237 devices(ofAgent.networkId()).forEach(this::deleteOFSwitch);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900238 }
239
240 private void processOFAgentStarted(OFAgent ofAgent) {
241 devices(ofAgent.networkId()).forEach(deviceId -> {
242 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
243 if (ofSwitch != null) {
244 connectController(ofSwitch, ofAgent.controllers());
245 }
246 });
247
Hyunsun Moon53381e82017-03-28 19:58:28 +0900248 DeviceService deviceService = virtualNetService.get(
249 ofAgent.networkId(),
250 DeviceService.class);
251 deviceService.addListener(deviceListener);
252
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900253 PacketService packetService = virtualNetService.get(
254 ofAgent.networkId(),
255 PacketService.class);
256 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
257
258 FlowRuleService flowRuleService = virtualNetService.get(
259 ofAgent.networkId(),
260 FlowRuleService.class);
261 flowRuleService.addListener(flowRuleListener);
262 }
263
264 private void processOFAgentStopped(OFAgent ofAgent) {
265 devices(ofAgent.networkId()).forEach(deviceId -> {
266 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
267 if (ofSwitch != null) {
268 disconnectController(ofSwitch, ofAgent.controllers());
269 }
270 });
271
Hyunsun Moon53381e82017-03-28 19:58:28 +0900272 DeviceService deviceService = virtualNetService.get(
273 ofAgent.networkId(),
274 DeviceService.class);
275 deviceService.removeListener(deviceListener);
276
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900277 PacketService packetService = virtualNetService.get(
278 ofAgent.networkId(),
279 PacketService.class);
280 packetService.removeProcessor(packetProcessor);
281
282 FlowRuleService flowRuleService = virtualNetService.get(
283 ofAgent.networkId(),
284 FlowRuleService.class);
285 flowRuleService.removeListener(flowRuleListener);
286 }
287
Hyunsun Moon53381e82017-03-28 19:58:28 +0900288 private class InternalVirtualNetworkListener implements VirtualNetworkListener {
289
290 @Override
291 public void event(VirtualNetworkEvent event) {
292 switch (event.type()) {
293 case VIRTUAL_DEVICE_ADDED:
294 eventExecutor.execute(() -> {
295 log.debug("Virtual device {} added to network {}",
296 event.virtualDevice().id(),
297 event.subject());
298 addOFSwitch(event.subject(), event.virtualDevice().id());
299 });
300 break;
301 case VIRTUAL_DEVICE_UPDATED:
302 // TODO handle device availability updates
303 break;
304 case VIRTUAL_DEVICE_REMOVED:
305 eventExecutor.execute(() -> {
306 log.debug("Virtual device {} removed from network {}",
307 event.virtualDevice().id(),
308 event.subject());
309 deleteOFSwitch(event.virtualDevice().id());
310 });
311 break;
312 case NETWORK_UPDATED:
313 case NETWORK_REMOVED:
314 case NETWORK_ADDED:
315 case VIRTUAL_PORT_ADDED:
316 case VIRTUAL_PORT_UPDATED:
317 case VIRTUAL_PORT_REMOVED:
318 default:
319 // do nothing
320 break;
321 }
322 }
323 }
324
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900325 private class InternalOFAgentListener implements OFAgentListener {
326
327 @Override
328 public boolean isRelevant(OFAgentEvent event) {
329 return Objects.equals(localId, leadershipService.getLeader(appId.name()));
330 }
331
332 @Override
333 public void event(OFAgentEvent event) {
334 switch (event.type()) {
335 case OFAGENT_CREATED:
336 eventExecutor.execute(() -> {
337 OFAgent ofAgent = event.subject();
338 log.debug("Processing OFAgent created: {}", ofAgent);
339 processOFAgentCreated(ofAgent);
340 });
341 break;
342 case OFAGENT_REMOVED:
343 eventExecutor.execute(() -> {
344 OFAgent ofAgent = event.subject();
345 log.debug("Processing OFAgent removed: {}", ofAgent);
346 processOFAgentRemoved(ofAgent);
347 });
348 break;
349 case OFAGENT_CONTROLLER_ADDED:
350 // TODO handle additional controller
351 break;
352 case OFAGENT_CONTROLLER_REMOVED:
353 // TODO handle removed controller
354 break;
355 case OFAGENT_STARTED:
356 eventExecutor.execute(() -> {
357 OFAgent ofAgent = event.subject();
358 log.debug("Processing OFAgent started: {}", ofAgent);
359 processOFAgentStarted(ofAgent);
360 });
361 break;
362 case OFAGENT_STOPPED:
363 eventExecutor.execute(() -> {
364 OFAgent ofAgent = event.subject();
365 log.debug("Processing OFAgent stopped: {}", ofAgent);
366 processOFAgentStopped(ofAgent);
367 });
368 break;
369 default:
370 // do nothing
371 break;
372 }
373 }
374 }
375
376 private class InternalDeviceListener implements DeviceListener {
377
378 @Override
379 public void event(DeviceEvent event) {
380 switch (event.type()) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900381 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900382 case DEVICE_ADDED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900383 case DEVICE_UPDATED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900384 case DEVICE_REMOVED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900385 case DEVICE_SUSPENDED:
386 case PORT_ADDED:
387 // TODO handle event
388 case PORT_REMOVED:
389 // TODO handle event
390 case PORT_STATS_UPDATED:
391 case PORT_UPDATED:
392 default:
393 break;
394 }
395 }
396 }
397
398 private class InternalPacketProcessor implements PacketProcessor {
399
400 @Override
401 public void process(PacketContext context) {
402 // TODO handle packet-in
403 }
404 }
405
406 private class InternalFlowRuleListener implements FlowRuleListener {
407
408 @Override
409 public void event(FlowRuleEvent event) {
410 // TODO handle flow rule event
411 }
412 }
413}