use of org.onosproject.net.provider.ProviderId in project onos by opennetworkinglab.
the class GossipDeviceStore method createOrUpdateDeviceInternal.
private DeviceEvent createOrUpdateDeviceInternal(ProviderId providerId, DeviceId deviceId, Timestamped<DeviceDescription> deltaDesc) {
// Collection of DeviceDescriptions for a Device
Map<ProviderId, DeviceDescriptions> device = getOrCreateDeviceDescriptionsMap(deviceId);
synchronized (device) {
if (isDeviceRemoved(deviceId, deltaDesc.timestamp())) {
log.debug("Ignoring outdated event: {}", deltaDesc);
return null;
}
DeviceDescriptions descs = getOrCreateProviderDeviceDescriptions(device, providerId, deltaDesc);
final Device oldDevice = devices.get(deviceId);
final Device newDevice;
if (deltaDesc == descs.getDeviceDesc() || deltaDesc.isNewer(descs.getDeviceDesc())) {
// on new device or valid update
descs.putDeviceDesc(deltaDesc);
newDevice = composeDevice(deviceId, device);
} else {
// outdated event, ignored.
return null;
}
if (oldDevice == null) {
// REGISTER
if (!deltaDesc.value().isDefaultAvailable()) {
return registerDevice(providerId, newDevice, deltaDesc.timestamp());
}
// ADD
return createDevice(providerId, newDevice, deltaDesc.timestamp());
} else {
// UPDATE or ignore (no change or stale)
return updateDevice(providerId, oldDevice, newDevice, deltaDesc.timestamp(), deltaDesc.value().isDefaultAvailable());
}
}
}
use of org.onosproject.net.provider.ProviderId in project onos by opennetworkinglab.
the class GossipDeviceStore method composePort.
/**
* Returns a Port, merging description given from multiple Providers.
*
* @param device device the port is on
* @param number port number
* @param descsMap Collection of Descriptions from multiple providers
* @return Port instance
*/
private Port composePort(Device device, PortNumber number, Map<ProviderId, DeviceDescriptions> descsMap) {
ProviderId primary = pickPrimaryPid(descsMap);
DeviceDescriptions primDescs = descsMap.get(primary);
// if no primary, assume not enabled
boolean isEnabled = false;
DefaultAnnotations.Builder annotations = DefaultAnnotations.builder();
Timestamp newest = null;
final Timestamped<PortDescription> portDesc = primDescs.getPortDesc(number);
if (portDesc != null) {
isEnabled = portDesc.value().isEnabled();
annotations.putAll(portDesc.value().annotations());
newest = portDesc.timestamp();
}
Port updated = null;
for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
if (e.getKey().equals(primary)) {
continue;
}
// Note: should keep track of Description timestamp in the future
// and only merge conflicting keys when timestamp is newer.
// Currently assuming there will never be a key conflict between
// providers
// annotation merging. not so efficient, should revisit later
final Timestamped<PortDescription> otherPortDesc = e.getValue().getPortDesc(number);
if (otherPortDesc != null) {
if (newest != null && newest.isNewerThan(otherPortDesc.timestamp())) {
continue;
}
annotations.putAll(otherPortDesc.value().annotations());
PortDescription other = otherPortDesc.value();
updated = buildTypedPort(device, number, isEnabled, other, annotations.build());
newest = otherPortDesc.timestamp();
}
}
if (portDesc == null) {
return updated == null ? new DefaultPort(device, number, false, annotations.build()) : updated;
}
PortDescription current = portDesc.value();
return updated == null ? buildTypedPort(device, number, isEnabled, current, annotations.build()) : updated;
}
use of org.onosproject.net.provider.ProviderId in project onos by opennetworkinglab.
the class GossipDeviceStore method updatePortStatus.
@Override
public synchronized DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, PortDescription portDescription) {
final Timestamp newTimestamp;
try {
newTimestamp = deviceClockService.getTimestamp(deviceId);
} catch (IllegalStateException e) {
log.info("Timestamp was not available for device {}", deviceId);
log.debug(" discarding {}", portDescription);
// See updatePorts comment
return null;
}
final Timestamped<PortDescription> deltaDesc = new Timestamped<>(portDescription, newTimestamp);
final DeviceEvent event;
Timestamped<PortDescription> mergedDesc;
final Map<ProviderId, DeviceDescriptions> device = getOrCreateDeviceDescriptionsMap(deviceId);
synchronized (device) {
event = updatePortStatusInternal(providerId, deviceId, deltaDesc);
mergedDesc = device.get(providerId).getPortDesc(portDescription.portNumber());
// on delete the port is removed, thus using latest known description
if (mergedDesc == null) {
mergedDesc = new Timestamped<>(portDescription, newTimestamp);
}
}
if (event != null) {
log.debug("Notifying peers of a port status update topology event for providerId: {} and deviceId: {}", providerId, deviceId);
notifyPeers(new InternalPortStatusEvent(providerId, deviceId, mergedDesc));
}
return event;
}
use of org.onosproject.net.provider.ProviderId in project onos by opennetworkinglab.
the class GossipDeviceStore method handleAdvertisement.
/**
* Responds to anti-entropy advertisement message.
* <p>
* Notify sender about out-dated information using regular replication message.
* Send back advertisement to sender if not in sync.
*
* @param advertisement to respond to
*/
private void handleAdvertisement(DeviceAntiEntropyAdvertisement advertisement) {
/*
* NOTE that when an instance rejoins the cluster, it will generate
* device events and send to the local apps through the delegate. This
* approach might be not the best if the apps are not enough robust or
* if there is no proper coordination in the cluster. Also, note that
* any ECMap will act on the same way during the bootstrap process
*/
final NodeId sender = advertisement.sender();
Map<DeviceFragmentId, Timestamp> devAds = new HashMap<>(advertisement.deviceFingerPrints());
Map<PortFragmentId, Timestamp> portAds = new HashMap<>(advertisement.ports());
Map<DeviceId, Timestamp> offlineAds = new HashMap<>(advertisement.offline());
// Fragments to request
Collection<DeviceFragmentId> reqDevices = new ArrayList<>();
Collection<PortFragmentId> reqPorts = new ArrayList<>();
for (Entry<DeviceId, Map<ProviderId, DeviceDescriptions>> de : deviceDescs.entrySet()) {
final DeviceId deviceId = de.getKey();
final Map<ProviderId, DeviceDescriptions> lDevice = de.getValue();
synchronized (lDevice) {
// latestTimestamp across provider
// Note: can be null initially
Timestamp localLatest = offline.get(deviceId);
// handle device Ads
for (Entry<ProviderId, DeviceDescriptions> prov : lDevice.entrySet()) {
final ProviderId provId = prov.getKey();
final DeviceDescriptions lDeviceDescs = prov.getValue();
final DeviceFragmentId devFragId = new DeviceFragmentId(deviceId, provId);
Timestamped<DeviceDescription> lProvDevice = lDeviceDescs.getDeviceDesc();
Timestamp advDevTimestamp = devAds.get(devFragId);
if (advDevTimestamp == null || lProvDevice.isNewerThan(advDevTimestamp)) {
// remote does not have it or outdated, suggest
log.trace("send to {} device update {} for {}", sender, lProvDevice, deviceId);
notifyPeer(sender, new InternalDeviceEvent(provId, deviceId, lProvDevice));
} else if (!lProvDevice.timestamp().equals(advDevTimestamp)) {
// local is outdated, request
log.trace("need update {} < {} for device {} from {}", lProvDevice.timestamp(), advDevTimestamp, deviceId, sender);
reqDevices.add(devFragId);
}
// handle port Ads
for (Entry<PortNumber, Timestamped<PortDescription>> pe : lDeviceDescs.getPortDescs().entrySet()) {
final PortNumber num = pe.getKey();
final Timestamped<PortDescription> lPort = pe.getValue();
final PortFragmentId portFragId = new PortFragmentId(deviceId, provId, num);
Timestamp advPortTimestamp = portAds.get(portFragId);
if (advPortTimestamp == null || lPort.isNewerThan(advPortTimestamp)) {
// remote does not have it or outdated, suggest
log.trace("send to {} port update {} for {}/{}", sender, lPort, deviceId, num);
notifyPeer(sender, new InternalPortStatusEvent(provId, deviceId, lPort));
} else if (!lPort.timestamp().equals(advPortTimestamp)) {
// local is outdated, request
log.trace("need update {} < {} for port {} from {}", lPort.timestamp(), advPortTimestamp, num, sender);
reqPorts.add(portFragId);
}
// remove port Ad already processed
portAds.remove(portFragId);
}
// end local port loop
// remove device Ad already processed
devAds.remove(devFragId);
// find latest and update
final Timestamp providerLatest = lDeviceDescs.getLatestTimestamp();
if (localLatest == null || providerLatest.compareTo(localLatest) > 0) {
localLatest = providerLatest;
}
}
// end local provider loop
// checking if remote timestamp is more recent.
Timestamp rOffline = offlineAds.get(deviceId);
if (localLatest == null || (rOffline != null && rOffline.compareTo(localLatest) > 0)) {
// remote offline timestamp suggests that the
// device is off-line
log.trace("remote offline timestamp from {} suggests that the device {} is off-line", sender, deviceId);
markOfflineInternal(deviceId, rOffline);
}
Timestamp lOffline = offline.get(deviceId);
if (lOffline != null && rOffline == null) {
// locally offline, but remote is online, suggest offline
log.trace("suggest to {} sthat the device {} is off-line", sender, deviceId);
notifyPeer(sender, new InternalDeviceStatusChangeEvent(deviceId, lOffline, false));
}
// remove device offline Ad already processed
offlineAds.remove(deviceId);
}
// end local device loop
}
// device lock
// If there is any Ads left, request them
log.trace("Ads left {}, {}", devAds, portAds);
reqDevices.addAll(devAds.keySet());
reqPorts.addAll(portAds.keySet());
if (reqDevices.isEmpty() && reqPorts.isEmpty()) {
log.trace("Nothing to request to remote peer {}", sender);
return;
}
log.debug("Need to sync {} {}", reqDevices, reqPorts);
// 2-way Anti-Entropy for now
try {
unicastMessage(sender, DEVICE_ADVERTISE, createAdvertisement());
} catch (IOException e) {
log.error("Failed to send response advertisement to " + sender, e);
}
// Sketch of 3-way Anti-Entropy
// DeviceAntiEntropyRequest request = new DeviceAntiEntropyRequest(self, reqDevices, reqPorts);
// ClusterMessage message = new ClusterMessage(
// clusterService.getLocalNode().id(),
// GossipDeviceStoreMessageSubjects.DEVICE_REQUEST,
// SERIALIZER.encode(request));
//
// try {
// clusterCommunicator.unicast(message, advertisement.sender());
// } catch (IOException e) {
// log.error("Failed to send advertisement reply to "
// + advertisement.sender(), e);
// }
}
use of org.onosproject.net.provider.ProviderId in project onos by opennetworkinglab.
the class GossipDeviceStore method handleDeviceEvent.
private void handleDeviceEvent(InternalDeviceEvent event) {
ProviderId providerId = event.providerId();
DeviceId deviceId = event.deviceId();
Timestamped<DeviceDescription> deviceDescription = event.deviceDescription();
try {
notifyDelegateIfNotNull(createOrUpdateDeviceInternal(providerId, deviceId, deviceDescription));
} catch (Exception e) {
log.warn("Exception thrown handling device update", e);
}
}
Aggregations