[ONOS-6248] VPLS refactoring
Change-Id: I8ffb2199ca108ad8dfe271681068636fc4af2a40
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/intent/VplsIntentUtility.java b/apps/vpls/src/main/java/org/onosproject/vpls/intent/VplsIntentUtility.java
new file mode 100644
index 0000000..a81a72f
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/intent/VplsIntentUtility.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2017-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.vpls.intent;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.Host;
+import org.onosproject.net.ResourceGroup;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.intent.ConnectivityIntent;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MultiPointToSinglePointIntent;
+import org.onosproject.net.intent.SinglePointToMultiPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.intent.constraint.PartialFailureConstraint;
+import org.onosproject.vpls.api.VplsData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static java.util.Objects.*;
+import static org.onosproject.net.EncapsulationType.*;
+
+/**
+ * Intent utilities for VPLS.
+ */
+public final class VplsIntentUtility {
+ private static final String SP2MP =
+ "Building sp2mp intent from {}";
+ private static final String MP2SP =
+ "Building mp2sp intent to {}";
+
+ private static final Logger log = LoggerFactory.getLogger(
+ VplsIntentUtility.class);
+
+ private static final int PRIORITY_OFFSET = 1000;
+ private static final int PRIORITY_UNI = 200;
+ private static final int PRIORITY_BRC = 100;
+
+ public static final String PREFIX_BROADCAST = "brc";
+ public static final String PREFIX_UNICAST = "uni";
+ private static final String SEPARATOR = "-";
+
+ public static final ImmutableList<Constraint> PARTIAL_FAILURE_CONSTRAINT =
+ ImmutableList.of(new PartialFailureConstraint());
+
+ private VplsIntentUtility() {
+ // Utility classes should not have a public or default constructor.
+ }
+
+ /**
+ * Builds broadcast Intents for a VPLS.
+ *
+ * @param vplsData the VPLS
+ * @param appId the application id for Intents
+ * @return broadcast Intents for the VPLS
+ */
+ public static Set<Intent> buildBrcIntents(VplsData vplsData, ApplicationId appId) {
+ Set<Interface> interfaces = vplsData.interfaces();
+
+ // At least two or more network interfaces to build broadcast Intents
+ if (interfaces.size() < 2) {
+ return ImmutableSet.of();
+ }
+ Set<Intent> brcIntents = Sets.newHashSet();
+ ResourceGroup resourceGroup = ResourceGroup.of(vplsData.name());
+
+ // Generates broadcast Intents from any network interface to other
+ // network interface from the VPLS.
+ interfaces.forEach(src -> {
+ FilteredConnectPoint srcFcp = VplsIntentUtility.buildFilteredConnectedPoint(src);
+ Set<FilteredConnectPoint> dstFcps =
+ interfaces.stream()
+ .filter(iface -> !iface.equals(src))
+ .map(VplsIntentUtility::buildFilteredConnectedPoint)
+ .collect(Collectors.toSet());
+ Key key = VplsIntentUtility.buildKey(PREFIX_BROADCAST,
+ srcFcp.connectPoint(),
+ vplsData.name(),
+ MacAddress.BROADCAST,
+ appId);
+ Intent brcIntent = buildBrcIntent(key,
+ appId,
+ srcFcp,
+ dstFcps,
+ vplsData.encapsulationType(),
+ resourceGroup);
+
+ brcIntents.add(brcIntent);
+ });
+ return brcIntents;
+ }
+
+ /**
+ * Builds a broadcast intent.
+ *
+ * @param key key to identify the intent
+ * @param appId application ID for this Intent
+ * @param src the source connect point
+ * @param dsts the destination connect points
+ * @param encap the encapsulation type
+ * @param resourceGroup resource group for this Intent
+ * @return the generated single-point to multi-point intent
+ */
+ protected static SinglePointToMultiPointIntent buildBrcIntent(Key key,
+ ApplicationId appId,
+ FilteredConnectPoint src,
+ Set<FilteredConnectPoint> dsts,
+ EncapsulationType encap,
+ ResourceGroup resourceGroup) {
+ log.debug("Building broadcast intent {} for source {}", SP2MP, src);
+
+ SinglePointToMultiPointIntent.Builder intentBuilder;
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthDst(MacAddress.BROADCAST)
+ .build();
+
+ intentBuilder = SinglePointToMultiPointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector)
+ .filteredIngressPoint(src)
+ .filteredEgressPoints(dsts)
+ .constraints(PARTIAL_FAILURE_CONSTRAINT)
+ .priority(PRIORITY_OFFSET + PRIORITY_BRC)
+ .resourceGroup(resourceGroup);
+
+ setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);
+
+ return intentBuilder.build();
+ }
+
+ /**
+ * Builds unicast Intents for a VPLS.
+ *
+ * @param vplsData the VPLS
+ * @param hosts the hosts of the VPLS
+ * @param appId application ID for Intents
+ * @return unicast Intents for the VPLS
+ */
+ public static Set<Intent> buildUniIntents(VplsData vplsData, Set<Host> hosts, ApplicationId appId) {
+ Set<Interface> interfaces = vplsData.interfaces();
+ if (interfaces.size() < 2) {
+ return ImmutableSet.of();
+ }
+ Set<Intent> uniIntents = Sets.newHashSet();
+ ResourceGroup resourceGroup = ResourceGroup.of(vplsData.name());
+ hosts.forEach(host -> {
+ FilteredConnectPoint hostFcp = buildFilteredConnectedPoint(host);
+ Set<FilteredConnectPoint> srcFcps =
+ interfaces.stream()
+ .map(VplsIntentUtility::buildFilteredConnectedPoint)
+ .filter(fcp -> !fcp.equals(hostFcp))
+ .collect(Collectors.toSet());
+ Key key = buildKey(PREFIX_UNICAST,
+ hostFcp.connectPoint(),
+ vplsData.name(),
+ host.mac(),
+ appId);
+ Intent uniIntent = buildUniIntent(key,
+ appId,
+ srcFcps,
+ hostFcp,
+ host,
+ vplsData.encapsulationType(),
+ resourceGroup);
+ uniIntents.add(uniIntent);
+ });
+
+ return uniIntents;
+ }
+
+ /**
+ * Builds a unicast intent.
+ *
+ * @param key key to identify the intent
+ * @param appId application ID for this Intent
+ * @param srcs the source Connect Points
+ * @param dst the destination Connect Point
+ * @param host destination Host
+ * @param encap the encapsulation type
+ * @param resourceGroup resource group for this Intent
+ * @return the generated multi-point to single-point intent
+ */
+ protected static MultiPointToSinglePointIntent buildUniIntent(Key key,
+ ApplicationId appId,
+ Set<FilteredConnectPoint> srcs,
+ FilteredConnectPoint dst,
+ Host host,
+ EncapsulationType encap,
+ ResourceGroup resourceGroup) {
+ log.debug("Building unicast intent {} for destination {}", MP2SP, dst);
+
+ MultiPointToSinglePointIntent.Builder intentBuilder;
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthDst(host.mac())
+ .build();
+
+ intentBuilder = MultiPointToSinglePointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector)
+ .filteredIngressPoints(srcs)
+ .filteredEgressPoint(dst)
+ .constraints(PARTIAL_FAILURE_CONSTRAINT)
+ .priority(PRIORITY_OFFSET + PRIORITY_UNI)
+ .resourceGroup(resourceGroup);
+
+ setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);
+
+ return intentBuilder.build();
+ }
+
+ /**
+ * Builds an intent key either for single-point to multi-point or
+ * multi-point to single-point intents, based on a prefix that defines
+ * the type of intent, the single connect point representing the single
+ * source or destination for that intent, the name of the VPLS the intent
+ * belongs to, and the destination host MAC address the intent reaches.
+ *
+ * @param prefix the key prefix
+ * @param cPoint the connect point identifying the source/destination
+ * @param vplsName the name of the VPLS
+ * @param hostMac the source/destination MAC address
+ * @param appId application ID for the key
+ * @return the key to identify the intent
+ */
+ protected static Key buildKey(String prefix,
+ ConnectPoint cPoint,
+ String vplsName,
+ MacAddress hostMac,
+ ApplicationId appId) {
+ String keyString = vplsName +
+ SEPARATOR +
+ prefix +
+ SEPARATOR +
+ cPoint.deviceId() +
+ SEPARATOR +
+ cPoint.port() +
+ SEPARATOR +
+ hostMac;
+
+ return Key.of(keyString, appId);
+ }
+
+
+ /**
+ * Sets one or more encapsulation constraints on the intent builder given.
+ *
+ * @param builder the intent builder
+ * @param constraints the existing intent constraints
+ * @param encap the encapsulation type to be set
+ */
+ public static void setEncap(ConnectivityIntent.Builder builder,
+ List<Constraint> constraints,
+ EncapsulationType encap) {
+ // Constraints might be an immutable list, so a new modifiable list
+ // is created
+ List<Constraint> newConstraints = new ArrayList<>(constraints);
+
+ // Remove any encapsulation constraint if already in the list
+ constraints.stream()
+ .filter(c -> c instanceof EncapsulationConstraint)
+ .forEach(newConstraints::remove);
+
+ // if the new encapsulation is different from NONE, a new encapsulation
+ // constraint should be added to the list
+ if (!encap.equals(NONE)) {
+ newConstraints.add(new EncapsulationConstraint(encap));
+ }
+
+ // Submit new constraint list as immutable list
+ builder.constraints(ImmutableList.copyOf(newConstraints));
+ }
+
+ /**
+ * Builds filtered connected point by a given network interface.
+ *
+ * @param iface the network interface
+ * @return the filtered connected point of a given network interface
+ */
+ protected static FilteredConnectPoint buildFilteredConnectedPoint(Interface iface) {
+ Objects.requireNonNull(iface);
+ TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
+
+ if (iface.vlan() != null && !iface.vlan().equals(VlanId.NONE)) {
+ trafficSelector.matchVlanId(iface.vlan());
+ }
+
+ return new FilteredConnectPoint(iface.connectPoint(), trafficSelector.build());
+ }
+
+ /**
+ * Builds filtered connected point by a given host.
+ *
+ * @param host the host
+ * @return the filtered connected point of the given host
+ */
+ protected static FilteredConnectPoint buildFilteredConnectedPoint(Host host) {
+ requireNonNull(host);
+ TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
+
+ if (host.vlan() != null && !host.vlan().equals(VlanId.NONE)) {
+ trafficSelector.matchVlanId(host.vlan());
+ }
+ return new FilteredConnectPoint(host.location(), trafficSelector.build());
+ }
+}
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/intent/package-info.java b/apps/vpls/src/main/java/org/onosproject/vpls/intent/package-info.java
new file mode 100644
index 0000000..197ea02
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/intent/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-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.
+ */
+
+/**
+ * Utility for generate Intent for VPLS.
+ */
+package org.onosproject.vpls.intent;
\ No newline at end of file