| package org.onosproject.vpls; |
| |
| import com.google.common.collect.SetMultimap; |
| import javafx.util.Pair; |
| import org.onlab.packet.MacAddress; |
| import org.onlab.packet.VlanId; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.net.ConnectPoint; |
| import org.onosproject.net.flow.DefaultTrafficSelector; |
| import org.onosproject.net.flow.DefaultTrafficTreatment; |
| import org.onosproject.net.flow.TrafficSelector; |
| import org.onosproject.net.flow.TrafficTreatment; |
| import org.onosproject.net.intent.Intent; |
| import org.onosproject.net.intent.IntentService; |
| import org.onosproject.net.intent.Key; |
| import org.onosproject.net.intent.MultiPointToSinglePointIntent; |
| import org.onosproject.net.intent.SinglePointToMultiPointIntent; |
| import org.onosproject.routing.IntentSynchronizationService; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| |
| /** |
| * Synchronizes intents between the in-memory intent store and the |
| * IntentService. |
| */ |
| public class IntentInstaller { |
| private static final Logger log = LoggerFactory.getLogger( |
| IntentInstaller.class); |
| |
| private static final int PRIORITY_OFFSET = 1000; |
| |
| private static final String PREFIX_BROADCAST = "brc"; |
| private static final String PREFIX_UNICAST = "uni"; |
| |
| private final ApplicationId appId; |
| private final IntentSynchronizationService intentSynchronizer; |
| private final IntentService intentService; |
| |
| /** |
| * Class constructor. |
| * |
| * @param appId the Application ID |
| * @param intentService the intent service |
| * @param intentSynchronizer the intent synchronizer service |
| */ |
| public IntentInstaller(ApplicationId appId, IntentService intentService, |
| IntentSynchronizationService intentSynchronizer) { |
| this.appId = appId; |
| this.intentService = intentService; |
| this.intentSynchronizer = intentSynchronizer; |
| } |
| |
| /** |
| * Formats the requests for creating and submit intents. |
| * Single Points to Multi Point intents are created for all the conigured |
| * Connect Points. Multi Point to Single Point intents are created for |
| * Connect Points configured that have hosts attached. |
| * |
| * @param confHostPresentCPoint A map of Connect Points with the eventual |
| * MAC address of the host attached, by VLAN |
| */ |
| protected void installIntents(SetMultimap<VlanId, |
| Pair<ConnectPoint, |
| MacAddress>> confHostPresentCPoint) { |
| List<Intent> intents = new ArrayList<>(); |
| |
| confHostPresentCPoint.asMap().keySet() |
| .forEach(vlanId -> { |
| List<Pair<ConnectPoint, MacAddress>> cPoints = |
| confHostPresentCPoint.get(vlanId).stream().collect(Collectors.toList()); |
| |
| if (cPoints != null && !cPoints.isEmpty()) { |
| for (int i = 0; i < cPoints.size(); i++) { |
| ConnectPoint src = cPoints.get(i).getKey(); |
| Set<ConnectPoint> dsts = new HashSet<>(); |
| MacAddress mac = cPoints.get(i).getValue(); |
| for (int j = 0; j < cPoints.size(); j++) { |
| ConnectPoint dst = cPoints.get(j).getKey(); |
| if (!dst.equals(src)) { |
| dsts.add(dst); |
| } |
| } |
| Key brcKey = buildKey(PREFIX_BROADCAST, src, vlanId); |
| if (intentService.getIntent(brcKey) == null) { |
| SinglePointToMultiPointIntent brcIntent = |
| buildBrcIntent(brcKey, src, dsts, vlanId); |
| intents.add(brcIntent); |
| } |
| if (mac != null && countMacInCPoints(cPoints) > 1) { |
| Key uniKey = buildKey(PREFIX_UNICAST, src, vlanId); |
| if (intentService.getIntent(uniKey) == null) { |
| MultiPointToSinglePointIntent uniIntent = |
| buildUniIntent(uniKey, |
| dsts, |
| src, |
| vlanId, |
| mac); |
| intents.add(uniIntent); |
| } |
| } |
| } |
| } |
| }); |
| submitIntents(intents); |
| } |
| |
| /** |
| * Requests to install the intents passed as argument to the Intent Service. |
| * |
| * @param intents intents to be submitted |
| */ |
| private void submitIntents(Collection<Intent> intents) { |
| log.debug("Submitting intents to the IntentSynchronizer"); |
| |
| for (Intent intent : intents) { |
| intentSynchronizer.submit(intent); |
| } |
| } |
| |
| /** |
| * Builds a Single Point to Multi Point intent. |
| * |
| * @param src The source Connect Point |
| * @param dsts The destination Connect Points |
| * @return Single Point to Multi Point intent generated. |
| */ |
| private SinglePointToMultiPointIntent buildBrcIntent(Key key, |
| ConnectPoint src, |
| Set<ConnectPoint> dsts, |
| VlanId vlanId) { |
| log.debug("Building p2mp intent from {}", src); |
| |
| SinglePointToMultiPointIntent intent; |
| |
| TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
| |
| TrafficSelector.Builder builder = DefaultTrafficSelector.builder() |
| .matchEthDst(MacAddress.BROADCAST) |
| .matchVlanId(vlanId); |
| |
| TrafficSelector selector = builder.build(); |
| |
| intent = SinglePointToMultiPointIntent.builder() |
| .appId(appId) |
| .key(key) |
| .selector(selector) |
| .treatment(treatment) |
| .ingressPoint(src) |
| .egressPoints(dsts) |
| .priority(PRIORITY_OFFSET) |
| .build(); |
| return intent; |
| } |
| |
| /** |
| * Builds a Multi Point to Single Point intent. |
| * |
| * @param srcs The source Connect Points |
| * @param dst The destination Connect Point |
| * @return Multi Point to Single Point intent generated. |
| */ |
| private MultiPointToSinglePointIntent buildUniIntent(Key key, |
| Set<ConnectPoint> srcs, |
| ConnectPoint dst, |
| VlanId vlanId, |
| MacAddress mac) { |
| log.debug("Building mp2p intent to {}", dst); |
| |
| MultiPointToSinglePointIntent intent; |
| |
| TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
| |
| TrafficSelector.Builder builder = DefaultTrafficSelector.builder() |
| .matchEthDst(mac) |
| .matchVlanId(vlanId); |
| |
| TrafficSelector selector = builder.build(); |
| |
| intent = MultiPointToSinglePointIntent.builder() |
| .appId(appId) |
| .key(key) |
| .selector(selector) |
| .treatment(treatment) |
| .ingressPoints(srcs) |
| .egressPoint(dst) |
| .priority(PRIORITY_OFFSET) |
| .build(); |
| return intent; |
| } |
| |
| /** |
| * Builds an intent Key for either for a Single Point to Multi Point or |
| * Multi Point to Single Point intent, based on a prefix that defines |
| * the type of intent, the single connection point representing the source |
| * or the destination and the vlan id representing the network. |
| * |
| * @param cPoint the source or destination connect point |
| * @param vlanId the network vlan id |
| * @param prefix prefix string |
| * @return |
| */ |
| private Key buildKey(String prefix, ConnectPoint cPoint, VlanId vlanId) { |
| String keyString = new StringBuilder() |
| .append(prefix) |
| .append("-") |
| .append(cPoint.deviceId()) |
| .append("-") |
| .append(cPoint.port()) |
| .append("-") |
| .append(vlanId) |
| .toString(); |
| |
| return Key.of(keyString, appId); |
| } |
| |
| /** |
| * Counts the number of mac addresses associated to a specific list of |
| * ConnectPoint. |
| * |
| * @param cPoints List of ConnectPoints, eventually binded to the MAC of the |
| * host attached |
| * @return number of mac addresses found. |
| */ |
| private int countMacInCPoints(List<Pair<ConnectPoint, MacAddress>> cPoints) { |
| int macFound = 0; |
| for (Pair<ConnectPoint, MacAddress> p : cPoints) { |
| if (p.getValue() != null) { |
| macFound++; |
| } |
| } |
| return macFound; |
| } |
| |
| } |