blob: 9d58115a8b648891ec27a271c4b763c5793777bf [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);
168 if (ofAgent.state() == STARTED) {
169 connectController(ofSwitch, ofAgent.controllers());
170 }
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900171 }
172
173 private void deleteOFSwitch(DeviceId deviceId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900174 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
175 ofSwitch.controllerChannels().forEach(ChannelOutboundInvoker::disconnect);
176
177 ofSwitchMap.remove(deviceId);
178 log.info("Removed virtual OFSwitch for {}", deviceId);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900179 }
180
181 private void connectController(OFSwitch ofSwitch, Set<OFController> controllers) {
182 controllers.forEach(controller -> {
183 OFConnectionHandler connectionHandler = new OFConnectionHandler(
184 ofSwitch,
185 controller,
186 ioWorker);
187 connectionHandler.connect();
188 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900189 }
190
191 private void disconnectController(OFSwitch ofSwitch, Set<OFController> controllers) {
192 Set<SocketAddress> controllerAddrs = controllers.stream()
Hyunsun Moon53381e82017-03-28 19:58:28 +0900193 .map(ctrl -> new InetSocketAddress(
194 ctrl.ip().toInetAddress(), ctrl.port().toInt()))
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900195 .collect(Collectors.toSet());
196
197 ofSwitch.controllerChannels().stream()
198 .filter(channel -> controllerAddrs.contains(channel.remoteAddress()))
199 .forEach(ChannelOutboundInvoker::disconnect);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900200 }
201
202 private Set<DeviceId> devices(NetworkId networkId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900203 Set<DeviceId> deviceIds = virtualNetService.getVirtualDevices(networkId)
204 .stream()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900205 .map(Device::id)
206 .collect(Collectors.toSet());
207 return ImmutableSet.copyOf(deviceIds);
208 }
209
210 private DatapathId dpidWithDeviceId(DeviceId deviceId) {
211 String strDeviceId = deviceId.toString().split(":")[1];
212 checkArgument(strDeviceId.length() == 16, "Invalid device ID " + strDeviceId);
213
214 String resultedHexString = "";
215 for (int i = 0; i < 8; i++) {
216 resultedHexString = resultedHexString + strDeviceId.charAt(2 * i)
217 + strDeviceId.charAt(2 * i + 1);
218 if (i != 7) {
219 resultedHexString += ":";
220 }
221 }
222 return DatapathId.of(resultedHexString);
223 }
224
225 private void processOFAgentCreated(OFAgent ofAgent) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900226 devices(ofAgent.networkId()).forEach(deviceId -> {
227 addOFSwitch(ofAgent.networkId(), deviceId);
228 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900229 }
230
231 private void processOFAgentRemoved(OFAgent ofAgent) {
232 devices(ofAgent.networkId()).forEach(this::deleteOFSwitch);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900233 }
234
235 private void processOFAgentStarted(OFAgent ofAgent) {
236 devices(ofAgent.networkId()).forEach(deviceId -> {
237 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
238 if (ofSwitch != null) {
239 connectController(ofSwitch, ofAgent.controllers());
240 }
241 });
242
Hyunsun Moon53381e82017-03-28 19:58:28 +0900243 DeviceService deviceService = virtualNetService.get(
244 ofAgent.networkId(),
245 DeviceService.class);
246 deviceService.addListener(deviceListener);
247
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900248 PacketService packetService = virtualNetService.get(
249 ofAgent.networkId(),
250 PacketService.class);
251 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
252
253 FlowRuleService flowRuleService = virtualNetService.get(
254 ofAgent.networkId(),
255 FlowRuleService.class);
256 flowRuleService.addListener(flowRuleListener);
257 }
258
259 private void processOFAgentStopped(OFAgent ofAgent) {
260 devices(ofAgent.networkId()).forEach(deviceId -> {
261 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
262 if (ofSwitch != null) {
263 disconnectController(ofSwitch, ofAgent.controllers());
264 }
265 });
266
Hyunsun Moon53381e82017-03-28 19:58:28 +0900267 DeviceService deviceService = virtualNetService.get(
268 ofAgent.networkId(),
269 DeviceService.class);
270 deviceService.removeListener(deviceListener);
271
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900272 PacketService packetService = virtualNetService.get(
273 ofAgent.networkId(),
274 PacketService.class);
275 packetService.removeProcessor(packetProcessor);
276
277 FlowRuleService flowRuleService = virtualNetService.get(
278 ofAgent.networkId(),
279 FlowRuleService.class);
280 flowRuleService.removeListener(flowRuleListener);
281 }
282
Hyunsun Moon53381e82017-03-28 19:58:28 +0900283 private class InternalVirtualNetworkListener implements VirtualNetworkListener {
284
285 @Override
286 public void event(VirtualNetworkEvent event) {
287 switch (event.type()) {
288 case VIRTUAL_DEVICE_ADDED:
289 eventExecutor.execute(() -> {
290 log.debug("Virtual device {} added to network {}",
291 event.virtualDevice().id(),
292 event.subject());
293 addOFSwitch(event.subject(), event.virtualDevice().id());
294 });
295 break;
296 case VIRTUAL_DEVICE_UPDATED:
297 // TODO handle device availability updates
298 break;
299 case VIRTUAL_DEVICE_REMOVED:
300 eventExecutor.execute(() -> {
301 log.debug("Virtual device {} removed from network {}",
302 event.virtualDevice().id(),
303 event.subject());
304 deleteOFSwitch(event.virtualDevice().id());
305 });
306 break;
307 case NETWORK_UPDATED:
308 case NETWORK_REMOVED:
309 case NETWORK_ADDED:
310 case VIRTUAL_PORT_ADDED:
311 case VIRTUAL_PORT_UPDATED:
312 case VIRTUAL_PORT_REMOVED:
313 default:
314 // do nothing
315 break;
316 }
317 }
318 }
319
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900320 private class InternalOFAgentListener implements OFAgentListener {
321
322 @Override
323 public boolean isRelevant(OFAgentEvent event) {
324 return Objects.equals(localId, leadershipService.getLeader(appId.name()));
325 }
326
327 @Override
328 public void event(OFAgentEvent event) {
329 switch (event.type()) {
330 case OFAGENT_CREATED:
331 eventExecutor.execute(() -> {
332 OFAgent ofAgent = event.subject();
333 log.debug("Processing OFAgent created: {}", ofAgent);
334 processOFAgentCreated(ofAgent);
335 });
336 break;
337 case OFAGENT_REMOVED:
338 eventExecutor.execute(() -> {
339 OFAgent ofAgent = event.subject();
340 log.debug("Processing OFAgent removed: {}", ofAgent);
341 processOFAgentRemoved(ofAgent);
342 });
343 break;
344 case OFAGENT_CONTROLLER_ADDED:
345 // TODO handle additional controller
346 break;
347 case OFAGENT_CONTROLLER_REMOVED:
348 // TODO handle removed controller
349 break;
350 case OFAGENT_STARTED:
351 eventExecutor.execute(() -> {
352 OFAgent ofAgent = event.subject();
353 log.debug("Processing OFAgent started: {}", ofAgent);
354 processOFAgentStarted(ofAgent);
355 });
356 break;
357 case OFAGENT_STOPPED:
358 eventExecutor.execute(() -> {
359 OFAgent ofAgent = event.subject();
360 log.debug("Processing OFAgent stopped: {}", ofAgent);
361 processOFAgentStopped(ofAgent);
362 });
363 break;
364 default:
365 // do nothing
366 break;
367 }
368 }
369 }
370
371 private class InternalDeviceListener implements DeviceListener {
372
373 @Override
374 public void event(DeviceEvent event) {
375 switch (event.type()) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900376 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900377 case DEVICE_ADDED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900378 case DEVICE_UPDATED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900379 case DEVICE_REMOVED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900380 case DEVICE_SUSPENDED:
381 case PORT_ADDED:
382 // TODO handle event
383 case PORT_REMOVED:
384 // TODO handle event
385 case PORT_STATS_UPDATED:
386 case PORT_UPDATED:
387 default:
388 break;
389 }
390 }
391 }
392
393 private class InternalPacketProcessor implements PacketProcessor {
394
395 @Override
396 public void process(PacketContext context) {
397 // TODO handle packet-in
398 }
399 }
400
401 private class InternalFlowRuleListener implements FlowRuleListener {
402
403 @Override
404 public void event(FlowRuleEvent event) {
405 // TODO handle flow rule event
406 }
407 }
408}