blob: 36be1118b7254aa45af37b9d7e6e7725c8b96381 [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;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090037import org.onosproject.net.Device;
38import org.onosproject.net.DeviceId;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040039import org.onosproject.net.Port;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090040import org.onosproject.net.device.DeviceEvent;
41import org.onosproject.net.device.DeviceListener;
42import org.onosproject.net.device.DeviceService;
Claudine Chiu2729ffd2017-07-31 21:38:27 -040043import org.onosproject.net.device.PortStatistics;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090044import org.onosproject.net.flow.FlowRuleEvent;
45import org.onosproject.net.flow.FlowRuleListener;
46import org.onosproject.net.flow.FlowRuleService;
47import org.onosproject.net.packet.PacketContext;
48import org.onosproject.net.packet.PacketProcessor;
49import org.onosproject.net.packet.PacketService;
50import org.onosproject.ofagent.api.OFAgent;
51import org.onosproject.ofagent.api.OFAgentEvent;
52import org.onosproject.ofagent.api.OFAgentListener;
53import org.onosproject.ofagent.api.OFAgentService;
54import org.onosproject.ofagent.api.OFController;
55import org.onosproject.ofagent.api.OFSwitch;
56import org.onosproject.ofagent.api.OFSwitchCapabilities;
57import org.onosproject.ofagent.api.OFSwitchService;
58import org.projectfloodlight.openflow.types.DatapathId;
59import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
62import java.net.InetSocketAddress;
63import java.net.SocketAddress;
Claudine Chiu2729ffd2017-07-31 21:38:27 -040064import java.util.List;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090065import java.util.Objects;
66import java.util.Set;
67import java.util.concurrent.ConcurrentHashMap;
68import java.util.concurrent.ExecutorService;
69import java.util.stream.Collectors;
70
71import static com.google.common.base.Preconditions.checkArgument;
72import static org.onlab.util.BoundedThreadPool.newSingleThreadExecutor;
73import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon53381e82017-03-28 19:58:28 +090074import static org.onosproject.ofagent.api.OFAgent.State.STARTED;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090075import static org.onosproject.ofagent.api.OFAgentService.APPLICATION_NAME;
76
77/**
78 * Manages OF switches.
79 */
80@Component(immediate = true)
81@Service
82public class OFSwitchManager implements OFSwitchService {
83
84 private final Logger log = LoggerFactory.getLogger(getClass());
85
Hyunsun Moon53381e82017-03-28 19:58:28 +090086 private static final OFSwitchCapabilities DEFAULT_CAPABILITIES =
87 DefaultOFSwitchCapabilities.builder()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090088 .flowStats()
89 .tableStats()
90 .portStats()
91 .groupStats()
92 .queueStats()
93 .ipReasm()
94 .portBlocked()
95 .build();
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected CoreService coreService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected LeadershipService leadershipService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected ClusterService clusterService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected VirtualNetworkService virtualNetService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected OFAgentService ofAgentService;
111
112 private final ConcurrentHashMap<DeviceId, OFSwitch> ofSwitchMap = new ConcurrentHashMap<>();
113 private final ExecutorService eventExecutor = newSingleThreadExecutor(
114 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
115 private final OFAgentListener ofAgentListener = new InternalOFAgentListener();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900116 private final VirtualNetworkListener vNetworkListener = new InternalVirtualNetworkListener();
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900117 private final DeviceListener deviceListener = new InternalDeviceListener();
118 private final FlowRuleListener flowRuleListener = new InternalFlowRuleListener();
119 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
120
121 private NioEventLoopGroup ioWorker;
122 private ApplicationId appId;
123 private NodeId localId;
124
125 @Activate
126 protected void activate() {
127 appId = coreService.registerApplication(APPLICATION_NAME);
128 localId = clusterService.getLocalNode().id();
129 ioWorker = new NioEventLoopGroup();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900130
131 ofAgentService.agents().forEach(this::processOFAgentCreated);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900132 ofAgentService.addListener(ofAgentListener);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900133 virtualNetService.addListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900134
135 log.info("Started");
136 }
137
138 @Deactivate
139 protected void deactivate() {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900140 virtualNetService.removeListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900141 ofAgentService.removeListener(ofAgentListener);
142 ofAgentService.agents().forEach(this::processOFAgentStopped);
143
144 ioWorker.shutdownGracefully();
145 eventExecutor.shutdown();
146
147 log.info("Stopped");
148 }
149
150 @Override
151 public Set<OFSwitch> ofSwitches() {
152 return ImmutableSet.copyOf(ofSwitchMap.values());
153 }
154
155 @Override
156 public Set<OFSwitch> ofSwitches(NetworkId networkId) {
157 Set<OFSwitch> ofSwitches = devices(networkId).stream()
158 .map(ofSwitchMap::get)
159 .filter(Objects::nonNull)
160 .collect(Collectors.toSet());
161 return ImmutableSet.copyOf(ofSwitches);
162 }
163
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400164 @Override
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400165 public OFSwitch ofSwitch(NetworkId networkId, DeviceId deviceId) {
166 return ofSwitchMap.get(deviceId);
167 }
168
169 @Override
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400170 public Set<Port> ports(NetworkId networkId, DeviceId deviceId) {
171 Set<Port> ports = virtualNetService.getVirtualPorts(networkId, deviceId)
172 .stream()
173 .collect(Collectors.toSet());
174 return ImmutableSet.copyOf(ports);
175 }
176
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400177 @Override
178 public List<PortStatistics> getPortStatistics(NetworkId networkId, DeviceId deviceId) {
179 DeviceService deviceService = virtualNetService.get(networkId, DeviceService.class);
180 List<PortStatistics> portStatistics = deviceService.getPortStatistics(deviceId);
181 return portStatistics;
182 }
183
Hyunsun Moon53381e82017-03-28 19:58:28 +0900184 private void addOFSwitch(NetworkId networkId, DeviceId deviceId) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900185 OFSwitch ofSwitch = DefaultOFSwitch.of(
186 dpidWithDeviceId(deviceId),
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400187 DEFAULT_CAPABILITIES, networkId, deviceId,
188 virtualNetService.getServiceDirectory());
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900189 ofSwitchMap.put(deviceId, ofSwitch);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900190 log.info("Added virtual OF switch for {}", deviceId);
191
192 OFAgent ofAgent = ofAgentService.agent(networkId);
Eric Tangdf833c82017-06-04 22:55:49 +0800193 if (ofAgent == null) {
194 log.error("OFAgent for network {} does not exist", networkId);
195 return;
196 }
197
Hyunsun Moon53381e82017-03-28 19:58:28 +0900198 if (ofAgent.state() == STARTED) {
199 connectController(ofSwitch, ofAgent.controllers());
200 }
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900201 }
202
203 private void deleteOFSwitch(DeviceId deviceId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900204 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
205 ofSwitch.controllerChannels().forEach(ChannelOutboundInvoker::disconnect);
206
207 ofSwitchMap.remove(deviceId);
208 log.info("Removed virtual OFSwitch for {}", deviceId);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900209 }
210
211 private void connectController(OFSwitch ofSwitch, Set<OFController> controllers) {
212 controllers.forEach(controller -> {
213 OFConnectionHandler connectionHandler = new OFConnectionHandler(
214 ofSwitch,
215 controller,
216 ioWorker);
217 connectionHandler.connect();
218 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900219 }
220
221 private void disconnectController(OFSwitch ofSwitch, Set<OFController> controllers) {
222 Set<SocketAddress> controllerAddrs = controllers.stream()
Hyunsun Moon53381e82017-03-28 19:58:28 +0900223 .map(ctrl -> new InetSocketAddress(
224 ctrl.ip().toInetAddress(), ctrl.port().toInt()))
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900225 .collect(Collectors.toSet());
226
227 ofSwitch.controllerChannels().stream()
228 .filter(channel -> controllerAddrs.contains(channel.remoteAddress()))
229 .forEach(ChannelOutboundInvoker::disconnect);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900230 }
231
232 private Set<DeviceId> devices(NetworkId networkId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900233 Set<DeviceId> deviceIds = virtualNetService.getVirtualDevices(networkId)
234 .stream()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900235 .map(Device::id)
236 .collect(Collectors.toSet());
237 return ImmutableSet.copyOf(deviceIds);
238 }
239
240 private DatapathId dpidWithDeviceId(DeviceId deviceId) {
241 String strDeviceId = deviceId.toString().split(":")[1];
242 checkArgument(strDeviceId.length() == 16, "Invalid device ID " + strDeviceId);
243
244 String resultedHexString = "";
245 for (int i = 0; i < 8; i++) {
246 resultedHexString = resultedHexString + strDeviceId.charAt(2 * i)
247 + strDeviceId.charAt(2 * i + 1);
248 if (i != 7) {
249 resultedHexString += ":";
250 }
251 }
252 return DatapathId.of(resultedHexString);
253 }
254
255 private void processOFAgentCreated(OFAgent ofAgent) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900256 devices(ofAgent.networkId()).forEach(deviceId -> {
257 addOFSwitch(ofAgent.networkId(), deviceId);
258 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900259 }
260
261 private void processOFAgentRemoved(OFAgent ofAgent) {
262 devices(ofAgent.networkId()).forEach(this::deleteOFSwitch);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900263 }
264
265 private void processOFAgentStarted(OFAgent ofAgent) {
266 devices(ofAgent.networkId()).forEach(deviceId -> {
267 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
268 if (ofSwitch != null) {
269 connectController(ofSwitch, ofAgent.controllers());
270 }
271 });
272
Hyunsun Moon53381e82017-03-28 19:58:28 +0900273 DeviceService deviceService = virtualNetService.get(
274 ofAgent.networkId(),
275 DeviceService.class);
276 deviceService.addListener(deviceListener);
277
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900278 PacketService packetService = virtualNetService.get(
279 ofAgent.networkId(),
280 PacketService.class);
281 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
282
283 FlowRuleService flowRuleService = virtualNetService.get(
284 ofAgent.networkId(),
285 FlowRuleService.class);
286 flowRuleService.addListener(flowRuleListener);
287 }
288
289 private void processOFAgentStopped(OFAgent ofAgent) {
290 devices(ofAgent.networkId()).forEach(deviceId -> {
291 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
292 if (ofSwitch != null) {
293 disconnectController(ofSwitch, ofAgent.controllers());
294 }
295 });
296
Hyunsun Moon53381e82017-03-28 19:58:28 +0900297 DeviceService deviceService = virtualNetService.get(
298 ofAgent.networkId(),
299 DeviceService.class);
300 deviceService.removeListener(deviceListener);
301
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900302 PacketService packetService = virtualNetService.get(
303 ofAgent.networkId(),
304 PacketService.class);
305 packetService.removeProcessor(packetProcessor);
306
307 FlowRuleService flowRuleService = virtualNetService.get(
308 ofAgent.networkId(),
309 FlowRuleService.class);
310 flowRuleService.removeListener(flowRuleListener);
311 }
312
Hyunsun Moon53381e82017-03-28 19:58:28 +0900313 private class InternalVirtualNetworkListener implements VirtualNetworkListener {
314
315 @Override
316 public void event(VirtualNetworkEvent event) {
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400317 log.trace("Vnet event {}", event);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900318 switch (event.type()) {
319 case VIRTUAL_DEVICE_ADDED:
320 eventExecutor.execute(() -> {
321 log.debug("Virtual device {} added to network {}",
322 event.virtualDevice().id(),
323 event.subject());
324 addOFSwitch(event.subject(), event.virtualDevice().id());
325 });
326 break;
327 case VIRTUAL_DEVICE_UPDATED:
328 // TODO handle device availability updates
329 break;
330 case VIRTUAL_DEVICE_REMOVED:
331 eventExecutor.execute(() -> {
332 log.debug("Virtual device {} removed from network {}",
333 event.virtualDevice().id(),
334 event.subject());
335 deleteOFSwitch(event.virtualDevice().id());
336 });
337 break;
338 case NETWORK_UPDATED:
339 case NETWORK_REMOVED:
340 case NETWORK_ADDED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400341 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900342 case VIRTUAL_PORT_ADDED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400343 eventExecutor.execute(() -> {
344 OFSwitch ofSwitch = ofSwitch(event.virtualPort());
345 if (ofSwitch != null) {
346 ofSwitch.processPortAdded(event.virtualPort());
347 log.debug("Virtual port {} added to network {}",
348 event.virtualPort(),
349 event.subject());
350 }
351 });
352 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900353 case VIRTUAL_PORT_UPDATED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400354 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900355 case VIRTUAL_PORT_REMOVED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400356 eventExecutor.execute(() -> {
357 OFSwitch ofSwitch = ofSwitch(event.virtualPort());
358 if (ofSwitch != null) {
359 ofSwitch.processPortRemoved(event.virtualPort());
360 log.debug("Virtual port {} removed from network {}",
361 event.virtualPort(),
362 event.subject());
363 }
364 });
365 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900366 default:
367 // do nothing
368 break;
369 }
370 }
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400371
372 private OFSwitch ofSwitch(VirtualPort virtualPort) {
373 OFSwitch ofSwitch = ofSwitchMap.get(virtualPort.element().id());
374 if (ofSwitch == null) {
375 log.warn("Switch does not exist for port {}", virtualPort);
376 } else {
377 log.trace("Switch exists for port {}", virtualPort);
378 }
379 return ofSwitch;
380 }
Hyunsun Moon53381e82017-03-28 19:58:28 +0900381 }
382
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900383 private class InternalOFAgentListener implements OFAgentListener {
384
385 @Override
386 public boolean isRelevant(OFAgentEvent event) {
387 return Objects.equals(localId, leadershipService.getLeader(appId.name()));
388 }
389
390 @Override
391 public void event(OFAgentEvent event) {
392 switch (event.type()) {
393 case OFAGENT_CREATED:
394 eventExecutor.execute(() -> {
395 OFAgent ofAgent = event.subject();
396 log.debug("Processing OFAgent created: {}", ofAgent);
397 processOFAgentCreated(ofAgent);
398 });
399 break;
400 case OFAGENT_REMOVED:
401 eventExecutor.execute(() -> {
402 OFAgent ofAgent = event.subject();
403 log.debug("Processing OFAgent removed: {}", ofAgent);
404 processOFAgentRemoved(ofAgent);
405 });
406 break;
407 case OFAGENT_CONTROLLER_ADDED:
408 // TODO handle additional controller
409 break;
410 case OFAGENT_CONTROLLER_REMOVED:
411 // TODO handle removed controller
412 break;
413 case OFAGENT_STARTED:
414 eventExecutor.execute(() -> {
415 OFAgent ofAgent = event.subject();
416 log.debug("Processing OFAgent started: {}", ofAgent);
417 processOFAgentStarted(ofAgent);
418 });
419 break;
420 case OFAGENT_STOPPED:
421 eventExecutor.execute(() -> {
422 OFAgent ofAgent = event.subject();
423 log.debug("Processing OFAgent stopped: {}", ofAgent);
424 processOFAgentStopped(ofAgent);
425 });
426 break;
427 default:
428 // do nothing
429 break;
430 }
431 }
432 }
433
434 private class InternalDeviceListener implements DeviceListener {
435
436 @Override
437 public void event(DeviceEvent event) {
438 switch (event.type()) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900439 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900440 case DEVICE_ADDED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900441 case DEVICE_UPDATED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900442 case DEVICE_REMOVED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900443 case DEVICE_SUSPENDED:
444 case PORT_ADDED:
445 // TODO handle event
446 case PORT_REMOVED:
447 // TODO handle event
448 case PORT_STATS_UPDATED:
449 case PORT_UPDATED:
450 default:
451 break;
452 }
453 }
454 }
455
456 private class InternalPacketProcessor implements PacketProcessor {
457
458 @Override
459 public void process(PacketContext context) {
460 // TODO handle packet-in
461 }
462 }
463
464 private class InternalFlowRuleListener implements FlowRuleListener {
465
466 @Override
467 public void event(FlowRuleEvent event) {
468 // TODO handle flow rule event
469 }
470 }
471}