Ray Milkey

ONOS-1334 - Allow multi to single intent across a single switch

Change-Id: I8be3dbc403ea1202fd496e666955402247f71bf1
......@@ -27,6 +27,7 @@ import org.onosproject.core.CoreService;
import org.onosproject.core.DefaultGroupId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.EdgeLink;
import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultFlowRule;
......@@ -77,8 +78,18 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti
SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
for (Link link : intent.links()) {
inputPorts.put(link.dst().deviceId(), link.dst().port());
outputPorts.put(link.src().deviceId(), link.src().port());
DeviceId srcDeviceId;
DeviceId dstDeviceId;
if (link instanceof EdgeLink) {
EdgeLink edgeLink = (EdgeLink) link;
dstDeviceId = edgeLink.hostLocation().deviceId();
srcDeviceId = dstDeviceId;
} else {
inputPorts.put(link.dst().deviceId(), link.dst().port());
srcDeviceId = link.src().deviceId();
}
outputPorts.put(srcDeviceId, link.src().port());
}
for (ConnectPoint ingressPoint : intent.ingressPoints()) {
......
......@@ -43,6 +43,8 @@ import org.onosproject.net.topology.PathService;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
/**
* An intent compiler for
* {@link org.onosproject.net.intent.MultiPointToSinglePointIntent}.
......@@ -71,28 +73,37 @@ public class MultiPointToSinglePointIntentCompiler
public List<Intent> compile(MultiPointToSinglePointIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
Map<DeviceId, Link> links = new HashMap<>();
Map<DeviceId, Link> edgeLinks = new HashMap<>();
ConnectPoint egressPoint = intent.egressPoint();
for (ConnectPoint ingressPoint : intent.ingressPoints()) {
Path path = getPath(ingressPoint, intent.egressPoint());
for (Link link : path.links()) {
if (links.containsKey(link.src().deviceId())) {
// We've already reached the existing tree with the first
// part of this path. Add the merging point with different
// incoming port, but don't add the remainder of the path
// in case it differs from the path we already have.
if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
edgeLinks.put(ingressPoint.deviceId(), createEdgeLink(ingressPoint, true));
edgeLinks.put(egressPoint.deviceId(), createEdgeLink(egressPoint, false));
} else {
Path path = getPath(ingressPoint, intent.egressPoint());
for (Link link : path.links()) {
if (links.containsKey(link.src().deviceId())) {
// We've already reached the existing tree with the first
// part of this path. Add the merging point with different
// incoming port, but don't add the remainder of the path
// in case it differs from the path we already have.
links.put(link.src().deviceId(), link);
break;
}
links.put(link.src().deviceId(), link);
break;
}
links.put(link.src().deviceId(), link);
}
}
Set<Link> allLinks = Sets.newHashSet(links.values());
allLinks.addAll(edgeLinks.values());
Intent result = LinkCollectionIntent.builder()
.appId(intent.appId())
.selector(intent.selector())
.treatment(intent.treatment())
.links(Sets.newHashSet(links.values()))
.links(Sets.newHashSet(allLinks))
.ingressPoints(intent.ingressPoints())
.egressPoints(ImmutableSet.of(intent.egressPoint()))
.priority(intent.priority())
......
......@@ -19,6 +19,7 @@ import java.util.Collection;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.onosproject.net.EdgeLink;
import org.onosproject.net.Link;
/**
......@@ -46,6 +47,14 @@ public class LinksHaveEntryWithSourceDestinationPairMatcher extends
@Override
public boolean matchesSafely(Collection<Link> links) {
for (Link link : links) {
if (source.equals(destination) && link instanceof EdgeLink) {
EdgeLink edgeLink = (EdgeLink) link;
if (edgeLink.hostLocation().elementId()
.toString().endsWith(source)) {
return true;
}
}
if (link.src().elementId().toString().endsWith(source) &&
link.dst().elementId().toString().endsWith(destination)) {
return true;
......
......@@ -15,10 +15,14 @@
*/
package org.onosproject.net.intent.impl.compiler;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.onosproject.core.ApplicationId;
import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.ElementId;
import org.onosproject.net.Path;
......@@ -32,10 +36,7 @@ import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.topology.LinkWeight;
import org.onosproject.net.topology.PathService;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
......@@ -76,9 +77,11 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
String[] allHops = new String[pathHops.length + 1];
allHops[0] = src.toString();
System.arraycopy(pathHops, 0, allHops, 1, pathHops.length);
if (pathHops.length != 0) {
System.arraycopy(pathHops, 0, allHops, 1, pathHops.length);
}
result.add(createPath(allHops));
return result;
}
......@@ -98,7 +101,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
*/
private MultiPointToSinglePointIntent makeIntent(String[] ingressIds, String egressId) {
Set<ConnectPoint> ingressPoints = new HashSet<>();
ConnectPoint egressPoint = connectPoint(egressId, 1);
ConnectPoint egressPoint = connectPoint(egressId, 2);
for (String ingressId : ingressIds) {
ingressPoints.add(connectPoint(ingressId, 1));
......@@ -228,4 +231,35 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
assertThat(linkIntent.links(), linksHasPath("n1", egress));
}
}
/**
* Tests ingress and egress on the same device.
*/
@Test
public void testSameDeviceCompilation() {
String[] ingress = {"i1", "i2"};
String egress = "i1";
MultiPointToSinglePointIntent intent = makeIntent(ingress, egress);
assertThat(intent, is(notNullValue()));
final String[] hops = {"i1", "i2"};
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(notNullValue()));
assertThat(result, hasSize(1));
Intent resultIntent = result.get(0);
assertThat(resultIntent, instanceOf(LinkCollectionIntent.class));
if (resultIntent instanceof LinkCollectionIntent) {
LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent;
assertThat(linkIntent.links(), hasSize(ingress.length + 1));
assertThat(linkIntent.links(), linksHasPath("i2", "i1"));
assertThat(linkIntent.links(), linksHasPath("i1", "i1"));
}
}
}
......