Brian Stanke
Committed by Gerrit Code Review

ONOS-2184 - Initial implementation of Virtual network Intent service.

Change-Id: I03103b4eca797cd32480fbd0e3b4cf0385b50ef2
Showing 24 changed files with 1543 additions and 7 deletions
...@@ -2,6 +2,7 @@ COMPILE_DEPS = [ ...@@ -2,6 +2,7 @@ COMPILE_DEPS = [
2 '//lib:CORE_DEPS', 2 '//lib:CORE_DEPS',
3 '//lib:org.apache.karaf.shell.console', 3 '//lib:org.apache.karaf.shell.console',
4 '//incubator/api:onos-incubator-api', 4 '//incubator/api:onos-incubator-api',
5 + '//incubator/net:onos-incubator-net',
5 '//utils/rest:onlab-rest', 6 '//utils/rest:onlab-rest',
6 '//core/common:onos-core-common', 7 '//core/common:onos-core-common',
7 ] 8 ]
......
1 +/*
2 + * Copyright 2016-present 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 +
17 +package org.onosproject.cli.net.vnet;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.onosproject.cli.net.ConnectivityIntentCommand;
22 +import org.onosproject.incubator.net.virtual.NetworkId;
23 +import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
24 +import org.onosproject.incubator.net.virtual.VirtualNetworkService;
25 +import org.onosproject.net.ConnectPoint;
26 +import org.onosproject.net.flow.TrafficSelector;
27 +import org.onosproject.net.flow.TrafficTreatment;
28 +import org.onosproject.net.intent.Constraint;
29 +import org.onosproject.net.intent.Intent;
30 +import org.onosproject.net.intent.IntentService;
31 +
32 +import java.util.List;
33 +
34 +/**
35 + * Installs virtual network intents.
36 + */
37 +@Command(scope = "onos", name = "add-vnet-intent",
38 + description = "Installs virtual network connectivity intent")
39 +public class VirtualNetworkIntentCreateCommand extends ConnectivityIntentCommand {
40 +
41 + @Argument(index = 0, name = "networkId", description = "Network ID",
42 + required = true, multiValued = false)
43 + Long networkId = null;
44 +
45 + @Argument(index = 1, name = "ingressDevice",
46 + description = "Ingress Device/Port Description",
47 + required = true, multiValued = false)
48 + String ingressDeviceString = null;
49 +
50 + @Argument(index = 2, name = "egressDevice",
51 + description = "Egress Device/Port Description",
52 + required = true, multiValued = false)
53 + String egressDeviceString = null;
54 +
55 + @Override
56 + protected void execute() {
57 + VirtualNetworkService service = get(VirtualNetworkService.class);
58 + IntentService virtualNetworkIntentService = service.get(NetworkId.networkId(networkId), IntentService.class);
59 +
60 + ConnectPoint ingress = ConnectPoint.deviceConnectPoint(ingressDeviceString);
61 + ConnectPoint egress = ConnectPoint.deviceConnectPoint(egressDeviceString);
62 +
63 + TrafficSelector selector = buildTrafficSelector();
64 + TrafficTreatment treatment = buildTrafficTreatment();
65 +
66 + List<Constraint> constraints = buildConstraints();
67 +
68 + Intent intent = VirtualNetworkIntent.builder()
69 + .networkId(NetworkId.networkId(networkId))
70 + .appId(appId())
71 + .key(key())
72 + .selector(selector)
73 + .treatment(treatment)
74 + .ingressPoint(ingress)
75 + .egressPoint(egress)
76 + .constraints(constraints)
77 + .priority(priority())
78 + .build();
79 + virtualNetworkIntentService.submit(intent);
80 + print("Virtual intent submitted:\n%s", intent.toString());
81 + }
82 +}
1 +/*
2 + * Copyright 2016-present 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 +
17 +package org.onosproject.cli.net.vnet;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.apache.karaf.shell.commands.Option;
22 +import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.core.ApplicationId;
24 +import org.onosproject.core.CoreService;
25 +import org.onosproject.incubator.net.virtual.NetworkId;
26 +import org.onosproject.incubator.net.virtual.VirtualNetworkService;
27 +import org.onosproject.net.intent.Intent;
28 +import org.onosproject.net.intent.IntentEvent;
29 +import org.onosproject.net.intent.IntentListener;
30 +import org.onosproject.net.intent.IntentService;
31 +import org.onosproject.net.intent.IntentState;
32 +import org.onosproject.net.intent.Key;
33 +
34 +import java.math.BigInteger;
35 +import java.util.EnumSet;
36 +import java.util.Objects;
37 +import java.util.concurrent.CountDownLatch;
38 +import java.util.concurrent.TimeUnit;
39 +
40 +import static com.google.common.base.Strings.isNullOrEmpty;
41 +import static org.onosproject.net.intent.IntentState.FAILED;
42 +import static org.onosproject.net.intent.IntentState.WITHDRAWN;
43 +
44 +/**
45 + * Removes a virtual network intent.
46 + */
47 +@Command(scope = "onos", name = "remove-vnet-intent",
48 + description = "Removes the virtual network intent")
49 +public class VirtualNetworkIntentRemoveCommand extends AbstractShellCommand {
50 +
51 + @Argument(index = 0, name = "networkId", description = "Network ID",
52 + required = true, multiValued = false)
53 + Long networkId = null;
54 +
55 + @Argument(index = 1, name = "app",
56 + description = "Application ID",
57 + required = false, multiValued = false)
58 + String applicationIdString = null;
59 +
60 + @Argument(index = 2, name = "key",
61 + description = "Intent Key",
62 + required = false, multiValued = false)
63 + String keyString = null;
64 +
65 + @Option(name = "-p", aliases = "--purge",
66 + description = "Purge the intent from the store after removal",
67 + required = false, multiValued = false)
68 + private boolean purgeAfterRemove = false;
69 +
70 + @Option(name = "-s", aliases = "--sync",
71 + description = "Waits for the removal before returning",
72 + required = false, multiValued = false)
73 + private boolean sync = false;
74 +
75 + private static final EnumSet<IntentState> CAN_PURGE = EnumSet.of(WITHDRAWN, FAILED);
76 +
77 + @Override
78 + protected void execute() {
79 + VirtualNetworkService service = get(VirtualNetworkService.class);
80 + IntentService intentService = service.get(NetworkId.networkId(networkId), IntentService.class);
81 + CoreService coreService = get(CoreService.class);
82 +
83 + if (purgeAfterRemove || sync) {
84 + print("Using \"sync\" to remove/purge intents - this may take a while...");
85 + print("Check \"summary\" to see remove/purge progress.");
86 + }
87 +
88 + ApplicationId appId = appId();
89 + if (!isNullOrEmpty(applicationIdString)) {
90 + appId = coreService.getAppId(applicationIdString);
91 + if (appId == null) {
92 + print("Cannot find application Id %s", applicationIdString);
93 + return;
94 + }
95 + }
96 +
97 + if (isNullOrEmpty(keyString)) {
98 + for (Intent intent : intentService.getIntents()) {
99 + if (intent.appId().equals(appId)) {
100 + removeIntent(intentService, intent);
101 + }
102 + }
103 +
104 + } else {
105 + final Key key;
106 + if (keyString.startsWith("0x")) {
107 + // The intent uses a LongKey
108 + keyString = keyString.replaceFirst("0x", "");
109 + key = Key.of(new BigInteger(keyString, 16).longValue(), appId);
110 + } else {
111 + // The intent uses a StringKey
112 + key = Key.of(keyString, appId);
113 + }
114 +
115 + Intent intent = intentService.getIntent(key);
116 + if (intent != null) {
117 + removeIntent(intentService, intent);
118 + } else {
119 + print("Intent not found!");
120 + }
121 + }
122 + }
123 +
124 + /**
125 + * Removes the intent using the specified intentService.
126 + *
127 + * @param intentService intent service
128 + * @param intent intent
129 + */
130 + private void removeIntent(IntentService intentService, Intent intent) {
131 + IntentListener listener = null;
132 + Key key = intent.key();
133 + final CountDownLatch withdrawLatch, purgeLatch;
134 + if (purgeAfterRemove || sync) {
135 + // set up latch and listener to track uninstall progress
136 + withdrawLatch = new CountDownLatch(1);
137 + purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null;
138 + listener = (IntentEvent event) -> {
139 + if (Objects.equals(event.subject().key(), key)) {
140 + if (event.type() == IntentEvent.Type.WITHDRAWN ||
141 + event.type() == IntentEvent.Type.FAILED) {
142 + withdrawLatch.countDown();
143 + } else if (purgeAfterRemove &&
144 + event.type() == IntentEvent.Type.PURGED) {
145 + purgeLatch.countDown();
146 + }
147 + }
148 + };
149 + intentService.addListener(listener);
150 + } else {
151 + purgeLatch = null;
152 + withdrawLatch = null;
153 + }
154 +
155 + // request the withdraw
156 + intentService.withdraw(intent);
157 +
158 + if (purgeAfterRemove || sync) {
159 + try { // wait for withdraw event
160 + withdrawLatch.await(5, TimeUnit.SECONDS);
161 + } catch (InterruptedException e) {
162 + print("Timed out waiting for intent {} withdraw", key);
163 + }
164 + if (purgeAfterRemove && CAN_PURGE.contains(intentService.getIntentState(key))) {
165 + intentService.purge(intent);
166 + if (sync) { // wait for purge event
167 + /* TODO
168 + Technically, the event comes before map.remove() is called.
169 + If we depend on sync and purge working together, we will
170 + need to address this.
171 + */
172 + try {
173 + purgeLatch.await(5, TimeUnit.SECONDS);
174 + } catch (InterruptedException e) {
175 + print("Timed out waiting for intent {} purge", key);
176 + }
177 + }
178 + }
179 + }
180 +
181 + if (listener != null) {
182 + // clean up the listener
183 + intentService.removeListener(listener);
184 + }
185 + }
186 +}
...@@ -683,6 +683,12 @@ ...@@ -683,6 +683,12 @@
683 <command> 683 <command>
684 <action class="org.onosproject.cli.net.vnet.VirtualHostRemoveCommand"/> 684 <action class="org.onosproject.cli.net.vnet.VirtualHostRemoveCommand"/>
685 </command> 685 </command>
686 + <command>
687 + <action class="org.onosproject.cli.net.vnet.VirtualNetworkIntentCreateCommand"/>
688 + </command>
689 + <command>
690 + <action class="org.onosproject.cli.net.vnet.VirtualNetworkIntentRemoveCommand"/>
691 + </command>
686 </command-bundle> 692 </command-bundle>
687 693
688 <bean id="reviewAppNameCompleter" class="org.onosproject.cli.security.ReviewApplicationNameCompleter"/> 694 <bean id="reviewAppNameCompleter" class="org.onosproject.cli.security.ReviewApplicationNameCompleter"/>
......
...@@ -155,7 +155,6 @@ public class FakeIntentManager implements TestableIntentService { ...@@ -155,7 +155,6 @@ public class FakeIntentManager implements TestableIntentService {
155 155
156 @Override 156 @Override
157 public void withdraw(Intent intent) { 157 public void withdraw(Intent intent) {
158 - intents.remove(intent.key());
159 executeWithdraw(intent); 158 executeWithdraw(intent);
160 } 159 }
161 160
...@@ -167,6 +166,7 @@ public class FakeIntentManager implements TestableIntentService { ...@@ -167,6 +166,7 @@ public class FakeIntentManager implements TestableIntentService {
167 intents.remove(intent.key()); 166 intents.remove(intent.key());
168 installables.remove(intent.key()); 167 installables.remove(intent.key());
169 intentStates.remove(intent.key()); 168 intentStates.remove(intent.key());
169 + dispatch(new IntentEvent(IntentEvent.Type.PURGED, intent));
170 } 170 }
171 } 171 }
172 172
......
1 COMPILE_DEPS = [ 1 COMPILE_DEPS = [
2 '//lib:CORE_DEPS', 2 '//lib:CORE_DEPS',
3 '//incubator/api:onos-incubator-api', 3 '//incubator/api:onos-incubator-api',
4 + '//utils/rest:onlab-rest',
5 + '//incubator/net:onos-incubator-net',
6 + '//incubator/store:onos-incubator-store',
4 ] 7 ]
5 8
6 TEST_DEPS = [ 9 TEST_DEPS = [
10 + '//lib:TEST_REST',
7 '//lib:TEST_ADAPTERS', 11 '//lib:TEST_ADAPTERS',
8 '//core/common:onos-core-common', 12 '//core/common:onos-core-common',
9 '//core/store/dist:onos-core-dist', 13 '//core/store/dist:onos-core-dist',
......
...@@ -93,6 +93,14 @@ ...@@ -93,6 +93,14 @@
93 93
94 <dependency> 94 <dependency>
95 <groupId>org.onosproject</groupId> 95 <groupId>org.onosproject</groupId>
96 + <artifactId>onlab-osgi</artifactId>
97 + <version>${project.version}</version>
98 + <classifier>tests</classifier>
99 + <scope>test</scope>
100 + </dependency>
101 +
102 + <dependency>
103 + <groupId>org.onosproject</groupId>
96 <artifactId>onos-incubator-api</artifactId> 104 <artifactId>onos-incubator-api</artifactId>
97 </dependency> 105 </dependency>
98 106
...@@ -110,6 +118,17 @@ ...@@ -110,6 +118,17 @@
110 <groupId>org.apache.felix</groupId> 118 <groupId>org.apache.felix</groupId>
111 <artifactId>org.apache.felix.scr</artifactId> 119 <artifactId>org.apache.felix.scr</artifactId>
112 </dependency> 120 </dependency>
121 + <dependency>
122 + <groupId>org.onosproject</groupId>
123 + <artifactId>onos-incubator-store</artifactId>
124 + <version>${project.version}</version>
125 + <scope>test</scope>
126 + </dependency>
127 + <dependency>
128 + <groupId>org.onosproject</groupId>
129 + <artifactId>onos-incubator-net</artifactId>
130 + <version>${project.version}</version>
131 + </dependency>
113 </dependencies> 132 </dependencies>
114 133
115 </project> 134 </project>
......
1 +/*
2 + * Copyright 2016-present 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 +
17 +package org.onosproject.net.intent.impl.compiler;
18 +
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.onlab.osgi.DefaultServiceDirectory;
25 +import org.onlab.osgi.ServiceDirectory;
26 +import org.onosproject.core.ApplicationId;
27 +import org.onosproject.incubator.net.tunnel.TunnelId;
28 +import org.onosproject.incubator.net.virtual.NetworkId;
29 +import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
30 +import org.onosproject.incubator.net.virtual.VirtualNetworkService;
31 +import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
32 +import org.onosproject.incubator.net.virtual.VirtualPort;
33 +import org.onosproject.net.ConnectPoint;
34 +import org.onosproject.net.EncapsulationType;
35 +import org.onosproject.net.Link;
36 +import org.onosproject.net.Path;
37 +import org.onosproject.net.intent.Constraint;
38 +import org.onosproject.net.intent.Intent;
39 +import org.onosproject.net.intent.IntentService;
40 +import org.onosproject.net.intent.Key;
41 +import org.onosproject.net.intent.PointToPointIntent;
42 +import org.onosproject.net.intent.constraint.EncapsulationConstraint;
43 +import org.onosproject.net.intent.impl.IntentCompilationException;
44 +import org.onosproject.net.topology.TopologyService;
45 +import org.slf4j.Logger;
46 +
47 +import java.util.ArrayList;
48 +import java.util.List;
49 +import java.util.Optional;
50 +import java.util.Set;
51 +
52 +import static org.slf4j.LoggerFactory.getLogger;
53 +
54 +/**
55 + * An intent compiler for {@link org.onosproject.incubator.net.virtual.VirtualNetworkIntent}.
56 + */
57 +@Component(immediate = true)
58 +public class VirtualNetworkIntentCompiler
59 + extends ConnectivityIntentCompiler<VirtualNetworkIntent> {
60 +
61 + private final Logger log = getLogger(getClass());
62 +
63 + private static final String NETWORK_ID = "networkId=";
64 + protected static final String KEY_FORMAT = "{" + NETWORK_ID + "%s, src=%s, dst=%s}";
65 +
66 + protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
67 +
68 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 + protected VirtualNetworkService manager;
70 +
71 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 + protected IntentService intentService;
73 +
74 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 + protected VirtualNetworkStore store;
76 +
77 +
78 + @Activate
79 + public void activate() {
80 + intentManager.registerCompiler(VirtualNetworkIntent.class, this);
81 + }
82 +
83 + @Deactivate
84 + public void deactivate() {
85 + intentManager.unregisterCompiler(VirtualNetworkIntent.class);
86 + }
87 +
88 + @Override
89 + public List<Intent> compile(VirtualNetworkIntent intent, List<Intent> installable) {
90 +
91 + log.debug("Compiling intent: " + intent);
92 + List<Intent> intents = new ArrayList<>();
93 + Optional<Path> path = getPaths(intent).stream()
94 + .findFirst();
95 + if (path != null && path.isPresent()) {
96 + path.get().links().forEach(link -> {
97 + Intent physicalIntent = createPtPtIntent(intent, link);
98 + intents.add(physicalIntent);
99 +
100 + // store the virtual intent to physical intent tunnelId mapping
101 + store.addTunnelId(intent, TunnelId.valueOf(physicalIntent.key().toString()));
102 + });
103 + } else {
104 + throw new IntentCompilationException("Unable to find a path for intent " + intent);
105 + }
106 +
107 + return intents;
108 + }
109 +
110 + /**
111 + * Returns the paths for the virtual network intent.
112 + *
113 + * @param intent virtual network intent
114 + * @return set of paths
115 + */
116 + private Set<Path> getPaths(VirtualNetworkIntent intent) {
117 +
118 + TopologyService topologyService = manager.get(intent.networkId(), TopologyService.class);
119 + if (topologyService == null) {
120 + throw new IntentCompilationException("topologyService is null");
121 + }
122 + return topologyService.getPaths(topologyService.currentTopology(),
123 + intent.ingressPoint().deviceId(), intent.egressPoint().deviceId());
124 + }
125 +
126 + /**
127 + * Encodes the key using the network identifier, application identifer, source and destination
128 + * connect points.
129 + *
130 + * @param networkId virtual network identifier
131 + * @param applicationId application identifier
132 + * @param src source connect point
133 + * @param dst destination connect point
134 + * @return encoded key
135 + */
136 + private static Key encodeKey(NetworkId networkId, ApplicationId applicationId, ConnectPoint src, ConnectPoint dst) {
137 + String key = String.format(KEY_FORMAT, networkId, src, dst);
138 + return Key.of(key, applicationId);
139 + }
140 +
141 + /**
142 + * Creates a point-to-point intent from the virtual network intent and virtual link.
143 + *
144 + * @param intent virtual network intent
145 + * @param link virtual link
146 + * @return point to point intent
147 + */
148 + private Intent createPtPtIntent(VirtualNetworkIntent intent, Link link) {
149 + ConnectPoint ingressPoint = mapVirtualToPhysicalPort(intent.networkId(), link.src());
150 + ConnectPoint egressPoint = mapVirtualToPhysicalPort(intent.networkId(), link.dst());
151 + Key intentKey = encodeKey(intent.networkId(), intent.appId(), ingressPoint, egressPoint);
152 +
153 + List<Constraint> constraints = new ArrayList<>();
154 + constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
155 +
156 + // TODO Currently there can only be one intent between the ingress and egress across
157 + // all virtual networks. We may want to support multiple intents between the same src/dst pairs.
158 + PointToPointIntent physicalIntent = PointToPointIntent.builder()
159 + .key(intentKey)
160 + .appId(intent.appId())
161 + .ingressPoint(ingressPoint)
162 + .egressPoint(egressPoint)
163 + .constraints(constraints)
164 + .build();
165 + log.debug("Submitting physical intent: " + physicalIntent);
166 + intentService.submit(physicalIntent);
167 +
168 + return physicalIntent;
169 + }
170 +
171 + /**
172 + * Maps the virtual connect point to a physical connect point.
173 + *
174 + * @param networkId virtual network identifier
175 + * @param virtualCp virtual connect point
176 + * @return physical connect point
177 + */
178 + private ConnectPoint mapVirtualToPhysicalPort(NetworkId networkId, ConnectPoint virtualCp) {
179 + Set<VirtualPort> ports = manager.getVirtualPorts(networkId, virtualCp.deviceId());
180 + for (VirtualPort port : ports) {
181 + if (port.element().id().equals(virtualCp.elementId()) &&
182 + port.number().equals(virtualCp.port())) {
183 + return new ConnectPoint(port.realizedBy().element().id(), port.realizedBy().number());
184 + }
185 + }
186 + return null;
187 + }
188 +}
189 +
1 +/*
2 + * Copyright 2016-present 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 +
17 +package org.onosproject.net.intent.impl.compiler;
18 +
19 +import org.junit.After;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +import org.onlab.osgi.ServiceDirectory;
23 +import org.onlab.osgi.TestServiceDirectory;
24 +import org.onlab.rest.BaseResource;
25 +import org.onosproject.TestApplicationId;
26 +import org.onosproject.common.event.impl.TestEventDispatcher;
27 +import org.onosproject.core.ApplicationId;
28 +import org.onosproject.core.CoreService;
29 +import org.onosproject.core.CoreServiceAdapter;
30 +import org.onosproject.core.IdGenerator;
31 +import org.onosproject.incubator.net.virtual.TenantId;
32 +import org.onosproject.incubator.net.virtual.VirtualDevice;
33 +import org.onosproject.incubator.net.virtual.VirtualLink;
34 +import org.onosproject.incubator.net.virtual.VirtualNetwork;
35 +import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
36 +import org.onosproject.incubator.net.virtual.VirtualNetworkService;
37 +import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
38 +import org.onosproject.incubator.net.virtual.impl.VirtualNetworkManager;
39 +import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore;
40 +import org.onosproject.net.ConnectPoint;
41 +import org.onosproject.net.DefaultPort;
42 +import org.onosproject.net.EncapsulationType;
43 +import org.onosproject.net.Link;
44 +import org.onosproject.net.NetTestTools;
45 +import org.onosproject.net.Port;
46 +import org.onosproject.net.PortNumber;
47 +import org.onosproject.net.TestDeviceParams;
48 +import org.onosproject.net.intent.Constraint;
49 +import org.onosproject.net.intent.FakeIntentManager;
50 +import org.onosproject.net.intent.Intent;
51 +import org.onosproject.net.intent.IntentExtensionService;
52 +import org.onosproject.net.intent.IntentService;
53 +import org.onosproject.net.intent.Key;
54 +import org.onosproject.net.intent.MockIdGenerator;
55 +import org.onosproject.net.intent.TestableIntentService;
56 +import org.onosproject.net.intent.constraint.EncapsulationConstraint;
57 +import org.onosproject.store.service.TestStorageService;
58 +
59 +import java.util.ArrayList;
60 +import java.util.Collections;
61 +import java.util.List;
62 +import java.util.concurrent.atomic.AtomicLong;
63 +
64 +import static org.junit.Assert.assertEquals;
65 +import static org.onlab.junit.TestUtils.TestUtilsException;
66 +import static org.onlab.junit.TestUtils.setField;
67 +
68 +/**
69 + * Junit tests for virtual network intent compiler.
70 + */
71 +public class VirtualNetworkIntentCompilerTest extends TestDeviceParams {
72 +
73 + private CoreService coreService;
74 + private TestableIntentService intentService = new FakeIntentManager();
75 + private IntentExtensionService intentExtensionService;
76 + private final IdGenerator idGenerator = new MockIdGenerator();
77 + private VirtualNetworkIntentCompiler compiler;
78 + private VirtualNetworkManager manager;
79 + private DistributedVirtualNetworkStore virtualNetworkManagerStore;
80 + private ServiceDirectory testDirectory;
81 +
82 + private final String tenantIdValue1 = "TENANT_ID1";
83 + private static final ApplicationId APP_ID =
84 + new TestApplicationId("test");
85 +
86 + private ConnectPoint cp1;
87 + private ConnectPoint cp2;
88 + private ConnectPoint cp3;
89 + private ConnectPoint cp4;
90 + private ConnectPoint cp5;
91 + private ConnectPoint cp6;
92 + private VirtualLink link1;
93 + private VirtualLink link2;
94 + private VirtualLink link3;
95 + private VirtualLink link4;
96 + private VirtualLink link5;
97 + private VirtualLink link6;
98 +
99 + @Before
100 + public void setUp() throws TestUtilsException {
101 + virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
102 +
103 + coreService = new TestCoreService();
104 +
105 + Intent.unbindIdGenerator(idGenerator);
106 + Intent.bindIdGenerator(idGenerator);
107 +
108 + virtualNetworkManagerStore.setCoreService(coreService);
109 + setField(coreService, "coreService", new TestCoreService());
110 + setField(virtualNetworkManagerStore, "storageService", new TestStorageService());
111 + virtualNetworkManagerStore.activate();
112 +
113 + manager = new VirtualNetworkManager();
114 + manager.setStore(virtualNetworkManagerStore);
115 + manager.setIntentService(intentService);
116 + NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
117 + manager.activate();
118 +
119 + // Register a compiler and an installer both setup for success.
120 + intentExtensionService = intentService;
121 +
122 + testDirectory = new TestServiceDirectory()
123 + .add(VirtualNetworkService.class, manager)
124 + .add(VirtualNetworkStore.class, virtualNetworkManagerStore)
125 + .add(IntentService.class, intentService);
126 + BaseResource.setServiceDirectory(testDirectory);
127 +
128 + compiler = new VirtualNetworkIntentCompiler();
129 + compiler.manager = manager;
130 + compiler.intentService = intentService;
131 + compiler.store = virtualNetworkManagerStore;
132 + compiler.intentManager = intentExtensionService;
133 + compiler.serviceDirectory = testDirectory;
134 + }
135 +
136 + @After
137 + public void tearDown() {
138 + Intent.unbindIdGenerator(idGenerator);
139 + manager.deactivate();
140 + }
141 +
142 + /**
143 + * Method to create the virtual network for further testing.
144 + *
145 + * @return virtual network
146 + */
147 + private VirtualNetwork setupVirtualNetworkTopology() {
148 + manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
149 + VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
150 + VirtualDevice virtualDevice1 =
151 + manager.createVirtualDevice(virtualNetwork.id(), DID1);
152 + VirtualDevice virtualDevice2 =
153 + manager.createVirtualDevice(virtualNetwork.id(), DID2);
154 + VirtualDevice virtualDevice3 =
155 + manager.createVirtualDevice(virtualNetwork.id(), DID3);
156 + VirtualDevice virtualDevice4 =
157 + manager.createVirtualDevice(virtualNetwork.id(), DID4);
158 +
159 + Port port1 = new DefaultPort(virtualDevice1, PortNumber.portNumber(1), true);
160 + manager.createVirtualPort(virtualNetwork.id(), virtualDevice1.id(), port1.number(), port1);
161 + cp1 = new ConnectPoint(virtualDevice1.id(), port1.number());
162 +
163 + Port port2 = new DefaultPort(virtualDevice1, PortNumber.portNumber(2), true);
164 + manager.createVirtualPort(virtualNetwork.id(), virtualDevice1.id(), port2.number(), port2);
165 + cp2 = new ConnectPoint(virtualDevice1.id(), port2.number());
166 +
167 + Port port3 = new DefaultPort(virtualDevice2, PortNumber.portNumber(3), true);
168 + manager.createVirtualPort(virtualNetwork.id(), virtualDevice2.id(), port3.number(), port3);
169 + cp3 = new ConnectPoint(virtualDevice2.id(), port3.number());
170 +
171 + Port port4 = new DefaultPort(virtualDevice2, PortNumber.portNumber(4), true);
172 + manager.createVirtualPort(virtualNetwork.id(), virtualDevice2.id(), port4.number(), port4);
173 + cp4 = new ConnectPoint(virtualDevice2.id(), port4.number());
174 +
175 + Port port5 = new DefaultPort(virtualDevice3, PortNumber.portNumber(5), true);
176 + manager.createVirtualPort(virtualNetwork.id(), virtualDevice3.id(), port5.number(), port5);
177 + cp5 = new ConnectPoint(virtualDevice3.id(), port5.number());
178 +
179 + Port port6 = new DefaultPort(virtualDevice3, PortNumber.portNumber(6), true);
180 + manager.createVirtualPort(virtualNetwork.id(), virtualDevice3.id(), port6.number(), port6);
181 + cp6 = new ConnectPoint(virtualDevice3.id(), port6.number());
182 +
183 + link1 = manager.createVirtualLink(virtualNetwork.id(), cp1, cp3);
184 + virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.ACTIVE);
185 + link2 = manager.createVirtualLink(virtualNetwork.id(), cp3, cp1);
186 + virtualNetworkManagerStore.updateLink(link2, link2.tunnelId(), Link.State.ACTIVE);
187 + link3 = manager.createVirtualLink(virtualNetwork.id(), cp4, cp5);
188 + virtualNetworkManagerStore.updateLink(link3, link3.tunnelId(), Link.State.ACTIVE);
189 + link4 = manager.createVirtualLink(virtualNetwork.id(), cp5, cp4);
190 + virtualNetworkManagerStore.updateLink(link4, link4.tunnelId(), Link.State.ACTIVE);
191 +
192 + return virtualNetwork;
193 + }
194 +
195 + @Test
196 + public void testCompiler() {
197 + compiler.activate();
198 + VirtualNetwork virtualNetwork = setupVirtualNetworkTopology();
199 +
200 + Key intentKey = Key.of("test", APP_ID);
201 +
202 + List<Constraint> constraints = new ArrayList<>();
203 + constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
204 +
205 + VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
206 + .networkId(virtualNetwork.id())
207 + .key(intentKey)
208 + .appId(APP_ID)
209 + .ingressPoint(cp1)
210 + .egressPoint(cp5)
211 + .constraints(constraints)
212 + .build();
213 +
214 + List<Intent> compiled = compiler.compile(virtualIntent, Collections.emptyList());
215 + assertEquals("The virtual intents size is not as expected.", 2, compiled.size());
216 +
217 + compiler.deactivate();
218 + }
219 +
220 +
221 + /**
222 + * Core service test class.
223 + */
224 + private class TestCoreService extends CoreServiceAdapter {
225 +
226 + @Override
227 + public IdGenerator getIdGenerator(String topic) {
228 + return new IdGenerator() {
229 + private AtomicLong counter = new AtomicLong(0);
230 +
231 + @Override
232 + public long getNewId() {
233 + return counter.getAndIncrement();
234 + }
235 + };
236 + }
237 + }
238 +
239 +}
...@@ -9,6 +9,7 @@ COMPILE_DEPS = [ ...@@ -9,6 +9,7 @@ COMPILE_DEPS = [
9 '//lib:netty-handler', 9 '//lib:netty-handler',
10 '//lib:netty-transport-native-epoll', 10 '//lib:netty-transport-native-epoll',
11 '//lib:commons-math3', 11 '//lib:commons-math3',
12 + '//incubator/api:onos-incubator-api',
12 ] 13 ]
13 14
14 TEST_DEPS = [ 15 TEST_DEPS = [
......
...@@ -27,6 +27,8 @@ import org.onlab.util.KryoNamespace; ...@@ -27,6 +27,8 @@ import org.onlab.util.KryoNamespace;
27 import org.onosproject.cluster.ClusterService; 27 import org.onosproject.cluster.ClusterService;
28 import org.onosproject.cluster.ControllerNode; 28 import org.onosproject.cluster.ControllerNode;
29 import org.onosproject.cluster.NodeId; 29 import org.onosproject.cluster.NodeId;
30 +import org.onosproject.incubator.net.virtual.NetworkId;
31 +import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
30 import org.onosproject.net.intent.Intent; 32 import org.onosproject.net.intent.Intent;
31 import org.onosproject.net.intent.IntentData; 33 import org.onosproject.net.intent.IntentData;
32 import org.onosproject.net.intent.IntentEvent; 34 import org.onosproject.net.intent.IntentEvent;
...@@ -97,6 +99,8 @@ public class GossipIntentStore ...@@ -97,6 +99,8 @@ public class GossipIntentStore
97 KryoNamespace.Builder intentSerializer = KryoNamespace.newBuilder() 99 KryoNamespace.Builder intentSerializer = KryoNamespace.newBuilder()
98 .register(KryoNamespaces.API) 100 .register(KryoNamespaces.API)
99 .register(IntentData.class) 101 .register(IntentData.class)
102 + .register(VirtualNetworkIntent.class)
103 + .register(NetworkId.class)
100 .register(MultiValuedTimestamp.class); 104 .register(MultiValuedTimestamp.class);
101 105
102 currentMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder() 106 currentMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
......
1 +/*
2 + * Copyright 2016-present 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 +
17 +package org.onosproject.incubator.net.virtual;
18 +
19 +import com.google.common.annotations.Beta;
20 +import com.google.common.base.MoreObjects;
21 +import org.onosproject.core.ApplicationId;
22 +import org.onosproject.net.ConnectPoint;
23 +import org.onosproject.net.flow.TrafficSelector;
24 +import org.onosproject.net.flow.TrafficTreatment;
25 +import org.onosproject.net.intent.ConnectivityIntent;
26 +import org.onosproject.net.intent.Constraint;
27 +import org.onosproject.net.intent.Key;
28 +
29 +import java.util.Collections;
30 +import java.util.List;
31 +
32 +import static com.google.common.base.Preconditions.checkArgument;
33 +import static com.google.common.base.Preconditions.checkNotNull;
34 +
35 +/**
36 + * Abstraction of VirtualNetworkIntent connectivity.
37 + */
38 +@Beta
39 +public final class VirtualNetworkIntent extends ConnectivityIntent {
40 +
41 + private final NetworkId networkId;
42 + private final ConnectPoint ingressPoint;
43 + private final ConnectPoint egressPoint;
44 +
45 + private static final String NETWORK_ID_NULL = "Network ID cannot be null";
46 +
47 + /**
48 + * Returns a new point to point intent builder. The application id,
49 + * ingress point and egress point are required fields. If they are
50 + * not set by calls to the appropriate methods, an exception will
51 + * be thrown.
52 + *
53 + * @return point to point builder
54 + */
55 + public static VirtualNetworkIntent.Builder builder() {
56 + return new VirtualNetworkIntent.Builder();
57 + }
58 +
59 + /**
60 + * Builder of a point to point intent.
61 + */
62 + public static final class Builder extends ConnectivityIntent.Builder {
63 + NetworkId networkId;
64 + ConnectPoint ingressPoint;
65 + ConnectPoint egressPoint;
66 +
67 + /**
68 + * Builder constructor.
69 + */
70 + private Builder() {
71 + // Hide constructor
72 + }
73 +
74 + @Override
75 + public VirtualNetworkIntent.Builder appId(ApplicationId appId) {
76 + return (VirtualNetworkIntent.Builder) super.appId(appId);
77 + }
78 +
79 + @Override
80 + public VirtualNetworkIntent.Builder key(Key key) {
81 + return (VirtualNetworkIntent.Builder) super.key(key);
82 + }
83 +
84 + @Override
85 + public VirtualNetworkIntent.Builder selector(TrafficSelector selector) {
86 + return (VirtualNetworkIntent.Builder) super.selector(selector);
87 + }
88 +
89 + @Override
90 + public VirtualNetworkIntent.Builder treatment(TrafficTreatment treatment) {
91 + return (VirtualNetworkIntent.Builder) super.treatment(treatment);
92 + }
93 +
94 + @Override
95 + public VirtualNetworkIntent.Builder constraints(List<Constraint> constraints) {
96 + return (VirtualNetworkIntent.Builder) super.constraints(constraints);
97 + }
98 +
99 + @Override
100 + public VirtualNetworkIntent.Builder priority(int priority) {
101 + return (VirtualNetworkIntent.Builder) super.priority(priority);
102 + }
103 +
104 + /**
105 + * Sets the virtual network of the virtual network intent.
106 + *
107 + * @param networkId virtual network identifier
108 + * @return this builder
109 + */
110 + public VirtualNetworkIntent.Builder networkId(NetworkId networkId) {
111 + this.networkId = networkId;
112 + return this;
113 + }
114 +
115 + /**
116 + * Sets the ingress point of the virtual network intent that will be built.
117 + *
118 + * @param ingressPoint ingress connect point
119 + * @return this builder
120 + */
121 + public VirtualNetworkIntent.Builder ingressPoint(ConnectPoint ingressPoint) {
122 + this.ingressPoint = ingressPoint;
123 + return this;
124 + }
125 +
126 + /**
127 + * Sets the egress point of the virtual network intent that will be built.
128 + *
129 + * @param egressPoint egress connect point
130 + * @return this builder
131 + */
132 + public VirtualNetworkIntent.Builder egressPoint(ConnectPoint egressPoint) {
133 + this.egressPoint = egressPoint;
134 + return this;
135 + }
136 +
137 + /**
138 + * Builds a virtual network intent from the accumulated parameters.
139 + *
140 + * @return virtual network intent
141 + */
142 + public VirtualNetworkIntent build() {
143 +
144 + return new VirtualNetworkIntent(
145 + networkId,
146 + appId,
147 + key,
148 + selector,
149 + treatment,
150 + ingressPoint,
151 + egressPoint,
152 + constraints,
153 + priority
154 + );
155 + }
156 + }
157 +
158 +
159 + /**
160 + * Creates a new point-to-point intent with the supplied ingress/egress
161 + * ports and constraints.
162 + *
163 + * @param networkId virtual network identifier
164 + * @param appId application identifier
165 + * @param key key of the intent
166 + * @param selector traffic selector
167 + * @param treatment treatment
168 + * @param ingressPoint ingress port
169 + * @param egressPoint egress port
170 + * @param constraints optional list of constraints
171 + * @param priority priority to use for flows generated by this intent
172 + * @throws NullPointerException if {@code ingressPoint} or
173 + * {@code egressPoints} or {@code appId} is null.
174 + */
175 + private VirtualNetworkIntent(NetworkId networkId,
176 + ApplicationId appId,
177 + Key key,
178 + TrafficSelector selector,
179 + TrafficTreatment treatment,
180 + ConnectPoint ingressPoint,
181 + ConnectPoint egressPoint,
182 + List<Constraint> constraints,
183 + int priority) {
184 + super(appId, key, Collections.emptyList(), selector, treatment, constraints,
185 + priority);
186 +
187 + checkNotNull(networkId, NETWORK_ID_NULL);
188 + checkArgument(!ingressPoint.equals(egressPoint),
189 + "ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint);
190 +
191 + this.networkId = networkId;
192 + this.ingressPoint = checkNotNull(ingressPoint);
193 + this.egressPoint = checkNotNull(egressPoint);
194 + }
195 +
196 + /**
197 + * Constructor for serializer.
198 + */
199 + protected VirtualNetworkIntent() {
200 + super();
201 + this.networkId = null;
202 + this.ingressPoint = null;
203 + this.egressPoint = null;
204 + }
205 +
206 + /**
207 + * Returns the virtual network identifier.
208 + *
209 + * @return network identifier
210 + */
211 + public NetworkId networkId() {
212 + return networkId;
213 + }
214 +
215 + /**
216 + * Returns the port on which the ingress traffic should be connected to
217 + * the egress.
218 + *
219 + * @return ingress port
220 + */
221 + public ConnectPoint ingressPoint() {
222 + return ingressPoint;
223 + }
224 +
225 + /**
226 + * Returns the port on which the traffic should egress.
227 + *
228 + * @return egress port
229 + */
230 + public ConnectPoint egressPoint() {
231 + return egressPoint;
232 + }
233 +
234 + @Override
235 + public String toString() {
236 + return MoreObjects.toStringHelper(getClass())
237 + .add("networkId", networkId)
238 + .add("id", id())
239 + .add("key", key())
240 + .add("appId", appId())
241 + .add("priority", priority())
242 + .add("resources", resources())
243 + .add("selector", selector())
244 + .add("treatment", treatment())
245 + .add("ingress", ingressPoint)
246 + .add("egress", egressPoint)
247 + .add("constraints", constraints())
248 + .toString();
249 + }
250 +
251 +}
...@@ -26,6 +26,10 @@ import org.onosproject.net.HostLocation; ...@@ -26,6 +26,10 @@ import org.onosproject.net.HostLocation;
26 import org.onosproject.net.Link; 26 import org.onosproject.net.Link;
27 import org.onosproject.net.Port; 27 import org.onosproject.net.Port;
28 import org.onosproject.net.PortNumber; 28 import org.onosproject.net.PortNumber;
29 +import org.onosproject.net.intent.Intent;
30 +import org.onosproject.net.intent.IntentData;
31 +import org.onosproject.net.intent.IntentState;
32 +import org.onosproject.net.intent.Key;
29 import org.onosproject.store.Store; 33 import org.onosproject.store.Store;
30 34
31 import java.util.Set; 35 import java.util.Set;
...@@ -223,4 +227,73 @@ public interface VirtualNetworkStore ...@@ -223,4 +227,73 @@ public interface VirtualNetworkStore
223 */ 227 */
224 Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId); 228 Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId);
225 229
230 + /**
231 + * Add or update the intent to the store.
232 + *
233 + * @param intent virtual intent
234 + * @param state intent state
235 + */
236 + void addOrUpdateIntent(Intent intent, IntentState state);
237 +
238 + /**
239 + * Remove the virtual intent from the store.
240 + *
241 + * @param intentKey intent key
242 + * @return intent data
243 + */
244 + IntentData removeIntent(Key intentKey);
245 +
246 + /**
247 + * Adds the intent to tunnel identifier mapping to the store.
248 + *
249 + * @param intent intent
250 + * @param tunnelId tunnel identifier
251 + */
252 + void addTunnelId(Intent intent, TunnelId tunnelId);
253 +
254 + /**
255 + * Return the set of tunnel identifiers store against the intent.
256 + *
257 + * @param intent intent
258 + * @return set of tunnel identifiers
259 + */
260 + Set<TunnelId> getTunnelIds(Intent intent);
261 +
262 + /**
263 + * Removes the intent to tunnel identifier mapping from the store.
264 + *
265 + * @param intent intent
266 + * @param tunnelId tunnel identifier
267 + */
268 + void removeTunnelId(Intent intent, TunnelId tunnelId);
269 +
270 + /**
271 + * Return all intents.
272 + *
273 + * @return set of intents
274 + */
275 + Set<Intent> getIntents();
276 +
277 + /**
278 + * Return the intent for the specified intent key.
279 + *
280 + * @param key intent key
281 + * @return intent
282 + */
283 + Intent getIntent(Key key);
284 +
285 + /**
286 + * Return the set of intent data.
287 + *
288 + * @return set of intent data
289 + */
290 + Set<IntentData> getIntentData();
291 +
292 + /**
293 + * Return the intent data matching the intent key.
294 + *
295 + * @param key intent key
296 + * @return intent data
297 + */
298 + IntentData getIntentData(Key key);
226 } 299 }
......
...@@ -2,13 +2,15 @@ COMPILE_DEPS = [ ...@@ -2,13 +2,15 @@ COMPILE_DEPS = [
2 '//lib:CORE_DEPS', 2 '//lib:CORE_DEPS',
3 '//core/common:onos-core-common', 3 '//core/common:onos-core-common',
4 '//incubator/api:onos-incubator-api', 4 '//incubator/api:onos-incubator-api',
5 + '//incubator/store:onos-incubator-store',
6 + '//utils/rest:onlab-rest',
5 ] 7 ]
6 8
7 TEST_DEPS = [ 9 TEST_DEPS = [
10 + '//lib:TEST_REST',
8 '//lib:TEST_ADAPTERS', 11 '//lib:TEST_ADAPTERS',
9 '//core/api:onos-api-tests', 12 '//core/api:onos-api-tests',
10 '//core/common:onos-core-common-tests', 13 '//core/common:onos-core-common-tests',
11 - '//incubator/store:onos-incubator-store',
12 '//core/store/serializers:onos-core-serializers', 14 '//core/store/serializers:onos-core-serializers',
13 '//lib:concurrent-trees', 15 '//lib:concurrent-trees',
14 ] 16 ]
......
...@@ -95,6 +95,14 @@ ...@@ -95,6 +95,14 @@
95 <groupId>org.apache.felix</groupId> 95 <groupId>org.apache.felix</groupId>
96 <artifactId>org.apache.felix.scr.annotations</artifactId> 96 <artifactId>org.apache.felix.scr.annotations</artifactId>
97 </dependency> 97 </dependency>
98 +
99 + <dependency>
100 + <groupId>org.onosproject</groupId>
101 + <artifactId>onlab-osgi</artifactId>
102 + <version>${project.version}</version>
103 + <classifier>tests</classifier>
104 + <scope>test</scope>
105 + </dependency>
98 </dependencies> 106 </dependencies>
99 107
100 <build> 108 <build>
......
1 +/*
2 + * Copyright 2016-present 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 +
17 +package org.onosproject.incubator.net.virtual.impl;
18 +
19 +import com.google.common.collect.Iterators;
20 +import org.onlab.osgi.ServiceDirectory;
21 +import org.onosproject.event.AbstractListenerManager;
22 +import org.onosproject.incubator.net.virtual.VirtualNetwork;
23 +import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
24 +import org.onosproject.incubator.net.virtual.VirtualNetworkService;
25 +import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
26 +import org.onosproject.incubator.net.virtual.VirtualPort;
27 +import org.onosproject.net.ConnectPoint;
28 +import org.onosproject.net.DeviceId;
29 +import org.onosproject.net.Port;
30 +import org.onosproject.net.PortNumber;
31 +import org.onosproject.net.intent.Intent;
32 +import org.onosproject.net.intent.IntentData;
33 +import org.onosproject.net.intent.IntentEvent;
34 +import org.onosproject.net.intent.IntentListener;
35 +import org.onosproject.net.intent.IntentPartitionService;
36 +import org.onosproject.net.intent.IntentService;
37 +import org.onosproject.net.intent.IntentState;
38 +import org.onosproject.net.intent.Key;
39 +import org.slf4j.Logger;
40 +import org.slf4j.LoggerFactory;
41 +
42 +import java.util.ArrayList;
43 +import java.util.List;
44 +import java.util.Optional;
45 +
46 +import static com.google.common.base.Preconditions.*;
47 +
48 +/**
49 + * intent service implementation built on the virtual network service.
50 + */
51 +public class VirtualNetworkIntentService extends AbstractListenerManager<IntentEvent, IntentListener>
52 + implements IntentService, VnetService {
53 +
54 + private final Logger log = LoggerFactory.getLogger(getClass());
55 +
56 + private static final String NETWORK_NULL = "Network cannot be null";
57 + private static final String NETWORK_ID_NULL = "Network ID cannot be null";
58 + private static final String DEVICE_NULL = "Device cannot be null";
59 + private static final String INTENT_NULL = "Intent cannot be null";
60 + private static final String KEY_NULL = "Key cannot be null";
61 + private static final String APP_ID_NULL = "Intent app identifier cannot be null";
62 + private static final String INTENT_KEY_NULL = "Intent key cannot be null";
63 + private static final String CP_NULL = "Connect Point cannot be null";
64 +
65 + protected IntentService intentService;
66 + protected VirtualNetworkStore store;
67 + protected IntentPartitionService partitionService;
68 +
69 + private final VirtualNetwork network;
70 + private final VirtualNetworkService manager;
71 +
72 + /**
73 + * Creates a new VirtualNetworkIntentService object.
74 + *
75 + * @param virtualNetworkManager virtual network manager service
76 + * @param network virtual network
77 + * @param serviceDirectory service directory
78 + */
79 + public VirtualNetworkIntentService(VirtualNetworkService virtualNetworkManager, VirtualNetwork network,
80 + ServiceDirectory serviceDirectory) {
81 + checkNotNull(network, NETWORK_NULL);
82 + this.network = network;
83 + this.manager = virtualNetworkManager;
84 + this.store = serviceDirectory.get(VirtualNetworkStore.class);
85 + this.intentService = serviceDirectory.get(IntentService.class);
86 + this.partitionService = serviceDirectory.get(IntentPartitionService.class);
87 + }
88 +
89 + @Override
90 + public void submit(Intent intent) {
91 + checkNotNull(intent, INTENT_NULL);
92 + checkState(intent instanceof VirtualNetworkIntent, "Only VirtualNetworkIntent is supported.");
93 + checkArgument(validateIntent((VirtualNetworkIntent) intent), "Invalid Intent");
94 +
95 + intentService.submit(intent);
96 + }
97 +
98 + /**
99 + * Returns true if the virtual network intent is valid.
100 + *
101 + * @param intent virtual network intent
102 + * @return true if intent is valid
103 + */
104 + private boolean validateIntent(VirtualNetworkIntent intent) {
105 + checkNotNull(intent, INTENT_NULL);
106 + checkNotNull(intent.networkId(), NETWORK_ID_NULL);
107 + checkNotNull(intent.appId(), APP_ID_NULL);
108 + checkNotNull(intent.key(), INTENT_KEY_NULL);
109 + ConnectPoint ingressPoint = intent.ingressPoint();
110 + ConnectPoint egressPoint = intent.egressPoint();
111 +
112 + return (validateConnectPoint(ingressPoint) && validateConnectPoint(egressPoint));
113 + }
114 +
115 + /**
116 + * Returns true if the connect point is valid.
117 + *
118 + * @param connectPoint connect point
119 + * @return true if connect point is valid
120 + */
121 + private boolean validateConnectPoint(ConnectPoint connectPoint) {
122 + checkNotNull(connectPoint, CP_NULL);
123 + Port port = getPort(connectPoint.deviceId(), connectPoint.port());
124 + return port == null ? false : true;
125 + }
126 +
127 + /**
128 + * Returns the virtual port for the given device identifier and port number.
129 + *
130 + * @param deviceId virtual device identifier
131 + * @param portNumber virtual port number
132 + * @return virtual port
133 + */
134 + private Port getPort(DeviceId deviceId, PortNumber portNumber) {
135 + checkNotNull(deviceId, DEVICE_NULL);
136 +
137 + Optional<VirtualPort> foundPort = manager.getVirtualPorts(this.network.id(), deviceId)
138 + .stream()
139 + .filter(port -> port.number().equals(portNumber))
140 + .findFirst();
141 + if (foundPort.isPresent()) {
142 + return foundPort.get();
143 + }
144 + return null;
145 + }
146 +
147 + @Override
148 + public void withdraw(Intent intent) {
149 + checkNotNull(intent, INTENT_NULL);
150 + // Withdraws the physical intents created due to the virtual intents.
151 + store.getTunnelIds(intent)
152 + .forEach(tunnelId -> {
153 + Key intentKey = Key.of(tunnelId.id(), intent.appId());
154 + Intent physicalIntent = intentService.getIntent(intentKey);
155 + checkNotNull(physicalIntent, INTENT_NULL);
156 +
157 + // Withdraw the physical intent(s)
158 + log.info("Withdrawing pt-pt intent: " + physicalIntent);
159 + intentService.withdraw(physicalIntent);
160 + });
161 + // Now withdraw the virtual intent
162 + log.info("Withdrawing virtual intent: " + intent);
163 + intentService.withdraw(intent);
164 + }
165 +
166 + @Override
167 + public void purge(Intent intent) {
168 + checkNotNull(intent, INTENT_NULL);
169 + // Purges the physical intents created for each tunnelId.
170 + store.getTunnelIds(intent)
171 + .forEach(tunnelId -> {
172 + Key intentKey = Key.of(tunnelId.id(), intent.appId());
173 + Intent physicalIntent = intentService.getIntent(intentKey);
174 + checkNotNull(physicalIntent, INTENT_NULL);
175 +
176 + // Purge the physical intent(s)
177 + intentService.purge(physicalIntent);
178 + store.removeTunnelId(intent, tunnelId);
179 + });
180 + // Now purge the virtual intent
181 + intentService.purge(intent);
182 + }
183 +
184 + @Override
185 + public Intent getIntent(Key key) {
186 + checkNotNull(key, KEY_NULL);
187 + return store.getIntent(key);
188 + }
189 +
190 + @Override
191 + public Iterable<Intent> getIntents() {
192 + return store.getIntents();
193 + }
194 +
195 + @Override
196 + public Iterable<IntentData> getIntentData() {
197 + return store.getIntentData();
198 + }
199 +
200 + @Override
201 + public long getIntentCount() {
202 + return Iterators.size(getIntents().iterator());
203 + }
204 +
205 + @Override
206 + public IntentState getIntentState(Key intentKey) {
207 + checkNotNull(intentKey, KEY_NULL);
208 + return store.getIntentData(intentKey).state();
209 + }
210 +
211 + @Override
212 + public List<Intent> getInstallableIntents(Key intentKey) {
213 + List<Intent> intents = new ArrayList<>();
214 + getIntentData().forEach(intentData -> {
215 + if (intentData.intent().key().equals(intentKey)) {
216 + intents.addAll(intentData.installables());
217 + }
218 + });
219 + return intents;
220 + }
221 +
222 + @Override
223 + public boolean isLocal(Key intentKey) {
224 + checkNotNull(intentKey, INTENT_KEY_NULL);
225 + Intent intent = getIntent(intentKey);
226 + checkNotNull(intent, INTENT_NULL);
227 + return partitionService.isMine(intentKey);
228 + }
229 +
230 + @Override
231 + public Iterable<Intent> getPending() {
232 + return null;
233 + }
234 +
235 +
236 + @Override
237 + public VirtualNetwork network() {
238 + return network;
239 + }
240 +}
...@@ -38,6 +38,8 @@ import org.onosproject.net.Port; ...@@ -38,6 +38,8 @@ import org.onosproject.net.Port;
38 import org.onosproject.net.PortNumber; 38 import org.onosproject.net.PortNumber;
39 import org.onosproject.net.TestDeviceParams; 39 import org.onosproject.net.TestDeviceParams;
40 import org.onosproject.net.device.DeviceService; 40 import org.onosproject.net.device.DeviceService;
41 +import org.onosproject.net.intent.FakeIntentManager;
42 +import org.onosproject.net.intent.TestableIntentService;
41 import org.onosproject.store.service.TestStorageService; 43 import org.onosproject.store.service.TestStorageService;
42 44
43 import java.util.Iterator; 45 import java.util.Iterator;
...@@ -54,6 +56,7 @@ public class VirtualNetworkDeviceServiceTest extends TestDeviceParams { ...@@ -54,6 +56,7 @@ public class VirtualNetworkDeviceServiceTest extends TestDeviceParams {
54 private VirtualNetworkManager manager; 56 private VirtualNetworkManager manager;
55 private DistributedVirtualNetworkStore virtualNetworkManagerStore; 57 private DistributedVirtualNetworkStore virtualNetworkManagerStore;
56 private CoreService coreService; 58 private CoreService coreService;
59 + private TestableIntentService intentService = new FakeIntentManager();
57 60
58 @Before 61 @Before
59 public void setUp() throws Exception { 62 public void setUp() throws Exception {
...@@ -67,6 +70,7 @@ public class VirtualNetworkDeviceServiceTest extends TestDeviceParams { ...@@ -67,6 +70,7 @@ public class VirtualNetworkDeviceServiceTest extends TestDeviceParams {
67 70
68 manager = new VirtualNetworkManager(); 71 manager = new VirtualNetworkManager();
69 manager.store = virtualNetworkManagerStore; 72 manager.store = virtualNetworkManagerStore;
73 + manager.intentService = intentService;
70 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher()); 74 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
71 manager.activate(); 75 manager.activate();
72 } 76 }
......
...@@ -35,6 +35,8 @@ import org.onosproject.net.Link; ...@@ -35,6 +35,8 @@ import org.onosproject.net.Link;
35 import org.onosproject.net.NetTestTools; 35 import org.onosproject.net.NetTestTools;
36 import org.onosproject.net.PortNumber; 36 import org.onosproject.net.PortNumber;
37 import org.onosproject.net.TestDeviceParams; 37 import org.onosproject.net.TestDeviceParams;
38 +import org.onosproject.net.intent.FakeIntentManager;
39 +import org.onosproject.net.intent.TestableIntentService;
38 import org.onosproject.net.link.LinkService; 40 import org.onosproject.net.link.LinkService;
39 import org.onosproject.store.service.TestStorageService; 41 import org.onosproject.store.service.TestStorageService;
40 42
...@@ -54,6 +56,7 @@ public class VirtualNetworkLinkServiceTest extends TestDeviceParams { ...@@ -54,6 +56,7 @@ public class VirtualNetworkLinkServiceTest extends TestDeviceParams {
54 private VirtualNetworkManager manager; 56 private VirtualNetworkManager manager;
55 private DistributedVirtualNetworkStore virtualNetworkManagerStore; 57 private DistributedVirtualNetworkStore virtualNetworkManagerStore;
56 private CoreService coreService; 58 private CoreService coreService;
59 + private TestableIntentService intentService = new FakeIntentManager();
57 60
58 @Before 61 @Before
59 public void setUp() throws Exception { 62 public void setUp() throws Exception {
...@@ -67,6 +70,7 @@ public class VirtualNetworkLinkServiceTest extends TestDeviceParams { ...@@ -67,6 +70,7 @@ public class VirtualNetworkLinkServiceTest extends TestDeviceParams {
67 70
68 manager = new VirtualNetworkManager(); 71 manager = new VirtualNetworkManager();
69 manager.store = virtualNetworkManagerStore; 72 manager.store = virtualNetworkManagerStore;
73 + manager.intentService = intentService;
70 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher()); 74 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
71 manager.activate(); 75 manager.activate();
72 } 76 }
...@@ -103,12 +107,12 @@ public class VirtualNetworkLinkServiceTest extends TestDeviceParams { ...@@ -103,12 +107,12 @@ public class VirtualNetworkLinkServiceTest extends TestDeviceParams {
103 Iterator<Link> it = linkService.getLinks().iterator(); 107 Iterator<Link> it = linkService.getLinks().iterator();
104 assertEquals("The link set size did not match.", 2, Iterators.size(it)); 108 assertEquals("The link set size did not match.", 2, Iterators.size(it));
105 109
106 - // test the getActiveLinks() method where no links are ACTIVE 110 + // test the getActiveLinks() method where all links are ACTIVE
107 Iterator<Link> it2 = linkService.getActiveLinks().iterator(); 111 Iterator<Link> it2 = linkService.getActiveLinks().iterator();
108 - assertEquals("The link set size did not match.", 0, Iterators.size(it2)); 112 + assertEquals("The link set size did not match.", 2, Iterators.size(it2));
109 113
110 // test the getActiveLinks() method where one link is ACTIVE 114 // test the getActiveLinks() method where one link is ACTIVE
111 - virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.ACTIVE); 115 + virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.INACTIVE);
112 Iterator<Link> it3 = linkService.getActiveLinks().iterator(); 116 Iterator<Link> it3 = linkService.getActiveLinks().iterator();
113 assertEquals("The link set size did not match.", 1, Iterators.size(it3)); 117 assertEquals("The link set size did not match.", 1, Iterators.size(it3));
114 118
......
...@@ -27,6 +27,7 @@ import org.onosproject.core.CoreService; ...@@ -27,6 +27,7 @@ import org.onosproject.core.CoreService;
27 import org.onosproject.core.CoreServiceAdapter; 27 import org.onosproject.core.CoreServiceAdapter;
28 import org.onosproject.core.IdGenerator; 28 import org.onosproject.core.IdGenerator;
29 import org.onosproject.event.Event; 29 import org.onosproject.event.Event;
30 +import org.onosproject.incubator.net.tunnel.TunnelId;
30 import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork; 31 import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
31 import org.onosproject.incubator.net.virtual.NetworkId; 32 import org.onosproject.incubator.net.virtual.NetworkId;
32 import org.onosproject.incubator.net.virtual.TenantId; 33 import org.onosproject.incubator.net.virtual.TenantId;
...@@ -35,6 +36,7 @@ import org.onosproject.incubator.net.virtual.VirtualHost; ...@@ -35,6 +36,7 @@ import org.onosproject.incubator.net.virtual.VirtualHost;
35 import org.onosproject.incubator.net.virtual.VirtualLink; 36 import org.onosproject.incubator.net.virtual.VirtualLink;
36 import org.onosproject.incubator.net.virtual.VirtualNetwork; 37 import org.onosproject.incubator.net.virtual.VirtualNetwork;
37 import org.onosproject.incubator.net.virtual.VirtualNetworkEvent; 38 import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
39 +import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
38 import org.onosproject.incubator.net.virtual.VirtualNetworkListener; 40 import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
39 import org.onosproject.incubator.net.virtual.VirtualNetworkService; 41 import org.onosproject.incubator.net.virtual.VirtualNetworkService;
40 import org.onosproject.incubator.net.virtual.VirtualPort; 42 import org.onosproject.incubator.net.virtual.VirtualPort;
...@@ -46,6 +48,12 @@ import org.onosproject.net.NetTestTools; ...@@ -46,6 +48,12 @@ import org.onosproject.net.NetTestTools;
46 import org.onosproject.net.Port; 48 import org.onosproject.net.Port;
47 import org.onosproject.net.PortNumber; 49 import org.onosproject.net.PortNumber;
48 import org.onosproject.net.TestDeviceParams; 50 import org.onosproject.net.TestDeviceParams;
51 +import org.onosproject.net.intent.FakeIntentManager;
52 +import org.onosproject.net.intent.Intent;
53 +import org.onosproject.net.intent.IntentState;
54 +import org.onosproject.net.intent.Key;
55 +import org.onosproject.net.intent.MockIdGenerator;
56 +import org.onosproject.net.intent.TestableIntentService;
49 import org.onosproject.store.service.TestStorageService; 57 import org.onosproject.store.service.TestStorageService;
50 58
51 import java.util.Collection; 59 import java.util.Collection;
...@@ -54,6 +62,7 @@ import java.util.Set; ...@@ -54,6 +62,7 @@ import java.util.Set;
54 import java.util.concurrent.atomic.AtomicLong; 62 import java.util.concurrent.atomic.AtomicLong;
55 63
56 import static org.junit.Assert.*; 64 import static org.junit.Assert.*;
65 +import static org.onosproject.net.NetTestTools.APP_ID;
57 66
58 /** 67 /**
59 * Junit tests for VirtualNetworkManager. 68 * Junit tests for VirtualNetworkManager.
...@@ -67,10 +76,13 @@ public class VirtualNetworkManagerTest extends TestDeviceParams { ...@@ -67,10 +76,13 @@ public class VirtualNetworkManagerTest extends TestDeviceParams {
67 private DistributedVirtualNetworkStore virtualNetworkManagerStore; 76 private DistributedVirtualNetworkStore virtualNetworkManagerStore;
68 private CoreService coreService; 77 private CoreService coreService;
69 private TestListener listener = new TestListener(); 78 private TestListener listener = new TestListener();
79 + private TestableIntentService intentService = new FakeIntentManager();
80 + private IdGenerator idGenerator = new MockIdGenerator();
70 81
71 @Before 82 @Before
72 public void setUp() throws Exception { 83 public void setUp() throws Exception {
73 virtualNetworkManagerStore = new DistributedVirtualNetworkStore(); 84 virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
85 + Intent.bindIdGenerator(idGenerator);
74 86
75 coreService = new TestCoreService(); 87 coreService = new TestCoreService();
76 virtualNetworkManagerStore.setCoreService(coreService); 88 virtualNetworkManagerStore.setCoreService(coreService);
...@@ -81,6 +93,7 @@ public class VirtualNetworkManagerTest extends TestDeviceParams { ...@@ -81,6 +93,7 @@ public class VirtualNetworkManagerTest extends TestDeviceParams {
81 manager = new VirtualNetworkManager(); 93 manager = new VirtualNetworkManager();
82 manager.store = virtualNetworkManagerStore; 94 manager.store = virtualNetworkManagerStore;
83 manager.addListener(listener); 95 manager.addListener(listener);
96 + manager.intentService = intentService;
84 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher()); 97 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
85 manager.activate(); 98 manager.activate();
86 virtualNetworkManagerService = manager; 99 virtualNetworkManagerService = manager;
...@@ -92,6 +105,7 @@ public class VirtualNetworkManagerTest extends TestDeviceParams { ...@@ -92,6 +105,7 @@ public class VirtualNetworkManagerTest extends TestDeviceParams {
92 manager.removeListener(listener); 105 manager.removeListener(listener);
93 manager.deactivate(); 106 manager.deactivate();
94 NetTestTools.injectEventDispatcher(manager, null); 107 NetTestTools.injectEventDispatcher(manager, null);
108 + Intent.unbindIdGenerator(idGenerator);
95 } 109 }
96 110
97 /** 111 /**
...@@ -377,6 +391,95 @@ public class VirtualNetworkManagerTest extends TestDeviceParams { ...@@ -377,6 +391,95 @@ public class VirtualNetworkManagerTest extends TestDeviceParams {
377 } 391 }
378 392
379 /** 393 /**
394 + * Tests the addOrUpdateIntent() method in the store with a null intent.
395 + */
396 + @Test(expected = NullPointerException.class)
397 + public void testAddOrUpdateNullIntent() {
398 + manager.store.addOrUpdateIntent(null, null);
399 + }
400 +
401 + /**
402 + * Tests the removeIntent() method in the store with a null intent key.
403 + */
404 + @Test(expected = NullPointerException.class)
405 + public void testRemoveNullIntentKey() {
406 + manager.store.removeIntent(null);
407 + }
408 +
409 + /**
410 + * Tests the addOrUpdateIntent(), getIntents(), getIntent(), removeIntent() methods with the store.
411 + */
412 + @Test
413 + public void testAddOrUpdateIntent() {
414 + manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
415 + VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
416 + ConnectPoint cp1 = new ConnectPoint(DID1, P1);
417 + ConnectPoint cp2 = new ConnectPoint(DID2, P1);
418 +
419 + VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
420 + .networkId(virtualNetwork.id())
421 + .key(Key.of("Test", APP_ID))
422 + .appId(APP_ID)
423 + .ingressPoint(cp1)
424 + .egressPoint(cp2)
425 + .build();
426 +
427 + // Add the intent to the store.
428 + manager.store.addOrUpdateIntent(virtualIntent, IntentState.INSTALL_REQ);
429 + assertEquals("The intent size should match.", 1, manager.store.getIntents().size());
430 + assertNotNull("The intent should not be null.", manager.store.getIntent(virtualIntent.key()));
431 +
432 + // remove the intent from the store.
433 + manager.store.removeIntent(virtualIntent.key());
434 + assertTrue("The intents should be empty.", manager.store.getIntents().isEmpty());
435 + assertNull("The intent should be null.", manager.store.getIntent(virtualIntent.key()));
436 + }
437 +
438 + /**
439 + * Tests the addTunnelId() method in the store with a null intent.
440 + */
441 + @Test(expected = NullPointerException.class)
442 + public void testAddTunnelIdNullIntent() {
443 + manager.store.addTunnelId(null, null);
444 + }
445 +
446 + /**
447 + * Tests the removeTunnelId() method in the store with a null intent.
448 + */
449 + @Test(expected = NullPointerException.class)
450 + public void testRemoveTunnelIdNullIntent() {
451 + manager.store.removeTunnelId(null, null);
452 + }
453 +
454 + /**
455 + * Tests the addTunnelId, getTunnelIds(), removeTunnelId() methods with the store.
456 + */
457 + @Test
458 + public void testAddTunnelId() {
459 + manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
460 + VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
461 + ConnectPoint cp1 = new ConnectPoint(DID1, P1);
462 + ConnectPoint cp2 = new ConnectPoint(DID2, P1);
463 +
464 + VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
465 + .networkId(virtualNetwork.id())
466 + .key(Key.of("Test", APP_ID))
467 + .appId(APP_ID)
468 + .ingressPoint(cp1)
469 + .egressPoint(cp2)
470 + .build();
471 +
472 + TunnelId tunnelId = TunnelId.valueOf("virtual tunnel");
473 + // Add the intent to tunnelID mapping to the store.
474 + manager.store.addTunnelId(virtualIntent, tunnelId);
475 + assertEquals("The tunnels size should match.", 1, manager.store.getTunnelIds(virtualIntent).size());
476 +
477 + // Remove the intent to tunnelID mapping from the store.
478 + manager.store.removeTunnelId(virtualIntent, tunnelId);
479 + assertTrue("The tunnels should be empty.", manager.store.getTunnelIds(virtualIntent).isEmpty());
480 + }
481 +
482 + /**
380 * Method to validate that the actual versus expected virtual network events were 483 * Method to validate that the actual versus expected virtual network events were
381 * received correctly. 484 * received correctly.
382 * 485 *
......
...@@ -38,6 +38,8 @@ import org.onosproject.net.NetTestTools; ...@@ -38,6 +38,8 @@ import org.onosproject.net.NetTestTools;
38 import org.onosproject.net.Path; 38 import org.onosproject.net.Path;
39 import org.onosproject.net.PortNumber; 39 import org.onosproject.net.PortNumber;
40 import org.onosproject.net.TestDeviceParams; 40 import org.onosproject.net.TestDeviceParams;
41 +import org.onosproject.net.intent.FakeIntentManager;
42 +import org.onosproject.net.intent.TestableIntentService;
41 import org.onosproject.net.topology.LinkWeight; 43 import org.onosproject.net.topology.LinkWeight;
42 import org.onosproject.net.topology.Topology; 44 import org.onosproject.net.topology.Topology;
43 import org.onosproject.net.topology.TopologyCluster; 45 import org.onosproject.net.topology.TopologyCluster;
...@@ -62,6 +64,7 @@ public class VirtualNetworkTopologyServiceTest extends TestDeviceParams { ...@@ -62,6 +64,7 @@ public class VirtualNetworkTopologyServiceTest extends TestDeviceParams {
62 private VirtualNetworkManager manager; 64 private VirtualNetworkManager manager;
63 private DistributedVirtualNetworkStore virtualNetworkManagerStore; 65 private DistributedVirtualNetworkStore virtualNetworkManagerStore;
64 private CoreService coreService; 66 private CoreService coreService;
67 + private TestableIntentService intentService = new FakeIntentManager();
65 68
66 @Before 69 @Before
67 public void setUp() throws Exception { 70 public void setUp() throws Exception {
...@@ -75,6 +78,7 @@ public class VirtualNetworkTopologyServiceTest extends TestDeviceParams { ...@@ -75,6 +78,7 @@ public class VirtualNetworkTopologyServiceTest extends TestDeviceParams {
75 78
76 manager = new VirtualNetworkManager(); 79 manager = new VirtualNetworkManager();
77 manager.store = virtualNetworkManagerStore; 80 manager.store = virtualNetworkManagerStore;
81 + manager.intentService = intentService;
78 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher()); 82 NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
79 manager.activate(); 83 manager.activate();
80 } 84 }
......
...@@ -42,6 +42,7 @@ import org.onosproject.incubator.net.virtual.VirtualHost; ...@@ -42,6 +42,7 @@ import org.onosproject.incubator.net.virtual.VirtualHost;
42 import org.onosproject.incubator.net.virtual.VirtualLink; 42 import org.onosproject.incubator.net.virtual.VirtualLink;
43 import org.onosproject.incubator.net.virtual.VirtualNetwork; 43 import org.onosproject.incubator.net.virtual.VirtualNetwork;
44 import org.onosproject.incubator.net.virtual.VirtualNetworkEvent; 44 import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
45 +import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
45 import org.onosproject.incubator.net.virtual.VirtualNetworkService; 46 import org.onosproject.incubator.net.virtual.VirtualNetworkService;
46 import org.onosproject.incubator.net.virtual.VirtualNetworkStore; 47 import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
47 import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate; 48 import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
...@@ -54,6 +55,10 @@ import org.onosproject.net.HostLocation; ...@@ -54,6 +55,10 @@ import org.onosproject.net.HostLocation;
54 import org.onosproject.net.Link; 55 import org.onosproject.net.Link;
55 import org.onosproject.net.Port; 56 import org.onosproject.net.Port;
56 import org.onosproject.net.PortNumber; 57 import org.onosproject.net.PortNumber;
58 +import org.onosproject.net.intent.Intent;
59 +import org.onosproject.net.intent.IntentData;
60 +import org.onosproject.net.intent.IntentState;
61 +import org.onosproject.net.intent.Key;
57 import org.onosproject.store.AbstractStore; 62 import org.onosproject.store.AbstractStore;
58 import org.onosproject.store.serializers.KryoNamespaces; 63 import org.onosproject.store.serializers.KryoNamespaces;
59 import org.onosproject.store.service.ConsistentMap; 64 import org.onosproject.store.service.ConsistentMap;
...@@ -64,6 +69,7 @@ import org.onosproject.store.service.Serializer; ...@@ -64,6 +69,7 @@ import org.onosproject.store.service.Serializer;
64 import org.onosproject.store.service.SetEvent; 69 import org.onosproject.store.service.SetEvent;
65 import org.onosproject.store.service.SetEventListener; 70 import org.onosproject.store.service.SetEventListener;
66 import org.onosproject.store.service.StorageService; 71 import org.onosproject.store.service.StorageService;
72 +import org.onosproject.store.service.WallClockTimestamp;
67 import org.slf4j.Logger; 73 import org.slf4j.Logger;
68 74
69 import java.util.HashSet; 75 import java.util.HashSet;
...@@ -134,6 +140,14 @@ public class DistributedVirtualNetworkStore ...@@ -134,6 +140,14 @@ public class DistributedVirtualNetworkStore
134 private ConsistentMap<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetConsistentMap; 140 private ConsistentMap<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetConsistentMap;
135 private Map<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetMap; 141 private Map<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetMap;
136 142
143 + // Track intent key to intent data
144 + private ConsistentMap<Key, IntentData> intentKeyIntentDataConsistentMap;
145 + private Map<Key, IntentData> intentKeyIntentDataMap;
146 +
147 + // Track intent ID to TunnelIds
148 + private ConsistentMap<Key, Set<TunnelId>> intentKeyTunnelIdSetConsistentMap;
149 + private Map<Key, Set<TunnelId>> intentKeyTunnelIdSetMap;
150 +
137 private static final Serializer SERIALIZER = Serializer 151 private static final Serializer SERIALIZER = Serializer
138 .using(new KryoNamespace.Builder().register(KryoNamespaces.API) 152 .using(new KryoNamespace.Builder().register(KryoNamespaces.API)
139 .register(TenantId.class) 153 .register(TenantId.class)
...@@ -150,8 +164,11 @@ public class DistributedVirtualNetworkStore ...@@ -150,8 +164,11 @@ public class DistributedVirtualNetworkStore
150 .register(DefaultVirtualPort.class) 164 .register(DefaultVirtualPort.class)
151 .register(Device.class) 165 .register(Device.class)
152 .register(TunnelId.class) 166 .register(TunnelId.class)
167 + .register(IntentData.class)
168 + .register(VirtualNetworkIntent.class)
169 + .register(WallClockTimestamp.class)
153 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID) 170 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
154 - .build("VirtualNetworkStore")); 171 + .build());
155 172
156 /** 173 /**
157 * Distributed network store service activate method. 174 * Distributed network store service activate method.
...@@ -220,11 +237,25 @@ public class DistributedVirtualNetworkStore ...@@ -220,11 +237,25 @@ public class DistributedVirtualNetworkStore
220 237
221 networkIdVirtualPortSetConsistentMap = storageService.<NetworkId, Set<VirtualPort>>consistentMapBuilder() 238 networkIdVirtualPortSetConsistentMap = storageService.<NetworkId, Set<VirtualPort>>consistentMapBuilder()
222 .withSerializer(SERIALIZER) 239 .withSerializer(SERIALIZER)
223 - .withName("onos-networkId-virtualportss") 240 + .withName("onos-networkId-virtualports")
224 .withRelaxedReadConsistency() 241 .withRelaxedReadConsistency()
225 .build(); 242 .build();
226 networkIdVirtualPortSetMap = networkIdVirtualPortSetConsistentMap.asJavaMap(); 243 networkIdVirtualPortSetMap = networkIdVirtualPortSetConsistentMap.asJavaMap();
227 244
245 + intentKeyTunnelIdSetConsistentMap = storageService.<Key, Set<TunnelId>>consistentMapBuilder()
246 + .withSerializer(SERIALIZER)
247 + .withName("onos-intentKey-tunnelIds")
248 + .withRelaxedReadConsistency()
249 + .build();
250 + intentKeyTunnelIdSetMap = intentKeyTunnelIdSetConsistentMap.asJavaMap();
251 +
252 + intentKeyIntentDataConsistentMap = storageService.<Key, IntentData>consistentMapBuilder()
253 + .withSerializer(SERIALIZER)
254 + .withName("onos-intentKey-intentData")
255 + .withRelaxedReadConsistency()
256 + .build();
257 + intentKeyIntentDataMap = intentKeyIntentDataConsistentMap.asJavaMap();
258 +
228 log.info("Started"); 259 log.info("Started");
229 } 260 }
230 261
...@@ -607,6 +638,85 @@ public class DistributedVirtualNetworkStore ...@@ -607,6 +638,85 @@ public class DistributedVirtualNetworkStore
607 return ImmutableSet.copyOf(portSet); 638 return ImmutableSet.copyOf(portSet);
608 } 639 }
609 640
641 + @Override
642 + public synchronized void addOrUpdateIntent(Intent intent, IntentState state) {
643 + checkNotNull(intent, "Intent cannot be null");
644 + IntentData intentData = removeIntent(intent.key());
645 + if (intentData == null) {
646 + intentData = new IntentData(intent, state, new WallClockTimestamp(System.currentTimeMillis()));
647 + } else {
648 + intentData = new IntentData(intent, state, intentData.version());
649 + }
650 + intentKeyIntentDataMap.put(intent.key(), intentData);
651 + }
652 +
653 + @Override
654 + public IntentData removeIntent(Key intentKey) {
655 + checkNotNull(intentKey, "Intent key cannot be null");
656 + return intentKeyIntentDataMap.remove(intentKey);
657 + }
658 +
659 + @Override
660 + public void addTunnelId(Intent intent, TunnelId tunnelId) {
661 + // Add the tunnelId to the intent key set map
662 + Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.remove(intent.key());
663 + if (tunnelIdSet == null) {
664 + tunnelIdSet = new HashSet<>();
665 + }
666 + tunnelIdSet.add(tunnelId);
667 + intentKeyTunnelIdSetMap.put(intent.key(), tunnelIdSet);
668 + }
669 +
670 + @Override
671 + public Set<TunnelId> getTunnelIds(Intent intent) {
672 + Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.get(intent.key());
673 + return tunnelIdSet == null ? new HashSet<TunnelId>() : ImmutableSet.copyOf(tunnelIdSet);
674 + }
675 +
676 + @Override
677 + public void removeTunnelId(Intent intent, TunnelId tunnelId) {
678 + Set<TunnelId> tunnelIdSet = new HashSet<>();
679 + intentKeyTunnelIdSetMap.get(intent.key()).forEach(tunnelId1 -> {
680 + if (tunnelId1.equals(tunnelId)) {
681 + tunnelIdSet.add(tunnelId);
682 + }
683 + });
684 +
685 + if (!tunnelIdSet.isEmpty()) {
686 + intentKeyTunnelIdSetMap.compute(intent.key(), (key, existingTunnelIds) -> {
687 + if (existingTunnelIds == null || existingTunnelIds.isEmpty()) {
688 + return new HashSet<>();
689 + } else {
690 + return new HashSet<>(Sets.difference(existingTunnelIds, tunnelIdSet));
691 + }
692 + });
693 + }
694 + }
695 +
696 + @Override
697 + public Set<Intent> getIntents() {
698 + Set<Intent> intents = new HashSet<>();
699 + intentKeyIntentDataMap.values().forEach(intentData -> intents.add(intentData.intent()));
700 + return ImmutableSet.copyOf(intents);
701 + }
702 +
703 + @Override
704 + public Intent getIntent(Key key) {
705 + IntentData intentData = intentKeyIntentDataMap.get(key);
706 + return intentData == null ? null : intentData.intent();
707 + }
708 +
709 + @Override
710 + public Set<IntentData> getIntentData() {
711 + return ImmutableSet.copyOf(intentKeyIntentDataMap.values());
712 + }
713 +
714 + @Override
715 + public IntentData getIntentData(Key key) {
716 + IntentData intentData = intentKeyIntentDataMap.get(key);
717 + return intentData == null ? null : new IntentData(intentData);
718 + }
719 +
610 /** 720 /**
611 * Listener class to map listener set events to the virtual network events. 721 * Listener class to map listener set events to the virtual network events.
612 */ 722 */
......
...@@ -142,6 +142,12 @@ ...@@ -142,6 +142,12 @@
142 142
143 <dependency> 143 <dependency>
144 <groupId>org.onosproject</groupId> 144 <groupId>org.onosproject</groupId>
145 + <artifactId>onos-incubator-net</artifactId>
146 + <version>${project.version}</version>
147 + </dependency>
148 +
149 + <dependency>
150 + <groupId>org.onosproject</groupId>
145 <artifactId>onos-core-common</artifactId> 151 <artifactId>onos-core-common</artifactId>
146 <version>${project.version}</version> 152 <version>${project.version}</version>
147 </dependency> 153 </dependency>
......