Fixed a defect that allowed ancillary device providers to overwrite primary provider's data.
Showing
2 changed files
with
60 additions
and
52 deletions
... | @@ -290,12 +290,17 @@ public class GossipDeviceStore | ... | @@ -290,12 +290,17 @@ public class GossipDeviceStore |
290 | private DeviceEvent updateDevice(ProviderId providerId, | 290 | private DeviceEvent updateDevice(ProviderId providerId, |
291 | Device oldDevice, | 291 | Device oldDevice, |
292 | Device newDevice, Timestamp newTimestamp) { | 292 | Device newDevice, Timestamp newTimestamp) { |
293 | - | ||
294 | // We allow only certain attributes to trigger update | 293 | // We allow only certain attributes to trigger update |
295 | - if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || | 294 | + boolean propertiesChanged = |
296 | - !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) || | 295 | + !Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || |
297 | - !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations())) { | 296 | + !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()); |
298 | - | 297 | + boolean annotationsChanged = |
298 | + !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations()); | ||
299 | + | ||
300 | + // Primary providers can respond to all changes, but ancillary ones | ||
301 | + // should respond only to annotation changes. | ||
302 | + if ((providerId.isAncillary() && annotationsChanged) || | ||
303 | + (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) { | ||
299 | boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); | 304 | boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); |
300 | if (!replaced) { | 305 | if (!replaced) { |
301 | verify(replaced, | 306 | verify(replaced, | ... | ... |
... | @@ -70,15 +70,16 @@ public class SimpleDeviceStore | ... | @@ -70,15 +70,16 @@ public class SimpleDeviceStore |
70 | 70 | ||
71 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | 71 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; |
72 | 72 | ||
73 | - // collection of Description given from various providers | 73 | + // Collection of Description given from various providers |
74 | private final ConcurrentMap<DeviceId, Map<ProviderId, DeviceDescriptions>> | 74 | private final ConcurrentMap<DeviceId, Map<ProviderId, DeviceDescriptions>> |
75 | - deviceDescs = Maps.newConcurrentMap(); | 75 | + deviceDescs = Maps.newConcurrentMap(); |
76 | 76 | ||
77 | - // cache of Device and Ports generated by compositing descriptions from providers | 77 | + // Cache of Device and Ports generated by compositing descriptions from providers |
78 | private final ConcurrentMap<DeviceId, Device> devices = Maps.newConcurrentMap(); | 78 | private final ConcurrentMap<DeviceId, Device> devices = Maps.newConcurrentMap(); |
79 | - private final ConcurrentMap<DeviceId, ConcurrentMap<PortNumber, Port>> devicePorts = Maps.newConcurrentMap(); | 79 | + private final ConcurrentMap<DeviceId, ConcurrentMap<PortNumber, Port>> |
80 | + devicePorts = Maps.newConcurrentMap(); | ||
80 | 81 | ||
81 | - // available(=UP) devices | 82 | + // Available (=UP) devices |
82 | private final Set<DeviceId> availableDevices = Sets.newConcurrentHashSet(); | 83 | private final Set<DeviceId> availableDevices = Sets.newConcurrentHashSet(); |
83 | 84 | ||
84 | 85 | ||
... | @@ -113,19 +114,17 @@ public class SimpleDeviceStore | ... | @@ -113,19 +114,17 @@ public class SimpleDeviceStore |
113 | 114 | ||
114 | @Override | 115 | @Override |
115 | public DeviceEvent createOrUpdateDevice(ProviderId providerId, | 116 | public DeviceEvent createOrUpdateDevice(ProviderId providerId, |
116 | - DeviceId deviceId, | 117 | + DeviceId deviceId, |
117 | - DeviceDescription deviceDescription) { | 118 | + DeviceDescription deviceDescription) { |
118 | - | ||
119 | Map<ProviderId, DeviceDescriptions> providerDescs | 119 | Map<ProviderId, DeviceDescriptions> providerDescs |
120 | - = getOrCreateDeviceDescriptions(deviceId); | 120 | + = getOrCreateDeviceDescriptions(deviceId); |
121 | 121 | ||
122 | synchronized (providerDescs) { | 122 | synchronized (providerDescs) { |
123 | // locking per device | 123 | // locking per device |
124 | - | ||
125 | DeviceDescriptions descs | 124 | DeviceDescriptions descs |
126 | - = getOrCreateProviderDeviceDescriptions(providerDescs, | 125 | + = getOrCreateProviderDeviceDescriptions(providerDescs, |
127 | - providerId, | 126 | + providerId, |
128 | - deviceDescription); | 127 | + deviceDescription); |
129 | 128 | ||
130 | Device oldDevice = devices.get(deviceId); | 129 | Device oldDevice = devices.get(deviceId); |
131 | // update description | 130 | // update description |
... | @@ -145,12 +144,11 @@ public class SimpleDeviceStore | ... | @@ -145,12 +144,11 @@ public class SimpleDeviceStore |
145 | // Creates the device and returns the appropriate event if necessary. | 144 | // Creates the device and returns the appropriate event if necessary. |
146 | // Guarded by deviceDescs value (=Device lock) | 145 | // Guarded by deviceDescs value (=Device lock) |
147 | private DeviceEvent createDevice(ProviderId providerId, Device newDevice) { | 146 | private DeviceEvent createDevice(ProviderId providerId, Device newDevice) { |
148 | - | ||
149 | // update composed device cache | 147 | // update composed device cache |
150 | Device oldDevice = devices.putIfAbsent(newDevice.id(), newDevice); | 148 | Device oldDevice = devices.putIfAbsent(newDevice.id(), newDevice); |
151 | verify(oldDevice == null, | 149 | verify(oldDevice == null, |
152 | - "Unexpected Device in cache. PID:%s [old=%s, new=%s]", | 150 | + "Unexpected Device in cache. PID:%s [old=%s, new=%s]", |
153 | - providerId, oldDevice, newDevice); | 151 | + providerId, oldDevice, newDevice); |
154 | 152 | ||
155 | if (!providerId.isAncillary()) { | 153 | if (!providerId.isAncillary()) { |
156 | availableDevices.add(newDevice.id()); | 154 | availableDevices.add(newDevice.id()); |
... | @@ -162,17 +160,24 @@ public class SimpleDeviceStore | ... | @@ -162,17 +160,24 @@ public class SimpleDeviceStore |
162 | // Updates the device and returns the appropriate event if necessary. | 160 | // Updates the device and returns the appropriate event if necessary. |
163 | // Guarded by deviceDescs value (=Device lock) | 161 | // Guarded by deviceDescs value (=Device lock) |
164 | private DeviceEvent updateDevice(ProviderId providerId, Device oldDevice, Device newDevice) { | 162 | private DeviceEvent updateDevice(ProviderId providerId, Device oldDevice, Device newDevice) { |
165 | - | ||
166 | // We allow only certain attributes to trigger update | 163 | // We allow only certain attributes to trigger update |
167 | - if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || | 164 | + boolean propertiesChanged = |
168 | - !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) || | 165 | + !Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || |
169 | - !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations())) { | 166 | + !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()); |
167 | + boolean annotationsChanged = | ||
168 | + !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations()); | ||
169 | + | ||
170 | + // Primary providers can respond to all changes, but ancillary ones | ||
171 | + // should respond only to annotation changes. | ||
172 | + if ((providerId.isAncillary() && annotationsChanged) || | ||
173 | + (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) { | ||
170 | 174 | ||
171 | boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); | 175 | boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); |
172 | if (!replaced) { | 176 | if (!replaced) { |
177 | + // FIXME: Is the enclosing if required here? | ||
173 | verify(replaced, | 178 | verify(replaced, |
174 | - "Replacing devices cache failed. PID:%s [expected:%s, found:%s, new=%s]", | 179 | + "Replacing devices cache failed. PID:%s [expected:%s, found:%s, new=%s]", |
175 | - providerId, oldDevice, devices.get(newDevice.id()) | 180 | + providerId, oldDevice, devices.get(newDevice.id()) |
176 | , newDevice); | 181 | , newDevice); |
177 | } | 182 | } |
178 | if (!providerId.isAncillary()) { | 183 | if (!providerId.isAncillary()) { |
... | @@ -193,7 +198,7 @@ public class SimpleDeviceStore | ... | @@ -193,7 +198,7 @@ public class SimpleDeviceStore |
193 | @Override | 198 | @Override |
194 | public DeviceEvent markOffline(DeviceId deviceId) { | 199 | public DeviceEvent markOffline(DeviceId deviceId) { |
195 | Map<ProviderId, DeviceDescriptions> providerDescs | 200 | Map<ProviderId, DeviceDescriptions> providerDescs |
196 | - = getOrCreateDeviceDescriptions(deviceId); | 201 | + = getOrCreateDeviceDescriptions(deviceId); |
197 | 202 | ||
198 | // locking device | 203 | // locking device |
199 | synchronized (providerDescs) { | 204 | synchronized (providerDescs) { |
... | @@ -212,9 +217,8 @@ public class SimpleDeviceStore | ... | @@ -212,9 +217,8 @@ public class SimpleDeviceStore |
212 | 217 | ||
213 | @Override | 218 | @Override |
214 | public List<DeviceEvent> updatePorts(ProviderId providerId, | 219 | public List<DeviceEvent> updatePorts(ProviderId providerId, |
215 | - DeviceId deviceId, | 220 | + DeviceId deviceId, |
216 | - List<PortDescription> portDescriptions) { | 221 | + List<PortDescription> portDescriptions) { |
217 | - | ||
218 | Device device = devices.get(deviceId); | 222 | Device device = devices.get(deviceId); |
219 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | 223 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); |
220 | 224 | ||
... | @@ -226,8 +230,8 @@ public class SimpleDeviceStore | ... | @@ -226,8 +230,8 @@ public class SimpleDeviceStore |
226 | DeviceDescriptions descs = descsMap.get(providerId); | 230 | DeviceDescriptions descs = descsMap.get(providerId); |
227 | // every provider must provide DeviceDescription. | 231 | // every provider must provide DeviceDescription. |
228 | checkArgument(descs != null, | 232 | checkArgument(descs != null, |
229 | - "Device description for Device ID %s from Provider %s was not found", | 233 | + "Device description for Device ID %s from Provider %s was not found", |
230 | - deviceId, providerId); | 234 | + deviceId, providerId); |
231 | 235 | ||
232 | Map<PortNumber, Port> ports = getPortMap(deviceId); | 236 | Map<PortNumber, Port> ports = getPortMap(deviceId); |
233 | 237 | ||
... | @@ -247,8 +251,8 @@ public class SimpleDeviceStore | ... | @@ -247,8 +251,8 @@ public class SimpleDeviceStore |
247 | newPort = composePort(device, number, descsMap); | 251 | newPort = composePort(device, number, descsMap); |
248 | 252 | ||
249 | events.add(oldPort == null ? | 253 | events.add(oldPort == null ? |
250 | - createPort(device, newPort, ports) : | 254 | + createPort(device, newPort, ports) : |
251 | - updatePort(device, oldPort, newPort, ports)); | 255 | + updatePort(device, oldPort, newPort, ports)); |
252 | } | 256 | } |
253 | 257 | ||
254 | events.addAll(pruneOldPorts(device, ports, processed)); | 258 | events.addAll(pruneOldPorts(device, ports, processed)); |
... | @@ -272,7 +276,7 @@ public class SimpleDeviceStore | ... | @@ -272,7 +276,7 @@ public class SimpleDeviceStore |
272 | Port newPort, | 276 | Port newPort, |
273 | Map<PortNumber, Port> ports) { | 277 | Map<PortNumber, Port> ports) { |
274 | if (oldPort.isEnabled() != newPort.isEnabled() || | 278 | if (oldPort.isEnabled() != newPort.isEnabled() || |
275 | - !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { | 279 | + !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { |
276 | 280 | ||
277 | ports.put(oldPort.number(), newPort); | 281 | ports.put(oldPort.number(), newPort); |
278 | return new DeviceEvent(PORT_UPDATED, device, newPort); | 282 | return new DeviceEvent(PORT_UPDATED, device, newPort); |
... | @@ -303,7 +307,7 @@ public class SimpleDeviceStore | ... | @@ -303,7 +307,7 @@ public class SimpleDeviceStore |
303 | // exist, it creates and registers a new one. | 307 | // exist, it creates and registers a new one. |
304 | private ConcurrentMap<PortNumber, Port> getPortMap(DeviceId deviceId) { | 308 | private ConcurrentMap<PortNumber, Port> getPortMap(DeviceId deviceId) { |
305 | return createIfAbsentUnchecked(devicePorts, deviceId, | 309 | return createIfAbsentUnchecked(devicePorts, deviceId, |
306 | - NewConcurrentHashMap.<PortNumber, Port>ifNeeded()); | 310 | + NewConcurrentHashMap.<PortNumber, Port>ifNeeded()); |
307 | } | 311 | } |
308 | 312 | ||
309 | private Map<ProviderId, DeviceDescriptions> getOrCreateDeviceDescriptions( | 313 | private Map<ProviderId, DeviceDescriptions> getOrCreateDeviceDescriptions( |
... | @@ -325,9 +329,8 @@ public class SimpleDeviceStore | ... | @@ -325,9 +329,8 @@ public class SimpleDeviceStore |
325 | 329 | ||
326 | // Guarded by deviceDescs value (=Device lock) | 330 | // Guarded by deviceDescs value (=Device lock) |
327 | private DeviceDescriptions getOrCreateProviderDeviceDescriptions( | 331 | private DeviceDescriptions getOrCreateProviderDeviceDescriptions( |
328 | - Map<ProviderId, DeviceDescriptions> device, | 332 | + Map<ProviderId, DeviceDescriptions> device, |
329 | - ProviderId providerId, DeviceDescription deltaDesc) { | 333 | + ProviderId providerId, DeviceDescription deltaDesc) { |
330 | - | ||
331 | synchronized (device) { | 334 | synchronized (device) { |
332 | DeviceDescriptions r = device.get(providerId); | 335 | DeviceDescriptions r = device.get(providerId); |
333 | if (r == null) { | 336 | if (r == null) { |
... | @@ -340,7 +343,7 @@ public class SimpleDeviceStore | ... | @@ -340,7 +343,7 @@ public class SimpleDeviceStore |
340 | 343 | ||
341 | @Override | 344 | @Override |
342 | public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, | 345 | public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
343 | - PortDescription portDescription) { | 346 | + PortDescription portDescription) { |
344 | Device device = devices.get(deviceId); | 347 | Device device = devices.get(deviceId); |
345 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | 348 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); |
346 | 349 | ||
... | @@ -351,8 +354,8 @@ public class SimpleDeviceStore | ... | @@ -351,8 +354,8 @@ public class SimpleDeviceStore |
351 | DeviceDescriptions descs = descsMap.get(providerId); | 354 | DeviceDescriptions descs = descsMap.get(providerId); |
352 | // assuming all providers must give DeviceDescription first | 355 | // assuming all providers must give DeviceDescription first |
353 | checkArgument(descs != null, | 356 | checkArgument(descs != null, |
354 | - "Device description for Device ID %s from Provider %s was not found", | 357 | + "Device description for Device ID %s from Provider %s was not found", |
355 | - deviceId, providerId); | 358 | + deviceId, providerId); |
356 | 359 | ||
357 | ConcurrentMap<PortNumber, Port> ports = getPortMap(deviceId); | 360 | ConcurrentMap<PortNumber, Port> ports = getPortMap(deviceId); |
358 | final PortNumber number = portDescription.portNumber(); | 361 | final PortNumber number = portDescription.portNumber(); |
... | @@ -404,19 +407,19 @@ public class SimpleDeviceStore | ... | @@ -404,19 +407,19 @@ public class SimpleDeviceStore |
404 | availableDevices.remove(deviceId); | 407 | availableDevices.remove(deviceId); |
405 | descs.clear(); | 408 | descs.clear(); |
406 | return device == null ? null : | 409 | return device == null ? null : |
407 | - new DeviceEvent(DEVICE_REMOVED, device, null); | 410 | + new DeviceEvent(DEVICE_REMOVED, device, null); |
408 | } | 411 | } |
409 | } | 412 | } |
410 | 413 | ||
411 | /** | 414 | /** |
412 | * Returns a Device, merging description given from multiple Providers. | 415 | * Returns a Device, merging description given from multiple Providers. |
413 | * | 416 | * |
414 | - * @param deviceId device identifier | 417 | + * @param deviceId device identifier |
415 | * @param providerDescs Collection of Descriptions from multiple providers | 418 | * @param providerDescs Collection of Descriptions from multiple providers |
416 | * @return Device instance | 419 | * @return Device instance |
417 | */ | 420 | */ |
418 | private Device composeDevice(DeviceId deviceId, | 421 | private Device composeDevice(DeviceId deviceId, |
419 | - Map<ProviderId, DeviceDescriptions> providerDescs) { | 422 | + Map<ProviderId, DeviceDescriptions> providerDescs) { |
420 | 423 | ||
421 | checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); | 424 | checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); |
422 | 425 | ||
... | @@ -447,21 +450,21 @@ public class SimpleDeviceStore | ... | @@ -447,21 +450,21 @@ public class SimpleDeviceStore |
447 | annotations = merge(annotations, e.getValue().getDeviceDesc().annotations()); | 450 | annotations = merge(annotations, e.getValue().getDeviceDesc().annotations()); |
448 | } | 451 | } |
449 | 452 | ||
450 | - return new DefaultDevice(primary, deviceId , type, manufacturer, | 453 | + return new DefaultDevice(primary, deviceId, type, manufacturer, |
451 | - hwVersion, swVersion, serialNumber, | 454 | + hwVersion, swVersion, serialNumber, |
452 | - chassisId, annotations); | 455 | + chassisId, annotations); |
453 | } | 456 | } |
454 | 457 | ||
455 | /** | 458 | /** |
456 | * Returns a Port, merging description given from multiple Providers. | 459 | * Returns a Port, merging description given from multiple Providers. |
457 | * | 460 | * |
458 | - * @param device device the port is on | 461 | + * @param device device the port is on |
459 | - * @param number port number | 462 | + * @param number port number |
460 | * @param descsMap Collection of Descriptions from multiple providers | 463 | * @param descsMap Collection of Descriptions from multiple providers |
461 | * @return Port instance | 464 | * @return Port instance |
462 | */ | 465 | */ |
463 | private Port composePort(Device device, PortNumber number, | 466 | private Port composePort(Device device, PortNumber number, |
464 | - Map<ProviderId, DeviceDescriptions> descsMap) { | 467 | + Map<ProviderId, DeviceDescriptions> descsMap) { |
465 | 468 | ||
466 | ProviderId primary = pickPrimaryPID(descsMap); | 469 | ProviderId primary = pickPrimaryPID(descsMap); |
467 | DeviceDescriptions primDescs = descsMap.get(primary); | 470 | DeviceDescriptions primDescs = descsMap.get(primary); | ... | ... |
-
Please register or login to post a comment