diff options
author | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
---|---|---|
committer | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
commit | 13d05bc8458758ee39cb829098241e89616717ee (patch) | |
tree | 22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java | |
parent | 6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff) |
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java')
-rw-r--r-- | framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java new file mode 100644 index 00000000..5fd1c85d --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java @@ -0,0 +1,291 @@ +/* + * Copyright 2015 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.net.intent.impl.compiler; + +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onlab.packet.EthType; +import org.onlab.packet.Ethernet; +import org.onlab.packet.VlanId; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction; +import org.onosproject.net.intent.FlowRuleIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentCompiler; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.MplsPathIntent; +import org.onosproject.net.link.LinkStore; +import org.onosproject.net.resource.link.DefaultLinkResourceRequest; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.resource.link.LinkResourceRequest; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.resource.link.MplsLabel; +import org.onosproject.net.resource.link.MplsLabelResourceAllocation; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceType; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +@Component(immediate = true) +public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentExtensionService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkResourceService resourceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkStore linkStore; + + protected ApplicationId appId; + + @Override + public List<Intent> compile(MplsPathIntent intent, List<Intent> installable, + Set<LinkResourceAllocations> resources) { + LinkResourceAllocations allocations = assignMplsLabel(intent); + List<FlowRule> rules = generateRules(intent, allocations); + + return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources())); + } + + @Activate + public void activate() { + appId = coreService.registerApplication("org.onosproject.net.intent"); + intentExtensionService.registerCompiler(MplsPathIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentExtensionService.unregisterCompiler(MplsPathIntent.class); + } + + private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) { + // TODO: do it better... Suggestions? + Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path() + .links().size() - 2); + for (int i = 1; i <= intent.path().links().size() - 2; i++) { + Link link = intent.path().links().get(i); + linkRequest.add(link); + // add the inverse link. I want that the label is reserved both for + // the direct and inverse link + linkRequest.add(linkStore.getLink(link.dst(), link.src())); + } + + LinkResourceRequest.Builder request = DefaultLinkResourceRequest + .builder(intent.id(), linkRequest).addMplsRequest(); + LinkResourceAllocations reqMpls = resourceService + .requestResources(request.build()); + return reqMpls; + } + + private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) { + for (ResourceAllocation allocation : allocations + .getResourceAllocation(link)) { + if (allocation.type() == ResourceType.MPLS_LABEL) { + return ((MplsLabelResourceAllocation) allocation).mplsLabel(); + + } + } + log.warn("MPLS label was not assigned successfully"); + return null; + } + + private List<FlowRule> generateRules(MplsPathIntent intent, + LinkResourceAllocations allocations) { + + Iterator<Link> links = intent.path().links().iterator(); + Link srcLink = links.next(); + ConnectPoint prev = srcLink.dst(); + + Link link = links.next(); + // List of flow rules to be installed + List<FlowRule> rules = new LinkedList<>(); + + // Ingress traffic + // Get the new MPLS label + MplsLabel mpls = getMplsLabel(allocations, link); + checkNotNull(mpls); + MplsLabel prevLabel = mpls; + rules.add(ingressFlow(prev.port(), link, intent, mpls)); + + prev = link.dst(); + + while (links.hasNext()) { + + link = links.next(); + + if (links.hasNext()) { + // Transit traffic + // Get the new MPLS label + mpls = getMplsLabel(allocations, link); + checkNotNull(mpls); + rules.add(transitFlow(prev.port(), link, intent, + prevLabel, mpls)); + prevLabel = mpls; + + } else { + // Egress traffic + rules.add(egressFlow(prev.port(), link, intent, + prevLabel)); + } + + prev = link.dst(); + } + return rules; + } + + private FlowRule ingressFlow(PortNumber inPort, Link link, + MplsPathIntent intent, MplsLabel label) { + + TrafficSelector.Builder ingressSelector = DefaultTrafficSelector + .builder(intent.selector()); + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); + ingressSelector.matchInPort(inPort); + + if (intent.ingressLabel().isPresent()) { + ingressSelector.matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(intent.ingressLabel().get()); + + // Swap the MPLS label + treat.setMpls(label.label()); + } else { + // Push and set the MPLS label + treat.pushMpls().setMpls(label.label()); + } + // Add the output action + treat.setOutput(link.src().port()); + + return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build()); + } + + private FlowRule transitFlow(PortNumber inPort, Link link, + MplsPathIntent intent, + MplsLabel prevLabel, + MplsLabel outLabel) { + + // Ignore the ingress Traffic Selector and use only the MPLS label + // assigned in the previous link + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(prevLabel.label()); + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); + + // Set the new label only if the label on the packet is + // different + if (!prevLabel.equals(outLabel)) { + treat.setMpls(outLabel.label()); + } + + treat.setOutput(link.src().port()); + return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build()); + } + + private FlowRule egressFlow(PortNumber inPort, Link link, + MplsPathIntent intent, + MplsLabel prevLabel) { + // egress point: either set the egress MPLS label or pop the + // MPLS label based on the intent annotations + + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(prevLabel.label()); + + // apply the intent's treatments + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent + .treatment()); + + // check if the treatement is popVlan or setVlan (rewrite), + // than selector needs to match any VlanId + for (Instruction instruct : intent.treatment().allInstructions()) { + if (instruct instanceof L2ModificationInstruction) { + L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct; + if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) { + break; + } + if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP || + l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) { + selector.matchVlanId(VlanId.ANY); + } + } + } + + if (intent.egressLabel().isPresent()) { + treat.setMpls(intent.egressLabel().get()); + } else { + treat.popMpls(outputEthType(intent.selector())); + } + treat.setOutput(link.src().port()); + return createFlowRule(intent, link.src().deviceId(), + selector.build(), treat.build()); + } + + protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId, + TrafficSelector selector, TrafficTreatment treat) { + return DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector) + .withTreatment(treat) + .withPriority(intent.priority()) + .fromApp(appId) + .makePermanent() + .build(); + } + + // if the ingress ethertype is defined, the egress traffic + // will be use that value, otherwise the IPv4 ethertype is used. + private EthType outputEthType(TrafficSelector selector) { + Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE); + if (c != null && c instanceof EthTypeCriterion) { + EthTypeCriterion ethertype = (EthTypeCriterion) c; + return ethertype.ethType(); + } else { + return EthType.EtherType.IPV4.ethType(); + } + } +} |