Hyunsun Moon
Committed by Gerrit Code Review

CORD-280 Enhanced initial node setup process considering various scenarios

- Handled situations where ovsdb, integration bridge, or vxlan port are
already connected or exists when the application activated
- Don't make use of mastership for ovsdb device, it does not work well in
device disconnected or re-connected situations

Change-Id: I002948f4a06126430f6019c79a0d84df16c9399c
...@@ -27,7 +27,6 @@ import org.onlab.util.KryoNamespace; ...@@ -27,7 +27,6 @@ import org.onlab.util.KryoNamespace;
27 import org.onosproject.cluster.ClusterService; 27 import org.onosproject.cluster.ClusterService;
28 import org.onosproject.core.ApplicationId; 28 import org.onosproject.core.ApplicationId;
29 import org.onosproject.core.CoreService; 29 import org.onosproject.core.CoreService;
30 -import org.onosproject.mastership.MastershipService;
31 import org.onosproject.net.Device; 30 import org.onosproject.net.Device;
32 import org.onosproject.net.DeviceId; 31 import org.onosproject.net.DeviceId;
33 import org.onosproject.net.Host; 32 import org.onosproject.net.Host;
...@@ -52,6 +51,7 @@ import java.util.ArrayList; ...@@ -52,6 +51,7 @@ import java.util.ArrayList;
52 import java.util.HashMap; 51 import java.util.HashMap;
53 import java.util.List; 52 import java.util.List;
54 import java.util.Map; 53 import java.util.Map;
54 +import java.util.NoSuchElementException;
55 import java.util.concurrent.ExecutorService; 55 import java.util.concurrent.ExecutorService;
56 import java.util.concurrent.Executors; 56 import java.util.concurrent.Executors;
57 57
...@@ -75,7 +75,8 @@ public class CordVtn implements CordVtnService { ...@@ -75,7 +75,8 @@ public class CordVtn implements CordVtnService {
75 .register(KryoNamespaces.API) 75 .register(KryoNamespaces.API)
76 .register(DefaultOvsdbNode.class); 76 .register(DefaultOvsdbNode.class);
77 private static final String DEFAULT_BRIDGE_NAME = "br-int"; 77 private static final String DEFAULT_BRIDGE_NAME = "br-int";
78 - private static final Map<String, String> VXLAN_OPTIONS = new HashMap<String, String>() { 78 + private static final String DEFAULT_TUNNEL = "vxlan";
79 + private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
79 { 80 {
80 put("key", "flow"); 81 put("key", "flow");
81 put("local_ip", "flow"); 82 put("local_ip", "flow");
...@@ -98,9 +99,6 @@ public class CordVtn implements CordVtnService { ...@@ -98,9 +99,6 @@ public class CordVtn implements CordVtnService {
98 protected HostService hostService; 99 protected HostService hostService;
99 100
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 - protected MastershipService mastershipService;
102 -
103 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected OvsdbController controller; 102 protected OvsdbController controller;
105 103
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -117,11 +115,10 @@ public class CordVtn implements CordVtnService { ...@@ -117,11 +115,10 @@ public class CordVtn implements CordVtnService {
117 private final VmHandler vmHandler = new VmHandler(); 115 private final VmHandler vmHandler = new VmHandler();
118 116
119 private ConsistentMap<DeviceId, OvsdbNode> nodeStore; 117 private ConsistentMap<DeviceId, OvsdbNode> nodeStore;
120 - private ApplicationId appId;
121 118
122 @Activate 119 @Activate
123 protected void activate() { 120 protected void activate() {
124 - appId = coreService.registerApplication("org.onosproject.cordvtn"); 121 + ApplicationId appId = coreService.registerApplication("org.onosproject.cordvtn");
125 nodeStore = storageService.<DeviceId, OvsdbNode>consistentMapBuilder() 122 nodeStore = storageService.<DeviceId, OvsdbNode>consistentMapBuilder()
126 .withSerializer(Serializer.using(NODE_SERIALIZER.build())) 123 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
127 .withName("cordvtn-nodestore") 124 .withName("cordvtn-nodestore")
...@@ -148,9 +145,18 @@ public class CordVtn implements CordVtnService { ...@@ -148,9 +145,18 @@ public class CordVtn implements CordVtnService {
148 @Override 145 @Override
149 public void addNode(OvsdbNode ovsdb) { 146 public void addNode(OvsdbNode ovsdb) {
150 checkNotNull(ovsdb); 147 checkNotNull(ovsdb);
148 +
149 + if (!nodeStore.containsKey(ovsdb.deviceId())) {
151 nodeStore.put(ovsdb.deviceId(), ovsdb); 150 nodeStore.put(ovsdb.deviceId(), ovsdb);
152 } 151 }
153 152
153 + if (isNodeConnected(ovsdb)) {
154 + init(ovsdb);
155 + } else {
156 + connect(ovsdb);
157 + }
158 + }
159 +
154 @Override 160 @Override
155 public void deleteNode(OvsdbNode ovsdb) { 161 public void deleteNode(OvsdbNode ovsdb) {
156 checkNotNull(ovsdb); 162 checkNotNull(ovsdb);
...@@ -159,13 +165,14 @@ public class CordVtn implements CordVtnService { ...@@ -159,13 +165,14 @@ public class CordVtn implements CordVtnService {
159 return; 165 return;
160 } 166 }
161 167
162 - // check ovsdb and integration bridge connection state first 168 + if (deviceService.getDevice(ovsdb.deviceId()) != null) {
163 - if (isNodeConnected(ovsdb)) { 169 + if (deviceService.isAvailable(ovsdb.deviceId())) {
164 log.warn("Cannot delete connected node {}", ovsdb.host()); 170 log.warn("Cannot delete connected node {}", ovsdb.host());
165 - } else { 171 + return;
166 - nodeStore.remove(ovsdb.deviceId());
167 } 172 }
168 } 173 }
174 + nodeStore.remove(ovsdb.deviceId());
175 + }
169 176
170 @Override 177 @Override
171 public void connect(OvsdbNode ovsdb) { 178 public void connect(OvsdbNode ovsdb) {
...@@ -175,8 +182,11 @@ public class CordVtn implements CordVtnService { ...@@ -175,8 +182,11 @@ public class CordVtn implements CordVtnService {
175 log.warn("Node {} does not exist", ovsdb.host()); 182 log.warn("Node {} does not exist", ovsdb.host());
176 return; 183 return;
177 } 184 }
185 +
186 + if (!isNodeConnected(ovsdb)) {
178 controller.connect(ovsdb.ip(), ovsdb.port()); 187 controller.connect(ovsdb.ip(), ovsdb.port());
179 } 188 }
189 + }
180 190
181 @Override 191 @Override
182 public void disconnect(OvsdbNode ovsdb) { 192 public void disconnect(OvsdbNode ovsdb) {
...@@ -187,14 +197,33 @@ public class CordVtn implements CordVtnService { ...@@ -187,14 +197,33 @@ public class CordVtn implements CordVtnService {
187 return; 197 return;
188 } 198 }
189 199
200 + if (isNodeConnected(ovsdb)) {
190 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); 201 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
191 - checkNotNull(ovsdbClient);
192 -
193 - if (ovsdbClient.isConnected()) {
194 ovsdbClient.disconnect(); 202 ovsdbClient.disconnect();
195 } 203 }
196 } 204 }
197 205
206 + private void init(OvsdbNode ovsdb) {
207 + checkNotNull(ovsdb);
208 +
209 + if (!nodeStore.containsKey(ovsdb.deviceId())) {
210 + log.warn("Node {} does not exist", ovsdb.host());
211 + return;
212 + }
213 +
214 + if (!isNodeConnected(ovsdb)) {
215 + log.warn("Node {} is not connected", ovsdb.host());
216 + return;
217 + }
218 +
219 + if (deviceService.getDevice(ovsdb.intBrId()) == null ||
220 + !deviceService.isAvailable(ovsdb.intBrId())) {
221 + createIntegrationBridge(ovsdb);
222 + } else if (!checkVxlanPort(ovsdb)) {
223 + createVxlanPort(ovsdb);
224 + }
225 + }
226 +
198 @Override 227 @Override
199 public int getNodeCount() { 228 public int getNodeCount() {
200 return nodeStore.size(); 229 return nodeStore.size();
...@@ -235,11 +264,45 @@ public class CordVtn implements CordVtnService { ...@@ -235,11 +264,45 @@ public class CordVtn implements CordVtnService {
235 OvsdbClientService ovsdbClient = controller.getOvsdbClient( 264 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
236 new OvsdbNodeId(ovsdb.ip(), ovsdb.port().toInt())); 265 new OvsdbNodeId(ovsdb.ip(), ovsdb.port().toInt()));
237 if (ovsdbClient == null) { 266 if (ovsdbClient == null) {
238 - log.warn("Couldn't find ovsdb client of node {}", ovsdb.host()); 267 + log.debug("Couldn't find ovsdb client for {}", ovsdb.host());
239 } 268 }
240 return ovsdbClient; 269 return ovsdbClient;
241 } 270 }
242 271
272 + private void createIntegrationBridge(OvsdbNode ovsdb) {
273 + List<ControllerInfo> controllers = new ArrayList<>();
274 + Sets.newHashSet(clusterService.getNodes())
275 + .forEach(controller -> {
276 + ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
277 + controllers.add(ctrlInfo);
278 + });
279 + String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN);
280 +
281 + // TODO change to use bridge config
282 + OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
283 + ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers);
284 + }
285 +
286 + private void createVxlanPort(OvsdbNode ovsdb) {
287 + // TODO change to use tunnel config and tunnel description
288 + OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
289 + ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, DEFAULT_TUNNEL,
290 + DEFAULT_TUNNEL, DEFAULT_TUNNEL_OPTIONS);
291 + }
292 +
293 + private boolean checkVxlanPort(OvsdbNode ovsdb) {
294 + // TODO change to use tunnel config
295 + OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
296 + try {
297 + ovsdbClient.getPorts().stream()
298 + .filter(p -> p.portName().value().equals(DEFAULT_TUNNEL))
299 + .findFirst().get();
300 + } catch (NoSuchElementException e) {
301 + return false;
302 + }
303 + return true;
304 + }
305 +
243 private class InternalDeviceListener implements DeviceListener { 306 private class InternalDeviceListener implements DeviceListener {
244 307
245 @Override 308 @Override
...@@ -252,8 +315,11 @@ public class CordVtn implements CordVtnService { ...@@ -252,8 +315,11 @@ public class CordVtn implements CordVtnService {
252 eventExecutor.submit(() -> handler.connected(device)); 315 eventExecutor.submit(() -> handler.connected(device));
253 break; 316 break;
254 case DEVICE_AVAILABILITY_CHANGED: 317 case DEVICE_AVAILABILITY_CHANGED:
318 + if (deviceService.isAvailable(device.id())) {
319 + eventExecutor.submit(() -> handler.connected(device));
320 + } else {
255 eventExecutor.submit(() -> handler.disconnected(device)); 321 eventExecutor.submit(() -> handler.disconnected(device));
256 - // TODO handle the case that the device is recovered 322 + }
257 break; 323 break;
258 default: 324 default:
259 break; 325 break;
...@@ -286,20 +352,10 @@ public class CordVtn implements CordVtnService { ...@@ -286,20 +352,10 @@ public class CordVtn implements CordVtnService {
286 public void connected(Device device) { 352 public void connected(Device device) {
287 log.info("Ovsdb {} is connected", device.id()); 353 log.info("Ovsdb {} is connected", device.id());
288 354
289 - if (!mastershipService.isLocalMaster(device.id())) {
290 - return;
291 - }
292 -
293 - // TODO change to use bridge config
294 OvsdbNode ovsdb = getNode(device.id()); 355 OvsdbNode ovsdb = getNode(device.id());
295 - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb); 356 + if (ovsdb != null) {
296 - 357 + init(ovsdb);
297 - List<ControllerInfo> controllers = new ArrayList<>(); 358 + }
298 - Sets.newHashSet(clusterService.getNodes()).forEach(controller ->
299 - controllers.add(new ControllerInfo(controller.ip(), OFPORT, "tcp")));
300 - String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN);
301 -
302 - ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers);
303 } 359 }
304 360
305 @Override 361 @Override
...@@ -314,22 +370,19 @@ public class CordVtn implements CordVtnService { ...@@ -314,22 +370,19 @@ public class CordVtn implements CordVtnService {
314 public void connected(Device device) { 370 public void connected(Device device) {
315 log.info("Integration Bridge {} is detected", device.id()); 371 log.info("Integration Bridge {} is detected", device.id());
316 372
317 - OvsdbNode ovsdb = getNodes().stream() 373 + OvsdbNode ovsdb;
374 + try {
375 + ovsdb = getNodes().stream()
318 .filter(node -> node.intBrId().equals(device.id())) 376 .filter(node -> node.intBrId().equals(device.id()))
319 .findFirst().get(); 377 .findFirst().get();
320 - 378 + } catch (NoSuchElementException e) {
321 - if (ovsdb == null) {
322 log.warn("Couldn't find OVSDB associated with {}", device.id()); 379 log.warn("Couldn't find OVSDB associated with {}", device.id());
323 return; 380 return;
324 } 381 }
325 382
326 - if (!mastershipService.isLocalMaster(ovsdb.deviceId())) { 383 + if (!checkVxlanPort(ovsdb)) {
327 - return; 384 + createVxlanPort(ovsdb);
328 } 385 }
329 -
330 - // TODO change to use tunnel config and tunnel description
331 - OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
332 - ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, "vxlan", "vxlan", VXLAN_OPTIONS);
333 } 386 }
334 387
335 @Override 388 @Override
......
...@@ -94,7 +94,6 @@ public class CordVtnConfigManager { ...@@ -94,7 +94,6 @@ public class CordVtnConfigManager {
94 DefaultOvsdbNode ovsdb = new DefaultOvsdbNode( 94 DefaultOvsdbNode ovsdb = new DefaultOvsdbNode(
95 node.host(), node.ip(), node.port(), node.bridgeId()); 95 node.host(), node.ip(), node.port(), node.bridgeId());
96 cordVtnService.addNode(ovsdb); 96 cordVtnService.addNode(ovsdb);
97 - cordVtnService.connect(ovsdb);
98 }); 97 });
99 } 98 }
100 99
......