blob: 072254de2f6aecb5e036e5bd8c5850dfd368d930 [file] [log] [blame]
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001/*
2 * Copyright 2014-2015 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.cordvtn;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
24import org.onlab.packet.IpAddress;
25import org.onlab.packet.TpPort;
26import org.onlab.util.KryoNamespace;
27import org.onosproject.cluster.ClusterService;
28import org.onosproject.cluster.LeadershipEvent;
29import org.onosproject.cluster.LeadershipEventListener;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.mastership.MastershipService;
35import org.onosproject.net.Device;
36import org.onosproject.net.DeviceId;
37import org.onosproject.net.Host;
38import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigRegistry;
40import org.onosproject.net.config.NetworkConfigService;
41import org.onosproject.net.config.basics.SubjectFactories;
42import org.onosproject.net.device.DeviceEvent;
43import org.onosproject.net.device.DeviceListener;
44import org.onosproject.net.device.DeviceService;
45import org.onosproject.net.host.HostEvent;
46import org.onosproject.net.host.HostListener;
47import org.onosproject.net.host.HostService;
48import org.onosproject.store.serializers.KryoNamespaces;
49import org.onosproject.store.service.EventuallyConsistentMap;
50import org.onosproject.store.service.LogicalClockService;
51import org.onosproject.store.service.StorageService;
52import org.slf4j.Logger;
53
54import java.util.List;
55import java.util.concurrent.ExecutorService;
56import java.util.concurrent.Executors;
57import java.util.stream.Collectors;
58
59import static org.onlab.util.Tools.groupedThreads;
60import static org.onosproject.cordvtn.OvsdbNode.State.INIT;
61import static org.slf4j.LoggerFactory.getLogger;
62
63/**
64 * CORD VTN Application that provisions overlay virtual tenant networks.
65 */
66@Component(immediate = true)
67@Service
68public class CordVtn implements CordVtnService {
69
70 protected final Logger log = getLogger(getClass());
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected CoreService coreService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected StorageService storageService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected LogicalClockService clockService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected ClusterService clusterService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected LeadershipService leadershipService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected NetworkConfigService configService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected NetworkConfigRegistry configRegistry;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DeviceService deviceService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected HostService hostService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected MastershipService mastershipService;
101
102 private static final int DEFAULT_NUM_THREADS = 1;
103 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
104 .register(KryoNamespaces.API)
105 .register(OvsdbNode.class);
106
107 private final ExecutorService eventExecutor = Executors.newFixedThreadPool(
108 DEFAULT_NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
109
110 private final LeadershipEventListener leadershipListener = new InternalLeadershipListener();
111 private final DeviceListener deviceListener = new InternalDeviceListener();
112 private final HostListener hostListener = new InternalHostListener();
113 private final NodeHandler nodeHandler = new NodeHandler();
114 private final BridgeHandler bridgeHandler = new BridgeHandler();
115 private final VirtualMachineHandler vmHandler = new VirtualMachineHandler();
116
117 private final ConfigFactory configFactory =
118 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
119 @Override
120 public CordVtnConfig createConfig() {
121 return new CordVtnConfig();
122 }
123 };
124
125 private ApplicationId appId;
126 private NodeId local;
127 private EventuallyConsistentMap<DeviceId, OvsdbNode> nodeStore;
128 private NodeConnectionManager nodeConnectionManager;
129
130 @Activate
131 protected void activate() {
132 appId = coreService.registerApplication("org.onosproject.cordvtn");
133
134 local = clusterService.getLocalNode().id();
135 nodeStore = storageService.<DeviceId, OvsdbNode>eventuallyConsistentMapBuilder()
136 .withName("cordvtn-nodestore")
137 .withSerializer(NODE_SERIALIZER)
138 .withTimestampProvider((k, v) -> clockService.getTimestamp())
139 .build();
140 configRegistry.registerConfigFactory(configFactory);
141
142 deviceService.addListener(deviceListener);
143 hostService.addListener(hostListener);
144 leadershipService.addListener(leadershipListener);
145 leadershipService.runForLeadership(appId.name());
146 nodeConnectionManager = new NodeConnectionManager(appId, local, nodeStore,
147 mastershipService, leadershipService);
148 nodeConnectionManager.start();
149 log.info("Started");
150 }
151
152 @Deactivate
153 protected void deactivate() {
154 nodeConnectionManager.stop();
155 leadershipService.removeListener(leadershipListener);
156 leadershipService.withdraw(appId.name());
157 deviceService.removeListener(deviceListener);
158 hostService.removeListener(hostListener);
159 eventExecutor.shutdown();
160 nodeStore.destroy();
161 configRegistry.unregisterConfigFactory(configFactory);
162 log.info("Stopped");
163 }
164
165 @Override
166 public void addNode(String hostname, IpAddress ip, TpPort port) {
167 DefaultOvsdbNode node = new DefaultOvsdbNode(hostname, ip, port, DeviceId.NONE, INIT);
168
169 if (nodeStore.containsKey(node.deviceId())) {
170 log.warn("Node {} with ovsdb-server {}:{} already exists", hostname, ip, port);
171 return;
172 }
173 nodeStore.put(node.deviceId(), node);
174 log.info("New node {} with ovsdb-server {}:{} has been added", hostname, ip, port);
175 }
176
177 @Override
178 public void deleteNode(IpAddress ip, TpPort port) {
179 DeviceId deviceId = DeviceId.deviceId("ovsdb:" + ip + ":" + port);
180 OvsdbNode node = nodeStore.get(deviceId);
181
182 if (node == null) {
183 log.warn("Node with ovsdb-server on {}:{} does not exist", ip, port);
184 return;
185 }
186 nodeConnectionManager.disconnectNode(node);
187 nodeStore.remove(node.deviceId());
188 }
189
190 @Override
191 public int getNodeCount() {
192 return nodeStore.size();
193 }
194
195 @Override
196 public List<OvsdbNode> getNodes() {
197 return nodeStore.values()
198 .stream()
199 .collect(Collectors.toList());
200 }
201
202 private void initialSetup() {
203 // Read ovsdb nodes from network config
204 CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class);
205 if (config == null) {
206 log.warn("No configuration found");
207 return;
208 }
209 config.ovsdbNodes().forEach(
210 node -> addNode(node.hostname(), node.ip(), node.port()));
211 }
212
213 private synchronized void processLeadershipChange(NodeId leader) {
214 // Only the leader performs the initial setup
215 if (leader == null || !leader.equals(local)) {
216 return;
217 }
218 initialSetup();
219 }
220
221 private class InternalLeadershipListener implements LeadershipEventListener {
222
223 @Override
224 public void event(LeadershipEvent event) {
225 if (event.subject().topic().equals(appId.name())) {
226 processLeadershipChange(event.subject().leader());
227 }
228 }
229 }
230
231 private class InternalDeviceListener implements DeviceListener {
232
233 @Override
234 public void event(DeviceEvent event) {
235 Device device = event.subject();
236 ConnectionHandler handler =
237 (device.type() == Device.Type.CONTROLLER ? nodeHandler : bridgeHandler);
238
239 switch (event.type()) {
240 case DEVICE_ADDED:
241 eventExecutor.submit(() -> handler.connected(device));
242 break;
243 case DEVICE_AVAILABILITY_CHANGED:
244 eventExecutor.submit(() -> handler.disconnected(device));
245 break;
246 default:
247 break;
248 }
249 }
250 }
251
252 private class InternalHostListener implements HostListener {
253
254 @Override
255 public void event(HostEvent event) {
256 Host vm = event.subject();
257
258 switch (event.type()) {
259 case HOST_ADDED:
260 eventExecutor.submit(() -> vmHandler.connected(vm));
261 break;
262 case HOST_REMOVED:
263 eventExecutor.submit(() -> vmHandler.disconnected(vm));
264 break;
265 default:
266 break;
267 }
268 }
269 }
270
271 private class NodeHandler implements ConnectionHandler<Device> {
272
273 @Override
274 public void connected(Device device) {
275 // create bridge and set bridgeId
276 // set node state connected
277 }
278
279 @Override
280 public void disconnected(Device device) {
281 // set node state disconnected if the node exists
282 // which means that the node is not deleted explicitly
283 }
284 }
285
286 private class BridgeHandler implements ConnectionHandler<Device> {
287
288 @Override
289 public void connected(Device device) {
290 // create vxlan port
291 }
292
293 @Override
294 public void disconnected(Device device) {
295
296 }
297 }
298
299 private class VirtualMachineHandler implements ConnectionHandler<Host> {
300
301 @Override
302 public void connected(Host host) {
303 // install flow rules for this vm
304 }
305
306 @Override
307 public void disconnected(Host host) {
308 // uninstall flow rules associated with this vm
309 }
310 }
311}