use of org.onosproject.net.ConnectPoint in project trellis-control by opennetworkinglab.
the class McastHandler method initInternal.
private void initInternal() {
srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> {
lastMcastChange.set(Instant.now());
log.debug("Init group {}", mcastRoute.group());
if (!mcastUtils.isLeader(mcastRoute.group())) {
log.debug("Skip {} due to lack of leadership", mcastRoute.group());
return;
}
McastRouteData mcastRouteData = srManager.multicastRouteService.routeData(mcastRoute);
// For each source process the mcast tree
srManager.multicastRouteService.sources(mcastRoute).forEach(source -> {
McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastRoute.group(), source);
Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(mcastPathStore.get(pathStoreKey), Lists.newArrayList());
Map<ConnectPoint, List<ConnectPoint>> mcastPaths = buildMcastPaths(storedPaths, mcastRoute.group(), source);
// Get all the sinks and process them
Set<ConnectPoint> sinks = processSinksToBeAdded(source, mcastRoute.group(), mcastRouteData.sinks());
// Filter out all the working sinks, we do not want to move them
// TODO we need a better way to distinguish flows coming from different sources
sinks = sinks.stream().filter(sink -> !mcastPaths.containsKey(sink) || !isSinkForSource(mcastRoute.group(), sink, source)).collect(Collectors.toSet());
if (sinks.isEmpty()) {
log.debug("Skip {} for source {} nothing to do", mcastRoute.group(), source);
return;
}
Map<ConnectPoint, List<Path>> mcasTree = mcastUtils.computeSinkMcastTree(mcastRoute.group(), source.deviceId(), sinks);
mcasTree.forEach((sink, paths) -> processSinkAddedInternal(source, sink, mcastRoute.group(), null));
});
});
}
use of org.onosproject.net.ConnectPoint 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.onosproject.net.ConnectPoint in project trellis-control by opennetworkinglab.
the class McastHandler method processPortUpdateInternal.
private void processPortUpdateInternal(Device affectedDevice, Port affectedPort) {
// Clean the filtering obj store. Edge port case.
lastMcastChange.set(Instant.now());
ConnectPoint portDown = new ConnectPoint(affectedDevice.id(), affectedPort.number());
if (!affectedPort.isEnabled()) {
log.info("Processing port down {}", portDown);
updateFilterObjStoreByPort(portDown);
}
}
use of org.onosproject.net.ConnectPoint in project trellis-control by opennetworkinglab.
the class DefaultGroupHandler method updateL3UcastGroupBucket.
/**
* Updates the next objective for the given nextId .
*
* @param hostMac mac of host for which Next obj is to be updated.
* @param hostVlanId vlan of host for which Next obj is to be updated.
* @param port port with which to update the Next Obj.
* @param nextId of Next Obj which needs to be updated.
*/
public void updateL3UcastGroupBucket(MacAddress hostMac, VlanId hostVlanId, PortNumber port, int nextId) {
MacAddress deviceMac;
try {
deviceMac = deviceConfig.getDeviceMac(deviceId);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " in updateL3UcastGroupBucket");
return;
}
ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder().deferred().setEthDst(hostMac).setEthSrc(deviceMac).setOutput(port);
if (taggedVlans.contains(hostVlanId)) {
mbuilder.matchVlanId(hostVlanId);
tbuilder.setVlanId(hostVlanId);
} else if (hostVlanId.equals(VlanId.NONE)) {
if (untaggedVlan != null) {
mbuilder.matchVlanId(untaggedVlan);
tbuilder.popVlan();
} else if (nativeVlan != null) {
mbuilder.matchVlanId(nativeVlan);
tbuilder.popVlan();
} else {
log.warn("Untagged nexthop {}/{} is not allowed on {} without untagged or native vlan", hostMac, hostVlanId, connectPoint);
return;
}
} else {
log.warn("Tagged nexthop {}/{} is not allowed on {} without VLAN listed" + " in tagged vlan", hostMac, hostVlanId, connectPoint);
return;
}
log.debug(" update L3Ucast : deviceMac {}, port {}, host {}/{}, nextid {}, Treatment {} Meta {}", deviceMac, port, hostMac, hostVlanId, nextId, tbuilder.build(), mbuilder.build());
NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder().withId(nextId).withType(NextObjective.Type.SIMPLE).fromApp(appId).addTreatment(tbuilder.build()).withMeta(mbuilder.build());
ObjectiveContext context = new DefaultObjectiveContext((objective) -> log.debug(" NextId {} successfully updated host {} vlan {} with port {}", nextId, hostMac, hostVlanId, port), (objective, error) -> {
log.warn(" NextId {} failed to update host {} vlan {} with port {}, error : {}", nextId, hostMac, hostVlanId, port, error);
srManager.invalidateNextObj(objective.id());
});
NextObjective nextObj = nextObjBuilder.modify(context);
flowObjectiveService.next(deviceId, nextObj);
}
use of org.onosproject.net.ConnectPoint in project trellis-control by opennetworkinglab.
the class LinkHandler method updateHostPorts.
/**
* Administratively enables or disables edge ports if the link that was
* added or removed was the only uplink port from an edge device. Edge ports
* that belong to dual-homed hosts are always processed. In addition,
* single-homed host ports are optionally processed depending on the
* singleHomedDown property.
*
* @param link the link to be processed
* @param added true if link was added, false if link was removed
*/
private void updateHostPorts(Link link, boolean added) {
// Topology has only a single pair of leaves
if (srManager.getInfraDeviceIds().isEmpty()) {
log.debug("No spine configured. Not updating edge port for {} {}", link, added ? "add" : "remove");
return;
}
DeviceConfiguration devConfig = srManager.deviceConfiguration;
if (added) {
try {
if (!devConfig.isEdgeDevice(link.src().deviceId()) || devConfig.isEdgeDevice(link.dst().deviceId())) {
return;
}
} catch (DeviceConfigNotFoundException e) {
log.warn("Unable to determine if link is a valid uplink" + e.getMessage());
}
// re-enable previously disabled ports on this edge-device if any
Set<PortNumber> p = downedPortStore.remove(link.src().deviceId());
if (p != null) {
log.warn("Link src {} --> dst {} added is an edge-device uplink, " + "enabling dual homed ports if any: {}", link.src().deviceId(), link.dst().deviceId(), (p.isEmpty()) ? "no ports" : p);
p.forEach(pnum -> srManager.deviceAdminService.changePortState(link.src().deviceId(), pnum, true));
}
} else {
// If the device does not have a pair device - skip
DeviceId dev = link.src().deviceId();
if (getPairDeviceIdOrNull(dev) == null) {
log.info("Device {} does not have pair device " + "not disabling access port", dev);
return;
}
// Verify if last uplink
if (!lastUplink(link)) {
return;
}
// find dual homed hosts on this dev to disable
Set<PortNumber> dp = srManager.hostHandler.getDualHomedHostPorts(dev);
log.warn("Link src {} --> dst {} removed was the last uplink, " + "disabling dual homed ports: {}", dev, link.dst().deviceId(), (dp.isEmpty()) ? "no ports" : dp);
dp.forEach(pnum -> srManager.deviceAdminService.changePortState(dev, pnum, false));
if (srManager.singleHomedDown) {
// get all configured ports and down them if they haven't already
// been downed
srManager.deviceService.getPorts(dev).stream().filter(p -> p.isEnabled() && !dp.contains(p.number())).filter(p -> srManager.interfaceService.isConfigured(new ConnectPoint(dev, p.number()))).filter(p -> !srManager.deviceConfiguration.isPairLocalPort(dev, p.number())).forEach(p -> {
log.warn("Last uplink gone src {} -> dst {} .. removing " + "configured port {}", p.number());
srManager.deviceAdminService.changePortState(dev, p.number(), false);
dp.add(p.number());
});
}
if (!dp.isEmpty()) {
// update global store
Set<PortNumber> p = downedPortStore.get(dev);
if (p == null) {
p = dp;
} else {
p.addAll(dp);
}
downedPortStore.put(link.src().deviceId(), p);
}
}
}
Aggregations