use of org.onosproject.net.DeviceId in project trellis-control by opennetworkinglab.
the class RoutingRulePopulator method getMplsForwardingObjective.
/**
* Returns a Forwarding Objective builder for the MPLS rule that references
* the desired Next Objective. Creates a DestinationSet that allows the
* groupHandler to create or find the required next objective.
*
* @param targetSw the target sw
* @param nextHops the set of next hops
* @param phpRequired true if penultimate-hop-popping is required
* @param isBos true if matched label is bottom-of-stack
* @param meta metadata for creating next objective
* @param routerIp the router ip representing the destination switch
* @param destSw the destination sw
* @return the mpls forwarding objective builder
*/
private ForwardingObjective.Builder getMplsForwardingObjective(DeviceId targetSw, Set<DeviceId> nextHops, boolean phpRequired, boolean isBos, TrafficSelector meta, IpAddress routerIp, int segmentId, DeviceId destSw) {
ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
DestinationSet ds = null;
DestinationSet.DestinationSetType dstType = null;
boolean simple = false;
if (phpRequired) {
// php case - pop should always be flow-action
log.debug("getMplsForwardingObjective: php required");
tbuilder.deferred().copyTtlIn();
if (isBos) {
if (routerIp.isIp4()) {
tbuilder.deferred().popMpls(EthType.EtherType.IPV4.ethType());
} else {
tbuilder.deferred().popMpls(EthType.EtherType.IPV6.ethType());
}
tbuilder.decNwTtl();
// standard case -> BoS == True; pop results in IP packet and forwarding
// is via an ECMP group
ds = DestinationSet.createTypePopBos(destSw);
} else {
tbuilder.deferred().popMpls(EthType.EtherType.MPLS_UNICAST.ethType()).decMplsTtl();
// double-label case -> BoS == False, pop results in MPLS packet
// depending on configuration we can ECMP this packet or choose one output
ds = DestinationSet.createTypePopNotBos(destSw);
if (!srManager.getMplsEcmp()) {
simple = true;
}
}
} else {
// swap with self case - SR CONTINUE
log.debug("getMplsForwardingObjective: swap with self");
tbuilder.deferred().decMplsTtl();
// swap results in MPLS packet with same BoS bit regardless of bit value
// depending on configuration we can ECMP this packet or choose one output
// differentiate here between swap with not bos or swap with bos
ds = isBos ? DestinationSet.createTypeSwapBos(segmentId, destSw) : DestinationSet.createTypeSwapNotBos(segmentId, destSw);
if (!srManager.getMplsEcmp()) {
simple = true;
}
}
fwdBuilder.withTreatment(tbuilder.build());
log.debug("Trying to get a nextObjId for mpls rule on device:{} to ds:{}", targetSw, ds);
DefaultGroupHandler gh = srManager.getGroupHandler(targetSw);
if (gh == null) {
log.warn("getNextObjectiveId query - groupHandler for device {} " + "not found", targetSw);
return null;
}
Map<DeviceId, Set<DeviceId>> dstNextHops = new HashMap<>();
dstNextHops.put(destSw, nextHops);
int nextId = gh.getNextObjectiveId(ds, dstNextHops, meta, simple);
if (nextId <= 0) {
log.warn("No next objective in {} for ds: {}", targetSw, ds);
return null;
} else {
log.debug("nextObjId found:{} for mpls rule on device:{} to ds:{}", nextId, targetSw, ds);
}
fwdBuilder.nextStep(nextId);
return fwdBuilder;
}
use of org.onosproject.net.DeviceId in project trellis-control by opennetworkinglab.
the class RoutingRulePopulator method anyDoubleTaggedHost.
/**
* Checks if there is any double tagged host attached to given location.
* This method will match on the effective location of a host.
* That is, it will match on auxLocations when auxLocations is not null. Otherwise, it will match on locations.
*
* @param deviceId device ID
* @param portNum port number
* @return true if there is any host attached to given location.
*/
private boolean anyDoubleTaggedHost(DeviceId deviceId, PortNumber portNum) {
ConnectPoint cp = new ConnectPoint(deviceId, portNum);
Set<Host> connectedHosts = srManager.hostService.getConnectedHosts(cp, false);
Set<Host> auxConnectedHosts = srManager.hostService.getConnectedHosts(cp, true);
return !auxConnectedHosts.isEmpty() || connectedHosts.stream().anyMatch(host -> host.auxLocations() == null);
}
use of org.onosproject.net.DeviceId 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.DeviceId 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.DeviceId in project trellis-control by opennetworkinglab.
the class TopologyHandler method processTopologyChange.
/**
* Process the TOPOLOGY_CHANGE event. An initial optimization
* is performed to avoid the processing of not relevant events.
*
* @param reasons list of events that triggered topology change
*/
void processTopologyChange(List<Event> reasons) {
// Store temporary in the map all the link events,
// events having the same subject will be automatically
// overridden.
Map<Link, LinkEvent> linkEvents = Maps.newHashMap();
// Store temporary in the map all the device events,
// events having the same subject will be automatically
// overridden.
Map<DeviceId, DeviceEvent> deviceEvents = Maps.newHashMap();
// Pre-process all the events putting them in the right map
reasons.forEach(reason -> {
// Relevant events for devices
if (reason.type() == DeviceEvent.Type.DEVICE_ADDED || reason.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED || reason.type() == DeviceEvent.Type.DEVICE_UPDATED) {
// Take the event and save in the map
DeviceEvent deviceEvent = (DeviceEvent) reason;
deviceEvents.put(deviceEvent.subject().id(), deviceEvent);
// / Relevant events for links
} else if (reason.type() == LinkEvent.Type.LINK_ADDED || reason.type() == LinkEvent.Type.LINK_UPDATED || reason.type() == LinkEvent.Type.LINK_REMOVED) {
// Take the event and store the link in the map
LinkEvent linkEvent = (LinkEvent) reason;
linkEvents.put(linkEvent.subject(), linkEvent);
// Other events are not relevant
} else {
log.debug("Unhandled event type: {}", reason.type());
}
});
// Verify if the link events are valid
// before sent for mcast handling
List<LinkEvent> toProcessLinkEvent = linkEvents.values().stream().filter(this::isValid).collect(Collectors.toList());
// Verify if the device events are valid
// before sent for mcast handling
List<DeviceEvent> toProcessDeviceEvent = deviceEvents.values().stream().filter(this::isValid).collect(Collectors.toList());
// Processing part of the received events
// We don't need to process all LINK_ADDED
boolean isLinkAdded = false;
// Iterate on link events
for (LinkEvent linkEvent : toProcessLinkEvent) {
// We process just the first one
if (linkEvent.type() == LinkEvent.Type.LINK_ADDED || linkEvent.type() == LinkEvent.Type.LINK_UPDATED) {
// Other ones are skipped
if (isLinkAdded) {
continue;
}
log.info("Processing - Event: {}", linkEvent);
// First time, let's process it
isLinkAdded = true;
// McastHandler, reroute all the mcast tree
srManager.mcastHandler.init();
} else {
log.info("Processing - Event: {}", linkEvent);
// We compute each time a LINK_DOWN event
srManager.mcastHandler.processLinkDown(linkEvent.subject());
}
}
// Process all the device events
toProcessDeviceEvent.forEach(deviceEvent -> {
log.info("Processing - Event: {}", deviceEvent);
srManager.mcastHandler.processDeviceDown(deviceEvent.subject().id());
});
}
Aggregations