Michele Santuari
Committed by Brian O'Connor

ONOS-631 #Initial MPLS intent implementation

Change-Id: I6f906b953f06f395cc67e612648802e333c0e581
Showing 39 changed files with 1176 additions and 71 deletions
......@@ -40,6 +40,7 @@ import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MplsLabel;
import org.slf4j.Logger;
/**
......@@ -98,7 +99,7 @@ public class MPLSForwarding {
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
int inport = 1;
int outport = 2;
Integer mplsLabel = 101;
MplsLabel mplsLabel = MplsLabel.mplsLabel(101);
Integer switchNumber = uglyMap.get(device.id());
if (switchNumber == null) {
return;
......
package org.onosproject.cli.net;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.PortNumber.portNumber;
import java.util.List;
import java.util.Optional;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onlab.packet.MplsLabel;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.intent.Constraint;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.MplsIntent;
@Command(scope = "onos", name = "add-mpls-intent", description = "Installs mpls connectivity intent")
public class AddMplsIntent extends ConnectivityIntentCommand {
@Argument(index = 0, name = "ingressDevice",
description = "Ingress Device/Port Description",
required = true,
multiValued = false)
private String ingressDeviceString = null;
@Option(name = "--ingressLabel",
description = "Ingress Mpls label",
required = false,
multiValued = false)
private String ingressLabelString = "";
@Argument(index = 1, name = "egressDevice",
description = "Egress Device/Port Description",
required = true,
multiValued = false)
private String egressDeviceString = null;
@Option(name = "--egressLabel",
description = "Egress Mpls label",
required = false,
multiValued = false)
private String egressLabelString = "";
@Override
protected void execute() {
IntentService service = get(IntentService.class);
DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
ConnectPoint ingress = new ConnectPoint(ingressDeviceId,
ingressPortNumber);
Optional<MplsLabel> ingressLabel = Optional.empty();
if (!ingressLabelString.isEmpty()) {
ingressLabel = Optional
.ofNullable(MplsLabel.mplsLabel(parseInt(ingressLabelString)));
}
DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
Optional<MplsLabel> egressLabel = Optional.empty();
if (!ingressLabelString.isEmpty()) {
egressLabel = Optional
.ofNullable(MplsLabel.mplsLabel(parseInt(egressLabelString)));
}
TrafficSelector selector = buildTrafficSelector();
TrafficTreatment treatment = buildTrafficTreatment();
List<Constraint> constraints = buildConstraints();
MplsIntent intent = new MplsIntent(appId(), selector, treatment,
ingress, ingressLabel, egress,
egressLabel, constraints);
service.submit(intent);
}
/**
* Extracts the port number portion of the ConnectPoint.
*
* @param deviceString string representing the device/port
* @return port number as a string, empty string if the port is not found
*/
public static String getPortNumber(String deviceString) {
int slash = deviceString.indexOf('/');
if (slash <= 0) {
return "";
}
return deviceString.substring(slash + 1, deviceString.length());
}
/**
* Extracts the device ID portion of the ConnectPoint.
*
* @param deviceString string representing the device/port
* @return device ID string
*/
public static String getDeviceId(String deviceString) {
int slash = deviceString.indexOf('/');
if (slash <= 0) {
return "";
}
return deviceString.substring(0, slash);
}
protected Integer parseInt(String value) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException nfe) {
return null;
}
}
}
......@@ -297,6 +297,12 @@
<command>
<action class="org.onosproject.cli.net.WipeOutCommand"/>
</command>
<command>
<action class="org.onosproject.cli.net.AddMplsIntent" />
<completers>
<ref component-id="connectPointCompleter" />
</completers>
</command>
</command-bundle>
<bean id="appNameCompleter" class="org.onosproject.cli.app.ApplicationNameCompleter"/>
......
......@@ -26,6 +26,7 @@ import org.onosproject.net.flow.criteria.Criterion;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import com.google.common.base.MoreObjects;
......@@ -275,7 +276,7 @@ public final class DefaultTrafficSelector implements TrafficSelector {
}
@Override
public Builder matchMplsLabel(Integer mplsLabel) {
public Builder matchMplsLabel(MplsLabel mplsLabel) {
return add(Criteria.matchMplsLabel(mplsLabel));
}
......
......@@ -17,8 +17,10 @@ package org.onosproject.net.flow;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.core.GroupId;
import org.onosproject.net.PortNumber;
......@@ -222,12 +224,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
public Builder popMpls(short etherType) {
public Builder popMpls(Short etherType) {
return add(Instructions.popMpls(etherType));
}
@Override
public Builder setMpls(Integer mplsLabel) {
public Builder setMpls(MplsLabel mplsLabel) {
return add(Instructions.modMplsLabel(mplsLabel));
}
......
......@@ -22,6 +22,7 @@ import org.onosproject.net.flow.criteria.Criterion;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
/**
......@@ -297,7 +298,7 @@ public interface TrafficSelector {
* @param mplsLabel a MPLS label.
* @return a selection builder
*/
public Builder matchMplsLabel(Integer mplsLabel);
public Builder matchMplsLabel(MplsLabel mplsLabel);
/**
* Matches on IPv6 Extension Header pseudo-field fiags.
......
......@@ -19,9 +19,11 @@ import java.util.List;
import org.onosproject.core.GroupId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment.Builder;
import org.onosproject.net.flow.instructions.Instruction;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
/**
......@@ -155,12 +157,12 @@ public interface TrafficTreatment {
public Builder popMpls();
/**
* Pops MPLS ether type.
* Pops MPLS ether type and set the new ethertype.
*
* @param ethType Ethernet type to set
* @param etherType an ether type
* @return a treatment builder.
*/
public Builder popMpls(short ethType);
public Builder popMpls(Short etherType);
/**
* Sets the mpls label.
......@@ -168,7 +170,7 @@ public interface TrafficTreatment {
* @param mplsLabel MPLS label.
* @return a treatment builder.
*/
public Builder setMpls(Integer mplsLabel);
public Builder setMpls(MplsLabel mplsLabel);
/**
* Decrement MPLS TTL.
......@@ -199,6 +201,8 @@ public interface TrafficTreatment {
* @return traffic treatment
*/
TrafficTreatment build();
}
}
......
......@@ -18,11 +18,13 @@ package org.onosproject.net.flow.criteria;
import static com.google.common.base.MoreObjects.toStringHelper;
import java.util.Objects;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.criteria.Criterion.Type;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
/**
......@@ -338,7 +340,7 @@ public final class Criteria {
* @param mplsLabel MPLS label (20 bits)
* @return match criterion
*/
public static Criterion matchMplsLabel(int mplsLabel) {
public static Criterion matchMplsLabel(MplsLabel mplsLabel) {
return new MplsCriterion(mplsLabel);
}
......@@ -1510,15 +1512,10 @@ public final class Criteria {
*/
public static final class MplsCriterion implements Criterion {
private static final int MASK = 0xfffff;
private final int mplsLabel; // MPLS label: 20 bits
private final MplsLabel mplsLabel;
/**
* Constructor.
*
* @param mplsLabel the MPLS label to match (20 bits)
*/
public MplsCriterion(int mplsLabel) {
this.mplsLabel = mplsLabel & MASK;
public MplsCriterion(MplsLabel mplsLabel) {
this.mplsLabel = mplsLabel;
}
@Override
......@@ -1526,19 +1523,14 @@ public final class Criteria {
return Type.MPLS_LABEL;
}
/**
* Gets the MPLS label to match.
*
* @return the MPLS label to match (20 bits)
*/
public int label() {
public MplsLabel label() {
return mplsLabel;
}
@Override
public String toString() {
return toStringHelper(type().toString())
.add("label", Long.toHexString(mplsLabel)).toString();
.add("mpls", mplsLabel).toString();
}
@Override
......
......@@ -35,6 +35,7 @@ import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModTtlIns
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
/**
......@@ -132,7 +133,7 @@ public final class Instructions {
* @param mplsLabel to set.
* @return a L2 Modification
*/
public static L2ModificationInstruction modMplsLabel(Integer mplsLabel) {
public static L2ModificationInstruction modMplsLabel(MplsLabel mplsLabel) {
checkNotNull(mplsLabel, "MPLS label cannot be null");
return new ModMplsLabelInstruction(mplsLabel);
}
......
......@@ -20,6 +20,7 @@ import static com.google.common.base.MoreObjects.toStringHelper;
import java.util.Objects;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
/**
......@@ -287,14 +288,14 @@ public abstract class L2ModificationInstruction implements Instruction {
public static final class ModMplsLabelInstruction extends
L2ModificationInstruction {
private final Integer mplsLabel;
private final MplsLabel mplsLabel;
public ModMplsLabelInstruction(Integer mplsLabel) {
public ModMplsLabelInstruction(MplsLabel mplsLabel) {
this.mplsLabel = mplsLabel;
}
public Integer label() {
return mplsLabel;
return mplsLabel.toInt();
}
@Override
......@@ -304,8 +305,8 @@ public abstract class L2ModificationInstruction implements Instruction {
@Override
public String toString() {
return toStringHelper(subtype().toString())
.add("mpls", mplsLabel.intValue()).toString();
return toStringHelper(type().toString())
.add("mpls", mplsLabel).toString();
}
@Override
......
package org.onosproject.net.intent;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Link;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.intent.constraint.LinkTypeConstraint;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
/**
* Abstraction of MPLS label-switched connectivity.
*/
public class MplsIntent extends ConnectivityIntent {
private final ConnectPoint ingressPoint;
private final Optional<MplsLabel> ingressLabel;
private final ConnectPoint egressPoint;
private final Optional<MplsLabel> egressLabel;
/**
* Creates a new MPLS intent with the supplied ingress/egress
* ports and labels and with built-in link type constraint to avoid optical links.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param ingressPoint ingress port
* @param ingressLabel ingress MPLS label
* @param egressPoint egress port
* @param egressLabel egress MPLS label
* @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
*/
public MplsIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPoint,
Optional<MplsLabel> ingressLabel,
ConnectPoint egressPoint,
Optional<MplsLabel> egressLabel) {
this(appId, selector, treatment, ingressPoint, ingressLabel, egressPoint, egressLabel,
ImmutableList.of(new LinkTypeConstraint(false, Link.Type.OPTICAL)));
}
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports, labels and constraints.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param ingressPoint ingress port
* @param ingressLabel ingress MPLS label
* @param egressPoint egress port
* @param egressLabel egress MPLS label
* @param constraints optional list of constraints
* @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
*/
public MplsIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPoint,
Optional<MplsLabel> ingressLabel,
ConnectPoint egressPoint,
Optional<MplsLabel> egressLabel,
List<Constraint> constraints) {
super(appId, Collections.emptyList(), selector, treatment, constraints);
checkNotNull(ingressPoint);
checkNotNull(egressPoint);
checkArgument(!ingressPoint.equals(egressPoint),
"ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint);
checkNotNull(ingressLabel);
checkNotNull(egressLabel);
this.ingressPoint = ingressPoint;
this.ingressLabel = ingressLabel;
this.egressPoint = egressPoint;
this.egressLabel = egressLabel;
}
/**
* Constructor for serializer.
*/
protected MplsIntent() {
super();
this.ingressPoint = null;
this.ingressLabel = null;
this.egressPoint = null;
this.egressLabel = null;
}
/**
* Returns the port on which the ingress traffic should be connected to
* the egress.
*
* @return ingress switch port
*/
public ConnectPoint ingressPoint() {
return ingressPoint;
}
/**
* Returns the port on which the traffic should egress.
*
* @return egress switch port
*/
public ConnectPoint egressPoint() {
return egressPoint;
}
/**
* Returns the MPLS label which the ingress traffic should tagged.
*
* @return ingress MPLS label
*/
public Optional<MplsLabel> ingressLabel() {
return ingressLabel;
}
/**
* Returns the MPLS label which the egress traffic should tagged.
*
* @return egress MPLS label
*/
public Optional<MplsLabel> egressLabel() {
return egressLabel;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", id())
.add("appId", appId())
.add("selector", selector())
.add("treatment", treatment())
.add("ingressPoint", ingressPoint)
.add("ingressLabel", ingressLabel)
.add("egressPoint", egressPoint)
.add("egressLabel", egressLabel)
.add("constraints", constraints())
.toString();
}
}
package org.onosproject.net.intent;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.Path;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
/**
* Abstraction of explicit MPLS label-switched path.
*/
public class MplsPathIntent extends PathIntent {
private Optional<MplsLabel> ingressLabel;
private Optional<MplsLabel> egressLabel;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and using the specified explicit path.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param path traversed links
* @param ingressLabel MPLS egress label
* @param egressLabel MPLS ingress label
* @throws NullPointerException {@code path} is null
*/
public MplsPathIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment, Path path, Optional<MplsLabel> ingressLabel,
Optional<MplsLabel> egressLabel) {
this(appId, selector, treatment, path, ingressLabel, egressLabel,
Collections.emptyList());
}
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and using the specified explicit path.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param path traversed links
* @param ingressLabel MPLS egress label
* @param egressLabel MPLS ingress label
* @param constraints optional list of constraints
* @throws NullPointerException {@code path} is null
*/
public MplsPathIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment, Path path, Optional<MplsLabel> ingressLabel,
Optional<MplsLabel> egressLabel, List<Constraint> constraints) {
super(appId, selector, treatment, path, constraints);
checkNotNull(ingressLabel);
checkNotNull(egressLabel);
this.ingressLabel = ingressLabel;
this.egressLabel = egressLabel;
}
/**
* Returns the MPLS label which the ingress traffic should tagged.
*
* @return ingress MPLS label
*/
public Optional<MplsLabel> ingressLabel() {
return ingressLabel;
}
/**
* Returns the MPLS label which the egress traffic should tagged.
*
* @return egress MPLS label
*/
public Optional<MplsLabel> egressLabel() {
return egressLabel;
}
}
......@@ -117,6 +117,17 @@ public final class DefaultLinkResourceRequest implements LinkResourceRequest {
}
/**
* Adds Mpls request.
*
* @return self
*/
@Override
public Builder addMplsRequest() {
resources.add(new MplsLabelResourceRequest());
return this;
}
/**
* Adds bandwidth request with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
......
......@@ -60,6 +60,13 @@ public interface LinkResourceRequest extends ResourceRequest {
public Builder addLambdaRequest();
/**
* Adds MPLS request.
*
* @return self
*/
public Builder addMplsRequest();
/**
* Adds bandwidth request with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
......
/*
* Copyright 2014 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.resource;
import java.util.Objects;
/**
* Representation of MPLS label resource.
*/
public final class MplsLabel extends LinkResource {
private final org.onlab.packet.MplsLabel mplsLabel;
/**
* Creates a new instance with given MPLS label.
*
* @param mplsLabel MPLS Label value to be assigned
*/
public MplsLabel(int mplsLabel) {
this.mplsLabel = org.onlab.packet.MplsLabel.mplsLabel(mplsLabel);
}
/**
* Creates a new instance with given MPLS label.
*
* @param mplsLabel mplsLabel value to be assigned
* @return {@link MplsLabel} instance with given bandwidth
*/
public static MplsLabel valueOf(int mplsLabel) {
return new MplsLabel(mplsLabel);
}
/**
* Returns MPLS Label as an MPLS Label Object.
*
* @return MPLS label as an MPLS Label Object.
*/
public org.onlab.packet.MplsLabel label() {
return mplsLabel;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MplsLabel) {
MplsLabel that = (MplsLabel) obj;
return Objects.equals(this.mplsLabel, that.mplsLabel);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(this.mplsLabel);
}
@Override
public String toString() {
return String.valueOf(this.mplsLabel);
}
}
/*
* Copyright 2014 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.resource;
import com.google.common.base.MoreObjects;
import java.util.Objects;
/**
* Representation of allocated MPLS label resource.
*/
public class MplsLabelResourceAllocation extends MplsLabelResourceRequest
implements ResourceAllocation {
private final MplsLabel mplsLabel;
@Override
public ResourceType type() {
return ResourceType.MPLS_LABEL;
}
/**
* Creates a new {@link MplsLabelResourceAllocation} with {@link MplsLabel}
* object.
*
* @param mplsLabel allocated MPLS Label
*/
public MplsLabelResourceAllocation(MplsLabel mplsLabel) {
this.mplsLabel = mplsLabel;
}
/**
* Returns the MPLS label resource.
*
* @return the MPLS label resource
*/
public MplsLabel mplsLabel() {
return mplsLabel;
}
@Override
public int hashCode() {
return Objects.hash(mplsLabel);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final MplsLabelResourceAllocation other = (MplsLabelResourceAllocation) obj;
return Objects.equals(this.mplsLabel, other.mplsLabel);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("mplsLabel", mplsLabel)
.toString();
}
}
/*
* Copyright 2014 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.resource;
import com.google.common.base.MoreObjects;
/**
* Representation of a request for lambda resource.
*/
public class MplsLabelResourceRequest implements ResourceRequest {
@Override
public ResourceType type() {
return ResourceType.MPLS_LABEL;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.toString();
}
}
......@@ -28,4 +28,9 @@ public enum ResourceType {
* Bandwidth resource type.
*/
BANDWIDTH,
/**
* MPLS label resource type.
*/
MPLS_LABEL,
}
......
......@@ -28,6 +28,7 @@ import org.onosproject.net.flow.criteria.Criterion;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import com.google.common.testing.EqualsTester;
......@@ -251,7 +252,7 @@ public class DefaultTrafficSelectorTest {
assertThat(selector, hasCriterionWithType(Type.IPV6_ND_TLL));
selector = DefaultTrafficSelector.builder()
.matchMplsLabel(3).build();
.matchMplsLabel(MplsLabel.mplsLabel(3)).build();
assertThat(selector, hasCriterionWithType(Type.MPLS_LABEL));
selector = DefaultTrafficSelector.builder()
......
......@@ -20,6 +20,7 @@ import org.onosproject.net.PortNumber;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import com.google.common.testing.EqualsTester;
......@@ -186,8 +187,8 @@ public class CriteriaTest {
Criterion matchTargetLlAddr2 =
Criteria.matchIPv6NDTargetLinkLayerAddress(llMac2);
int mpls1 = 1;
int mpls2 = 2;
MplsLabel mpls1 = MplsLabel.mplsLabel(1);
MplsLabel mpls2 = MplsLabel.mplsLabel(2);
Criterion matchMpls1 = Criteria.matchMplsLabel(mpls1);
Criterion sameAsMatchMpls1 = Criteria.matchMplsLabel(mpls1);
Criterion matchMpls2 = Criteria.matchMplsLabel(mpls2);
......
......@@ -19,6 +19,7 @@ import org.junit.Test;
import org.onosproject.net.PortNumber;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import com.google.common.testing.EqualsTester;
......@@ -527,16 +528,16 @@ public class InstructionsTest {
is(not(equalTo(modIPv6FlowLabelInstruction2.hashCode()))));
}
private Instruction modMplsLabelInstruction1 = Instructions.modMplsLabel(1);
private Instruction sameAsModMplsLabelInstruction1 = Instructions.modMplsLabel(1);
private Instruction modMplsLabelInstruction2 = Instructions.modMplsLabel(2);
private Instruction modMplsLabelInstruction1 = Instructions.modMplsLabel(MplsLabel.mplsLabel(1));
private Instruction sameAsModMplsLabelInstruction1 = Instructions.modMplsLabel(MplsLabel.mplsLabel(1));
private Instruction modMplsLabelInstruction2 = Instructions.modMplsLabel(MplsLabel.mplsLabel(2));
/**
* Test the modMplsLabel method.
*/
@Test
public void testModMplsMethod() {
final Instruction instruction = Instructions.modMplsLabel(33);
final Instruction instruction = Instructions.modMplsLabel(MplsLabel.mplsLabel(33));
final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction =
checkAndConvert(instruction,
Instruction.Type.L2MODIFICATION,
......
package org.onosproject.net.intent.impl;
import static java.util.Arrays.asList;
import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultPath;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.MplsIntent;
import org.onosproject.net.intent.MplsPathIntent;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.resource.LinkResourceAllocations;
@Component(immediate = true)
public class MplsIntentCompiler extends ConnectivityIntentCompiler<MplsIntent> {
// TODO: use off-the-shell core provider ID
private static final ProviderId PID =
new ProviderId("core", "org.onosproject.core", true);
// TODO: consider whether the default cost is appropriate or not
public static final int DEFAULT_COST = 1;
@Activate
public void activate() {
intentManager.registerCompiler(MplsIntent.class, this);
}
@Deactivate
public void deactivate() {
intentManager.unregisterCompiler(MplsIntent.class);
}
@Override
public List<Intent> compile(MplsIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
ConnectPoint ingressPoint = intent.ingressPoint();
ConnectPoint egressPoint = intent.egressPoint();
if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
List<Link> links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false));
return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST), intent));
}
List<Link> links = new ArrayList<>();
Path path = getPath(intent, ingressPoint.deviceId(),
egressPoint.deviceId());
links.add(createEdgeLink(ingressPoint, true));
links.addAll(path.links());
links.add(createEdgeLink(egressPoint, false));
return asList(createPathIntent(new DefaultPath(PID, links, path.cost(),
path.annotations()), intent));
}
/**
* Creates a path intent from the specified path and original
* connectivity intent.
*
* @param path path to create an intent for
* @param intent original intent
*/
private Intent createPathIntent(Path path,
MplsIntent intent) {
return new MplsPathIntent(intent.appId(),
intent.selector(), intent.treatment(), path,
intent.ingressLabel(), intent.egressLabel(),
intent.constraints());
}
}
......@@ -49,6 +49,9 @@ import org.onosproject.net.resource.LinkResourceRequest;
import org.onosproject.net.resource.LinkResourceService;
import org.onosproject.net.resource.LinkResourceStore;
import org.onosproject.net.resource.LinkResourceStoreDelegate;
import org.onosproject.net.resource.MplsLabel;
import org.onosproject.net.resource.MplsLabelResourceAllocation;
import org.onosproject.net.resource.MplsLabelResourceRequest;
import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.ResourceRequest;
import org.onosproject.net.resource.ResourceType;
......@@ -104,6 +107,7 @@ public class LinkResourceManager implements LinkResourceService {
return lambdas;
}
/**
* Returns available lambdas on specified links.
*
......@@ -121,13 +125,36 @@ public class LinkResourceManager implements LinkResourceService {
return lambdas;
}
/**
* Returns available MPLS label on specified link.
*
* @param link the link
* @return available MPLS labels on specified link
*/
private Iterable<MplsLabel> getAvailableMplsLabels(Link link) {
Set<ResourceAllocation> resAllocs = store.getFreeResources(link);
if (resAllocs == null) {
return Collections.emptySet();
}
Set<MplsLabel> mplsLabels = new HashSet<>();
for (ResourceAllocation res : resAllocs) {
if (res.type() == ResourceType.MPLS_LABEL) {
mplsLabels.add(((MplsLabelResourceAllocation) res).mplsLabel());
}
}
return mplsLabels;
}
@Override
public LinkResourceAllocations requestResources(LinkResourceRequest req) {
// TODO Concatenate multiple bandwidth requests.
// TODO Support multiple lambda resource requests.
// TODO Throw appropriate exception.
Set<ResourceAllocation> allocs = new HashSet<>();
Map<Link, Set<ResourceAllocation>> allocsPerLink = new HashMap<>();
for (ResourceRequest r : req.resources()) {
switch (r.type()) {
case BANDWIDTH:
......@@ -144,6 +171,24 @@ public class LinkResourceManager implements LinkResourceService {
return null;
}
break;
case MPLS_LABEL:
for (Link link : req.links()) {
if (allocsPerLink.get(link) == null) {
allocsPerLink.put(link,
new HashSet<ResourceAllocation>());
}
Iterator<MplsLabel> mplsIter = getAvailableMplsLabels(link)
.iterator();
if (mplsIter.hasNext()) {
allocsPerLink.get(link)
.add(new MplsLabelResourceAllocation(mplsIter
.next()));
} else {
log.info("Failed to allocate MPLS resource.");
break;
}
}
break;
default:
break;
}
......@@ -151,7 +196,8 @@ public class LinkResourceManager implements LinkResourceService {
Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>();
for (Link link : req.links()) {
allocations.put(link, allocs);
allocations.put(link, new HashSet<ResourceAllocation>(allocs));
allocations.get(link).addAll(allocsPerLink.get(link));
}
LinkResourceAllocations result =
new DefaultLinkResourceAllocations(req, allocations);
......@@ -203,6 +249,8 @@ public class LinkResourceManager implements LinkResourceService {
case LAMBDA:
result.add(new LambdaResourceRequest());
break;
case MPLS_LABEL:
result.add(new MplsLabelResourceRequest());
default:
break;
}
......
......@@ -24,6 +24,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.core.DefaultGroupId;
......@@ -162,7 +163,7 @@ public class GroupManagerTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
......@@ -244,7 +245,7 @@ public class GroupManagerTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
......@@ -280,7 +281,7 @@ public class GroupManagerTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
buckets.remove(DefaultGroupBucket.createSelectGroupBucket(
......@@ -338,7 +339,7 @@ public class GroupManagerTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
......@@ -411,7 +412,7 @@ public class GroupManagerTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
......
package org.onosproject.net.intent.impl;
import java.util.List;
import java.util.Optional;
import org.hamcrest.Matchers;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.onlab.packet.MplsLabel;
import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentTestsMocks;
import org.onosproject.net.intent.MplsIntent;
import org.onosproject.net.intent.MplsPathIntent;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.NetTestTools.APP_ID;
import static org.onosproject.net.NetTestTools.connectPoint;
import static org.onosproject.net.PortNumber.portNumber;
import static org.onosproject.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;
/**
* Unit tests for the HostToHost intent compiler.
*/
public class MplsIntentCompilerTest extends AbstractIntentTest {
private static final ApplicationId APPID = new TestApplicationId("foo");
private TrafficSelector selector = new IntentTestsMocks.MockSelector();
private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
/**
* Creates a PointToPoint intent based on ingress and egress device Ids.
*
* @param ingressIdString string for id of ingress device
* @param egressIdString string for id of egress device
* @return PointToPointIntent for the two devices
*/
private MplsIntent makeIntent(String ingressIdString, Optional<MplsLabel> ingressLabel,
String egressIdString, Optional<MplsLabel> egressLabel) {
return new MplsIntent(APPID, selector, treatment,
connectPoint(ingressIdString, 1),
ingressLabel,
connectPoint(egressIdString, 1),
egressLabel);
}
/**
* Creates a compiler for HostToHost intents.
*
* @param hops string array describing the path hops to use when compiling
* @return HostToHost intent compiler
*/
private MplsIntentCompiler makeCompiler(String[] hops) {
MplsIntentCompiler compiler =
new MplsIntentCompiler();
compiler.pathService = new IntentTestsMocks.MockPathService(hops);
return compiler;
}
/**
* Tests a pair of devices in an 8 hop path, forward direction.
*/
@Test
public void testForwardPathCompilation() {
Optional<MplsLabel> ingressLabel = Optional.ofNullable(MplsLabel.mplsLabel(10));
Optional<MplsLabel> egressLabel = Optional.ofNullable(MplsLabel.mplsLabel(20));
MplsIntent intent = makeIntent("d1", ingressLabel, "d8", egressLabel);
assertThat(intent, is(notNullValue()));
String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
MplsIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(Matchers.notNullValue()));
assertThat(result, hasSize(1));
Intent forwardResultIntent = result.get(0);
assertThat(forwardResultIntent instanceof MplsPathIntent, is(true));
if (forwardResultIntent instanceof MplsIntent) {
MplsPathIntent forwardPathIntent = (MplsPathIntent) forwardResultIntent;
// 7 links for the hops, plus one default lnk on ingress and egress
assertThat(forwardPathIntent.path().links(), hasSize(hops.length + 1));
assertThat(forwardPathIntent.path().links(), linksHasPath("d1", "d2"));
assertThat(forwardPathIntent.path().links(), linksHasPath("d2", "d3"));
assertThat(forwardPathIntent.path().links(), linksHasPath("d3", "d4"));
assertThat(forwardPathIntent.path().links(), linksHasPath("d4", "d5"));
assertThat(forwardPathIntent.path().links(), linksHasPath("d5", "d6"));
assertThat(forwardPathIntent.path().links(), linksHasPath("d6", "d7"));
assertThat(forwardPathIntent.path().links(), linksHasPath("d7", "d8"));
assertEquals(forwardPathIntent.egressLabel(), egressLabel);
assertEquals(forwardPathIntent.ingressLabel(), ingressLabel);
}
}
/**
* Tests a pair of devices in an 8 hop path, forward direction.
*/
@Test
public void testReversePathCompilation() {
Optional<MplsLabel> ingressLabel = Optional.ofNullable(MplsLabel.mplsLabel(10));
Optional<MplsLabel> egressLabel = Optional.ofNullable(MplsLabel.mplsLabel(20));
MplsIntent intent = makeIntent("d8", ingressLabel, "d1", egressLabel);
assertThat(intent, is(notNullValue()));
String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
MplsIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(Matchers.notNullValue()));
assertThat(result, hasSize(1));
Intent reverseResultIntent = result.get(0);
assertThat(reverseResultIntent instanceof MplsPathIntent, is(true));
if (reverseResultIntent instanceof MplsIntent) {
MplsPathIntent reversePathIntent = (MplsPathIntent) reverseResultIntent;
assertThat(reversePathIntent.path().links(), hasSize(hops.length + 1));
assertThat(reversePathIntent.path().links(), linksHasPath("d2", "d1"));
assertThat(reversePathIntent.path().links(), linksHasPath("d3", "d2"));
assertThat(reversePathIntent.path().links(), linksHasPath("d4", "d3"));
assertThat(reversePathIntent.path().links(), linksHasPath("d5", "d4"));
assertThat(reversePathIntent.path().links(), linksHasPath("d6", "d5"));
assertThat(reversePathIntent.path().links(), linksHasPath("d7", "d6"));
assertThat(reversePathIntent.path().links(), linksHasPath("d8", "d7"));
assertEquals(reversePathIntent.egressLabel(), egressLabel);
assertEquals(reversePathIntent.ingressLabel(), ingressLabel);
}
}
/**
* Tests compilation of the intent which designates two different ports on the same switch.
*/
@Test
public void testSameSwitchDifferentPortsIntentCompilation() {
ConnectPoint src = new ConnectPoint(deviceId("1"), portNumber(1));
ConnectPoint dst = new ConnectPoint(deviceId("1"), portNumber(2));
MplsIntent intent = new MplsIntent(APP_ID, selector, treatment, src, Optional.empty(), dst, Optional.empty());
String[] hops = {"1"};
MplsIntentCompiler sut = makeCompiler(hops);
List<Intent> compiled = sut.compile(intent, null, null);
assertThat(compiled, hasSize(1));
assertThat(compiled.get(0), is(instanceOf(MplsPathIntent.class)));
Path path = ((MplsPathIntent) compiled.get(0)).path();
assertThat(path.links(), hasSize(2));
Link firstLink = path.links().get(0);
assertThat(firstLink, is(createEdgeLink(src, true)));
Link secondLink = path.links().get(1);
assertThat(secondLink, is(createEdgeLink(dst, false)));
}
}
......@@ -42,6 +42,8 @@ import org.onosproject.net.resource.LambdaResourceAllocation;
import org.onosproject.net.resource.LinkResourceAllocations;
import org.onosproject.net.resource.LinkResourceEvent;
import org.onosproject.net.resource.LinkResourceStore;
import org.onosproject.net.resource.MplsLabel;
import org.onosproject.net.resource.MplsLabelResourceAllocation;
import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.ResourceAllocationException;
import org.onosproject.net.resource.ResourceType;
......@@ -105,9 +107,10 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
// Link annotation key name to use as max lambda
private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
// Max MPLS labels: 2^20 – 1
private int maxMplsLabel = 0xFFFFF;
private StoreSerializer serializer;
void createTable(String tableName) {
boolean tableReady = false;
do {
......@@ -150,6 +153,9 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
if (type == ResourceType.LAMBDA) {
return getLambdaResourceCapacity(link);
}
if (type == ResourceType.MPLS_LABEL) {
return getMplsResourceCapacity();
}
return null;
}
......@@ -189,6 +195,17 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
return new BandwidthResourceAllocation(bandwidth);
}
private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
//Ignoring reserved labels of 0 through 15
for (int i = 16; i <= maxMplsLabel; i++) {
allocations.add(new MplsLabelResourceAllocation(MplsLabel
.valueOf(i)));
}
return allocations;
}
private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
for (ResourceType type : ResourceType.values()) {
......@@ -273,6 +290,34 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
free.put(type, freeL);
break;
}
case MPLS_LABEL:
{
Set<? extends ResourceAllocation> mpls = caps.get(type);
if (mpls == null || mpls.isEmpty()) {
// nothing left
break;
}
Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
for (ResourceAllocation r : mpls) {
if (r instanceof MplsLabelResourceAllocation) {
freeLabel.add((MplsLabelResourceAllocation) r);
}
}
// enumerate current allocations, removing resources
for (LinkResourceAllocations alloc : allocations) {
Set<ResourceAllocation> types = alloc
.getResourceAllocation(link);
for (ResourceAllocation a : types) {
if (a instanceof MplsLabelResourceAllocation) {
freeLabel.remove(a);
}
}
}
free.put(type, freeLabel);
break;
}
default:
break;
......@@ -298,7 +343,6 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
encodeIntentAllocations(alloc));
}
@Override
public void allocateResources(LinkResourceAllocations allocations) {
checkNotNull(allocations);
......@@ -314,7 +358,8 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
BatchWriteRequest batch = tx.build();
// log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
// log.info("Link: {}", databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
// log.info("Link: {}",
// databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
BatchWriteResult result = databaseService.batchWrite(batch);
if (!result.isSuccessful()) {
......@@ -407,6 +452,21 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
link,
lambdaAllocation.lambda().toInt()));
}
} else if (req instanceof MplsLabelResourceAllocation) {
final MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
// check if allocation should be accepted
if (!avail.contains(req)) {
// requested mpls label was not available
throw new ResourceAllocationException(
PositionalParameterStringFormatter
.format("Unable to allocate MPLS label for "
+ "link {} MPLS label is {}",
link,
mplsAllocation
.mplsLabel()
.toString()));
}
}
}
// all requests allocatable => add allocation
......@@ -466,8 +526,7 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
// Issue events to force recompilation of intents.
final List<LinkResourceAllocations> releasedResources =
ImmutableList.of(allocations);
final List<LinkResourceAllocations> releasedResources = ImmutableList.of(allocations);
return new LinkResourceEvent(
LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
releasedResources);
......@@ -485,10 +544,10 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
}
private String toLinkDbKey(LinkKey linkid) {
// introduce cache if necessary
// introduce cache if necessary
return linkid.toString();
// Note: Above is irreversible, if we need reverse conversion
// we may need something like below, due to String only limitation
// Note: Above is irreversible, if we need reverse conversion
// we may need something like below, due to String only limitation
// byte[] bytes = serializer.encode(linkid);
// StringBuilder builder = new StringBuilder(bytes.length * 4);
// boolean isFirst = true;
......
......@@ -43,6 +43,8 @@ import org.onosproject.net.resource.LambdaResourceAllocation;
import org.onosproject.net.resource.LinkResourceAllocations;
import org.onosproject.net.resource.LinkResourceEvent;
import org.onosproject.net.resource.LinkResourceStore;
import org.onosproject.net.resource.MplsLabel;
import org.onosproject.net.resource.MplsLabelResourceAllocation;
import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.ResourceAllocationException;
import org.onosproject.net.resource.ResourceType;
......@@ -103,6 +105,9 @@ public class HazelcastLinkResourceStore
// Link annotation key name to use as max lambda
private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
// Max MPLS labels: 2^20 – 1
private int maxMplsLabel = 0xFFFFF;
@Override
@Activate
public void activate() {
......@@ -141,6 +146,9 @@ public class HazelcastLinkResourceStore
if (type == ResourceType.LAMBDA) {
return getLambdaResourceCapacity(link);
}
if (type == ResourceType.MPLS_LABEL) {
return getMplsResourceCapacity();
}
return null;
}
......@@ -180,6 +188,17 @@ public class HazelcastLinkResourceStore
return new BandwidthResourceAllocation(bandwidth);
}
private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
//Ignoring reserved labels of 0 through 15
for (int i = 16; i <= maxMplsLabel; i++) {
allocations.add(new MplsLabelResourceAllocation(MplsLabel
.valueOf(i)));
}
return allocations;
}
private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
for (ResourceType type : ResourceType.values()) {
......@@ -275,6 +294,33 @@ public class HazelcastLinkResourceStore
break;
}
case MPLS_LABEL:
Set<? extends ResourceAllocation> mpls = caps.get(type);
if (mpls == null || mpls.isEmpty()) {
// nothing left
break;
}
Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
for (ResourceAllocation r : mpls) {
if (r instanceof MplsLabelResourceAllocation) {
freeLabel.add((MplsLabelResourceAllocation) r);
}
}
// enumerate current allocations, removing resources
for (LinkResourceAllocations alloc : allocations) {
Set<ResourceAllocation> types = alloc
.getResourceAllocation(link);
for (ResourceAllocation a : types) {
if (a instanceof MplsLabelResourceAllocation) {
freeLabel.remove(a);
}
}
}
free.put(type, freeLabel);
break;
default:
break;
}
......@@ -354,6 +400,18 @@ public class HazelcastLinkResourceStore
link,
lambdaAllocation.lambda().toInt()));
}
} else if (req instanceof MplsLabelResourceAllocation) {
MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
if (!avail.contains(req)) {
throw new ResourceAllocationException(
PositionalParameterStringFormatter
.format("Unable to allocate MPLS label for link "
+ "{} MPLS label is {}",
link,
mplsAllocation
.mplsLabel()
.toString()));
}
}
}
// all requests allocatable => add allocation
......
......@@ -87,6 +87,8 @@ import org.onosproject.net.intent.IntentOperation;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.MplsIntent;
import org.onosproject.net.intent.MplsPathIntent;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.OpticalConnectivityIntent;
import org.onosproject.net.intent.OpticalPathIntent;
......@@ -113,6 +115,9 @@ import org.onosproject.net.resource.Lambda;
import org.onosproject.net.resource.LambdaResourceAllocation;
import org.onosproject.net.resource.LambdaResourceRequest;
import org.onosproject.net.resource.LinkResourceRequest;
import org.onosproject.net.resource.MplsLabel;
import org.onosproject.net.resource.MplsLabelResourceAllocation;
import org.onosproject.net.resource.MplsLabelResourceRequest;
import org.onosproject.store.Timestamp;
import org.onosproject.store.service.BatchReadRequest;
import org.onosproject.store.service.BatchWriteRequest;
......@@ -345,6 +350,14 @@ public final class KryoNamespaces {
.register(WriteStatus.class)
.register(VersionedValue.class)
.register(DefaultGroupId.class)
.register(
MplsIntent.class,
MplsPathIntent.class,
MplsLabelResourceAllocation.class,
MplsLabelResourceRequest.class,
MplsLabel.class,
org.onlab.packet.MplsLabel.class
)
.build();
......
......@@ -25,6 +25,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.core.GroupId;
......@@ -184,7 +185,7 @@ public class SimpleGroupStoreTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
......@@ -244,7 +245,7 @@ public class SimpleGroupStoreTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:03"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
toAddBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
......@@ -347,7 +348,7 @@ public class SimpleGroupStoreTest {
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(106);
.setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
......
......@@ -16,11 +16,13 @@
package org.onosproject.provider.of.flow.impl;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.Ip6Prefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.net.DeviceId;
......@@ -309,7 +311,7 @@ public class FlowEntryBuilder {
case MPLS_LABEL:
@SuppressWarnings("unchecked")
OFOxm<U32> labelId = (OFOxm<U32>) oxm;
builder.setMpls((int) labelId.getValue().getValue());
builder.setMpls(MplsLabel.mplsLabel((int) labelId.getValue().getValue()));
break;
case ARP_OP:
case ARP_SHA:
......@@ -471,6 +473,9 @@ public class FlowEntryBuilder {
break;
case UDP_DST:
builder.matchUdpDst((short) match.get(MatchField.UDP_DST).getPort());
case MPLS_LABEL:
builder.matchMplsLabel(MplsLabel.mplsLabel((int) match.get(MatchField.MPLS_LABEL)
.getValue()));
break;
case SCTP_SRC:
builder.matchSctpSrc((short) match.get(MatchField.SCTP_SRC).getPort());
......@@ -538,10 +543,6 @@ public class FlowEntryBuilder {
mac = MacAddress.valueOf(match.get(MatchField.IPV6_ND_TLL).getLong());
builder.matchIPv6NDTargetLinkLayerAddress(mac);
break;
case MPLS_LABEL:
builder.matchMplsLabel((int) match.get(MatchField.MPLS_LABEL)
.getValue());
break;
case IPV6_EXTHDR:
builder.matchIPv6ExthdrFlags((int) match.get(MatchField.IPV6_EXTHDR)
.getValue());
......
......@@ -362,7 +362,7 @@ public abstract class FlowModBuilder {
break;
case MPLS_LABEL:
Criteria.MplsCriterion mp = (Criteria.MplsCriterion) c;
mBuilder.setExact(MatchField.MPLS_LABEL, U32.of(mp.label()));
mBuilder.setExact(MatchField.MPLS_LABEL, U32.of(mp.label().toInt()));
break;
case IPV6_EXTHDR:
Criteria.IPv6ExthdrFlagsCriterion exthdrFlagsCriterion =
......
......@@ -16,8 +16,10 @@
package org.onosproject.provider.of.group.impl;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.core.GroupId;
......@@ -263,7 +265,7 @@ public class GroupBucketEntryBuilder {
case MPLS_LABEL:
@SuppressWarnings("unchecked")
OFOxm<U32> labelId = (OFOxm<U32>) oxm;
builder.setMpls((int) labelId.getValue().getValue());
builder.setMpls(MplsLabel.mplsLabel((int) labelId.getValue().getValue()));
break;
case ARP_OP:
case ARP_SHA:
......
package org.onlab.packet;
/*
* Copyright 2014 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.
*/
/**
* Representation of a MPLS label.
*/
public class MplsLabel {
private final int mplsLabel;
// An MPLS Label maximum 20 bits.
public static final int MAX_MPLS = 0xFFFFF;
protected MplsLabel(int value) {
this.mplsLabel = value;
}
public static MplsLabel mplsLabel(int value) {
if (value > MAX_MPLS) {
throw new IllegalArgumentException("value exceeds allowed maximum MPLS label value (0xFFFFF)");
}
return new MplsLabel(value);
}
public int toInt() {
return this.mplsLabel;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof MplsLabel) {
MplsLabel other = (MplsLabel) obj;
if (this.mplsLabel == other.mplsLabel) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return this.mplsLabel;
}
@Override
public String toString() {
return String.valueOf(this.mplsLabel);
}
}
......@@ -285,7 +285,7 @@ public final class CriterionCodec extends JsonCodec<Criterion> {
public ObjectNode formatCriterion(ObjectNode root, Criterion criterion) {
final Criteria.MplsCriterion mplsCriterion =
(Criteria.MplsCriterion) criterion;
return root.put("label", mplsCriterion.label());
return root.put("label", mplsCriterion.label().toInt());
}
}
......
......@@ -22,6 +22,7 @@ import org.junit.Test;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
......@@ -374,7 +375,7 @@ public class CriterionCodecTest {
*/
@Test
public void matchMplsLabelTest() {
Criterion criterion = Criteria.matchMplsLabel(0xffffe);
Criterion criterion = Criteria.matchMplsLabel(MplsLabel.mplsLabel(0xffffe));
ObjectNode result = criterionCodec.encode(criterion, context);
assertThat(result, matchesCriterion(criterion));
}
......
......@@ -397,7 +397,7 @@ public final class CriterionJsonMatcher extends
* @return true if the JSON matches the criterion, false otherwise.
*/
private boolean matchCriterion(Criteria.MplsCriterion criterion) {
final int label = criterion.label();
final int label = criterion.label().toInt();
final int jsonLabel = jsonCriterion.get("label").intValue();
if (label != jsonLabel) {
description.appendText("label was " + Integer.toString(jsonLabel));
......
......@@ -20,6 +20,7 @@ import org.junit.Test;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
......@@ -220,7 +221,7 @@ public class InstructionCodecTest {
public void modMplsLabelInstructionTest() {
final L2ModificationInstruction.ModMplsLabelInstruction instruction =
(L2ModificationInstruction.ModMplsLabelInstruction)
Instructions.modMplsLabel(99);
Instructions.modMplsLabel(MplsLabel.mplsLabel(99));
final ObjectNode instructionJson =
instructionCodec.encode(instruction, context);
assertThat(instructionJson, matchesInstruction(instruction));
......
......@@ -21,6 +21,7 @@ import java.util.List;
import org.junit.Test;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.ApplicationId;
......@@ -54,8 +55,6 @@ import com.google.common.collect.ImmutableList;
import static org.onosproject.codec.impl.IntentJsonMatcher.matchesIntent;
import static org.onosproject.net.NetTestTools.did;
import static org.onosproject.net.NetTestTools.hid;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
......@@ -123,7 +122,7 @@ public class IntentCodecTest extends AbstractIntentTest {
DeviceId did3 = did("device3");
final TrafficSelector selector = DefaultTrafficSelector.builder()
.matchIPProtocol((byte) 3)
.matchMplsLabel(4)
.matchMplsLabel(MplsLabel.mplsLabel(4))
.matchOpticalSignalType((short) 5)
.matchLambda((short) 6)
.matchEthDst(MacAddress.BROADCAST)
......@@ -131,7 +130,7 @@ public class IntentCodecTest extends AbstractIntentTest {
.build();
final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setLambda((short) 33)
.setMpls(44)
.setMpls(MplsLabel.mplsLabel(44))
.setOutput(PortNumber.CONTROLLER)
.setEthDst(MacAddress.BROADCAST)
.build();
......