blob: 5b6aabf36c765a33f0adef679075d00acf3d0409 [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.openstacknetworking.switching;
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.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
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.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.openstacknetworking.AbstractVmHandler;
import org.onosproject.openstacknetworking.OpenstackSwitchingService;
import org.onosproject.openstacknetworking.RulePopulatorUtil;
import org.onosproject.openstacknode.OpenstackNodeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;
import static org.onosproject.openstacknetworking.Constants.*;
import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
/**
* Populates switching flow rules.
*/
@Service
@Component(immediate = true)
public final class OpenstackSwitchingManager extends AbstractVmHandler
implements OpenstackSwitchingService {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackNodeService nodeService;
private ApplicationId appId;
@Activate
protected void activate() {
super.activate();
appId = coreService.registerApplication(SWITCHING_APP_ID);
}
@Deactivate
protected void deactivate() {
super.deactivate();
}
private void populateSwitchingRules(Host host) {
setFlowRulesForTunnelTag(host, true);
setFlowRulesForTrafficToSameCnode(host, true);
setFlowRulesForTrafficToDifferentCnode(host, true);
log.debug("Populated switching rule for {}", host);
}
private void removeSwitchingRules(Host host) {
setFlowRulesForTunnelTag(host, false);
setFlowRulesForTrafficToSameCnode(host, false);
setFlowRulesForTrafficToDifferentCnode(host, false);
log.debug("Removed switching rule for {}", host);
}
private void setFlowRulesForTunnelTag(Host host, boolean install) {
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchInPort(host.location().port());
tBuilder.setTunnelId(Long.valueOf(getVni(host)));
RulePopulatorUtil.setRule(flowObjectiveService, appId, host.location().deviceId(),
sBuilder.build(), tBuilder.build(), ForwardingObjective.Flag.SPECIFIC,
TUNNELTAG_RULE_PRIORITY, install);
}
private void setFlowRulesForTrafficToSameCnode(Host host, boolean install) {
//For L2 Switching Case
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(getIp(host).toIpPrefix())
.matchTunnelId(Long.valueOf(getVni(host)));
// Destination setting is required for routing cases.
// We do not believe the rule would not degrade the forwarding performance.
// But, if it does, we need to move the rule in a separate routing table.
tBuilder.setEthDst(host.mac())
.setOutput(host.location().port());
RulePopulatorUtil.setRule(flowObjectiveService, appId, host.location().deviceId(),
sBuilder.build(), tBuilder.build(), ForwardingObjective.Flag.SPECIFIC,
SWITCHING_RULE_PRIORITY, install);
}
private void setFlowRulesForTrafficToDifferentCnode(Host host, boolean install) {
Ip4Address localVmIp = getIp(host);
DeviceId localDeviceId = host.location().deviceId();
Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
if (!localDataIp.isPresent()) {
log.debug("Failed to get data IP for device {}",
host.location().deviceId());
return;
}
String vni = getVni(host);
getVmsInDifferentCnode(host).forEach(remoteVm -> {
Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
if (remoteDataIp.isPresent()) {
setVxLanFlowRule(vni,
localDeviceId,
remoteDataIp.get().getIp4Address(),
getIp(remoteVm), install);
setVxLanFlowRule(vni,
remoteVm.location().deviceId(),
localDataIp.get().getIp4Address(),
localVmIp, install);
}
});
}
private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
Ip4Address vmIp, boolean install) {
Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
if (!tunnelPort.isPresent()) {
log.warn("Failed to get tunnel port from {}", deviceId);
return;
}
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchTunnelId(Long.parseLong(vni))
.matchIPDst(vmIp.toIpPrefix());
tBuilder.extension(buildExtension(deviceService, deviceId, remoteIp), deviceId)
.setOutput(tunnelPort.get());
RulePopulatorUtil.setRule(flowObjectiveService, appId, deviceId,
sBuilder.build(), tBuilder.build(), ForwardingObjective.Flag.SPECIFIC,
SWITCHING_RULE_PRIORITY, install);
}
@Override
protected void hostDetected(Host host) {
populateSwitchingRules(host);
log.info("Added new virtual machine to switching service {}", host);
}
@Override
protected void hostRemoved(Host host) {
removeSwitchingRules(host);
log.info("Removed virtual machine from switching service {}", host);
}
@Override
public void reinstallVmFlow(Host host) {
if (host == null) {
hostService.getHosts().forEach(h -> {
populateSwitchingRules(h);
log.info("Re-Install data plane flow of virtual machine {}", h);
});
} else {
populateSwitchingRules(host);
log.info("Re-Install data plane flow of virtual machine {}", host);
}
}
@Override
public void purgeVmFlow(Host host) {
if (host == null) {
hostService.getHosts().forEach(h -> {
removeSwitchingRules(h);
log.info("Purge data plane flow of virtual machine {}", h);
});
} else {
removeSwitchingRules(host);
log.info("Purge data plane flow of virtual machine {}", host);
}
}
}