blob: 101e531a1e132ebaa43346b1b1d50726ba8af73f [file] [log] [blame]
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +09003 *
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;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040036import org.onosproject.incubator.net.virtual.VirtualPort;
Claudine Chiu5c184e12017-08-08 21:21:38 -040037import org.onosproject.net.ConnectPoint;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090038import org.onosproject.net.Device;
39import org.onosproject.net.DeviceId;
Claudine Chiu5c184e12017-08-08 21:21:38 -040040import org.onosproject.net.Link;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040041import org.onosproject.net.Port;
Claudine Chiu5c184e12017-08-08 21:21:38 -040042import org.onosproject.net.PortNumber;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090043import org.onosproject.net.device.DeviceEvent;
44import org.onosproject.net.device.DeviceListener;
45import org.onosproject.net.device.DeviceService;
Claudine Chiu2729ffd2017-07-31 21:38:27 -040046import org.onosproject.net.device.PortStatistics;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090047import org.onosproject.net.flow.FlowRuleEvent;
48import org.onosproject.net.flow.FlowRuleListener;
49import org.onosproject.net.flow.FlowRuleService;
Claudine Chiu5c184e12017-08-08 21:21:38 -040050import org.onosproject.net.link.LinkService;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090051import org.onosproject.net.packet.PacketContext;
52import org.onosproject.net.packet.PacketProcessor;
53import org.onosproject.net.packet.PacketService;
54import org.onosproject.ofagent.api.OFAgent;
55import org.onosproject.ofagent.api.OFAgentEvent;
56import org.onosproject.ofagent.api.OFAgentListener;
57import org.onosproject.ofagent.api.OFAgentService;
58import org.onosproject.ofagent.api.OFController;
59import org.onosproject.ofagent.api.OFSwitch;
60import org.onosproject.ofagent.api.OFSwitchCapabilities;
61import org.onosproject.ofagent.api.OFSwitchService;
62import org.projectfloodlight.openflow.types.DatapathId;
63import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
66import java.net.InetSocketAddress;
67import java.net.SocketAddress;
Claudine Chiu2729ffd2017-07-31 21:38:27 -040068import java.util.List;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090069import java.util.Objects;
70import java.util.Set;
71import java.util.concurrent.ConcurrentHashMap;
72import java.util.concurrent.ExecutorService;
73import java.util.stream.Collectors;
74
75import static com.google.common.base.Preconditions.checkArgument;
76import static org.onlab.util.BoundedThreadPool.newSingleThreadExecutor;
77import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon53381e82017-03-28 19:58:28 +090078import static org.onosproject.ofagent.api.OFAgent.State.STARTED;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090079import static org.onosproject.ofagent.api.OFAgentService.APPLICATION_NAME;
80
81/**
82 * Manages OF switches.
83 */
84@Component(immediate = true)
85@Service
86public class OFSwitchManager implements OFSwitchService {
87
88 private final Logger log = LoggerFactory.getLogger(getClass());
89
Hyunsun Moon53381e82017-03-28 19:58:28 +090090 private static final OFSwitchCapabilities DEFAULT_CAPABILITIES =
91 DefaultOFSwitchCapabilities.builder()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090092 .flowStats()
93 .tableStats()
94 .portStats()
95 .groupStats()
96 .queueStats()
97 .ipReasm()
98 .portBlocked()
99 .build();
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected CoreService coreService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected LeadershipService leadershipService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected ClusterService clusterService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected VirtualNetworkService virtualNetService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected OFAgentService ofAgentService;
115
116 private final ConcurrentHashMap<DeviceId, OFSwitch> ofSwitchMap = new ConcurrentHashMap<>();
117 private final ExecutorService eventExecutor = newSingleThreadExecutor(
118 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
119 private final OFAgentListener ofAgentListener = new InternalOFAgentListener();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900120 private final VirtualNetworkListener vNetworkListener = new InternalVirtualNetworkListener();
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900121 private final DeviceListener deviceListener = new InternalDeviceListener();
122 private final FlowRuleListener flowRuleListener = new InternalFlowRuleListener();
123 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
124
125 private NioEventLoopGroup ioWorker;
126 private ApplicationId appId;
127 private NodeId localId;
128
129 @Activate
130 protected void activate() {
131 appId = coreService.registerApplication(APPLICATION_NAME);
132 localId = clusterService.getLocalNode().id();
133 ioWorker = new NioEventLoopGroup();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900134
135 ofAgentService.agents().forEach(this::processOFAgentCreated);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900136 ofAgentService.addListener(ofAgentListener);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900137 virtualNetService.addListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900138
139 log.info("Started");
140 }
141
142 @Deactivate
143 protected void deactivate() {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900144 virtualNetService.removeListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900145 ofAgentService.removeListener(ofAgentListener);
146 ofAgentService.agents().forEach(this::processOFAgentStopped);
147
148 ioWorker.shutdownGracefully();
149 eventExecutor.shutdown();
150
151 log.info("Stopped");
152 }
153
154 @Override
155 public Set<OFSwitch> ofSwitches() {
156 return ImmutableSet.copyOf(ofSwitchMap.values());
157 }
158
159 @Override
160 public Set<OFSwitch> ofSwitches(NetworkId networkId) {
161 Set<OFSwitch> ofSwitches = devices(networkId).stream()
162 .map(ofSwitchMap::get)
163 .filter(Objects::nonNull)
164 .collect(Collectors.toSet());
165 return ImmutableSet.copyOf(ofSwitches);
166 }
167
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400168 @Override
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400169 public OFSwitch ofSwitch(NetworkId networkId, DeviceId deviceId) {
170 return ofSwitchMap.get(deviceId);
171 }
172
173 @Override
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400174 public Set<Port> ports(NetworkId networkId, DeviceId deviceId) {
175 Set<Port> ports = virtualNetService.getVirtualPorts(networkId, deviceId)
176 .stream()
177 .collect(Collectors.toSet());
178 return ImmutableSet.copyOf(ports);
179 }
180
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400181 @Override
182 public List<PortStatistics> getPortStatistics(NetworkId networkId, DeviceId deviceId) {
183 DeviceService deviceService = virtualNetService.get(networkId, DeviceService.class);
184 List<PortStatistics> portStatistics = deviceService.getPortStatistics(deviceId);
185 return portStatistics;
186 }
187
Claudine Chiu5c184e12017-08-08 21:21:38 -0400188 @Override
189 public ConnectPoint neighbour(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
190 ConnectPoint cp = new ConnectPoint(deviceId, portNumber);
191 LinkService linkService = virtualNetService.get(networkId, LinkService.class);
192 Set<Link> links = linkService.getEgressLinks(cp);
193 log.trace("neighbour cp {} egressLinks {}", cp, links);
194 if (links != null && links.size() > 0) {
195 Link link = links.iterator().next();
196 return link.src();
197 }
198 return null;
199 }
200
Hyunsun Moon53381e82017-03-28 19:58:28 +0900201 private void addOFSwitch(NetworkId networkId, DeviceId deviceId) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900202 OFSwitch ofSwitch = DefaultOFSwitch.of(
203 dpidWithDeviceId(deviceId),
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400204 DEFAULT_CAPABILITIES, networkId, deviceId,
205 virtualNetService.getServiceDirectory());
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900206 ofSwitchMap.put(deviceId, ofSwitch);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900207 log.info("Added virtual OF switch for {}", deviceId);
208
209 OFAgent ofAgent = ofAgentService.agent(networkId);
Eric Tangdf833c82017-06-04 22:55:49 +0800210 if (ofAgent == null) {
211 log.error("OFAgent for network {} does not exist", networkId);
212 return;
213 }
214
Hyunsun Moon53381e82017-03-28 19:58:28 +0900215 if (ofAgent.state() == STARTED) {
216 connectController(ofSwitch, ofAgent.controllers());
217 }
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900218 }
219
220 private void deleteOFSwitch(DeviceId deviceId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900221 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
222 ofSwitch.controllerChannels().forEach(ChannelOutboundInvoker::disconnect);
223
224 ofSwitchMap.remove(deviceId);
225 log.info("Removed virtual OFSwitch for {}", deviceId);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900226 }
227
228 private void connectController(OFSwitch ofSwitch, Set<OFController> controllers) {
229 controllers.forEach(controller -> {
230 OFConnectionHandler connectionHandler = new OFConnectionHandler(
231 ofSwitch,
232 controller,
233 ioWorker);
234 connectionHandler.connect();
235 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900236 }
237
238 private void disconnectController(OFSwitch ofSwitch, Set<OFController> controllers) {
239 Set<SocketAddress> controllerAddrs = controllers.stream()
Hyunsun Moon53381e82017-03-28 19:58:28 +0900240 .map(ctrl -> new InetSocketAddress(
241 ctrl.ip().toInetAddress(), ctrl.port().toInt()))
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900242 .collect(Collectors.toSet());
243
244 ofSwitch.controllerChannels().stream()
245 .filter(channel -> controllerAddrs.contains(channel.remoteAddress()))
246 .forEach(ChannelOutboundInvoker::disconnect);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900247 }
248
249 private Set<DeviceId> devices(NetworkId networkId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900250 Set<DeviceId> deviceIds = virtualNetService.getVirtualDevices(networkId)
251 .stream()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900252 .map(Device::id)
253 .collect(Collectors.toSet());
254 return ImmutableSet.copyOf(deviceIds);
255 }
256
257 private DatapathId dpidWithDeviceId(DeviceId deviceId) {
258 String strDeviceId = deviceId.toString().split(":")[1];
259 checkArgument(strDeviceId.length() == 16, "Invalid device ID " + strDeviceId);
260
261 String resultedHexString = "";
262 for (int i = 0; i < 8; i++) {
263 resultedHexString = resultedHexString + strDeviceId.charAt(2 * i)
264 + strDeviceId.charAt(2 * i + 1);
265 if (i != 7) {
266 resultedHexString += ":";
267 }
268 }
269 return DatapathId.of(resultedHexString);
270 }
271
272 private void processOFAgentCreated(OFAgent ofAgent) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900273 devices(ofAgent.networkId()).forEach(deviceId -> {
274 addOFSwitch(ofAgent.networkId(), deviceId);
275 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900276 }
277
278 private void processOFAgentRemoved(OFAgent ofAgent) {
279 devices(ofAgent.networkId()).forEach(this::deleteOFSwitch);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900280 }
281
282 private void processOFAgentStarted(OFAgent ofAgent) {
283 devices(ofAgent.networkId()).forEach(deviceId -> {
284 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
285 if (ofSwitch != null) {
286 connectController(ofSwitch, ofAgent.controllers());
287 }
288 });
289
Hyunsun Moon53381e82017-03-28 19:58:28 +0900290 DeviceService deviceService = virtualNetService.get(
291 ofAgent.networkId(),
292 DeviceService.class);
293 deviceService.addListener(deviceListener);
294
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900295 PacketService packetService = virtualNetService.get(
296 ofAgent.networkId(),
297 PacketService.class);
298 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
299
300 FlowRuleService flowRuleService = virtualNetService.get(
301 ofAgent.networkId(),
302 FlowRuleService.class);
303 flowRuleService.addListener(flowRuleListener);
304 }
305
306 private void processOFAgentStopped(OFAgent ofAgent) {
307 devices(ofAgent.networkId()).forEach(deviceId -> {
308 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
309 if (ofSwitch != null) {
310 disconnectController(ofSwitch, ofAgent.controllers());
311 }
312 });
313
Hyunsun Moon53381e82017-03-28 19:58:28 +0900314 DeviceService deviceService = virtualNetService.get(
315 ofAgent.networkId(),
316 DeviceService.class);
317 deviceService.removeListener(deviceListener);
318
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900319 PacketService packetService = virtualNetService.get(
320 ofAgent.networkId(),
321 PacketService.class);
322 packetService.removeProcessor(packetProcessor);
323
324 FlowRuleService flowRuleService = virtualNetService.get(
325 ofAgent.networkId(),
326 FlowRuleService.class);
327 flowRuleService.removeListener(flowRuleListener);
328 }
329
Hyunsun Moon53381e82017-03-28 19:58:28 +0900330 private class InternalVirtualNetworkListener implements VirtualNetworkListener {
331
332 @Override
333 public void event(VirtualNetworkEvent event) {
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400334 log.trace("Vnet event {}", event);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900335 switch (event.type()) {
336 case VIRTUAL_DEVICE_ADDED:
337 eventExecutor.execute(() -> {
338 log.debug("Virtual device {} added to network {}",
339 event.virtualDevice().id(),
340 event.subject());
341 addOFSwitch(event.subject(), event.virtualDevice().id());
342 });
343 break;
344 case VIRTUAL_DEVICE_UPDATED:
345 // TODO handle device availability updates
346 break;
347 case VIRTUAL_DEVICE_REMOVED:
348 eventExecutor.execute(() -> {
349 log.debug("Virtual device {} removed from network {}",
350 event.virtualDevice().id(),
351 event.subject());
352 deleteOFSwitch(event.virtualDevice().id());
353 });
354 break;
355 case NETWORK_UPDATED:
356 case NETWORK_REMOVED:
357 case NETWORK_ADDED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400358 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900359 case VIRTUAL_PORT_ADDED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400360 eventExecutor.execute(() -> {
361 OFSwitch ofSwitch = ofSwitch(event.virtualPort());
362 if (ofSwitch != null) {
363 ofSwitch.processPortAdded(event.virtualPort());
364 log.debug("Virtual port {} added to network {}",
365 event.virtualPort(),
366 event.subject());
367 }
368 });
369 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900370 case VIRTUAL_PORT_UPDATED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400371 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900372 case VIRTUAL_PORT_REMOVED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400373 eventExecutor.execute(() -> {
374 OFSwitch ofSwitch = ofSwitch(event.virtualPort());
375 if (ofSwitch != null) {
376 ofSwitch.processPortRemoved(event.virtualPort());
377 log.debug("Virtual port {} removed from network {}",
378 event.virtualPort(),
379 event.subject());
380 }
381 });
382 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900383 default:
384 // do nothing
385 break;
386 }
387 }
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400388
389 private OFSwitch ofSwitch(VirtualPort virtualPort) {
390 OFSwitch ofSwitch = ofSwitchMap.get(virtualPort.element().id());
391 if (ofSwitch == null) {
392 log.warn("Switch does not exist for port {}", virtualPort);
393 } else {
394 log.trace("Switch exists for port {}", virtualPort);
395 }
396 return ofSwitch;
397 }
Hyunsun Moon53381e82017-03-28 19:58:28 +0900398 }
399
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900400 private class InternalOFAgentListener implements OFAgentListener {
401
402 @Override
403 public boolean isRelevant(OFAgentEvent event) {
404 return Objects.equals(localId, leadershipService.getLeader(appId.name()));
405 }
406
407 @Override
408 public void event(OFAgentEvent event) {
409 switch (event.type()) {
410 case OFAGENT_CREATED:
411 eventExecutor.execute(() -> {
412 OFAgent ofAgent = event.subject();
413 log.debug("Processing OFAgent created: {}", ofAgent);
414 processOFAgentCreated(ofAgent);
415 });
416 break;
417 case OFAGENT_REMOVED:
418 eventExecutor.execute(() -> {
419 OFAgent ofAgent = event.subject();
420 log.debug("Processing OFAgent removed: {}", ofAgent);
421 processOFAgentRemoved(ofAgent);
422 });
423 break;
424 case OFAGENT_CONTROLLER_ADDED:
425 // TODO handle additional controller
426 break;
427 case OFAGENT_CONTROLLER_REMOVED:
428 // TODO handle removed controller
429 break;
430 case OFAGENT_STARTED:
431 eventExecutor.execute(() -> {
432 OFAgent ofAgent = event.subject();
433 log.debug("Processing OFAgent started: {}", ofAgent);
434 processOFAgentStarted(ofAgent);
435 });
436 break;
437 case OFAGENT_STOPPED:
438 eventExecutor.execute(() -> {
439 OFAgent ofAgent = event.subject();
440 log.debug("Processing OFAgent stopped: {}", ofAgent);
441 processOFAgentStopped(ofAgent);
442 });
443 break;
444 default:
445 // do nothing
446 break;
447 }
448 }
449 }
450
451 private class InternalDeviceListener implements DeviceListener {
452
453 @Override
454 public void event(DeviceEvent event) {
455 switch (event.type()) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900456 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900457 case DEVICE_ADDED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900458 case DEVICE_UPDATED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900459 case DEVICE_REMOVED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900460 case DEVICE_SUSPENDED:
461 case PORT_ADDED:
462 // TODO handle event
463 case PORT_REMOVED:
464 // TODO handle event
465 case PORT_STATS_UPDATED:
466 case PORT_UPDATED:
467 default:
468 break;
469 }
470 }
471 }
472
473 private class InternalPacketProcessor implements PacketProcessor {
474
475 @Override
476 public void process(PacketContext context) {
477 // TODO handle packet-in
478 }
479 }
480
481 private class InternalFlowRuleListener implements FlowRuleListener {
482
483 @Override
484 public void event(FlowRuleEvent event) {
485 // TODO handle flow rule event
486 }
487 }
488}