blob: deac5235d07f84ca7e85cdcdb344697f64b3e52e [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;
43import org.onosproject.net.flow.FlowRuleEvent;
44import org.onosproject.net.flow.FlowRuleListener;
45import org.onosproject.net.flow.FlowRuleService;
46import org.onosproject.net.packet.PacketContext;
47import org.onosproject.net.packet.PacketProcessor;
48import org.onosproject.net.packet.PacketService;
49import org.onosproject.ofagent.api.OFAgent;
50import org.onosproject.ofagent.api.OFAgentEvent;
51import org.onosproject.ofagent.api.OFAgentListener;
52import org.onosproject.ofagent.api.OFAgentService;
53import org.onosproject.ofagent.api.OFController;
54import org.onosproject.ofagent.api.OFSwitch;
55import org.onosproject.ofagent.api.OFSwitchCapabilities;
56import org.onosproject.ofagent.api.OFSwitchService;
57import org.projectfloodlight.openflow.types.DatapathId;
58import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
61import java.net.InetSocketAddress;
62import java.net.SocketAddress;
63import java.util.Objects;
64import java.util.Set;
65import java.util.concurrent.ConcurrentHashMap;
66import java.util.concurrent.ExecutorService;
67import java.util.stream.Collectors;
68
69import static com.google.common.base.Preconditions.checkArgument;
70import static org.onlab.util.BoundedThreadPool.newSingleThreadExecutor;
71import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon53381e82017-03-28 19:58:28 +090072import static org.onosproject.ofagent.api.OFAgent.State.STARTED;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090073import static org.onosproject.ofagent.api.OFAgentService.APPLICATION_NAME;
74
75/**
76 * Manages OF switches.
77 */
78@Component(immediate = true)
79@Service
80public class OFSwitchManager implements OFSwitchService {
81
82 private final Logger log = LoggerFactory.getLogger(getClass());
83
Hyunsun Moon53381e82017-03-28 19:58:28 +090084 private static final OFSwitchCapabilities DEFAULT_CAPABILITIES =
85 DefaultOFSwitchCapabilities.builder()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090086 .flowStats()
87 .tableStats()
88 .portStats()
89 .groupStats()
90 .queueStats()
91 .ipReasm()
92 .portBlocked()
93 .build();
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected CoreService coreService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected LeadershipService leadershipService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected ClusterService clusterService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected VirtualNetworkService virtualNetService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected OFAgentService ofAgentService;
109
110 private final ConcurrentHashMap<DeviceId, OFSwitch> ofSwitchMap = new ConcurrentHashMap<>();
111 private final ExecutorService eventExecutor = newSingleThreadExecutor(
112 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
113 private final OFAgentListener ofAgentListener = new InternalOFAgentListener();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900114 private final VirtualNetworkListener vNetworkListener = new InternalVirtualNetworkListener();
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900115 private final DeviceListener deviceListener = new InternalDeviceListener();
116 private final FlowRuleListener flowRuleListener = new InternalFlowRuleListener();
117 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
118
119 private NioEventLoopGroup ioWorker;
120 private ApplicationId appId;
121 private NodeId localId;
122
123 @Activate
124 protected void activate() {
125 appId = coreService.registerApplication(APPLICATION_NAME);
126 localId = clusterService.getLocalNode().id();
127 ioWorker = new NioEventLoopGroup();
Hyunsun Moon53381e82017-03-28 19:58:28 +0900128
129 ofAgentService.agents().forEach(this::processOFAgentCreated);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900130 ofAgentService.addListener(ofAgentListener);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900131 virtualNetService.addListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900132
133 log.info("Started");
134 }
135
136 @Deactivate
137 protected void deactivate() {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900138 virtualNetService.removeListener(vNetworkListener);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900139 ofAgentService.removeListener(ofAgentListener);
140 ofAgentService.agents().forEach(this::processOFAgentStopped);
141
142 ioWorker.shutdownGracefully();
143 eventExecutor.shutdown();
144
145 log.info("Stopped");
146 }
147
148 @Override
149 public Set<OFSwitch> ofSwitches() {
150 return ImmutableSet.copyOf(ofSwitchMap.values());
151 }
152
153 @Override
154 public Set<OFSwitch> ofSwitches(NetworkId networkId) {
155 Set<OFSwitch> ofSwitches = devices(networkId).stream()
156 .map(ofSwitchMap::get)
157 .filter(Objects::nonNull)
158 .collect(Collectors.toSet());
159 return ImmutableSet.copyOf(ofSwitches);
160 }
161
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400162 @Override
163 public Set<Port> ports(NetworkId networkId, DeviceId deviceId) {
164 Set<Port> ports = virtualNetService.getVirtualPorts(networkId, deviceId)
165 .stream()
166 .collect(Collectors.toSet());
167 return ImmutableSet.copyOf(ports);
168 }
169
Hyunsun Moon53381e82017-03-28 19:58:28 +0900170 private void addOFSwitch(NetworkId networkId, DeviceId deviceId) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900171 OFSwitch ofSwitch = DefaultOFSwitch.of(
172 dpidWithDeviceId(deviceId),
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400173 DEFAULT_CAPABILITIES, networkId, deviceId,
174 virtualNetService.getServiceDirectory());
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900175 ofSwitchMap.put(deviceId, ofSwitch);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900176 log.info("Added virtual OF switch for {}", deviceId);
177
178 OFAgent ofAgent = ofAgentService.agent(networkId);
Eric Tangdf833c82017-06-04 22:55:49 +0800179 if (ofAgent == null) {
180 log.error("OFAgent for network {} does not exist", networkId);
181 return;
182 }
183
Hyunsun Moon53381e82017-03-28 19:58:28 +0900184 if (ofAgent.state() == STARTED) {
185 connectController(ofSwitch, ofAgent.controllers());
186 }
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900187 }
188
189 private void deleteOFSwitch(DeviceId deviceId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900190 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
191 ofSwitch.controllerChannels().forEach(ChannelOutboundInvoker::disconnect);
192
193 ofSwitchMap.remove(deviceId);
194 log.info("Removed virtual OFSwitch for {}", deviceId);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900195 }
196
197 private void connectController(OFSwitch ofSwitch, Set<OFController> controllers) {
198 controllers.forEach(controller -> {
199 OFConnectionHandler connectionHandler = new OFConnectionHandler(
200 ofSwitch,
201 controller,
202 ioWorker);
203 connectionHandler.connect();
204 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900205 }
206
207 private void disconnectController(OFSwitch ofSwitch, Set<OFController> controllers) {
208 Set<SocketAddress> controllerAddrs = controllers.stream()
Hyunsun Moon53381e82017-03-28 19:58:28 +0900209 .map(ctrl -> new InetSocketAddress(
210 ctrl.ip().toInetAddress(), ctrl.port().toInt()))
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900211 .collect(Collectors.toSet());
212
213 ofSwitch.controllerChannels().stream()
214 .filter(channel -> controllerAddrs.contains(channel.remoteAddress()))
215 .forEach(ChannelOutboundInvoker::disconnect);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900216 }
217
218 private Set<DeviceId> devices(NetworkId networkId) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900219 Set<DeviceId> deviceIds = virtualNetService.getVirtualDevices(networkId)
220 .stream()
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900221 .map(Device::id)
222 .collect(Collectors.toSet());
223 return ImmutableSet.copyOf(deviceIds);
224 }
225
226 private DatapathId dpidWithDeviceId(DeviceId deviceId) {
227 String strDeviceId = deviceId.toString().split(":")[1];
228 checkArgument(strDeviceId.length() == 16, "Invalid device ID " + strDeviceId);
229
230 String resultedHexString = "";
231 for (int i = 0; i < 8; i++) {
232 resultedHexString = resultedHexString + strDeviceId.charAt(2 * i)
233 + strDeviceId.charAt(2 * i + 1);
234 if (i != 7) {
235 resultedHexString += ":";
236 }
237 }
238 return DatapathId.of(resultedHexString);
239 }
240
241 private void processOFAgentCreated(OFAgent ofAgent) {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900242 devices(ofAgent.networkId()).forEach(deviceId -> {
243 addOFSwitch(ofAgent.networkId(), deviceId);
244 });
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900245 }
246
247 private void processOFAgentRemoved(OFAgent ofAgent) {
248 devices(ofAgent.networkId()).forEach(this::deleteOFSwitch);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900249 }
250
251 private void processOFAgentStarted(OFAgent ofAgent) {
252 devices(ofAgent.networkId()).forEach(deviceId -> {
253 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
254 if (ofSwitch != null) {
255 connectController(ofSwitch, ofAgent.controllers());
256 }
257 });
258
Hyunsun Moon53381e82017-03-28 19:58:28 +0900259 DeviceService deviceService = virtualNetService.get(
260 ofAgent.networkId(),
261 DeviceService.class);
262 deviceService.addListener(deviceListener);
263
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900264 PacketService packetService = virtualNetService.get(
265 ofAgent.networkId(),
266 PacketService.class);
267 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
268
269 FlowRuleService flowRuleService = virtualNetService.get(
270 ofAgent.networkId(),
271 FlowRuleService.class);
272 flowRuleService.addListener(flowRuleListener);
273 }
274
275 private void processOFAgentStopped(OFAgent ofAgent) {
276 devices(ofAgent.networkId()).forEach(deviceId -> {
277 OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
278 if (ofSwitch != null) {
279 disconnectController(ofSwitch, ofAgent.controllers());
280 }
281 });
282
Hyunsun Moon53381e82017-03-28 19:58:28 +0900283 DeviceService deviceService = virtualNetService.get(
284 ofAgent.networkId(),
285 DeviceService.class);
286 deviceService.removeListener(deviceListener);
287
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900288 PacketService packetService = virtualNetService.get(
289 ofAgent.networkId(),
290 PacketService.class);
291 packetService.removeProcessor(packetProcessor);
292
293 FlowRuleService flowRuleService = virtualNetService.get(
294 ofAgent.networkId(),
295 FlowRuleService.class);
296 flowRuleService.removeListener(flowRuleListener);
297 }
298
Hyunsun Moon53381e82017-03-28 19:58:28 +0900299 private class InternalVirtualNetworkListener implements VirtualNetworkListener {
300
301 @Override
302 public void event(VirtualNetworkEvent event) {
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400303 log.trace("Vnet event {}", event);
Hyunsun Moon53381e82017-03-28 19:58:28 +0900304 switch (event.type()) {
305 case VIRTUAL_DEVICE_ADDED:
306 eventExecutor.execute(() -> {
307 log.debug("Virtual device {} added to network {}",
308 event.virtualDevice().id(),
309 event.subject());
310 addOFSwitch(event.subject(), event.virtualDevice().id());
311 });
312 break;
313 case VIRTUAL_DEVICE_UPDATED:
314 // TODO handle device availability updates
315 break;
316 case VIRTUAL_DEVICE_REMOVED:
317 eventExecutor.execute(() -> {
318 log.debug("Virtual device {} removed from network {}",
319 event.virtualDevice().id(),
320 event.subject());
321 deleteOFSwitch(event.virtualDevice().id());
322 });
323 break;
324 case NETWORK_UPDATED:
325 case NETWORK_REMOVED:
326 case NETWORK_ADDED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400327 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900328 case VIRTUAL_PORT_ADDED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400329 eventExecutor.execute(() -> {
330 OFSwitch ofSwitch = ofSwitch(event.virtualPort());
331 if (ofSwitch != null) {
332 ofSwitch.processPortAdded(event.virtualPort());
333 log.debug("Virtual port {} added to network {}",
334 event.virtualPort(),
335 event.subject());
336 }
337 });
338 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900339 case VIRTUAL_PORT_UPDATED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400340 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900341 case VIRTUAL_PORT_REMOVED:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400342 eventExecutor.execute(() -> {
343 OFSwitch ofSwitch = ofSwitch(event.virtualPort());
344 if (ofSwitch != null) {
345 ofSwitch.processPortRemoved(event.virtualPort());
346 log.debug("Virtual port {} removed from network {}",
347 event.virtualPort(),
348 event.subject());
349 }
350 });
351 break;
Hyunsun Moon53381e82017-03-28 19:58:28 +0900352 default:
353 // do nothing
354 break;
355 }
356 }
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400357
358 private OFSwitch ofSwitch(VirtualPort virtualPort) {
359 OFSwitch ofSwitch = ofSwitchMap.get(virtualPort.element().id());
360 if (ofSwitch == null) {
361 log.warn("Switch does not exist for port {}", virtualPort);
362 } else {
363 log.trace("Switch exists for port {}", virtualPort);
364 }
365 return ofSwitch;
366 }
Hyunsun Moon53381e82017-03-28 19:58:28 +0900367 }
368
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900369 private class InternalOFAgentListener implements OFAgentListener {
370
371 @Override
372 public boolean isRelevant(OFAgentEvent event) {
373 return Objects.equals(localId, leadershipService.getLeader(appId.name()));
374 }
375
376 @Override
377 public void event(OFAgentEvent event) {
378 switch (event.type()) {
379 case OFAGENT_CREATED:
380 eventExecutor.execute(() -> {
381 OFAgent ofAgent = event.subject();
382 log.debug("Processing OFAgent created: {}", ofAgent);
383 processOFAgentCreated(ofAgent);
384 });
385 break;
386 case OFAGENT_REMOVED:
387 eventExecutor.execute(() -> {
388 OFAgent ofAgent = event.subject();
389 log.debug("Processing OFAgent removed: {}", ofAgent);
390 processOFAgentRemoved(ofAgent);
391 });
392 break;
393 case OFAGENT_CONTROLLER_ADDED:
394 // TODO handle additional controller
395 break;
396 case OFAGENT_CONTROLLER_REMOVED:
397 // TODO handle removed controller
398 break;
399 case OFAGENT_STARTED:
400 eventExecutor.execute(() -> {
401 OFAgent ofAgent = event.subject();
402 log.debug("Processing OFAgent started: {}", ofAgent);
403 processOFAgentStarted(ofAgent);
404 });
405 break;
406 case OFAGENT_STOPPED:
407 eventExecutor.execute(() -> {
408 OFAgent ofAgent = event.subject();
409 log.debug("Processing OFAgent stopped: {}", ofAgent);
410 processOFAgentStopped(ofAgent);
411 });
412 break;
413 default:
414 // do nothing
415 break;
416 }
417 }
418 }
419
420 private class InternalDeviceListener implements DeviceListener {
421
422 @Override
423 public void event(DeviceEvent event) {
424 switch (event.type()) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900425 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900426 case DEVICE_ADDED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900427 case DEVICE_UPDATED:
Hyunsun Moon53381e82017-03-28 19:58:28 +0900428 case DEVICE_REMOVED:
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900429 case DEVICE_SUSPENDED:
430 case PORT_ADDED:
431 // TODO handle event
432 case PORT_REMOVED:
433 // TODO handle event
434 case PORT_STATS_UPDATED:
435 case PORT_UPDATED:
436 default:
437 break;
438 }
439 }
440 }
441
442 private class InternalPacketProcessor implements PacketProcessor {
443
444 @Override
445 public void process(PacketContext context) {
446 // TODO handle packet-in
447 }
448 }
449
450 private class InternalFlowRuleListener implements FlowRuleListener {
451
452 @Override
453 public void event(FlowRuleEvent event) {
454 // TODO handle flow rule event
455 }
456 }
457}