Thomas Vachuska
Committed by Gerrit Code Review

Merge "Add latency constraint"

1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onlab.onos.net.intent.constraint;
17 +
18 +import com.google.common.base.MoreObjects;
19 +import org.onlab.onos.net.Link;
20 +import org.onlab.onos.net.Path;
21 +import org.onlab.onos.net.intent.Constraint;
22 +import org.onlab.onos.net.resource.LinkResourceService;
23 +
24 +import java.time.Duration;
25 +import java.time.temporal.ChronoUnit;
26 +import java.util.Objects;
27 +
28 +/**
29 + * Constraint that evaluates the latency through a path.
30 + */
31 +public class LatencyConstraint implements Constraint {
32 +
33 + // TODO: formalize the key for latency all over the codes.
34 + private static final String LATENCY_KEY = "latency";
35 +
36 + private final Duration latency;
37 +
38 + /**
39 + * Creates a new constraint to keep under specified latency through a path.
40 + * @param latency latency to be kept
41 + */
42 + public LatencyConstraint(Duration latency) {
43 + this.latency = latency;
44 + }
45 +
46 + public Duration getLatency() {
47 + return latency;
48 + }
49 +
50 + @Override
51 + public double cost(Link link, LinkResourceService resourceService) {
52 + String value = link.annotations().value(LATENCY_KEY);
53 +
54 + double latencyInMicroSec;
55 + try {
56 + latencyInMicroSec = Double.parseDouble(value);
57 + } catch (NumberFormatException e) {
58 + latencyInMicroSec = 1.0;
59 + }
60 +
61 + return latencyInMicroSec;
62 + }
63 +
64 + @Override
65 + public boolean validate(Path path, LinkResourceService resourceService) {
66 + double pathLatency = path.links().stream().mapToDouble(link -> cost(link, resourceService)).sum();
67 + return Duration.of((long) pathLatency, ChronoUnit.MICROS).compareTo(latency) <= 0;
68 + }
69 +
70 + @Override
71 + public int hashCode() {
72 + return Objects.hash(latency);
73 + }
74 +
75 + @Override
76 + public boolean equals(Object obj) {
77 + if (this == obj) {
78 + return true;
79 + }
80 +
81 + if (!(obj instanceof LatencyConstraint)) {
82 + return false;
83 + }
84 +
85 + final LatencyConstraint that = (LatencyConstraint) obj;
86 + return Objects.equals(this.latency, that.latency);
87 + }
88 +
89 + @Override
90 + public String toString() {
91 + return MoreObjects.toStringHelper(this)
92 + .add("latency", latency)
93 + .toString();
94 + }
95 +}
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onlab.onos.net.intent.constraint;
17 +
18 +import com.google.common.testing.EqualsTester;
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +import org.onlab.onos.net.Annotations;
22 +import org.onlab.onos.net.DefaultAnnotations;
23 +import org.onlab.onos.net.DefaultLink;
24 +import org.onlab.onos.net.DefaultPath;
25 +import org.onlab.onos.net.DeviceId;
26 +import org.onlab.onos.net.Link;
27 +import org.onlab.onos.net.Path;
28 +import org.onlab.onos.net.PortNumber;
29 +import org.onlab.onos.net.provider.ProviderId;
30 +import org.onlab.onos.net.resource.LinkResourceService;
31 +
32 +import java.time.Duration;
33 +import java.time.temporal.ChronoUnit;
34 +import java.util.Arrays;
35 +
36 +import static org.easymock.EasyMock.createMock;
37 +import static org.hamcrest.Matchers.closeTo;
38 +import static org.hamcrest.Matchers.is;
39 +import static org.junit.Assert.assertThat;
40 +import static org.onlab.onos.net.DefaultLinkTest.cp;
41 +import static org.onlab.onos.net.DeviceId.deviceId;
42 +import static org.onlab.onos.net.Link.Type.DIRECT;
43 +
44 +public class LatencyConstraintTest {
45 +
46 + private static final DeviceId DID1 = deviceId("of:1");
47 + private static final DeviceId DID2 = deviceId("of:2");
48 + private static final DeviceId DID3 = deviceId("of:3");
49 + private static final PortNumber PN1 = PortNumber.portNumber(1);
50 + private static final PortNumber PN2 = PortNumber.portNumber(2);
51 + private static final PortNumber PN3 = PortNumber.portNumber(3);
52 + private static final PortNumber PN4 = PortNumber.portNumber(4);
53 + private static final ProviderId PROVIDER_ID = new ProviderId("of", "foo");
54 + private static final String LATENCY_KEY = "latency";
55 + private static final String LATENCY1 = "3.0";
56 + private static final String LATENCY2 = "4.0";
57 +
58 + private LatencyConstraint sut;
59 + private LinkResourceService linkResourceService;
60 +
61 + private Path path;
62 + private Link link1;
63 + private Link link2;
64 +
65 + @Before
66 + public void setUp() {
67 + linkResourceService = createMock(LinkResourceService.class);
68 +
69 + Annotations annotations1 = DefaultAnnotations.builder().set(LATENCY_KEY, LATENCY1).build();
70 + Annotations annotations2 = DefaultAnnotations.builder().set(LATENCY_KEY, LATENCY2).build();
71 +
72 + link1 = new DefaultLink(PROVIDER_ID, cp(DID1, PN1), cp(DID2, PN2), DIRECT, annotations1);
73 + link2 = new DefaultLink(PROVIDER_ID, cp(DID2, PN3), cp(DID3, PN4), DIRECT, annotations2);
74 + path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), 10);
75 + }
76 +
77 + /**
78 + * Tests the path latency is less than the supplied constraint.
79 + */
80 + @Test
81 + public void testLessThanLatency() {
82 + sut = new LatencyConstraint(Duration.of(10, ChronoUnit.MICROS));
83 +
84 + assertThat(sut.validate(path, linkResourceService), is(true));
85 + }
86 +
87 + /**
88 + * Tests the path latency is more than the supplied constraint.
89 + */
90 + @Test
91 + public void testMoreThanLatency() {
92 + sut = new LatencyConstraint(Duration.of(3, ChronoUnit.MICROS));
93 +
94 + assertThat(sut.validate(path, linkResourceService), is(false));
95 + }
96 +
97 + /**
98 + * Tests the link latency is equal to "latency" annotated value.
99 + */
100 + @Test
101 + public void testCost() {
102 + sut = new LatencyConstraint(Duration.of(10, ChronoUnit.MICROS));
103 +
104 + assertThat(sut.cost(link1, linkResourceService), is(closeTo(Double.parseDouble(LATENCY1), 1.0e-6)));
105 + assertThat(sut.cost(link2, linkResourceService), is(closeTo(Double.parseDouble(LATENCY2), 1.0e-6)));
106 + }
107 +
108 + /**
109 + * Tests equality of the instances.
110 + */
111 + @Test
112 + public void testEquality() {
113 + LatencyConstraint c1 = new LatencyConstraint(Duration.of(1, ChronoUnit.SECONDS));
114 + LatencyConstraint c2 = new LatencyConstraint(Duration.of(1000, ChronoUnit.MILLIS));
115 +
116 + LatencyConstraint c3 = new LatencyConstraint(Duration.of(2, ChronoUnit.SECONDS));
117 + LatencyConstraint c4 = new LatencyConstraint(Duration.of(2000, ChronoUnit.MILLIS));
118 +
119 + new EqualsTester()
120 + .addEqualityGroup(c1, c2)
121 + .addEqualityGroup(c3, c4)
122 + .testEquals();
123 + }
124 +}