blob: 7b4667b022e3b5418bb60ee9cd3b3cfa7e55a93e [file] [log] [blame]
/*
* 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;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.EncapsulationType;
import org.onosproject.net.FilteredConnectPoint;
import org.onosproject.net.Host;
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.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;
import org.onosproject.net.intent.constraint.EncapsulationConstraint;
import org.onosproject.net.intent.constraint.PartialFailureConstraint;
import org.onosproject.routing.IntentSynchronizationService;
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 static org.onosproject.net.EncapsulationType.*;
/**
* 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 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 SEPARATOR = "-";
private final ApplicationId appId;
private final IntentSynchronizationService intentSynchronizer;
private final IntentService intentService;
public static final ImmutableList<Constraint> PARTIAL_FAILURE_CONSTRAINT =
ImmutableList.of(new PartialFailureConstraint());
/**
* 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;
}
/**
* Requests to install the intents passed as argument to the Intent Service.
*
* @param intents intents to be submitted
*/
protected void submitIntents(Collection<Intent> intents) {
log.debug(SUBMIT);
intents.forEach(intentSynchronizer::submit);
}
/**
* Requests to withdraw the intents passed as argument to the Intent Service.
*
* @param intents intents to be withdraw
*/
protected void withdrawIntents(Collection<Intent> intents) {
log.debug(WITHDRAW);
intents.forEach(intentSynchronizer::withdraw);
}
/**
* Returns list of intents belongs to a VPLS.
*
* @param name the name of the VPLS
* @return the list of intents belonging 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
* @param encap the encapsulation type
* @return the generated single-point to multi-point intent
*/
protected SinglePointToMultiPointIntent buildBrcIntent(Key key,
FilteredConnectPoint src,
Set<FilteredConnectPoint> dsts,
EncapsulationType encap) {
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);
setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);
return intentBuilder.build();
}
/**
* Builds a unicast intent.
*
* @param key key to identify the intent
* @param srcs the source Connect Points
* @param dst the destination Connect Point
* @param host destination Host
* @param encap the encapsulation type
* @return the generated multi-point to single-point intent
*/
protected MultiPointToSinglePointIntent buildUniIntent(Key key,
Set<FilteredConnectPoint> srcs,
FilteredConnectPoint dst,
Host host,
EncapsulationType encap) {
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);
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
* @return the key to identify the intent
*/
protected Key buildKey(String prefix,
ConnectPoint cPoint,
String vplsName,
MacAddress hostMac) {
String keyString = vplsName +
SEPARATOR +
prefix +
SEPARATOR +
cPoint.deviceId() +
SEPARATOR +
cPoint.port() +
SEPARATOR +
hostMac;
return Key.of(keyString, appId);
}
/**
* Returns true if the specified intent exists; false otherwise.
*
* @param intentKey the intent key
* @return true if the intent exists; false otherwise
*/
protected boolean intentExists(Key intentKey) {
if (intentService.getIntent(intentKey) == null) {
return false;
}
// Intent does not exist if intent withdrawn
IntentState currentIntentState = intentService.getIntentState(intentKey);
return !WITHDRAWN_INTENT_STATES.contains(currentIntentState);
}
/**
* 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));
}
}