Hyunsun Moon
Committed by Gerrit Code Review

CORD-562 Don't allow nodes with duplicate hostname

And update existing node if newly added node has the same hostname with
existing node.

Change-Id: Ifebbf4129df4f742e16b9a25be619dd90e0745ff
...@@ -60,7 +60,7 @@ public class CordVtnConfig extends Config<ApplicationId> { ...@@ -60,7 +60,7 @@ public class CordVtnConfig extends Config<ApplicationId> {
60 /** 60 /**
61 * Returns the set of nodes read from network config. 61 * Returns the set of nodes read from network config.
62 * 62 *
63 - * @return set of CordVtnNodeConfig or null 63 + * @return set of CordVtnNodeConfig or empty set
64 */ 64 */
65 public Set<CordVtnNode> cordVtnNodes() { 65 public Set<CordVtnNode> cordVtnNodes() {
66 66
...@@ -68,7 +68,7 @@ public class CordVtnConfig extends Config<ApplicationId> { ...@@ -68,7 +68,7 @@ public class CordVtnConfig extends Config<ApplicationId> {
68 JsonNode jsonNodes = object.get(CORDVTN_NODES); 68 JsonNode jsonNodes = object.get(CORDVTN_NODES);
69 if (jsonNodes == null) { 69 if (jsonNodes == null) {
70 log.debug("No CORD VTN nodes found"); 70 log.debug("No CORD VTN nodes found");
71 - return null; 71 + return nodes;
72 } 72 }
73 73
74 for (JsonNode jsonNode : jsonNodes) { 74 for (JsonNode jsonNode : jsonNodes) {
...@@ -94,7 +94,8 @@ public class CordVtnConfig extends Config<ApplicationId> { ...@@ -94,7 +94,8 @@ public class CordVtnConfig extends Config<ApplicationId> {
94 TpPort.tpPort(Integer.parseInt(getConfig(object, OVSDB_PORT))), 94 TpPort.tpPort(Integer.parseInt(getConfig(object, OVSDB_PORT))),
95 sshInfo, 95 sshInfo,
96 DeviceId.deviceId(getConfig(jsonNode, BRIDGE_ID)), 96 DeviceId.deviceId(getConfig(jsonNode, BRIDGE_ID)),
97 - getConfig(jsonNode, DATA_PLANE_INTF)); 97 + getConfig(jsonNode, DATA_PLANE_INTF),
98 + CordVtnNodeState.noState());
98 99
99 log.info("Successfully read {} from the config", hostname); 100 log.info("Successfully read {} from the config", hostname);
100 nodes.add(newNode); 101 nodes.add(newNode);
......
1 /* 1 /*
2 - * Copyright 2014-2015 Open Networking Laboratory 2 + * Copyright 2015-2016 Open Networking Laboratory
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
...@@ -37,6 +37,7 @@ public final class CordVtnNode { ...@@ -37,6 +37,7 @@ public final class CordVtnNode {
37 private final SshAccessInfo sshInfo; 37 private final SshAccessInfo sshInfo;
38 private final DeviceId bridgeId; 38 private final DeviceId bridgeId;
39 private final String dpIntf; 39 private final String dpIntf;
40 + private final CordVtnNodeState state;
40 41
41 public static final Comparator<CordVtnNode> CORDVTN_NODE_COMPARATOR = 42 public static final Comparator<CordVtnNode> CORDVTN_NODE_COMPARATOR =
42 (node1, node2) -> node1.hostname().compareTo(node2.hostname()); 43 (node1, node2) -> node1.hostname().compareTo(node2.hostname());
...@@ -52,10 +53,11 @@ public final class CordVtnNode { ...@@ -52,10 +53,11 @@ public final class CordVtnNode {
52 * @param sshInfo SSH access information 53 * @param sshInfo SSH access information
53 * @param bridgeId integration bridge identifier 54 * @param bridgeId integration bridge identifier
54 * @param dpIntf data plane interface name 55 * @param dpIntf data plane interface name
56 + * @param state cordvtn node state
55 */ 57 */
56 public CordVtnNode(String hostname, NetworkAddress hostMgmtIp, NetworkAddress localMgmtIp, 58 public CordVtnNode(String hostname, NetworkAddress hostMgmtIp, NetworkAddress localMgmtIp,
57 NetworkAddress dpIp, TpPort ovsdbPort, SshAccessInfo sshInfo, 59 NetworkAddress dpIp, TpPort ovsdbPort, SshAccessInfo sshInfo,
58 - DeviceId bridgeId, String dpIntf) { 60 + DeviceId bridgeId, String dpIntf, CordVtnNodeState state) {
59 this.hostname = checkNotNull(hostname, "hostname cannot be null"); 61 this.hostname = checkNotNull(hostname, "hostname cannot be null");
60 this.hostMgmtIp = checkNotNull(hostMgmtIp, "hostMgmtIp cannot be null"); 62 this.hostMgmtIp = checkNotNull(hostMgmtIp, "hostMgmtIp cannot be null");
61 this.localMgmtIp = checkNotNull(localMgmtIp, "localMgmtIp cannot be null"); 63 this.localMgmtIp = checkNotNull(localMgmtIp, "localMgmtIp cannot be null");
...@@ -64,6 +66,23 @@ public final class CordVtnNode { ...@@ -64,6 +66,23 @@ public final class CordVtnNode {
64 this.sshInfo = checkNotNull(sshInfo, "sshInfo cannot be null"); 66 this.sshInfo = checkNotNull(sshInfo, "sshInfo cannot be null");
65 this.bridgeId = checkNotNull(bridgeId, "bridgeId cannot be null"); 67 this.bridgeId = checkNotNull(bridgeId, "bridgeId cannot be null");
66 this.dpIntf = checkNotNull(dpIntf, "dpIntf cannot be null"); 68 this.dpIntf = checkNotNull(dpIntf, "dpIntf cannot be null");
69 + this.state = state;
70 + }
71 +
72 + /**
73 + * Returns cordvtn node with new state.
74 + *
75 + * @param node cordvtn node
76 + * @param state cordvtn node init state
77 + * @return cordvtn node
78 + */
79 + public static CordVtnNode getUpdatedNode(CordVtnNode node, CordVtnNodeState state) {
80 + return new CordVtnNode(node.hostname,
81 + node.hostMgmtIp, node.localMgmtIp, node.dpIp,
82 + node.ovsdbPort,
83 + node.sshInfo,
84 + node.bridgeId,
85 + node.dpIntf, state);
67 } 86 }
68 87
69 /** 88 /**
...@@ -147,6 +166,15 @@ public final class CordVtnNode { ...@@ -147,6 +166,15 @@ public final class CordVtnNode {
147 return this.dpIntf; 166 return this.dpIntf;
148 } 167 }
149 168
169 + /**
170 + * Returns the state of the node.
171 + *
172 + * @return state
173 + */
174 + public CordVtnNodeState state() {
175 + return this.state;
176 + }
177 +
150 @Override 178 @Override
151 public boolean equals(Object obj) { 179 public boolean equals(Object obj) {
152 if (this == obj) { 180 if (this == obj) {
...@@ -180,6 +208,7 @@ public final class CordVtnNode { ...@@ -180,6 +208,7 @@ public final class CordVtnNode {
180 .add("sshInfo", sshInfo) 208 .add("sshInfo", sshInfo)
181 .add("bridgeId", bridgeId) 209 .add("bridgeId", bridgeId)
182 .add("dpIntf", dpIntf) 210 .add("dpIntf", dpIntf)
211 + .add("state", state)
183 .toString(); 212 .toString();
184 } 213 }
185 } 214 }
......
...@@ -72,6 +72,7 @@ import java.util.List; ...@@ -72,6 +72,7 @@ import java.util.List;
72 import java.util.Map; 72 import java.util.Map;
73 import java.util.Set; 73 import java.util.Set;
74 import java.util.concurrent.ExecutorService; 74 import java.util.concurrent.ExecutorService;
75 +import java.util.stream.Collectors;
75 76
76 import static com.google.common.base.Preconditions.checkNotNull; 77 import static com.google.common.base.Preconditions.checkNotNull;
77 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; 78 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
...@@ -165,11 +166,11 @@ public class CordVtnNodeManager { ...@@ -165,11 +166,11 @@ public class CordVtnNodeManager {
165 private final OvsdbHandler ovsdbHandler = new OvsdbHandler(); 166 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
166 private final BridgeHandler bridgeHandler = new BridgeHandler(); 167 private final BridgeHandler bridgeHandler = new BridgeHandler();
167 168
168 - private ConsistentMap<CordVtnNode, NodeState> nodeStore; 169 + private ConsistentMap<String, CordVtnNode> nodeStore;
169 private CordVtnRuleInstaller ruleInstaller; 170 private CordVtnRuleInstaller ruleInstaller;
170 private ApplicationId appId; 171 private ApplicationId appId;
171 172
172 - private enum NodeState { 173 + private enum NodeState implements CordVtnNodeState {
173 174
174 INIT { 175 INIT {
175 @Override 176 @Override
...@@ -197,7 +198,6 @@ public class CordVtnNodeManager { ...@@ -197,7 +198,6 @@ public class CordVtnNodeManager {
197 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) { 198 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
198 nodeManager.setIpAddress(node); 199 nodeManager.setIpAddress(node);
199 } 200 }
200 -
201 }, 201 },
202 COMPLETE { 202 COMPLETE {
203 @Override 203 @Override
...@@ -217,7 +217,7 @@ public class CordVtnNodeManager { ...@@ -217,7 +217,7 @@ public class CordVtnNodeManager {
217 @Activate 217 @Activate
218 protected void active() { 218 protected void active() {
219 appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID); 219 appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID);
220 - nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder() 220 + nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
221 .withSerializer(Serializer.using(NODE_SERIALIZER.build())) 221 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
222 .withName("cordvtn-nodestore") 222 .withName("cordvtn-nodestore")
223 .withApplicationId(appId) 223 .withApplicationId(appId)
...@@ -252,7 +252,8 @@ public class CordVtnNodeManager { ...@@ -252,7 +252,8 @@ public class CordVtnNodeManager {
252 public void addNode(CordVtnNode node) { 252 public void addNode(CordVtnNode node) {
253 checkNotNull(node); 253 checkNotNull(node);
254 254
255 - nodeStore.putIfAbsent(node, getNodeState(node)); 255 + // allow update node attributes
256 + nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
256 initNode(node); 257 initNode(node);
257 } 258 }
258 259
...@@ -268,7 +269,7 @@ public class CordVtnNodeManager { ...@@ -268,7 +269,7 @@ public class CordVtnNodeManager {
268 disconnectOvsdb(node); 269 disconnectOvsdb(node);
269 } 270 }
270 271
271 - nodeStore.remove(node); 272 + nodeStore.remove(node.hostname());
272 } 273 }
273 274
274 /** 275 /**
...@@ -279,12 +280,13 @@ public class CordVtnNodeManager { ...@@ -279,12 +280,13 @@ public class CordVtnNodeManager {
279 public void initNode(CordVtnNode node) { 280 public void initNode(CordVtnNode node) {
280 checkNotNull(node); 281 checkNotNull(node);
281 282
282 - if (!nodeStore.containsKey(node)) { 283 + if (!nodeStore.containsKey(node.hostname())) {
283 log.warn("Node {} does not exist, add node first", node.hostname()); 284 log.warn("Node {} does not exist, add node first", node.hostname());
284 return; 285 return;
285 } 286 }
286 287
287 NodeState state = getNodeState(node); 288 NodeState state = getNodeState(node);
289 + log.debug("Init node: {} state: {}", node.hostname(), state.toString());
288 state.process(this, node); 290 state.process(this, node);
289 } 291 }
290 292
...@@ -296,7 +298,7 @@ public class CordVtnNodeManager { ...@@ -296,7 +298,7 @@ public class CordVtnNodeManager {
296 */ 298 */
297 public boolean isNodeInitComplete(CordVtnNode node) { 299 public boolean isNodeInitComplete(CordVtnNode node) {
298 checkNotNull(node); 300 checkNotNull(node);
299 - return nodeStore.containsKey(node) && getNodeState(node).equals(NodeState.COMPLETE); 301 + return nodeStore.containsKey(node.hostname()) && getNodeState(node).equals(NodeState.COMPLETE);
300 } 302 }
301 303
302 /** 304 /**
...@@ -311,8 +313,9 @@ public class CordVtnNodeManager { ...@@ -311,8 +313,9 @@ public class CordVtnNodeManager {
311 // the state saved in nodeStore can be wrong if IP address settings are changed 313 // the state saved in nodeStore can be wrong if IP address settings are changed
312 // after the node init has been completed since there's no way to detect it 314 // after the node init has been completed since there's no way to detect it
313 // getNodeState and checkNodeInitState always return correct answer but can be slow 315 // getNodeState and checkNodeInitState always return correct answer but can be slow
314 - Versioned<NodeState> state = nodeStore.get(node); 316 + Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
315 - return state != null && state.value().equals(NodeState.COMPLETE); 317 + CordVtnNodeState state = versionedNode.value().state();
318 + return state != null && state.equals(NodeState.COMPLETE);
316 } 319 }
317 320
318 /** 321 /**
...@@ -324,7 +327,7 @@ public class CordVtnNodeManager { ...@@ -324,7 +327,7 @@ public class CordVtnNodeManager {
324 public String checkNodeInitState(CordVtnNode node) { 327 public String checkNodeInitState(CordVtnNode node) {
325 checkNotNull(node); 328 checkNotNull(node);
326 329
327 - if (!nodeStore.containsKey(node)) { 330 + if (!nodeStore.containsKey(node.hostname())) {
328 log.warn("Node {} does not exist, add node first", node.hostname()); 331 log.warn("Node {} does not exist, add node first", node.hostname());
329 return null; 332 return null;
330 } 333 }
...@@ -337,13 +340,13 @@ public class CordVtnNodeManager { ...@@ -337,13 +340,13 @@ public class CordVtnNodeManager {
337 340
338 Set<IpAddress> intBrIps = RemoteIpCommandUtil.getCurrentIps(session, DEFAULT_BRIDGE); 341 Set<IpAddress> intBrIps = RemoteIpCommandUtil.getCurrentIps(session, DEFAULT_BRIDGE);
339 String result = String.format( 342 String result = String.format(
340 - "Integration bridge created/connected : %s (%s)%n" + 343 + "br-int created and connected : %s (%s)%n" +
341 "VXLAN interface created : %s%n" + 344 "VXLAN interface created : %s%n" +
342 "Data plane interface added : %s (%s)%n" + 345 "Data plane interface added : %s (%s)%n" +
343 "IP flushed from %s : %s%n" + 346 "IP flushed from %s : %s%n" +
344 "Data plane IP added to br-int : %s (%s)%n" + 347 "Data plane IP added to br-int : %s (%s)%n" +
345 "Local management IP added to br-int : %s (%s)", 348 "Local management IP added to br-int : %s (%s)",
346 - isBrIntCreated(node) ? OK : NO, DEFAULT_BRIDGE, 349 + isBrIntCreated(node) ? OK : NO, node.intBrId(),
347 isTunnelIntfCreated(node) ? OK : NO, 350 isTunnelIntfCreated(node) ? OK : NO,
348 isDataPlaneIntfAdded(node) ? OK : NO, node.dpIntf(), 351 isDataPlaneIntfAdded(node) ? OK : NO, node.dpIntf(),
349 node.dpIntf(), 352 node.dpIntf(),
...@@ -371,9 +374,9 @@ public class CordVtnNodeManager { ...@@ -371,9 +374,9 @@ public class CordVtnNodeManager {
371 * @return list of nodes 374 * @return list of nodes
372 */ 375 */
373 public List<CordVtnNode> getNodes() { 376 public List<CordVtnNode> getNodes() {
374 - List<CordVtnNode> nodes = new ArrayList<>(); 377 + return nodeStore.values().stream()
375 - nodes.addAll(nodeStore.keySet()); 378 + .map(Versioned::value)
376 - return nodes; 379 + .collect(Collectors.toList());
377 } 380 }
378 381
379 /** 382 /**
...@@ -410,8 +413,7 @@ public class CordVtnNodeManager { ...@@ -410,8 +413,7 @@ public class CordVtnNodeManager {
410 checkNotNull(node); 413 checkNotNull(node);
411 414
412 log.debug("Changed {} state: {}", node.hostname(), newState.toString()); 415 log.debug("Changed {} state: {}", node.hostname(), newState.toString());
413 - 416 + nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
414 - nodeStore.put(node, newState);
415 newState.process(this, node); 417 newState.process(this, node);
416 } 418 }
417 419
...@@ -497,7 +499,7 @@ public class CordVtnNodeManager { ...@@ -497,7 +499,7 @@ public class CordVtnNodeManager {
497 private void connectOvsdb(CordVtnNode node) { 499 private void connectOvsdb(CordVtnNode node) {
498 checkNotNull(node); 500 checkNotNull(node);
499 501
500 - if (!nodeStore.containsKey(node)) { 502 + if (!nodeStore.containsKey(node.hostname())) {
501 log.warn("Node {} does not exist", node.hostname()); 503 log.warn("Node {} does not exist", node.hostname());
502 return; 504 return;
503 } 505 }
...@@ -515,7 +517,7 @@ public class CordVtnNodeManager { ...@@ -515,7 +517,7 @@ public class CordVtnNodeManager {
515 private void disconnectOvsdb(CordVtnNode node) { 517 private void disconnectOvsdb(CordVtnNode node) {
516 checkNotNull(node); 518 checkNotNull(node);
517 519
518 - if (!nodeStore.containsKey(node)) { 520 + if (!nodeStore.containsKey(node.hostname())) {
519 log.warn("Node {} does not exist", node.hostname()); 521 log.warn("Node {} does not exist", node.hostname());
520 return; 522 return;
521 } 523 }
...@@ -747,6 +749,7 @@ public class CordVtnNodeManager { ...@@ -747,6 +749,7 @@ public class CordVtnNodeManager {
747 @Override 749 @Override
748 public void disconnected(Device device) { 750 public void disconnected(Device device) {
749 if (!deviceService.isAvailable(device.id())) { 751 if (!deviceService.isAvailable(device.id())) {
752 + log.debug("Device {} is disconnected", device.id());
750 adminService.removeDevice(device.id()); 753 adminService.removeDevice(device.id());
751 } 754 }
752 } 755 }
......
1 +/*
2 + * Copyright 2016 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 + */
16 +package org.onosproject.cordvtn;
17 +
18 +/**
19 + * Entity that defines possible init state of the cordvtn node.
20 + */
21 +public interface CordVtnNodeState {
22 + /**
23 + * Returns null for no state.
24 + *
25 + * @return null
26 + */
27 + static CordVtnNodeState noState() {
28 + return null;
29 + }
30 +}