blob: 2cec14a3ffcdf002aebbaef0935877178e9a3309 [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.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.routing.IntentSynchronizationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* 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)
.priority(PRIORITY_OFFSET);
encap(intentBuilder, 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)
.priority(PRIORITY_OFFSET);
encap(intentBuilder, 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);
}
/**
* Adds an encapsulation constraint to the builder given, if encap is not
* equal to NONE.
*
* @param builder the intent builder
* @param encap the encapsulation type
*/
private static void encap(ConnectivityIntent.Builder builder,
EncapsulationType encap) {
if (!encap.equals(NONE)) {
builder.constraints(ImmutableList.of(
new EncapsulationConstraint(encap)));
}
}
}