use of org.onosproject.net.PortNumber in project trellis-control by opennetworkinglab.
the class SegmentRoutingManager method updateInterface.
private void updateInterface(InterfaceConfig conf, InterfaceConfig prevConf) {
try {
Set<Interface> intfs = conf.getInterfaces();
Set<Interface> prevIntfs = prevConf.getInterfaces();
// Now we only handle one interface config at each port.
if (intfs.size() != 1 || prevIntfs.size() != 1) {
log.warn("Interface update aborted - one at a time is allowed, " + "but {} / {}(prev) received.", intfs.size(), prevIntfs.size());
return;
}
// The system is in an incoherent state, abort
if (defaultRoutingHandler == null) {
log.warn("Interface update aborted, defaultRoutingHandler is null");
return;
}
Interface intf = intfs.stream().findFirst().get();
Interface prevIntf = prevIntfs.stream().findFirst().get();
DeviceId deviceId = intf.connectPoint().deviceId();
PortNumber portNum = intf.connectPoint().port();
if (!shouldProgram(deviceId)) {
log.debug("Not leading the programming of {} skip update interface {}", deviceId, intf);
return;
}
// We need to do nexthop update al least one time for each
// interface config change. There is no difference when it is done;
boolean updateNexthop = false;
removeSubnetConfig(prevIntf.connectPoint(), Sets.difference(new HashSet<>(prevIntf.ipAddressesList()), new HashSet<>(intf.ipAddressesList())));
if (!prevIntf.vlanNative().equals(VlanId.NONE) && !prevIntf.vlanNative().equals(intf.vlanUntagged()) && !prevIntf.vlanNative().equals(intf.vlanNative())) {
if (intf.vlanTagged().contains(prevIntf.vlanNative())) {
// Update filtering objective and L2IG group bucket
updatePortVlanTreatment(deviceId, portNum, prevIntf.vlanNative(), false);
} else {
// RemoveVlanNative - affected scenarios:
// (T,N)->U; (T*,N)->U; (T,N)->(T,N); (T,N)->T
updateVlanConfigInternal(deviceId, portNum, prevIntf.vlanNative(), true, false);
// Update the nexthops of the indirect routes
updateNexthop = true;
routeEventExecutor.execute(() -> routeHandler.processIntfVlanUpdatedEvent(deviceId, portNum));
}
}
if (!prevIntf.vlanUntagged().equals(VlanId.NONE) && !prevIntf.vlanUntagged().equals(intf.vlanUntagged()) && !prevIntf.vlanUntagged().equals(intf.vlanNative())) {
if (intf.vlanTagged().contains(prevIntf.vlanUntagged())) {
// Update filtering objective and L2IG group bucket - affected scenarios:
// U->(T*,N); U->T*
updatePortVlanTreatment(deviceId, portNum, prevIntf.vlanUntagged(), false);
if (!updateNexthop) {
updateNexthop = true;
routeEventExecutor.execute(() -> routeHandler.processIntfVlanUpdatedEvent(deviceId, portNum));
}
} else {
// RemoveVlanUntagged - affected scenarios:
// U->U; U->(T,N); U->T
updateVlanConfigInternal(deviceId, portNum, prevIntf.vlanUntagged(), true, false);
if (!updateNexthop) {
updateNexthop = true;
routeEventExecutor.execute(() -> routeHandler.processIntfVlanUpdatedEvent(deviceId, portNum));
}
}
}
if (!prevIntf.vlanTagged().isEmpty() && !intf.vlanTagged().equals(prevIntf.vlanTagged())) {
// RemoveVlanTagged - affected scenarios:
// T->U; T->T; (T,N*)->U; (T,N)->(T,N)
Sets.difference(prevIntf.vlanTagged(), intf.vlanTagged()).stream().filter(i -> !intf.vlanUntagged().equals(i)).filter(i -> !intf.vlanNative().equals(i)).forEach(vlanId -> updateVlanConfigInternal(deviceId, portNum, vlanId, false, false));
}
if (!intf.vlanNative().equals(VlanId.NONE) && !prevIntf.vlanNative().equals(intf.vlanNative()) && !prevIntf.vlanUntagged().equals(intf.vlanNative())) {
if (prevIntf.vlanTagged().contains(intf.vlanNative())) {
// Update filtering objective and L2IG group bucket
updatePortVlanTreatment(deviceId, portNum, intf.vlanNative(), true);
} else {
// AddVlanNative - affected scenarios
// U->(T,N); U->(T*,N); T->(T,N)
updateVlanConfigInternal(deviceId, portNum, intf.vlanNative(), true, true);
if (!updateNexthop) {
updateNexthop = true;
routeEventExecutor.execute(() -> routeHandler.processIntfVlanUpdatedEvent(deviceId, portNum));
}
}
}
if (!intf.vlanTagged().isEmpty() && !intf.vlanTagged().equals(prevIntf.vlanTagged())) {
// AddVlanTagged - affected scenarios
// U->T; U->(T,N*); T->T; (T,N)->(T,N)
Sets.difference(intf.vlanTagged(), prevIntf.vlanTagged()).stream().filter(i -> !prevIntf.vlanUntagged().equals(i)).filter(i -> !prevIntf.vlanNative().equals(i)).forEach(vlanId -> updateVlanConfigInternal(deviceId, portNum, vlanId, false, true));
}
if (!intf.vlanUntagged().equals(VlanId.NONE) && !prevIntf.vlanUntagged().equals(intf.vlanUntagged()) && !prevIntf.vlanNative().equals(intf.vlanUntagged())) {
if (prevIntf.vlanTagged().contains(intf.vlanUntagged())) {
// Update filtering objective and L2IG group bucket - affected scenarios
// (T*,N)->U; T*->U
updatePortVlanTreatment(deviceId, portNum, intf.vlanUntagged(), true);
if (!updateNexthop) {
routeEventExecutor.execute(() -> routeHandler.processIntfVlanUpdatedEvent(deviceId, portNum));
}
} else {
// AddVlanUntagged - affected scenarios
// U->U; (T,N)->U; T->U
updateVlanConfigInternal(deviceId, portNum, intf.vlanUntagged(), true, true);
if (!updateNexthop) {
routeEventExecutor.execute(() -> routeHandler.processIntfVlanUpdatedEvent(deviceId, portNum));
}
}
}
addSubnetConfig(prevIntf.connectPoint(), Sets.difference(new HashSet<>(intf.ipAddressesList()), new HashSet<>(prevIntf.ipAddressesList())));
} catch (ConfigException e) {
log.error("Error in configuration");
}
}
use of org.onosproject.net.PortNumber in project trellis-control by opennetworkinglab.
the class SegmentRoutingManager method removeSubnetConfig.
private void removeSubnetConfig(ConnectPoint cp, Set<InterfaceIpAddress> ipAddressSet) {
Set<IpPrefix> ipPrefixSet = ipAddressSet.stream().map(InterfaceIpAddress::subnetAddress).collect(Collectors.toSet());
Set<InterfaceIpAddress> deviceIntfIpAddrs = interfaceService.getInterfaces().stream().filter(intf -> intf.connectPoint().deviceId().equals(cp.deviceId())).filter(intf -> !intf.connectPoint().equals(cp)).flatMap(intf -> intf.ipAddressesList().stream()).collect(Collectors.toSet());
// 1. Partial subnet population
// Remove routing rules for removed subnet from previous configuration,
// which does not also exist in other interfaces in the same device
Set<IpPrefix> deviceIpPrefixSet = deviceIntfIpAddrs.stream().map(InterfaceIpAddress::subnetAddress).collect(Collectors.toSet());
Set<IpPrefix> subnetsToBeRevoked = ipPrefixSet.stream().filter(ipPrefix -> !deviceIpPrefixSet.contains(ipPrefix)).collect(Collectors.toSet());
// Check if any of the subnets to be revoked is configured in the pairDevice.
// If any, repopulate the subnet with pairDevice connectPoint instead of revoking.
Optional<DeviceId> pairDevice = getPairDeviceId(cp.deviceId());
if (pairDevice.isPresent()) {
Set<IpPrefix> pairDeviceIpPrefix = getDeviceSubnetMap().get(pairDevice.get());
Set<IpPrefix> subnetsExistingInPairDevice = subnetsToBeRevoked.stream().filter(ipPrefix -> pairDeviceIpPrefix.contains(ipPrefix)).collect(Collectors.toSet());
// Update the subnets existing in pair device with pair device connect point.
if (!subnetsExistingInPairDevice.isEmpty()) {
// PortNumber of connect point is not relevant in populate subnet and hence providing as ANY.
ConnectPoint pairDeviceCp = new ConnectPoint(pairDevice.get(), PortNumber.ANY);
log.debug("Updating the subnets: {} with pairDevice connectPoint as it exists in the Pair device: {}", subnetsExistingInPairDevice, pairDeviceCp);
defaultRoutingHandler.populateSubnet(Collections.singleton(pairDeviceCp), subnetsExistingInPairDevice);
}
// Remove only the subnets that are not configured in the pairDevice.
subnetsToBeRevoked = Sets.difference(subnetsToBeRevoked, subnetsExistingInPairDevice);
}
if (!subnetsToBeRevoked.isEmpty()) {
log.debug("Removing subnets for connectPoint: {}, subnets: {}", cp, subnetsToBeRevoked);
defaultRoutingHandler.revokeSubnet(subnetsToBeRevoked, cp.deviceId());
}
// 2. Interface IP punts
// Remove IP punts for old Intf address
Set<IpAddress> deviceIpAddrs = deviceIntfIpAddrs.stream().map(InterfaceIpAddress::ipAddress).collect(Collectors.toSet());
ipAddressSet.stream().map(InterfaceIpAddress::ipAddress).filter(interfaceIpAddress -> !deviceIpAddrs.contains(interfaceIpAddress)).forEach(interfaceIpAddress -> routingRulePopulator.revokeSingleIpPunts(cp.deviceId(), interfaceIpAddress));
// 3. Host unicast routing rule
// Remove unicast routing rule
hostEventExecutor.execute(() -> hostHandler.processIntfIpUpdatedEvent(cp, ipPrefixSet, false));
}
use of org.onosproject.net.PortNumber 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.onosproject.net.PortNumber 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.onosproject.net.PortNumber in project trellis-control by opennetworkinglab.
the class McastHandler method addPortToDevice.
/**
* Adds a port to 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
*/
private void addPortToDevice(DeviceId deviceId, PortNumber port, IpAddress mcastIp, VlanId assignedVlan) {
// TODO trace
log.info("Adding {} on {}/{} and vlan {}", mcastIp, deviceId, port, assignedVlan);
McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId, assignedVlan);
ImmutableSet.Builder<PortNumber> portBuilder = ImmutableSet.builder();
NextObjective newNextObj;
if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
// First time someone request this mcast group via this device
portBuilder.add(port);
// New nextObj
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("Passing 0 as nextId for unconfigured device {}", deviceId);
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), 0).add();
} else {
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), null).add();
}
// Store the new port
mcastNextObjStore.put(mcastStoreKey, newNextObj);
// Create, store and apply the new nextObj and fwdObj
ObjectiveContext context = new DefaultObjectiveContext((objective) -> log.debug("Successfully add {} on {}/{}, vlan {}", mcastIp, deviceId, port.toLong(), assignedVlan), (objective, error) -> {
log.warn("Failed to add {} on {}/{}, vlan {}: {}", mcastIp, deviceId, port.toLong(), assignedVlan, error);
// Schedule the removal using directly the key
mcastWorker.execute(() -> mcastNextObjStore.remove(mcastStoreKey));
});
ForwardingObjective fwdObj = mcastUtils.fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(context);
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("skip next and forward flowobjective addition for device: {}", deviceId);
} else {
srManager.flowObjectiveService.next(deviceId, newNextObj);
srManager.flowObjectiveService.forward(deviceId, fwdObj);
}
} else {
// This device already serves some subscribers of this mcast group
NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
// Stop if the port is already in the nextobj
Set<PortNumber> existingPorts = mcastUtils.getPorts(nextObj.next());
if (existingPorts.contains(port)) {
log.debug("Port {}/{} already exists for {}. Abort", deviceId, port, mcastIp);
return;
}
// Let's add the port and reuse the previous one
portBuilder.addAll(existingPorts).add(port);
// Reuse previous nextObj
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), nextObj.id()).addToExisting();
// Store the final next objective and send only the difference to the driver
mcastNextObjStore.put(mcastStoreKey, newNextObj);
// Add just the new port
portBuilder = ImmutableSet.builder();
portBuilder.add(port);
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), nextObj.id()).addToExisting();
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 nextobjective/group
// the existing flow will keep pointing to the updated nextobj
srManager.flowObjectiveService.next(deviceId, newNextObj);
}
}
}
Aggregations