use of org.onlab.packet.IpAddress in project trellis-control by opennetworkinglab.
the class McastHandler method getSinks.
/**
* Gets sink(s) of given multicast group.
*
* @param mcastIp multicast IP
* @return set of connect point or empty set if not found
*/
private Set<ConnectPoint> getSinks(IpAddress mcastIp, DeviceId device, ConnectPoint source) {
McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(mcastPathStore.get(pathStoreKey), Lists.newArrayList());
VlanId assignedVlan = mcastUtils.assignedVlan(device.equals(source.deviceId()) ? source : null);
McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, device, assignedVlan);
NextObjective nextObjective = Versioned.valueOrNull(mcastNextObjStore.get(mcastStoreKey));
ImmutableSet.Builder<ConnectPoint> cpBuilder = ImmutableSet.builder();
if (nextObjective != null) {
Set<PortNumber> outputPorts = mcastUtils.getPorts(nextObjective.next());
outputPorts.forEach(portNumber -> cpBuilder.add(new ConnectPoint(device, portNumber)));
}
Set<ConnectPoint> egressCp = cpBuilder.build();
return egressCp.stream().filter(connectPoint -> !mcastUtils.isInfraPort(connectPoint, storedPaths)).collect(Collectors.toSet());
}
use of org.onlab.packet.IpAddress in project trellis-control by opennetworkinglab.
the class McastHandler method processMcastEventInternal.
private void processMcastEventInternal(McastEvent event) {
lastMcastChange.set(Instant.now());
// Current subject is null, for ROUTE_REMOVED events
final McastRouteUpdate mcastUpdate = event.subject();
final McastRouteUpdate mcastPrevUpdate = event.prevSubject();
IpAddress mcastIp = mcastPrevUpdate.route().group();
Set<ConnectPoint> prevSinks = mcastPrevUpdate.sinks().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
Set<ConnectPoint> prevSources = mcastPrevUpdate.sources().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
Set<ConnectPoint> sources;
// Events handling
if (event.type() == ROUTE_ADDED) {
processRouteAddedInternal(mcastUpdate.route().group());
} else if (event.type() == ROUTE_REMOVED) {
processRouteRemovedInternal(prevSources, mcastIp);
} else if (event.type() == SOURCES_ADDED) {
// Current subject and prev just differ for the source connect points
sources = mcastUpdate.sources().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
Set<ConnectPoint> sourcesToBeAdded = Sets.difference(sources, prevSources);
processSourcesAddedInternal(sourcesToBeAdded, mcastIp, mcastUpdate.sinks());
} else if (event.type() == SOURCES_REMOVED) {
// Current subject and prev just differ for the source connect points
sources = mcastUpdate.sources().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
Set<ConnectPoint> sourcesToBeRemoved = Sets.difference(prevSources, sources);
processSourcesRemovedInternal(sourcesToBeRemoved, sources, mcastIp, mcastUpdate.sinks());
} else if (event.type() == SINKS_ADDED) {
processSinksAddedInternal(prevSources, mcastIp, mcastUpdate.sinks(), prevSinks);
} else if (event.type() == SINKS_REMOVED) {
processSinksRemovedInternal(prevSources, mcastIp, mcastUpdate.sinks(), mcastPrevUpdate.sinks());
} else {
log.warn("Event {} not handled", event);
}
}
use of org.onlab.packet.IpAddress in project trellis-control by opennetworkinglab.
the class McastHandler method removePortFromDevice.
/**
* Removes a port from given multicast group on given device.
* This involves the update of L3 multicast group and multicast routing
* table entry.
*
* @param deviceId device ID
* @param port port to be added
* @param mcastIp multicast group
* @param assignedVlan assigned VLAN ID
* @return true if this is the last sink on this device
*/
private boolean removePortFromDevice(DeviceId deviceId, PortNumber port, IpAddress mcastIp, VlanId assignedVlan) {
// TODO trace
log.info("Removing {} on {}/{} and vlan {}", mcastIp, deviceId, port, assignedVlan);
McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId, assignedVlan);
// This device is not serving this multicast group
if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
return true;
}
NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
Set<PortNumber> existingPorts = mcastUtils.getPorts(nextObj.next());
// This port does not serve this multicast group
if (!existingPorts.contains(port)) {
if (!existingPorts.isEmpty()) {
log.debug("{} is not serving {} on port {}. Abort.", deviceId, mcastIp, port);
return false;
}
return true;
}
// Copy and modify the ImmutableSet
existingPorts = Sets.newHashSet(existingPorts);
existingPorts.remove(port);
NextObjective newNextObj;
ObjectiveContext context;
ForwardingObjective fwdObj;
if (existingPorts.isEmpty()) {
context = new DefaultObjectiveContext((objective) -> log.debug("Successfully remove {} on {}/{}, vlan {}", mcastIp, deviceId, port.toLong(), assignedVlan), (objective, error) -> log.warn("Failed to remove {} on {}/{}, vlan {}: {}", mcastIp, deviceId, port.toLong(), assignedVlan, error));
fwdObj = mcastUtils.fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(context);
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("skip forward flowobjective removal for device: {}", deviceId);
} else {
srManager.flowObjectiveService.forward(deviceId, fwdObj);
}
mcastNextObjStore.remove(mcastStoreKey);
} else {
// Here we store the next objective with the remaining port
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, existingPorts, nextObj.id()).removeFromExisting();
mcastNextObjStore.put(mcastStoreKey, newNextObj);
// Let's modify the next objective removing the bucket
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, ImmutableSet.of(port), nextObj.id()).removeFromExisting();
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("skip next flowobjective update for device: {}", deviceId);
} else {
// no need to update the flow here since we have updated the next objective + group
// the existing flow will keep pointing to the updated nextobj
srManager.flowObjectiveService.next(deviceId, newNextObj);
}
}
return existingPorts.isEmpty();
}
use of org.onlab.packet.IpAddress in project trellis-control by opennetworkinglab.
the class McastHandler method processSinksToBeAdded.
/**
* Process all the sinks related to a mcast group and return
* the ones to be processed.
*
* @param source the source connect point
* @param mcastIp the group address
* @param sinks the sinks to be evaluated
* @return the set of the sinks to be processed
*/
private Set<ConnectPoint> processSinksToBeAdded(ConnectPoint source, IpAddress mcastIp, Map<HostId, Set<ConnectPoint>> sinks) {
final Set<ConnectPoint> sinksToBeProcessed = Sets.newHashSet();
log.debug("Processing sinks to be added for Multicast group {}, source {}", mcastIp, source);
sinks.forEach(((hostId, connectPoints) -> {
// add all connect points that are not tied with any host
if (Objects.equal(HostId.NONE, hostId)) {
sinksToBeProcessed.addAll(connectPoints);
return;
}
// If it has more than 2 locations
if (connectPoints.size() > 2 || connectPoints.size() == 0) {
log.debug("Skip {} since sink {} has {} locations", mcastIp, hostId, connectPoints.size());
return;
}
// If it has one location, just use it
if (connectPoints.size() == 1) {
sinksToBeProcessed.add(connectPoints.stream().findFirst().orElse(null));
return;
}
// We prefer to reuse existing flows
ConnectPoint sinkToBeProcessed = connectPoints.stream().filter(connectPoint -> {
if (!isSinkForGroup(mcastIp, connectPoint, source)) {
return false;
}
if (!isSinkReachable(mcastIp, connectPoint, source)) {
return false;
}
ConnectPoint other = connectPoints.stream().filter(remaining -> !remaining.equals(connectPoint)).findFirst().orElse(null);
// We are already serving the sink
return !isSinkForSource(mcastIp, other, source);
}).findFirst().orElse(null);
if (sinkToBeProcessed != null) {
sinksToBeProcessed.add(sinkToBeProcessed);
return;
}
// Otherwise we prefer to reuse existing egresses
Set<DeviceId> egresses = getDevice(mcastIp, EGRESS, source);
sinkToBeProcessed = connectPoints.stream().filter(connectPoint -> {
if (!egresses.contains(connectPoint.deviceId())) {
return false;
}
if (!isSinkReachable(mcastIp, connectPoint, source)) {
return false;
}
ConnectPoint other = connectPoints.stream().filter(remaining -> !remaining.equals(connectPoint)).findFirst().orElse(null);
return !isSinkForSource(mcastIp, other, source);
}).findFirst().orElse(null);
if (sinkToBeProcessed != null) {
sinksToBeProcessed.add(sinkToBeProcessed);
return;
}
// Otherwise we prefer a location co-located with the source (if it exists)
sinkToBeProcessed = connectPoints.stream().filter(connectPoint -> connectPoint.deviceId().equals(source.deviceId())).findFirst().orElse(null);
if (sinkToBeProcessed != null) {
sinksToBeProcessed.add(sinkToBeProcessed);
return;
}
// Finally, we randomly pick a new location if it is reachable
sinkToBeProcessed = connectPoints.stream().filter(connectPoint -> {
if (!isSinkReachable(mcastIp, connectPoint, source)) {
return false;
}
ConnectPoint other = connectPoints.stream().filter(remaining -> !remaining.equals(connectPoint)).findFirst().orElse(null);
return !isSinkForSource(mcastIp, other, source);
}).findFirst().orElse(null);
if (sinkToBeProcessed != null) {
sinksToBeProcessed.add(sinkToBeProcessed);
}
}));
return sinksToBeProcessed;
}
use of org.onlab.packet.IpAddress in project trellis-control by opennetworkinglab.
the class IpHandler method addToPacketBuffer.
/**
* Adds the IPv6 packet to a buffer.
* The packets are forwarded to corresponding destination when the destination
* MAC address is known via NDP response.
*
* @param ipPacket IP packet to add to the buffer
*/
public void addToPacketBuffer(IPv6 ipPacket) {
// Better not buffer TCP packets due to out-of-order packet transfer
if (ipPacket.getNextHeader() == IPv6.PROTOCOL_TCP) {
return;
}
IpAddress destIpAddress = IpAddress.valueOf(INET6, ipPacket.getDestinationAddress());
enqueuePacket(ipPacket, destIpAddress);
}
Aggregations