/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.ui.impl.topo.util; import org.onosproject.net.ConnectPoint; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.Link; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.intent.FlowObjectiveIntent; import org.onosproject.net.intent.FlowRuleIntent; import org.onosproject.net.intent.HostToHostIntent; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentService; import org.onosproject.net.intent.LinkCollectionIntent; import org.onosproject.net.intent.MultiPointToSinglePointIntent; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.PathIntent; import org.onosproject.net.intent.PointToPointIntent; import org.onosproject.net.link.LinkService; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import static org.onosproject.net.intent.IntentState.INSTALLED; /** * Auxiliary facility to query the intent service based on the specified * set of end-station hosts, edge points or infrastructure devices. */ public class TopoIntentFilter { private final IntentService intentService; private final LinkService linkService; /** * Creates an intent filter. * * @param services service references bundle */ public TopoIntentFilter(ServicesBundle services) { this.intentService = services.intent(); this.linkService = services.link(); } /** * Finds all path (host-to-host or point-to-point) intents that pertain * to the given hosts and devices. * * @param hosts set of hosts to query by * @param devices set of devices to query by * @param links set of links to query by * @return set of intents that 'match' all hosts, devices and links given */ public List<Intent> findPathIntents(Set<Host> hosts, Set<Device> devices, Set<Link> links) { // start with all intents Iterable<Intent> sourceIntents = intentService.getIntents(); // Derive from this the set of edge connect points. Set<ConnectPoint> edgePoints = getEdgePoints(hosts); // Iterate over all intents and produce a set that contains only those // intents that target all selected hosts or derived edge connect points. return getIntents(hosts, devices, links, edgePoints, sourceIntents); } // Produces a set of edge points from the specified set of hosts. private Set<ConnectPoint> getEdgePoints(Set<Host> hosts) { Set<ConnectPoint> edgePoints = new HashSet<>(); for (Host host : hosts) { edgePoints.add(host.location()); } return edgePoints; } // Produces a list of intents that target all selected hosts, devices, links or connect points. private List<Intent> getIntents(Set<Host> hosts, Set<Device> devices, Set<Link> links, Set<ConnectPoint> edgePoints, Iterable<Intent> sourceIntents) { List<Intent> intents = new ArrayList<>(); if (hosts.isEmpty() && devices.isEmpty() && links.isEmpty()) { return intents; } Set<OpticalConnectivityIntent> opticalIntents = new HashSet<>(); // Search through all intents and see if they are relevant to our search. for (Intent intent : sourceIntents) { if (intentService.getIntentState(intent.key()) == INSTALLED) { boolean isRelevant = false; if (intent instanceof HostToHostIntent) { isRelevant = isIntentRelevantToHosts((HostToHostIntent) intent, hosts) && isIntentRelevantToDevices(intent, devices) && isIntentRelevantToLinks(intent, links); } else if (intent instanceof PointToPointIntent) { isRelevant = isIntentRelevant((PointToPointIntent) intent, edgePoints) && isIntentRelevantToDevices(intent, devices) && isIntentRelevantToLinks(intent, links); } else if (intent instanceof MultiPointToSinglePointIntent) { isRelevant = isIntentRelevant((MultiPointToSinglePointIntent) intent, edgePoints) && isIntentRelevantToDevices(intent, devices) && isIntentRelevantToLinks(intent, links); } else if (intent instanceof OpticalConnectivityIntent) { opticalIntents.add((OpticalConnectivityIntent) intent); } // TODO: add other intents, e.g. SinglePointToMultiPointIntent if (isRelevant) { intents.add(intent); } } } // As a second pass, try to link up any optical intents with the // packet-level ones. for (OpticalConnectivityIntent intent : opticalIntents) { if (isIntentRelevant(intent, intents) && isIntentRelevantToDevices(intent, devices)) { intents.add(intent); } } return intents; } // Indicates whether the specified intent involves all of the given hosts. private boolean isIntentRelevantToHosts(HostToHostIntent intent, Iterable<Host> hosts) { for (Host host : hosts) { HostId id = host.id(); // Bail if intent does not involve this host. if (!id.equals(intent.one()) && !id.equals(intent.two())) { return false; } } return true; } // Indicates whether the specified intent involves all of the given devices. private boolean isIntentRelevantToDevices(Intent intent, Iterable<Device> devices) { List<Intent> installables = intentService.getInstallableIntents(intent.key()); for (Device device : devices) { if (!isIntentRelevantToDevice(installables, device)) { return false; } } return true; } // Indicates whether the specified intent involves all of the given links. private boolean isIntentRelevantToLinks(Intent intent, Iterable<Link> links) { List<Intent> installables = intentService.getInstallableIntents(intent.key()); for (Link link : links) { if (!isIntentRelevantToLink(installables, link)) { return false; } } return true; } // Indicates whether the specified intent involves the given device. private boolean isIntentRelevantToDevice(List<Intent> installables, Device device) { if (installables != null) { for (Intent installable : installables) { if (installable instanceof PathIntent) { PathIntent pathIntent = (PathIntent) installable; if (pathContainsDevice(pathIntent.path().links(), device.id())) { return true; } } else if (installable instanceof FlowRuleIntent) { FlowRuleIntent flowRuleIntent = (FlowRuleIntent) installable; if (rulesContainDevice(flowRuleIntent.flowRules(), device.id())) { return true; } } else if (installable instanceof FlowObjectiveIntent) { FlowObjectiveIntent objectiveIntent = (FlowObjectiveIntent) installable; return objectiveIntent.devices().contains(device.id()); } else if (installable instanceof LinkCollectionIntent) { LinkCollectionIntent linksIntent = (LinkCollectionIntent) installable; if (pathContainsDevice(linksIntent.links(), device.id())) { return true; } } } } return false; } // Indicates whether the specified intent involves the given link. private boolean isIntentRelevantToLink(List<Intent> installables, Link link) { Link reverseLink = linkService.getLink(link.dst(), link.src()); if (installables != null) { for (Intent installable : installables) { if (installable instanceof PathIntent) { PathIntent pathIntent = (PathIntent) installable; return pathIntent.path().links().contains(link) || pathIntent.path().links().contains(reverseLink); } else if (installable instanceof FlowRuleIntent) { FlowRuleIntent flowRuleIntent = (FlowRuleIntent) installable; return flowRuleIntent.resources().contains(link) || flowRuleIntent.resources().contains(reverseLink); } else if (installable instanceof FlowObjectiveIntent) { FlowObjectiveIntent objectiveIntent = (FlowObjectiveIntent) installable; return objectiveIntent.resources().contains(link) || objectiveIntent.resources().contains(reverseLink); } else if (installable instanceof LinkCollectionIntent) { LinkCollectionIntent linksIntent = (LinkCollectionIntent) installable; return linksIntent.links().contains(link) || linksIntent.links().contains(reverseLink); } } } return false; } // Indicates whether the specified links involve the given device. private boolean pathContainsDevice(Iterable<Link> links, DeviceId id) { for (Link link : links) { if (link.src().elementId().equals(id) || link.dst().elementId().equals(id)) { return true; } } return false; } // Indicates whether the specified flow rules involves the given device. private boolean rulesContainDevice(Collection<FlowRule> flowRules, DeviceId id) { for (FlowRule rule : flowRules) { if (rule.deviceId().equals(id)) { return true; } } return false; } private boolean isIntentRelevant(PointToPointIntent intent, Iterable<ConnectPoint> edgePoints) { for (ConnectPoint point : edgePoints) { // Bail if intent does not involve this edge point. if (!point.equals(intent.egressPoint()) && !point.equals(intent.ingressPoint())) { return false; } } return true; } // Indicates whether the specified intent involves all of the given edge points. private boolean isIntentRelevant(MultiPointToSinglePointIntent intent, Iterable<ConnectPoint> edgePoints) { for (ConnectPoint point : edgePoints) { // Bail if intent does not involve this edge point. if (!point.equals(intent.egressPoint()) && !intent.ingressPoints().contains(point)) { return false; } } return true; } // Indicates whether the specified intent involves all of the given edge points. private boolean isIntentRelevant(OpticalConnectivityIntent opticalIntent, Iterable<Intent> intents) { Link ccSrc = getFirstLink(opticalIntent.getSrc(), false); Link ccDst = getFirstLink(opticalIntent.getDst(), true); if (ccSrc == null || ccDst == null) { return false; } for (Intent intent : intents) { List<Intent> installables = intentService.getInstallableIntents(intent.key()); for (Intent installable : installables) { if (installable instanceof PathIntent) { List<Link> links = ((PathIntent) installable).path().links(); if (links.size() == 3) { Link tunnel = links.get(1); if (Objects.equals(tunnel.src(), ccSrc.src()) && Objects.equals(tunnel.dst(), ccDst.dst())) { return true; } } } } } return false; } private Link getFirstLink(ConnectPoint point, boolean ingress) { for (Link link : linkService.getLinks(point)) { if (point.equals(ingress ? link.src() : link.dst())) { return link; } } return null; } }