[ONOS-5283] Arbitrary connect points, support multiple vlans
Change-Id: I9bd3536c08dfd8a637293460395de7e2a1dc1dc1
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java b/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java
index 79ed713..52a3924 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java
@@ -15,18 +15,18 @@
*/
package org.onosproject.vpls;
-import com.google.common.collect.SetMultimap;
-import org.apache.commons.lang3.tuple.Pair;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.Host;
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.IntentState;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.SinglePointToMultiPointIntent;
@@ -34,24 +34,37 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
import java.util.Collection;
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 String SUBMIT =
+ "Submitting intents to the Intent Synchronizer";
+ private static final String WITHDRAW =
+ "Withdrawing intents to the Intent Synchronizer";
+ 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(
IntentInstaller.class);
private static final int PRIORITY_OFFSET = 1000;
- private static final String PREFIX_BROADCAST = "brc";
- private static final String PREFIX_UNICAST = "uni";
+ private static final Set<IntentState> WITHDRAWN_INTENT_STATES =
+ ImmutableSet.of(IntentState.WITHDRAWN,
+ IntentState.WITHDRAW_REQ,
+ IntentState.WITHDRAWING);
+
+ static final String PREFIX_BROADCAST = "brc";
+ static final String PREFIX_UNICAST = "uni";
+ static final String DASH = "-";
private final ApplicationId appId;
private final IntentSynchronizationService intentSynchronizer;
@@ -72,173 +85,150 @@
}
/**
- * Formats the requests for creating and submit intents.
- * Single Points to Multi Point intents are created for all the configured
- * 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.keySet()
- .stream()
- .filter(vlanId -> confHostPresentCPoint.get(vlanId) != null)
- .forEach(vlanId -> {
- Set<Pair<ConnectPoint, MacAddress>> cPoints =
- confHostPresentCPoint.get(vlanId);
- cPoints.forEach(cPoint -> {
- MacAddress mac = cPoint.getValue();
- ConnectPoint src = cPoint.getKey();
- Set<ConnectPoint> dsts = cPoints.stream()
- .map(Pair::getKey)
- .filter(cp -> !cp.equals(src))
- .collect(Collectors.toSet());
- Key brcKey = buildKey(PREFIX_BROADCAST, src, vlanId);
-
- if (dsts.isEmpty()) {
- return;
- }
-
- intents.add(buildBrcIntent(brcKey, src, dsts, vlanId));
-
- if (mac != null && countMacInCPoints(cPoints) > 1) {
- Key uniKey = buildKey(PREFIX_UNICAST, src, vlanId);
- 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 Intent Synchronizer");
- intents.forEach(intent -> {
- intentSynchronizer.submit(intent);
- });
+ protected void submitIntents(Collection<Intent> intents) {
+ log.debug(SUBMIT);
+ intents.forEach(intentSynchronizer::submit);
}
/**
- * Builds a Single Point to Multi Point intent.
+ * Requests to withdraw the intents passed as argument to the Intent Service.
*
- * @param src The source Connect Point
- * @param dsts The destination Connect Points
- * @return Single Point to Multi Point intent generated.
+ * @param intents intents to be withdraw
*/
- private SinglePointToMultiPointIntent buildBrcIntent(Key key,
- ConnectPoint src,
- Set<ConnectPoint> dsts,
- VlanId vlanId) {
- log.debug("Building p2mp intent from {}", src);
+ protected void withdrawIntents(Collection<Intent> intents) {
+ log.debug(WITHDRAW);
+ intents.forEach(intentSynchronizer::withdraw);
+ }
+
+ /**
+ * Returns list of intents belongs to a VPLS.
+ *
+ * @param name required VPLS network name
+ * @return list of intents belongs to a VPLS
+ */
+ protected List<Intent> getIntentsFromVpls(String name) {
+ List<Intent> intents = Lists.newArrayList();
+
+ intentService.getIntents().forEach(intent -> {
+ if (intent.key().toString().startsWith(name)) {
+ intents.add(intent);
+ }
+ });
+
+ return intents;
+ }
+
+ /**
+ * Builds a broadcast intent.
+ *
+ * @param key key to identify the intent
+ * @param src the source connect point
+ * @param dsts the destination connect points
+ * @return the generated single-point to multi-point intent
+ */
+ protected SinglePointToMultiPointIntent buildBrcIntent(Key key,
+ FilteredConnectPoint src,
+ Set<FilteredConnectPoint> dsts) {
+ log.debug(SP2MP, src);
SinglePointToMultiPointIntent intent;
- TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
-
- TrafficSelector.Builder builder = DefaultTrafficSelector.builder()
+ TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthDst(MacAddress.BROADCAST)
- .matchVlanId(vlanId);
-
- TrafficSelector selector = builder.build();
+ .build();
intent = SinglePointToMultiPointIntent.builder()
.appId(appId)
.key(key)
.selector(selector)
- .treatment(treatment)
- .ingressPoint(src)
- .egressPoints(dsts)
+ .filteredIngressPoint(src)
+ .filteredEgressPoints(dsts)
.priority(PRIORITY_OFFSET)
.build();
return intent;
}
/**
- * Builds a Multi Point to Single Point intent.
+ * Builds a unicast intent.
*
- * @param srcs The source Connect Points
- * @param dst The destination Connect Point
- * @return Multi Point to Single Point intent generated.
+ * @param key key to identify the intent
+ * @param srcs the source Connect Points
+ * @param dst the destination Connect Point
+ * @param host destination Host
+ * @return the generated multi-point to single-point intent
*/
- private MultiPointToSinglePointIntent buildUniIntent(Key key,
- Set<ConnectPoint> srcs,
- ConnectPoint dst,
- VlanId vlanId,
- MacAddress mac) {
- log.debug("Building mp2p intent to {}", dst);
+ protected MultiPointToSinglePointIntent buildUniIntent(Key key,
+ Set<FilteredConnectPoint> srcs,
+ FilteredConnectPoint dst,
+ Host host) {
+ log.debug(MP2SP, dst);
- MultiPointToSinglePointIntent intent;
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthDst(host.mac())
+ .build();
- TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
- TrafficSelector.Builder builder = DefaultTrafficSelector.builder()
- .matchEthDst(mac)
- .matchVlanId(vlanId);
-
- TrafficSelector selector = builder.build();
-
- intent = MultiPointToSinglePointIntent.builder()
+ return MultiPointToSinglePointIntent.builder()
.appId(appId)
.key(key)
.selector(selector)
- .treatment(treatment)
- .ingressPoints(srcs)
- .egressPoint(dst)
+ .filteredIngressPoints(srcs)
+ .filteredEgressPoint(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
+ * 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.
+ * or the destination and the VLAN identifier representing the network.
*
- * @param cPoint the source or destination connect point
- * @param vlanId the network vlan id
- * @param prefix prefix string
- * @return
+ * @param prefix key prefix
+ * @param cPoint connect point for single source/destination
+ * @param networkName VPLS network name
+ * @param hostMac source/destination mac address
+ * @return key to identify the intent
*/
- 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();
+ protected Key buildKey(String prefix,
+ ConnectPoint cPoint,
+ String networkName,
+ MacAddress hostMac) {
+ String keyString = networkName +
+ DASH +
+ prefix +
+ DASH +
+ cPoint.deviceId() +
+ DASH +
+ cPoint.port() +
+ DASH +
+ hostMac;
return Key.of(keyString, appId);
}
/**
- * Counts the number of mac addresses associated to a specific list of
- * ConnectPoint.
+ * Returns true if the specified intent exists; false otherwise.
*
- * @param cPoints Set of ConnectPoints, eventually bound to the MAC of the
- * host attached
- * @return number of mac addresses found.
+ * @param intentKey intent key
+ * @return true if the intent exists, false otherwise
*/
- private int countMacInCPoints(Set<Pair<ConnectPoint, MacAddress>> cPoints) {
- return (int) cPoints.stream().filter(p -> p.getValue() != null).count();
- }
+ protected boolean intentExists(Key intentKey) {
+ if (intentService.getIntent(intentKey) == null) {
+ return false;
+ }
+ // Intent does not exist if intent withdrawn
+ IntentState currentIntentState = intentService.getIntentState(intentKey);
+ if (WITHDRAWN_INTENT_STATES.contains(currentIntentState)) {
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java b/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java
index 2951d13..4e4bd4b 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java
@@ -15,10 +15,10 @@
*/
package org.onosproject.vpls;
-import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import com.google.common.collect.SetMultimap;
-
-import org.apache.commons.lang3.tuple.Pair;
+import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -29,29 +29,56 @@
import org.onosproject.app.ApplicationService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.incubator.net.intf.InterfaceEvent;
import org.onosproject.incubator.net.intf.InterfaceListener;
import org.onosproject.incubator.net.intf.InterfaceService;
-import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.FilteredConnectPoint;
import org.onosproject.net.Host;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
+import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
import org.onosproject.routing.IntentSynchronizationService;
+import org.onosproject.vpls.config.VplsConfigurationService;
import org.slf4j.Logger;
-import java.util.Map;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import static org.slf4j.LoggerFactory.getLogger;
+import static org.onosproject.vpls.IntentInstaller.PREFIX_BROADCAST;
+import static org.onosproject.vpls.IntentInstaller.PREFIX_UNICAST;
/**
* Application to create L2 broadcast overlay networks using VLAN.
*/
@Component(immediate = true)
public class Vpls {
- protected static final String VPLS_APP = "org.onosproject.vpls";
+ /**
+ * Application name of VPLS.
+ */
+ static final String VPLS_APP = "org.onosproject.vpls";
+
+ private static final String HOST_FCP_NOT_FOUND =
+ "Filtered connected point for host {} not found";
+ private static final String HOST_EVENT = "Received HostEvent {}";
+ private static final String INTF_CONF_EVENT =
+ "Received InterfaceConfigEvent {}";
+ private static final String NET_CONF_EVENT =
+ "Received NetworkConfigEvent {}";
private final Logger log = getLogger(getClass());
@@ -73,11 +100,20 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentSynchronizationService intentSynchronizer;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected VplsConfigurationService vplsConfigService;
+
private final HostListener hostListener = new InternalHostListener();
private final InternalInterfaceListener interfaceListener
= new InternalInterfaceListener();
+ private final InternalNetworkConfigListener configListener =
+ new InternalNetworkConfigListener();
+
private IntentInstaller intentInstaller;
private ApplicationId appId;
@@ -97,111 +133,250 @@
hostService.addListener(hostListener);
interfaceService.addListener(interfaceListener);
+ configService.addListener(configListener);
- setupConnectivity();
+ setupConnectivity(false);
log.info("Activated");
}
@Deactivate
public void deactivate() {
+ configService.removeListener(configListener);
intentSynchronizer.removeIntentsByAppId(appId);
log.info("Deactivated");
}
- protected void setupConnectivity() {
- /*
- * Parse Configuration and get Connect Point by VlanId.
- */
- SetMultimap<VlanId, ConnectPoint> confCPointsByVlan = getConfigCPoints();
+ /**
+ * Sets up connectivity for all VPLSs.
+ *
+ * @param isNetworkConfigEvent true if this function is triggered
+ * by NetworkConfigEvent; false otherwise
+ */
+ private void setupConnectivity(boolean isNetworkConfigEvent) {
+ SetMultimap<String, Interface> networkInterfaces =
+ vplsConfigService.getVplsNetworks();
- /*
- * Check that configured Connect Points have hosts attached and
- * associate their Mac Address to the Connect Points configured.
- */
- SetMultimap<VlanId, Pair<ConnectPoint, MacAddress>> confHostPresentCPoint =
- pairAvailableHosts(confCPointsByVlan);
+ Set<String> vplsAffectedByApi =
+ new HashSet<>(vplsConfigService.getVplsAffectedByApi());
- /*
- * Create and submit intents between the Connect Points.
- * Intents for broadcast between all the configured Connect Points.
- * Intents for unicast between all the configured Connect Points with
- * hosts attached.
- */
- intentInstaller.installIntents(confHostPresentCPoint);
+ if (isNetworkConfigEvent && vplsAffectedByApi.isEmpty()) {
+ vplsAffectedByApi.addAll(vplsConfigService.getOldVpls());
+ }
+ networkInterfaces.asMap().forEach((networkName, interfaces) -> {
+ Set<Host> hosts = Sets.newHashSet();
+ interfaces.forEach(intf -> {
+ // Add hosts that belongs to the specific VPLS
+ hostService.getConnectedHosts(intf.connectPoint())
+ .stream()
+ .filter(host -> host.vlan().equals(intf.vlan()))
+ .forEach(hosts::add);
+ });
+
+ setupConnectivity(networkName, interfaces, hosts,
+ vplsAffectedByApi.contains(networkName));
+ vplsAffectedByApi.remove(networkName);
+ });
+
+ if (!vplsAffectedByApi.isEmpty()) {
+ for (String networkName:vplsAffectedByApi) {
+ withdrawIntents(networkName, Lists.newArrayList());
+ }
+ }
}
/**
- * Computes the list of configured interfaces with a VLAN Id.
+ * Sets up connectivity for specific VPLS.
*
- * @return the interfaces grouped by vlan id
+ * @param networkName the VPLS name
+ * @param interfaces the interfaces that belong to the VPLS
+ * @param hosts the hosts that belong to the VPLS
+ * @param affectedByApi true if this function is triggered from the APIs;
+ * false otherwise
*/
- protected SetMultimap<VlanId, ConnectPoint> getConfigCPoints() {
- log.debug("Checking interface configuration");
+ private void setupConnectivity(String networkName,
+ Collection<Interface> interfaces,
+ Set<Host> hosts,
+ boolean affectedByApi) {
+ List<Intent> intents = Lists.newArrayList();
+ List<Key> keys = Lists.newArrayList();
+ Set<FilteredConnectPoint> fcPoints = buildFCPoints(interfaces);
- SetMultimap<VlanId, ConnectPoint> confCPointsByVlan =
- HashMultimap.create();
+ intents.addAll(buildUnicastIntents(
+ networkName, hosts, fcPoints, affectedByApi));
+ intents.addAll(buildBroadcastIntents(
+ networkName, fcPoints, affectedByApi));
- interfaceService.getInterfaces()
- .stream()
- .filter(intf -> intf.ipAddressesList().isEmpty())
- .forEach(intf -> confCPointsByVlan.put(intf.vlan(), intf.connectPoint()));
- return confCPointsByVlan;
+ if (affectedByApi) {
+ intents.forEach(intent -> keys.add(intent.key()));
+ withdrawIntents(networkName, keys);
+ }
+
+ intentInstaller.submitIntents(intents);
}
/**
- * Checks if for any ConnectPoint configured there's an host presents
- * and in case it associates them together.
+ * Withdraws intents belonging to a VPLS, given a VPLS name.
*
- * @param confCPointsByVlan the configured ConnectPoints grouped by VLAN Id
- * @return the configured ConnectPoints with eventual hosts associated.
+ * @param networkName the VPLS name
+ * @param keys the keys of the intents to be installed
*/
- protected SetMultimap<VlanId, Pair<ConnectPoint, MacAddress>> pairAvailableHosts(
- SetMultimap<VlanId, ConnectPoint> confCPointsByVlan) {
- log.debug("Binding connected hosts MAC addresses");
+ private void withdrawIntents(String networkName,
+ List<Key> keys) {
+ List<Intent> intents = Lists.newArrayList();
- SetMultimap<VlanId, Pair<ConnectPoint, MacAddress>> confHostPresentCPoint =
- HashMultimap.create();
+ intentInstaller.getIntentsFromVpls(networkName)
+ .forEach(intent -> {
+ if (!keys.contains(intent.key())) {
+ intents.add(intent);
+ }
+ });
- confCPointsByVlan.entries()
- .forEach(e -> bindMacAddr(e, confHostPresentCPoint));
-
- return confHostPresentCPoint;
+ intentInstaller.withdrawIntents(intents);
}
- // Bind VLAN Id with hosts and connect points
- private void bindMacAddr(Map.Entry<VlanId, ConnectPoint> e,
- SetMultimap<VlanId, Pair<ConnectPoint,
- MacAddress>> confHostPresentCPoint) {
- VlanId vlanId = e.getKey();
- ConnectPoint cp = e.getValue();
- Set<Host> connectedHosts = hostService.getConnectedHosts(cp);
- connectedHosts.forEach(host -> {
- if (host.vlan().equals(vlanId)) {
- confHostPresentCPoint.put(vlanId, Pair.of(cp, host.mac()));
- } else {
- confHostPresentCPoint.put(vlanId, Pair.of(cp, null));
+ /**
+ * Sets up broadcast intents between any given filtered connect point.
+ *
+ * @param networkName the VPLS name
+ * @param fcPoints the set of filtered connect points
+ * @param affectedByApi true if the function triggered from APIs;
+ * false otherwise
+ * @return the set of broadcast intents
+ */
+ private Set<Intent> buildBroadcastIntents(String networkName,
+ Set<FilteredConnectPoint> fcPoints,
+ boolean affectedByApi) {
+ Set<Intent> intents = Sets.newHashSet();
+ fcPoints.forEach(point -> {
+ Set<FilteredConnectPoint> otherPoints =
+ fcPoints.stream()
+ .filter(fcp -> !fcp.equals(point))
+ .collect(Collectors.toSet());
+
+ Key brcKey = intentInstaller.buildKey(PREFIX_BROADCAST,
+ point.connectPoint(),
+ networkName,
+ MacAddress.BROADCAST);
+
+ if ((!intentInstaller.intentExists(brcKey) || affectedByApi) &&
+ !otherPoints.isEmpty()) {
+ intents.add(intentInstaller.buildBrcIntent(brcKey,
+ point,
+ otherPoints));
}
});
- if (connectedHosts.isEmpty()) {
- confHostPresentCPoint.put(vlanId, Pair.of(cp, null));
- }
+
+ return ImmutableSet.copyOf(intents);
+ }
+
+ /**
+ * Sets up unicast intents between any given filtered connect point.
+ *
+ * @param networkName the VPLS name
+ * @param hosts the set of destination hosts
+ * @param fcPoints the set of filtered connect points
+ * @param affectedByApi true if the function triggered from APIs;
+ * false otherwise
+ * @return the set of unicast intents
+ */
+ private Set<Intent> buildUnicastIntents(String networkName,
+ Set<Host> hosts,
+ Set<FilteredConnectPoint> fcPoints,
+ boolean affectedByApi) {
+ Set<Intent> intents = Sets.newHashSet();
+ hosts.forEach(host -> {
+ FilteredConnectPoint hostPoint = getHostPoint(host, fcPoints);
+
+ if (hostPoint == null) {
+ log.warn(HOST_FCP_NOT_FOUND, host);
+ return;
+ }
+
+ Set<FilteredConnectPoint> otherPoints =
+ fcPoints.stream()
+ .filter(fcp -> !fcp.equals(hostPoint))
+ .collect(Collectors.toSet());
+
+ Key uniKey = intentInstaller.buildKey(PREFIX_UNICAST,
+ host.location(),
+ networkName,
+ host.mac());
+
+ if ((!intentInstaller.intentExists(uniKey) || affectedByApi) &&
+ !otherPoints.isEmpty()) {
+ intents.add(intentInstaller.buildUniIntent(uniKey,
+ otherPoints,
+ hostPoint,
+ host));
+ }
+ });
+
+ return ImmutableSet.copyOf(intents);
+ }
+
+ /**
+ * Finds the filtered connect point a host is attached to.
+ *
+ * @param host the target host
+ * @param fcps the filtered connected points
+ * @return null if not found; the filtered connect point otherwise
+ */
+ private FilteredConnectPoint getHostPoint(Host host,
+ Set<FilteredConnectPoint> fcps) {
+ return fcps.stream()
+ .filter(fcp -> fcp.connectPoint().equals(host.location()))
+ .filter(fcp -> {
+ VlanIdCriterion vlanCriterion =
+ (VlanIdCriterion) fcp.trafficSelector().
+ getCriterion(Criterion.Type.VLAN_VID);
+
+ return vlanCriterion != null &&
+ vlanCriterion.vlanId().equals(host.vlan());
+ })
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
+ * Computes a set of filtered connect points from a list of given interfaces.
+ *
+ * @param interfaces the interfaces to compute
+ * @return the set of filtered connect points
+ */
+ private Set<FilteredConnectPoint> buildFCPoints(Collection<Interface> interfaces) {
+ // Build all filtered connected points in the network
+ return interfaces
+ .stream()
+ .map(intf -> {
+ TrafficSelector.Builder selectorBuilder =
+ DefaultTrafficSelector.builder();
+
+ if (!intf.vlan().equals(VlanId.NONE)) {
+ selectorBuilder.matchVlanId(intf.vlan());
+ }
+
+ return new FilteredConnectPoint(intf.connectPoint(),
+ selectorBuilder.build());
+ })
+ .collect(Collectors.toSet());
}
/**
* Listener for host events.
*/
- class InternalHostListener implements HostListener {
+ private class InternalHostListener implements HostListener {
@Override
public void event(HostEvent event) {
- log.debug("Received HostEvent {}", event);
+ log.debug(HOST_EVENT, event);
switch (event.type()) {
case HOST_ADDED:
case HOST_UPDATED:
case HOST_REMOVED:
- setupConnectivity();
+ setupConnectivity(false);
break;
+
default:
break;
}
@@ -214,16 +389,39 @@
private class InternalInterfaceListener implements InterfaceListener {
@Override
public void event(InterfaceEvent event) {
- log.debug("Received InterfaceConfigEvent {}", event);
+ log.debug(INTF_CONF_EVENT, event);
switch (event.type()) {
case INTERFACE_ADDED:
case INTERFACE_UPDATED:
case INTERFACE_REMOVED:
- setupConnectivity();
+ setupConnectivity(false);
break;
+
default:
break;
}
}
}
+
+ /**
+ * Listener for VPLS configuration events.
+ */
+ private class InternalNetworkConfigListener implements NetworkConfigListener {
+ @Override
+ public void event(NetworkConfigEvent event) {
+ if (event.configClass() == VplsConfigurationService.CONFIG_CLASS) {
+ log.debug(NET_CONF_EVENT, event.configClass());
+ switch (event.type()) {
+ case CONFIG_ADDED:
+ case CONFIG_UPDATED:
+ case CONFIG_REMOVED:
+ setupConnectivity(true);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
}
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfig.java b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfig.java
new file mode 100644
index 0000000..f8323ef
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfig.java
@@ -0,0 +1,194 @@
+/*
+ * 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.vpls.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Sets;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+
+import java.util.Set;
+
+/**
+ * Configuration object for VPLS config.
+ */
+public class VplsConfig extends Config<ApplicationId> {
+ private static final String VPLS = "vplsNetworks";
+ private static final String NAME = "name";
+ private static final String INTERFACE = "interfaces";
+
+ /**
+ * Returns a set of configured VPLSs.
+ *
+ * @return set of VPLSs
+ */
+ public Set<VplsNetworkConfig> vplsNetworks() {
+ Set<VplsNetworkConfig> vpls = Sets.newHashSet();
+
+ JsonNode vplsNode = object.get(VPLS);
+
+ if (vplsNode == null) {
+ return vpls;
+ }
+
+ vplsNode.forEach(jsonNode -> {
+ Set<String> ifaces = Sets.newHashSet();
+ jsonNode.path(INTERFACE).forEach(ifacesNode ->
+ ifaces.add(ifacesNode.asText())
+ );
+
+ String name = jsonNode.get(NAME).asText();
+
+ vpls.add(new VplsNetworkConfig(name, ifaces));
+ });
+
+ return vpls;
+ }
+
+ /**
+ * Returns the VPLS configuration given a VPLS name.
+ *
+ * @param name the VPLS name
+ * @return the VPLS configuration if it exists; null otherwise
+ */
+ public VplsNetworkConfig getVplsWithName(String name) {
+ for (VplsNetworkConfig vpls : vplsNetworks()) {
+ if (vpls.name().equals(name)) {
+ return vpls;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds a VPLS to the configuration.
+ *
+ * @param name the name of the VPLS to be added
+ */
+ public void addVpls(VplsNetworkConfig name) {
+ ObjectNode vplsNode = JsonNodeFactory.instance.objectNode();
+
+ vplsNode.put(NAME, name.name());
+
+ ArrayNode ifacesNode = vplsNode.putArray(INTERFACE);
+ name.ifaces().forEach(ifacesNode::add);
+
+ ArrayNode vplsArray = vplsNetworks().isEmpty() ?
+ initVplsConfiguration() : (ArrayNode) object.get(VPLS);
+ vplsArray.add(vplsNode);
+ }
+
+ /**
+ * Removes a VPLS from the configuration.
+ *
+ * @param name the name of the VPLS to be removed
+ */
+ public void removeVpls(String name) {
+ ArrayNode vplsArray = (ArrayNode) object.get(VPLS);
+
+ for (int i = 0; i < vplsArray.size(); i++) {
+ if (vplsArray.get(i).hasNonNull(NAME) &&
+ vplsArray.get(i).get(NAME).asText().equals(name)) {
+ vplsArray.remove(i);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Finds a VPLS with a given network interface.
+ *
+ * @param iface the network interface
+ * @return the VPLS if found; null otherwise
+ */
+ public VplsNetworkConfig getVplsFromInterface(String iface) {
+ for (VplsNetworkConfig vpls : vplsNetworks()) {
+ if (vpls.isAttached(iface)) {
+ return vpls;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds a network interface to a VPLS.
+ *
+ * @param name the name of the VPLS
+ * @param iface the network interface to be added
+ */
+ public void addInterfaceToVpls(String name, String iface) {
+ JsonNode vplsNode = object.get(VPLS);
+ vplsNode.forEach(jsonNode -> {
+
+ if (hasNamedNode(jsonNode, name)) {
+ ArrayNode ifacesNode = (ArrayNode) jsonNode.get(INTERFACE);
+ for (int i = 0; i < ifacesNode.size(); i++) {
+ if (ifacesNode.get(i).asText().equals(iface)) {
+ return; // Interface already exists.
+ }
+ }
+ ifacesNode.add(iface);
+ }
+ });
+ }
+
+ /**
+ * Removes a network interface from a VPLS.
+ *
+ * @param name the name of the VPLS
+ * @param iface the network interface to be removed
+ */
+ public void removeInterfaceFromVpls(VplsNetworkConfig name, String iface) {
+ JsonNode vplsNode = object.get(VPLS);
+ vplsNode.forEach(jsonNode -> {
+ if (hasNamedNode(jsonNode, name.name())) {
+ ArrayNode ifacesNode = (ArrayNode) jsonNode.get(INTERFACE);
+ for (int i = 0; i < ifacesNode.size(); i++) {
+ if (ifacesNode.get(i).asText().equals(iface)) {
+ ifacesNode.remove(i);
+ return;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * States if a JSON node has a "name" attribute and if the value is equal to
+ * the name given.
+ *
+ * @param jsonNode the JSON node
+ * @param name the node name
+ * @return true if the JSON node has a "name" attribute with value equal to
+ * the name given; false otherwise
+ */
+ private boolean hasNamedNode(JsonNode jsonNode, String name) {
+ return jsonNode.hasNonNull(NAME) &&
+ jsonNode.get(NAME).asText().equals(name);
+ }
+
+ /**
+ * Creates an empty VPLS configuration.
+ *
+ * @return empty ArrayNode to store the VPLS configuration
+ */
+ private ArrayNode initVplsConfiguration() {
+ return object.putArray(VPLS);
+ }
+}
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfigurationService.java b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfigurationService.java
new file mode 100644
index 0000000..16cd4c4
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsConfigurationService.java
@@ -0,0 +1,120 @@
+/*
+ * 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.vpls.config;
+
+import com.google.common.collect.SetMultimap;
+import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Set;
+
+/**
+ * Provides information about the VPLS configuration.
+ */
+public interface VplsConfigurationService {
+ Class<VplsConfig> CONFIG_CLASS = VplsConfig.class;
+
+ /**
+ * Adds a VPLS to the configuration.
+ *
+ * @param name the name of the VPLS
+ * @param ifaces the interfaces associated with the VPLS
+ */
+ void addVpls(String name, Set<String> ifaces);
+
+ /**
+ * Removes a VPLS from the configuration.
+ *
+ * @param name the name of the VPLS to be removed
+ */
+ void removeVpls(String name);
+
+ /**
+ * Adds a network interface to a VPLS.
+ *
+ * @param name the name of the VPLS
+ * @param iface the network interface to be added to the VPLS
+ */
+ void addInterfaceToVpls(String name, String iface);
+
+ /**
+ * Removes a network interface from a VPLS.
+ *
+ * @param iface the network interface to be removed from the VPLS
+ */
+ void removeInterfaceFromVpls(String iface);
+
+ /**
+ * Cleans up the VPLS configuration. Removes all VPLSs.
+ */
+ void cleanVpls();
+
+ /**
+ * Retrieves the VPLS names modified from CLI.
+ *
+ * @return a set of VPLS names modified from CLI
+ */
+ Set<String> getVplsAffectedByApi();
+ // TODO Removes this function after intent framework fix race condition
+
+ /**
+ * Retrieves the interfaces from the VPLS configuration.
+ *
+ * @return a set of interfaces contained in the VPLS configuration
+ */
+ Set<Interface> getAllInterfaces();
+
+ /**
+ * Retrieves the interfaces belonging to the VPLS.
+ *
+ * @param name the name of the VPLS
+ * @return a set of interfaces belonging to the VPLS
+ */
+ Set<Interface> getVplsInterfaces(String name);
+
+ /**
+ * Retrieves all VPLS names.
+ *
+ * @return a set of VPLS names
+ */
+ Set<String> getAllVpls();
+
+ /**
+ * Retrieves all VPLS names from the old config.
+ *
+ * @return a set of VPLS names
+ */
+ Set<String> getOldVpls();
+ // TODO Removes this function after intent framework fix race condition
+
+ /**
+ * Retrieves the VPLS names and associated interfaces from the configuration.
+ *
+ * @return a map VPLS names and associated interfaces
+ */
+ SetMultimap<String, Interface> getVplsNetworks();
+
+ /**
+ * Retrieves a VPLS network given a VLAN Id and a connect point.
+ *
+ * @param vlan the VLAN Id
+ * @param connectPoint the connect point
+ * @return a map VPLS names and associated interfaces; null otherwise
+ */
+ SetMultimap<String, Interface> getVplsNetwork(VlanId vlan,
+ ConnectPoint connectPoint);
+}
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsNetworkConfig.java b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsNetworkConfig.java
new file mode 100644
index 0000000..b3c721b
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/config/VplsNetworkConfig.java
@@ -0,0 +1,88 @@
+/*
+ * 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.vpls.config;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Objects;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Configuration of a VPLS Network.
+ */
+public class VplsNetworkConfig {
+ private final String name;
+ private final Set<String> ifaces;
+
+ /**
+ * Creates a new VPLS configuration.
+ *
+ * @param name the VPLS name
+ * @param ifaces the interfaces associated with the VPLS
+ */
+ public VplsNetworkConfig(String name, Set<String> ifaces) {
+ this.name = checkNotNull(name);
+ this.ifaces = checkNotNull(ImmutableSet.copyOf(ifaces));
+ }
+
+ /**
+ * Returns the name of the VPLS.
+ *
+ * @return the name of the VPLS
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns the name of interfaces associated with the VPLS.
+ *
+ * @return a set of interface names associated with the VPLS
+ */
+ public Set<String> ifaces() {
+ return ImmutableSet.copyOf(ifaces);
+ }
+
+ /**
+ * States if a given interface is part of a VPLS.
+ *
+ * @param iface the interface attached to a VPLS
+ * @return true if the interface is associated to the VPLS; false otherwise
+ */
+ public boolean isAttached(String iface) {
+ return ifaces.stream().anyMatch(i -> i.equals(iface));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof VplsNetworkConfig) {
+ final VplsNetworkConfig that = (VplsNetworkConfig) obj;
+ return Objects.equals(this.name, that.name) &&
+ Objects.equals(this.ifaces, that.ifaces);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, ifaces);
+ }
+}
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/config/impl/VplsConfigurationImpl.java b/apps/vpls/src/main/java/org/onosproject/vpls/config/impl/VplsConfigurationImpl.java
new file mode 100644
index 0000000..e977170
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/config/impl/VplsConfigurationImpl.java
@@ -0,0 +1,335 @@
+/*
+ * 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.vpls.config.impl;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.basics.SubjectFactories;
+import org.onosproject.vpls.config.VplsConfig;
+import org.onosproject.vpls.config.VplsNetworkConfig;
+import org.onosproject.vpls.config.VplsConfigurationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Implementation of VPLSConfigurationService which reads VPLS configuration
+ * from the network configuration service.
+ */
+@Component(immediate = true)
+@Service
+public class VplsConfigurationImpl implements VplsConfigurationService {
+ private static final String VPLS_APP = "org.onosproject.vpls";
+ private static final String VPLS = "vpls";
+ private static final String EMPTY = "";
+ private static final String CONFIG_NULL = "VPLS configuration not defined";
+ private static final String APP_ID_NULL = "VPLS application ID is null";
+ private static final String CONFIG_CHANGED = "VPLS configuration changed: {}";
+ private static final String CHECK_CONFIG =
+ "Checking the interface configuration";
+ private static final String NET_CONF_EVENT =
+ "Received NetworkConfigEvent {}";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry registry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected InterfaceService interfaceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigService configService;
+
+ private final Set<String> vplsAffectedByApi = new HashSet<>();
+
+ private VplsConfig vplsConfig = new VplsConfig();
+
+ private SetMultimap<String, String> ifacesOfVpls = HashMultimap.create();
+ private SetMultimap<String, String> oldIfacesOfVpls = HashMultimap.create();
+ private SetMultimap<String, Interface> vplsNetworks = HashMultimap.create();
+
+ private final InternalNetworkConfigListener configListener =
+ new InternalNetworkConfigListener();
+
+ private ConfigFactory<ApplicationId, VplsConfig> vplsConfigFactory =
+ new ConfigFactory<ApplicationId, VplsConfig>(
+ SubjectFactories.APP_SUBJECT_FACTORY, VplsConfig.class, VPLS) {
+ @Override
+ public VplsConfig createConfig() {
+ return new VplsConfig();
+ }
+ };
+
+ private ApplicationId vplsAppId;
+
+ @Activate
+ protected void active() {
+ configService.addListener(configListener);
+ registry.registerConfigFactory(vplsConfigFactory);
+ loadConfiguration();
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactive() {
+ registry.unregisterConfigFactory(vplsConfigFactory);
+ configService.removeListener(configListener);
+ log.info("Stopped");
+ }
+
+ /**
+ * Retrieves the VPLS configuration from network configuration.
+ */
+ private void loadConfiguration() {
+ loadAppId();
+
+ vplsConfig = configService.getConfig(vplsAppId, VplsConfig.class);
+
+ if (vplsConfig == null) {
+ log.warn(CONFIG_NULL);
+ configService.addConfig(vplsAppId, VplsConfig.class);
+ return;
+ }
+
+ oldIfacesOfVpls = ifacesOfVpls;
+ ifacesOfVpls = getConfigInterfaces();
+ vplsNetworks = getConfigCPoints();
+ log.debug(CONFIG_CHANGED, ifacesOfVpls);
+ }
+
+ /**
+ * Retrieves the application identifier from core service.
+ */
+ private void loadAppId() {
+ vplsAppId = coreService.getAppId(VPLS_APP);
+ if (vplsAppId == null) {
+ log.warn(APP_ID_NULL);
+ }
+ }
+
+ /**
+ * Applies a given configuration to the VPLS application.
+ */
+ private void applyConfig(VplsConfig vplsConfig) {
+ loadAppId();
+ configService.applyConfig(vplsAppId, VplsConfig.class, vplsConfig.node());
+ }
+
+ /**
+ * Retrieves the VPLS names and associated interfaces names from the configuration.
+ *
+ * @return a map VPLS names and associated interface names
+ */
+ private SetMultimap<String, String> getConfigInterfaces() {
+ SetMultimap<String, String> confIntfByVpls =
+ HashMultimap.create();
+
+ vplsConfig.vplsNetworks().forEach(vpls -> {
+ if (vpls.ifaces().isEmpty()) {
+ confIntfByVpls.put(vpls.name(), EMPTY);
+ } else {
+ vpls.ifaces().forEach(iface -> confIntfByVpls.put(vpls.name(), iface));
+ }
+ });
+
+ return confIntfByVpls;
+ }
+
+ /**
+ * Retrieves the VPLS names and associated interfaces from the configuration.
+ *
+ * @return a map VPLS names and associated interfaces
+ */
+ private SetMultimap<String, Interface> getConfigCPoints() {
+ log.debug(CHECK_CONFIG);
+
+ SetMultimap<String, Interface> confCPointsByIntf =
+ HashMultimap.create();
+
+ ifacesOfVpls.entries().forEach(vpls -> {
+ interfaceService.getInterfaces()
+ .stream()
+ .filter(intf -> intf.ipAddressesList().isEmpty())
+ .filter(intf -> intf.name().equals(vpls.getValue()))
+ .forEach(intf -> confCPointsByIntf.put(vpls.getKey(), intf));
+ });
+
+ return confCPointsByIntf;
+ }
+
+ /**
+ * Listener for VPLS configuration events.
+ */
+ private class InternalNetworkConfigListener implements NetworkConfigListener {
+ @Override
+ public void event(NetworkConfigEvent event) {
+ if (event.configClass() == VplsConfigurationService.CONFIG_CLASS) {
+ log.debug(NET_CONF_EVENT, event.configClass());
+ switch (event.type()) {
+ case CONFIG_ADDED:
+ case CONFIG_UPDATED:
+ case CONFIG_REMOVED:
+ loadConfiguration();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void addVpls(String name, Set<String> ifaces) {
+ VplsNetworkConfig vpls;
+
+ if (ifacesOfVpls.containsKey(name)) {
+ if (ifaces.isEmpty()) {
+ return;
+ }
+
+ ifaces.forEach(iface ->
+ vplsConfig.addInterfaceToVpls(name, iface));
+ } else {
+ vpls = new VplsNetworkConfig(name, ifaces);
+ vplsConfig.addVpls(vpls);
+ }
+
+ vplsAffectedByApi.add(name);
+ applyConfig(vplsConfig);
+ }
+
+ @Override
+ public void removeVpls(String name) {
+ if (ifacesOfVpls.containsKey(name)) {
+ vplsConfig.removeVpls(name);
+ vplsAffectedByApi.add(name);
+ applyConfig(vplsConfig);
+ }
+ }
+
+ @Override
+ public void addInterfaceToVpls(String name, String iface) {
+ if (ifacesOfVpls.containsKey(name)) {
+ vplsConfig.addInterfaceToVpls(name, iface);
+ vplsAffectedByApi.add(name);
+ applyConfig(vplsConfig);
+ }
+ }
+
+ @Override
+ public void removeInterfaceFromVpls(String iface) {
+ if (ifacesOfVpls.containsValue(iface)) {
+ VplsNetworkConfig vpls = vplsConfig.getVplsFromInterface(iface);
+ vplsConfig.removeInterfaceFromVpls(vpls, iface);
+ vplsAffectedByApi.add(vpls.name());
+ applyConfig(vplsConfig);
+ }
+ }
+
+ @Override
+ public void cleanVpls() {
+ ifacesOfVpls.entries().forEach(e -> {
+ vplsConfig.removeVpls(e.getKey());
+ vplsAffectedByApi.add(e.getKey());
+ });
+ applyConfig(vplsConfig);
+ }
+
+ @Override
+ public Set<String> getVplsAffectedByApi() {
+ Set<String> vplsNames = ImmutableSet.copyOf(vplsAffectedByApi);
+
+ vplsAffectedByApi.clear();
+
+ return vplsNames;
+ }
+
+ @Override
+ public Set<Interface> getAllInterfaces() {
+ Set<Interface> allInterfaces = new HashSet<>();
+ vplsNetworks.values().forEach(allInterfaces::add);
+
+ return allInterfaces;
+ }
+
+ @Override
+ public Set<Interface> getVplsInterfaces(String name) {
+ Set<Interface> vplsInterfaces = new HashSet<>();
+ vplsNetworks.get(name).forEach(vplsInterfaces::add);
+
+ return vplsInterfaces;
+ }
+
+ @Override
+ public Set<String> getAllVpls() {
+ return ifacesOfVpls.keySet();
+ }
+
+ @Override
+ public Set<String> getOldVpls() {
+ return oldIfacesOfVpls.keySet();
+ }
+
+ @Override
+ public SetMultimap<String, Interface> getVplsNetworks() {
+ return ImmutableSetMultimap.copyOf(vplsNetworks);
+ }
+
+ @Override
+ public SetMultimap<String, Interface> getVplsNetwork(VlanId vlan,
+ ConnectPoint connectPoint) {
+ String vplsNetworkName =
+ vplsNetworks.entries().stream()
+ .filter(e -> e.getValue().connectPoint().equals(connectPoint))
+ .filter(e -> e.getValue().vlan().equals(vlan))
+ .map(e -> e.getKey())
+ .findFirst()
+ .orElse(null);
+ SetMultimap<String, Interface> result = HashMultimap.create();
+ if (vplsNetworkName != null && vplsNetworks.containsKey(vplsNetworkName)) {
+ vplsNetworks.get(vplsNetworkName)
+ .forEach(intf -> result.put(vplsNetworkName, intf));
+ return result;
+ }
+ return null;
+ }
+}
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/config/impl/package-info.java b/apps/vpls/src/main/java/org/onosproject/vpls/config/impl/package-info.java
new file mode 100644
index 0000000..3229c7b
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/config/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Configuration implementation to create L2 broadcast network using VLAN.
+ */
+package org.onosproject.vpls.config.impl;
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/config/package-info.java b/apps/vpls/src/main/java/org/onosproject/vpls/config/package-info.java
new file mode 100644
index 0000000..f080044
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/config/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Configuration to create L2 broadcast network using VLAN.
+ */
+package org.onosproject.vpls.config;